Skip to content

Commit

Permalink
Alert when stoping a vm with logged in users
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacov committed Jun 17, 2020
1 parent b7dcb34 commit c81de9f
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as React from 'react';
import { HandlePromiseProps, withHandlePromise } from '@console/internal/components/utils';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalComponentProps,
} from '@console/internal/components/factory';
import { VMIKind } from '../../../types';
import { VMIUsersAlert } from './vmi-users-alert';
import { redirectAfterVMDeletion } from './utils';

export const ConfirmVMIModal = withHandlePromise((props: ConfirmVMIModalProps) => {
const {
inProgress,
errorMessage,
handlePromise,
close,
cancel,
vmi,
title,
message,
executeFn,
btnText,
cancelText,
alertTitle,
submitDanger,
} = props;

const submit = (e) => {
e.preventDefault();

return handlePromise(executeFn())
.then(close)
.then(() => redirectAfterVMDeletion(vmi));
};

return (
<form onSubmit={submit} className="modal-content">
<ModalTitle>{title}</ModalTitle>
<ModalBody>{message}</ModalBody>
<VMIUsersAlert vmi={vmi} cancel={cancel} alertTitle={alertTitle} />
<ModalSubmitFooter
errorMessage={errorMessage}
submitDisabled={inProgress}
inProgress={inProgress}
submitText={btnText || 'Confirm'}
submitDanger={submitDanger}
cancel={cancel}
cancelText={cancelText || 'Cancel'}
/>
</form>
);
});

export type ConfirmVMIModalProps = {
vmi: VMIKind;
message: React.ReactNode | string;
title: React.ReactNode | string;
executeFn: () => Promise<any>;
btnText?: React.ReactNode | string;
cancelText?: React.ReactNode | string;
alertTitle?: string;
submitDanger?: boolean;
} & ModalComponentProps &
HandlePromiseProps;

