Skip to content

Commit

Permalink
UI support for consistency group - techpreview
Browse files Browse the repository at this point in the history
Signed-off-by: Gowtham Shanmugasundaram <[email protected]>
  • Loading branch information
GowthamShanmugam committed Dec 9, 2024
1 parent fdf816d commit c8f0350
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 95 deletions.
3 changes: 3 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@
"{{count}} selected_one": "{{count}} selected",
"{{count}} selected_other": "{{count}} selected",
"Select labels": "Select labels",
"Volume consistency group": "Volume consistency group",
"Enable disaster recovery for volume consistency groups.": "Enable disaster recovery for volume consistency groups.",
"Protect applications deployed across multiple volumes and ensure consistent recovery with volume consistency groups.": "Protect applications deployed across multiple volumes and ensure consistent recovery with volume consistency groups.",
"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.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export enum EnrollDiscoveredApplicationStateType {
SET_POLICY = 'REPLICATION/SET_POLICY',
SET_K8S_RESOURCE_REPLICATION_INTERVAL = 'REPLICATION/SET_K8S_RESOURCE_REPLICATION_INTERVAL',
SET_NAME = 'NAMESPACE/SET_NAME',
ENABLE_CONSISTENCY_GROUP = 'CONFIGURATION/ENABLE_CONSISTENCY_GROUP',
}

