mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-05 17:53:12 +02:00
fix: strategy remove menu (#3807)
 Menu was hindering the rendering of confirmation dialog. https://linear.app/unleash/issue/1-935/fix-feature-strategy-actions-menu
This commit is contained in:
parent
116c94ae49
commit
149c54b0b3
@ -1,179 +0,0 @@
|
|||||||
import { VFC, useState } from 'react';
|
|
||||||
import { Alert, Typography } from '@mui/material';
|
|
||||||
import BlockIcon from '@mui/icons-material/Block';
|
|
||||||
import TrackChangesIcon from '@mui/icons-material/TrackChanges';
|
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
|
||||||
import { UPDATE_FEATURE_STRATEGY } from '@server/types/permissions';
|
|
||||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
|
||||||
import { useEnableDisable } from './hooks/useEnableDisable';
|
|
||||||
import { useSuggestEnableDisable } from './hooks/useSuggestEnableDisable';
|
|
||||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
import { FeatureStrategyChangeRequestAlert } from 'component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyChangeRequestAlert/FeatureStrategyChangeRequestAlert';
|
|
||||||
import { IDisableEnableStrategyProps } from './IDisableEnableStrategyProps';
|
|
||||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
|
||||||
|
|
||||||
const DisableStrategy: VFC<IDisableEnableStrategyProps> = ({ ...props }) => {
|
|
||||||
const { projectId, environmentId, featureId } = props;
|
|
||||||
const [isDialogueOpen, setDialogueOpen] = useState(false);
|
|
||||||
const { onDisable } = useEnableDisable({ ...props });
|
|
||||||
const { onSuggestDisable } = useSuggestEnableDisable({ ...props });
|
|
||||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
|
||||||
const isChangeRequest = isChangeRequestConfigured(environmentId);
|
|
||||||
const { refetchFeature } = useFeature(projectId, featureId);
|
|
||||||
|
|
||||||
const onClick = (event: React.FormEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if (isChangeRequest) {
|
|
||||||
onSuggestDisable();
|
|
||||||
} else {
|
|
||||||
onDisable();
|
|
||||||
refetchFeature();
|
|
||||||
}
|
|
||||||
setDialogueOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() => setDialogueOpen(true)}
|
|
||||||
projectId={projectId}
|
|
||||||
environmentId={environmentId}
|
|
||||||
permission={UPDATE_FEATURE_STRATEGY}
|
|
||||||
tooltipProps={{
|
|
||||||
title: 'Disable strategy',
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<BlockIcon />
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(props.text)}
|
|
||||||
show={
|
|
||||||
<Typography
|
|
||||||
variant={'body1'}
|
|
||||||
color={'text.secondary'}
|
|
||||||
sx={{ ml: theme => theme.spacing(1) }}
|
|
||||||
>
|
|
||||||
Disable
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</PermissionIconButton>
|
|
||||||
<Dialogue
|
|
||||||
title={
|
|
||||||
isChangeRequest
|
|
||||||
? 'Add disabling strategy to change request?'
|
|
||||||
: 'Are you sure you want to disable this strategy?'
|
|
||||||
}
|
|
||||||
open={isDialogueOpen}
|
|
||||||
primaryButtonText={
|
|
||||||
isChangeRequest ? 'Add to draft' : 'Disable strategy'
|
|
||||||
}
|
|
||||||
secondaryButtonText="Cancel"
|
|
||||||
onClick={onClick}
|
|
||||||
onClose={() => setDialogueOpen(false)}
|
|
||||||
>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={isChangeRequest}
|
|
||||||
show={
|
|
||||||
<FeatureStrategyChangeRequestAlert
|
|
||||||
environment={environmentId}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<Alert severity="error">
|
|
||||||
Disabling the strategy will change which users
|
|
||||||
receive access to the feature.
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Dialogue>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const EnableStrategy: VFC<IDisableEnableStrategyProps> = ({ ...props }) => {
|
|
||||||
const { projectId, environmentId } = props;
|
|
||||||
const [isDialogueOpen, setDialogueOpen] = useState(false);
|
|
||||||
const { onEnable } = useEnableDisable({ ...props });
|
|
||||||
const { onSuggestEnable } = useSuggestEnableDisable({ ...props });
|
|
||||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
|
||||||
const isChangeRequest = isChangeRequestConfigured(environmentId);
|
|
||||||
|
|
||||||
const onClick = (event: React.FormEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if (isChangeRequest) {
|
|
||||||
onSuggestEnable();
|
|
||||||
} else {
|
|
||||||
onEnable();
|
|
||||||
}
|
|
||||||
setDialogueOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() => setDialogueOpen(true)}
|
|
||||||
projectId={projectId}
|
|
||||||
environmentId={environmentId}
|
|
||||||
permission={UPDATE_FEATURE_STRATEGY}
|
|
||||||
tooltipProps={{
|
|
||||||
title: 'Enable strategy',
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<TrackChangesIcon />
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(props.text)}
|
|
||||||
show={
|
|
||||||
<Typography
|
|
||||||
variant={'body1'}
|
|
||||||
color={'text.secondary'}
|
|
||||||
sx={{ ml: theme => theme.spacing(1) }}
|
|
||||||
>
|
|
||||||
Disable
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</PermissionIconButton>
|
|
||||||
<Dialogue
|
|
||||||
title={
|
|
||||||
isChangeRequest
|
|
||||||
? 'Add enabling strategy to change request?'
|
|
||||||
: 'Are you sure you want to enable this strategy?'
|
|
||||||
}
|
|
||||||
open={isDialogueOpen}
|
|
||||||
primaryButtonText={
|
|
||||||
isChangeRequest ? 'Add to draft' : 'Enable strategy'
|
|
||||||
}
|
|
||||||
secondaryButtonText="Cancel"
|
|
||||||
onClick={onClick}
|
|
||||||
onClose={() => setDialogueOpen(false)}
|
|
||||||
>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={isChangeRequest}
|
|
||||||
show={
|
|
||||||
<FeatureStrategyChangeRequestAlert
|
|
||||||
environment={environmentId}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<Alert severity="error">
|
|
||||||
Enabling the strategy will change which users
|
|
||||||
receive access to the feature.
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Dialogue>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DisableEnableStrategy: VFC<IDisableEnableStrategyProps> = ({
|
|
||||||
...props
|
|
||||||
}) =>
|
|
||||||
props.strategy.disabled ? (
|
|
||||||
<EnableStrategy {...props} />
|
|
||||||
) : (
|
|
||||||
<DisableStrategy {...props} />
|
|
||||||
);
|
|
@ -3,7 +3,7 @@ import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFe
|
|||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatFeaturePath } from '../FeatureStrategyEdit/FeatureStrategyEdit';
|
import { formatFeaturePath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
|
||||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
import { Alert, styled, Typography } from '@mui/material';
|
import { Alert, styled, Typography } from '@mui/material';
|
||||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||||
@ -157,7 +157,11 @@ const useOnSuggestRemove = ({
|
|||||||
return onSuggestRemove;
|
return onSuggestRemove;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FeatureStrategyRemove = ({
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* TODO: remove when strategyImprovements flag is removed
|
||||||
|
*/
|
||||||
|
export const LegacyFeatureStrategyRemove = ({
|
||||||
projectId,
|
projectId,
|
||||||
featureId,
|
featureId,
|
||||||
environmentId,
|
environmentId,
|
@ -0,0 +1,201 @@
|
|||||||
|
import React, { FC } 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 '../../../../../../../../FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
|
||||||
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
|
import { Alert, styled, Typography } from '@mui/material';
|
||||||
|
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||||
|
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
||||||
|
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||||
|
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
|
||||||
|
|
||||||
|
interface IFeatureStrategyRemoveProps {
|
||||||
|
projectId: string;
|
||||||
|
featureId: string;
|
||||||
|
environmentId: string;
|
||||||
|
strategyId: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
icon?: boolean;
|
||||||
|
text?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}: IRemoveProps) => {
|
||||||
|
const { deleteStrategyFromFeature } = useFeatureStrategyApi();
|
||||||
|
const { setToastData, setToastApiError } = useToast();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { refetchFeature } = useFeature(projectId, featureId);
|
||||||
|
|
||||||
|
const onRemove = async (event: React.FormEvent) => {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
await deleteStrategyFromFeature(
|
||||||
|
projectId,
|
||||||
|
featureId,
|
||||||
|
environmentId,
|
||||||
|
strategyId
|
||||||
|
);
|
||||||
|
setToastData({
|
||||||
|
title: 'Strategy deleted',
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
refetchFeature();
|
||||||
|
navigate(formatFeaturePath(projectId, featureId));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return onRemove;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useOnSuggestRemove = ({
|
||||||
|
projectId,
|
||||||
|
featureId,
|
||||||
|
environmentId,
|
||||||
|
strategyId,
|
||||||
|
}: IRemoveProps) => {
|
||||||
|
const { addChange } = useChangeRequestApi();
|
||||||
|
const { refetch: refetchChangeRequests } =
|
||||||
|
usePendingChangeRequests(projectId);
|
||||||
|
const { setToastData, setToastApiError } = useToast();
|
||||||
|
const onSuggestRemove = async (event: React.FormEvent) => {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
await addChange(projectId, environmentId, {
|
||||||
|
action: 'deleteStrategy',
|
||||||
|
feature: featureId,
|
||||||
|
payload: {
|
||||||
|
id: strategyId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setToastData({
|
||||||
|
title: 'Changes added to the draft!',
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
await refetchChangeRequests();
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return onSuggestRemove;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DialogStrategyRemove = ({
|
||||||
|
projectId,
|
||||||
|
featureId,
|
||||||
|
environmentId,
|
||||||
|
strategyId,
|
||||||
|
text,
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
}: IFeatureStrategyRemoveProps & {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}) => {
|
||||||
|
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||||
|
|
||||||
|
const onRemove = useOnRemove({
|
||||||
|
featureId,
|
||||||
|
projectId,
|
||||||
|
strategyId,
|
||||||
|
environmentId,
|
||||||
|
});
|
||||||
|
const onSuggestRemove = useOnSuggestRemove({
|
||||||
|
featureId,
|
||||||
|
projectId,
|
||||||
|
strategyId,
|
||||||
|
environmentId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isChangeRequestConfigured(environmentId)) {
|
||||||
|
return (
|
||||||
|
<SuggestFeatureStrategyRemoveDialogue
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={() => onClose()}
|
||||||
|
onRemove={async e => {
|
||||||
|
await onSuggestRemove(e);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FeatureStrategyRemoveDialogue
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={() => onClose()}
|
||||||
|
onRemove={onRemove}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,78 @@
|
|||||||
|
import { Alert } from '@mui/material';
|
||||||
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
|
import { useEnableDisable } from './hooks/useEnableDisable';
|
||||||
|
import { useSuggestEnableDisable } from './hooks/useSuggestEnableDisable';
|
||||||
|
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { FeatureStrategyChangeRequestAlert } from 'component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyChangeRequestAlert/FeatureStrategyChangeRequestAlert';
|
||||||
|
import { IDisableEnableStrategyProps } from './IDisableEnableStrategyProps';
|
||||||
|
|
||||||
|
export const DisableEnableStrategyDialog = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
...props
|
||||||
|
}: IDisableEnableStrategyProps & {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}) => {
|
||||||
|
const { projectId, environmentId } = props;
|
||||||
|
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||||
|
const isChangeRequest = isChangeRequestConfigured(environmentId);
|
||||||
|
const { onSuggestEnable } = useSuggestEnableDisable({ ...props });
|
||||||
|
const { onEnable, onDisable } = useEnableDisable({ ...props });
|
||||||
|
const disabled = Boolean(props.strategy?.disabled);
|
||||||
|
|
||||||
|
const onClick = (event: React.FormEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (isChangeRequest) {
|
||||||
|
if (disabled) {
|
||||||
|
onSuggestEnable();
|
||||||
|
} else {
|
||||||
|
onSuggestEnable();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (disabled) {
|
||||||
|
onEnable();
|
||||||
|
} else {
|
||||||
|
onDisable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialogue
|
||||||
|
title={
|
||||||
|
isChangeRequest
|
||||||
|
? `Add ${
|
||||||
|
disabled ? 'enable' : 'disable'
|
||||||
|
} strategy to change request?`
|
||||||
|
: 'Are you sure you want to enable this strategy?'
|
||||||
|
}
|
||||||
|
open={isOpen}
|
||||||
|
primaryButtonText={
|
||||||
|
isChangeRequest
|
||||||
|
? 'Add to draft'
|
||||||
|
: `${disabled ? 'Enable' : 'Disable'} strategy`
|
||||||
|
}
|
||||||
|
secondaryButtonText="Cancel"
|
||||||
|
onClick={onClick}
|
||||||
|
onClose={() => onClose()}
|
||||||
|
>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={isChangeRequest}
|
||||||
|
show={
|
||||||
|
<FeatureStrategyChangeRequestAlert
|
||||||
|
environment={environmentId}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<Alert severity="error">
|
||||||
|
Enabling the strategy will change which users receive
|
||||||
|
access to the feature.
|
||||||
|
</Alert>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Dialogue>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,149 @@
|
|||||||
|
import React, { SyntheticEvent, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
IconButton,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Tooltip,
|
||||||
|
} from '@mui/material';
|
||||||
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
|
import { IFeatureStrategy } from 'interfaces/strategy';
|
||||||
|
import { DialogStrategyRemove } from './DialogStrategyRemove';
|
||||||
|
import { DisableEnableStrategyDialog } from './DisableEnableStrategyDialog/DisableEnableStrategyDialog';
|
||||||
|
import TrackChangesIcon from '@mui/icons-material/TrackChanges';
|
||||||
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
|
import BlockIcon from '@mui/icons-material/Block';
|
||||||
|
import {
|
||||||
|
DELETE_FEATURE_STRATEGY,
|
||||||
|
UPDATE_FEATURE_STRATEGY,
|
||||||
|
} from '@server/types/permissions';
|
||||||
|
import { useHasProjectEnvironmentAccess } from 'hooks/useHasAccess';
|
||||||
|
import { STRATEGY_FORM_REMOVE_ID } from 'utils/testIds';
|
||||||
|
|
||||||
|
export interface IRemoveStrategyMenuProps {
|
||||||
|
projectId: string;
|
||||||
|
featureId: string;
|
||||||
|
environmentId: string;
|
||||||
|
strategy: IFeatureStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MenuStrategyRemove = ({
|
||||||
|
projectId,
|
||||||
|
strategy,
|
||||||
|
featureId,
|
||||||
|
environmentId,
|
||||||
|
}: IRemoveStrategyMenuProps) => {
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
const [isDisableEnableDialogOpen, setDisableEnableDialogOpen] =
|
||||||
|
useState(false);
|
||||||
|
const [isRemoveDialogOpen, setRemoveDialogOpen] = useState(false);
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
const handleClose = (event: SyntheticEvent) => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
const updateAccess = useHasProjectEnvironmentAccess(
|
||||||
|
UPDATE_FEATURE_STRATEGY,
|
||||||
|
projectId,
|
||||||
|
environmentId
|
||||||
|
);
|
||||||
|
const deleteAccess = useHasProjectEnvironmentAccess(
|
||||||
|
DELETE_FEATURE_STRATEGY,
|
||||||
|
projectId,
|
||||||
|
environmentId
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip title="More actions">
|
||||||
|
<IconButton
|
||||||
|
onClick={handleClick}
|
||||||
|
size="small"
|
||||||
|
aria-controls={open ? 'actions-menu' : undefined}
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={open ? 'true' : undefined}
|
||||||
|
>
|
||||||
|
<MoreVertIcon sx={{ width: 32, height: 32 }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
id="actions-menu"
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
onClick={handleClose}
|
||||||
|
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||||
|
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
strategy.disabled
|
||||||
|
? 'Enable strategy'
|
||||||
|
: 'Disable strategy'
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
placement="left"
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
disabled={!updateAccess}
|
||||||
|
onClick={() => setDisableEnableDialogOpen(true)}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
{strategy.disabled ? (
|
||||||
|
<TrackChangesIcon />
|
||||||
|
) : (
|
||||||
|
<BlockIcon />
|
||||||
|
)}
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>
|
||||||
|
{strategy.disabled ? 'Enable' : 'Disable'}
|
||||||
|
</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="Remove strategy" arrow placement="left">
|
||||||
|
<MenuItem
|
||||||
|
disabled={!deleteAccess}
|
||||||
|
onClick={() => setRemoveDialogOpen(true)}
|
||||||
|
data-testid={STRATEGY_FORM_REMOVE_ID}
|
||||||
|
>
|
||||||
|
<ListItemIcon>
|
||||||
|
<DeleteIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>Remove</ListItemText>
|
||||||
|
</MenuItem>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu>
|
||||||
|
<DisableEnableStrategyDialog
|
||||||
|
isOpen={isDisableEnableDialogOpen}
|
||||||
|
onClose={() => setDisableEnableDialogOpen(false)}
|
||||||
|
projectId={projectId}
|
||||||
|
featureId={featureId}
|
||||||
|
environmentId={environmentId}
|
||||||
|
strategy={strategy}
|
||||||
|
/>
|
||||||
|
<DialogStrategyRemove
|
||||||
|
isOpen={isRemoveDialogOpen}
|
||||||
|
onClose={() => setRemoveDialogOpen(false)}
|
||||||
|
projectId={projectId}
|
||||||
|
featureId={featureId}
|
||||||
|
environmentId={environmentId}
|
||||||
|
strategyId={strategy.id}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MenuStrategyRemove;
|
@ -1,134 +0,0 @@
|
|||||||
import React, { SyntheticEvent } from 'react';
|
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Box,
|
|
||||||
IconButton,
|
|
||||||
ListItem,
|
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
styled,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
} from '@mui/material';
|
|
||||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
|
||||||
import { IFeatureStrategy } from '../../../../../../../../../../interfaces/strategy';
|
|
||||||
import { FeatureStrategyRemove } from '../../../../../../../../FeatureStrategy/FeatureStrategyRemove/FeatureStrategyRemove';
|
|
||||||
import { DisableEnableStrategy } from '../DisableEnableStrategy/DisableEnableStrategy';
|
|
||||||
|
|
||||||
export interface IRemoveStrategyMenuProps {
|
|
||||||
projectId: string;
|
|
||||||
featureId: string;
|
|
||||||
environmentId: string;
|
|
||||||
strategy: IFeatureStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledContainer = styled(ListItem)(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'center',
|
|
||||||
minWidth: 'fit-content',
|
|
||||||
padding: theme.spacing(0, 2),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const RemoveStrategyMenu = ({
|
|
||||||
projectId,
|
|
||||||
strategy,
|
|
||||||
featureId,
|
|
||||||
environmentId,
|
|
||||||
}: IRemoveStrategyMenuProps) => {
|
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
||||||
const open = Boolean(anchorEl);
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
|
||||||
setAnchorEl(event.currentTarget);
|
|
||||||
};
|
|
||||||
const handleClose = (event: SyntheticEvent) => {
|
|
||||||
setAnchorEl(null);
|
|
||||||
event.stopPropagation();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
textAlign: 'center',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tooltip title="More actions">
|
|
||||||
<IconButton
|
|
||||||
onClick={handleClick}
|
|
||||||
size="small"
|
|
||||||
aria-controls={open ? 'actions-menu' : undefined}
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded={open ? 'true' : undefined}
|
|
||||||
>
|
|
||||||
<MoreVertIcon sx={{ width: 32, height: 32 }} />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
|
||||||
<Menu
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
id="actions-menu"
|
|
||||||
open={open}
|
|
||||||
onClose={handleClose}
|
|
||||||
onClick={handleClose}
|
|
||||||
PaperProps={{
|
|
||||||
elevation: 0,
|
|
||||||
sx: {
|
|
||||||
overflow: 'visible',
|
|
||||||
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
|
|
||||||
mt: 1.5,
|
|
||||||
pl: 0.5,
|
|
||||||
minWidth: 'fit-content',
|
|
||||||
justifyContent: 'center',
|
|
||||||
li: {
|
|
||||||
pl: 0,
|
|
||||||
},
|
|
||||||
'&:before': {
|
|
||||||
content: '""',
|
|
||||||
display: 'block',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
right: 14,
|
|
||||||
width: 10,
|
|
||||||
height: 10,
|
|
||||||
bgcolor: 'background.paper',
|
|
||||||
transform: 'translateY(-50%) rotate(45deg)',
|
|
||||||
zIndex: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
|
||||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
|
||||||
>
|
|
||||||
<MenuItem
|
|
||||||
component={() => (
|
|
||||||
<StyledContainer>
|
|
||||||
<DisableEnableStrategy
|
|
||||||
projectId={projectId}
|
|
||||||
featureId={featureId}
|
|
||||||
environmentId={environmentId}
|
|
||||||
strategy={strategy}
|
|
||||||
text
|
|
||||||
/>
|
|
||||||
</StyledContainer>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<MenuItem
|
|
||||||
component={() => (
|
|
||||||
<FeatureStrategyRemove
|
|
||||||
projectId={projectId}
|
|
||||||
featureId={featureId}
|
|
||||||
environmentId={environmentId}
|
|
||||||
strategyId={strategy.id}
|
|
||||||
text
|
|
||||||
icon
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RemoveStrategyMenu;
|
|
@ -6,15 +6,14 @@ import { IFeatureStrategy } from 'interfaces/strategy';
|
|||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
import { UPDATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
|
import { UPDATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
|
||||||
import { formatEditStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
|
import { formatEditStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
|
||||||
import { FeatureStrategyRemove } from 'component/feature/FeatureStrategy/FeatureStrategyRemove/FeatureStrategyRemove';
|
|
||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { StrategyExecution } from './StrategyExecution/StrategyExecution';
|
import { StrategyExecution } from './StrategyExecution/StrategyExecution';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu';
|
import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu';
|
||||||
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
|
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
|
||||||
import { DisableEnableStrategy } from './DisableEnableStrategy/DisableEnableStrategy';
|
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import RemoveStrategyMenu from './RemoveStrategyMenu/RemoveStrategyMenu';
|
import MenuStrategyRemove from './MenuStrategyRemove/MenuStrategyRemove';
|
||||||
|
import { LegacyFeatureStrategyRemove } from './LegacyFeatureStrategyRemove';
|
||||||
|
|
||||||
interface IStrategyItemProps {
|
interface IStrategyItemProps {
|
||||||
environmentId: string;
|
environmentId: string;
|
||||||
@ -85,7 +84,7 @@ export const StrategyItem: FC<IStrategyItemProps> = ({
|
|||||||
uiConfig?.flags?.strategyImprovements
|
uiConfig?.flags?.strategyImprovements
|
||||||
)}
|
)}
|
||||||
show={() => (
|
show={() => (
|
||||||
<RemoveStrategyMenu
|
<MenuStrategyRemove
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
featureId={featureId}
|
featureId={featureId}
|
||||||
environmentId={environmentId}
|
environmentId={environmentId}
|
||||||
@ -93,7 +92,7 @@ export const StrategyItem: FC<IStrategyItemProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
elseShow={() => (
|
elseShow={() => (
|
||||||
<FeatureStrategyRemove
|
<LegacyFeatureStrategyRemove
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
featureId={featureId}
|
featureId={featureId}
|
||||||
environmentId={environmentId}
|
environmentId={environmentId}
|
||||||
|
Loading…
Reference in New Issue
Block a user