mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
chore: new confirmation dialog for replacing release plans (#10720)
https://linear.app/unleash/issue/2-3931/add-a-confirmation-dialog-when-replacing-existing-release-plan Adds a confirmation dialog when replacing an already active release plan. <img width="706" height="325" alt="image" src="https://github.com/user-attachments/assets/f682809c-f563-4dca-9924-be1e9188c698" />
This commit is contained in:
parent
6c6d4c0ccc
commit
df67c041fc
@ -21,12 +21,13 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { LegacyReleasePlanReviewDialog } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/LegacyReleasePlanReviewDialog.tsx';
|
||||
import { ReleasePlanPreview } from '../../FeatureView/FeatureOverview/ReleasePlan/ReleasePlanPreview.tsx';
|
||||
import { ReleasePlanPreview } from './ReleasePlanPreview.tsx';
|
||||
import {
|
||||
FeatureStrategyMenuCards,
|
||||
type StrategyFilterValue,
|
||||
} from './FeatureStrategyMenuCards/FeatureStrategyMenuCards.tsx';
|
||||
import { useUiFlag } from 'hooks/useUiFlag.ts';
|
||||
import { ReleasePlanConfirmationDialog } from './ReleasePlanConfirmationDialog.tsx';
|
||||
|
||||
interface IFeatureStrategyMenuProps {
|
||||
label: string;
|
||||
@ -78,6 +79,8 @@ export const FeatureStrategyMenu = ({
|
||||
useState<IReleasePlanTemplate>();
|
||||
const [addReleasePlanOpen, setAddReleasePlanOpen] = useState(false);
|
||||
const [releasePlanPreview, setReleasePlanPreview] = useState(false);
|
||||
const [addReleasePlanConfirmationOpen, setAddReleasePlanConfirmationOpen] =
|
||||
useState(false);
|
||||
const dialogId = isStrategyMenuDialogOpen
|
||||
? 'FeatureStrategyMenuDialog'
|
||||
: undefined;
|
||||
@ -86,13 +89,19 @@ export const FeatureStrategyMenu = ({
|
||||
const { addChange } = useChangeRequestApi();
|
||||
const { refetch: refetchChangeRequests } =
|
||||
usePendingChangeRequests(projectId);
|
||||
const { refetch } = useReleasePlans(projectId, featureId, environmentId);
|
||||
const { refetch, releasePlans } = useReleasePlans(
|
||||
projectId,
|
||||
featureId,
|
||||
environmentId,
|
||||
);
|
||||
const { addReleasePlanToFeature } = useReleasePlansApi();
|
||||
const { isEnterprise } = useUiConfig();
|
||||
const displayReleasePlanButton = isEnterprise();
|
||||
const crProtected = isChangeRequestConfigured(environmentId);
|
||||
const newStrategyModalEnabled = useUiFlag('newStrategyModal');
|
||||
|
||||
const activeReleasePlan = releasePlans[0];
|
||||
|
||||
const onClose = () => {
|
||||
setIsStrategyMenuDialogOpen(false);
|
||||
};
|
||||
@ -121,8 +130,15 @@ export const FeatureStrategyMenu = ({
|
||||
setIsStrategyMenuDialogOpen(true);
|
||||
};
|
||||
|
||||
const addReleasePlan = async (template: IReleasePlanTemplate) => {
|
||||
const addReleasePlan = async (
|
||||
template: IReleasePlanTemplate,
|
||||
confirmed?: boolean,
|
||||
) => {
|
||||
try {
|
||||
if (newStrategyModalEnabled && !confirmed && activeReleasePlan) {
|
||||
setAddReleasePlanConfirmationOpen(true);
|
||||
return;
|
||||
}
|
||||
if (crProtected) {
|
||||
await addChange(projectId, environmentId, {
|
||||
feature: featureId,
|
||||
@ -153,18 +169,19 @@ export const FeatureStrategyMenu = ({
|
||||
|
||||
refetch();
|
||||
}
|
||||
|
||||
trackEvent('release-management', {
|
||||
props: {
|
||||
eventType: 'add-plan',
|
||||
plan: template.name,
|
||||
},
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
} finally {
|
||||
setAddReleasePlanConfirmationOpen(false);
|
||||
setAddReleasePlanOpen(false);
|
||||
setSelectedTemplate(undefined);
|
||||
onClose();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
@ -284,6 +301,7 @@ export const FeatureStrategyMenu = ({
|
||||
projectId={projectId}
|
||||
featureName={featureId}
|
||||
environment={environmentId}
|
||||
activeReleasePlan={activeReleasePlan}
|
||||
crProtected={crProtected}
|
||||
onBack={() => setReleasePlanPreview(false)}
|
||||
onConfirm={() => {
|
||||
@ -329,23 +347,34 @@ export const FeatureStrategyMenu = ({
|
||||
)}
|
||||
</Dialog>
|
||||
{selectedTemplate && (
|
||||
<LegacyReleasePlanReviewDialog
|
||||
open={addReleasePlanOpen}
|
||||
setOpen={(open) => {
|
||||
setAddReleasePlanOpen(open);
|
||||
if (!open) {
|
||||
setIsStrategyMenuDialogOpen(true);
|
||||
}
|
||||
}}
|
||||
onConfirm={() => {
|
||||
addReleasePlan(selectedTemplate);
|
||||
}}
|
||||
template={selectedTemplate}
|
||||
projectId={projectId}
|
||||
featureName={featureId}
|
||||
environment={environmentId}
|
||||
crProtected={crProtected}
|
||||
/>
|
||||
<>
|
||||
<LegacyReleasePlanReviewDialog
|
||||
open={addReleasePlanOpen}
|
||||
setOpen={(open) => {
|
||||
setAddReleasePlanOpen(open);
|
||||
if (!open) {
|
||||
setIsStrategyMenuDialogOpen(true);
|
||||
}
|
||||
}}
|
||||
onConfirm={() => {
|
||||
addReleasePlan(selectedTemplate);
|
||||
}}
|
||||
template={selectedTemplate}
|
||||
projectId={projectId}
|
||||
featureName={featureId}
|
||||
environment={environmentId}
|
||||
crProtected={crProtected}
|
||||
/>
|
||||
<ReleasePlanConfirmationDialog
|
||||
template={selectedTemplate}
|
||||
crProtected={crProtected}
|
||||
open={addReleasePlanConfirmationOpen}
|
||||
setOpen={setAddReleasePlanConfirmationOpen}
|
||||
onConfirm={() => {
|
||||
addReleasePlan(selectedTemplate, true);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</StyledStrategyMenu>
|
||||
);
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import type React from 'react';
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
|
||||
|
||||
interface IReleasePlanConfirmationDialogProps {
|
||||
template: IReleasePlanTemplate;
|
||||
crProtected: boolean;
|
||||
open: boolean;
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
export const ReleasePlanConfirmationDialog = ({
|
||||
template,
|
||||
crProtected,
|
||||
open,
|
||||
setOpen,
|
||||
onConfirm,
|
||||
}: IReleasePlanConfirmationDialogProps) => (
|
||||
<Dialogue
|
||||
title='Replace release plan?'
|
||||
open={open}
|
||||
primaryButtonText={
|
||||
crProtected ? 'Add suggestion to draft' : 'Add release plan'
|
||||
}
|
||||
secondaryButtonText='Close'
|
||||
onClick={onConfirm}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
This environment currently has a release plan added. Do you want to
|
||||
replace it with <strong>{template.name}</strong>?
|
||||
</Dialogue>
|
||||
);
|
||||
@ -1,5 +1,8 @@
|
||||
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
|
||||
import { ReleasePlan } from './ReleasePlan.tsx';
|
||||
import type {
|
||||
IReleasePlan,
|
||||
IReleasePlanTemplate,
|
||||
} from 'interfaces/releasePlans';
|
||||
import { ReleasePlan } from '../../FeatureView/FeatureOverview/ReleasePlan/ReleasePlan.tsx';
|
||||
import { useReleasePlanPreview } from 'hooks/useReleasePlanPreview';
|
||||
import {
|
||||
styled,
|
||||
@ -9,9 +12,8 @@ import {
|
||||
DialogActions,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import { useReleasePlans } from 'hooks/api/getters/useReleasePlans/useReleasePlans';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature.ts';
|
||||
|
||||
const StyledScrollableContent = styled(Box)(({ theme }) => ({
|
||||
width: theme.breakpoints.values.md,
|
||||
@ -38,6 +40,8 @@ interface IReleasePlanPreviewProps {
|
||||
projectId: string;
|
||||
featureName: string;
|
||||
environment: string;
|
||||
environmentEnabled?: boolean;
|
||||
activeReleasePlan?: IReleasePlan;
|
||||
crProtected?: boolean;
|
||||
onConfirm: () => void;
|
||||
onBack: () => void;
|
||||
@ -48,19 +52,12 @@ export const ReleasePlanPreview = ({
|
||||
projectId,
|
||||
featureName,
|
||||
environment,
|
||||
activeReleasePlan,
|
||||
crProtected,
|
||||
onConfirm,
|
||||
onBack,
|
||||
}: IReleasePlanPreviewProps) => {
|
||||
const { feature } = useFeature(projectId, featureName);
|
||||
const { releasePlans, loading } = useReleasePlans(
|
||||
projectId,
|
||||
featureName,
|
||||
environment,
|
||||
);
|
||||
|
||||
const activeReleasePlan = releasePlans[0];
|
||||
|
||||
const environmentData = feature?.environments.find(
|
||||
({ name }) => name === environment,
|
||||
);
|
||||
@ -72,8 +69,6 @@ export const ReleasePlanPreview = ({
|
||||
environment,
|
||||
);
|
||||
|
||||
if (loading) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledSubHeader>
|
||||
@ -85,13 +80,17 @@ export const ReleasePlanPreview = ({
|
||||
<StyledScrollableContent>
|
||||
{activeReleasePlan && (
|
||||
<Box sx={{ px: 4, pb: 2 }}>
|
||||
<Alert severity='error'>
|
||||
<Alert severity='warning'>
|
||||
This feature environment currently has{' '}
|
||||
<strong>{activeReleasePlan.name}</strong> -{' '}
|
||||
<strong>{activeReleasePlan.name}</strong> (
|
||||
<strong>
|
||||
{activeReleasePlan.milestones[0].name}
|
||||
{activeReleasePlan.milestones.find(
|
||||
({ id }) =>
|
||||
activeReleasePlan.activeMilestoneId ===
|
||||
id,
|
||||
)?.name ?? activeReleasePlan.milestones[0].name}
|
||||
</strong>
|
||||
{environmentEnabled ? ' running' : ' paused'}.
|
||||
){environmentEnabled ? ' running' : ' paused'}.
|
||||
Adding a new release plan will replace the existing
|
||||
release plan.
|
||||
</Alert>
|
||||
Loading…
Reference in New Issue
Block a user