1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-11-24 20:06:55 +01:00

refactor: simplify safeguard form management (#11013)

This commit is contained in:
Mateusz Kwasniewski 2025-11-21 16:00:45 +01:00 committed by GitHub
parent 63e969821c
commit 97a20b0929
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 38 additions and 26 deletions

View File

@ -66,7 +66,7 @@ export const EnvironmentAccordionBody = ({
const [strategies, setStrategies] = useState(
featureEnvironment?.strategies || [],
);
const { releasePlans } = useFeatureReleasePlans(
const { releasePlans, refetch } = useFeatureReleasePlans(
projectId,
featureId,
featureEnvironment?.name,
@ -229,6 +229,7 @@ export const EnvironmentAccordionBody = ({
<ReleasePlan
plan={plan}
environmentIsDisabled={isDisabled}
onAutomationChange={refetch}
/>
</StrategyListItem>
))}

View File

@ -4,7 +4,6 @@ import PlayCircle from '@mui/icons-material/PlayCircle';
import { DELETE_FEATURE_STRATEGY } from '@server/types/permissions';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { useReleasePlansApi } from 'hooks/api/actions/useReleasePlansApi/useReleasePlansApi';
import { useFeatureReleasePlans } from 'hooks/api/getters/useFeatureReleasePlans/useFeatureReleasePlans';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import useToast from 'hooks/useToast';
import type {
@ -32,7 +31,10 @@ import { ReleasePlanMilestoneItem } from './ReleasePlanMilestoneItem/ReleasePlan
import Add from '@mui/icons-material/Add';
import { StyledActionButton } from './ReleasePlanMilestoneItem/StyledActionButton.tsx';
import { SafeguardForm } from './SafeguardForm/SafeguardForm.tsx';
import {
SafeguardForm,
useSafeguardForm,
} from './SafeguardForm/SafeguardForm.tsx';
import { useSafeguardsApi } from 'hooks/api/actions/useSafeguardsApi/useSafeguardsApi';
import type { CreateSafeguardSchema } from 'openapi/models/createSafeguardSchema';
import { DeleteSafeguardDialog } from './DeleteSafeguardDialog.tsx';
@ -120,12 +122,14 @@ interface IReleasePlanProps {
plan: IReleasePlan;
environmentIsDisabled?: boolean;
readonly?: boolean;
onAutomationChange?: () => void;
}
export const ReleasePlan = ({
plan,
environmentIsDisabled,
readonly,
onAutomationChange,
}: IReleasePlanProps) => {
const {
id,
@ -139,8 +143,6 @@ export const ReleasePlan = ({
} = plan;
const projectId = useRequiredPathParam('projectId');
const { refetch, loading: featureReleasePlansLoading } =
useFeatureReleasePlans(projectId, featureName, environment);
const { removeReleasePlanFromFeature, startReleasePlanMilestone } =
useReleasePlansApi();
const {
@ -221,9 +223,11 @@ export const ReleasePlan = ({
>(null);
const [milestoneToDeleteProgression, setMilestoneToDeleteProgression] =
useState<IReleasePlanMilestone | null>(null);
const [safeguardFormOpen, setSafeguardFormOpen] = useState(false);
const [safeguardDeleteDialogOpen, setSafeguardDeleteDialogOpen] =
useState(false);
const { safeguardFormOpen, setSafeguardFormOpen } =
useSafeguardForm(safeguards);
const onChangeRequestConfirm = async () => {
if (!changeRequestAction) return;
@ -311,7 +315,7 @@ export const ReleasePlan = ({
type: 'success',
});
refetch();
onAutomationChange?.();
setRemoveOpen(false);
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
@ -337,7 +341,7 @@ export const ReleasePlan = ({
text: `Milestone "${milestone.name}" has started`,
type: 'success',
});
refetch();
onAutomationChange?.();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
@ -387,7 +391,7 @@ export const ReleasePlan = ({
featureName,
sourceMilestoneId: milestoneToDeleteProgression.id,
});
await refetch();
onAutomationChange?.();
setMilestoneToDeleteProgression(null);
setToastData({
type: 'success',
@ -411,7 +415,7 @@ export const ReleasePlan = ({
type: 'success',
text: 'Automation resumed successfully',
});
refetch();
onAutomationChange?.();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
@ -434,11 +438,9 @@ export const ReleasePlan = ({
type: 'success',
text: 'Safeguard added successfully',
});
refetch();
onAutomationChange?.();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
} finally {
setSafeguardFormOpen(false);
}
};
@ -461,7 +463,7 @@ export const ReleasePlan = ({
type: 'success',
text: 'Safeguard deleted successfully',
});
refetch();
onAutomationChange?.();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
} finally {
@ -529,20 +531,15 @@ export const ReleasePlan = ({
) : null}
<StyledBody border={safeguardBorder}>
{safeguardsEnabled ? (
{onAutomationChange && safeguardsEnabled ? (
<StyledAddSafeguard border={safeguardBorder}>
{safeguards.length > 0 ? (
{safeguardFormOpen ? (
<SafeguardForm
safeguard={safeguards[0]}
safeguard={safeguards?.[0]}
onSubmit={handleSafeguardSubmit}
onCancel={() => setSafeguardFormOpen(false)}
onDelete={handleSafeguardDelete}
/>
) : safeguardFormOpen || featureReleasePlansLoading ? (
<SafeguardForm
onSubmit={handleSafeguardSubmit}
onCancel={() => setSafeguardFormOpen(false)}
/>
) : (
<StyledActionButton
onClick={() => setSafeguardFormOpen(true)}
@ -582,7 +579,7 @@ export const ReleasePlan = ({
projectId={projectId}
environment={environment}
featureName={featureName}
onUpdate={refetch}
onUpdate={onAutomationChange}
/>
))}
</StyledMilestones>

View File

@ -52,7 +52,7 @@ export interface IReleasePlanMilestoneItemProps {
projectId: string;
environment: string;
featureName: string;
onUpdate: () => void | Promise<void>;
onUpdate?: () => void;
}
const getTimeUnit = (intervalMinutes: number): 'minutes' | 'hours' | 'days' => {
@ -134,7 +134,7 @@ export const ReleasePlanMilestoneItem = ({
text: 'Automation configured successfully',
});
handleCloseProgressionForm();
await onUpdate();
onUpdate?.();
return {};
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));

View File

@ -26,6 +26,20 @@ import type { ISafeguard } from 'interfaces/releasePlans.ts';
const StyledIcon = createStyledIcon(ShieldIcon);
export const useSafeguardForm = (safeguards: ISafeguard[] | undefined) => {
const [safeguardFormOpen, setSafeguardFormOpen] = useState(false);
useEffect(() => {
if (safeguards && safeguards.length > 0) {
setSafeguardFormOpen(true);
} else {
setSafeguardFormOpen(false);
}
}, [JSON.stringify(safeguards)]);
return { safeguardFormOpen, setSafeguardFormOpen };
};
interface ISafeguardFormProps {
onSubmit: (data: CreateSafeguardSchema) => void;
onCancel: () => void;
@ -182,7 +196,7 @@ export const SafeguardForm = ({
threshold: Number(threshold),
});
if (mode === 'edit') {
if (mode === 'edit' || mode === 'create') {
setMode('display');
}
};