export const confirmVMIModal = createModalLauncher(ConfirmVMIModal);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as _ from 'lodash';
import { HandlePromiseProps, history, withHandlePromise } from '@console/internal/components/utils';
import { HandlePromiseProps, withHandlePromise } from '@console/internal/components/utils';
import { YellowExclamationTriangleIcon } from '@console/shared/src/components/status/icons';
import { getName, getNamespace } from '@console/shared/src/selectors/common';
import {
Expand All @@ -11,88 +11,65 @@ import {
ModalComponentProps,
} from '@console/internal/components/factory';
import { apiVersionForModel } from '@console/internal/module/k8s';
import { VMLikeEntityKind } from '../../../types/vmLike';
import { asVM, getVMLikeModel, getVolumes } from '../../../selectors/vm';
import { VMKind, VMIKind } from '../../../types/vm';
import { VirtualMachineModel, VirtualMachineImportModel } from '../../../models';
import { getVolumes } from '../../../selectors/vm';
import { useOwnedVolumeReferencedResources } from '../../../hooks/use-owned-volume-referenced-resources';
import { isTemplate, isVM } from '../../../selectors/check-type';
import { useVirtualMachineImport } from '../../../hooks/use-virtual-machine-import';
import { useUpToDateVMLikeEntity } from '../../../hooks/use-vm-like-entity';
import { VirtualMachineImportModel } from '../../../models';
import { deleteVM } from '../../../k8s/requests/vm';
import { deleteVMTemplate } from '../../../k8s/requests/vmtemplate/actions';
import { VMIUsersAlert } from './vmi-users-alert';
import { redirectAfterVMDeletion } from './utils';

const redirectFn = (vmLikeEntity: VMLikeEntityKind) => {
// If we are currently on the deleted resource's page, redirect to the resource list page
const re = new RegExp(`/${getName(vmLikeEntity)}(/|$)`);
if (re.test(window.location.pathname)) {
history.push(
`/k8s/ns/${getNamespace(vmLikeEntity)}/virtualization${
isTemplate(vmLikeEntity) ? '/templates' : ''
}`,
);
}
};
export const DeleteVMModal = withHandlePromise((props: DeleteVMModalProps) => {
const { inProgress, errorMessage, handlePromise, close, cancel, vm, vmi } = props;

export const DeleteVMLikeEntityModal = withHandlePromise((props: DeleteVMLikeEntityModalProps) => {
const { inProgress, errorMessage, handlePromise, close, cancel } = props;
const vmLikeEntity = useUpToDateVMLikeEntity(props.vmLikeEntity);
const vmUpToDate = useUpToDateVMLikeEntity<VMKind>(vm);
const [deleteDisks, setDeleteDisks] = React.useState<boolean>(true);
const [deleteVMImport, setDeleteVMImport] = React.useState<boolean>(true);

const entityModel = getVMLikeModel(vmLikeEntity);
const namespace = getNamespace(vmLikeEntity);
const namespace = getNamespace(vmUpToDate);
const name = getName(vmUpToDate);

const vmLikeReference = {
name: getName(vmLikeEntity),
kind: entityModel.kind,
apiVersion: apiVersionForModel(entityModel),
const vmReference = {
name,
kind: VirtualMachineModel.kind,
apiVersion: apiVersionForModel(VirtualMachineModel),
} as any;

const [vmImport, vmImportLoaded] = useVirtualMachineImport(
isVM(vmLikeEntity) ? vmLikeEntity : null,
);
const [vmImport, vmImportLoaded] = useVirtualMachineImport(vmUpToDate);
const [ownedVolumeResources, isOwnedVolumeResourcesLoaded] = useOwnedVolumeReferencedResources(
vmLikeReference,
vmReference,
namespace,
getVolumes(asVM(vmLikeEntity), null),
getVolumes(vmUpToDate, null),
);
const isInProgress = inProgress || !vmImportLoaded || !isOwnedVolumeResourcesLoaded;
const numOfAllResources = _.sum([ownedVolumeResources.length, vmImport ? 1 : 0]);

const submit = (e) => {
e.preventDefault();

let promise;

if (isVM(vmLikeEntity)) {
promise = deleteVM(vmLikeEntity, {
vmImport,
deleteVMImport,
ownedVolumeResources,
deleteOwnedVolumeResources: deleteDisks,
});
} else if (isTemplate(vmLikeEntity)) {
promise = deleteVMTemplate(vmLikeEntity, {
ownedVolumeResources,
deleteOwnedVolumeResources: deleteDisks,
});
}
const promise = deleteVM(vmUpToDate, {
vmImport,
deleteVMImport,
ownedVolumeResources,
deleteOwnedVolumeResources: deleteDisks,
});

return handlePromise(promise)
.then(close)
.then(() => redirectFn(vmLikeEntity));
.then(() => redirectAfterVMDeletion(vmUpToDate));
};

return (
<form onSubmit={submit} className="modal-content">
<ModalTitle>
<YellowExclamationTriangleIcon className="co-icon-space-r" /> Delete{' '}
{isTemplate(vmLikeEntity) ? 'Virtual Machine Template' : entityModel.label}?
<YellowExclamationTriangleIcon className="co-icon-space-r" />
Delete {VirtualMachineModel.label}?
</ModalTitle>
<ModalBody>
Are you sure you want to delete{' '}
<strong className="co-break-word">{getName(vmLikeEntity)}</strong> in namespace{' '}
<strong>{getNamespace(vmLikeEntity)}</strong> ?
Are you sure you want to delete <strong className="co-break-word">{name}</strong> in
namespace <strong>{namespace}</strong>?
{numOfAllResources > 0 && (
<p>
The following resources will be deleted along with this virtual machine. Unchecked items
Expand Down Expand Up @@ -124,6 +101,7 @@ export const DeleteVMLikeEntityModal = withHandlePromise((props: DeleteVMLikeEnt
</div>
)}
</ModalBody>
<VMIUsersAlert vmi={vmi} cancel={cancel} alertTitle="Delete Virtual Machine alert" />
<ModalSubmitFooter
errorMessage={errorMessage}
submitDisabled={isInProgress}
Expand All @@ -136,9 +114,10 @@ export const DeleteVMLikeEntityModal = withHandlePromise((props: DeleteVMLikeEnt
);
});

export type DeleteVMLikeEntityModalProps = {
vmLikeEntity: VMLikeEntityKind;
export type DeleteVMModalProps = {
vm: VMKind;
vmi?: VMIKind;
} & ModalComponentProps &
HandlePromiseProps;

export const deleteVMLikeEntityModal = createModalLauncher(DeleteVMLikeEntityModal);
export const deleteVMModal = createModalLauncher(DeleteVMModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as React from 'react';
import { HandlePromiseProps, history, withHandlePromise } from '@console/internal/components/utils';
import { YellowExclamationTriangleIcon } from '@console/shared/src/components/status/icons';
import { getName, getNamespace } from '@console/shared/src/selectors/common';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalComponentProps,
} from '@console/internal/components/factory';
import { TemplateModel } from '@console/internal/models';
import { apiVersionForModel, TemplateKind } from '@console/internal/module/k8s';
import { asVM, getVolumes } from '../../../selectors/vm';
import { useOwnedVolumeReferencedResources } from '../../../hooks/use-owned-volume-referenced-resources';
import { useUpToDateVMLikeEntity } from '../../../hooks/use-vm-like-entity';
import { deleteVMTemplate } from '../../../k8s/requests/vmtemplate/actions';

const redirectAfterDeletion = (vmLikeEntity: TemplateKind) => {
// If we are currently on the deleted resource's page, redirect to the resource list page
const re = new RegExp(`/${getName(vmLikeEntity)}(/|$)`);
if (re.test(window.location.pathname)) {
history.push(`/k8s/ns/${getNamespace(vmLikeEntity)}/virtualization/templates`);
}
};

export const DeleteVMTemplateModal = withHandlePromise((props: DeleteVMTemplateModalProps) => {
const { inProgress, errorMessage, handlePromise, close, cancel, vmTemplate } = props;
const vmTemplateUpToDate = useUpToDateVMLikeEntity<TemplateKind>(vmTemplate);
const [deleteDisks, setDeleteDisks] = React.useState<boolean>(true);

const namespace = getNamespace(vmTemplateUpToDate);
const name = getName(vmTemplateUpToDate);

const vmTemplateReference = {
name,
kind: TemplateModel.kind,
apiVersion: apiVersionForModel(TemplateModel),
} as any;

const [ownedVolumeResources, isOwnedVolumeResourcesLoaded] = useOwnedVolumeReferencedResources(
vmTemplateReference,
namespace,
getVolumes(asVM(vmTemplateUpToDate), null),
);
const isInProgress = inProgress || !isOwnedVolumeResourcesLoaded;
const numOfAllResources = ownedVolumeResources.length;

const submit = (e) => {
e.preventDefault();

const promise = deleteVMTemplate(vmTemplateUpToDate, {
ownedVolumeResources,
deleteOwnedVolumeResources: deleteDisks,
});

return handlePromise(promise)
.then(close)
.then(() => redirectAfterDeletion(vmTemplateUpToDate));
};

return (
<form onSubmit={submit} className="modal-content">
<ModalTitle>
<YellowExclamationTriangleIcon className="co-icon-space-r" /> Delete Virtual Machine
Template?
</ModalTitle>
<ModalBody>
Are you sure you want to delete <strong className="co-break-word">{name}</strong> in
namespace <strong>{namespace}</strong>?
{numOfAllResources > 0 && (
<p>
The following resources will be deleted along with this virtual machine. Unchecked items
will not be deleted.
</p>
)}
{ownedVolumeResources.length > 0 && (
<div className="checkbox">
<label className="control-label">
<input
type="checkbox"
onChange={() => setDeleteDisks(!deleteDisks)}
checked={deleteDisks}
/>
Delete Disks ({ownedVolumeResources.length}x)
</label>
</div>
)}
</ModalBody>
<ModalSubmitFooter
errorMessage={errorMessage}
submitDisabled={isInProgress}
inProgress={isInProgress}
submitText="Delete"
submitDanger
cancel={cancel}
/>
</form>
);
});

export type DeleteVMTemplateModalProps = {
vmTemplate: TemplateKind;
} & ModalComponentProps &
HandlePromiseProps;

export const deleteVMTemplateModal = createModalLauncher(DeleteVMTemplateModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { k8sKill } from '@console/internal/module/k8s';
import { HandlePromiseProps, withHandlePromise } from '@console/internal/components/utils';
import { YellowExclamationTriangleIcon } from '@console/shared/src/components/status/icons';
import { getName, getNamespace } from '@console/shared/src/selectors/common';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalComponentProps,
} from '@console/internal/components/factory';
import { VMIKind } from '../../../types';
import { VirtualMachineInstanceModel } from '../../../models';
import { redirectAfterVMDeletion } from './utils';

export const DeleteVMIModal = withHandlePromise((props: DeleteVMIProps) => {
const { inProgress, errorMessage, handlePromise, close, cancel, vmi } = props;

const namespace = getNamespace(vmi);
const name = getName(vmi);

const submit = (e) => {
e.preventDefault();

return handlePromise(k8sKill(VirtualMachineInstanceModel, vmi))
.then(close)
.then(() => redirectAfterVMDeletion(vmi));
};

return (
<form onSubmit={submit} className="modal-content">
<ModalTitle>
<YellowExclamationTriangleIcon className="co-icon-space-r" /> Delete Virtual Machine
Instanse ?
</ModalTitle>
<ModalBody>
Are you sure you want to delete <strong className="co-break-word">{name}</strong> in
namespace <strong>{namespace}</strong>?
</ModalBody>
<ModalSubmitFooter
errorMessage={errorMessage}
submitDisabled={inProgress}
inProgress={inProgress}
submitText="Delete"
submitDanger
cancel={cancel}
/>
</form>
);
});

export type DeleteVMIProps = {
vmi: VMIKind;
} & ModalComponentProps &
HandlePromiseProps;

export const deleteVMIModal = createModalLauncher(DeleteVMIModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.kubevirt-confirm-vmi-model__alert {
padding: 0 var(--pf-global--spacer--xl) 0;
}

0 comments on commit c81de9f

Please sign in to comment.