export type EnrollDiscoveredApplicationState = {
Expand All @@ -45,6 +46,7 @@ export type EnrollDiscoveredApplicationState = {
k8sResourceLabelExpressions: MatchExpression[];
pvcLabelExpressions: MatchExpression[];
};
isConsistencyGroupEnabled: boolean;
};
replication: {
drPolicy: DRPolicyKind;
Expand Down Expand Up @@ -75,6 +77,7 @@ export const initialState: EnrollDiscoveredApplicationState = {
k8sResourceLabelExpressions: [],
pvcLabelExpressions: [],
},
isConsistencyGroupEnabled: false,
},
replication: {
drPolicy: {},
Expand Down Expand Up @@ -119,6 +122,10 @@ export type EnrollDiscoveredApplicationAction =
| {
type: EnrollDiscoveredApplicationStateType.SET_NAME;
payload: string;
}
| {
type: EnrollDiscoveredApplicationStateType.ENABLE_CONSISTENCY_GROUP;
payload: boolean;
};

export const reducer: EnrollReducer = (state, action) => {
Expand Down Expand Up @@ -225,6 +232,15 @@ export const reducer: EnrollReducer = (state, action) => {
},
};
}
case EnrollDiscoveredApplicationStateType.ENABLE_CONSISTENCY_GROUP: {
return {
...state,
configuration: {
...state.configuration,
isConsistencyGroupEnabled: action.payload,
},
};
}
default:
throw new TypeError(`${action} is not a valid reducer action`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { ConsistencyGroupCheckBox } from '@odf/mco/components/modals/app-manage-policies/helper/pvc-details-wizard-content';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import {
Alert,
Expand Down Expand Up @@ -32,7 +33,12 @@ export const Configuration: React.FC<ConfigurationProps> = ({
const { t } = useCustomTranslation();

const { namespaces, clusterName } = state.namespace;
const { protectionMethod, recipe, resourceLabels } = state.configuration;
const {
protectionMethod,
recipe,
resourceLabels,
isConsistencyGroupEnabled,
} = state.configuration;

const setProtectionMethod = (_unUsed, event) => {
dispatch({
Expand All @@ -41,6 +47,13 @@ export const Configuration: React.FC<ConfigurationProps> = ({
});
};

const consistencyGroupOnChange = (checked: boolean) => {
dispatch({
type: EnrollDiscoveredApplicationStateType.ENABLE_CONSISTENCY_GROUP,
payload: checked,
});
};

return (
<Form maxWidth="58rem">
<FormSection title={t('Configure definition')}>
Expand Down Expand Up @@ -121,6 +134,10 @@ export const Configuration: React.FC<ConfigurationProps> = ({
dispatch={dispatch}
/>
)}
<ConsistencyGroupCheckBox
isConsistencyGroupEnabled={isConsistencyGroupEnabled}
onChange={consistencyGroupOnChange}
/>
</FormSection>
</Form>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export const createSteps = (
isValidationEnabled={isValidationEnabled}
dispatch={dispatch}
protectedPVCSelectors={protectedPVCSelectors}
isConsistencyGroupEnabled={
state.persistentVolumeClaim.isConsistencyGroupEnabled
}
/>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@odf/mco/constants';
import { useACMSafeFetch } from '@odf/mco/hooks/acm-safe-fetch';
import { SearchResult } from '@odf/mco/types';
import { TechPreviewBadge } from '@odf/shared';
import { MultiSelectDropdown } from '@odf/shared/dropdown/multiselectdropdown';
import { SingleSelectDropdown } from '@odf/shared/dropdown/singleselectdropdown';
import { StatusBox } from '@odf/shared/generic/status-box';
Expand All @@ -32,6 +33,7 @@ import {
GridItem,
Popover,
ButtonVariant,
Checkbox,
} from '@patternfly/react-core';
import { MinusCircleIcon } from '@patternfly/react-icons';
import { queryAppWorkloadPVCs } from '../../../../utils/acm-search-queries';
Expand Down Expand Up @@ -245,108 +247,145 @@ const PairElement: React.FC<PairElementProps> = ({
);
};

export const PVCDetailsWizardContent: React.FC<PVCDetailsWizardContentProps> =
({
pvcSelectors,
unProtectedPlacements,
workloadNamespace,
isValidationEnabled,
protectedPVCSelectors,
dispatch,
}) => {
export const ConsistencyGroupCheckBox: React.FC<ConsistencyGroupCheckBoxProps> =
({ isConsistencyGroupEnabled, onChange }) => {
const { t } = useCustomTranslation();

// To update placement and label info
const selectedPVCSelectors = React.useMemo(
() => _.cloneDeep(pvcSelectors) || [],
[pvcSelectors]
return (
<FormGroup
label={t('Volume consistency group')}
labelIcon={<TechPreviewBadge />}
>
<Checkbox
label={t('Enable disaster recovery for volume consistency groups.')}
description={t(
'Protect applications deployed across multiple volumes and ensure consistent recovery with volume consistency groups.'
)}
isChecked={isConsistencyGroupEnabled}
onChange={(_event, checked: boolean) => onChange(checked)}
id="cg-heckbox"
name="cg-heckbox"
/>
</FormGroup>
);
};

// Selected placement and labels
const [tags, setTags] = React.useState<TagsType>(
getPlacementTags([...protectedPVCSelectors, ...selectedPVCSelectors])
);
export const PVCDetailsWizardContent: React.FC<PVCDetailsWizardContentProps> = (
props
) => {
const { isConsistencyGroupEnabled, dispatch } = props;
const consistencyGroupOnChange = (checked: boolean) => {
dispatch({
type: ManagePolicyStateType.ENABLE_CONSISTENCY_GROUP,
context: ModalViewContext.ASSIGN_POLICY_VIEW,
payload: checked,
});
};
return (
<Form>
<PVCLabelSelector {...props} />
<ConsistencyGroupCheckBox
isConsistencyGroupEnabled={isConsistencyGroupEnabled}
onChange={consistencyGroupOnChange}
/>
</Form>
);
};

// ACM search proxy api call
const searchQuery = React.useMemo(
() =>
queryAppWorkloadPVCs(
workloadNamespace,
getClusterNamesFromPlacements(unProtectedPlacements)
),
[unProtectedPlacements, workloadNamespace]
);
const [searchResult, error, loaded] = useACMSafeFetch(searchQuery);
export const PVCLabelSelector: React.FC<PVCLabelSelectorProps> = ({
pvcSelectors,
unProtectedPlacements,
workloadNamespace,
isValidationEnabled,
protectedPVCSelectors,
dispatch,
}) => {
const { t } = useCustomTranslation();

// All labels
const labels: string[] = React.useMemo(
() => getLabelsFromSearchResult(searchResult),
[searchResult]
);
// To update placement and label info
const selectedPVCSelectors = React.useMemo(
() => _.cloneDeep(pvcSelectors) || [],
[pvcSelectors]
);

// All unprotected placements
const unProtectedPlacementNames: string[] =
unProtectedPlacements.map(getName);
// Selected placement and labels
const [tags, setTags] = React.useState<TagsType>(
getPlacementTags([...protectedPVCSelectors, ...selectedPVCSelectors])
);

// All protected placements
const protectedPlacementNames: string[] = protectedPVCSelectors.map(
(pvcSelector) => pvcSelector.placementName
);
// ACM search proxy api call
const searchQuery = React.useMemo(
() =>
queryAppWorkloadPVCs(
workloadNamespace,
getClusterNamesFromPlacements(unProtectedPlacements)
),
[unProtectedPlacements, workloadNamespace]
);
const [searchResult, error, loaded] = useACMSafeFetch(searchQuery);

return (
<Form>
<FormGroup>
<span>
{t(
'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, '
)}
</span>
<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>
</FormGroup>
{loaded && !error ? (
<LazyNameValueEditor
nameValuePairs={tags}
updateParentData={({ nameValuePairs }) => {
setTags(nameValuePairs);
dispatch({
type: ManagePolicyStateType.SET_PVC_SELECTORS,
context: ModalViewContext.ASSIGN_POLICY_VIEW,
payload: getPVCSelectors(
nameValuePairs,
protectedPlacementNames
),
});
}}
PairElementComponent={PairElement}
nameString={t('Application resource')}
valueString={t('PVC label selector')}
addString={t('Add application resource')}
extraProps={{
unProtectedPlacementNames,
labels,
tags,
isValidationEnabled,
protectedPlacementNames,
}}
className="co-required mco-manage-policies__nameValue--weight"
/>
) : (
<StatusBox loaded={loaded} loadError={error} />
)}
</Form>
);
};
// All labels
const labels: string[] = React.useMemo(
() => getLabelsFromSearchResult(searchResult),
[searchResult]
);

// All unprotected placements
const unProtectedPlacementNames: string[] =
unProtectedPlacements.map(getName);

// All protected placements
const protectedPlacementNames: string[] = protectedPVCSelectors.map(
(pvcSelector) => pvcSelector.placementName
);

return (
<>
<FormGroup>
<span>
{t(
'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, '
)}
</span>
<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>
</FormGroup>
{loaded && !error ? (
<LazyNameValueEditor
nameValuePairs={tags}
updateParentData={({ nameValuePairs }) => {
setTags(nameValuePairs);
dispatch({
type: ManagePolicyStateType.SET_PVC_SELECTORS,
context: ModalViewContext.ASSIGN_POLICY_VIEW,
payload: getPVCSelectors(nameValuePairs, protectedPlacementNames),
});
}}
PairElementComponent={PairElement}
nameString={t('Application resource')}
valueString={t('PVC label selector')}
addString={t('Add application resource')}
extraProps={{
unProtectedPlacementNames,
labels,
tags,
isValidationEnabled,
protectedPlacementNames,
}}
className="co-required mco-manage-policies__nameValue--weight"
/>
) : (
<StatusBox loaded={loaded} loadError={error} />
)}
</>
);
};

type TagsType = (string | string[] | number)[][];

Expand All @@ -358,11 +397,20 @@ type ExtraProps = {
protectedPlacementNames: string[];
};

type PVCDetailsWizardContentProps = {
type PVCLabelSelectorProps = {
pvcSelectors: PVCSelectorType[];
unProtectedPlacements: PlacementType[];
workloadNamespace: string;
isValidationEnabled: boolean;
dispatch: React.Dispatch<ManagePolicyStateAction>;
protectedPVCSelectors: PVCSelectorType[];
isConsistencyGroupEnabled: boolean;
};

type ConsistencyGroupCheckBoxProps = {
isConsistencyGroupEnabled: boolean;
onChange: (checked: boolean) => void;
};

type PVCDetailsWizardContentProps = PVCLabelSelectorProps &
Omit<ConsistencyGroupCheckBoxProps, 'onChange'>;
Loading

0 comments on commit c8f0350

Please sign in to comment.