diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx index cba83a9ece..87cbf7426e 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyForm/FeatureStrategyForm.tsx @@ -248,7 +248,11 @@ export const FeatureStrategyForm = ({ /> void; removeVariant: (variantId: string) => void; error?: string; + disableOverrides?: boolean; } export const VariantForm = ({ @@ -158,6 +159,7 @@ export const VariantForm = ({ updateVariant, removeVariant, error, + disableOverrides = false, }: IVariantFormProps) => { const [name, setName] = useState(variant.name); const [customPercentage, setCustomPercentage] = useState( @@ -168,8 +170,9 @@ export const VariantForm = ({ variant.payload || EMPTY_PAYLOAD ); const [overrides, overridesDispatch] = useOverrides( - variant.overrides || [] + 'overrides' in variant ? variant.overrides || [] : [] ); + const { context } = useUnleashContext(); const [errors, setErrors] = useState({}); @@ -269,7 +272,7 @@ export const VariantForm = ({ }; useEffect(() => { - updateVariant({ + const newVariant: IFeatureVariantEdit = { ...variant, name, weight: Number(customPercentage ? percentage : 100) * 10, @@ -277,19 +280,22 @@ export const VariantForm = ({ stickiness: variants?.length > 0 ? variants[0].stickiness : 'default', payload: payload.value ? payload : undefined, - overrides: overrides - .map(o => ({ - contextName: o.contextName, - values: o.values, - })) - .filter(o => o.values && o.values.length > 0), isValid: isNameNotEmpty(name) && isNameUnique(name, variant.id) && isValidPercentage(percentage) && isValidPayload(payload) && !error, - }); + }; + if (!disableOverrides) { + newVariant['overrides'] = overrides + .map(o => ({ + contextName: o.contextName, + values: o.values, + })) + .filter(o => o.values && o.values.length > 0); + } + updateVariant(newVariant); }, [name, customPercentage, percentage, payload, overrides]); useEffect(() => { @@ -423,24 +429,28 @@ export const VariantForm = ({ /> - - Overrides - - - -
- - Add override - -
+ {!disableOverrides ? ( + <> + + Overrides + + + +
+ + Add override + +
+ + ) : null} ); }; diff --git a/frontend/src/component/feature/StrategyTypes/StrategyVariants.test.tsx b/frontend/src/component/feature/StrategyTypes/StrategyVariants.test.tsx new file mode 100644 index 0000000000..57b2961226 --- /dev/null +++ b/frontend/src/component/feature/StrategyTypes/StrategyVariants.test.tsx @@ -0,0 +1,96 @@ +import { screen, waitFor } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { StrategyVariants } from './StrategyVariants'; +import { Route, Routes } from 'react-router-dom'; +import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvider/permissions'; +import { IFeatureStrategy } from '../../../interfaces/strategy'; +import React, { useState } from 'react'; + +test('should render variants', async () => { + let currentStrategy: Partial = {}; + const initialStrategy = { + name: '', + constraints: [], + parameters: { stickiness: 'clientId' }, + variants: [ + { + name: 'variantName', + stickiness: 'default', + weight: 1000, + weightType: 'variable', + payload: { + type: 'string', + value: 'variantValue', + }, + }, + ], + }; + const Parent = () => { + const [strategy, setStrategy] = + useState>(initialStrategy); + + currentStrategy = strategy; + + return ( + + ); + }; + render( + + } + /> + , + { + route: 'projects/default/features/colors/strategies/edit?environmentId=development&strategyId=2e4f0555-518b-45b3-b0cd-a32cca388a92', + permissions: [ + { + permission: UPDATE_FEATURE_ENVIRONMENT_VARIANTS, + project: 'default', + environment: 'development', + }, + ], + } + ); + + // static form info + await screen.findByText('Variants'); + const button = await screen.findByText('Add variant'); + + // variant form populated + const variantInput = screen.getByDisplayValue('variantValue'); + expect(variantInput).toBeInTheDocument(); + + // overrides disabled + expect(screen.queryByText('Overrides')).not.toBeInTheDocument(); + + // add second variant + button.click(); + + // UI allows to adjust percentages + const matchedElements = screen.getAllByText('Custom percentage'); + expect(matchedElements.length).toBe(2); + + // correct variants set on the parent + await waitFor(() => { + expect(currentStrategy).toMatchObject({ + ...initialStrategy, + variants: [ + { + name: 'variantName', + payload: { type: 'string', value: 'variantValue' }, + stickiness: 'clientId', + weight: 500, + weightType: 'variable', + }, + { + name: '', + stickiness: 'clientId', + weight: 500, + weightType: 'variable', + }, + ], + }); + }); +}); diff --git a/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx b/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx index ff91c8d751..404bbd3253 100644 --- a/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx +++ b/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx @@ -7,8 +7,7 @@ import { UPDATE_FEATURE_ENVIRONMENT_VARIANTS } from '../../providers/AccessProvi import { v4 as uuidv4 } from 'uuid'; import { WeightType } from '../../../constants/variantTypes'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; -import { useDefaultProjectSettings } from 'hooks/useDefaultProjectSettings'; -import { styled } from '@mui/material'; +import { styled, Typography } from '@mui/material'; import { useRequiredQueryParam } from 'hooks/useRequiredQueryParam'; import { IFeatureStrategy } from 'interfaces/strategy'; @@ -26,8 +25,10 @@ export const StrategyVariants: FC<{ const projectId = useRequiredPathParam('projectId'); const environment = useRequiredQueryParam('environmentId'); const [variantsEdit, setVariantsEdit] = useState([]); - const [newVariant, setNewVariant] = useState(); - const { defaultStickiness, loading } = useDefaultProjectSettings(projectId); + const stickiness = + strategy?.parameters && 'stickiness' in strategy?.parameters + ? String(strategy.parameters.stickiness) + : 'default'; useEffect(() => { setVariantsEdit( @@ -41,19 +42,6 @@ export const StrategyVariants: FC<{ ); }, []); - useEffect(() => { - setStrategy(prev => ({ - ...prev, - variants: variantsEdit.map(variant => ({ - name: variant.name, - weight: variant.weight, - stickiness: variant.stickiness, - payload: variant.payload, - weightType: variant.weightType, - })), - })); - }, [JSON.stringify(variantsEdit)]); - const updateVariant = (updatedVariant: IFeatureVariantEdit, id: string) => { setVariantsEdit(prevVariants => updateWeightEdit( @@ -63,6 +51,16 @@ export const StrategyVariants: FC<{ 1000 ) ); + setStrategy(prev => ({ + ...prev, + variants: variantsEdit.map(variant => ({ + name: variant.name, + weight: variant.weight, + stickiness, + payload: variant.payload, + weightType: variant.weightType, + })), + })); }; const addVariant = () => { @@ -73,24 +71,23 @@ export const StrategyVariants: FC<{ name: '', weightType: WeightType.VARIABLE, weight: 0, - overrides: [], - stickiness: - variantsEdit?.length > 0 - ? variantsEdit[0].stickiness - : defaultStickiness, + stickiness, new: true, isValid: false, id, }, ]); - setNewVariant(id); }; return ( <> + + Variants + {variantsEdit.map(variant => (