Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add StorageClass input to 'Add bootable Volume' modal #1016

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions locales/en/plugin__kubevirt-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
"annotation value": "annotation value",
"Annotations": "Annotations",
"Annotations cannot be edited for Red Hat templates": "Annotations cannot be edited for Red Hat templates",
"Annotations for the bootable Volume": "Annotations for the bootable Volume",
"Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects",
"Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. ": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. ",
"Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: <2>http://kubernetes.io/docs/user-guide/annotations</2><3><0>Template</0><1>metadata</1><2>annotations</2></3>": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: <2>http://kubernetes.io/docs/user-guide/annotations</2><3><0>Template</0><1>metadata</1><2>annotations</2></3>",
Expand Down Expand Up @@ -457,7 +456,8 @@
"Info": "Info",
"installation iso of Microsoft Windows 10 ": "installation iso of Microsoft Windows 10 ",
"Installed version": "Installed version",
"InstanceType": "InstanceType",
"Instancetype": "Instancetype",
"Instancetypes": "Instancetypes",
"InstanceTypes": "InstanceTypes",
"Interface": "Interface",
"Interface Type": "Interface Type",
Expand All @@ -476,6 +476,7 @@
"Label selectors let you select Nodes based on the value of one or more labels.": "Label selectors let you select Nodes based on the value of one or more labels.",
"Labels": "Labels",
"Labels cannot be edited for Red Hat templates": "Labels cannot be edited for Red Hat templates",
"Labels for the bootable Volume": "Labels for the bootable Volume",
"Labels help you organize and select resources. Adding labels below will let you query for objects that have similar, overlapping or dissimilar labels.": "Labels help you organize and select resources. Adding labels below will let you query for objects that have similar, overlapping or dissimilar labels.",
"Last {{count}} days' trend": "Last {{count}} days' trend",
"Last {{count}} days' trend_plural": "Last {{count}} days' trend",
Expand Down Expand Up @@ -702,7 +703,6 @@
"Post-copy": "Post-copy",
"Preference": "Preference",
"Preferences": "Preferences",
"Preferred Instancetype": "Preferred Instancetype",
"Preffered": "Preffered",
"Primary live migration network": "Primary live migration network",
"Primary Network": "Primary Network",
Expand Down Expand Up @@ -804,6 +804,7 @@
"Select DataSource to use for automatic image upload.": "Select DataSource to use for automatic image upload.",
"Select InstanceType": "Select InstanceType",
"Select Nodes that must have all the following expressions.": "Select Nodes that must have all the following expressions.",
"Select StorageClass": "Select StorageClass",
"Select workloads that must have all the following expressions.": "Select workloads that must have all the following expressions.",
"Selected StorageClass is different from the default StorageClass": "Selected StorageClass is different from the default StorageClass",
"Selected sysprep": "Selected sysprep",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';

import { IoK8sApiStorageV1StorageClass } from '@kubevirt-ui/kubevirt-api/kubernetes/models';
import Loading from '@kubevirt-utils/components/Loading/Loading';
Expand All @@ -7,19 +7,19 @@ import { modelToGroupVersionKind, StorageClassModel } from '@kubevirt-utils/mode
import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
import { Alert, AlertVariant, FormGroup, Select, SelectVariant } from '@patternfly/react-core';

import { diskReducerActions, DiskReducerActionType } from '../state/actions';

import { FilterSCSelect, getSCSelectOptions } from './utils/Filters';
import { getDefaultStorageClass } from './utils/helpers';

type StorageClassSelectProps = {
storageClass: string;
dispatchDiskState: React.Dispatch<DiskReducerActionType>;
setStorageClassName: (scName: string) => void;
setStorageClassProvisioner?: (scProvisioner: string) => void;
};

