mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
Constrain card adjustments
This commit is contained in:
parent
e33ed6b8e7
commit
7f0a0afb84
3
frontend/src/assets/icons/24_Negator off.svg
Normal file
3
frontend/src/assets/icons/24_Negator off.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.10831 2.60839C3.71687 2.23054 3.09322 2.23475 2.70696 2.62102C2.31643 3.01154 2.31643 3.64471 2.70696 4.03523L10.414 11.7423L10.6238 13.7566C10.6974 14.4631 11.293 14.9998 12.0033 14.9998C12.4551 14.9998 12.8605 14.7827 13.1147 14.4429L19.6775 21.0058C20.068 21.3963 20.7012 21.3963 21.0917 21.0058C21.478 20.6195 21.4822 19.9959 21.1044 19.6044C21.1001 19.6003 21.0958 19.5961 21.0916 19.5919L4.12102 2.62132C4.11674 2.61704 4.1125 2.61273 4.10831 2.60839ZM13.8264 9.4983L14.2443 5.4864C14.3828 4.15689 13.34 2.99985 12.0033 2.99985C10.6859 2.99985 9.65401 4.12375 9.7571 5.42898L13.8264 9.4983ZM12.0033 16.9998C11.0368 16.9998 10.2533 17.7834 10.2533 18.7498C10.2533 19.7163 11.0368 20.4998 12.0033 20.4998C12.9698 20.4998 13.7533 19.7163 13.7533 18.7498C13.7533 17.7834 12.9698 16.9998 12.0033 16.9998Z" fill="#78787A"/>
|
||||
</svg>
|
After Width: | Height: | Size: 979 B |
3
frontend/src/assets/icons/24_Negator.svg
Normal file
3
frontend/src/assets/icons/24_Negator.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0033 3C10.6666 3 9.62387 4.15704 9.76236 5.48654L10.6238 13.7567C10.6974 14.4633 11.293 15 12.0033 15C12.7137 15 13.3093 14.4633 13.3829 13.7567L14.2443 5.48655C14.3828 4.15704 13.34 3 12.0033 3ZM12.0033 17C11.0368 17 10.2533 17.7835 10.2533 18.75C10.2533 19.7165 11.0368 20.5 12.0033 20.5C12.9698 20.5 13.7533 19.7165 13.7533 18.75C13.7533 17.7835 12.9698 17 12.0033 17Z" fill="#78787A"/>
|
||||
</svg>
|
After Width: | Height: | Size: 546 B |
3
frontend/src/assets/icons/24_Text format off.svg
Normal file
3
frontend/src/assets/icons/24_Text format off.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.10831 2.60839C3.71687 2.23054 3.09322 2.23475 2.70696 2.62102C2.31643 3.01154 2.31643 3.64471 2.70696 4.03523L8.65871 9.98698L7.07 13.6598C6.8 14.2898 7.27 14.9998 7.96 14.9998C8.35 14.9998 8.7 14.7598 8.85 14.3998L9.5 12.7998H11.4716L15.6716 16.9998H6C5.45 16.9998 5 17.4498 5 17.9998C5 18.5498 5.45 18.9998 6 18.9998H17.6716L19.6775 21.0058C20.068 21.3963 20.7012 21.3963 21.0917 21.0058C21.478 20.6195 21.4822 19.9959 21.1044 19.6044C21.1001 19.6003 21.0958 19.5961 21.0916 19.5919L4.12102 2.62132C4.11674 2.61704 4.1125 2.61273 4.10831 2.60839ZM16.1235 11.7954L13.05 4.68985C12.87 4.26985 12.46 3.99985 12 3.99985C11.54 3.99985 11.13 4.26985 10.95 4.68985L10.3666 6.03851L11.5408 7.21265L12 5.97985L13.0045 8.67635L16.1235 11.7954Z" fill="#78787A"/>
|
||||
</svg>
|
After Width: | Height: | Size: 909 B |
3
frontend/src/assets/icons/24_Text format.svg
Normal file
3
frontend/src/assets/icons/24_Text format.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 18C5 18.55 5.45 19 6 19H18C18.55 19 19 18.55 19 18C19 17.45 18.55 17 18 17H6C5.45 17 5 17.45 5 18ZM9.5 12.8H14.5L15.16 14.4C15.31 14.76 15.66 15 16.05 15C16.74 15 17.2 14.29 16.93 13.66L13.05 4.69C12.87 4.27 12.46 4 12 4C11.54 4 11.13 4.27 10.95 4.69L7.07 13.66C6.8 14.29 7.27 15 7.96 15C8.35 15 8.7 14.76 8.85 14.4L9.5 12.8ZM12 5.98L13.87 11H10.13L12 5.98Z" fill="#78787A"/>
|
||||
</svg>
|
After Width: | Height: | Size: 491 B |
@ -106,7 +106,8 @@ export const useStyles = makeStyles()(theme => ({
|
||||
marginTop: '1rem',
|
||||
},
|
||||
},
|
||||
headerSelect: { marginRight: '2rem', width: '200px' },
|
||||
invertedOperatorButton: { marginRight: '1rem', marginLeft: 'auto', },
|
||||
headerSelect: { marginRight: '1rem', width: '200px' },
|
||||
chip: {
|
||||
margin: '0 0.5rem 0.5rem 0',
|
||||
},
|
||||
|
@ -33,6 +33,7 @@ export const ConstraintAccordion = ({
|
||||
constraint={constraint}
|
||||
onCancel={onCancel}
|
||||
onSave={onSave!}
|
||||
onDelete={onDelete}
|
||||
compact={compact}
|
||||
/>
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ interface IConstraintAccordionEditProps {
|
||||
onCancel: () => void;
|
||||
onSave: (constraint: IConstraint) => void;
|
||||
compact: boolean;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
||||
export const CANCEL = 'cancel';
|
||||
@ -48,6 +49,7 @@ export const ConstraintAccordionEdit = ({
|
||||
compact,
|
||||
onCancel,
|
||||
onSave,
|
||||
onDelete,
|
||||
}: IConstraintAccordionEditProps) => {
|
||||
const [localConstraint, setLocalConstraint] = useState<IConstraint>(
|
||||
cleanConstraint(constraint)
|
||||
@ -203,6 +205,8 @@ export const ConstraintAccordionEdit = ({
|
||||
setOperator={setOperator}
|
||||
action={action}
|
||||
compact={compact}
|
||||
setInvertedOperator={setInvertedOperator}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
</AccordionSummary>
|
||||
|
||||
@ -217,7 +221,6 @@ export const ConstraintAccordionEdit = ({
|
||||
setCaseInsensitive={setCaseInsensitive}
|
||||
triggerTransition={triggerTransition}
|
||||
setAction={setAction}
|
||||
setInvertedOperator={setInvertedOperator}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<ResolveInput
|
||||
|
@ -17,7 +17,6 @@ interface IConstraintAccordionBody {
|
||||
setValue: (value: string) => void;
|
||||
setAction: React.Dispatch<React.SetStateAction<string>>;
|
||||
setCaseInsensitive: () => void;
|
||||
setInvertedOperator: () => void;
|
||||
onSubmit: () => void;
|
||||
}
|
||||
|
||||
@ -40,10 +39,6 @@ export const ConstraintAccordionEditBody: React.FC<
|
||||
condition={oneOf(newOperators, localConstraint.operator)}
|
||||
show={<OperatorUpgradeAlert />}
|
||||
/>
|
||||
<InvertedOperator
|
||||
inverted={Boolean(localConstraint.inverted)}
|
||||
setInvertedOperator={setInvertedOperator}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
<div className={styles.buttonContainer}>
|
||||
@ -71,33 +66,3 @@ export const ConstraintAccordionEditBody: React.FC<
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface IInvertedOperatorProps {
|
||||
inverted: boolean;
|
||||
setInvertedOperator: () => void;
|
||||
}
|
||||
|
||||
const InvertedOperator = ({
|
||||
inverted,
|
||||
setInvertedOperator,
|
||||
}: IInvertedOperatorProps) => {
|
||||
return (
|
||||
<>
|
||||
<ConstraintFormHeader>
|
||||
Should the operator be negated? (this will make the operator do
|
||||
the opposite)
|
||||
</ConstraintFormHeader>
|
||||
<FormControlLabel
|
||||
style={{ display: 'inline-block' }}
|
||||
control={
|
||||
<Switch
|
||||
checked={inverted}
|
||||
onChange={() => setInvertedOperator()}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="Negated"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -110,8 +110,8 @@ export const FreeTextInput = ({
|
||||
</div>
|
||||
<Button
|
||||
className={styles.button}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => addValues()}
|
||||
>
|
||||
Add values
|
||||
|
@ -4,7 +4,7 @@ import { useStyles } from 'component/common/ConstraintAccordion/ConstraintAccord
|
||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
|
||||
import { ConstraintIcon } from 'component/common/ConstraintAccordion/ConstraintIcon';
|
||||
import { Help } from '@mui/icons-material';
|
||||
import { Delete, Edit, Help } from '@mui/icons-material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { dateOperators, DATE_AFTER, IN } from 'constants/operators';
|
||||
import { SAVE } from '../ConstraintAccordionEdit';
|
||||
@ -17,7 +17,10 @@ import {
|
||||
operatorsForContext,
|
||||
CURRENT_TIME_CONTEXT_FIELD,
|
||||
} from 'utils/operatorsForContext';
|
||||
import { Tooltip } from '@mui/material';
|
||||
import { IconButton, Tooltip } from '@mui/material';
|
||||
import { ReactComponent as NegatedIcon } from 'assets/icons/24_Negator.svg';
|
||||
import { ReactComponent as NegatedIconOff } from 'assets/icons/24_Negator off.svg';
|
||||
import { InvertedOperator } from './InvertedOperatorButton/InvertedOperator';
|
||||
|
||||
interface IConstraintAccordionViewHeader {
|
||||
localConstraint: IConstraint;
|
||||
@ -26,6 +29,8 @@ interface IConstraintAccordionViewHeader {
|
||||
setLocalConstraint: React.Dispatch<React.SetStateAction<IConstraint>>;
|
||||
action: string;
|
||||
compact: boolean;
|
||||
onDelete?: () => void;
|
||||
setInvertedOperator: () => void;
|
||||
}
|
||||
|
||||
export const ConstraintAccordionEditHeader = ({
|
||||
@ -34,7 +39,8 @@ export const ConstraintAccordionEditHeader = ({
|
||||
setLocalConstraint,
|
||||
setContextName,
|
||||
setOperator,
|
||||
action,
|
||||
onDelete,
|
||||
setInvertedOperator,
|
||||
}: IConstraintAccordionViewHeader) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const { context } = useUnleashContext();
|
||||
@ -83,6 +89,13 @@ export const ConstraintAccordionEditHeader = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onDeleteClick =
|
||||
onDelete &&
|
||||
((event: React.SyntheticEvent) => {
|
||||
event.stopPropagation();
|
||||
onDelete();
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.headerContainer}>
|
||||
<ConstraintIcon />
|
||||
@ -99,6 +112,13 @@ export const ConstraintAccordionEditHeader = ({
|
||||
className={styles.headerSelect}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<InvertedOperator
|
||||
localConstraint={localConstraint}
|
||||
setInvertedOperator={setInvertedOperator}
|
||||
className={styles.invertedOperatorButton}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.bottomSelect}>
|
||||
<div className={styles.headerSelect}>
|
||||
<ConstraintOperatorSelect
|
||||
@ -117,21 +137,18 @@ export const ConstraintAccordionEditHeader = ({
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={action === SAVE}
|
||||
show={<p className={styles.editingBadge}>Updating...</p>}
|
||||
elseShow={<p className={styles.editingBadge}>Editing</p>}
|
||||
/>
|
||||
<Tooltip title="Help" arrow>
|
||||
<a
|
||||
href="https://docs.getunleash.io/advanced/strategy_constraints"
|
||||
style={{ marginLeft: 'auto' }}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Help className={styles.help} />
|
||||
</a>
|
||||
</Tooltip>
|
||||
<div className={styles.headerActions}>
|
||||
<Tooltip title="Edit constraint" arrow>
|
||||
<IconButton type="button" disabled>
|
||||
<Edit />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete constraint" arrow>
|
||||
<IconButton type="button" onClick={onDeleteClick}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,43 @@
|
||||
import { Button, IconButton, Tooltip } from '@mui/material';
|
||||
import { ReactComponent as NegatedIcon } from '../../../../../../assets/icons/24_Negator.svg';
|
||||
import { ReactComponent as NegatedIconOff } from '../../../../../../assets/icons/24_Negator off.svg';
|
||||
import React, { useMemo } from 'react';
|
||||
import { IConstraint } from '../../../../../../interfaces/strategy';
|
||||
|
||||
interface InvertedOperatorProps {
|
||||
localConstraint: IConstraint;
|
||||
setInvertedOperator: () => void;
|
||||
className: any;
|
||||
}
|
||||
|
||||
export const InvertedOperator = ({
|
||||
localConstraint,
|
||||
setInvertedOperator,
|
||||
className
|
||||
}: InvertedOperatorProps) => {
|
||||
const icon = useMemo(() => {
|
||||
return localConstraint.inverted ? (
|
||||
<NegatedIcon fill='white' stroke='white'/>
|
||||
) : (
|
||||
<NegatedIconOff fill='white' stroke='white'/>
|
||||
);
|
||||
}, [localConstraint]);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
localConstraint.inverted ? 'Remove negation' : 'Negate operator'
|
||||
}
|
||||
arrow
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={setInvertedOperator}
|
||||
disableRipple
|
||||
className={className}
|
||||
>
|
||||
{icon}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
@ -12,7 +12,7 @@ import {
|
||||
} from 'constants/operators';
|
||||
|
||||
import { useStyles } from '../ConstraintAccordion.styles';
|
||||
import {useState} from "react";
|
||||
import { useState } from 'react';
|
||||
interface IConstraintAccordionViewProps {
|
||||
constraint: IConstraint;
|
||||
onDelete?: () => void;
|
||||
@ -27,7 +27,7 @@ export const ConstraintAccordionView = ({
|
||||
onDelete,
|
||||
}: IConstraintAccordionViewProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const [expandable, setExpandable] = useState(true)
|
||||
const [expandable, setExpandable] = useState(true);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const singleValue = oneOf(
|
||||
@ -35,8 +35,8 @@ export const ConstraintAccordionView = ({
|
||||
constraint.operator
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
console.log('click')
|
||||
const handleClick = () => {
|
||||
console.log('click');
|
||||
if (expandable) {
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
@ -48,17 +48,18 @@ export const ConstraintAccordionView = ({
|
||||
classes={{ root: styles.accordionRoot }}
|
||||
expanded={expanded}
|
||||
>
|
||||
<AccordionSummary className={styles.summary} expandIcon={null} onClick={handleClick}>
|
||||
<AccordionSummary
|
||||
className={styles.summary}
|
||||
expandIcon={null}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<ConstraintAccordionViewHeader
|
||||
compact={compact}
|
||||
constraint={constraint}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
singleValue={singleValue}
|
||||
allowExpand={(shouldExpand) => {
|
||||
console.log(shouldExpand)
|
||||
setExpandable(shouldExpand)
|
||||
}}
|
||||
allowExpand={setExpandable}
|
||||
/>
|
||||
</AccordionSummary>
|
||||
|
||||
|
@ -11,6 +11,7 @@ import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||
import { ConstraintOperator } from 'component/common/ConstraintAccordion/ConstraintOperator/ConstraintOperator';
|
||||
import classnames from 'classnames';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { getTextWidth } from '../../utils';
|
||||
|
||||
const StyledHeaderText = styled('span')(({ theme }) => ({
|
||||
display: '-webkit-box',
|
||||
@ -64,13 +65,13 @@ export const ConstraintAccordionViewHeader = ({
|
||||
onEdit,
|
||||
onDelete,
|
||||
singleValue,
|
||||
allowExpand
|
||||
allowExpand,
|
||||
}: IConstraintAccordionViewHeaderProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const { locationSettings } = useLocationSettings();
|
||||
const [height, setHeight] = useState(0);
|
||||
const [width, setWidth] = useState(0);
|
||||
const [textWidth, setTextWidth] = useState(0);
|
||||
const [expandable, setExpandable] = useState(false);
|
||||
const elementRef = useRef<HTMLElement>(null);
|
||||
|
||||
const onEditClick =
|
||||
@ -92,29 +93,16 @@ export const ConstraintAccordionViewHeader = ({
|
||||
setTextWidth(
|
||||
Math.round(getTextWidth(elementRef.current.innerText) / 2) // 2 lines
|
||||
);
|
||||
setHeight(elementRef.current.clientHeight);
|
||||
setWidth(elementRef.current.clientWidth);
|
||||
console.log(textWidth)
|
||||
console.log(width)
|
||||
allowExpand(textWidth > width)
|
||||
}
|
||||
}, []);
|
||||
|
||||
function getTextWidth(text: string | null) {
|
||||
if (text != null) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
if (context != null) {
|
||||
context.font = getComputedStyle(document.body).font;
|
||||
|
||||
return context.measureText(text).width;
|
||||
}
|
||||
useEffect(() => {
|
||||
if (textWidth && width) {
|
||||
setExpandable(textWidth > width);
|
||||
allowExpand(textWidth > width);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const shouldBeExpandable = textWidth > width;
|
||||
}, [textWidth, width, allowExpand]);
|
||||
|
||||
return (
|
||||
<div className={styles.headerContainer}>
|
||||
@ -146,7 +134,7 @@ export const ConstraintAccordionViewHeader = ({
|
||||
.join(', ')}
|
||||
</StyledValuesSpan>
|
||||
<ConditionallyRender
|
||||
condition={shouldBeExpandable}
|
||||
condition={expandable}
|
||||
show={
|
||||
<p
|
||||
className={classnames(
|
||||
|
13
frontend/src/component/common/ConstraintAccordion/utils.ts
Normal file
13
frontend/src/component/common/ConstraintAccordion/utils.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function getTextWidth(text: string | null) {
|
||||
if (text != null) {
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
if (context != null) {
|
||||
context.font = getComputedStyle(document.body).font;
|
||||
|
||||
return context.measureText(text).width;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user