Skip to content

Commit

Permalink
Bulk unassign data policy for application
Browse files Browse the repository at this point in the history
Signed-off-by: Gowtham Shanmugasundaram <[email protected]>
  • Loading branch information
GowthamShanmugam committed Jun 19, 2023
1 parent d0202d1 commit 15ced70
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 2 deletions.
6 changes: 6 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@
"Select the subscriptions groups you wish to replicate via": "Select the subscriptions groups you wish to replicate via",
"Manage Policy": "Manage Policy",
"Assign policy to protect the application and ensure quick recovery. Unassign policy from an application when they no longer require to be managed.": "Assign policy to protect the application and ensure quick recovery. Unassign policy from an application when they no longer require to be managed.",
"Manage list view alert": "Manage list view alert",
"Unable to unassign selected policies for the application.": "Unable to unassign selected policies for the application.",
"Selected policies ({{ count }}) will be removed for your application. This may have some affect on other applications sharing the placement._one": "Selected policies ({{ count }}) will be removed for your application. This may have some affect on other applications sharing the placement.",
"Selected policies ({{ count }}) will be removed for your application. This may have some affect on other applications sharing the placement._other": "Selected policies ({{ count }}) will be removed for your application. This may have some affect on other applications sharing the placement.",
"Confirm unassign": "Confirm unassign",
"Selected policies unassigned for the application.": "Selected policies unassigned for the application.",
"Policy type": "Policy type",
"Assigned on": "Assigned on",
"View configurations": "View configurations",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as React from 'react';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { TFunction } from 'i18next';
import {
Alert,
AlertVariant,
Button,
ButtonVariant,
} from '@patternfly/react-core';
import { ModalActionContext, PolicyListViewState } from '../utils/reducer';

const AlertMessage: React.FC<AlertMessageType> = (props) => {
const { title, variant, children, t } = props;
return (
<Alert
area-label={t('Manage list view alert')}
title={title}
variant={variant}
isInline
className="odf-alert"
>
{children}
</Alert>
);
};

export const ListViewMessages: React.FC<ListViewMessagesType> = (props) => {
const { t } = useCustomTranslation();
const modalActionContext = props?.state?.modalActionContext;

return (
<React.Fragment>
{(!!props?.state?.error && (
<AlertMessage
title={t('Unable to unassign selected policies for the application.')}
variant={AlertVariant.danger}
t={t}
>
{props?.state?.error}
</AlertMessage>
)) ||
(modalActionContext === ModalActionContext.UN_ASSIGNING_POLICIES && (
<AlertMessage
title={t(
'Selected policies ({{ count }}) will be removed for your application. This may have some affect on other applications sharing the placement.',
{ count: props?.state?.policies?.length }
)}
variant={AlertVariant.warning}
t={t}
>
<Button variant={ButtonVariant.link} onClick={props?.OnConfirm}>
{t('Confirm unassign')}{' '}
</Button>
<Button variant={ButtonVariant.link} onClick={props?.OnCancel}>
{t('Cancel')}
</Button>
</AlertMessage>
)) ||
(modalActionContext ===
ModalActionContext.UN_ASSIGN_POLICIES_SUCCEEDED && (
<AlertMessage
title={t('Selected policies unassigned for the application.')}
variant={AlertVariant.success}
t={t}
/>
))}
</React.Fragment>
);
};

export type ListViewMessagesType = {
state: PolicyListViewState;
OnCancel: () => void;
OnConfirm: () => void;
};