const StorageClassSelect: React.FC<StorageClassSelectProps> = ({
storageClass,
dispatchDiskState,
setStorageClassName,
setStorageClassProvisioner,
}) => {
const { t } = useKubevirtTranslation();
const [isOpen, setIsOpen] = useState<boolean>(false);
Expand All @@ -35,38 +35,16 @@ const StorageClassSelect: React.FC<StorageClassSelectProps> = ({
const onSelect = useCallback(
(event: React.MouseEvent<Element, MouseEvent>, selection: string) => {
setShowSCAlert(selection !== defaultSC?.metadata?.name);
dispatchDiskState({ type: diskReducerActions.SET_STORAGE_CLASS, payload: selection });
setStorageClassName(selection);
setIsOpen(false);
const provisioner = storageClasses.find(
(sc) => sc?.metadata?.name === selection,
)?.provisioner;
dispatchDiskState({
type: diskReducerActions.SET_STORAGE_CLASS_PROVISIONER,
payload: provisioner,
});
setStorageClassProvisioner?.(
(storageClasses || []).find((sc) => sc?.metadata?.name === selection)?.provisioner,
);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[storageClasses],
);

// inserting the default storage class as initial value
useEffect(() => {
if (!loaded) {
return;
} else if (storageClasses.length === 0) {
dispatchDiskState({ type: diskReducerActions.SET_STORAGE_CLASS, payload: null });
} else if (!storageClass) {
dispatchDiskState({
type: diskReducerActions.SET_STORAGE_CLASS,
payload: defaultSC?.metadata.name || storageClasses?.[0].metadata.name,
});
dispatchDiskState({
type: diskReducerActions.SET_STORAGE_CLASS_PROVISIONER,
payload: defaultSC?.provisioner || storageClasses?.[0].provisioner,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loaded, storageClass, storageClasses]);
return (
<>
<FormGroup fieldId="storage-class" label={t('StorageClass')}>
Expand All @@ -79,12 +57,12 @@ const StorageClassSelect: React.FC<StorageClassSelectProps> = ({
onSelect={onSelect}
variant={SelectVariant.single}
selections={storageClass}
onFilter={FilterSCSelect(storageClasses, t)}
onFilter={FilterSCSelect(storageClasses)}
hasInlineFilter
maxHeight={200}
direction="up"
placeholderText={t('Select StorageClass')}
>
{getSCSelectOptions(storageClasses, t)}
{getSCSelectOptions(storageClasses)}
</Select>
) : (
<Loading />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as React from 'react';

import { modelToGroupVersionKind } from '@kubevirt-ui/kubevirt-api/console';
import StorageProfileModel from '@kubevirt-ui/kubevirt-api/console/models/StorageProfileModel';
import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
Expand All @@ -18,21 +16,17 @@ type UseStorageProfileClaimPropertySetsValue = {
const useStorageProfileClaimPropertySets = (
storageClassName: string,
): UseStorageProfileClaimPropertySetsValue => {
const watchStorageProfileResource = React.useMemo(
() => ({
groupVersionKind: modelToGroupVersionKind(StorageProfileModel),
isList: false,
name: storageClassName,
}),
[storageClassName],
);
const [storageProfile, loaded, error] = useK8sWatchResource<StorageProfile>({
groupVersionKind: modelToGroupVersionKind(StorageProfileModel),
isList: false,
name: storageClassName,
});

const errorState = !storageClassName || !loaded || error;

const [storageProfile, loaded, error] = useK8sWatchResource<StorageProfile>(
watchStorageProfileResource,
);
const { claimPropertySets } = storageProfile?.status || {};

return { claimPropertySets, loaded, error };
return { claimPropertySets: errorState ? null : claimPropertySets, loaded, error };
};

export default useStorageProfileClaimPropertySets;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { TFunction } from 'i18next';

import { IoK8sApiStorageV1StorageClass } from '@kubevirt-ui/kubevirt-api/kubernetes/models';
import { t } from '@kubevirt-utils/hooks/useKubevirtTranslation';
import { StorageClassModel } from '@kubevirt-utils/models';
import { ResourceLink } from '@openshift-console/dynamic-plugin-sdk';
import { SelectOption } from '@patternfly/react-core';
Expand All @@ -25,7 +25,6 @@ export const FilterPVCSelect = (options: string[]) => {

export const getSCSelectOptions = (
storageClasses: IoK8sApiStorageV1StorageClass[],
t: TFunction,
): React.ReactElement[] => {
return storageClasses?.map((sc) => {
const scName = sc?.metadata?.name;
Expand All @@ -46,7 +45,7 @@ export const getSCSelectOptions = (
});
};

export const FilterSCSelect = (options: IoK8sApiStorageV1StorageClass[], t: TFunction) => {
export const FilterSCSelect = (options: IoK8sApiStorageV1StorageClass[]) => {
return (_, value: string): React.ReactElement[] => {
let newOptions = options;

Expand All @@ -55,6 +54,6 @@ export const FilterSCSelect = (options: IoK8sApiStorageV1StorageClass[], t: TFun
newOptions = options.filter((sc) => regex.test(sc.metadata.name));
}

return getSCSelectOptions(newOptions, t);
return getSCSelectOptions(newOptions);
};
};
12 changes: 11 additions & 1 deletion src/utils/components/DiskModal/DiskModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import NameFormField from './DiskFormFields/NameFormField';
import StorageClassSelect from './DiskFormFields/StorageClassSelect';
import { sourceTypes } from './DiskFormFields/utils/constants';
import VolumeMode from './DiskFormFields/VolumeMode';
import { diskReducerActions } from './state/actions';
import { initialStateDiskForm, initialStateDiskSource } from './state/initialState';
import { diskReducer, diskSourceReducer } from './state/reducers';
import {
Expand Down Expand Up @@ -114,6 +115,7 @@ const DiskModal: React.FC<DiskModalProps> = ({
diskState,
diskSourceState,
createOwnerReference,
resultVolume,
});
const resultDataVolumeTemplate = getDataVolumeTemplate(resultDataVolume);

Expand Down Expand Up @@ -216,7 +218,15 @@ const DiskModal: React.FC<DiskModalProps> = ({
<>
<StorageClassSelect
storageClass={diskState.storageClass}
dispatchDiskState={dispatchDiskState}
setStorageClassName={(scName) =>
dispatchDiskState({ type: diskReducerActions.SET_STORAGE_CLASS, payload: scName })
}
setStorageClassProvisioner={(scProvisioner: string) =>
dispatchDiskState({
type: diskReducerActions.SET_STORAGE_CLASS_PROVISIONER,
payload: scProvisioner,
})
}
/>
<ApplyStorageProfileSettingsCheckbox
diskState={diskState}
Expand Down
11 changes: 10 additions & 1 deletion src/utils/components/DiskModal/EditDiskModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import NameFormField from './DiskFormFields/NameFormField';
import StorageClassSelect from './DiskFormFields/StorageClassSelect';
import { sourceTypes } from './DiskFormFields/utils/constants';
import VolumeMode from './DiskFormFields/VolumeMode';
import { diskReducerActions } from './state/actions';
import { DiskFormState, DiskSourceState } from './state/initialState';
import { diskReducer, diskSourceReducer } from './state/reducers';
import {
Expand Down Expand Up @@ -230,7 +231,15 @@ const EditDiskModal: React.FC<DiskModalProps> = ({
<>
<StorageClassSelect
storageClass={diskState.storageClass}
dispatchDiskState={dispatchDiskState}
setStorageClassName={(scName) =>
dispatchDiskState({ type: diskReducerActions.SET_STORAGE_CLASS, payload: scName })
}
setStorageClassProvisioner={(scProvisioner: string) =>
dispatchDiskState({
type: diskReducerActions.SET_STORAGE_CLASS_PROVISIONER,
payload: scProvisioner,
})
}
/>
<ApplyStorageProfileSettingsCheckbox
diskState={diskState}
Expand Down
3 changes: 2 additions & 1 deletion src/utils/components/DiskModal/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const getDataVolumeFromState = ({
createOwnerReference?: boolean;
}): V1beta1DataVolume => {
const dataVolume = getEmptyVMDataVolumeResource(vm, createOwnerReference);
const dvName = resultVolume?.dataVolume?.name || `uploaded-${diskState.diskName}`;
const dvName = resultVolume?.dataVolume?.name || `${vm?.metadata?.name}-${diskState.diskName}`;

dataVolume.metadata.name = dvName;
dataVolume.spec.storage.resources.requests.storage = diskState.diskSize;
Expand Down Expand Up @@ -174,6 +174,7 @@ export const getDataVolumeFromState = ({
dataVolume.spec.source = {
upload: {},
};
dataVolume.metadata.name = `uploaded-${diskState.diskName}`;
}
return dataVolume;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import './CreateFromInstanceType.scss';

const CreateFromInstanceType: FC<RouteComponentProps<{ ns: string }>> = () => {
const sectionState = useState<INSTANCE_TYPES_SECTIONS>(INSTANCE_TYPES_SECTIONS.SELECT_VOLUME);
const { preferences, instanceTypes, loaded } = useInstanceTypesAndPreferences();
const { preferences, instanceTypes, loaded, loadError } = useInstanceTypesAndPreferences();
return (
<>
<Grid className="co-dashboard-body">
Expand All @@ -31,6 +31,7 @@ const CreateFromInstanceType: FC<RouteComponentProps<{ ns: string }>> = () => {
preferencesNames={(preferences || []).map(getName)}
instanceTypesNames={(instanceTypes || []).map(getName)}
loaded={loaded}
loadError={loadError}
/>
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ export type AddBootableVolumeButtonProps = {
preferencesNames: string[];
instanceTypesNames: string[];
loaded: boolean;
loadError?: any;
};

const AddBootableVolumeButton: FC<AddBootableVolumeButtonProps> = ({
loaded,
preferencesNames,
instanceTypesNames,
loaded,
loadError,
}) => {
const { t } = useKubevirtTranslation();
const { createModal } = useModal();
Expand All @@ -33,7 +35,7 @@ const AddBootableVolumeButton: FC<AddBootableVolumeButtonProps> = ({
}
variant={ButtonVariant.secondary}
isLoading={!loaded}
isDisabled={!loaded}
isDisabled={!loaded || loadError}
>
{t('Add bootable Volume')}
</Button>
Expand Down
Loading