Skip to content

Commit

Permalink
Feat/new strategy configuration general tab (#5628)
Browse files Browse the repository at this point in the history
* Adds the new general tab settings behind a feature flag
* Adds a test for the FlexibleStrategy component
  • Loading branch information
FredrikOseberg committed Dec 13, 2023
1 parent 54316ca commit c552f3a
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 22 deletions.
9 changes: 8 additions & 1 deletion frontend/src/component/common/select.tsx
Expand Up @@ -24,6 +24,7 @@ export interface ISelectMenuProps {
disabled?: boolean;
className?: string;
classes?: any;
formControlStyles?: React.CSSProperties;
}

const SelectMenu: React.FC<ISelectMenuProps> = ({
Expand All @@ -36,6 +37,7 @@ const SelectMenu: React.FC<ISelectMenuProps> = ({
disabled = false,
className,
classes,
formControlStyles = {},
...rest
}) => {
const renderSelectItems = () =>
Expand All @@ -51,7 +53,12 @@ const SelectMenu: React.FC<ISelectMenuProps> = ({
));

return (
<FormControl variant='outlined' size='small' classes={classes}>
<FormControl
variant='outlined'
size='small'
classes={classes}
style={formControlStyles}
>
<InputLabel htmlFor={id}>{label}</InputLabel>
<Select
name={name}
Expand Down
@@ -1,14 +1,50 @@
import { FormControlLabel, Switch } from '@mui/material';
import {
Box,
FormControlLabel,
Switch,
Typography,
styled,
} from '@mui/material';
import { useUiFlag } from 'hooks/useUiFlag';
import { VFC } from 'react';

interface IFeatureStrategyEnabledDisabledProps {
enabled: boolean;
onToggleEnabled: () => void;
}

const StyledBox = styled(Box)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: theme.palette.background.elevation1,
padding: theme.spacing(2),
borderRadius: `${theme.shape.borderRadiusMedium}px`,
}));

export const FeatureStrategyEnabledDisabled: VFC<
IFeatureStrategyEnabledDisabledProps
> = ({ enabled, onToggleEnabled }) => {
const strategyConfigurationEnabled = useUiFlag('newStrategyConfiguration');

if (strategyConfigurationEnabled) {
return (
<StyledBox>
<Typography>Strategy Status</Typography>
<FormControlLabel
control={
<Switch
name='enabled'
onChange={onToggleEnabled}
checked={enabled}
/>
}
label='Enabled'
/>
</StyledBox>
);
}

return (
<FormControlLabel
control={
Expand Down
Expand Up @@ -249,14 +249,6 @@ export const NewFeatureStrategyForm = ({
}));
}}
/>
<FeatureStrategyType
strategy={strategy}
strategyDefinition={strategyDefinition}
setStrategy={setStrategy}
validateParameter={validateParameter}
errors={errors}
hasAccess={access}
/>
<FeatureStrategyEnabledDisabled
enabled={!strategy?.disabled}
onToggleEnabled={() =>
Expand All @@ -266,6 +258,14 @@ export const NewFeatureStrategyForm = ({
}))
}
/>
<FeatureStrategyType
strategy={strategy}
strategyDefinition={strategyDefinition}
setStrategy={setStrategy}
validateParameter={validateParameter}
errors={errors}
hasAccess={access}
/>
</>
}
/>
Expand Down
@@ -0,0 +1,63 @@
import { useState } from 'react';
import { screen, fireEvent, within } from '@testing-library/react';
import FlexibleStrategy from './FlexibleStrategy';
import { render } from 'utils/testRenderer';
import { Route, Routes } from 'react-router-dom';
import { testServerSetup, testServerRoute } from 'utils/testServer';

const server = testServerSetup();

const setupApi = () => {
testServerRoute(server, '/api/admin/projects/default', {});
};

