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

move legal/deleted values up

This commit is contained in:
Thomas Heartman 2025-05-07 12:11:22 +02:00
parent 4d4a6b422a
commit 7a25c2e23f
3 changed files with 77 additions and 105 deletions

View File

@ -6,7 +6,10 @@ import {
} from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/useConstraintInput/useConstraintInput';
import { stringOperators, type Operator } from 'constants/operators';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import type { IUnleashContextDefinition } from 'interfaces/context';
import type {
ILegalValue,
IUnleashContextDefinition,
} from 'interfaces/context';
import type { IConstraint } from 'interfaces/strategy';
import { useMemo, useRef, type FC } from 'react';
import { operatorsForContext } from 'utils/operatorsForContext';
@ -24,7 +27,6 @@ import { ReactComponent as NotEqualsIcon } from 'assets/icons/constraint-not-equ
import { AddSingleValueWidget } from './AddSingleValueWidget';
import { ConstraintDateInput } from './ConstraintDateInput';
import { LegalValuesSelector } from './LegalValuesSelector';
import { resolveLegalValues } from './resolve-legal-values';
import { constraintValidator } from './constraint-validator';
const Container = styled('article')(({ theme }) => ({
@ -186,14 +188,17 @@ type Props = {
contextDefinition: Pick<IUnleashContextDefinition, 'legalValues'>;
constraintValues: string[];
updateConstraint: (action: ConstraintUpdateAction) => void;
deletedLegalValues?: Set<string>;
legalValues?: ILegalValue[];
};
export const EditableConstraint: FC<Props> = ({
localConstraint,
onDelete,
contextDefinition,
constraintValues,
updateConstraint,
deletedLegalValues,
legalValues,
}) => {
const { input } = useConstraintInput({
contextDefinition,
@ -391,11 +396,6 @@ export const EditableConstraint: FC<Props> = ({
{inputType.input === 'legal values' ? (
<LegalValuesContainer>
<LegalValuesSelector
data={resolveLegalValues(
constraintValues,
contextDefinition.legalValues,
)}
constraintValues={constraintValues}
values={localConstraint.values || new Set()}
clearAll={() =>
updateConstraint({
@ -414,6 +414,8 @@ export const EditableConstraint: FC<Props> = ({
payload: value,
})
}
deletedLegalValues={deletedLegalValues}
legalValues={legalValues ?? []}
/>
</LegalValuesContainer>
) : null}

View File

@ -1,4 +1,4 @@
import { useState } from 'react';
import { useMemo, useState } from 'react';
import type { IConstraint } from 'interfaces/strategy';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import type { IUnleashContextDefinition } from 'interfaces/context';
@ -72,9 +72,43 @@ export const EditableConstraintWrapper = ({
onDelete,
onAutoSave,
}: IConstraintAccordionEditProps) => {
const [localConstraint, setLocalConstraint] = useState(() => {
const withSet = {
...constraint,
values: new Set(constraint.values),
};
return cleanConstraint(withSet);
});
const { context } = useUnleashContext();
const [contextDefinition, setContextDefinition] = useState(
resolveContextDefinition(context, localConstraint.contextName),
);
const deletedLegalValues = useMemo(() => {
if (
contextDefinition.legalValues?.length &&
constraint.values?.length
) {
const currentLegalValues = new Set(
contextDefinition.legalValues.map(({ value }) => value),
);
const deletedValues = new Set(constraint.values).difference(
currentLegalValues,
);
return deletedValues;
}
return undefined;
}, [
JSON.stringify(contextDefinition.legalValues),
JSON.stringify(constraint.values),
]);
const constraintReducer = (
state: ConstraintWithValueSet,
action: ConstraintUpdateAction,
deletedLegalValues?: Set<string>,
): ConstraintWithValueSet => {
switch (action.type) {
case 'set context field':
@ -127,9 +161,15 @@ export const EditableConstraintWrapper = ({
value: '',
});
case 'add value(s)': {
const combinedValues = state.values?.union(
new Set(action.payload),
);
const filteredValues = deletedLegalValues
? combinedValues?.difference(deletedLegalValues)
: deletedLegalValues;
return {
...state,
values: state.values?.union(new Set(action.payload)),
values: filteredValues,
};
}
case 'set value':
@ -153,21 +193,12 @@ export const EditableConstraintWrapper = ({
}
};
const [localConstraint, setLocalConstraint] = useState(() => {
const withSet = {
...constraint,
values: new Set(constraint.values),
};
return cleanConstraint(withSet);
});
const { context } = useUnleashContext();
const [contextDefinition, setContextDefinition] = useState(
resolveContextDefinition(context, localConstraint.contextName),
);
const updateConstraint = (action: ConstraintUpdateAction) => {
const nextState = constraintReducer(localConstraint, action);
const nextState = constraintReducer(
localConstraint,
action,
deletedLegalValues,
);
const contextFieldHasChanged =
localConstraint.contextName !== nextState.contextName;
@ -191,6 +222,8 @@ export const EditableConstraintWrapper = ({
constraintValues={constraint?.values || []}
contextDefinition={contextDefinition}
updateConstraint={updateConstraint}
deletedLegalValues={deletedLegalValues}
legalValues={contextDefinition.legalValues}
/>
);
};

View File

@ -1,54 +1,21 @@
import { useState } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Alert, Button, Checkbox, styled } from '@mui/material';
import type { ILegalValue } from 'interfaces/context';
import {
filterLegalValues,
LegalValueLabel,
} from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/LegalValueLabel/LegalValueLabel';
import { ConstraintValueSearch } from './ConstraintValueSearch';
import type { ILegalValue } from 'interfaces/context';
interface IRestrictiveLegalValuesProps {
data: {
legalValues: ILegalValue[];
deletedLegalValues: ILegalValue[];
};
constraintValues: string[];
values: Set<string>;
addValues: (values: string[]) => void;
removeValue: (value: string) => void;
clearAll: () => void;
beforeValues?: JSX.Element;
deletedLegalValues?: Set<string>;
legalValues: ILegalValue[];
}
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))',
@ -71,41 +38,17 @@ const LegalValuesSelectorWidget = styled('article')(({ theme }) => ({
}));
export const LegalValuesSelector = ({
data,
legalValues,
values,
addValues,
removeValue,
clearAll,
constraintValues,
deletedLegalValues,
}: IRestrictiveLegalValuesProps) => {
const [filter, setFilter] = useState('');
const { legalValues, deletedLegalValues } = data;
const filteredValues = filterLegalValues(legalValues, filter);
const cleanDeletedLegalValues = (constraintValues: string[]): string[] => {
const deletedValuesSet = getLegalValueSet(deletedLegalValues);
return (
constraintValues?.filter((value) => !deletedValuesSet.has(value)) ||
[]
);
};
const illegalValues = getIllegalValues(
constraintValues,
deletedLegalValues,
);
//todo: maybe move this up?
// useEffect(() => {
// if (illegalValues.length > 0) {
// removeValues(...illegalValues)
// // todo: impl this
// console.log('would clean deleted values here');
// // setvalues(cleandeletedlegalvalues(values));
// }
// }, []);
const onChange = (legalValue: string) => {
if (values.has(legalValue)) {
removeValue(legalValue);
@ -137,22 +80,18 @@ export const LegalValuesSelector = ({
return (
<LegalValuesSelectorWidget>
<ConditionallyRender
condition={Boolean(illegalValues && illegalValues.length > 0)}
show={
<Alert severity='warning'>
This constraint is using legal values that have been
deleted as valid options. 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>
}
/>
{deletedLegalValues?.size ? (
<Alert severity='warning'>
This constraint is using legal values that have been deleted
as valid options. If you save changes on this constraint and
then save the strategy the following values will be removed:
<ul>
{[...deletedLegalValues].map((value) => (
<li key={value}>{value}</li>
))}
</ul>
</Alert>
) : null}
<p>Select values from a predefined set</p>
<Row>
<ConstraintValueSearch
@ -182,9 +121,7 @@ export const LegalValuesSelector = ({
onChange={() => onChange(match.value)}
name='legal-value'
color='primary'
disabled={deletedLegalValues
.map(({ value }) => value)
.includes(match.value)}
disabled={deletedLegalValues?.has(match.value)}
/>
}
/>