1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-18 13:48:58 +02:00

clean some more

This commit is contained in:
Thomas Heartman 2025-05-07 10:54:53 +02:00
parent 47843b3c52
commit 275cac95c5
4 changed files with 77 additions and 47 deletions

View File

@ -28,7 +28,7 @@ const AddValuesButton = styled('button')(({ theme }) => ({
})); }));
interface AddValuesProps { interface AddValuesProps {
onAddValues: (newValues: string[]) => void; onAddValues: (newValues: Set<string>) => void;
helpText?: string; helpText?: string;
validator: (...values: string[]) => ConstraintValidatorOutput; validator: (...values: string[]) => ConstraintValidatorOutput;
} }
@ -60,7 +60,7 @@ export const AddValuesWidget = forwardRef<HTMLButtonElement, AddValuesProps>(
const [isValid, errorMessage] = validator(...newValues); const [isValid, errorMessage] = validator(...newValues);
if (isValid) { if (isValid) {
onAddValues(newValues); onAddValues(new Set(newValues));
clearInput(); clearInput();
setError(''); setError('');
} else { } else {

View File

@ -167,6 +167,9 @@ const getInputType = (input: Input): InputType => {
} }
}; };
type ConstraintWithValueSet = Omit<IConstraint, 'values'> & {
values?: Set<string>;
};
type ConstraintUpdateAction = type ConstraintUpdateAction =
| { type: 'add value(s)'; payload: string[] } | { type: 'add value(s)'; payload: string[] }
| { type: 'set value'; payload: string } | { type: 'set value'; payload: string }
@ -178,7 +181,7 @@ type ConstraintUpdateAction =
| { type: 'toggle inverted operator' }; | { type: 'toggle inverted operator' };
type Props = { type Props = {
localConstraint: IConstraint; localConstraint: ConstraintWithValueSet;
onDelete?: () => void; onDelete?: () => void;
contextDefinition: Pick<IUnleashContextDefinition, 'legalValues'>; contextDefinition: Pick<IUnleashContextDefinition, 'legalValues'>;
constraintValues: string[]; constraintValues: string[];
@ -194,6 +197,7 @@ export const EditableConstraint: FC<Props> = ({
}) => { }) => {
const { input } = useConstraintInput({ const { input } = useConstraintInput({
contextDefinition, contextDefinition,
// @ts-ignore
localConstraint, localConstraint,
}); });
@ -352,7 +356,11 @@ export const EditableConstraint: FC<Props> = ({
</OperatorOptions> </OperatorOptions>
</ConstraintOptions> </ConstraintOptions>
<ValueList <ValueList
values={localConstraint.values} values={
localConstraint.values
? Array.from(localConstraint.values)
: undefined
}
removeValue={(value) => removeValue={(value) =>
updateConstraint({ updateConstraint({
type: 'remove value from list', type: 'remove value from list',
@ -388,7 +396,7 @@ export const EditableConstraint: FC<Props> = ({
contextDefinition.legalValues, contextDefinition.legalValues,
)} )}
constraintValues={constraintValues} constraintValues={constraintValues}
values={localConstraint.values || []} values={localConstraint.values || new Set()}
clearAll={() => clearAll={() =>
updateConstraint({ updateConstraint({
type: 'clear values', type: 'clear values',

View File

@ -1,16 +1,17 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import type { IConstraint } from 'interfaces/strategy'; import type { IConstraint } from 'interfaces/strategy';
import { cleanConstraint } from 'utils/cleanConstraint';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import type { IUnleashContextDefinition } from 'interfaces/context'; import type { IUnleashContextDefinition } from 'interfaces/context';
import { import {
DATE_AFTER, DATE_AFTER,
dateOperators, dateOperators,
IN, IN,
singleValueOperators,
type Operator, type Operator,
} from 'constants/operators'; } from 'constants/operators';
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint'; import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint';
import { CURRENT_TIME_CONTEXT_FIELD } from 'utils/operatorsForContext'; import { CURRENT_TIME_CONTEXT_FIELD } from 'utils/operatorsForContext';
import produce from 'immer';
interface IConstraintAccordionEditProps { interface IConstraintAccordionEditProps {
constraint: IConstraint; constraint: IConstraint;
@ -50,15 +51,31 @@ type ConstraintUpdateAction =
| { type: 'toggle case sensitivity' } | { type: 'toggle case sensitivity' }
| { type: 'toggle inverted operator' }; | { type: 'toggle inverted operator' };
type ConstraintWithValueSet = Omit<IConstraint, 'values'> & {
values?: Set<string>;
};
const cleanConstraint = (
constraint: Readonly<ConstraintWithValueSet>,
): ConstraintWithValueSet => {
return produce(constraint, (draft) => {
if (singleValueOperators.includes(constraint.operator)) {
delete draft.values;
} else {
delete draft.value;
}
});
};
export const EditableConstraintWrapper = ({ export const EditableConstraintWrapper = ({
constraint, constraint,
onDelete, onDelete,
onAutoSave, onAutoSave,
}: IConstraintAccordionEditProps) => { }: IConstraintAccordionEditProps) => {
const constraintReducer = ( const constraintReducer = (
state: IConstraint, state: ConstraintWithValueSet,
action: ConstraintUpdateAction, action: ConstraintUpdateAction,
): IConstraint => { ): ConstraintWithValueSet => {
switch (action.type) { switch (action.type) {
case 'set context field': case 'set context field':
if ( if (
@ -68,7 +85,7 @@ export const EditableConstraintWrapper = ({
return cleanConstraint({ return cleanConstraint({
...state, ...state,
operator: DATE_AFTER, operator: DATE_AFTER,
values: [], values: new Set(),
value: new Date().toISOString(), value: new Date().toISOString(),
}); });
} else if ( } else if (
@ -78,7 +95,8 @@ export const EditableConstraintWrapper = ({
return cleanConstraint({ return cleanConstraint({
...state, ...state,
operator: IN, operator: IN,
values: [], values: new Set(),
value: '', value: '',
}); });
} }
@ -86,22 +104,23 @@ export const EditableConstraintWrapper = ({
return cleanConstraint({ return cleanConstraint({
...state, ...state,
contextName: action.payload, contextName: action.payload,
values: [], values: new Set(),
value: '', value: '',
}); });
case 'set operator': case 'set operator':
return cleanConstraint({ return cleanConstraint({
...state, ...state,
operator: action.payload, operator: action.payload,
values: [], values: new Set(),
value: '', value: '',
}); });
case 'add value(s)': { case 'add value(s)': {
const combinedValues = new Set([ return {
...(state.values || []), ...state,
...action.payload, values: state.values?.union(new Set(action.payload)),
]); };
return { ...state, values: Array.from(combinedValues) };
} }
case 'set value': case 'set value':
return { ...state, value: action.payload }; return { ...state, value: action.payload };
@ -110,25 +129,35 @@ export const EditableConstraintWrapper = ({
case 'toggle case sensitivity': case 'toggle case sensitivity':
return { ...state, caseInsensitive: !state.inverted }; return { ...state, caseInsensitive: !state.inverted };
case 'remove value from list': case 'remove value from list':
state.values?.delete(action.payload);
return { return {
...state, ...state,
values: (state.values ?? []).filter( values: state.values ?? new Set(),
(value) => value !== action.payload,
),
}; };
case 'clear values': case 'clear values':
return cleanConstraint({ ...state, values: [], value: '' }); return cleanConstraint({
...state,
values: new Set(),
value: '',
});
} }
}; };
const [localConstraint, setLocalConstraint] = useState( const [localConstraint, setLocalConstraint] = useState(() => {
cleanConstraint(constraint), const withSet = {
); ...constraint,
values: new Set(constraint.values),
};
return cleanConstraint(withSet);
});
const updateConstraint = (action: ConstraintUpdateAction) => { const updateConstraint = (action: ConstraintUpdateAction) => {
const nextState = constraintReducer(localConstraint, action); const nextState = constraintReducer(localConstraint, action);
setLocalConstraint(nextState); setLocalConstraint(nextState);
onAutoSave(nextState); onAutoSave({
...nextState,
values: Array.from(nextState.values ?? []),
});
}; };
const { context } = useUnleashContext(); const { context } = useUnleashContext();

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'; import { useState } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Alert, Button, Checkbox, styled } from '@mui/material'; import { Alert, Button, Checkbox, styled } from '@mui/material';
import type { ILegalValue } from 'interfaces/context'; import type { ILegalValue } from 'interfaces/context';
@ -14,9 +14,9 @@ interface IRestrictiveLegalValuesProps {
deletedLegalValues: ILegalValue[]; deletedLegalValues: ILegalValue[];
}; };
constraintValues: string[]; constraintValues: string[];
values: string[]; values: Set<string>;
addValues: (values: string[]) => void; addValues: (values: string[]) => void;
removeValue: (values: string) => void; removeValue: (value: string) => void;
clearAll: () => void; clearAll: () => void;
beforeValues?: JSX.Element; beforeValues?: JSX.Element;
} }
@ -83,9 +83,6 @@ export const LegalValuesSelector = ({
const filteredValues = filterLegalValues(legalValues, filter); const filteredValues = filterLegalValues(legalValues, filter);
// Lazily initialise the values because there might be a lot of them.
const [valuesMap, setValuesMap] = useState(() => createValuesMap(values));
const cleanDeletedLegalValues = (constraintValues: string[]): string[] => { const cleanDeletedLegalValues = (constraintValues: string[]): string[] => {
const deletedValuesSet = getLegalValueSet(deletedLegalValues); const deletedValuesSet = getLegalValueSet(deletedLegalValues);
return ( return (
@ -99,29 +96,25 @@ export const LegalValuesSelector = ({
deletedLegalValues, deletedLegalValues,
); );
useEffect(() => { //todo: maybe move this up?
setValuesMap(createValuesMap(values)); // useEffect(() => {
}, [values, setValuesMap, createValuesMap]); // if (illegalValues.length > 0) {
// removeValues(...illegalValues)
useEffect(() => { // // todo: impl this
if (illegalValues.length > 0) { // console.log('would clean deleted values here');
// todo: impl this // // setvalues(cleandeletedlegalvalues(values));
console.log('would clean deleted values here'); // }
// setValues(cleanDeletedLegalValues(values)); // }, []);
}
}, []);
const onChange = (legalValue: string) => { const onChange = (legalValue: string) => {
if (valuesMap[legalValue]) { if (values.has(legalValue)) {
removeValue(legalValue); removeValue(legalValue);
} else { } else {
addValues([legalValue]); addValues([legalValue]);
} }
}; };
const isAllSelected = legalValues.every((value) => const isAllSelected = legalValues.every((value) => values.has(value.value));
values.includes(value.value),
);
const onSelectAll = () => { const onSelectAll = () => {
if (isAllSelected) { if (isAllSelected) {
@ -185,7 +178,7 @@ export const LegalValuesSelector = ({
filter={filter} filter={filter}
control={ control={
<Checkbox <Checkbox
checked={Boolean(valuesMap[match.value])} checked={Boolean(values.has(match.value))}
onChange={() => onChange(match.value)} onChange={() => onChange(match.value)}
name='legal-value' name='legal-value'
color='primary' color='primary'