Skip to content

Commit

Permalink
UI change for creation of pvc label selector for managed applications
Browse files Browse the repository at this point in the history
Signed-off-by: Gowtham Shanmugasundaram <[email protected]>
  • Loading branch information
GowthamShanmugam committed Aug 30, 2024
1 parent dcd01fc commit f327fd3
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 39 deletions.
9 changes: 6 additions & 3 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,18 @@
"<0>Application:</0> {getName(applicaitonInfo)} (Namespace: {getNamespace(applicaitonInfo)})": "<0>Application:</0> {getName(applicaitonInfo)} (Namespace: {getNamespace(applicaitonInfo)})",
"Assign policy nav": "Assign policy nav",
"Assign policy content": "Assign policy content",
"Labels must start and end with an alphanumeric character, can consist of lower-case letters, numbers, dots (.), hyphens (-), forward slash (/), underscore(_) and equal to (=)": "Labels must start and end with an alphanumeric character, can consist of lower-case letters, numbers, dots (.), hyphens (-), forward slash (/), underscore(_) and equal to (=)",
"Invalid label selector": "Invalid label selector",
"The selected PVC label selector doesn't meet the label requirements. Choose a valid label selector or create one with the following requirements: {{ message }}": "The selected PVC label selector doesn't meet the label requirements. Choose a valid label selector or create one with the following requirements: {{ message }}",
"Assign": "Assign",
"Delete": "Delete",
"Select a placement": "Select a placement",
"{{count}} selected_one": "{{count}} selected",
"{{count}} selected_other": "{{count}} selected",
"Select labels": "Select labels",
"Use PVC label selectors to effortlessly specify the application resources that need protection.": "Use PVC label selectors to effortlessly specify the application resources that need protection.",
"Use PVC label selectors to effortlessly specify the application resources that need protection. You can also create a custom PVC label selector if one doesn’t exists. For more information, ": "Use PVC label selectors to effortlessly specify the application resources that need protection. You can also create a custom PVC label selector if one doesn’t exists. For more information, ",
"Help": "Help",
"see PVC label selector requirements.": "see PVC label selector requirements.",
"Application resource": "Application resource",
"PVC label selector": "PVC label selector",
"Add application resource": "Add application resource",
Expand Down Expand Up @@ -638,7 +643,6 @@
"Data Foundation's StorageCluster is not available. Try again after the StorageCluster is ready to use.": "Data Foundation's StorageCluster is not available. Try again after the StorageCluster is ready to use.",
"Create storage pool": "Create storage pool",
"Pool creation is not supported for Data Foundation's external RHCS StorageSystem.": "Pool creation is not supported for Data Foundation's external RHCS StorageSystem.",
"Help": "Help",
"StorageClasses": "StorageClasses",
"Last synced": "Last synced",
"Default pool cannot be deleted.": "Default pool cannot be deleted.",
Expand Down Expand Up @@ -1362,7 +1366,6 @@
"Duplicate keys found.": "Duplicate keys found.",
"Edit {{description}}": "Edit {{description}}",
"Invalid label name": "Invalid label name",
"Labels must start and end with an alphanumeric character, can consist of lower-case letters, numbers, dots (.), hyphens (-), forward slash (/), underscore(_) and equal to (=)": "Labels must start and end with an alphanumeric character, can consist of lower-case letters, numbers, dots (.), hyphens (-), forward slash (/), underscore(_) and equal to (=)",
"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.",
"{{description}} for": "{{description}} for",
"Labels for": "Labels for",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ import {
AssignPolicySteps,
AssignPolicyStepsNames,
} from '@odf/mco/constants';
import { requirementFromString } from '@odf/shared/modals';
import { getName } from '@odf/shared/selectors';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { Operator } from '@openshift-console/dynamic-plugin-sdk';
import {
WizardContextType,
WizardContext,
WizardFooter,
} from '@patternfly/react-core/deprecated';
import { TFunction } from 'i18next';
import { Button, Alert, AlertVariant } from '@patternfly/react-core';
import {
Button,
Alert,
AlertVariant,
AlertProps,
} from '@patternfly/react-core';
import {
AssignPolicyViewState,
ModalActionContext,
Expand All @@ -22,9 +29,31 @@ import { DRPolicyType } from '../utils/types';
import '../../../../style.scss';
import '../style.scss';

export const getLabelValidationMessage = (t: TFunction) =>
t(
'Labels must start and end with an alphanumeric character, can consist of lower-case letters, numbers, dots (.), hyphens (-), forward slash (/), underscore(_) and equal to (=)'
);

export const isValidLabelInput = (labels: string[] = []): boolean =>
labels.length
? labels.every((label) => {
const requirement = requirementFromString(label);
// "key" or "key=value" is supported
return (
!!requirement &&
[Operator.Equals, Operator.Exists].includes(
requirement?.operator as Operator
)
);
})
: false;

const isPVCSelectorFound = (pvcSelectors: PVCSelectorType[]) =>
!!pvcSelectors.length &&
!!pvcSelectors.every((pvcSelector) => !!pvcSelector.labels?.length);
!!pvcSelectors.every(
(pvcSelector) =>
!!pvcSelector.placementName && isValidLabelInput(pvcSelector.labels)
);

const isDRPolicySelected = (dataPolicy: DRPolicyType) => !!getName(dataPolicy);

Expand All @@ -43,6 +72,45 @@ const canJumpToNextStep = (
}
};

