From f327fd35ca3af07a1a01cf54377d6abb5162fee7 Mon Sep 17 00:00:00 2001 From: Gowtham Shanmugasundaram Date: Tue, 27 Aug 2024 14:26:13 +0530 Subject: [PATCH] UI change for creation of pvc label selector for managed applications Signed-off-by: Gowtham Shanmugasundaram --- locales/en/plugin__odf-console.json | 9 +- .../helper/assign-policy-view-footer.tsx | 97 +++++++++++++++---- .../helper/pvc-details-wizard-content.tsx | 57 ++++++++--- .../parsers/application-set-parser.spec.tsx | 2 +- .../parsers/subscription-parser.spec.tsx | 2 +- 5 files changed, 128 insertions(+), 39 deletions(-) diff --git a/locales/en/plugin__odf-console.json b/locales/en/plugin__odf-console.json index 56dad42df..0ce5b7c17 100644 --- a/locales/en/plugin__odf-console.json +++ b/locales/en/plugin__odf-console.json @@ -328,13 +328,18 @@ "<0>Application: {getName(applicaitonInfo)} (Namespace: {getNamespace(applicaitonInfo)})": "<0>Application: {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", @@ -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.", @@ -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", diff --git a/packages/mco/components/modals/app-manage-policies/helper/assign-policy-view-footer.tsx b/packages/mco/components/modals/app-manage-policies/helper/assign-policy-view-footer.tsx index 63e3dd290..e3b214832 100644 --- a/packages/mco/components/modals/app-manage-policies/helper/assign-policy-view-footer.tsx +++ b/packages/mco/components/modals/app-manage-policies/helper/assign-policy-view-footer.tsx @@ -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, @@ -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); @@ -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 = ({ state, stepIdReached, @@ -64,6 +132,9 @@ export const AssignPolicyViewFooter: React.FC = ({ const canJumpToNext = canJumpToNextStep(stepName, state, t); const validationError = isValidationEnabled && !canJumpToNext; + const message = + (validationError || !!errorMessage) && + getErrorMessage(state, stepName, errorMessage, t); const moveToNextStep = () => { if (canJumpToNext) { @@ -89,26 +160,16 @@ export const AssignPolicyViewFooter: React.FC = ({ return ( <> - {validationError && ( + {!!message && ( + > + {message?.children} + )} - {!!errorMessage && - stepName === - AssignPolicyStepsNames(t)[AssignPolicySteps.ReviewAndAssign] && ( - - )} + {loaded && !error ? ( diff --git a/packages/mco/components/modals/app-manage-policies/parsers/application-set-parser.spec.tsx b/packages/mco/components/modals/app-manage-policies/parsers/application-set-parser.spec.tsx index ec2fbc789..1cbf57c0b 100644 --- a/packages/mco/components/modals/app-manage-policies/parsers/application-set-parser.spec.tsx +++ b/packages/mco/components/modals/app-manage-policies/parsers/application-set-parser.spec.tsx @@ -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(); diff --git a/packages/mco/components/modals/app-manage-policies/parsers/subscription-parser.spec.tsx b/packages/mco/components/modals/app-manage-policies/parsers/subscription-parser.spec.tsx index 03f3385d4..1a3fb2f4d 100644 --- a/packages/mco/components/modals/app-manage-policies/parsers/subscription-parser.spec.tsx +++ b/packages/mco/components/modals/app-manage-policies/parsers/subscription-parser.spec.tsx @@ -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();