type AlertMessageType = {
title: string;
variant: AlertVariant;
children?: React.ReactNode;
t: TFunction;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import { Text } from '@patternfly/react-core';

export const ViewPanelHeader: React.FC<ViewPanelHeaderProps> = ({
title,
children,
}) => {
return (
<div className="mco-manage-policies__panelHeader">
<Text component="h3"> {title} </Text>
{children}
</div>
);
};

export const ViewPanelContent: React.FC<ViewPanelContentProps> = ({
children,
}) => {
return (
<div className="mco-manage-policies__panelContent--col-padding">
{children}
</div>
);
};

type ViewPanelHeaderProps = {
title: React.ReactNode;
children?: React.ReactNode;
};

type ViewPanelContentProps = {
children?: React.ReactNode;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { screen, render, fireEvent } from '@testing-library/react';
import { screen, render, fireEvent, waitFor } from '@testing-library/react';
import { PLACEMENT_REF_LABEL } from '../../../../constants';
import { ArgoApplicationSetResourceKind } from '../../../../hooks';
import { DisasterRecoveryResourceKind } from '../../../../hooks/disaster-recovery';
Expand Down Expand Up @@ -191,6 +191,9 @@ jest.mock('@odf/mco/hooks/argo-application-set', () => ({
__esModule: true,
useArgoApplicationSetResourceWatch: () => [appResources, true, ''],
}));
jest.mock('../utils/k8s-utils', () => ({
unAssignPromises: jest.fn(() => [Promise.resolve({ data: {} })]),
}));

describe('ApplicationSet manage data policy modal', () => {
beforeEach(async () => {
Expand Down Expand Up @@ -248,4 +251,25 @@ describe('ApplicationSet manage data policy modal', () => {
expect(screen.getByText('Not found')).toBeInTheDocument();
fireEvent.change(searchBox, { target: { value: '' } });
});

test('Bulk unassign policy action test', async () => {
// Select all policy
fireEvent.click(screen.getByLabelText('Select all rows'));
// Check primary action is disabled
expect(screen.getByText('Assign policy')).toBeDisabled();
// Check secondary action is enabled
expect(screen.getByLabelText('Select input')).toBeEnabled();
// Trigger bulk unassign
fireEvent.click(screen.getByLabelText('Select input'));
fireEvent.click(screen.getByText('Unassign policy'));
expect(screen.getByText('Cancel')).toBeInTheDocument();
expect(screen.getByText('Confirm unassign')).toBeInTheDocument();
await waitFor(() => {
fireEvent.click(screen.getByText('Confirm unassign'));
});
// Confirm unassign is successful
expect(
screen.getByText('Selected policies unassigned for the application.')
).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ActionDropdown } from '@odf/shared/dropdown/action-dropdown';
import { ModalBody } from '@odf/shared/modals/Modal';
import { getName } from '@odf/shared/selectors';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { getErrorMessage } from '@odf/shared/utils';
import { TFunction } from 'i18next';
import {
Button,
Expand All @@ -14,15 +15,17 @@ import {
ToolbarItem,
Text,
} from '@patternfly/react-core';
import { ListViewMessages } from './helper/messages';
import { PolicyListViewTable } from './helper/policy-list-view-table';
import { unAssignPromises } from './utils/k8s-utils';
import {
ManagePolicyStateType,
ModalActionContext,
ModalViewContext,
PolicyListViewState,
} from './utils/reducer';
import { ManagePolicyStateAction } from './utils/reducer';
import { DataPolicyType } from './utils/types';
import { DataPolicyType, DRPlacementControlType } from './utils/types';
import './style.scss';

const INITIAL_PAGE_NUMBER = 1;
Expand Down Expand Up @@ -87,6 +90,7 @@ export const PolicyListView: React.FC<PolicyListViewProps> = (props) => {
dispatch,
setModalContext,
setModalActionContext,
setError,
} = props;
const [start, end] = getRange(page, perPage);
const policies = filterPolicies(dataPolicyInfo, searchText);
Expand All @@ -109,6 +113,27 @@ export const PolicyListView: React.FC<PolicyListViewProps> = (props) => {
payload: policy,
});

const unAssignPolicies = () => {
// unassign DRPolicy
const drpcs: DRPlacementControlType[] = state.policies?.reduce(
(acc, policy) => [...acc, ...policy?.placementControInfo],
[]
);
const promises = unAssignPromises(drpcs);
Promise.all(promises)
.then(() => {
dispatch({
type: ManagePolicyStateType.SET_SELECTED_POLICIES,
context: ModalViewContext.POLICY_LIST_VIEW,
payload: [],
});
setModalActionContext(ModalActionContext.UN_ASSIGN_POLICIES_SUCCEEDED);
})
.catch((error) => {
setError(getErrorMessage(error));
});
};

return (
<ModalBody>
<div className="mco-manage-policies__header">
Expand All @@ -130,6 +155,11 @@ export const PolicyListView: React.FC<PolicyListViewProps> = (props) => {
t={t}
/>
<div className="mco-manage-policies__col-padding">
<ListViewMessages
state={state}
OnCancel={() => setModalActionContext(null)}
OnConfirm={unAssignPolicies}
/>
<PolicyListViewTable
policies={paginatedPolicies}
selectedPolicies={state.policies}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ACMPlacementModel, DRPlacementControlModel } from '@odf/mco//models';
import {
HUB_CLUSTER_NAME,
PROTECTED_APP_ANNOTATION_WO_SLASH,
} from '@odf/mco/constants';
import { getName, getNamespace } from '@odf/shared/selectors';
import { K8sResourceKind } from '@odf/shared/types';
import { k8sDelete, k8sPatch } from '@openshift-console/dynamic-plugin-sdk';
import { DRPlacementControlType } from './types';

export const unAssignPromises = (drpcs: DRPlacementControlType[]) => {
const promises: Promise<K8sResourceKind>[] = [];
const patch = [
{
op: 'remove',
path: `/metadata/annotations/${PROTECTED_APP_ANNOTATION_WO_SLASH}`,
},
];

drpcs?.forEach((drpc) => {
promises.push(
k8sPatch({
model: ACMPlacementModel,
resource: {
metadata: {
name: getName(drpc?.placementInfo),
namespace: getNamespace(drpc?.placementInfo),
},
},
data: patch,
cluster: HUB_CLUSTER_NAME,
})
);

promises.push(
k8sDelete({
model: DRPlacementControlModel,
resource: {
metadata: {
name: getName(drpc),
namespace: getNamespace(drpc),
},
},
requestInit: null,
json: null,
cluster: HUB_CLUSTER_NAME,
})
);
});

return promises;
};

0 comments on commit 15ced70

Please sign in to comment.