const getErrorMessage = (
state: AssignPolicyViewState,
stepName: string,
errorMessage: string,
t: TFunction
): AlertProps => {
const defualtMessage = {
title: t(
'1 or more mandatory fields are empty. To proceed, fill in the required information.'
),
variant: AlertVariant.danger,
};
switch (stepName) {
case AssignPolicyStepsNames(t)[AssignPolicySteps.ReviewAndAssign]:
return {
title: errorMessage,
variant: AlertVariant.danger,
};
case AssignPolicyStepsNames(t)[AssignPolicySteps.PersistentVolumeClaim]: {
const { pvcSelectors } = state.persistentVolumeClaim;
const isValidPVCSelector = pvcSelectors.every((pvcSelector) =>
pvcSelector.labels.length ? isValidLabelInput(pvcSelector.labels) : true
);
return !isValidPVCSelector
? {
title: t('Invalid label selector'),
children: t(
"The selected PVC label selector doesn't meet the label requirements. Choose a valid label selector or create one with the following requirements: {{ message }}",
{ message: getLabelValidationMessage(t) }
),
variant: AlertVariant.danger,
}
: defualtMessage;
}
default:
return defualtMessage;
}
};

export const AssignPolicyViewFooter: React.FC<AssignPolicyViewFooterProps> = ({
state,
stepIdReached,
Expand All @@ -64,6 +132,9 @@ export const AssignPolicyViewFooter: React.FC<AssignPolicyViewFooterProps> = ({

const canJumpToNext = canJumpToNextStep(stepName, state, t);
const validationError = isValidationEnabled && !canJumpToNext;
const message =
(validationError || !!errorMessage) &&
getErrorMessage(state, stepName, errorMessage, t);

const moveToNextStep = () => {
if (canJumpToNext) {
Expand All @@ -89,26 +160,16 @@ export const AssignPolicyViewFooter: React.FC<AssignPolicyViewFooterProps> = ({

return (
<>
{validationError && (
{!!message && (
<Alert
title={t(
'1 or more mandatory fields are empty. To proceed, fill in the required information.'
)}
variant={AlertVariant.danger}
title={message.title}
variant={message.variant}
isInline
className="odf-alert mco-manage-policies__alert--margin-left"
/>
>
{message?.children}
</Alert>
)}
{!!errorMessage &&
stepName ===
AssignPolicyStepsNames(t)[AssignPolicySteps.ReviewAndAssign] && (
<Alert
title={errorMessage}
variant={AlertVariant.danger}
isInline
className="odf-alert mco-manage-policies__alert--margin-left"
/>
)}
<WizardFooter>
<Button
isLoading={requestInProgress}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ import {
LazyNameValueEditor,
NameValueEditorPair,
} from '@odf/shared/utils/NameValueEditor';
import { SelectOption, SelectVariant } from '@patternfly/react-core/deprecated';
import {
SelectOption,
SelectVariant,
SelectPosition,
} from '@patternfly/react-core/deprecated';
import * as _ from 'lodash-es';
import {
Button,
Expand All @@ -27,6 +31,8 @@ import {
Text,
Grid,
GridItem,
Popover,
ButtonVariant,
} from '@patternfly/react-core';
import { MinusCircleIcon } from '@patternfly/react-icons';
import { queryAppWorkloadPVCs } from '../../../../utils/acm-search-quries';
Expand All @@ -38,6 +44,10 @@ import {
PVCSelectorType,
} from '../utils/reducer';
import { PlacementType } from '../utils/types';
import {
getLabelValidationMessage,
isValidLabelInput,
} from './assign-policy-view-footer';
import '../../../../style.scss';
import '../style.scss';

Expand Down Expand Up @@ -91,12 +101,16 @@ const getPlacementDropdownOptions = (

const getLabelsDropdownOptions = (
labels: string[],
tags: TagsType,
currIndex: number
) => {
selectedLabels: string[]
): JSX.Element[] => {
// Display labels names except selected from other indexes
const selectedLabels = getLabelsFromTags(tags, currIndex);
return labels.filter((name) => !selectedLabels.includes(name));
return labels.reduce(
(acc, name) =>
!selectedLabels.includes(name)
? [...acc, <SelectOption key={name} value={name} />]
: acc,
[]
);
};

const getPVCSelectors = (
Expand Down Expand Up @@ -167,7 +181,6 @@ const PairElement: React.FC<PairElementProps> = ({
<Grid hasGutter>
<GridItem lg={5} sm={5}>
<FormGroup hasNoPaddingTop isRequired>
{/* Add validation */}
<SingleSelectDropdown
id="placement-selection-dropdown"
selectedKey={selectedPlacement}
Expand All @@ -189,17 +202,14 @@ const PairElement: React.FC<PairElementProps> = ({

<GridItem lg={5} sm={5}>
<FormGroup hasNoPaddingTop isRequired>
{/* Add validation */}
<MultiSelectDropdown
id="labels-selection-dropdown"
selections={selectedLabels}
onChange={onChangeValue}
options={
// Display labels only after placement is selected
!!selectedPlacement
? getLabelsDropdownOptions(labels, tags, index)
: []
}
selectOptions={getLabelsDropdownOptions(
labels,
getLabelsFromTags(tags, index)
)}
placeholderText={
!!selectedLabels?.length
? t('{{count}} selected', { count: selectedLabels?.length })
Expand All @@ -208,9 +218,12 @@ const PairElement: React.FC<PairElementProps> = ({
variant={SelectVariant.checkbox}
required
validated={getValidatedProp(
isValidationEnabled && !selectedLabels?.length
isValidationEnabled && !isValidLabelInput(selectedLabels)
)}
isDisabled={isDisabled}
position={SelectPosition.right}
isCreatable
hasInlineFilter
/>
</FormGroup>
</GridItem>
Expand Down Expand Up @@ -284,8 +297,20 @@ export const PVCDetailsWizardContent: React.FC<PVCDetailsWizardContentProps> =
<FormGroup>
<Text>
{t(
'Use PVC label selectors to effortlessly specify the application resources that need protection.'
'Use PVC label selectors to effortlessly specify the application resources that need protection. You can also create a custom PVC label selector if one doesn’t exists. For more information, '
)}
<Popover
aria-label={t('Help')}
bodyContent={getLabelValidationMessage(t)}
>
<Button
aria-label={t('Help')}
variant={ButtonVariant.link}
isInline
>
{t('see PVC label selector requirements.')}
</Button>
</Popover>
</Text>
</FormGroup>
{loaded && !error ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ describe('ApplicationSet manage disaster recovery modal', () => {
expect(screen.getByText('Back')).toBeEnabled();
// PVC selector
screen.getByText(
'Use PVC label selectors to effortlessly specify the application resources that need protection.'
/Use PVC label selectors to effortlessly specify the application resources that need protection. You can also create a custom PVC label selector if one doesn’t exists. For more information,/i
);
await waitFor(() => {
expect(screen.getByText('Application resource')).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ describe('Subscription manage disaster recovery modal', () => {
expect(screen.getByText('Back')).toBeEnabled();
// PVC selector
screen.getByText(
'Use PVC label selectors to effortlessly specify the application resources that need protection.'
/Use PVC label selectors to effortlessly specify the application resources that need protection. You can also create a custom PVC label selector if one doesn’t exists. For more information/i
);
await waitFor(() => {
expect(screen.getByText('Application resource')).toBeInTheDocument();
Expand Down

0 comments on commit f327fd3

Please sign in to comment.