test('manipulates the rollout slider', async () => {
const Wrapper = () => {
const [parameters, setParameters] = useState({
groupId: 'testid',
rollout: '0',
stickiness: 'default',
});

const updateParameter = (parameter: string, value: string) => {
setParameters((prevParameters) => ({
...prevParameters,
[parameter]: value,
}));
};

return (
<Routes>
<Route
path='/projects/:projectId/features/:featureName'
element={
<FlexibleStrategy
parameters={parameters}
updateParameter={updateParameter}
context={{}}
editable={true}
/>
}
/>
</Routes>
);
};

setupApi();

render(<Wrapper />, {
route: '/projects/default/features/test',
});

const slider = await screen.findByRole('slider', { name: /rollout/i });
const groupIdInput = await screen.getByLabelText('groupId');

expect(slider).toHaveValue('0');
expect(groupIdInput).toHaveValue('testid');

fireEvent.change(slider, { target: { value: '50' } });
fireEvent.change(groupIdInput, { target: { value: 'newGroupId' } });

expect(slider).toHaveValue('50');
expect(groupIdInput).toHaveValue('newGroupId');
});
@@ -1,4 +1,4 @@
import { Typography } from '@mui/material';
import { Box, Typography, styled } from '@mui/material';
import { IFeatureStrategyParameters } from 'interfaces/strategy';
import RolloutSlider from '../RolloutSlider/RolloutSlider';
import Input from 'component/common/Input/Input';
Expand All @@ -17,6 +17,7 @@ import Loader from '../../../common/Loader/Loader';
import { useEffect, useMemo } from 'react';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useLocation } from 'react-router';
import { useUiFlag } from 'hooks/useUiFlag';

interface IFlexibleStrategyProps {
parameters: IFeatureStrategyParameters;
Expand All @@ -25,6 +26,31 @@ interface IFlexibleStrategyProps {
editable: boolean;
}

const StyledBox = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.background.elevation1,
padding: theme.spacing(2),
borderRadius: `${theme.shape.borderRadiusMedium}px`,
}));

const StyledOuterBox = styled(Box)(({ theme }) => ({
marginTop: '1rem',
display: 'flex',
width: '100%',
justifyContent: 'space-between',
}));

const StyledInnerBox1 = styled(Box)(({ theme }) => ({
width: '50%',
marginRight: theme.spacing(0.5),
}));

const StyledInnerBox2 = styled(Box)(({ theme }) => ({
width: '50%',
marginLeft: theme.spacing(0.5),
}));

const FlexibleStrategy = ({
updateParameter,
parameters,
Expand All @@ -34,6 +60,8 @@ const FlexibleStrategy = ({
const { defaultStickiness, loading } = useDefaultProjectSettings(projectId);
const { pathname } = useLocation();

const newStrategyConfiguration = useUiFlag('newStrategyConfiguration');

const isDefaultStrategyEdit = pathname.includes('default-strategy');
const onUpdate = (field: string) => (newValue: string) => {
updateParameter(field, newValue);
Expand Down Expand Up @@ -70,6 +98,45 @@ const FlexibleStrategy = ({
return <Loader />;
}

if (newStrategyConfiguration) {
return (
<StyledBox>
<RolloutSlider
name='Rollout'
value={rollout}
disabled={!editable}
onChange={updateRollout}
/>
<StyledOuterBox>
<StyledInnerBox1>
<StickinessSelect
label='Stickiness'
value={stickiness}
editable={editable}
dataTestId={FLEXIBLE_STRATEGY_STICKINESS_ID}
onChange={(e) =>
onUpdate('stickiness')(e.target.value)
}
/>
</StyledInnerBox1>
<StyledInnerBox2>
<Input
label='groupId'
sx={{ width: '100%' }}
id='groupId-input'
value={parseParameterString(parameters.groupId)}
disabled={!editable}
onChange={(e) =>
onUpdate('groupId')(e.target.value)
}
data-testid={FLEXIBLE_STRATEGY_GROUP_ID}
/>
</StyledInnerBox2>
</StyledOuterBox>
</StyledBox>
);
}

return (
<div>
<RolloutSlider
Expand Down
@@ -1,6 +1,7 @@
import Select from 'component/common/select';
import { SelectChangeEvent, useTheme } from '@mui/material';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import { useUiFlag } from 'hooks/useUiFlag';

type OptionType = { key: string; label: string };

Expand All @@ -22,6 +23,7 @@ export const StickinessSelect = ({
dataTestId,
}: IStickinessSelectProps) => {
const { context } = useUnleashContext();
const newStrategyConfiguration = useUiFlag('newStrategyConfiguration');
const theme = useTheme();

const resolveStickinessOptions = () => {
Expand Down Expand Up @@ -51,6 +53,9 @@ export const StickinessSelect = ({
return options;
};

// newStrategyConfiguration - Temporary check for backwards compatibility
const formControlStyles = newStrategyConfiguration ? { width: '100%' } : {};

const stickinessOptions = resolveStickinessOptions();
return (
<Select
Expand All @@ -63,10 +68,10 @@ export const StickinessSelect = ({
data-testid={dataTestId}
onChange={onChange}
style={{
width: 'inherit',
minWidth: '100%',
marginBottom: theme.spacing(2),
}}
formControlStyles={formControlStyles}
/>
);
};

0 comments on commit c552f3a

Please sign in to comment.