mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-24 17:51:14 +02:00
Chore(1-3831)/add edit strategy cleanup pt iv (#10135)
This PR addresses and removes the last comment related to the addEditStrategy flag. In doing so, I have also removed the remaining dangling files from the new constraint accordion directory. I believe that everything that's left in there now is currently in use.
This commit is contained in:
parent
d7c32d688a
commit
74ae35298d
@ -1,104 +0,0 @@
|
|||||||
import type React from 'react';
|
|
||||||
import { IconButton, styled, Tooltip } from '@mui/material';
|
|
||||||
import Delete from '@mui/icons-material/Delete';
|
|
||||||
import Edit from '@mui/icons-material/Edit';
|
|
||||||
import Undo from '@mui/icons-material/Undo';
|
|
||||||
import { ConditionallyRender } from '../../ConditionallyRender/ConditionallyRender.tsx';
|
|
||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
|
|
||||||
interface ConstraintAccordionEditActionsProps {
|
|
||||||
onDelete?: () => void;
|
|
||||||
onEdit?: () => void;
|
|
||||||
onUndo?: () => void;
|
|
||||||
constraintChanges?: IConstraint[];
|
|
||||||
disableEdit?: boolean;
|
|
||||||
disableDelete?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledHeaderActions = styled('div')(({ theme }) => ({
|
|
||||||
marginLeft: 'auto',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
display: 'none',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ConstraintAccordionEditActions = ({
|
|
||||||
onEdit,
|
|
||||||
onDelete,
|
|
||||||
onUndo,
|
|
||||||
constraintChanges = [],
|
|
||||||
disableDelete = false,
|
|
||||||
disableEdit = false,
|
|
||||||
}: ConstraintAccordionEditActionsProps) => {
|
|
||||||
const onEditClick =
|
|
||||||
onEdit &&
|
|
||||||
((event: React.SyntheticEvent) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
onEdit();
|
|
||||||
});
|
|
||||||
|
|
||||||
const onDeleteClick =
|
|
||||||
onDelete &&
|
|
||||||
((event: React.SyntheticEvent) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
onDelete();
|
|
||||||
});
|
|
||||||
|
|
||||||
const onUndoClick =
|
|
||||||
onUndo &&
|
|
||||||
((event: React.SyntheticEvent) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
onUndo();
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledHeaderActions>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(onEditClick) && !disableEdit}
|
|
||||||
show={
|
|
||||||
<Tooltip title='Edit constraint' arrow>
|
|
||||||
<IconButton
|
|
||||||
type='button'
|
|
||||||
onClick={onEditClick}
|
|
||||||
disabled={disableEdit}
|
|
||||||
data-testid='EDIT_CONSTRAINT_BUTTON'
|
|
||||||
>
|
|
||||||
<Edit />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(onUndoClick) && constraintChanges.length > 1}
|
|
||||||
show={
|
|
||||||
<Tooltip title='Undo last change' arrow>
|
|
||||||
<IconButton
|
|
||||||
type='button'
|
|
||||||
onClick={onUndoClick}
|
|
||||||
disabled={disableDelete}
|
|
||||||
data-testid='UNDO_CONSTRAINT_CHANGE_BUTTON'
|
|
||||||
>
|
|
||||||
<Undo />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(onDeleteClick) && !disableDelete}
|
|
||||||
show={
|
|
||||||
<Tooltip title='Delete constraint' arrow>
|
|
||||||
<IconButton
|
|
||||||
type='button'
|
|
||||||
onClick={onDeleteClick}
|
|
||||||
disabled={disableDelete}
|
|
||||||
data-testid='DELETE_CONSTRAINT_BUTTON'
|
|
||||||
>
|
|
||||||
<Delete />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</StyledHeaderActions>
|
|
||||||
);
|
|
||||||
};
|
|
@ -10,20 +10,11 @@ import {
|
|||||||
import type { IConstraint } from 'interfaces/strategy';
|
import type { IConstraint } from 'interfaces/strategy';
|
||||||
import { ConstraintAccordionViewBody } from './ConstraintAccordionViewBody/ConstraintAccordionViewBody.tsx';
|
import { ConstraintAccordionViewBody } from './ConstraintAccordionViewBody/ConstraintAccordionViewBody.tsx';
|
||||||
import { ConstraintAccordionViewHeader } from './ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx';
|
import { ConstraintAccordionViewHeader } from './ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx';
|
||||||
import { oneOf } from 'utils/oneOf';
|
|
||||||
import {
|
|
||||||
dateOperators,
|
|
||||||
numOperators,
|
|
||||||
semVerOperators,
|
|
||||||
} from 'constants/operators';
|
|
||||||
|
|
||||||
interface IConstraintAccordionViewProps {
|
interface IConstraintAccordionViewProps {
|
||||||
constraint: IConstraint;
|
constraint: IConstraint;
|
||||||
onDelete?: () => void;
|
|
||||||
onEdit?: () => void;
|
|
||||||
onUse?: () => void;
|
onUse?: () => void;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
compact?: boolean;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
renderAfter?: JSX.Element;
|
renderAfter?: JSX.Element;
|
||||||
borderStyle?: 'solid' | 'dashed';
|
borderStyle?: 'solid' | 'dashed';
|
||||||
@ -73,11 +64,8 @@ const StyledWrapper = styled('div')({
|
|||||||
|
|
||||||
export const ConstraintAccordionView = ({
|
export const ConstraintAccordionView = ({
|
||||||
constraint,
|
constraint,
|
||||||
onEdit,
|
|
||||||
onDelete,
|
|
||||||
onUse,
|
onUse,
|
||||||
sx = undefined,
|
sx = undefined,
|
||||||
compact = false,
|
|
||||||
disabled = false,
|
disabled = false,
|
||||||
renderAfter,
|
renderAfter,
|
||||||
borderStyle = 'solid',
|
borderStyle = 'solid',
|
||||||
@ -85,10 +73,6 @@ export const ConstraintAccordionView = ({
|
|||||||
const [expandable, setExpandable] = useState(true);
|
const [expandable, setExpandable] = useState(true);
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
const singleValue = oneOf(
|
|
||||||
[...semVerOperators, ...numOperators, ...dateOperators],
|
|
||||||
constraint.operator,
|
|
||||||
);
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (expandable) {
|
if (expandable) {
|
||||||
setExpanded(!expanded);
|
setExpanded(!expanded);
|
||||||
@ -111,14 +95,10 @@ export const ConstraintAccordionView = ({
|
|||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<ConstraintAccordionViewHeader
|
<ConstraintAccordionViewHeader
|
||||||
constraint={constraint}
|
constraint={constraint}
|
||||||
onEdit={onEdit}
|
|
||||||
onDelete={onDelete}
|
|
||||||
onUse={onUse}
|
onUse={onUse}
|
||||||
singleValue={singleValue}
|
|
||||||
allowExpand={setExpandable}
|
allowExpand={setExpandable}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
compact={compact}
|
|
||||||
/>
|
/>
|
||||||
{renderAfter}
|
{renderAfter}
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
|
@ -1,25 +1,13 @@
|
|||||||
import type { IConstraint } from 'interfaces/strategy';
|
import type { IConstraint } from 'interfaces/strategy';
|
||||||
import { ConstraintAccordionViewHeaderInfo } from './ConstraintAccordionViewHeaderInfo.tsx';
|
import { ConstraintAccordionViewHeaderInfo } from './ConstraintAccordionViewHeaderInfo.tsx';
|
||||||
import { styled } from '@mui/system';
|
import { styled } from '@mui/system';
|
||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
|
||||||
import { ConstraintAccordionViewActions } from '../../ConstraintAccordionViewActions/ConstraintAccordionViewActions.tsx';
|
import { ConstraintAccordionViewActions } from '../../ConstraintAccordionViewActions/ConstraintAccordionViewActions.tsx';
|
||||||
import { ConstraintAccordionEditActions } from '../../ConstraintAccordionEditActions/ConstraintAccordionEditActions.tsx';
|
|
||||||
|
|
||||||
interface IConstraintAccordionViewHeaderProps {
|
interface IConstraintAccordionViewHeaderProps {
|
||||||
constraint: IConstraint;
|
constraint: IConstraint;
|
||||||
onDelete?: () => void;
|
|
||||||
onEdit?: () => void;
|
|
||||||
onUse?: () => void;
|
onUse?: () => void;
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
singleValue: boolean;
|
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
allowExpand: (shouldExpand: boolean) => void;
|
allowExpand: (shouldExpand: boolean) => void;
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
compact?: boolean;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,22 +24,11 @@ const StyledContainer = styled('div')(({ theme }) => ({
|
|||||||
|
|
||||||
export const ConstraintAccordionViewHeader = ({
|
export const ConstraintAccordionViewHeader = ({
|
||||||
constraint,
|
constraint,
|
||||||
onEdit,
|
|
||||||
onDelete,
|
|
||||||
onUse,
|
onUse,
|
||||||
singleValue,
|
|
||||||
allowExpand,
|
allowExpand,
|
||||||
expanded,
|
expanded,
|
||||||
compact,
|
|
||||||
disabled,
|
disabled,
|
||||||
}: IConstraintAccordionViewHeaderProps) => {
|
}: IConstraintAccordionViewHeaderProps) => {
|
||||||
const { context } = useUnleashContext();
|
|
||||||
const { contextName } = constraint;
|
|
||||||
|
|
||||||
const disableEdit = !context
|
|
||||||
.map((contextDefinition) => contextDefinition.name)
|
|
||||||
.includes(contextName);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<ConstraintAccordionViewHeaderInfo
|
<ConstraintAccordionViewHeaderInfo
|
||||||
@ -60,16 +37,7 @@ export const ConstraintAccordionViewHeader = ({
|
|||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
{onUse ? (
|
{onUse ? <ConstraintAccordionViewActions onUse={onUse} /> : null}
|
||||||
<ConstraintAccordionViewActions onUse={onUse} />
|
|
||||||
) : (
|
|
||||||
// @deprecated : remove onEdit and onDelete from current file together with NewConstraintAccordionList and addEditStrategy flag
|
|
||||||
<ConstraintAccordionEditActions
|
|
||||||
onEdit={onEdit}
|
|
||||||
onDelete={onDelete}
|
|
||||||
disableEdit={disableEdit}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
import { styled } from '@mui/material';
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
|
||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
|
|
||||||
const StyledValuesSpan = styled('span')(({ theme }) => ({
|
|
||||||
display: '-webkit-box',
|
|
||||||
WebkitLineClamp: 2,
|
|
||||||
WebkitBoxOrient: 'vertical',
|
|
||||||
overflow: 'hidden',
|
|
||||||
wordBreak: 'break-word',
|
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
margin: 'auto 0',
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
margin: theme.spacing(1, 0),
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface ConstraintSingleValueProps {
|
|
||||||
constraint: IConstraint;
|
|
||||||
expanded: boolean;
|
|
||||||
maxLength: number;
|
|
||||||
allowExpand: (shouldExpand: boolean) => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledHeaderValuesContainerWrapper = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'stretch',
|
|
||||||
margin: 'auto 0',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledHeaderValuesContainer = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'stretch',
|
|
||||||
margin: 'auto 0',
|
|
||||||
flexDirection: 'column',
|
|
||||||
marginLeft: theme.spacing(1),
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
marginLeft: 0,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledHeaderValuesExpand = styled('p')(({ theme }) => ({
|
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
marginTop: theme.spacing(0.5),
|
|
||||||
color: theme.palette.links,
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ConstraintAccordionViewHeaderMultipleValues = ({
|
|
||||||
constraint,
|
|
||||||
expanded,
|
|
||||||
allowExpand,
|
|
||||||
maxLength,
|
|
||||||
disabled = false,
|
|
||||||
}: ConstraintSingleValueProps) => {
|
|
||||||
const [expandable, setExpandable] = useState(false);
|
|
||||||
|
|
||||||
const text = useMemo(() => {
|
|
||||||
return constraint?.values?.map((value) => value).join(', ');
|
|
||||||
}, [constraint]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (text) {
|
|
||||||
allowExpand((text?.length ?? 0) > maxLength);
|
|
||||||
setExpandable((text?.length ?? 0) > maxLength);
|
|
||||||
}
|
|
||||||
}, [text, maxLength, allowExpand, setExpandable]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledHeaderValuesContainerWrapper>
|
|
||||||
<StyledHeaderValuesContainer>
|
|
||||||
<StyledValuesSpan
|
|
||||||
sx={(theme) => ({
|
|
||||||
color: disabled
|
|
||||||
? theme.palette.text.secondary
|
|
||||||
: 'inherit',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</StyledValuesSpan>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={expandable}
|
|
||||||
show={
|
|
||||||
<StyledHeaderValuesExpand
|
|
||||||
className={'valuesExpandLabel'}
|
|
||||||
>
|
|
||||||
{!expanded
|
|
||||||
? `View all (${constraint?.values?.length})`
|
|
||||||
: 'View less'}
|
|
||||||
</StyledHeaderValuesExpand>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</StyledHeaderValuesContainer>
|
|
||||||
</StyledHeaderValuesContainerWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
import { useEffect } from 'react';
|
|
||||||
import { Chip, styled } from '@mui/material';
|
|
||||||
import { formatConstraintValue } from 'utils/formatConstraintValue';
|
|
||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
|
||||||
|
|
||||||
const StyledSingleValueChip = styled(Chip)(({ theme }) => ({
|
|
||||||
margin: 'auto 0',
|
|
||||||
marginLeft: theme.spacing(1),
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
margin: theme.spacing(1, 0),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface ConstraintSingleValueProps {
|
|
||||||
constraint: IConstraint;
|
|
||||||
allowExpand: (shouldExpand: boolean) => void;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledHeaderValuesContainerWrapper = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'stretch',
|
|
||||||
margin: 'auto 0',
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ConstraintAccordionViewHeaderSingleValue = ({
|
|
||||||
constraint,
|
|
||||||
allowExpand,
|
|
||||||
disabled = false,
|
|
||||||
}: ConstraintSingleValueProps) => {
|
|
||||||
const { locationSettings } = useLocationSettings();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
allowExpand(false);
|
|
||||||
}, [allowExpand]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledHeaderValuesContainerWrapper>
|
|
||||||
<StyledSingleValueChip
|
|
||||||
sx={(theme) => ({
|
|
||||||
color: disabled ? theme.palette.text.secondary : 'inherit',
|
|
||||||
})}
|
|
||||||
label={formatConstraintValue(constraint, locationSettings)}
|
|
||||||
/>
|
|
||||||
</StyledHeaderValuesContainerWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,72 +0,0 @@
|
|||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
import { ConditionallyRender } from '../../../ConditionallyRender/ConditionallyRender.tsx';
|
|
||||||
import { Tooltip, Box, styled } from '@mui/material';
|
|
||||||
import { stringOperators } from 'constants/operators';
|
|
||||||
import { ReactComponent as NegatedOnIcon } from 'assets/icons/not_operator_selected.svg';
|
|
||||||
import { ConstraintOperator } from '../../ConstraintOperator/ConstraintOperator.tsx';
|
|
||||||
import { StyledIconWrapper } from './StyledIconWrapper.tsx';
|
|
||||||
import { ReactComponent as CaseSensitive } from 'assets/icons/24_Text format.svg';
|
|
||||||
import { oneOf } from 'utils/oneOf';
|
|
||||||
import { useTheme } from '@mui/material';
|
|
||||||
|
|
||||||
interface ConstraintViewHeaderOperatorProps {
|
|
||||||
constraint: IConstraint;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledHeaderValuesContainerWrapper = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'stretch',
|
|
||||||
margin: 'auto 0',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledHeaderConstraintContainer = styled('div')(({ theme }) => ({
|
|
||||||
minWidth: '152px',
|
|
||||||
position: 'relative',
|
|
||||||
[theme.breakpoints.down('sm')]: {
|
|
||||||
paddingRight: 0,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ConstraintViewHeaderOperator = ({
|
|
||||||
constraint,
|
|
||||||
disabled = false,
|
|
||||||
}: ConstraintViewHeaderOperatorProps) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
return (
|
|
||||||
<StyledHeaderValuesContainerWrapper>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(constraint.inverted)}
|
|
||||||
show={
|
|
||||||
<Tooltip title={'Operator is negated'} arrow>
|
|
||||||
<Box sx={{ display: 'flex' }}>
|
|
||||||
<StyledIconWrapper isPrefix>
|
|
||||||
<NegatedOnIcon />
|
|
||||||
</StyledIconWrapper>
|
|
||||||
</Box>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<StyledHeaderConstraintContainer>
|
|
||||||
<ConstraintOperator
|
|
||||||
constraint={constraint}
|
|
||||||
hasPrefix={Boolean(constraint.inverted)}
|
|
||||||
disabled={disabled}
|
|
||||||
/>
|
|
||||||
</StyledHeaderConstraintContainer>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={
|
|
||||||
!constraint.caseInsensitive &&
|
|
||||||
oneOf(stringOperators, constraint.operator)
|
|
||||||
}
|
|
||||||
show={
|
|
||||||
<Tooltip title='Case sensitive is active' arrow>
|
|
||||||
<StyledIconWrapper>
|
|
||||||
<CaseSensitive />
|
|
||||||
</StyledIconWrapper>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</StyledHeaderValuesContainerWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
@ -2,7 +2,7 @@ import { forwardRef, type ReactNode } from 'react';
|
|||||||
import { styled } from '@mui/material';
|
import { styled } from '@mui/material';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
export const StyledIconWrapperBase = styled('div')<{
|
const StyledIconWrapperBase = styled('div')<{
|
||||||
prefix?: boolean;
|
prefix?: boolean;
|
||||||
}>(({ theme }) => ({
|
}>(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.background.elevation2,
|
backgroundColor: theme.palette.background.elevation2,
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
import { styled } from '@mui/material';
|
|
||||||
import { formatOperatorDescription } from 'utils/formatOperatorDescription';
|
|
||||||
|
|
||||||
interface IConstraintOperatorProps {
|
|
||||||
constraint: IConstraint;
|
|
||||||
hasPrefix?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
|
||||||
padding: theme.spacing(0.5, 1.5),
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
backgroundColor: theme.palette.background.elevation2,
|
|
||||||
lineHeight: 1.25,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledName = styled('p', {
|
|
||||||
shouldForwardProp: (prop) => prop !== 'disabled',
|
|
||||||
})<{ disabled: boolean }>(({ theme, disabled }) => ({
|
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
lineHeight: 17 / 14,
|
|
||||||
color: disabled ? theme.palette.text.secondary : theme.palette.text.primary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledText = styled('p', {
|
|
||||||
shouldForwardProp: (prop) => prop !== 'disabled',
|
|
||||||
})<{ disabled: boolean }>(({ theme, disabled }) => ({
|
|
||||||
fontSize: theme.fontSizes.smallerBody,
|
|
||||||
color: disabled ? theme.palette.text.secondary : theme.palette.neutral.main,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ConstraintOperator = ({
|
|
||||||
constraint,
|
|
||||||
hasPrefix,
|
|
||||||
disabled = false,
|
|
||||||
}: IConstraintOperatorProps) => {
|
|
||||||
const operatorName = constraint.operator;
|
|
||||||
const operatorText = formatOperatorDescription(constraint.operator);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer
|
|
||||||
style={{
|
|
||||||
borderTopLeftRadius: hasPrefix ? 0 : undefined,
|
|
||||||
borderBottomLeftRadius: hasPrefix ? 0 : undefined,
|
|
||||||
paddingLeft: hasPrefix ? 0 : undefined,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<StyledName disabled={disabled}>{operatorName}</StyledName>
|
|
||||||
<StyledText disabled={disabled}>{operatorText}</StyledText>
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
};
|
|
@ -7,7 +7,7 @@ import produce from 'immer';
|
|||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||||
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
|
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
|
||||||
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
|
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
|
||||||
import { createEmptyConstraint } from '../NewConstraintAccordionList/createEmptyConstraint.ts';
|
import { createEmptyConstraint } from '../../../../utils/createEmptyConstraint.ts';
|
||||||
import { constraintId } from 'constants/constraintId.ts';
|
import { constraintId } from 'constants/constraintId.ts';
|
||||||
export interface IEditableConstraintsListRef {
|
export interface IEditableConstraintsListRef {
|
||||||
addConstraint?: (contextName: string) => void;
|
addConstraint?: (contextName: string) => void;
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
import type React from 'react';
|
|
||||||
import { forwardRef } from 'react';
|
|
||||||
import { styled } from '@mui/material';
|
|
||||||
import type { IConstraint } from 'interfaces/strategy';
|
|
||||||
import produce from 'immer';
|
|
||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
|
||||||
import type { IUseWeakMap } from 'hooks/useWeakMap';
|
|
||||||
import { ConstraintsList } from 'component/common/ConstraintsList/ConstraintsList';
|
|
||||||
import { ConstraintAccordionView } from 'component/common/NewConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView';
|
|
||||||
import { EditableConstraint } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/EditableConstraint';
|
|
||||||
import { constraintId } from 'constants/constraintId';
|
|
||||||
|
|
||||||
export interface IConstraintAccordionListProps {
|
|
||||||
constraints: IConstraint[];
|
|
||||||
setConstraints?: React.Dispatch<React.SetStateAction<IConstraint[]>>;
|
|
||||||
showCreateButton?: boolean;
|
|
||||||
/* Add "constraints" title on the top - default `true` */
|
|
||||||
showLabel?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ref methods exposed by this component.
|
|
||||||
export interface IConstraintAccordionListRef {
|
|
||||||
addConstraint?: (contextName: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra form state for each constraint.
|
|
||||||
interface IConstraintAccordionListItemState {
|
|
||||||
// Is the constraint new (never been saved)?
|
|
||||||
new?: boolean;
|
|
||||||
// Is the constraint currently being edited?
|
|
||||||
editing?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const constraintAccordionListId = 'constraintAccordionListId';
|
|
||||||
|
|
||||||
const StyledContainer = styled('div')({
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
});
|
|
||||||
|
|
||||||
interface IConstraintList {
|
|
||||||
constraints: IConstraint[];
|
|
||||||
setConstraints?: React.Dispatch<React.SetStateAction<IConstraint[]>>;
|
|
||||||
state: IUseWeakMap<IConstraint, IConstraintAccordionListItemState>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NewConstraintAccordionList = forwardRef<
|
|
||||||
IConstraintAccordionListRef | undefined,
|
|
||||||
IConstraintList
|
|
||||||
>(({ constraints, setConstraints, state }, ref) => {
|
|
||||||
const { context } = useUnleashContext();
|
|
||||||
|
|
||||||
const onEdit =
|
|
||||||
setConstraints &&
|
|
||||||
((constraint: IConstraint) => {
|
|
||||||
state.set(constraint, { editing: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
const onRemove =
|
|
||||||
setConstraints &&
|
|
||||||
((index: number) => {
|
|
||||||
const constraint = constraints[index];
|
|
||||||
state.set(constraint, {});
|
|
||||||
setConstraints(
|
|
||||||
produce((draft) => {
|
|
||||||
draft.splice(index, 1);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSave =
|
|
||||||
setConstraints &&
|
|
||||||
((index: number, constraint: IConstraint) => {
|
|
||||||
state.set(constraint, {});
|
|
||||||
setConstraints(
|
|
||||||
produce((draft) => {
|
|
||||||
draft[index] = constraint;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const onAutoSave =
|
|
||||||
setConstraints &&
|
|
||||||
((id: string | undefined) => (constraint: IConstraint) => {
|
|
||||||
state.set(constraint, { editing: true });
|
|
||||||
setConstraints(
|
|
||||||
produce((draft) => {
|
|
||||||
return draft.map((oldConstraint) => {
|
|
||||||
if (oldConstraint[constraintId] === id) {
|
|
||||||
return constraint;
|
|
||||||
}
|
|
||||||
return oldConstraint;
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const onCancel = (index: number) => {
|
|
||||||
const constraint = constraints[index];
|
|
||||||
state.get(constraint)?.new && onRemove?.(index);
|
|
||||||
state.set(constraint, {});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (context.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer id={constraintAccordionListId}>
|
|
||||||
<ConstraintsList>
|
|
||||||
{constraints.map((constraint, index) =>
|
|
||||||
state.get(constraint)?.editing &&
|
|
||||||
Boolean(setConstraints) ? (
|
|
||||||
<EditableConstraint
|
|
||||||
key={constraint[constraintId]}
|
|
||||||
constraint={constraint}
|
|
||||||
// @ts-ignore todo: find a better way to do this
|
|
||||||
onDelete={() => onRemove(index)}
|
|
||||||
// @ts-ignore
|
|
||||||
onUpdate={onAutoSave(constraintId)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ConstraintAccordionView
|
|
||||||
key={constraint[constraintId]}
|
|
||||||
constraint={constraint}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</ConstraintsList>
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
});
|
|
@ -12,7 +12,7 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|||||||
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints/RecentlyUsedConstraints.tsx';
|
import { RecentlyUsedConstraints } from '../RecentlyUsedConstraints/RecentlyUsedConstraints.tsx';
|
||||||
import { useWeakMap } from 'hooks/useWeakMap.ts';
|
import { useWeakMap } from 'hooks/useWeakMap.ts';
|
||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext.ts';
|
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext.ts';
|
||||||
import { createEmptyConstraint } from 'component/common/NewConstraintAccordion/NewConstraintAccordionList/createEmptyConstraint.ts';
|
import { createEmptyConstraint } from 'utils/createEmptyConstraint.ts';
|
||||||
|
|
||||||
interface IConstraintAccordionListProps {
|
interface IConstraintAccordionListProps {
|
||||||
constraints: IConstraint[];
|
constraints: IConstraint[];
|
||||||
@ -20,8 +20,6 @@ interface IConstraintAccordionListProps {
|
|||||||
showCreateButton?: boolean;
|
showCreateButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const constraintAccordionListId = 'constraintAccordionListId';
|
|
||||||
|
|
||||||
const StyledContainer = styled('div')({
|
const StyledContainer = styled('div')({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -102,7 +100,7 @@ export const FeatureStrategyConstraintAccordionList = forwardRef<
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer id={constraintAccordionListId}>
|
<StyledContainer>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(showCreateButton && onAdd)}
|
condition={Boolean(showCreateButton && onAdd)}
|
||||||
show={
|
show={
|
||||||
|
@ -6,13 +6,13 @@ import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
|||||||
import Visibility from '@mui/icons-material/Visibility';
|
import Visibility from '@mui/icons-material/Visibility';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { styled, type Theme, Tooltip } from '@mui/material';
|
import { styled, type Theme, Tooltip } from '@mui/material';
|
||||||
import { constraintAccordionListId } from 'component/common/NewConstraintAccordion/NewConstraintAccordionList/NewConstraintAccordionList';
|
|
||||||
|
|
||||||
interface IFeatureStrategySegmentListProps {
|
interface IFeatureStrategySegmentListProps {
|
||||||
segment: ISegment;
|
segment: ISegment;
|
||||||
setSegments: React.Dispatch<React.SetStateAction<ISegment[]>>;
|
setSegments: React.Dispatch<React.SetStateAction<ISegment[]>>;
|
||||||
preview?: ISegment;
|
preview?: ISegment;
|
||||||
setPreview: React.Dispatch<React.SetStateAction<ISegment | undefined>>;
|
setPreview: React.Dispatch<React.SetStateAction<ISegment | undefined>>;
|
||||||
|
'aria-controls'?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledChip = styled('span')(({ theme }) => ({
|
const StyledChip = styled('span')(({ theme }) => ({
|
||||||
@ -48,6 +48,7 @@ export const FeatureStrategySegmentChip = ({
|
|||||||
setSegments,
|
setSegments,
|
||||||
preview,
|
preview,
|
||||||
setPreview,
|
setPreview,
|
||||||
|
'aria-controls': ariaControls,
|
||||||
}: IFeatureStrategySegmentListProps) => {
|
}: IFeatureStrategySegmentListProps) => {
|
||||||
const onRemove = () => {
|
const onRemove = () => {
|
||||||
setSegments((prev) => {
|
setSegments((prev) => {
|
||||||
@ -91,7 +92,7 @@ export const FeatureStrategySegmentChip = ({
|
|||||||
type='button'
|
type='button'
|
||||||
onClick={onTogglePreview}
|
onClick={onTogglePreview}
|
||||||
aria-expanded={segment === preview}
|
aria-expanded={segment === preview}
|
||||||
aria-controls={constraintAccordionListId}
|
aria-controls={ariaControls}
|
||||||
>
|
>
|
||||||
{togglePreviewIcon}
|
{togglePreviewIcon}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { Fragment, useState } from 'react';
|
import { Fragment, useId, useState } from 'react';
|
||||||
import type { ISegment } from 'interfaces/segment';
|
import type { ISegment } from 'interfaces/segment';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
||||||
@ -34,12 +34,17 @@ const StyledAnd = styled('p')(({ theme }) => ({
|
|||||||
backgroundColor: theme.palette.background.elevation2,
|
backgroundColor: theme.palette.background.elevation2,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledPreviewContainer = styled('div')({
|
||||||
|
display: 'contents',
|
||||||
|
});
|
||||||
|
|
||||||
export const FeatureStrategySegmentList = ({
|
export const FeatureStrategySegmentList = ({
|
||||||
segments,
|
segments,
|
||||||
setSegments,
|
setSegments,
|
||||||
}: IFeatureStrategySegmentListProps) => {
|
}: IFeatureStrategySegmentListProps) => {
|
||||||
const [preview, setPreview] = useState<ISegment>();
|
const [preview, setPreview] = useState<ISegment>();
|
||||||
const lastSegmentIndex = segments.length - 1;
|
const lastSegmentIndex = segments.length - 1;
|
||||||
|
const segmentDetailsId = useId();
|
||||||
|
|
||||||
if (segments.length === 0) {
|
if (segments.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -63,6 +68,7 @@ export const FeatureStrategySegmentList = ({
|
|||||||
setSegments={setSegments}
|
setSegments={setSegments}
|
||||||
preview={preview}
|
preview={preview}
|
||||||
setPreview={setPreview}
|
setPreview={setPreview}
|
||||||
|
aria-controls={segmentDetailsId}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={i < lastSegmentIndex}
|
condition={i < lastSegmentIndex}
|
||||||
@ -71,10 +77,12 @@ export const FeatureStrategySegmentList = ({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</StyledList>
|
</StyledList>
|
||||||
<ConditionallyRender
|
<StyledPreviewContainer id={segmentDetailsId}>
|
||||||
condition={Boolean(preview)}
|
<ConditionallyRender
|
||||||
show={() => <SegmentItem segment={preview!} isExpanded />}
|
condition={Boolean(preview)}
|
||||||
/>
|
show={<SegmentItem segment={preview!} isExpanded />}
|
||||||
|
/>
|
||||||
|
</StyledPreviewContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -29,11 +29,7 @@ export const ConstraintExecutionWithoutResults: FC<
|
|||||||
condition={index > 0}
|
condition={index > 0}
|
||||||
show={<ConstraintSeparator />}
|
show={<ConstraintSeparator />}
|
||||||
/>
|
/>
|
||||||
<ConstraintAccordionView
|
<ConstraintAccordionView constraint={constraint} disabled />
|
||||||
constraint={constraint}
|
|
||||||
compact
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</ConstraintExecutionWrapper>
|
</ConstraintExecutionWrapper>
|
||||||
|
@ -9,7 +9,6 @@ import type { ActionsFilterState } from '../../useProjectActionsForm.ts';
|
|||||||
import Delete from '@mui/icons-material/Delete';
|
import Delete from '@mui/icons-material/Delete';
|
||||||
import Input from 'component/common/Input/Input';
|
import Input from 'component/common/Input/Input';
|
||||||
import { ProjectActionsFormItem } from '../ProjectActionsFormItem.tsx';
|
import { ProjectActionsFormItem } from '../ProjectActionsFormItem.tsx';
|
||||||
import { ConstraintOperatorSelect } from 'component/common/NewConstraintAccordion/ConstraintOperatorSelect';
|
|
||||||
import {
|
import {
|
||||||
inOperators,
|
inOperators,
|
||||||
numOperators,
|
numOperators,
|
||||||
@ -24,6 +23,7 @@ import { CaseSensitiveButton } from './StyledToggleButton/CaseSensitiveButton/Ca
|
|||||||
import { InvertedOperatorButton } from './StyledToggleButton/InvertedOperatorButton/InvertedOperatorButton.tsx';
|
import { InvertedOperatorButton } from './StyledToggleButton/InvertedOperatorButton/InvertedOperatorButton.tsx';
|
||||||
import { constraintValidator } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/useEditableConstraint/constraint-validator.ts';
|
import { constraintValidator } from 'component/feature/FeatureStrategy/FeatureStrategyConstraints/EditableConstraint/useEditableConstraint/constraint-validator.ts';
|
||||||
import { ResolveInput } from './ProjectActionsFilterItemInputs/ResolveInput.tsx';
|
import { ResolveInput } from './ProjectActionsFilterItemInputs/ResolveInput.tsx';
|
||||||
|
import { ConstraintOperatorSelect } from './ConstraintOperatorSelect.tsx';
|
||||||
|
|
||||||
const StyledDeleteButton = styled(IconButton)({
|
const StyledDeleteButton = styled(IconButton)({
|
||||||
marginRight: '-6px',
|
marginRight: '-6px',
|
||||||
|
Loading…
Reference in New Issue
Block a user