diff --git a/locales/en/plugin__kubevirt-plugin.json b/locales/en/plugin__kubevirt-plugin.json index 0e71189cb..e88e34b2e 100644 --- a/locales/en/plugin__kubevirt-plugin.json +++ b/locales/en/plugin__kubevirt-plugin.json @@ -216,6 +216,7 @@ "Clone": "Clone", "Clone a VirtualMachine": "Clone a VirtualMachine", "Clone existing PVC": "Clone existing PVC", + "Clone in progress": "Clone in progress", "Clone template": "Clone template", "Clone VirtualMachine": "Clone VirtualMachine", "Cloning": "Cloning", diff --git a/src/utils/resources/template/hooks/useVmTemplateSource/utils.ts b/src/utils/resources/template/hooks/useVmTemplateSource/utils.ts index 1d404aca2..bf1cf124a 100644 --- a/src/utils/resources/template/hooks/useVmTemplateSource/utils.ts +++ b/src/utils/resources/template/hooks/useVmTemplateSource/utils.ts @@ -108,6 +108,19 @@ export const getDataSourcePVC = (name: string, ns: string) => export const isDataSourceReady = (dataSource: V1beta1DataSource): boolean => dataSource?.status?.conditions?.some((c) => c.type === 'Ready' && c.status === 'True'); +/** + * a function that returns true if the data source is cloning in progress + * @param dataSource the data source to check if cloning + * @returns true if the data source is in cloning state, false otherwise + */ +export const isDataSourceCloning = (dataSource: V1beta1DataSource): boolean => + dataSource?.status?.conditions?.some( + (c) => + c.type === 'Ready' && + c.status === 'False' && + ['CloneScheduled', 'CloneInProgress'].includes(c?.reason), + ); + /** * update template's boot source storage class * @param template the template to get the boot source from diff --git a/src/views/catalog/templatescatalog/hooks/useAvailableDataSourcesAndPVCs.ts b/src/views/catalog/templatescatalog/hooks/useAvailableDataSourcesAndPVCs.ts index 64c3f8878..bfcc92cba 100644 --- a/src/views/catalog/templatescatalog/hooks/useAvailableDataSourcesAndPVCs.ts +++ b/src/views/catalog/templatescatalog/hooks/useAvailableDataSourcesAndPVCs.ts @@ -7,6 +7,7 @@ import { IoK8sApiCoreV1PersistentVolumeClaim } from '@kubevirt-ui/kubevirt-api/k import { BOOT_SOURCE } from '@kubevirt-utils/resources/template'; import { getTemplateBootSourceType, + isDataSourceCloning, isDataSourceReady, } from '@kubevirt-utils/resources/template/hooks/useVmTemplateSource/utils'; import { @@ -81,14 +82,26 @@ export const useAvailableDataSourcesAndPVCs = ( (watchResource) => watchResource.loaded || watchResource.loadError, ); - const availableDatasources = Object.values(watchDataSources).reduce( + const { availableDatasources, cloneInProgressDatasources } = Object.values( + watchDataSources, + ).reduce( (acc, { data: dataSource }) => { if (isDataSourceReady(dataSource as V1beta1DataSource)) { - acc[`${dataSource?.metadata?.namespace}-${dataSource?.metadata?.name}`] = dataSource; + acc.availableDatasources[ + `${dataSource?.metadata?.namespace}-${dataSource?.metadata?.name}` + ] = dataSource; + return acc; + } + + if (isDataSourceCloning(dataSource)) { + acc.cloneInProgressDatasources[ + `${dataSource?.metadata?.namespace}-${dataSource?.metadata?.name}` + ] = dataSource; + return acc; } return acc; }, - {}, + { availableDatasources: {}, cloneInProgressDatasources: {} }, ); const availablePVCs = new Set( @@ -97,5 +110,5 @@ export const useAvailableDataSourcesAndPVCs = ( ), ); - return { availableDatasources, availablePVCs, loaded }; + return { availableDatasources, cloneInProgressDatasources, availablePVCs, loaded }; }; diff --git a/src/views/templates/list/VirtualMachineTemplatesList.tsx b/src/views/templates/list/VirtualMachineTemplatesList.tsx index 2c9ff2824..81c077ee1 100644 --- a/src/views/templates/list/VirtualMachineTemplatesList.tsx +++ b/src/views/templates/list/VirtualMachineTemplatesList.tsx @@ -33,6 +33,7 @@ const VirtualMachineTemplatesList: React.FC> error, availableTemplatesUID, availableDatasources, + cloneInProgressDatasources, bootSourcesLoaded, } = useTemplatesWithAvailableSource({ namespace, @@ -82,6 +83,7 @@ const VirtualMachineTemplatesList: React.FC> { availableTemplatesUID: Set; availableDatasources: Record; + cloneInProgressDatasources: Record; } > data={filteredData} @@ -90,7 +92,7 @@ const VirtualMachineTemplatesList: React.FC> loadError={error} columns={activeColumns} Row={VirtualMachineTemplatesRow} - rowData={{ availableTemplatesUID, availableDatasources }} + rowData={{ availableTemplatesUID, availableDatasources, cloneInProgressDatasources }} /> diff --git a/src/views/templates/list/components/VirtualMachineTemplatesRow.tsx b/src/views/templates/list/components/VirtualMachineTemplatesRow.tsx index 1277d2495..abc6e2f7d 100644 --- a/src/views/templates/list/components/VirtualMachineTemplatesRow.tsx +++ b/src/views/templates/list/components/VirtualMachineTemplatesRow.tsx @@ -17,9 +17,17 @@ import VirtualMachineTemplatesSource from './VirtualMachineTemplatesSource'; const VirtualMachineTemplatesRow: React.FC< RowProps< V1Template, - { availableTemplatesUID: Set; availableDatasources: Record } + { + availableTemplatesUID: Set; + availableDatasources: Record; + cloneInProgressDatasources: Record; + } > -> = ({ obj, activeColumnIDs, rowData: { availableDatasources, availableTemplatesUID } }) => { +> = ({ + obj, + activeColumnIDs, + rowData: { availableDatasources, cloneInProgressDatasources, availableTemplatesUID }, +}) => { const { t } = useKubevirtTranslation(); const history = useHistory(); @@ -47,6 +55,7 @@ const VirtualMachineTemplatesRow: React.FC< diff --git a/src/views/templates/list/components/VirtualMachineTemplatesSource.tsx b/src/views/templates/list/components/VirtualMachineTemplatesSource.tsx index 9d713fefa..dff491f57 100644 --- a/src/views/templates/list/components/VirtualMachineTemplatesSource.tsx +++ b/src/views/templates/list/components/VirtualMachineTemplatesSource.tsx @@ -5,16 +5,18 @@ import { V1beta1DataSource } from '@kubevirt-ui/kubevirt-api/containerized-data- import { useKubevirtTranslation } from '@kubevirt-utils/hooks/useKubevirtTranslation'; import { getTemplateBootSourceType } from '@kubevirt-utils/resources/template/hooks/useVmTemplateSource/utils'; import { getVMBootSourceLabel } from '@kubevirt-utils/resources/vm/utils/source'; -import { Badge, Split, SplitItem } from '@patternfly/react-core'; +import { Badge, Label, Split, SplitItem } from '@patternfly/react-core'; type VirtualMachineTemplatesSourceProps = { template: V1Template; availableDatasources: Record; + cloneInProgressDatasources: Record; availableTemplatesUID: Set; }; const VirtualMachineTemplatesSource: React.FC = ({ template, availableDatasources, + cloneInProgressDatasources, availableTemplatesUID, }) => { const { t } = useKubevirtTranslation(); @@ -26,6 +28,11 @@ const VirtualMachineTemplatesSource: React.FC {bootSourceLabel} @@ -34,6 +41,11 @@ const VirtualMachineTemplatesSource: React.FC{t('Source available')} )} + {isCloningSource && ( + + + + )} ); }; diff --git a/src/views/templates/list/hooks/useTemplatesWithAvailableSource.ts b/src/views/templates/list/hooks/useTemplatesWithAvailableSource.ts index 9a35a8671..fbb829ec3 100644 --- a/src/views/templates/list/hooks/useTemplatesWithAvailableSource.ts +++ b/src/views/templates/list/hooks/useTemplatesWithAvailableSource.ts @@ -45,6 +45,7 @@ export const useTemplatesWithAvailableSource = ({ }); const { availableDatasources, + cloneInProgressDatasources, availablePVCs, loaded: bootSourcesLoaded, } = useAvailableDataSourcesAndPVCs(templates, loaded); @@ -98,6 +99,7 @@ export const useTemplatesWithAvailableSource = ({ templates: filteredTemplates, availableTemplatesUID, availableDatasources, + cloneInProgressDatasources, loaded, bootSourcesLoaded, error: loadError, @@ -108,6 +110,7 @@ type useTemplatesWithAvailableSourceValues = { templates: V1Template[]; availableTemplatesUID: Set; availableDatasources: Record; + cloneInProgressDatasources: Record; loaded: boolean; bootSourcesLoaded: boolean; error: any;