1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-24 17:51:14 +02:00
This commit is contained in:
Thomas Heartman 2025-09-24 14:23:38 +02:00 committed by GitHub
commit 0def4cb3b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 49 additions and 47 deletions

View File

@ -4,7 +4,7 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import type { IFeatureStrategy } from 'interfaces/strategy';
import type { IEditableStrategy, IFeatureStrategy } from 'interfaces/strategy';
import { UPDATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import type { ISegment } from 'interfaces/segment';
import { useFormErrors } from 'hooks/useFormErrors';
@ -63,7 +63,7 @@ export const EditChange = ({
const constraintsWithId = addIdSymbolToConstraints(change.payload);
const [strategy, setStrategy] = useState<Partial<IFeatureStrategy>>({
const [strategy, setStrategy] = useState<Partial<IEditableStrategy>>({
...change.payload,
constraints: constraintsWithId,
});

View File

@ -7,12 +7,12 @@ import {
type Theme,
styled,
} from '@mui/material';
import type { IConstraint } from 'interfaces/strategy';
import { ConstraintAccordionViewBody } from './ConstraintAccordionViewBody/ConstraintAccordionViewBody.tsx';
import { ConstraintAccordionViewHeader } from './ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx';
import type { IConstraintWithId } from 'interfaces/strategy.ts';
interface IConstraintAccordionViewProps {
constraint: IConstraint;
constraint: IConstraintWithId;
onUse?: () => void;
sx?: SxProps<Theme>;
disabled?: boolean;

View File

@ -1,21 +1,20 @@
import type React from 'react';
import { useEffect, useImperativeHandle } from 'react';
import { useImperativeHandle } from 'react';
import { forwardRef } from 'react';
import { styled } from '@mui/material';
import type { IConstraint } from 'interfaces/strategy';
import type { IConstraint, IConstraintWithId } from 'interfaces/strategy';
import produce from 'immer';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
import { createEmptyConstraint } from '../../../../utils/createEmptyConstraint.ts';
import { constraintId } from 'constants/constraintId.ts';
import { v4 as uuidv4 } from 'uuid';
export interface IEditableConstraintsListRef {
addConstraint?: (contextName: string) => void;
}
export interface IEditableConstraintsListProps {
constraints: IConstraint[];
constraints: IConstraintWithId[];
setConstraints: React.Dispatch<React.SetStateAction<IConstraint[]>>;
}
@ -40,17 +39,6 @@ export const EditableConstraintsList = forwardRef<
},
}));
useEffect(() => {
if (!constraints.every((constraint) => constraintId in constraint)) {
setConstraints(
constraints.map((constraint) => ({
[constraintId]: uuidv4(),
...constraint,
})),
);
}
}, [constraints, setConstraints]);
const onDelete = (index: number) => {
setConstraints(
produce((draft) => {
@ -79,6 +67,7 @@ export const EditableConstraintsList = forwardRef<
return (
<StyledContainer>
IN THE constraints list. mapping: {JSON.stringify(constraints)}
<ConstraintsList>
{constraints.map((constraint, index) => (
<EditableConstraint

View File

@ -2,7 +2,7 @@ import type React from 'react';
import { forwardRef, useImperativeHandle, type RefObject } from 'react';
import { Box, Button, styled, Typography } from '@mui/material';
import Add from '@mui/icons-material/Add';
import type { IConstraint } from 'interfaces/strategy';
import type { IConstraint, IConstraintWithId } from 'interfaces/strategy';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
@ -15,8 +15,8 @@ import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashCon
import { createEmptyConstraint } from 'utils/createEmptyConstraint.ts';
interface IConstraintAccordionListProps {
constraints: IConstraint[];
setConstraints?: React.Dispatch<React.SetStateAction<IConstraint[]>>;
constraints: IConstraintWithId[];
setConstraints?: React.Dispatch<React.SetStateAction<IConstraintWithId[]>>;
showCreateButton?: boolean;
}
@ -57,7 +57,7 @@ interface IConstraintAccordionListItemState {
const useConstraintAccordionList = (
setConstraints:
| React.Dispatch<React.SetStateAction<IConstraint[]>>
| React.Dispatch<React.SetStateAction<IConstraintWithId[]>>
| undefined,
ref: React.RefObject<IConstraintAccordionListRef>,
) => {
@ -88,7 +88,7 @@ const useConstraintAccordionList = (
export const FeatureStrategyConstraintAccordionList = forwardRef<
IConstraintAccordionListRef | undefined,
IConstraintAccordionListProps
>(({ constraints, setConstraints, showCreateButton }, ref) => {
>(({ constraints, setConstraints }, ref) => {
const { onAdd, context } = useConstraintAccordionList(
setConstraints,
ref as RefObject<IConstraintAccordionListRef>,
@ -101,8 +101,9 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
return (
<StyledContainer>
constraints are {JSON.stringify(constraints)}
<ConditionallyRender
condition={Boolean(showCreateButton && onAdd)}
condition={Boolean(true)}
show={
<div>
<StyledHelpIconBox>
@ -128,13 +129,14 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
}
/>
</StyledHelpIconBox>
{setConstraints ? (
<fieldset disabled>
<EditableConstraintsList
ref={ref}
setConstraints={setConstraints}
setConstraints={() => {}}
constraints={constraints}
/>
) : null}
</fieldset>
<Box
sx={(theme) => ({
marginTop: theme.spacing(2),
@ -156,7 +158,7 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
variant='outlined'
color='primary'
data-testid='ADD_CONSTRAINT_BUTTON'
disabled={Boolean(limitReached)}
disabled={Boolean(limitReached || !onAdd)}
>
Add constraint
</Button>

View File

@ -1,4 +1,4 @@
import type { IConstraint, IFeatureStrategy } from 'interfaces/strategy';
import type { IConstraintWithId, IEditableStrategy } from 'interfaces/strategy';
import type React from 'react';
import { useEffect } from 'react';
import {
@ -11,9 +11,9 @@ import { FeatureStrategyConstraintAccordionList } from './FeatureStrategyConstra
interface IFeatureStrategyConstraintsProps {
projectId: string;
environmentId: string;
strategy: Partial<IFeatureStrategy>;
strategy: Partial<IEditableStrategy>;
setStrategy: React.Dispatch<
React.SetStateAction<Partial<IFeatureStrategy>>
React.SetStateAction<Partial<IEditableStrategy>>
>;
}
@ -53,7 +53,9 @@ export const FeatureStrategyConstraints = ({
const constraints = strategy.constraints || [];
const setConstraints = (value: React.SetStateAction<IConstraint[]>) => {
const setConstraints = (
value: React.SetStateAction<IConstraintWithId[]>,
) => {
setStrategy((prev) => {
return {
...prev,

View File

@ -5,11 +5,11 @@ import {
areConstraintsEqual,
getConstraintKey,
} from './useRecentlyUsedConstraints.ts';
import type { IConstraint } from 'interfaces/strategy';
import type { IConstraintWithId } from 'interfaces/strategy.ts';
type IRecentlyUsedConstraintsProps = {
setConstraints?: React.Dispatch<React.SetStateAction<IConstraint[]>>;
constraints?: IConstraint[];
setConstraints?: React.Dispatch<React.SetStateAction<IConstraintWithId[]>>;
constraints?: IConstraintWithId[];
};
const StyledContainer = styled('div')(({ theme }) => ({

View File

@ -1,5 +1,5 @@
import { useLocalStorageState } from 'hooks/useLocalStorageState';
import type { IConstraint } from 'interfaces/strategy';
import type { IConstraint, IConstraintWithId } from 'interfaces/strategy';
const hashString = (str: string): number => {
let hash = 0;
@ -41,14 +41,14 @@ export const areConstraintsEqual = (
};
export const useRecentlyUsedConstraints = (
initialItems: IConstraint[] = [],
initialItems: IConstraintWithId[] = [],
) => {
const [items, setItems] = useLocalStorageState<IConstraint[]>(
const [items, setItems] = useLocalStorageState<IConstraintWithId[]>(
'recently-used-constraints',
initialItems,
);
const addItem = (newItem: IConstraint | IConstraint[]) => {
const addItem = (newItem: IConstraintWithId | IConstraintWithId[]) => {
setItems((prevItems) => {
const itemsToAdd = Array.isArray(newItem) ? newItem : [newItem];

View File

@ -13,7 +13,7 @@ import {
Link,
} from '@mui/material';
import type {
IFeatureStrategy,
IEditableStrategy,
IFeatureStrategyParameters,
IStrategyParameter,
} from 'interfaces/strategy';
@ -57,9 +57,9 @@ interface IFeatureStrategyFormProps {
onCancel?: () => void;
loading: boolean;
isChangeRequest: boolean;
strategy: Partial<IFeatureStrategy>;
strategy: Partial<IEditableStrategy>;
setStrategy: React.Dispatch<
React.SetStateAction<Partial<IFeatureStrategy>>
React.SetStateAction<Partial<IEditableStrategy>>
>;
segments: ISegment[];
setSegments: React.Dispatch<React.SetStateAction<ISegment[]>>;

View File

@ -1,4 +1,8 @@
import type { IFeatureStrategy, IStrategy } from 'interfaces/strategy';
import type {
IEditableStrategy,
IFeatureStrategy,
IStrategy,
} from 'interfaces/strategy';
import DefaultStrategy from 'component/feature/StrategyTypes/DefaultStrategy/DefaultStrategy';
import FlexibleStrategy from 'component/feature/StrategyTypes/FlexibleStrategy/FlexibleStrategy';
import GeneralStrategy from 'component/feature/StrategyTypes/GeneralStrategy/GeneralStrategy';
@ -12,7 +16,7 @@ interface IFeatureStrategyTypeProps {
strategy: Partial<IFeatureStrategy>;
strategyDefinition: IStrategy;
setStrategy: React.Dispatch<
React.SetStateAction<Partial<IFeatureStrategy>>
React.SetStateAction<Partial<IEditableStrategy>>
>;
validateParameter: (name: string, value: string) => boolean;
errors: IFormErrors;

View File

@ -8,7 +8,7 @@ import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvi
import { v4 as uuidv4 } from 'uuid';
import { WeightType } from '../../../constants/variantTypes.ts';
import { Box, styled, Typography, useTheme, Alert } from '@mui/material';
import type { IFeatureStrategy } from 'interfaces/strategy';
import type { IEditableStrategy, IFeatureStrategy } from 'interfaces/strategy';
import { VariantsSplitPreview } from 'component/common/VariantsSplitPreview/VariantsSplitPreview';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { StrategyVariantsUpgradeAlert } from 'component/common/StrategyVariantsUpgradeAlert/StrategyVariantsUpgradeAlert';
@ -30,7 +30,7 @@ const StyledHelpIconBox = styled(Box)(({ theme }) => ({
export const NewStrategyVariants: FC<{
setStrategy: React.Dispatch<
React.SetStateAction<Partial<IFeatureStrategy>>
React.SetStateAction<Partial<IEditableStrategy>>
>;
strategy: Partial<IFeatureStrategy>;
projectId: string;

View File

@ -3,6 +3,7 @@ import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler.js';
import type { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
// we get constraints here
export const useChangeRequest = (projectId: string, id: string) => {
const { data, error, mutate } = useSWR<ChangeRequestType>(
formatApiPath(`api/admin/projects/${projectId}/change-requests/${id}`),

View File

@ -69,6 +69,10 @@ export interface IConstraint {
[constraintId]?: string;
}
export interface IEditableStrategy extends IFeatureStrategy {
constraints: IConstraintWithId[];
}
export interface IConstraintWithId extends IConstraint {
[constraintId]: string;
}