1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-23 00:22:19 +01:00

feat: suggest remove strategy UI (#2321)

* feat: suggest remove strategy UI

* add delete strategy to draft

* refactor: extract hooks

* refactor: consistent fn usage
This commit is contained in:
Mateusz Kwasniewski 2022-11-03 12:26:35 +01:00 committed by GitHub
parent 4937b23e16
commit 147408045b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 152 additions and 24 deletions

View File

@ -1,11 +1,11 @@
import React, { useState } from 'react';
import React, { FC, useState } from 'react';
import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useNavigate } from 'react-router-dom';
import useToast from 'hooks/useToast';
import { formatFeaturePath } from '../FeatureStrategyEdit/FeatureStrategyEdit';
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { Alert } from '@mui/material';
import { Alert, styled, Typography } from '@mui/material';
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
import { DELETE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
@ -13,6 +13,8 @@ import { STRATEGY_FORM_REMOVE_ID } from 'utils/testIds';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { Delete } from '@mui/icons-material';
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
import { useChangeRequestApi } from '../../../../hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
interface IFeatureStrategyRemoveProps {
projectId: string;
@ -23,19 +25,81 @@ interface IFeatureStrategyRemoveProps {
icon?: boolean;
}
export const FeatureStrategyRemove = ({
interface IFeatureStrategyRemoveDialogueProps {
onRemove: (event: React.FormEvent) => Promise<void>;
onClose: () => void;
isOpen: boolean;
}
const RemoveAlert: FC = () => (
<Alert severity="error">
Removing the strategy will change which users receive access to the
feature.
</Alert>
);
const FeatureStrategyRemoveDialogue: FC<
IFeatureStrategyRemoveDialogueProps
> = ({ onRemove, onClose, isOpen }) => {
return (
<Dialogue
title="Are you sure you want to delete this strategy?"
open={isOpen}
primaryButtonText="Remove strategy"
secondaryButtonText="Cancel"
onClick={onRemove}
onClose={onClose}
>
<RemoveAlert />
</Dialogue>
);
};
const MsgContainer = styled('div')(({ theme }) => ({
marginTop: theme.spacing(3),
marginBottom: theme.spacing(1),
}));
const SuggestFeatureStrategyRemoveDialogue: FC<
IFeatureStrategyRemoveDialogueProps
> = ({ onRemove, onClose, isOpen }) => {
return (
<Dialogue
title="Suggest changes"
open={isOpen}
primaryButtonText="Add suggestion to draft"
secondaryButtonText="Cancel"
onClick={onRemove}
onClose={onClose}
>
<RemoveAlert />
<MsgContainer>
<Typography variant="body2" color="text.secondary">
Your suggestion:
</Typography>
</MsgContainer>
<Typography fontWeight="bold">Remove strategy</Typography>
</Dialogue>
);
};
interface IRemoveProps {
projectId: string;
featureId: string;
environmentId: string;
strategyId: string;
}
const useOnRemove = ({
projectId,
featureId,
environmentId,
strategyId,
disabled,
icon,
}: IFeatureStrategyRemoveProps) => {
const [openDialogue, setOpenDialogue] = useState(false);
}: IRemoveProps) => {
const { deleteStrategyFromFeature } = useFeatureStrategyApi();
const { refetchFeature } = useFeature(projectId, featureId);
const { setToastData, setToastApiError } = useToast();
const navigate = useNavigate();
const { refetchFeature } = useFeature(projectId, featureId);
const onRemove = async (event: React.FormEvent) => {
try {
@ -56,6 +120,63 @@ export const FeatureStrategyRemove = ({
setToastApiError(formatUnknownError(error));
}
};
return onRemove;
};
const useOnSuggestRemove = ({
projectId,
featureId,
environmentId,
strategyId,
}: IRemoveProps) => {
const { addChangeRequest } = useChangeRequestApi();
const { setToastData, setToastApiError } = useToast();
const onSuggestRemove = async (event: React.FormEvent) => {
try {
event.preventDefault();
await addChangeRequest(projectId, environmentId, {
action: 'deleteStrategy',
feature: featureId,
payload: {
id: strategyId,
},
});
setToastData({
title: 'Changes added to the draft!',
type: 'success',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};
return onSuggestRemove;
};
export const FeatureStrategyRemove = ({
projectId,
featureId,
environmentId,
strategyId,
disabled,
icon,
}: IFeatureStrategyRemoveProps) => {
const [openDialogue, setOpenDialogue] = useState(false);
const { uiConfig } = useUiConfig();
const suggestChangesEnabled = Boolean(uiConfig?.flags?.changeRequests);
const onRemove = useOnRemove({
featureId,
projectId,
strategyId,
environmentId,
});
const onSuggestRemove = useOnSuggestRemove({
featureId,
projectId,
strategyId,
environmentId,
});
return (
<>
@ -91,19 +212,26 @@ export const FeatureStrategyRemove = ({
</PermissionButton>
}
/>
<Dialogue
title="Are you sure you want to delete this strategy?"
open={openDialogue}
primaryButtonText="Remove strategy"
secondaryButtonText="Cancel"
onClick={onRemove}
<ConditionallyRender
condition={suggestChangesEnabled}
show={
<SuggestFeatureStrategyRemoveDialogue
isOpen={openDialogue}
onClose={() => setOpenDialogue(false)}
>
<Alert severity="error">
Removing the strategy will change which users receive access
to the feature.
</Alert>
</Dialogue>
onRemove={async e => {
await onSuggestRemove(e);
setOpenDialogue(false);
}}
/>
}
elseShow={
<FeatureStrategyRemoveDialogue
isOpen={openDialogue}
onClose={() => setOpenDialogue(false)}
onRemove={onRemove}
/>
}
/>
</>
);
};

View File

@ -4,9 +4,9 @@ interface IChangeRequestsSchema {
feature: string;
action:
| 'updateEnabled'
| 'strategyAdd'
| 'strategyUpdate'
| 'strategyDelete';
| 'addStrategy'
| 'updateStrategy'
| 'deleteStrategy';
payload: string | boolean | object | number;
}