mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
delete restricted legal values selector
This commit is contained in:
parent
730578b50c
commit
d2521312b8
@ -1,119 +0,0 @@
|
||||
import { render } from 'utils/testRenderer';
|
||||
import { fireEvent, screen } from '@testing-library/react';
|
||||
import { RestrictiveLegalValues } from './RestrictiveLegalValues.tsx';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
vi.mock('../../../../../../hooks/useUiFlag', () => ({
|
||||
useUiFlag: vi.fn(
|
||||
(flag: string) => flag !== 'disableShowContextFieldSelectionValues',
|
||||
),
|
||||
}));
|
||||
|
||||
test('should show alert when you have illegal legal values', async () => {
|
||||
const contextDefinitionValues = [{ value: 'value1' }, { value: 'value2' }];
|
||||
const fixedValues = ['value1', 'value2'];
|
||||
const localValues = ['value1', 'value2'];
|
||||
const deletedLegalValues = [{ value: 'value1' }];
|
||||
|
||||
render(
|
||||
<RestrictiveLegalValues
|
||||
data={{ legalValues: contextDefinitionValues, deletedLegalValues }}
|
||||
constraintValues={fixedValues}
|
||||
values={localValues}
|
||||
setValues={() => {}}
|
||||
setValuesWithRecord={() => {}}
|
||||
error={''}
|
||||
setError={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
await screen.findByText(
|
||||
'This constraint is currently using values that were valid in the past but have since been deleted. If you save changes on this constraint and then save the strategy the following values will be removed:',
|
||||
);
|
||||
});
|
||||
|
||||
test('Should remove illegal legal values from internal value state when mounting', () => {
|
||||
const contextDefinitionValues = [{ value: 'value1' }, { value: 'value2' }];
|
||||
const fixedValues = ['value1', 'value2'];
|
||||
let localValues = ['value1', 'value2'];
|
||||
const deletedLegalValues = [{ value: 'value1' }];
|
||||
|
||||
const setValues = (values: string[]) => {
|
||||
localValues = values;
|
||||
};
|
||||
|
||||
render(
|
||||
<RestrictiveLegalValues
|
||||
data={{
|
||||
legalValues: contextDefinitionValues,
|
||||
deletedLegalValues,
|
||||
}}
|
||||
constraintValues={fixedValues}
|
||||
values={localValues}
|
||||
setValues={setValues}
|
||||
setValuesWithRecord={() => {}}
|
||||
error={''}
|
||||
setError={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(localValues).toEqual(['value2']);
|
||||
});
|
||||
|
||||
test('Should select all', async () => {
|
||||
const contextDefinitionValues = [{ value: 'value1' }, { value: 'value2' }];
|
||||
let localValues: string[] = [];
|
||||
|
||||
const setValuesWithRecord = (values: string[]) => {
|
||||
localValues = values;
|
||||
};
|
||||
|
||||
render(
|
||||
<RestrictiveLegalValues
|
||||
data={{
|
||||
legalValues: contextDefinitionValues,
|
||||
deletedLegalValues: [{ value: 'value3' }],
|
||||
}}
|
||||
constraintValues={[]}
|
||||
values={localValues}
|
||||
setValues={() => {}}
|
||||
setValuesWithRecord={setValuesWithRecord}
|
||||
error={''}
|
||||
setError={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const selectedAllButton = await screen.findByText(/Select all/i);
|
||||
|
||||
fireEvent.click(selectedAllButton);
|
||||
expect(localValues).toEqual(['value1', 'value2']);
|
||||
});
|
||||
|
||||
test('Should unselect all', async () => {
|
||||
const contextDefinitionValues = [{ value: 'value1' }, { value: 'value2' }];
|
||||
let localValues: string[] = ['value1', 'value2'];
|
||||
|
||||
const setValuesWithRecord = (values: string[]) => {
|
||||
localValues = values;
|
||||
};
|
||||
|
||||
render(
|
||||
<RestrictiveLegalValues
|
||||
data={{
|
||||
legalValues: contextDefinitionValues,
|
||||
deletedLegalValues: [{ value: 'value3' }],
|
||||
}}
|
||||
constraintValues={[]}
|
||||
values={localValues}
|
||||
setValues={() => {}}
|
||||
setValuesWithRecord={setValuesWithRecord}
|
||||
error={''}
|
||||
setError={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const selectedAllButton = await screen.findByText(/Unselect all/i);
|
||||
|
||||
fireEvent.click(selectedAllButton);
|
||||
expect(localValues).toEqual([]);
|
||||
});
|
@ -1,256 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Alert, Button, Checkbox, Chip, Stack, styled } from '@mui/material';
|
||||
import { ConstraintValueSearch } from 'component/common/LegacyConstraintAccordion/ConstraintValueSearch/ConstraintValueSearch';
|
||||
import { ConstraintFormHeader } from '../ConstraintFormHeader/ConstraintFormHeader.tsx';
|
||||
import type { ILegalValue } from 'interfaces/context';
|
||||
import {
|
||||
filterLegalValues,
|
||||
LegalValueLabel,
|
||||
} from '../LegalValueLabel/LegalValueLabel.tsx';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
interface IRestrictiveLegalValuesProps {
|
||||
data: {
|
||||
legalValues: ILegalValue[];
|
||||
deletedLegalValues: ILegalValue[];
|
||||
};
|
||||
constraintValues: string[];
|
||||
values: string[];
|
||||
setValues: (values: string[]) => void;
|
||||
setValuesWithRecord: (values: string[]) => void;
|
||||
beforeValues?: JSX.Element;
|
||||
error: string;
|
||||
setError: React.Dispatch<React.SetStateAction<string>>;
|
||||
}
|
||||
|
||||
interface IValuesMap {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
const createValuesMap = (values: string[]): IValuesMap => {
|
||||
return values.reduce((result: IValuesMap, currentValue: string) => {
|
||||
if (!result[currentValue]) {
|
||||
result[currentValue] = true;
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
};
|
||||
|
||||
export const getLegalValueSet = (values: ILegalValue[]) => {
|
||||
return new Set(values.map(({ value }) => value));
|
||||
};
|
||||
|
||||
export const getIllegalValues = (
|
||||
constraintValues: string[],
|
||||
deletedLegalValues: ILegalValue[],
|
||||
) => {
|
||||
const deletedValuesSet = getLegalValueSet(deletedLegalValues);
|
||||
|
||||
return constraintValues.filter(
|
||||
(value) => value !== '' && deletedValuesSet.has(value),
|
||||
);
|
||||
};
|
||||
|
||||
const StyledValuesContainer = styled('div')(({ theme }) => ({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',
|
||||
gap: theme.spacing(1),
|
||||
padding: theme.spacing(2),
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
maxHeight: '378px',
|
||||
overflow: 'auto',
|
||||
}));
|
||||
|
||||
const StyledChipList = styled('ul')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
listStyle: 'none',
|
||||
gap: theme.spacing(1),
|
||||
padding: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledStack = styled(Stack)(({ theme }) => ({
|
||||
marginTop: theme.spacing(2),
|
||||
marginBottom: theme.spacing(0.5),
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
const ErrorText = styled('p')(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
color: theme.palette.error.main,
|
||||
}));
|
||||
|
||||
/**
|
||||
* @deprecated use `/component/feature/FeatureStrategy/FeatureStrategyConstraints/LegalValuesSelector.tsx`
|
||||
* Remove with flag `addEditStrategy`
|
||||
*/
|
||||
export const RestrictiveLegalValues = ({
|
||||
data,
|
||||
values,
|
||||
setValues,
|
||||
setValuesWithRecord,
|
||||
error,
|
||||
setError,
|
||||
constraintValues,
|
||||
}: IRestrictiveLegalValuesProps) => {
|
||||
const [filter, setFilter] = useState('');
|
||||
const { legalValues, deletedLegalValues } = data;
|
||||
|
||||
const filteredValues = filterLegalValues(legalValues, filter);
|
||||
|
||||
// Lazily initialise the values because there might be a lot of them.
|
||||
const [valuesMap, setValuesMap] = useState(() => createValuesMap(values));
|
||||
|
||||
const disableShowContextFieldSelectionValues = useUiFlag(
|
||||
'disableShowContextFieldSelectionValues',
|
||||
);
|
||||
|
||||
const cleanDeletedLegalValues = (constraintValues: string[]): string[] => {
|
||||
const deletedValuesSet = getLegalValueSet(deletedLegalValues);
|
||||
return (
|
||||
constraintValues?.filter((value) => !deletedValuesSet.has(value)) ||
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
const illegalValues = getIllegalValues(
|
||||
constraintValues,
|
||||
deletedLegalValues,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setValuesMap(createValuesMap(values));
|
||||
}, [values, setValuesMap, createValuesMap]);
|
||||
|
||||
useEffect(() => {
|
||||
if (illegalValues.length > 0) {
|
||||
setValues(cleanDeletedLegalValues(values));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onChange = (legalValue: string) => {
|
||||
setError('');
|
||||
|
||||
if (valuesMap[legalValue]) {
|
||||
const index = values.findIndex((value) => value === legalValue);
|
||||
const newValues = [...values];
|
||||
newValues.splice(index, 1);
|
||||
setValuesWithRecord(newValues);
|
||||
return;
|
||||
}
|
||||
|
||||
setValuesWithRecord([...cleanDeletedLegalValues(values), legalValue]);
|
||||
};
|
||||
|
||||
const isAllSelected = legalValues.every((value) =>
|
||||
values.includes(value.value),
|
||||
);
|
||||
|
||||
const onSelectAll = () => {
|
||||
if (isAllSelected) {
|
||||
return setValuesWithRecord([]);
|
||||
}
|
||||
setValuesWithRecord([
|
||||
...legalValues.map((legalValue) => legalValue.value),
|
||||
]);
|
||||
};
|
||||
|
||||
const handleSearchKeyDown = (event: React.KeyboardEvent) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
if (filteredValues.length > 0) {
|
||||
const firstValue = filteredValues[0].value;
|
||||
onChange(firstValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(illegalValues && illegalValues.length > 0)}
|
||||
show={
|
||||
<Alert severity='warning'>
|
||||
This constraint is currently using values that were
|
||||
valid in the past but have since been deleted. If you
|
||||
save changes on this constraint and then save the
|
||||
strategy the following values will be removed:
|
||||
<ul>
|
||||
{illegalValues?.map((value) => (
|
||||
<li key={value}>{value}</li>
|
||||
))}
|
||||
</ul>
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<StyledStack direction={'row'}>
|
||||
<ConstraintFormHeader>
|
||||
Select values from a predefined set
|
||||
</ConstraintFormHeader>
|
||||
<Button variant={'text'} onClick={onSelectAll}>
|
||||
{isAllSelected ? 'Unselect all' : 'Select all'}
|
||||
</Button>
|
||||
</StyledStack>
|
||||
<ConditionallyRender
|
||||
condition={legalValues.length > 100}
|
||||
show={
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
!disableShowContextFieldSelectionValues &&
|
||||
Boolean(values)
|
||||
}
|
||||
show={
|
||||
<StyledChipList
|
||||
sx={{ border: 0, paddingTop: 0 }}
|
||||
>
|
||||
{values.map((value) => {
|
||||
return (
|
||||
<li key={value}>
|
||||
<Chip
|
||||
label={value}
|
||||
onDelete={() =>
|
||||
onChange(value)
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</StyledChipList>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div onKeyDown={handleSearchKeyDown}>
|
||||
<ConstraintValueSearch filter={filter} setFilter={setFilter} />
|
||||
</div>
|
||||
<StyledValuesContainer>
|
||||
{filteredValues.map((match) => (
|
||||
<LegalValueLabel
|
||||
key={match.value}
|
||||
legal={match}
|
||||
filter={filter}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={Boolean(valuesMap[match.value])}
|
||||
onChange={() => onChange(match.value)}
|
||||
name={match.value}
|
||||
color='primary'
|
||||
disabled={deletedLegalValues
|
||||
.map(({ value }) => value)
|
||||
.includes(match.value)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</StyledValuesContainer>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(error)}
|
||||
show={<ErrorText>{error}</ErrorText>}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user