diff --git a/frontend/src/component/changeRequest/ChangeRequest/Changes/Change/EditChange.tsx b/frontend/src/component/changeRequest/ChangeRequest/Changes/Change/EditChange.tsx index bb60ca07b9..aa926db936 100644 --- a/frontend/src/component/changeRequest/ChangeRequest/Changes/Change/EditChange.tsx +++ b/frontend/src/component/changeRequest/ChangeRequest/Changes/Change/EditChange.tsx @@ -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>({ + const [strategy, setStrategy] = useState>({ ...change.payload, constraints: constraintsWithId, }); diff --git a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx index a8d90c81f1..ba7c9c944b 100644 --- a/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx +++ b/frontend/src/component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx @@ -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; disabled?: boolean; diff --git a/frontend/src/component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList.tsx b/frontend/src/component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList.tsx index 0c37645762..b88f83e2e1 100644 --- a/frontend/src/component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList.tsx +++ b/frontend/src/component/common/NewConstraintAccordion/ConstraintsList/EditableConstraintsList.tsx @@ -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>; } @@ -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 ( + IN THE constraints list. mapping: {JSON.stringify(constraints)} {constraints.map((constraint, index) => ( >; + constraints: IConstraintWithId[]; + setConstraints?: React.Dispatch>; showCreateButton?: boolean; } @@ -57,7 +57,7 @@ interface IConstraintAccordionListItemState { const useConstraintAccordionList = ( setConstraints: - | React.Dispatch> + | React.Dispatch> | undefined, ref: React.RefObject, ) => { @@ -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, @@ -101,8 +101,9 @@ export const FeatureStrategyConstraintAccordionList = forwardRef< return ( + constraints are {JSON.stringify(constraints)} @@ -128,13 +129,14 @@ export const FeatureStrategyConstraintAccordionList = forwardRef< } /> - {setConstraints ? ( + +
{}} constraints={constraints} /> - ) : null} +
({ 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 diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/FeatureStrategyConstraints.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/FeatureStrategyConstraints.tsx index deb07a1301..6aecdb4959 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/FeatureStrategyConstraints.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/FeatureStrategyConstraints.tsx @@ -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; + strategy: Partial; setStrategy: React.Dispatch< - React.SetStateAction> + React.SetStateAction> >; } @@ -53,7 +53,9 @@ export const FeatureStrategyConstraints = ({ const constraints = strategy.constraints || []; - const setConstraints = (value: React.SetStateAction) => { + const setConstraints = ( + value: React.SetStateAction, + ) => { setStrategy((prev) => { return { ...prev, diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/RecentlyUsedConstraints.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/RecentlyUsedConstraints.tsx index f2bede7da8..3f26bbd9f6 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/RecentlyUsedConstraints.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/RecentlyUsedConstraints.tsx @@ -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>; - constraints?: IConstraint[]; + setConstraints?: React.Dispatch>; + constraints?: IConstraintWithId[]; }; const StyledContainer = styled('div')(({ theme }) => ({ diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints.ts b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints.ts index 2be72642cc..d4119528c1 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints.ts +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyConstraints/RecentlyUsedConstraints/useRecentlyUsedConstraints.ts @@ -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( + const [items, setItems] = useLocalStorageState( 'recently-used-constraints', initialItems, ); - const addItem = (newItem: IConstraint | IConstraint[]) => { + const addItem = (newItem: IConstraintWithId | IConstraintWithId[]) => { setItems((prevItems) => { const itemsToAdd = Array.isArray(newItem) ? newItem : [newItem]; diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx index 40a1dcf1e9..3ee08e0d86 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx @@ -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; + strategy: Partial; setStrategy: React.Dispatch< - React.SetStateAction> + React.SetStateAction> >; segments: ISegment[]; setSegments: React.Dispatch>; diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyType/FeatureStrategyType.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyType/FeatureStrategyType.tsx index cadc095128..244f275aac 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyType/FeatureStrategyType.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyType/FeatureStrategyType.tsx @@ -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; strategyDefinition: IStrategy; setStrategy: React.Dispatch< - React.SetStateAction> + React.SetStateAction> >; validateParameter: (name: string, value: string) => boolean; errors: IFormErrors; diff --git a/frontend/src/component/feature/StrategyTypes/NewStrategyVariants.tsx b/frontend/src/component/feature/StrategyTypes/NewStrategyVariants.tsx index db742d1d47..2bbf872b88 100644 --- a/frontend/src/component/feature/StrategyTypes/NewStrategyVariants.tsx +++ b/frontend/src/component/feature/StrategyTypes/NewStrategyVariants.tsx @@ -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> + React.SetStateAction> >; strategy: Partial; projectId: string; diff --git a/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts b/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts index 98e5f217ea..5ac0e3e2b9 100644 --- a/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts +++ b/frontend/src/hooks/api/getters/useChangeRequest/useChangeRequest.ts @@ -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( formatApiPath(`api/admin/projects/${projectId}/change-requests/${id}`), diff --git a/frontend/src/interfaces/strategy.ts b/frontend/src/interfaces/strategy.ts index 0f46621f79..4c9bba805b 100644 --- a/frontend/src/interfaces/strategy.ts +++ b/frontend/src/interfaces/strategy.ts @@ -68,6 +68,10 @@ export interface IConstraint { [constraintId]?: string; } +export interface IEditableStrategy extends IFeatureStrategy { + constraints: IConstraintWithId[]; +} + export interface IConstraintWithId extends IConstraint { [constraintId]: string; }