mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
chore: Set up the basis of the new constraint editing component. (#9701)
This PR creates/steals the logic and basic components that we need for the new constraint editing design and shows it instead of the old one if the flag is on. The interface needs a lot of work, but this essentially wires everything up so that it works with the API on direct editing: <img width="781" alt="image" src="https://github.com/user-attachments/assets/97489a08-5f12-47ee-98b3-aefc0b840a2b" /> Additionally the code here will need a lot of refactoring. This is a first draft where I've yanked all the constraint editing logic out of a nested hierarchy of components that handle validation and lots more. I expect to clean this up significantly before finishing it up, so please excuse the mess it's currently in. It turns out to have been lots and lots more logic than I had anticipated. This is just a PR to get started, so that the next one will be easier to work on.
This commit is contained in:
parent
6ea823f011
commit
5e35a0fa22
@ -33,6 +33,7 @@ export const ConstraintsList: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
result.push(
|
||||
<StyledListItem key={index}>
|
||||
{index > 0 ? (
|
||||
// todo (addEditStrategy): change divider for edit screen (probably a new component or a prop)
|
||||
<ConstraintSeparator key={`${index}-divider`} />
|
||||
) : null}
|
||||
{child}
|
||||
|
@ -96,6 +96,7 @@ export const ConstraintOperatorSelect = ({
|
||||
);
|
||||
};
|
||||
|
||||
// todo (addEditStrategy): add prop to configure the select element or style it. (currently, the chevron is different from the other select element we use). Maybe add a new component.
|
||||
return (
|
||||
<StyledFormInput variant='outlined' size='small' fullWidth>
|
||||
<InputLabel htmlFor='operator-select'>Operator</InputLabel>
|
||||
|
@ -14,6 +14,7 @@ import { StrategySeparator } from 'component/common/StrategySeparator/LegacyStra
|
||||
import { NewConstraintAccordion } from 'component/common/NewConstraintAccordion/NewConstraintAccordion';
|
||||
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { EditableConstraintWrapper } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraintWrapper';
|
||||
|
||||
export interface IConstraintAccordionListProps {
|
||||
constraints: IConstraint[];
|
||||
@ -86,6 +87,7 @@ export const NewConstraintAccordionList = forwardRef<
|
||||
>(({ constraints, setConstraints, state }, ref) => {
|
||||
const { context } = useUnleashContext();
|
||||
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
|
||||
const addEditStrategy = useUiFlag('addEditStrategy');
|
||||
|
||||
const onEdit =
|
||||
setConstraints &&
|
||||
@ -146,19 +148,36 @@ export const NewConstraintAccordionList = forwardRef<
|
||||
return (
|
||||
<StyledContainer id={constraintAccordionListId}>
|
||||
<ConstraintsList>
|
||||
{constraints.map((constraint, index) => (
|
||||
<NewConstraintAccordion
|
||||
key={constraint[constraintId]}
|
||||
constraint={constraint}
|
||||
onEdit={onEdit?.bind(null, constraint)}
|
||||
onCancel={onCancel.bind(null, index)}
|
||||
onDelete={onRemove?.bind(null, index)}
|
||||
onSave={onSave?.bind(null, index)}
|
||||
onAutoSave={onAutoSave?.(constraint[constraintId])}
|
||||
editing={Boolean(state.get(constraint)?.editing)}
|
||||
compact
|
||||
/>
|
||||
))}
|
||||
{constraints.map((constraint, index) =>
|
||||
addEditStrategy ? (
|
||||
<EditableConstraintWrapper
|
||||
key={constraint[constraintId]}
|
||||
constraint={constraint}
|
||||
onCancel={onCancel.bind(null, index)}
|
||||
onDelete={onRemove?.bind(null, index)}
|
||||
onSave={onSave!.bind(null, index)}
|
||||
onAutoSave={onAutoSave?.(
|
||||
constraint[constraintId],
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<NewConstraintAccordion
|
||||
key={constraint[constraintId]}
|
||||
constraint={constraint}
|
||||
onEdit={onEdit?.bind(null, constraint)}
|
||||
onCancel={onCancel.bind(null, index)}
|
||||
onDelete={onRemove?.bind(null, index)}
|
||||
onSave={onSave?.bind(null, index)}
|
||||
onAutoSave={onAutoSave?.(
|
||||
constraint[constraintId],
|
||||
)}
|
||||
editing={Boolean(
|
||||
state.get(constraint)?.editing,
|
||||
)}
|
||||
compact
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</ConstraintsList>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
@ -0,0 +1,334 @@
|
||||
import { styled } from '@mui/material';
|
||||
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
|
||||
import { DateSingleValue } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/DateSingleValue/DateSingleValue';
|
||||
import { FreeTextInput } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/FreeTextInput/FreeTextInput';
|
||||
import { RestrictiveLegalValues } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/RestrictiveLegalValues/RestrictiveLegalValues';
|
||||
import { SingleLegalValue } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/SingleLegalValue/SingleLegalValue';
|
||||
import { SingleValue } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/SingleValue/SingleValue';
|
||||
import {
|
||||
DATE_OPERATORS_SINGLE_VALUE,
|
||||
IN_OPERATORS_FREETEXT,
|
||||
IN_OPERATORS_LEGAL_VALUES,
|
||||
NUM_OPERATORS_LEGAL_VALUES,
|
||||
NUM_OPERATORS_SINGLE_VALUE,
|
||||
SEMVER_OPERATORS_LEGAL_VALUES,
|
||||
SEMVER_OPERATORS_SINGLE_VALUE,
|
||||
STRING_OPERATORS_FREETEXT,
|
||||
STRING_OPERATORS_LEGAL_VALUES,
|
||||
type Input,
|
||||
} from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/useConstraintInput/useConstraintInput';
|
||||
import { CaseSensitiveButton } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/StyledToggleButton/CaseSensitiveButton/CaseSensitiveButton';
|
||||
import { ConstraintOperatorSelect } from 'component/common/NewConstraintAccordion/ConstraintOperatorSelect';
|
||||
import {
|
||||
DATE_AFTER,
|
||||
dateOperators,
|
||||
IN,
|
||||
stringOperators,
|
||||
type Operator,
|
||||
} from 'constants/operators';
|
||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||
import type {
|
||||
ILegalValue,
|
||||
IUnleashContextDefinition,
|
||||
} from 'interfaces/context';
|
||||
import type { IConstraint } from 'interfaces/strategy';
|
||||
import { useEffect, useState, type FC } from 'react';
|
||||
import { oneOf } from 'utils/oneOf';
|
||||
import {
|
||||
CURRENT_TIME_CONTEXT_FIELD,
|
||||
operatorsForContext,
|
||||
} from 'utils/operatorsForContext';
|
||||
|
||||
const Container = styled('article')(({ theme }) => ({
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
padding: theme.spacing(2),
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
}));
|
||||
|
||||
const resolveLegalValues = (
|
||||
values: IConstraint['values'],
|
||||
legalValues: IUnleashContextDefinition['legalValues'],
|
||||
): { legalValues: ILegalValue[]; deletedLegalValues: ILegalValue[] } => {
|
||||
if (legalValues?.length === 0) {
|
||||
return {
|
||||
legalValues: [],
|
||||
deletedLegalValues: [],
|
||||
};
|
||||
}
|
||||
|
||||
const deletedLegalValues = (values || [])
|
||||
.filter(
|
||||
(value) =>
|
||||
!(legalValues || []).some(
|
||||
({ value: legalValue }) => legalValue === value,
|
||||
),
|
||||
)
|
||||
.map((v) => ({ value: v, description: '' }));
|
||||
|
||||
return {
|
||||
legalValues: legalValues || [],
|
||||
deletedLegalValues,
|
||||
};
|
||||
};
|
||||
|
||||
type Props = {
|
||||
localConstraint: IConstraint;
|
||||
setContextName: (contextName: string) => void;
|
||||
setOperator: (operator: Operator) => void;
|
||||
setLocalConstraint: React.Dispatch<React.SetStateAction<IConstraint>>;
|
||||
action: string;
|
||||
onDelete?: () => void;
|
||||
setInvertedOperator: () => void;
|
||||
setCaseInsensitive: () => void;
|
||||
onUndo: () => void;
|
||||
constraintChanges: IConstraint[];
|
||||
contextDefinition: Pick<IUnleashContextDefinition, 'legalValues'>;
|
||||
constraintValues: string[];
|
||||
constraintValue: string;
|
||||
setValue: (value: string) => void;
|
||||
setValues: (values: string[]) => void;
|
||||
setValuesWithRecord: (values: string[]) => void;
|
||||
setError: React.Dispatch<React.SetStateAction<string>>;
|
||||
removeValue: (index: number) => void;
|
||||
input: Input;
|
||||
error: string;
|
||||
};
|
||||
export const EditableConstraint: FC<Props> = ({
|
||||
constraintChanges,
|
||||
localConstraint,
|
||||
setLocalConstraint,
|
||||
setContextName,
|
||||
setOperator,
|
||||
onDelete,
|
||||
onUndo,
|
||||
setInvertedOperator,
|
||||
setCaseInsensitive,
|
||||
input,
|
||||
contextDefinition,
|
||||
constraintValues,
|
||||
constraintValue,
|
||||
setValue,
|
||||
setValues,
|
||||
setValuesWithRecord,
|
||||
setError,
|
||||
removeValue,
|
||||
error,
|
||||
}) => {
|
||||
const { context } = useUnleashContext();
|
||||
const { contextName, operator } = localConstraint;
|
||||
const [showCaseSensitiveButton, setShowCaseSensitiveButton] =
|
||||
useState(false);
|
||||
|
||||
/* We need a special case to handle the currentTime context field. Since
|
||||
this field will be the only one to allow DATE_BEFORE and DATE_AFTER operators
|
||||
this will check if the context field is the current time context field AND check
|
||||
if it is not already using one of the date operators (to not overwrite if there is existing
|
||||
data). */
|
||||
useEffect(() => {
|
||||
if (
|
||||
contextName === CURRENT_TIME_CONTEXT_FIELD &&
|
||||
!oneOf(dateOperators, operator)
|
||||
) {
|
||||
setLocalConstraint((prev) => ({
|
||||
...prev,
|
||||
operator: DATE_AFTER,
|
||||
value: new Date().toISOString(),
|
||||
}));
|
||||
} else if (
|
||||
contextName !== CURRENT_TIME_CONTEXT_FIELD &&
|
||||
oneOf(dateOperators, operator)
|
||||
) {
|
||||
setOperator(IN);
|
||||
}
|
||||
|
||||
if (oneOf(stringOperators, operator)) {
|
||||
setShowCaseSensitiveButton(true);
|
||||
} else {
|
||||
setShowCaseSensitiveButton(false);
|
||||
}
|
||||
}, [contextName, setOperator, operator, setLocalConstraint]);
|
||||
|
||||
if (!context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const constraintNameOptions = context.map((context) => {
|
||||
return { key: context.name, label: context.name };
|
||||
});
|
||||
|
||||
const onOperatorChange = (operator: Operator) => {
|
||||
if (oneOf(stringOperators, operator)) {
|
||||
setShowCaseSensitiveButton(true);
|
||||
} else {
|
||||
setShowCaseSensitiveButton(false);
|
||||
}
|
||||
|
||||
if (oneOf(dateOperators, operator)) {
|
||||
setLocalConstraint((prev) => ({
|
||||
...prev,
|
||||
operator: operator,
|
||||
value: new Date().toISOString(),
|
||||
}));
|
||||
} else {
|
||||
setOperator(operator);
|
||||
}
|
||||
};
|
||||
|
||||
const resolveInput = () => {
|
||||
switch (input) {
|
||||
case IN_OPERATORS_LEGAL_VALUES:
|
||||
case STRING_OPERATORS_LEGAL_VALUES:
|
||||
return (
|
||||
<>
|
||||
<RestrictiveLegalValues
|
||||
data={resolveLegalValues(
|
||||
constraintValues,
|
||||
contextDefinition.legalValues,
|
||||
)}
|
||||
constraintValues={constraintValues}
|
||||
values={localConstraint.values || []}
|
||||
setValuesWithRecord={setValuesWithRecord}
|
||||
setValues={setValues}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case NUM_OPERATORS_LEGAL_VALUES:
|
||||
return (
|
||||
<>
|
||||
<SingleLegalValue
|
||||
data={resolveLegalValues(
|
||||
[constraintValue],
|
||||
contextDefinition.legalValues,
|
||||
)}
|
||||
setValue={setValue}
|
||||
value={localConstraint.value}
|
||||
constraintValue={constraintValue}
|
||||
type='number'
|
||||
legalValues={
|
||||
contextDefinition.legalValues?.filter(
|
||||
(legalValue) => Number(legalValue.value),
|
||||
) || []
|
||||
}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case SEMVER_OPERATORS_LEGAL_VALUES:
|
||||
return (
|
||||
<>
|
||||
<SingleLegalValue
|
||||
data={resolveLegalValues(
|
||||
[constraintValue],
|
||||
contextDefinition.legalValues,
|
||||
)}
|
||||
setValue={setValue}
|
||||
value={localConstraint.value}
|
||||
constraintValue={constraintValue}
|
||||
type='semver'
|
||||
legalValues={contextDefinition.legalValues || []}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case DATE_OPERATORS_SINGLE_VALUE:
|
||||
return (
|
||||
<DateSingleValue
|
||||
value={localConstraint.value}
|
||||
setValue={setValue}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
case IN_OPERATORS_FREETEXT:
|
||||
return (
|
||||
<FreeTextInput
|
||||
values={localConstraint.values || []}
|
||||
removeValue={removeValue}
|
||||
setValues={setValuesWithRecord}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
case STRING_OPERATORS_FREETEXT:
|
||||
return (
|
||||
<>
|
||||
<FreeTextInput
|
||||
values={localConstraint.values || []}
|
||||
removeValue={removeValue}
|
||||
setValues={setValuesWithRecord}
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
case NUM_OPERATORS_SINGLE_VALUE:
|
||||
return (
|
||||
<SingleValue
|
||||
setValue={setValue}
|
||||
value={localConstraint.value}
|
||||
type='number'
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
case SEMVER_OPERATORS_SINGLE_VALUE:
|
||||
return (
|
||||
<SingleValue
|
||||
setValue={setValue}
|
||||
value={localConstraint.value}
|
||||
type='semver'
|
||||
error={error}
|
||||
setError={setError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<GeneralSelect
|
||||
id='context-field-select'
|
||||
name='contextName'
|
||||
label='Context Field'
|
||||
autoFocus
|
||||
options={constraintNameOptions}
|
||||
value={contextName || ''}
|
||||
onChange={setContextName}
|
||||
/>
|
||||
<ConstraintOperatorSelect
|
||||
options={operatorsForContext(contextName)}
|
||||
value={operator}
|
||||
onChange={onOperatorChange}
|
||||
/>
|
||||
|
||||
{/* this is how to style them */}
|
||||
{/* <StrategyEvaluationChip label='label' /> */}
|
||||
{showCaseSensitiveButton ? (
|
||||
<CaseSensitiveButton
|
||||
localConstraint={localConstraint}
|
||||
setCaseInsensitive={setCaseInsensitive}
|
||||
/>
|
||||
) : null}
|
||||
{resolveInput()}
|
||||
{/* <ul>
|
||||
<li>
|
||||
<Chip
|
||||
label='value1'
|
||||
onDelete={() => console.log('Clicked')}
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Chip
|
||||
label='value2'
|
||||
onDelete={() => console.log('Clicked')}
|
||||
/>
|
||||
</li>
|
||||
</ul> */}
|
||||
</Container>
|
||||
);
|
||||
};
|
@ -0,0 +1,211 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import type { IConstraint } from 'interfaces/strategy';
|
||||
import { cleanConstraint } from 'utils/cleanConstraint';
|
||||
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
|
||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||
import type { IUnleashContextDefinition } from 'interfaces/context';
|
||||
import type { Operator } from 'constants/operators';
|
||||
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint';
|
||||
import { useConstraintInput } from 'component/common/NewConstraintAccordion/ConstraintAccordionEdit/ConstraintAccordionEditBody/useConstraintInput/useConstraintInput';
|
||||
|
||||
interface IConstraintAccordionEditProps {
|
||||
constraint: IConstraint;
|
||||
onCancel: () => void;
|
||||
onSave: (constraint: IConstraint) => void;
|
||||
onDelete?: () => void;
|
||||
onAutoSave?: (constraint: IConstraint) => void;
|
||||
}
|
||||
|
||||
export const CANCEL = 'cancel';
|
||||
export const SAVE = 'save';
|
||||
|
||||
const resolveContextDefinition = (
|
||||
context: IUnleashContextDefinition[],
|
||||
contextName: string,
|
||||
): IUnleashContextDefinition => {
|
||||
const definition = context.find(
|
||||
(contextDef) => contextDef.name === contextName,
|
||||
);
|
||||
|
||||
return (
|
||||
definition || {
|
||||
name: '',
|
||||
description: '',
|
||||
createdAt: '',
|
||||
sortOrder: 1,
|
||||
stickiness: false,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableConstraintWrapper = ({
|
||||
constraint,
|
||||
onSave,
|
||||
onDelete,
|
||||
onAutoSave,
|
||||
}: IConstraintAccordionEditProps) => {
|
||||
const [localConstraint, setLocalConstraint] = useState<IConstraint>(
|
||||
cleanConstraint(constraint),
|
||||
);
|
||||
const [constraintChanges, setConstraintChanges] = useState<IConstraint[]>([
|
||||
cleanConstraint(constraint),
|
||||
]);
|
||||
|
||||
const { context } = useUnleashContext();
|
||||
const [contextDefinition, setContextDefinition] = useState(
|
||||
resolveContextDefinition(context, localConstraint.contextName),
|
||||
);
|
||||
const { validateConstraint } = useFeatureApi();
|
||||
const [action, setAction] = useState('');
|
||||
|
||||
const { input, validator, setError, error } = useConstraintInput({
|
||||
contextDefinition,
|
||||
localConstraint,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setContextDefinition(
|
||||
resolveContextDefinition(context, localConstraint.contextName),
|
||||
);
|
||||
}, [localConstraint.contextName, context]);
|
||||
|
||||
useEffect(() => {
|
||||
setError('');
|
||||
}, [setError]);
|
||||
|
||||
const onUndo = () => {
|
||||
if (constraintChanges.length < 2) return;
|
||||
const previousChange = constraintChanges[constraintChanges.length - 2];
|
||||
|
||||
setLocalConstraint(previousChange);
|
||||
setConstraintChanges((prev) => prev.slice(0, prev.length - 1));
|
||||
autoSave(previousChange);
|
||||
};
|
||||
|
||||
const autoSave = (localConstraint: IConstraint) => {
|
||||
if (onAutoSave) {
|
||||
onAutoSave(localConstraint);
|
||||
}
|
||||
};
|
||||
|
||||
const recordChange = (localConstraint: IConstraint) => {
|
||||
setConstraintChanges((prev) => [...prev, localConstraint]);
|
||||
autoSave(localConstraint);
|
||||
};
|
||||
|
||||
const setContextName = useCallback((contextName: string) => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = cleanConstraint({
|
||||
...prev,
|
||||
contextName,
|
||||
values: [],
|
||||
value: '',
|
||||
});
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setOperator = useCallback((operator: Operator) => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = cleanConstraint({
|
||||
...prev,
|
||||
operator,
|
||||
values: [],
|
||||
value: '',
|
||||
});
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setValuesWithRecord = useCallback((values: string[]) => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = { ...prev, values };
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setValues = useCallback((values: string[]) => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = { ...prev, values };
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setValue = useCallback((value: string) => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = { ...prev, value };
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setInvertedOperator = () => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = { ...prev, inverted: !prev.inverted };
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
};
|
||||
|
||||
const setCaseInsensitive = useCallback(() => {
|
||||
setLocalConstraint((prev) => {
|
||||
const localConstraint = {
|
||||
...prev,
|
||||
caseInsensitive: !prev.caseInsensitive,
|
||||
};
|
||||
|
||||
recordChange(localConstraint);
|
||||
|
||||
return localConstraint;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const removeValue = useCallback(
|
||||
(index: number) => {
|
||||
const valueCopy = [...localConstraint.values!];
|
||||
valueCopy.splice(index, 1);
|
||||
|
||||
setValuesWithRecord(valueCopy);
|
||||
},
|
||||
[localConstraint, setValuesWithRecord],
|
||||
);
|
||||
|
||||
return (
|
||||
<EditableConstraint
|
||||
localConstraint={localConstraint}
|
||||
setLocalConstraint={setLocalConstraint}
|
||||
setContextName={setContextName}
|
||||
setOperator={setOperator}
|
||||
action={action}
|
||||
setInvertedOperator={setInvertedOperator}
|
||||
setCaseInsensitive={setCaseInsensitive}
|
||||
onDelete={onDelete}
|
||||
onUndo={onUndo}
|
||||
constraintChanges={constraintChanges}
|
||||
setValues={setValues}
|
||||
setValuesWithRecord={setValuesWithRecord}
|
||||
setValue={setValue}
|
||||
setError={setError}
|
||||
constraintValues={constraint?.values || []}
|
||||
constraintValue={constraint?.value || ''}
|
||||
input={input}
|
||||
error={error}
|
||||
contextDefinition={contextDefinition}
|
||||
removeValue={removeValue}
|
||||
/>
|
||||
);
|
||||
};
|
@ -18,8 +18,6 @@ interface IConstraintAccordionListProps {
|
||||
constraints: IConstraint[];
|
||||
setConstraints?: React.Dispatch<React.SetStateAction<IConstraint[]>>;
|
||||
showCreateButton?: boolean;
|
||||
/* Add "constraints" title on the top - default `true` */
|
||||
showLabel?: boolean;
|
||||
}
|
||||
|
||||
export const constraintAccordionListId = 'constraintAccordionListId';
|
||||
|
Loading…
Reference in New Issue
Block a user