mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-22 11:18:20 +02:00
This PR takes two steps towards better constraint handling: ## New type: `IConstraintWithId` Introduces a new type, `IConstraintWithId`. This is the same as an `IConstraint`, except the constraint id property is required. The idea is that the list of editable constraints should move towards using this instead of just `IConstraint`. That should prevent us (on a type-level) from seeing more of the same kind of errors we saw with the segment constraints yesterday. I don't want to go ahead and update all the upstream uses of this to IConstraintWithId in this PR, so I'll look at that separately. ## API payload constraint replacer Introduces an api payload constraint "replacer", which we can use for [JSON.stringify's `replacer` parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#the_replacer_parameter). The current implementation works both for strategies and for segments and has been added to edit + create forms for both of these resources. This has a couple benefits: 1. We can clearly state exactly how we want them to be rendered, including property order. I've decided to go with context -> operator -> value(s) as the main one (check the screenie), as I believe this is the most logical reading order. 2. We can exclude value/values (whichever one doesn't work with the operator) 3. It doesn't matter how we treat constraints internally, we can still present the payload how we want 4. Importantly: this only affects the stringification for the user-facing API payload, so it's very low risk. It does not affect anything that we actually send to the api. Here's what it can look like with ordered properties: <img width="392" alt="image" src="https://github.com/user-attachments/assets/f46f77c8-0b5a-4ded-b13a-bb567df60bd3" />
91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
import type { IConstraint, IConstraintWithId } from 'interfaces/strategy';
|
|
import { SegmentFormStepOne } from './SegmentFormStepOne.tsx';
|
|
import { SegmentFormStepTwo } from './SegmentFormStepTwo.tsx';
|
|
import type React from 'react';
|
|
import { useState } from 'react';
|
|
import { SegmentFormStepList } from 'component/segments/SegmentFormStepList';
|
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
import { styled } from '@mui/material';
|
|
|
|
export type SegmentFormStep = 1 | 2;
|
|
export type SegmentFormMode = 'create' | 'edit';
|
|
|
|
interface ISegmentProps {
|
|
name: string;
|
|
description: string;
|
|
project?: string;
|
|
constraints: IConstraintWithId[];
|
|
setName: React.Dispatch<React.SetStateAction<string>>;
|
|
setDescription: React.Dispatch<React.SetStateAction<string>>;
|
|
setProject: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
setConstraints: React.Dispatch<React.SetStateAction<IConstraint[]>>;
|
|
handleSubmit: (e: any) => void;
|
|
errors: { [key: string]: string };
|
|
clearErrors: () => void;
|
|
mode: SegmentFormMode;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
const StyledForm = styled('form')(({ theme }) => ({
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
height: '100%',
|
|
}));
|
|
|
|
export const SegmentForm: React.FC<ISegmentProps> = ({
|
|
children,
|
|
name,
|
|
description,
|
|
project,
|
|
constraints,
|
|
setName,
|
|
setDescription,
|
|
setProject,
|
|
setConstraints,
|
|
handleSubmit,
|
|
errors,
|
|
clearErrors,
|
|
mode,
|
|
}) => {
|
|
const totalSteps = 2;
|
|
const [currentStep, setCurrentStep] = useState<SegmentFormStep>(1);
|
|
|
|
return (
|
|
<>
|
|
<SegmentFormStepList total={totalSteps} current={currentStep} />
|
|
<StyledForm onSubmit={handleSubmit}>
|
|
<ConditionallyRender
|
|
condition={currentStep === 1}
|
|
show={
|
|
<SegmentFormStepOne
|
|
name={name}
|
|
description={description}
|
|
project={project}
|
|
setName={setName}
|
|
setDescription={setDescription}
|
|
setProject={setProject}
|
|
errors={errors}
|
|
clearErrors={clearErrors}
|
|
setCurrentStep={setCurrentStep}
|
|
/>
|
|
}
|
|
/>
|
|
<ConditionallyRender
|
|
condition={currentStep === 2}
|
|
show={
|
|
<SegmentFormStepTwo
|
|
project={project}
|
|
constraints={constraints}
|
|
setConstraints={setConstraints}
|
|
setCurrentStep={setCurrentStep}
|
|
mode={mode}
|
|
>
|
|
{children}
|
|
</SegmentFormStepTwo>
|
|
}
|
|
/>
|
|
</StyledForm>
|
|
</>
|
|
);
|
|
};
|