-
Notifications
You must be signed in to change notification settings - Fork 593
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(feat): Setup create storage system wizard
- Adds Backing Storage step - implements a wizard with [incrementally enabled steps](https://www.patternfly.org/v4/components/wizard/#incrementally-enabled-steps) - This step creates the Storage System for an external Provider other than RHCS on clicking Next. - This step otherwise, allow choosing the backing storage for Storage Cluster. The Storage Cluster is hidden from UI but it is created internally by wizard flow. The creation of storage cluster happens in the last step. - https://issues.redhat.com/browse/ODFE-83 Signed-off-by: Afreen Rahman <afrahman@redhat.com>
- Loading branch information
Afreen Rahman
committed
Jul 7, 2021
1 parent
fe0f165
commit 92b28f0
Showing
17 changed files
with
715 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
...ceph-storage-plugin/src/components/create-storage-system/create-storage-system-footer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import * as React from 'react'; | ||
import { TFunction } from 'i18next'; | ||
import { | ||
WizardFooter, | ||
Button, | ||
WizardContext, | ||
WizardContextType, | ||
Alert, | ||
AlertActionCloseButton, | ||
} from '@patternfly/react-core'; | ||
import { k8sCreate } from '@console/internal/module/k8s'; | ||
import { WizardCommonProps } from './reducer'; | ||
import { createSSPayload } from './payloads'; | ||
import { RHCS, StepsId } from '../../constants/create-storage-system'; | ||
import { StorageSystemModel } from '../../models'; | ||
import './create-storage-system.scss'; | ||
|
||
export const CreateStorageSystemFooter: React.FC<CreateStorageSystemFooterProps> = ({ | ||
t, | ||
dispatch, | ||
state, | ||
}) => { | ||
const { activeStep, onNext, onBack, onClose } = React.useContext<WizardContextType>( | ||
WizardContext, | ||
); | ||
const [inProgress, setInProgress] = React.useState(false); | ||
const [error, setError] = React.useState(''); | ||
const [showErrorAlert, setShowErrorAlert] = React.useState(false); | ||
|
||
const { externalProvider } = state.backingStorage; | ||
|
||
const { id } = activeStep; | ||
|
||
const handleCustomNext = async () => { | ||
if (id === StepsId.BackingStorage && externalProvider !== RHCS) { | ||
setInProgress(true); | ||
const payload = createSSPayload(externalProvider); | ||
try { | ||
await k8sCreate(StorageSystemModel, payload); | ||
dispatch({ | ||
type: 'currentStep/incrementCount', | ||
}); | ||
onNext(); | ||
} catch (err) { | ||
setError(err.message); | ||
setShowErrorAlert(true); | ||
} finally { | ||
setInProgress(false); | ||
} | ||
} else { | ||
dispatch({ | ||
type: 'currentStep/incrementCount', | ||
}); | ||
onNext(); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
{showErrorAlert && ( | ||
<Alert | ||
className="odf-create-storage-system-footer__alert" | ||
variant="danger" | ||
isInline | ||
actionClose={<AlertActionCloseButton onClose={() => setShowErrorAlert(false)} />} | ||
title={t('ceph-storage-plugin~An error occurred')} | ||
> | ||
{error} | ||
</Alert> | ||
)} | ||
<WizardFooter> | ||
<Button | ||
isLoading={inProgress} | ||
isDisabled={inProgress} | ||
variant="primary" | ||
type="submit" | ||
onClick={handleCustomNext} | ||
> | ||
{id === StepsId.ReviewAndCreate | ||
? t('ceph-storage-plugin~Create') | ||
: t('ceph-storage-plugin~Next')} | ||
</Button> | ||
{/* Disabling the back button for the first step (Backing storage) in wizard */} | ||
<Button variant="secondary" onClick={onBack} isDisabled={id === StepsId.BackingStorage}> | ||
{t('ceph-storage-plugin~Back')} | ||
</Button> | ||
<Button variant="link" onClick={onClose}> | ||
{t('ceph-storage-plugin~Cancel')} | ||
</Button> | ||
</WizardFooter> | ||
</> | ||
); | ||
}; | ||
|
||
type CreateStorageSystemFooterProps = WizardCommonProps & { | ||
t: TFunction; | ||
}; |
37 changes: 37 additions & 0 deletions
37
...ceph-storage-plugin/src/components/create-storage-system/create-storage-system-header.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import * as React from 'react'; | ||
import { TFunction } from 'i18next'; | ||
import { | ||
TextVariants, | ||
Text, | ||
TextContent, | ||
Breadcrumb, | ||
BreadcrumbItem, | ||
} from '@patternfly/react-core'; | ||
import './create-storage-system.scss'; | ||
|
||
export const CreateStorageSystemHeader: React.FC<CreateStorageSystemHeaderProps> = ({ | ||
appName, | ||
url, | ||
t, | ||
}) => ( | ||
<div className="odf-create-storage-system__header"> | ||
<Breadcrumb className="odf-create-storage-system__breadcrumb"> | ||
<BreadcrumbItem to={url.replace('/~new', '')}>{appName}</BreadcrumbItem> | ||
<BreadcrumbItem>{t('ceph-storage-plugin~Create StorageSystem')}</BreadcrumbItem> | ||
</Breadcrumb> | ||
<TextContent> | ||
<Text component={TextVariants.h1}>{t('ceph-storage-plugin~Create StorageSystem')}</Text> | ||
<Text component={TextVariants.small}> | ||
{t( | ||
'ceph-storage-plugin~StorageSystem is an entity of OpenShift Data Foundation. It represents all of the required storage and compute resources.', | ||
)} | ||
</Text> | ||
</TextContent> | ||
</div> | ||
); | ||
|
||
type CreateStorageSystemHeaderProps = { | ||
t: TFunction; | ||
appName: string; | ||
url: string; | ||
}; |
3 changes: 3 additions & 0 deletions
3
...eate-storage-system/create-storage-system-steps/backing-storage-step/backing-storage.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.odf-backing-storage__selection--width { | ||
width: 16rem; | ||
} |
168 changes: 168 additions & 0 deletions
168
...reate-storage-system/create-storage-system-steps/backing-storage-step/backing-storage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import * as React from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { TFunction } from 'i18next'; | ||
import { Form, FormSelect, FormSelectOption, FormSelectProps, Radio } from '@patternfly/react-core'; | ||
import { StorageClassDropdown } from '@console/internal/components/utils/storage-class-dropdown'; | ||
import { StorageClassResourceKind } from '@console/internal/module/k8s'; | ||
import './backing-storage.scss'; | ||
import { ExternalProvider } from '../../../../odf-external-providers/types'; | ||
import { ODF_EXTERNAL_PROVIDERS } from '../../../../odf-external-providers/external-providers'; | ||
import { StorageSystemKind } from '../../../../types'; | ||
import { filterSCWithoutNoProv } from '../../../../utils/install'; | ||
import { WizardCommonProps, WizardReducer, WizardState, WizardDispatch } from '../../reducer'; | ||
import { BackingStorageType } from '../../../../constants/create-storage-system'; | ||
|
||
const ExternalSystemSelection: React.FC<ExternalSystemSelectionProps> = ({ | ||
dispatch, | ||
providersList, | ||
selectedProvider, | ||
t, | ||
}) => { | ||
const handleSelection: FormSelectProps['onChange'] = (value) => | ||
dispatch({ | ||
type: 'backingStorage/setExternalProvider', | ||
payload: value, | ||
}); | ||
|
||
return ( | ||
<FormSelect | ||
aria-label={t('ceph-storage-plugin~Select external system from list')} | ||
value={selectedProvider} | ||
className="odf-backing-storage__selection--width" | ||
onChange={handleSelection} | ||
> | ||
{providersList.map((p) => ( | ||
<FormSelectOption key={p.name} value={p.name} label={p.label} /> | ||
))} | ||
</FormSelect> | ||
); | ||
}; | ||
|
||
type ExternalSystemSelectionProps = { | ||
dispatch: React.Dispatch<React.ReducerAction<WizardReducer>>; | ||
selectedProvider: WizardState['backingStorage']['externalProvider']; | ||
providersList: ExternalProvider[]; | ||
t: TFunction; | ||
}; | ||
|
||
const StorageClassSelection: React.FC<StorageClassSelectionProps> = ({ dispatch, selected }) => { | ||
const onStorageClassSelect = (sc: StorageClassResourceKind) => | ||
dispatch({ | ||
type: 'wizard/setStorageClass', | ||
payload: { name: sc?.metadata?.name, provisioner: sc.provisioner }, | ||
}); | ||
return ( | ||
<div className="odf-backing-storage__selection--width"> | ||
<StorageClassDropdown | ||
noSelection | ||
onChange={onStorageClassSelect} | ||
selectedKey={selected.name} | ||
filter={filterSCWithoutNoProv} | ||
data-test="storage-class-dropdown" | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
type StorageClassSelectionProps = { | ||
dispatch: WizardDispatch; | ||
selected: WizardState['storageClass']; | ||
}; | ||
|
||
export const BackingStorage: React.FC<BackingStorageProps> = ({ | ||
state, | ||
dispatch, | ||
hasOCS, | ||
existingStorageSystems, | ||
}) => { | ||
const { t } = useTranslation(); | ||
|
||
const externalProviders = ODF_EXTERNAL_PROVIDERS.filter( | ||
(provider) => !existingStorageSystems.has(provider.kind), | ||
); | ||
|
||
React.useEffect(() => { | ||
/* | ||
Allow pre selecting the "external connection" option instead of the "existing" option | ||
if an OCS Storage System is already created and no external system is created. | ||
*/ | ||
if (hasOCS && externalProviders.length) { | ||
dispatch({ type: 'backingStorage/setType', payload: BackingStorageType.EXTERNAL }); | ||
} | ||
}, [dispatch, externalProviders.length, hasOCS]); | ||
|
||
const { type, externalProvider } = state.backingStorage; | ||
const { storageClass } = state; | ||
|
||
const showExternalSystemSelection = type === BackingStorageType.EXTERNAL; | ||
const showStorageClassSelection = !hasOCS && type === BackingStorageType.EXISTING; | ||
const RADIO_GROUP_NAME = 'backing-storage-radio-group'; | ||
|
||
const onRadioSelect = (_, event) => { | ||
dispatch({ type: 'backingStorage/setType', payload: event.target.value }); | ||
dispatch({ | ||
type: 'currentStep/resetCount', | ||
}); | ||
}; | ||
|
||
return ( | ||
<Form> | ||
<Radio | ||
label={t('ceph-storage-plugin~Use an existing storage class')} | ||
description={t( | ||
'ceph-storage-plugin~Can be used on all platforms except BareMetal. OpenShift Data Foundation will use an infrastructure storage class provided by the hosting platform.', | ||
)} | ||
name={RADIO_GROUP_NAME} | ||
value={BackingStorageType.EXISTING} | ||
isChecked={type === BackingStorageType.EXISTING} | ||
onChange={onRadioSelect} | ||
isDisabled={hasOCS} | ||
body={ | ||
showStorageClassSelection && ( | ||
<StorageClassSelection dispatch={dispatch} selected={storageClass} /> | ||
) | ||
} | ||
id={`bs-${BackingStorageType.EXISTING}`} | ||
/> | ||
<Radio | ||
label={t('ceph-storage-plugin~Create a new storage class using local devices')} | ||
description={t( | ||
'ceph-storage-plugin~Can be used on any platform having nodes with local devices. The infrastructure storage class is provided by Local Storage Operator on top of the local devices.', | ||
)} | ||
name={RADIO_GROUP_NAME} | ||
value={BackingStorageType.LOCAL_DEVICES} | ||
isChecked={type === BackingStorageType.LOCAL_DEVICES} | ||
onChange={onRadioSelect} | ||
isDisabled={hasOCS} | ||
id={`bs-${BackingStorageType.LOCAL_DEVICES}`} | ||
/> | ||
<Radio | ||
label={t('ceph-storage-plugin~Connect a new external storage system')} | ||
description={t( | ||
'ceph-storage-plugin~Can be used to connect an external storage platform to OpenShift Data Foundation.', | ||
)} | ||
name={RADIO_GROUP_NAME} | ||
value={BackingStorageType.EXTERNAL} | ||
isChecked={type === BackingStorageType.EXTERNAL} | ||
onChange={onRadioSelect} | ||
isDisabled={externalProviders.length === 0} | ||
body={ | ||
showExternalSystemSelection && ( | ||
<ExternalSystemSelection | ||
selectedProvider={externalProvider} | ||
dispatch={dispatch} | ||
providersList={externalProviders} | ||
t={t} | ||
/> | ||
) | ||
} | ||
id={`bs-${BackingStorageType.EXTERNAL}`} | ||
/> | ||
</Form> | ||
); | ||
}; | ||
|
||
type BackingStorageProps = WizardCommonProps & { | ||
hasOCS: boolean; | ||
existingStorageSystems: Set<StorageSystemKind['spec']['kind']>; | ||
}; |
Oops, something went wrong.