1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-18 11:14:57 +02:00
unleash.unleash/frontend/src/component/segments/EditSegment/EditSegment.tsx
Thomas Heartman 95049b8f9f
Fix/constraint editing is broken in segment form (#10152)
This adds constraint ids to segment constraints used in editing
segments. Without them, there was a bug where when you went to edit the
segment, all constraints would be invisibly set to the same constraint.
2025-06-17 13:38:42 +00:00

167 lines
6.3 KiB
TypeScript

import FormTemplate from 'component/common/FormTemplate/FormTemplate';
import {
UPDATE_PROJECT_SEGMENT,
UPDATE_SEGMENT,
} from 'component/providers/AccessProvider/permissions';
import { useSegmentsApi } from 'hooks/api/actions/useSegmentsApi/useSegmentsApi';
import { useConstraintsValidation } from 'hooks/api/getters/useConstraintsValidation/useConstraintsValidation';
import { useSegment } from 'hooks/api/getters/useSegment/useSegment';
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import useToast from 'hooks/useToast';
import type React from 'react';
import { useNavigate } from 'react-router-dom';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useSegmentForm } from '../hooks/useSegmentForm.ts';
import { SegmentForm } from '../SegmentForm.tsx';
import { segmentsFormDescription } from 'component/segments/CreateSegment/CreateSegment';
import { UpdateButton } from 'component/common/UpdateButton/UpdateButton';
import { segmentsDocsLink } from 'component/segments/SegmentDocs';
import { useSegmentValuesCount } from 'component/segments/hooks/useSegmentValuesCount';
import { SEGMENT_SAVE_BTN_ID } from 'utils/testIds';
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
import { useHighestPermissionChangeRequestEnvironment } from 'hooks/useHighestPermissionChangeRequestEnvironment';
import type { ISegment } from 'interfaces/segment.ts';
import { constraintId } from 'constants/constraintId.ts';
import { v4 as uuidv4 } from 'uuid';
interface IEditSegmentProps {
modal?: boolean;
}
const addIdSymbolToConstraints = (segment?: ISegment): ISegment | undefined => {
if (!segment) return;
const constraints = segment.constraints.map((constraint) => {
return { ...constraint, [constraintId]: uuidv4() };
});
return { ...segment, constraints };
};
export const EditSegment = ({ modal }: IEditSegmentProps) => {
const projectId = useOptionalPathParam('projectId');
const segmentId = useRequiredPathParam('segmentId');
const { segment: segmentWithoutConstraintIds } = useSegment(
Number(segmentId),
);
const segment = addIdSymbolToConstraints(segmentWithoutConstraintIds);
const { uiConfig } = useUiConfig();
const { setToastData, setToastApiError } = useToast();
const navigate = useNavigate();
const { updateSegment, loading } = useSegmentsApi();
const { refetchSegments } = useSegments();
const {
name,
setName,
description,
setDescription,
project,
setProject,
constraints,
setConstraints,
getSegmentPayload,
errors,
clearErrors,
} = useSegmentForm(
segment?.name,
segment?.description,
segment?.project,
segment?.constraints,
);
const hasValidConstraints = useConstraintsValidation(constraints);
const segmentValuesCount = useSegmentValuesCount(constraints);
const { segmentValuesLimit } = useSegmentLimits();
const overSegmentValuesLimit: boolean = Boolean(
segmentValuesLimit && segmentValuesCount > segmentValuesLimit,
);
const formatApiCode = () => {
return `curl --location --request PUT '${
uiConfig.unleashUrl
}/api/admin/segments/${segmentId}' \\
--header 'Authorization: INSERT_API_KEY' \\
--header 'Content-Type: application/json' \\
--data-raw '${JSON.stringify(getSegmentPayload(), undefined, 2)}'`;
};
const highestPermissionChangeRequestEnv =
useHighestPermissionChangeRequestEnvironment(segment?.project);
const changeRequestEnv = highestPermissionChangeRequestEnv();
const { addChange } = useChangeRequestApi();
const handleSubmit = async (e: React.FormEvent) => {
if (segment) {
e.preventDefault();
clearErrors();
try {
if (changeRequestEnv) {
await addChange(segment.project || '', changeRequestEnv, {
action: 'updateSegment',
feature: null,
payload: { id: segment.id, ...getSegmentPayload() },
});
} else {
await updateSegment(segment.id, getSegmentPayload());
}
refetchSegments();
if (projectId) {
navigate(`/projects/${projectId}/settings/segments/`);
} else {
navigate('/segments/');
}
setToastData({
text: `Segment ${
changeRequestEnv ? 'change added to draft' : 'updated'
}`,
type: 'success',
});
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
}
};
return (
<FormTemplate
loading={loading}
modal={modal}
title='Edit segment'
description={segmentsFormDescription}
documentationLink={segmentsDocsLink}
documentationLinkLabel='Segments documentation'
formatApiCode={formatApiCode}
>
<SegmentForm
handleSubmit={handleSubmit}
name={name}
setName={setName}
description={description}
setDescription={setDescription}
project={project}
setProject={setProject}
constraints={constraints}
setConstraints={setConstraints}
errors={errors}
clearErrors={clearErrors}
mode='edit'
>
<UpdateButton
permission={[UPDATE_SEGMENT, UPDATE_PROJECT_SEGMENT]}
projectId={projectId}
disabled={!hasValidConstraints || overSegmentValuesLimit}
data-testid={SEGMENT_SAVE_BTN_ID}
>
{changeRequestEnv ? 'Add to draft' : 'Save'}
</UpdateButton>
</SegmentForm>
</FormTemplate>
);
};