diff --git a/locales/en/plugin__kubevirt-plugin.json b/locales/en/plugin__kubevirt-plugin.json index 74bd540ecc..59695afd26 100644 --- a/locales/en/plugin__kubevirt-plugin.json +++ b/locales/en/plugin__kubevirt-plugin.json @@ -312,7 +312,6 @@ "Customize and create VirtualMachine": "Customize and create VirtualMachine", "Customize template parameters": "Customize template parameters", "Customize VirtualMachine": "Customize VirtualMachine", - "Customize VirtualMachine parameters": "Customize VirtualMachine parameters", "CX series": "CX series", "CX Series": "CX Series", "cx1": "cx1", @@ -1069,7 +1068,7 @@ "This is a CD-ROM boot source": "This is a CD-ROM boot source", "This key will override the SSH key secret set on the template": "This key will override the SSH key secret set on the template", "This Persistent Volume Claim will be created using a DataVolume through Containerized Data Importer (CDI)": "This Persistent Volume Claim will be created using a DataVolume through Containerized Data Importer (CDI)", - "This Template requires some additional parameters. Click the Customize VirtualMachine button to complete the creation flow.": "This Template requires some additional parameters. Click the Customize VirtualMachine button to complete the creation flow.", + "This Template requires some additional parameters.": "This Template requires some additional parameters.", "This Template supports quick create VirtualMachine": "This Template supports quick create VirtualMachine", "This user is not allowed to edit this boot source": "This user is not allowed to edit this boot source", "This VirtualMachine has": "This VirtualMachine has", diff --git a/src/views/catalog/Catalog.tsx b/src/views/catalog/Catalog.tsx index 1945fecac0..71ac18f874 100644 --- a/src/views/catalog/Catalog.tsx +++ b/src/views/catalog/Catalog.tsx @@ -1,32 +1,23 @@ -import * as React from 'react'; +import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; import CreateVMHorizontalNav from './CreateVMHorizontalNav/CreateVMHorizontalNav'; -import CustomizeVirtualMachine from './customize/CustomizeVirtualMachine'; import { WizardVMContextProvider } from './utils/WizardVMContext'; import Wizard from './wizard/Wizard'; -const Catalog: React.FC = () => { - return ( - - - - - - - - ); -}; +const Catalog: FC = () => ( + + + + + + +); + export default Catalog; diff --git a/src/views/catalog/customize/CustomizeVirtualMachine.scss b/src/views/catalog/customize/CustomizeVirtualMachine.scss deleted file mode 100644 index 6ba5ab3364..0000000000 --- a/src/views/catalog/customize/CustomizeVirtualMachine.scss +++ /dev/null @@ -1,19 +0,0 @@ -.customize-vm { - &__right-header { - a { - padding-left: 0; - } - - img { - width: 2em; - } - } - - .pf-c-expandable-section__toggle { - align-items: center; - - &-text { - font-size: 18px; - } - } -} diff --git a/src/views/catalog/customize/CustomizeVirtualMachine.tsx b/src/views/catalog/customize/CustomizeVirtualMachine.tsx deleted file mode 100644 index 22d0638e58..0000000000 --- a/src/views/catalog/customize/CustomizeVirtualMachine.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { FC, useMemo } from 'react'; -import { useParams } from 'react-router-dom'; - -import { - modelToGroupVersionKind, - TemplateModel, - V1Template, -} from '@kubevirt-ui/kubevirt-api/console'; -import { useURLParams } from '@kubevirt-utils/hooks/useURLParams'; -import useVMTemplateGeneratedParams from '@kubevirt-utils/resources/template/hooks/useVMTemplateGeneratedParams'; -import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; - -import { CustomizeError } from './components/CustomizeError'; -import { CustomizeForm } from './components/CustomizeForms/CustomizeForm'; -import CustomizeFormWithStorage from './components/CustomizeForms/CustomizeFormWithStorage'; -import { CustomizeVirtualMachineHeader } from './components/CustomizeVirtualMachineHeader'; -import { CustomizeVirtualMachineSkeleton } from './components/CustomizeVirtualMachineSkeleton'; -import { RightHeader } from './components/RightHeading'; -import { hasCustomizableSource } from './utils'; - -import './CustomizeVirtualMachine.scss'; - -const CustomizeVirtualMachine: FC = () => { - const { ns } = useParams<{ ns: string }>(); - const { params } = useURLParams(); - const name = params.get('name'); - const templateNamespace = params.get('namespace'); - const isBootSourceAvailable = params.get('defaultSourceExists') === 'true'; - - const [template, loaded, error] = useK8sWatchResource({ - groupVersionKind: modelToGroupVersionKind(TemplateModel), - isList: false, - name, - namespace: templateNamespace, - namespaced: true, - }); - - const [templateWithGeneratedValues, processError] = useVMTemplateGeneratedParams( - loaded ? template : null, - ); - - const Form = useMemo(() => { - const withDiskSource = hasCustomizableSource(template); - - if (withDiskSource) { - return CustomizeFormWithStorage; - } else { - return CustomizeForm; - } - }, [template]); - - if (error || processError) return ; - - if (!loaded || !templateWithGeneratedValues) return ; - - return ( - <> - - - - - - - - - {template && ( - - )} - - - - > - ); -}; - -export default CustomizeVirtualMachine; diff --git a/src/views/catalog/customize/components/CustomizeForms/CustomizeForm.tsx b/src/views/catalog/customize/components/CustomizeForms/CustomizeForm.tsx index 1071dd5bc0..936338d809 100644 --- a/src/views/catalog/customize/components/CustomizeForms/CustomizeForm.tsx +++ b/src/views/catalog/customize/components/CustomizeForms/CustomizeForm.tsx @@ -1,15 +1,12 @@ -import React, { FC, useMemo } from 'react'; +import React, { FC } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { getTemplateNameParameterValue } from '@catalog/customize/utils'; import { V1Template } from '@kubevirt-ui/kubevirt-api/console'; -import { useURLParams } from '@kubevirt-utils/hooks/useURLParams'; import { Form } from '@patternfly/react-core'; -import { buildFields, getVirtualMachineNameField } from '../../utils'; +import { buildFields } from '../../utils'; import { ExpandableOptionsFields } from '../ExpandableOptionalFields'; import { FieldGroup } from '../FieldGroup'; -import { FormActionGroup } from '../FormActionGroup'; import { FormError } from '../FormError'; import { useCustomizeFormSubmit } from './useCustomizeFormSubmit'; @@ -22,18 +19,12 @@ type CustomizeFormProps = { export const CustomizeForm: FC = ({ template }) => { const methods = useForm(); - const { error, loaded, onSubmit } = useCustomizeFormSubmit({ template }); + const { error, onSubmit } = useCustomizeFormSubmit({ template }); const [requiredFields, optionalFields] = buildFields(template); - const { params } = useURLParams(); - const vmName = params.get('vmName') || getTemplateNameParameterValue(template); - - const nameField = useMemo(() => getVirtualMachineNameField(vmName), [vmName]); - return ( - {requiredFields?.map((field) => ( ))} @@ -41,7 +32,6 @@ export const CustomizeForm: FC = ({ template }) => { - ); diff --git a/src/views/catalog/customize/components/CustomizeForms/CustomizeFormWithStorage.tsx b/src/views/catalog/customize/components/CustomizeForms/CustomizeFormWithStorage.tsx index d13debb038..ac359f473b 100644 --- a/src/views/catalog/customize/components/CustomizeForms/CustomizeFormWithStorage.tsx +++ b/src/views/catalog/customize/components/CustomizeForms/CustomizeFormWithStorage.tsx @@ -1,10 +1,8 @@ import React, { FC, useMemo, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { getTemplateNameParameterValue } from '@catalog/customize/utils'; import { V1Template } from '@kubevirt-ui/kubevirt-api/console'; import { V1beta1DataVolumeSpec, V1ContainerDiskSource } from '@kubevirt-ui/kubevirt-api/kubevirt'; -import { useURLParams } from '@kubevirt-utils/hooks/useURLParams'; import { getTemplateOS, getTemplateVirtualMachineObject, @@ -14,15 +12,10 @@ import { import { Form } from '@patternfly/react-core'; import { addCDToTemplate } from '../../cd'; -import { - buildFields, - getVirtualMachineNameField, - overrideVirtualMachineDataVolumeSpec, -} from '../../utils'; +import { buildFields, overrideVirtualMachineDataVolumeSpec } from '../../utils'; import { ExpandableCustomizeSourceSection } from '../CustomizeSource/ExpandableCustomizeSourceSection'; import { ExpandableOptionsFields } from '../ExpandableOptionalFields'; import { FieldGroup } from '../FieldGroup'; -import { FormActionGroup } from '../FormActionGroup'; import { FormError } from '../FormError'; import { useCustomizeFormSubmit } from './useCustomizeFormSubmit'; @@ -37,8 +30,6 @@ const CustomizeFormWithStorage: FC = ({ template, }) => { const methods = useForm(); - const { params } = useURLParams(); - const vmName = params.get('vmName') || getTemplateNameParameterValue(template); const [diskSource, setDiskSource] = useState(); const [cdSource, setCDSource] = useState(); @@ -62,7 +53,7 @@ const CustomizeFormWithStorage: FC = ({ getTemplateOS(template) === OS_NAME_TYPES.windows, ); - const { cdUpload, diskUpload, error, loaded, onCancel, onSubmit } = useCustomizeFormSubmit({ + const { cdUpload, diskUpload, error, onSubmit } = useCustomizeFormSubmit({ cdSource, diskSource, template: templateWithSources, @@ -71,13 +62,9 @@ const CustomizeFormWithStorage: FC = ({ const [requiredFields, optionalFields] = useMemo(() => buildFields(template), [template]); - const nameField = useMemo(() => getVirtualMachineNameField(vmName), [vmName]); - return ( - - {requiredFields?.map((field) => ( ))} @@ -98,7 +85,6 @@ const CustomizeFormWithStorage: FC = ({ - ); diff --git a/src/views/catalog/customize/components/CustomizeVirtualMachineHeader.tsx b/src/views/catalog/customize/components/CustomizeVirtualMachineHeader.tsx deleted file mode 100644 index 75022e2ef4..0000000000 --- a/src/views/catalog/customize/components/CustomizeVirtualMachineHeader.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React, { FC, memo } from 'react'; -import { useHistory } from 'react-router-dom'; - -import { DEFAULT_NAMESPACE } from '@kubevirt-utils/constants/constants'; -import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; -import { Breadcrumb, BreadcrumbItem, Button } from '@patternfly/react-core'; - -import { CUSTOMIZE_TEMPLATE_TITLE } from '../constants'; - -export const CustomizeVirtualMachineHeader: FC<{ namespace: string }> = memo(({ namespace }) => { - const { t } = useKubevirtTranslation(); - const history = useHistory(); - - return ( - - - - - history.push(`/k8s/ns/${namespace || DEFAULT_NAMESPACE}/templatescatalog`) - } - isInline - variant="link" - > - {t('Catalog')} - - - {CUSTOMIZE_TEMPLATE_TITLE} - - {CUSTOMIZE_TEMPLATE_TITLE} - - ); -}); -CustomizeVirtualMachineHeader.displayName = 'CustomizeVirtualMachineHeader'; diff --git a/src/views/catalog/customize/components/ExpandableOptionalFields.tsx b/src/views/catalog/customize/components/ExpandableOptionalFields.tsx index d8bf1e66f9..66956e3946 100644 --- a/src/views/catalog/customize/components/ExpandableOptionalFields.tsx +++ b/src/views/catalog/customize/components/ExpandableOptionalFields.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { FC, useState } from 'react'; import { TemplateParameter } from '@kubevirt-ui/kubevirt-api/console'; import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; @@ -12,11 +12,9 @@ type ExpandableOptionsFieldsProps = { optionalFields: TemplateParameter[]; }; -export const ExpandableOptionsFields: React.FC = ({ - optionalFields, -}) => { +export const ExpandableOptionsFields: FC = ({ optionalFields }) => { const { t } = useKubevirtTranslation(); - const [optionalFieldsExpanded, setOptionalFieldsExpanded] = React.useState(false); + const [optionalFieldsExpanded, setOptionalFieldsExpanded] = useState(false); if (!optionalFields || optionalFields.length === 0) return null; diff --git a/src/views/catalog/customize/components/FormActionGroup.tsx b/src/views/catalog/customize/components/FormActionGroup.tsx deleted file mode 100644 index 75fadfccdc..0000000000 --- a/src/views/catalog/customize/components/FormActionGroup.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { FC, useCallback } from 'react'; -import { useHistory, useParams } from 'react-router-dom'; - -import { clearSessionStorageVM } from '@catalog/utils/WizardVMContext'; -import { ALL_NAMESPACES } from '@kubevirt-utils/hooks/constants'; -import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; -import { kubevirtConsole } from '@kubevirt-utils/utils/utils'; -import { ActionGroup, Button } from '@patternfly/react-core'; - -type FormActionGroupProps = { - loading: boolean; - onCancel?: () => Promise<{ - metadata: { - name: string; - namespace: string; - }; - }>; -}; - -export const FormActionGroup: FC = ({ loading, onCancel }) => { - const { t } = useKubevirtTranslation(); - const { ns: namespace } = useParams<{ ns: string }>(); - const history = useHistory(); - - const handleCancel = useCallback(() => { - const namespaceUrl = namespace ? `ns/${namespace}` : ALL_NAMESPACES; - onCancel?.().catch(kubevirtConsole.error); - clearSessionStorageVM(); - history.push(`/k8s/${namespaceUrl}/templatescatalog`); - }, [history, namespace, onCancel]); - - return ( - - - {t('Customize VirtualMachine parameters')} - - - {t('Cancel')} - - - ); -}; diff --git a/src/views/catalog/customize/components/RightHeading.tsx b/src/views/catalog/customize/components/RightHeading.tsx deleted file mode 100644 index f069ca0a74..0000000000 --- a/src/views/catalog/customize/components/RightHeading.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from 'react'; - -import { getTemplateOSIcon } from '@catalog/templatescatalog/utils/os-icons'; -import { V1Template } from '@kubevirt-ui/kubevirt-api/console'; -import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; -import { - getTemplateDescription, - getTemplateDocumentationURL, - getTemplateName, -} from '@kubevirt-utils/resources/template/utils/selectors'; -import { Button, Flex, FlexItem } from '@patternfly/react-core'; -import ExternalLinkAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-alt-icon'; - -type RightHeadingProps = { - template: V1Template; -}; - -export const RightHeader: React.FC = ({ template }) => { - const { t } = useKubevirtTranslation(); - if (!template?.metadata?.annotations) return null; - - const displayName = getTemplateName(template); - const documentationLink = getTemplateDocumentationURL(template); - const description = getTemplateDescription(template); - const icon = getTemplateOSIcon(template); - return ( - - - - - - - - - {displayName} - - - {documentationLink && ( - - } - iconPosition="right" - target="_blank" - variant="link" - > - {t('View documentation')} - - - )} - - {description && {description}} - - ); -}; diff --git a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerCreateForm.tsx b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerCreateForm.tsx index 7f5f68b465..d43348f815 100644 --- a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerCreateForm.tsx +++ b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerCreateForm.tsx @@ -5,7 +5,6 @@ import produce from 'immer'; import { NAME_INPUT_FIELD } from '@catalog/customize/constants'; import { isNameParameterExists, replaceTemplateParameterValue } from '@catalog/customize/utils'; import { quickCreateVM } from '@catalog/utils/quick-create-vm'; -import { isRHELTemplate } from '@catalog/utils/utils'; import { useWizardVMContext } from '@catalog/utils/WizardVMContext'; import { ProcessedTemplatesModel, @@ -13,24 +12,13 @@ import { V1Template, } from '@kubevirt-ui/kubevirt-api/console'; import VirtualMachineModel from '@kubevirt-ui/kubevirt-api/console/models/VirtualMachineModel'; -import { updateCloudInitRHELSubscription } from '@kubevirt-utils/components/CloudinitModal/utils/cloudinit-utils'; -import { - addSecretToVM, - applyCloudDriveCloudInitVolume, -} from '@kubevirt-utils/components/SSHSecretSection/utils/utils'; +import { DEFAULT_NAMESPACE } from '@kubevirt-utils/constants/constants'; import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; import { RHELAutomaticSubscriptionData } from '@kubevirt-utils/hooks/useRHELAutomaticSubscription/utils/types'; -import { getAnnotation, getResourceUrl } from '@kubevirt-utils/resources/shared'; -import { - ANNOTATIONS, - getTemplateOS, - getTemplateVirtualMachineObject, - LABEL_USED_TEMPLATE_NAME, - LABEL_USED_TEMPLATE_NAMESPACE, -} from '@kubevirt-utils/resources/template'; +import { getResourceUrl } from '@kubevirt-utils/resources/shared'; +import { getTemplateVirtualMachineObject } from '@kubevirt-utils/resources/template'; import { getMemoryCPU } from '@kubevirt-utils/resources/vm'; import { ensurePath, isEmpty } from '@kubevirt-utils/utils/utils'; -import { k8sCreate } from '@openshift-console/dynamic-plugin-sdk'; import { useAccessReview, useK8sModels } from '@openshift-console/dynamic-plugin-sdk'; import { Alert, @@ -76,7 +64,7 @@ export const TemplatesCatalogDrawerCreateForm: FC { const history = useHistory(); const { t } = useKubevirtTranslation(); - const { updateTabsData, updateVM, vm } = useWizardVMContext(); + const { updateTabsData, vm } = useWizardVMContext(); const [vmName, setVMName] = useState(initialVMName || ''); const [startVM, setStartVM] = useState(true); @@ -90,7 +78,9 @@ export const TemplatesCatalogDrawerCreateForm: FC { + const onQuickCreate = (e: MouseEvent) => { + e.preventDefault(); + setIsQuickCreating(true); setQuickCreateError(undefined); @@ -142,68 +132,6 @@ export const TemplatesCatalogDrawerCreateForm: FC { e.preventDefault(); - if (isEmpty(template?.parameters)) { - return k8sCreate({ - data: { ...template, metadata: { ...template?.metadata, namespace } }, - model: ProcessedTemplatesModel, - ns: namespace, - queryParams: { - dryRun: 'All', - }, - }).then(async (processedTemplate) => { - const vmObject = getTemplateVirtualMachineObject(processedTemplate); - - const updatedVM = produce(vmObject, (vmDraft) => { - ensurePath(vmDraft, [ - 'spec.template.spec.domain.cpu', - 'spec.template.spec.domain.memory.guest', - ]); - - vmDraft.metadata.namespace = namespace; - vmDraft.metadata.labels[LABEL_USED_TEMPLATE_NAME] = template.metadata.name; - vmDraft.metadata.labels[LABEL_USED_TEMPLATE_NAMESPACE] = template.metadata.namespace; - const { cpu, memory } = getMemoryCPU(vm); - vmDraft.spec.template.spec.domain.cpu.cores = cpu?.cores; - vmDraft.spec.template.spec.domain.memory.guest = memory; - - const updatedVolumes = applyCloudDriveCloudInitVolume(vmObject); - vmDraft.spec.template.spec.volumes = isRHELTemplate(processedTemplate) - ? updateCloudInitRHELSubscription(updatedVolumes, subscriptionData) - : updatedVolumes; - }); - - updateTabsData((tabsDataDraft) => { - // additional objects - tabsDataDraft.additionalObjects = processedTemplate.objects.filter((obj) => - !isEmpty(authorizedSSHKey) - ? obj.kind !== VirtualMachineModel.kind || obj.kind !== SecretModel - : obj.kind !== VirtualMachineModel.kind, - ); - // overview - ensurePath(tabsDataDraft, 'overview.templateMetadata'); - tabsDataDraft.overview.templateMetadata.name = template.metadata.name; - tabsDataDraft.overview.templateMetadata.namespace = template.metadata.namespace; - tabsDataDraft.overview.templateMetadata.osType = getTemplateOS(template); - tabsDataDraft.overview.templateMetadata.displayName = getAnnotation( - template, - ANNOTATIONS.displayName, - ); - }); - - // update context vm - await updateVM( - !isEmpty(authorizedSSHKey) ? addSecretToVM(updatedVM, authorizedSSHKey) : updatedVM, - ); - - history.push(`/k8s/ns/${namespace}/templatescatalog/review`); - }); - } - let catalogUrl = `templatescatalog/customize?name=${template.metadata.name}&namespace=${template.metadata.namespace}&defaultSourceExists=${isBootSourceAvailable}`; - - if (vmName) { - catalogUrl += `&vmName=${vmName}`; - } - updateTabsData((currentTabs) => { currentTabs.authorizedSSHKey = authorizedSSHKey; }); @@ -212,7 +140,7 @@ export const TemplatesCatalogDrawerCreateForm: FC ({ ...currentTabsData, subscriptionData })); } - history.push(catalogUrl); + history.push(`/k8s/ns/${namespace || DEFAULT_NAMESPACE}/templatescatalog/review`); }; const onChangeStartVM = (checked: boolean) => { @@ -222,6 +150,13 @@ export const TemplatesCatalogDrawerCreateForm: FC @@ -264,11 +199,7 @@ export const TemplatesCatalogDrawerCreateForm: FC > ) : ( - - {t( - 'This Template requires some additional parameters. Click the Customize VirtualMachine button to complete the creation flow.', - )} - + {t('This Template requires some additional parameters.')} )} {quickCreateError && ( @@ -281,29 +212,22 @@ export const TemplatesCatalogDrawerCreateForm: FC - {canQuickCreate && ( - - { - e.preventDefault(); - onQuickCreate(); - }} - data-test-id="quick-create-vm-btn" - form="quick-create-form" - isLoading={isQuickCreating || modelsLoading} - type="submit" - > - {t('Quick create VirtualMachine')} - - - )} + + + {t('Quick create VirtualMachine')} + + diff --git a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerLeftColumn.tsx b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerLeftColumn.tsx new file mode 100644 index 0000000000..31f3ddf2df --- /dev/null +++ b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerLeftColumn.tsx @@ -0,0 +1,94 @@ +import React, { FC } from 'react'; + +import { CustomizeError } from '@catalog/customize/components/CustomizeError'; +import { CustomizeVirtualMachineSkeleton } from '@catalog/customize/components/CustomizeVirtualMachineSkeleton'; +import { V1Template } from '@kubevirt-ui/kubevirt-api/console'; +import AdditionalResources from '@kubevirt-utils/components/AdditionalResources/AdditionalResources'; +import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; +import { + getTemplateDescription, + getTemplateDocumentationURL, + getTemplateName, + getTemplateWorkload, + isDefaultVariantTemplate, + WORKLOADS_LABELS, +} from '@kubevirt-utils/resources/template'; +import useVMTemplateGeneratedParams from '@kubevirt-utils/resources/template/hooks/useVMTemplateGeneratedParams'; +import { + Button, + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, +} from '@patternfly/react-core'; +import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons'; + +import TemplateExpandableDescription from './TemplateExpandableDescription'; + +type TemplatesCatalogDrawerLeftColumnProps = { + template: V1Template; +}; + +const TemplatesCatalogDrawerLeftColumn: FC = ({ + template, +}) => { + const { t } = useKubevirtTranslation(); + const [templateWithGeneratedValues, processError] = useVMTemplateGeneratedParams(template); + + const notAvailable = t('N/A'); + const description = getTemplateDescription(template) || notAvailable; + const displayName = getTemplateName(template); + const documentationUrl = getTemplateDocumentationURL(template); + const isDefaultTemplate = isDefaultVariantTemplate(template); + const workload = getTemplateWorkload(template); + + if (processError) return ; + + if (!templateWithGeneratedValues) return ; + + return ( + <> + + + {t('Operating system')} + {displayName} + + + {t('Workload type')} + + {WORKLOADS_LABELS[workload] ?? t('Other')} {isDefaultTemplate && t('(default)')} + + + + {t('Description')} + + {} + + + + {t('Documentation')} + + {documentationUrl ? ( + } + iconPosition="right" + isInline + isSmall + variant="link" + > + + {t('Refer to documentation')} + + + ) : ( + notAvailable + )} + + + + + > + ); +}; + +export default TemplatesCatalogDrawerLeftColumn; diff --git a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerPanel.tsx b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerPanel.tsx index 2c6f0c16d1..69c74e5f74 100644 --- a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerPanel.tsx +++ b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerPanel.tsx @@ -1,54 +1,31 @@ -import React, { FC, memo, useEffect, useState } from 'react'; +import React, { FC, memo, useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import produce from 'immer'; +import { CustomizeForm } from '@catalog/customize/components/CustomizeForms/CustomizeForm'; +import CustomizeFormWithStorage from '@catalog/customize/components/CustomizeForms/CustomizeFormWithStorage'; +import { hasCustomizableSource } from '@catalog/customize/utils'; import { updateVMCPUMemory } from '@catalog/templatescatalog/utils/helpers'; import { useWizardVMContext } from '@catalog/utils/WizardVMContext'; -import { WizardOverviewDisksTable } from '@catalog/wizard/tabs/overview/components/WizardOverviewDisksTable/WizardOverviewDisksTable'; -import { WizardOverviewNetworksTable } from '@catalog/wizard/tabs/overview/components/WizardOverviewNetworksTable/WizardOverviewNetworksTable'; import { ProcessedTemplatesModel, V1Template } from '@kubevirt-ui/kubevirt-api/console'; import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt'; -import AdditionalResources from '@kubevirt-utils/components/AdditionalResources/AdditionalResources'; -import CPUDescription from '@kubevirt-utils/components/CPUDescription/CPUDescription'; -import { CpuMemHelperTextResources } from '@kubevirt-utils/components/CPUDescription/utils/utils'; -import CPUMemory from '@kubevirt-utils/components/CPUMemory/CPUMemory'; -import CPUMemoryModal from '@kubevirt-utils/components/CPUMemoryModal/CpuMemoryModal'; -import HardwareDevices from '@kubevirt-utils/components/HardwareDevices/HardwareDevices'; -import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider'; -import VirtualMachineDescriptionItem from '@kubevirt-utils/components/VirtualMachineDescriptionItem/VirtualMachineDescriptionItem'; import { DEFAULT_NAMESPACE } from '@kubevirt-utils/constants/constants'; import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; -import { WORKLOADS_LABELS } from '@kubevirt-utils/resources/template/utils/constants'; -import { - getTemplateDescription, - getTemplateDisks, - getTemplateDocumentationURL, - getTemplateInterfaces, - getTemplateName, - getTemplateNetworks, - getTemplateVirtualMachineObject, - getTemplateWorkload, - isDefaultVariantTemplate, -} from '@kubevirt-utils/resources/template/utils/selectors'; -import { getCPU, getGPUDevices, getHostDevices } from '@kubevirt-utils/resources/vm'; +import { useURLParams } from '@kubevirt-utils/hooks/useURLParams'; +import { getTemplateVirtualMachineObject } from '@kubevirt-utils/resources/template/utils/selectors'; import { k8sCreate } from '@openshift-console/dynamic-plugin-sdk'; import { Alert, AlertVariant, - Button, - DescriptionList, - DescriptionListDescription, - DescriptionListGroup, - DescriptionListTerm, Grid, GridItem, Stack, StackItem, Title, } from '@patternfly/react-core'; -import ExternalLinkSquareAltIcon from '@patternfly/react-icons/dist/esm/icons/external-link-square-alt-icon'; -import TemplateExpandableDescription from './TemplateExpandableDescription'; +import TemplatesCatalogDrawerLeftColumn from './TemplatesCatalogDrawerLeftColumn'; +import TemplatesCatalogDrawerRightColumn from './TemplatesCatalogDrawerRightColumn'; type TemplatesCatalogDrawerPanelProps = { template: V1Template; @@ -57,28 +34,28 @@ type TemplatesCatalogDrawerPanelProps = { export const TemplatesCatalogDrawerPanel: FC = memo( ({ template }) => { const { t } = useKubevirtTranslation(); - const { createModal } = useModal(); const { updateVM } = useWizardVMContext(); const { ns } = useParams<{ ns: string }>(); - const vmNamespace = ns || DEFAULT_NAMESPACE; + const { params } = useURLParams(); - const notAvailable = t('N/A'); - const vmObject = getTemplateVirtualMachineObject(template); - const displayName = getTemplateName(template); - const description = getTemplateDescription(template) || notAvailable; - const documentationUrl = getTemplateDocumentationURL(template); - const workload = getTemplateWorkload(template); - const networks = getTemplateNetworks(template); - const interfaces = getTemplateInterfaces(template); - const disks = getTemplateDisks(template); - const isDefaultTemplate = isDefaultVariantTemplate(template); - const hostDevicesCount = getHostDevices(vmObject)?.length || 0; - const gpusCount = getGPUDevices(vmObject)?.length || 0; - const hardwareDevicesCount = hostDevicesCount + gpusCount; + const isBootSourceAvailable = params.get('defaultSourceExists') === 'true'; + const vmNamespace = ns || DEFAULT_NAMESPACE; const [updatedVM, setUpdatedVM] = useState(undefined); const [error, setError] = useState(undefined); + const [templateWithGeneratedValues, setTemplateWithGeneratedValues] = useState(template); + + const Form = useMemo(() => { + const withDiskSource = hasCustomizableSource(template); + + if (withDiskSource) { + return CustomizeFormWithStorage; + } else { + return CustomizeForm; + } + }, [template]); + useEffect(() => { setError(undefined); @@ -94,6 +71,7 @@ export const TemplatesCatalogDrawerPanel: FC = }, }) .then((processedTemplate) => { + setTemplateWithGeneratedValues(processedTemplate); updateVMCPUMemory( vmNamespace, updateVM, @@ -121,106 +99,25 @@ export const TemplatesCatalogDrawerPanel: FC = - - - {t('Operating system')} - {displayName} - - - {t('Workload type')} - - {WORKLOADS_LABELS[workload] ?? t('Other')}{' '} - {isDefaultTemplate && t('(default)')} - - - - {t('Description')} - - {} - - - - {t('Documentation')} - - {documentationUrl ? ( - } - iconPosition="right" - isInline - isSmall - variant="link" - > - - {t('Refer to documentation')} - - - ) : ( - notAvailable - )} - - - - + - - - } - onEditClick={() => - createModal(({ isOpen, onClose }) => ( - - )) - } - descriptionData={} - descriptionHeader={t('CPU | Memory')} - isEdit - isPopover - /> - - - {t('Network interfaces')} - {` (${networks.length})`} - - - - - - - - {t('Disks')} - {` (${disks.length})`} - - - - - - - - {t('Hardware devices')} - {` (${hardwareDevicesCount})`} - - - - - - + + + + + + {error && ( diff --git a/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerRightColumn.tsx b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerRightColumn.tsx new file mode 100644 index 0000000000..f360efce49 --- /dev/null +++ b/src/views/catalog/templatescatalog/components/TemplatesCatalogDrawer/TemplatesCatalogDrawerRightColumn.tsx @@ -0,0 +1,113 @@ +import React, { FC } from 'react'; +import { useParams } from 'react-router-dom'; + +import { updateVMCPUMemory } from '@catalog/templatescatalog/utils/helpers'; +import { useWizardVMContext } from '@catalog/utils/WizardVMContext'; +import { WizardOverviewDisksTable } from '@catalog/wizard/tabs/overview/components/WizardOverviewDisksTable/WizardOverviewDisksTable'; +import { WizardOverviewNetworksTable } from '@catalog/wizard/tabs/overview/components/WizardOverviewNetworksTable/WizardOverviewNetworksTable'; +import { V1Template } from '@kubevirt-ui/kubevirt-api/console'; +import { V1VirtualMachine } from '@kubevirt-ui/kubevirt-api/kubevirt'; +import CPUDescription from '@kubevirt-utils/components/CPUDescription/CPUDescription'; +import { CpuMemHelperTextResources } from '@kubevirt-utils/components/CPUDescription/utils/utils'; +import CPUMemory from '@kubevirt-utils/components/CPUMemory/CPUMemory'; +import CPUMemoryModal from '@kubevirt-utils/components/CPUMemoryModal/CpuMemoryModal'; +import HardwareDevices from '@kubevirt-utils/components/HardwareDevices/HardwareDevices'; +import { useModal } from '@kubevirt-utils/components/ModalProvider/ModalProvider'; +import VirtualMachineDescriptionItem from '@kubevirt-utils/components/VirtualMachineDescriptionItem/VirtualMachineDescriptionItem'; +import { DEFAULT_NAMESPACE } from '@kubevirt-utils/constants/constants'; +import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; +import { + getTemplateDisks, + getTemplateInterfaces, + getTemplateNetworks, + getTemplateVirtualMachineObject, +} from '@kubevirt-utils/resources/template'; +import { getCPU, getGPUDevices, getHostDevices } from '@kubevirt-utils/resources/vm'; +import { + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, +} from '@patternfly/react-core'; + +type TemplatesCatalogDrawerLeftColumnProps = { + setUpdatedVM: React.Dispatch>; + template: V1Template; + updatedVM: V1VirtualMachine; +}; + +const TemplatesCatalogDrawerRightColumn: FC = ({ + setUpdatedVM, + template, + updatedVM, +}) => { + const { t } = useKubevirtTranslation(); + const { createModal } = useModal(); + const { updateVM } = useWizardVMContext(); + const { ns } = useParams<{ ns: string }>(); + + const disks = getTemplateDisks(template); + const interfaces = getTemplateInterfaces(template); + const networks = getTemplateNetworks(template); + const vmObject = getTemplateVirtualMachineObject(template); + const hostDevicesCount = getHostDevices(vmObject)?.length || 0; + const gpusCount = getGPUDevices(vmObject)?.length || 0; + const hardwareDevicesCount = hostDevicesCount + gpusCount; + + return ( + + + } + onEditClick={() => + createModal(({ isOpen, onClose }) => ( + + )) + } + descriptionData={} + descriptionHeader={t('CPU | Memory')} + isEdit + isPopover + /> + + + {t('Network interfaces')} + {` (${networks.length})`} + + + + + + + + {t('Disks')} + {` (${disks.length})`} + + + + + + + + {t('Hardware devices')} + {` (${hardwareDevicesCount})`} + + + + + + + ); +}; + +export default TemplatesCatalogDrawerRightColumn; diff --git a/src/views/catalog/wizard/Wizard.tsx b/src/views/catalog/wizard/Wizard.tsx index 8712ca1672..df7dfdb717 100644 --- a/src/views/catalog/wizard/Wizard.tsx +++ b/src/views/catalog/wizard/Wizard.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { FC } from 'react'; import { useParams } from 'react-router-dom'; import { SidebarEditorProvider } from '@kubevirt-utils/components/SidebarEditor/SidebarEditorContext'; @@ -14,7 +14,7 @@ import { wizardNavPages } from './tabs'; import './Wizard.scss'; -const Wizard: React.FC = () => { +const Wizard: FC = () => { const { ns } = useParams<{ ns: string }>(); const { vm } = useWizardVMContext();
{description}