diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard-footer.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard-footer.tsx index 1e47213f406..a2acb6925f4 100644 --- a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard-footer.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard-footer.tsx @@ -133,8 +133,8 @@ const CreateVMWizardFooterComponent: React.FC ({ - stepData: iGetCreateVMWizardTabs(state, wizardReduxId), +const stateToProps = (state, { wizardReduxID }) => ({ + stepData: iGetCreateVMWizardTabs(state, wizardReduxID), }); export const CreateVMWizardFooter = connect(stateToProps)(CreateVMWizardFooterComponent); diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard.tsx index 00eaf04641d..2f7c3f717f7 100644 --- a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/create-vm-wizard.tsx @@ -53,6 +53,7 @@ import { isStepLocked, isStepValid } from './selectors/immutable/wizard-selector import { VMSettingsTab } from './tabs/vm-settings-tab/vm-settings-tab'; import { ResourceLoadErrors } from './resource-load-errors'; import { CreateVMWizardFooter } from './create-vm-wizard-footer'; +import { ReviewTab } from './tabs/review-tab/review-tab'; import './create-vm-wizard.scss'; @@ -157,7 +158,7 @@ export class CreateVMWizardComponent extends React.ComponentVM review, + component: , }, { id: VMWizardTab.RESULT, @@ -207,7 +208,7 @@ export class CreateVMWizardComponent extends React.Component} + footer={} /> ); @@ -235,7 +236,7 @@ const wizardDispatchToProps = (dispatch, props) => ({ ); }, lockTab: (tabID) => { - dispatch(vmWizardActions[ActionType.SetTabLocked](props.reduxId, tabID, true)); + dispatch(vmWizardActions[ActionType.SetTabLocked](props.reduxID, tabID, true)); }, onCommonDataChanged: (commonData: CommonData, changedCommonData: ChangedCommonData) => { dispatch( diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.scss b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.scss new file mode 100644 index 00000000000..d738c8dde7d --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.scss @@ -0,0 +1,8 @@ +@import "../../../../../../public/style/vars"; + +.kubevirt-form-field-form__container { + dt { + color: $color-text-muted; + text-transform: capitalize; + } +} diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.tsx new file mode 100644 index 00000000000..b4bffa72355 --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-form.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { Form } from '@patternfly/react-core'; +import { FormFieldReviewContext } from './form-field-review-context'; + +import './form-field-form.scss'; + +export const FormFieldForm: React.FC = ({ children, isReview }) => { + const result = isReview ? ( +
{children}
+ ) : ( +
{children}
+ ); + return ( + {result} + ); +}; +type FormFieldFormProps = { + children?: React.ReactNode; + isReview: boolean; +}; diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-context.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-context.tsx new file mode 100644 index 00000000000..677618f8d5e --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-context.tsx @@ -0,0 +1,5 @@ +import * as React from 'react'; + +export const FormFieldReviewContext = React.createContext({ + isReview: false, +}); diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-row.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-row.tsx new file mode 100644 index 00000000000..1b7a3dc6906 --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-review-row.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import { getFieldTitle } from '../utils/vm-settings-tab-utils'; +import { iGetFieldValue } from '../selectors/immutable/vm-settings'; +import { iGet } from '../../../utils/immutable'; +import { getCheckboxReadableValue } from '../../../utils/strings'; +import { FormFieldType } from './form-field'; + +type FormFieldReviewRowProps = { + field: any; + fieldType: FormFieldType; +}; + +export const FormFieldReviewRow: React.FC = ({ fieldType, field }) => { + const fieldKey = iGet(field, 'key'); + const value = iGetFieldValue(field); + const reviewValue = [FormFieldType.CHECKBOX, FormFieldType.INLINE_CHECKBOX].includes(fieldType) + ? getCheckboxReadableValue(value) + : value; + if (!reviewValue) { + return null; + } + return ( + <> +
{getFieldTitle(fieldKey)}
+
{reviewValue}
+ + ); +}; diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-row.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-row.tsx index a1c5bfc2cb1..f6abd2eba56 100644 --- a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-row.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/form/form-field-row.tsx @@ -1,11 +1,13 @@ import * as React from 'react'; import * as _ from 'lodash'; import { getFieldHelp, getFieldId, getFieldTitle } from '../utils/vm-settings-tab-utils'; -import { isFieldHidden, isFieldRequired } from '../selectors/immutable/vm-settings'; +import { iGetFieldValue, isFieldHidden, isFieldRequired } from '../selectors/immutable/vm-settings'; import { iGet, iGetIn, iGetIsLoaded } from '../../../utils/immutable'; import { FormRow } from '../../form/form-row'; import { FormFieldContext } from './form-field-context'; import { FormFieldType } from './form-field'; +import { FormFieldReviewContext } from './form-field-review-context'; +import { FormFieldReviewRow } from './form-field-review-row'; const isLoading = (loadingResources?: { [k: string]: any }) => loadingResources && @@ -26,19 +28,30 @@ export const FormFieldRow: React.FC = ({ const loading = isLoading(loadingResources); return ( - - - {children} - - + + {({ isReview }: { isReview: boolean }) => { + if (isReview) { + return ; + } + return ( + + + {children} + + + ); + }} + ); }; diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/review-tab/review-tab.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/review-tab/review-tab.tsx new file mode 100644 index 00000000000..17c49c3df9b --- /dev/null +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/review-tab/review-tab.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { VMSettingsTab } from '../vm-settings-tab/vm-settings-tab'; + +export const ReviewTab: React.FC = ({ wizardReduxID }) => { + return ( + <> +

Review and confirm your settings

+ + + ); +}; + +type ReviewTabProps = { + wizardReduxID: string; +}; diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/memory-cpu.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/memory-cpu.tsx index 666a7551834..97cab6d88fa 100644 --- a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/memory-cpu.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/memory-cpu.tsx @@ -9,41 +9,56 @@ import { isFieldHidden } from '../../selectors/immutable/vm-settings'; import './vm-settings-tab.scss'; export const MemoryCPU: React.FC = React.memo( - ({ memoryField, cpuField, onChange }) => { + ({ memoryField, cpuField, onChange, isReview }) => { if (isFieldHidden(memoryField) && isFieldHidden(cpuField)) { return null; } + const memory = ( + + + onChange(VMSettingsField.MEMORY, value)} + /> + + + ); + + const cpu = ( + + + onChange(VMSettingsField.CPU, value)} + /> + + + ); + + if (isReview) { + return ( + <> + {memory} + {cpu} + + ); + } return ( - - - onChange(VMSettingsField.MEMORY, value)} - /> - - - - - - - onChange(VMSettingsField.CPU, value)} - /> - - + {memory} + {cpu} ); }, ); type MemoryCPUProps = { + isReview: boolean; memoryField: any; cpuField: any; onChange: (key: string, value: string) => void; diff --git a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/vm-settings-tab.tsx b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/vm-settings-tab.tsx index d2380ae8ec4..82f5e0de65b 100644 --- a/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/vm-settings-tab.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/create-vm-wizard/tabs/vm-settings-tab/vm-settings-tab.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { - Form, FormSelect, FormSelectOption, TextArea, @@ -18,6 +17,7 @@ import { iGetVmSettings } from '../../selectors/immutable/vm-settings'; import { ActionType } from '../../redux/types'; import { getFieldId, getPlaceholder } from '../../utils/vm-settings-tab-utils'; import { iGetCommonData } from '../../selectors/immutable/selectors'; +import { FormFieldForm } from '../../form/form-field-form'; import { WorkloadProfile } from './workload-profile'; import { OSFlavor } from './os-flavor'; import { UserTemplates } from './user-templates'; @@ -35,17 +35,20 @@ export class VMSettingsTabComponent extends React.Component (value) => this.props.onFieldChange(key, value); render() { - const { userTemplates, commonTemplates, dataVolumes } = this.props; + const { userTemplates, commonTemplates, dataVolumes, isReview } = this.props; return ( -
- + + {!isReview && ( + + )} - + ); } } @@ -152,6 +156,7 @@ type VMSettingsTabComponentProps = { commonTemplates: any; userTemplates: any; dataVolumes: any; + isReview: boolean; }; const dispatchToProps = (dispatch, props) => ({ diff --git a/frontend/packages/kubevirt-plugin/src/components/modals/clone-vm-modal/configuration-summary.tsx b/frontend/packages/kubevirt-plugin/src/components/modals/clone-vm-modal/configuration-summary.tsx index 3a290f4d10c..251783f9f4d 100644 --- a/frontend/packages/kubevirt-plugin/src/components/modals/clone-vm-modal/configuration-summary.tsx +++ b/frontend/packages/kubevirt-plugin/src/components/modals/clone-vm-modal/configuration-summary.tsx @@ -39,24 +39,26 @@ const getDisksDescription = ( const description = [disk.name]; const volume = volumes.find((v) => v.name === disk.name); - if (volume.dataVolume) { - let dataVolume = dataVolumeTemplates.find((dv) => getName(dv) === volume.dataVolume.name); - if (!dataVolume) { - dataVolume = dataVolumes.find( - (dv) => getName(dv) === volume.dataVolume.name && getNamespace(dv) === getNamespace(vm), + if (volume) { + if (volume.dataVolume) { + let dataVolume = dataVolumeTemplates.find((dv) => getName(dv) === volume.dataVolume.name); + if (!dataVolume) { + dataVolume = dataVolumes.find( + (dv) => getName(dv) === volume.dataVolume.name && getNamespace(dv) === getNamespace(vm), + ); + } + description.push( + getStorageSize(getDataVolumeResources(dataVolume)), + getDataVolumeStorageClassName(dataVolume), ); + } else if (volume.persistentVolumeClaim) { + const pvc = pvcs.find((p) => getName(p) === volume.persistentVolumeClaim.claimName); + description.push(getStorageSize(getPvcResources(pvc)), getPvcStorageClassName(pvc)); + } else if (volume.containerDisk) { + description.push('container disk'); + } else if (volume.cloudInitNoCloud) { + description.push('cloud-init disk'); } - description.push( - getStorageSize(getDataVolumeResources(dataVolume)), - getDataVolumeStorageClassName(dataVolume), - ); - } else if (volume.persistentVolumeClaim) { - const pvc = pvcs.find((p) => getName(p) === volume.persistentVolumeClaim.claimName); - description.push(getStorageSize(getPvcResources(pvc)), getPvcStorageClassName(pvc)); - } else if (volume.containerDisk) { - description.push('container disk'); - } else if (volume.cloudInitNoCloud) { - description.push('cloud-init disk'); } return
{description.join(' - ')}
; }); diff --git a/frontend/packages/kubevirt-plugin/src/utils/strings.ts b/frontend/packages/kubevirt-plugin/src/utils/strings.ts index 88768ef1868..6379aaa26a4 100644 --- a/frontend/packages/kubevirt-plugin/src/utils/strings.ts +++ b/frontend/packages/kubevirt-plugin/src/utils/strings.ts @@ -6,3 +6,5 @@ export const CREATED_WITH_FAILED_CLEANUP = 'created & failed to clean up'; export const CREATED_WITH_CLEANUP = 'created & cleaned up'; export const FAILED_TO_CREATE = 'failed to create'; export const FAILED_TO_PATCH = 'failed to patch'; + +export const getCheckboxReadableValue = (value: boolean) => (value ? 'yes' : 'no');