Skip to content

Commit

Permalink
add snapshots to vm details
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilad Lekner authored and Gilad Lekner committed Jul 13, 2020
1 parent 335f024 commit 50beb4d
Show file tree
Hide file tree
Showing 11 changed files with 459 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as React from 'react';
import { HandlePromiseProps, withHandlePromise } from '@console/internal/components/utils';
import { YellowExclamationTriangleIcon } from '@console/shared/src/components/status/icons';
import { getNamespace } from '@console/shared';
import {
createModalLauncher,
ModalTitle,
ModalBody,
ModalSubmitFooter,
ModalComponentProps,
} from '@console/internal/components/factory';
import { k8sKill } from '@console/internal/module/k8s';
import { VirtualMachineSnapshotModel } from '../../../models';
import { SnapshotRowData } from '../../vm-snapshots/types';
import { VMLikeEntityKind } from 'packages/kubevirt-plugin/src/types/vmLike';

export const DeleteSnapshotModal = withHandlePromise((props: DeleteSnapshotModalProps) => {
const {
snapshot: { name },
vmLikeEntity,
inProgress,
errorMessage,
handlePromise,
close,
cancel,
} = props;
const namespace = getNamespace(vmLikeEntity);

const submit = (e) => {
e.preventDefault();
const promise = k8sKill(VirtualMachineSnapshotModel, { metadata: { name, namespace } });
return handlePromise(promise).then(close);
};

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

export type DeleteSnapshotModalProps = {
snapshot: SnapshotRowData;
vmLikeEntity: VMLikeEntityKind;
} & ModalComponentProps &
HandlePromiseProps;

export default createModalLauncher(DeleteSnapshotModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { Form, TextInput } from '@patternfly/react-core';
import { prefixedID } from '../../../utils';
import { HandlePromiseProps, withHandlePromise } from '@console/internal/components/utils';
import { getName, getNamespace } from '@console/shared';
import {
createModalLauncher,
ModalBody,
ModalComponentProps,
ModalTitle,
} from '@console/internal/components/factory';
import { apiVersionForModel, k8sCreate } from '@console/internal/module/k8s';
import { VMLikeEntityKind } from '../../../types/vmLike';
import { FormRow } from '../../form/form-row';
import { SAVE } from '../../../utils/strings';
import { ModalFooter } from '../modal/modal-footer';
import { VMSnapshot } from '../../../types';
import { VirtualMachineModel, VirtualMachineSnapshotModel } from '../../../models';

const SnapshotsModal = withHandlePromise((props: SnapshotsModalProps) => {
const { vmLikeEntity, inProgress, errorMessage, handlePromise, close, cancel } = props;
const asId = prefixedID.bind(null, 'snapshot');
const [name, setName] = React.useState<string>('');

const submit = async (e) => {
e.preventDefault();
const newSnapshot: VMSnapshot = {
apiVersion: apiVersionForModel(VirtualMachineSnapshotModel),
kind: VirtualMachineSnapshotModel.kind,
metadata: {
name,
namespace: getNamespace(vmLikeEntity),
},
spec: {
source: {
apiGroup: apiVersionForModel(VirtualMachineModel),
kind: VirtualMachineModel.kind,
name: getName(vmLikeEntity),
},
},
};
// eslint-disable-next-line promise/catch-or-return
handlePromise(k8sCreate(VirtualMachineSnapshotModel, newSnapshot)).then(close);
};

return (
<div className="modal-content">
<ModalTitle>Add Snapshot</ModalTitle>
<ModalBody>
<Form>
<FormRow title="Snapshot Name" fieldId={asId('name')} isRequired>
<TextInput isRequired id={asId('name')} value={name} onChange={(v) => setName(v)} />
</FormRow>
</Form>
</ModalBody>
<ModalFooter
id="snapshot"
submitButtonText={SAVE}
errorMessage={errorMessage}
isDisabled={inProgress}
onSubmit={submit}
onCancel={(e) => {
e.stopPropagation();
cancel();
}}
/>
</div>
);
});

export default createModalLauncher(SnapshotsModal);

export type SnapshotsModalProps = {
vmLikeEntity: VMLikeEntityKind;
} & ModalComponentProps &
HandlePromiseProps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import * as React from 'react';
import { TableData, TableRow, RowFunction } from '@console/internal/components/factory';
import {
asAccessReview,
Kebab,
KebabOption,
resourcePath,
Timestamp,
} from '@console/internal/components/utils';
import { dimensifyRow, getDeletetionTimestamp } from '@console/shared';
import { K8sResourceConditionStatus } from '@console/internal/module/k8s';
import deleteSnapshotModal from '../modals/delete-snapshot-modal/delete-snapshot-modal';
import { VirtualMachineModel, VirtualMachineSnapshotModel } from '../../models';
import { isVMI } from '../../selectors/check-type';
import { VMLikeEntityKind } from '../../types/vmLike';
import { ValidationCell } from '../table/validation-cell';
import {
VMSnapshotRowActionOpts,
SnapshotSimpleDataValidation,
VMSnapshotRowCustomData,
SnapshotRowData,
} from './types';
import { Link } from 'react-router-dom';

// TODO: add revertMenuAction once implemented

const menuActionDelete = (
snapshot: SnapshotRowData,
vmLikeEntity: VMLikeEntityKind,
{ withProgress }: { withProgress: (promise: Promise<any>) => void },
): KebabOption => ({
label: 'Delete',
callback: () => withProgress(deleteSnapshotModal({ snapshot, vmLikeEntity }).result),
accessReview: asAccessReview(VirtualMachineModel, vmLikeEntity, 'patch'),
});

const getActions = (
snapshot: SnapshotRowData,
vmLikeEntity: VMLikeEntityKind,
opts: VMSnapshotRowActionOpts,
) => {
if (isVMI(vmLikeEntity)) {
return [];
}
const actions = [menuActionDelete];
return actions.map((a) => a(snapshot, vmLikeEntity, opts));
};

export type VMSnapshotSimpleRowProps = {
data: SnapshotRowData;
validation?: SnapshotSimpleDataValidation;
columnClasses: string[];
actionsComponent: React.ReactNode;
index: number;
style: object;
};

export const SnapshotSimpleRow: React.FC<VMSnapshotSimpleRowProps> = ({
data: { name, namespace, date, status },
validation = {},
columnClasses,
actionsComponent,
index,
style,
}) => {
const dimensify = dimensifyRow(columnClasses);

return (
<TableRow id={name} index={index} trKey={name} style={style}>
<TableData className={dimensify()}>
<ValidationCell validation={validation.name}>
<Link to={resourcePath(VirtualMachineSnapshotModel.kind, name, namespace)}>{name}</Link>
</ValidationCell>
</TableData>
<TableData className={dimensify()}>
<ValidationCell validation={validation.date}>
<Timestamp simple timestamp={date} />
</ValidationCell>
</TableData>
<TableData className={dimensify()}>
<ValidationCell validation={validation.status}>
{status === K8sResourceConditionStatus.True ? 'Ready' : 'Progressing'}
</ValidationCell>
</TableData>
<TableData className={dimensify(true)}>{actionsComponent}</TableData>
</TableRow>
);
};

export const SnapshotRow: RowFunction<SnapshotRowData, VMSnapshotRowCustomData> = ({
obj: snapshot,
customData: { isDisabled, withProgress, vmLikeEntity, columnClasses },
index,
style,
}) => (
<SnapshotSimpleRow
data={snapshot}
columnClasses={columnClasses}
index={index}
style={style}
actionsComponent={
<Kebab
options={getActions(snapshot, vmLikeEntity, { withProgress })}
isDisabled={isDisabled || isVMI(vmLikeEntity) || !!getDeletetionTimestamp(vmLikeEntity)}
id={`kebab-for-${snapshot?.name}`}
/>
}
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ValidationObject } from '@console/shared';
import { VMLikeEntityKind } from '../../types/vmLike';

export type VMSnapshotRowActionOpts = { withProgress: (promise: Promise<any>) => void };

export type VMSnapshotRowCustomData = {
vmLikeEntity: VMLikeEntityKind;
columnClasses: string[];
isDisabled: boolean;
} & VMSnapshotRowActionOpts;

export type SnapshotSimpleDataValidation = {
name?: ValidationObject;
date?: ValidationObject;
status?: ValidationObject;
};

export type SnapshotRowData = {
name: string;
namespace: string;
date: string;
status: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as classNames from 'classnames';
import { Kebab } from '@console/internal/components/utils';

export const snapshotsTableColumnClasses = [
classNames('col-lg-2'),
classNames('col-lg-2'),
classNames('col-lg-2'),
Kebab.columnClass,
];

0 comments on commit 50beb4d

Please sign in to comment.