mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-23 01:16:27 +02:00
fmt and lint
This commit is contained in:
parent
2299eb9305
commit
2bd239f481
@ -17,17 +17,11 @@ import {
|
||||
semVerOperators,
|
||||
} from 'constants/operators';
|
||||
import { useStyles } from '../ConstraintAccordion.styles';
|
||||
import {
|
||||
PlaygroundConstraintSchema,
|
||||
PlaygroundRequestSchema,
|
||||
} from '../../../../hooks/api/actions/usePlayground/playground.model';
|
||||
|
||||
interface IConstraintAccordionViewProps {
|
||||
constraint: IConstraint | PlaygroundConstraintSchema;
|
||||
constraint: IConstraint;
|
||||
onDelete?: () => void;
|
||||
onEdit?: () => void;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
maxLength?: number;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
@ -36,8 +30,6 @@ export const ConstraintAccordionView = ({
|
||||
onEdit,
|
||||
onDelete,
|
||||
sx = undefined,
|
||||
maxLength,
|
||||
playgroundInput,
|
||||
}: IConstraintAccordionViewProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const [expandable, setExpandable] = useState(true);
|
||||
@ -53,11 +45,6 @@ export const ConstraintAccordionView = ({
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
};
|
||||
const backgroundColor = Boolean(playgroundInput)
|
||||
? !Boolean((constraint as PlaygroundConstraintSchema).result)
|
||||
? theme.palette.neutral.light
|
||||
: 'inherit'
|
||||
: 'inherit';
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
@ -75,7 +62,6 @@ export const ConstraintAccordionView = ({
|
||||
'&:hover': {
|
||||
cursor: expandable ? 'pointer' : 'default!important',
|
||||
},
|
||||
backgroundColor: backgroundColor,
|
||||
}}
|
||||
>
|
||||
<ConstraintAccordionViewHeader
|
||||
@ -85,8 +71,6 @@ export const ConstraintAccordionView = ({
|
||||
singleValue={singleValue}
|
||||
allowExpand={setExpandable}
|
||||
expanded={expanded}
|
||||
maxLength={maxLength ?? 112}
|
||||
playgroundInput={playgroundInput}
|
||||
/>
|
||||
</AccordionSummary>
|
||||
|
||||
|
@ -3,20 +3,14 @@ import { IConstraint } from 'interfaces/strategy';
|
||||
import { ConstraintAccordionViewHeaderInfo } from './ConstraintAccordionViewHeaderInfo/ConstraintAccordionViewHeaderInfo';
|
||||
import { ConstraintAccordionHeaderActions } from '../../ConstraintAccordionHeaderActions/ConstraintAccordionHeaderActions';
|
||||
import { useStyles } from 'component/common/ConstraintAccordion/ConstraintAccordion.styles';
|
||||
import {
|
||||
PlaygroundConstraintSchema,
|
||||
PlaygroundRequestSchema,
|
||||
} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
|
||||
interface IConstraintAccordionViewHeaderProps {
|
||||
constraint: IConstraint | PlaygroundConstraintSchema;
|
||||
constraint: IConstraint;
|
||||
onDelete?: () => void;
|
||||
onEdit?: () => void;
|
||||
singleValue: boolean;
|
||||
expanded: boolean;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export const ConstraintAccordionViewHeader = ({
|
||||
@ -26,8 +20,6 @@ export const ConstraintAccordionViewHeader = ({
|
||||
singleValue,
|
||||
allowExpand,
|
||||
expanded,
|
||||
maxLength,
|
||||
playgroundInput,
|
||||
}: IConstraintAccordionViewHeaderProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
@ -39,9 +31,6 @@ export const ConstraintAccordionViewHeader = ({
|
||||
singleValue={singleValue}
|
||||
allowExpand={allowExpand}
|
||||
expanded={expanded}
|
||||
result={'result' in constraint ? constraint.result : undefined}
|
||||
maxLength={maxLength}
|
||||
playgroundInput={playgroundInput}
|
||||
/>
|
||||
<ConstraintAccordionHeaderActions
|
||||
onEdit={onEdit}
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { styled, Tooltip, Typography, useTheme } from '@mui/material';
|
||||
import { styled, Tooltip } from '@mui/material';
|
||||
import { ConstraintViewHeaderOperator } from '../ConstraintViewHeaderOperator/ConstraintViewHeaderOperator';
|
||||
import { ConditionallyRender } from '../../../../ConditionallyRender/ConditionallyRender';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ConstraintAccordionViewHeaderSingleValue } from '../ContraintAccordionViewHeaderSingleValue/ConstraintAccordionViewHeaderSingleValue';
|
||||
import { ConstraintAccordionViewHeaderMultipleValues } from '../ContraintAccordionViewHeaderMultipleValues/ConstraintAccordionViewHeaderMultipleValues';
|
||||
import React from 'react';
|
||||
import { IConstraint } from '../../../../../../interfaces/strategy';
|
||||
import { useStyles } from '../../../ConstraintAccordion.styles';
|
||||
import { CancelOutlined } from '@mui/icons-material';
|
||||
import { PlaygroundRequestSchema } from '../../../../../../hooks/api/actions/usePlayground/playground.model';
|
||||
|
||||
const StyledHeaderText = styled('span')(({ theme }) => ({
|
||||
display: '-webkit-box',
|
||||
@ -41,9 +39,7 @@ interface ConstraintAccordionViewHeaderMetaInfoProps {
|
||||
singleValue: boolean;
|
||||
expanded: boolean;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
result?: boolean;
|
||||
maxLength?: number;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
}
|
||||
|
||||
export const ConstraintAccordionViewHeaderInfo = ({
|
||||
@ -51,17 +47,9 @@ export const ConstraintAccordionViewHeaderInfo = ({
|
||||
singleValue,
|
||||
allowExpand,
|
||||
expanded,
|
||||
result,
|
||||
playgroundInput,
|
||||
maxLength = 112,
|
||||
}: ConstraintAccordionViewHeaderMetaInfoProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const theme = useTheme();
|
||||
|
||||
const isPlayground = Boolean(playgroundInput);
|
||||
const constrainExistsInContext =
|
||||
isPlayground &&
|
||||
Boolean(playgroundInput?.context[constraint.contextName]);
|
||||
|
||||
return (
|
||||
<StyledHeaderWrapper>
|
||||
@ -69,23 +57,6 @@ export const ConstraintAccordionViewHeaderInfo = ({
|
||||
<Tooltip title={constraint.contextName} arrow>
|
||||
<StyledHeaderText>
|
||||
{constraint.contextName}
|
||||
<ConditionallyRender
|
||||
condition={isPlayground}
|
||||
show={
|
||||
<Typography
|
||||
variant={'body1'}
|
||||
color={
|
||||
constrainExistsInContext
|
||||
? theme.palette.neutral.dark
|
||||
: theme.palette.error.main
|
||||
}
|
||||
>
|
||||
{playgroundInput?.context[
|
||||
constraint.contextName
|
||||
] || 'no value'}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</StyledHeaderText>
|
||||
</Tooltip>
|
||||
<ConstraintViewHeaderOperator constraint={constraint} />
|
||||
@ -107,10 +78,6 @@ export const ConstraintAccordionViewHeaderInfo = ({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<ConditionallyRender
|
||||
condition={result !== undefined && !Boolean(result)}
|
||||
show={<CancelOutlined color="error" sx={{ mt: 1 }} />}
|
||||
/>
|
||||
</StyledHeaderWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -27,7 +27,9 @@ export const FeatureResultInfoPopoverCell = ({
|
||||
const { classes: styles } = useStyles();
|
||||
const ref = useRef(null);
|
||||
|
||||
const togglePopover = (event: React.SyntheticEvent) => {
|
||||
console.log(feature)
|
||||
|
||||
const togglePopover = () => {
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,9 @@ export const useStyles = makeStyles()(theme => ({
|
||||
gap: '12px',
|
||||
marginTop: '12px',
|
||||
},
|
||||
alertRow: {},
|
||||
alertRow: {
|
||||
margin: theme.spacing(1,0),
|
||||
},
|
||||
descriptionRow: {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
|
@ -24,25 +24,19 @@ export const PlaygroundResultFeatureDetails = ({
|
||||
const theme = useTheme();
|
||||
|
||||
const description =
|
||||
feature.isEnabled === 'unevaluated'
|
||||
? `This feature toggle is Unevaluated in ${input?.environment} because `
|
||||
: feature.isEnabled
|
||||
feature.isEnabled
|
||||
? `This feature toggle is True in ${input?.environment} because `
|
||||
: `This feature toggle is False in ${input?.environment} because `;
|
||||
|
||||
const reason =
|
||||
feature.isEnabled === 'unevaluated'
|
||||
? 'custom strategies are not evaluated yet'
|
||||
feature.isEnabled
|
||||
? 'at least one strategy is True'
|
||||
: !feature.isEnabledInCurrentEnvironment
|
||||
? 'the environment is disabled'
|
||||
: feature.isEnabled
|
||||
? 'at least one strategy is True'
|
||||
: 'all strategies are False';
|
||||
|
||||
const color =
|
||||
feature.isEnabled === 'unevaluated'
|
||||
? theme.palette.warning.main
|
||||
: feature.isEnabled
|
||||
feature.isEnabled
|
||||
? theme.palette.success.main
|
||||
: theme.palette.error.main;
|
||||
|
||||
@ -67,10 +61,7 @@ export const PlaygroundResultFeatureDetails = ({
|
||||
<span>
|
||||
<PlaygroundResultChip
|
||||
enabled={feature.isEnabled}
|
||||
label={
|
||||
feature.isEnabled === 'unevaluated'
|
||||
? '?'
|
||||
: Boolean(feature.isEnabled)
|
||||
label={feature.isEnabled
|
||||
? 'True'
|
||||
: 'False'
|
||||
}
|
||||
|
@ -20,17 +20,17 @@ export const PlaygroundResultFeatureStrategyList = ({
|
||||
}: PlaygroundResultFeatureStrategyListProps) => {
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={!feature.isEnabledInCurrentEnvironment}
|
||||
condition={!feature.isEnabledInCurrentEnvironment && Boolean(feature?.strategies?.data)}
|
||||
show={
|
||||
<WrappedPlaygroundResultStrategyList
|
||||
strategies={feature?.strategies}
|
||||
strategies={feature?.strategies?.data!}
|
||||
feature={feature}
|
||||
input={input}
|
||||
/>
|
||||
}
|
||||
elseShow={
|
||||
<PlaygroundResultStrategyLists
|
||||
strategies={feature?.strategies}
|
||||
strategies={feature?.strategies?.data!}
|
||||
input={input}
|
||||
/>
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ const StyledItemWrapper = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: '4px',
|
||||
gap: '8px',
|
||||
margin: theme.spacing(0.5),
|
||||
gap: theme.spacing(1),
|
||||
}));
|
||||
|
||||
export const PlaygroundResultFeatureStrategyItem = ({
|
||||
@ -63,8 +63,8 @@ export const PlaygroundResultFeatureStrategyItem = ({
|
||||
condition={index > 0}
|
||||
show={<StrategySeparator text="OR" />}
|
||||
/>
|
||||
<StyledItemWrapper>
|
||||
<Typography variant={'subtitle1'} color={'text.secondary'}>
|
||||
<StyledItemWrapper sx={{mr: 2}}>
|
||||
<Typography variant={'subtitle1'} color={'text.secondary'} sx={{ml: 1}}>
|
||||
{index + 1}
|
||||
</Typography>
|
||||
<Box className={styles.innerContainer} sx={{ border }}>
|
||||
|
@ -0,0 +1,158 @@
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
export const useStyles = makeStyles()(theme => ({
|
||||
constraintIconContainer: {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
borderRadius: '50%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: theme.spacing(1),
|
||||
[theme.breakpoints.down(650)]: {
|
||||
marginBottom: '1rem',
|
||||
marginRight: 0,
|
||||
},
|
||||
},
|
||||
constraintIcon: {
|
||||
fill: '#fff',
|
||||
},
|
||||
accordion: {
|
||||
border: `1px solid ${theme.palette.grey[400]}`,
|
||||
borderRadius: '8px',
|
||||
backgroundColor: '#fff',
|
||||
boxShadow: 'none',
|
||||
margin: 0,
|
||||
},
|
||||
accordionRoot: {
|
||||
'&:before': {
|
||||
opacity: '0 !important',
|
||||
},
|
||||
},
|
||||
accordionEdit: {
|
||||
backgroundColor: '#F6F6FA',
|
||||
},
|
||||
headerMetaInfo: {
|
||||
display: 'flex',
|
||||
alignItems: 'stretch',
|
||||
[theme.breakpoints.down(710)]: { flexDirection: 'column' },
|
||||
},
|
||||
headerContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
[theme.breakpoints.down(710)]: {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
},
|
||||
},
|
||||
headerValuesContainerWrapper: {
|
||||
display: 'flex',
|
||||
alignItems: 'stretch',
|
||||
margin: 'auto 0',
|
||||
},
|
||||
headerValuesContainer: {
|
||||
display: 'flex',
|
||||
justifyContent: 'stretch',
|
||||
margin: 'auto 0',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
headerValues: {
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
},
|
||||
headerValuesExpand: {
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
marginTop: '4px',
|
||||
color: theme.palette.primary.dark,
|
||||
[theme.breakpoints.down(710)]: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
headerConstraintContainer: {
|
||||
minWidth: '220px',
|
||||
position: 'relative',
|
||||
paddingRight: '1rem',
|
||||
[theme.breakpoints.between(1101, 1365)]: {
|
||||
minWidth: '152px',
|
||||
paddingRight: '0.5rem',
|
||||
},
|
||||
},
|
||||
editingBadge: {
|
||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||
padding: '0.25rem 0.5rem',
|
||||
backgroundColor: '#635DC5',
|
||||
color: '#fff',
|
||||
marginLeft: 'auto',
|
||||
fontSize: '0.9rem',
|
||||
[theme.breakpoints.down(650)]: {
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: '-10px',
|
||||
},
|
||||
},
|
||||
headerText: {
|
||||
maxWidth: '400px',
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
[theme.breakpoints.down('xl')]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
selectContainer: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
[theme.breakpoints.down(770)]: {
|
||||
flexDirection: 'column',
|
||||
},
|
||||
},
|
||||
bottomSelect: {
|
||||
[theme.breakpoints.down(770)]: {
|
||||
marginTop: '1rem',
|
||||
},
|
||||
display: 'inline-flex',
|
||||
},
|
||||
headerSelect: {
|
||||
marginRight: '1rem',
|
||||
width: '200px',
|
||||
[theme.breakpoints.between(1101, 1365)]: {
|
||||
width: '170px',
|
||||
marginRight: '8px',
|
||||
},
|
||||
},
|
||||
chip: {
|
||||
margin: '0 0.5rem 0.5rem 0',
|
||||
},
|
||||
chipValue: {
|
||||
whiteSpace: 'pre',
|
||||
},
|
||||
headerActions: {
|
||||
marginLeft: 'auto',
|
||||
whiteSpace: 'nowrap',
|
||||
[theme.breakpoints.down(710)]: {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
accordionDetails: {
|
||||
borderTop: `1px dashed ${theme.palette.grey[300]}`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
valuesContainer: {
|
||||
padding: '1rem 0rem',
|
||||
maxHeight: '400px',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
summary: {
|
||||
border: 'none',
|
||||
padding: theme.spacing(0.5, 3),
|
||||
'&:hover .valuesExpandLabel': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
},
|
||||
settingsIcon: {
|
||||
height: '32.5px',
|
||||
width: '32.5px',
|
||||
marginRight: '0.5rem',
|
||||
fill: theme.palette.inactiveIcon,
|
||||
},
|
||||
form: { padding: 0, margin: 0, width: '100%' },
|
||||
}));
|
@ -0,0 +1,41 @@
|
||||
import {ConstraintIcon} from 'component/common/ConstraintAccordion/ConstraintIcon';
|
||||
import {
|
||||
PlaygroundConstraintAccordionViewHeaderInfo
|
||||
} from './PlaygroundConstraintAccordionViewHeaderInfo/PlaygroundConstraintAccordionViewHeaderInfo';
|
||||
import {useStyles} from 'component/common/ConstraintAccordion/ConstraintAccordion.styles';
|
||||
import {PlaygroundConstraintSchema, PlaygroundRequestSchema,} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
|
||||
interface PlaygroundConstraintAccordionViewHeaderProps {
|
||||
constraint: PlaygroundConstraintSchema;
|
||||
singleValue: boolean;
|
||||
expanded: boolean;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
maxLength?: number;
|
||||
}
|
||||
|
||||
export const PlaygroundConstraintAccordionViewHeader = ({
|
||||
constraint,
|
||||
singleValue,
|
||||
allowExpand,
|
||||
expanded,
|
||||
maxLength,
|
||||
playgroundInput,
|
||||
}: PlaygroundConstraintAccordionViewHeaderProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
return (
|
||||
<div className={styles.headerContainer}>
|
||||
<ConstraintIcon />
|
||||
<PlaygroundConstraintAccordionViewHeaderInfo
|
||||
constraint={constraint}
|
||||
singleValue={singleValue}
|
||||
allowExpand={allowExpand}
|
||||
expanded={expanded}
|
||||
result={constraint.result}
|
||||
maxLength={maxLength}
|
||||
playgroundInput={playgroundInput}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,110 @@
|
||||
import { styled, Tooltip, Typography, useTheme } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { PlaygroundConstraintAccordionViewHeaderSingleValue } from '../PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue';
|
||||
import { PLaygroundConstraintAccordionViewHeaderMultipleValues } from '../PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues';
|
||||
import React from 'react';
|
||||
import { useStyles } from '../../PlaygroundConstraintAccordion.styles';
|
||||
import { CancelOutlined } from '@mui/icons-material';
|
||||
import {PlaygroundConstraintSchema, PlaygroundRequestSchema} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import {
|
||||
ConstraintViewHeaderOperator
|
||||
} from "component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintViewHeaderOperator/ConstraintViewHeaderOperator";
|
||||
|
||||
const StyledHeaderText = styled('span')(({ theme }) => ({
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 3,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
overflow: 'hidden',
|
||||
maxWidth: '100px',
|
||||
minWidth: '100px',
|
||||
marginRight: '10px',
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
wordBreak: 'break-word',
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
[theme.breakpoints.down(710)]: {
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing(1, 0),
|
||||
marginRight: 'inherit',
|
||||
maxWidth: 'inherit',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledHeaderWrapper = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
borderRadius: theme.spacing(1),
|
||||
}));
|
||||
|
||||
interface PlaygroundConstraintAccordionViewHeaderInfoProps {
|
||||
constraint: PlaygroundConstraintSchema;
|
||||
singleValue: boolean;
|
||||
expanded: boolean;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
result?: boolean;
|
||||
maxLength?: number;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
}
|
||||
|
||||
export const PlaygroundConstraintAccordionViewHeaderInfo = ({
|
||||
constraint,
|
||||
singleValue,
|
||||
allowExpand,
|
||||
expanded,
|
||||
result,
|
||||
playgroundInput,
|
||||
maxLength = 112,
|
||||
}: PlaygroundConstraintAccordionViewHeaderInfoProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const theme = useTheme();
|
||||
|
||||
const constraintExistsInContext =
|
||||
Boolean(playgroundInput?.context[constraint.contextName]);
|
||||
|
||||
return (
|
||||
<StyledHeaderWrapper>
|
||||
<div className={styles.headerMetaInfo}>
|
||||
<Tooltip title={constraint.contextName} arrow>
|
||||
<StyledHeaderText>
|
||||
{constraint.contextName}
|
||||
<Typography
|
||||
variant={'body1'}
|
||||
color={
|
||||
constraintExistsInContext
|
||||
? theme.palette.neutral.dark
|
||||
: theme.palette.error.main
|
||||
}
|
||||
>
|
||||
{playgroundInput?.context[
|
||||
constraint.contextName
|
||||
] || 'no value'}
|
||||
</Typography>
|
||||
</StyledHeaderText>
|
||||
</Tooltip>
|
||||
<ConstraintViewHeaderOperator constraint={constraint} />
|
||||
<ConditionallyRender
|
||||
condition={singleValue}
|
||||
show={
|
||||
<PlaygroundConstraintAccordionViewHeaderSingleValue
|
||||
constraint={constraint}
|
||||
allowExpand={allowExpand}
|
||||
/>
|
||||
}
|
||||
elseShow={
|
||||
<PLaygroundConstraintAccordionViewHeaderMultipleValues
|
||||
constraint={constraint}
|
||||
expanded={expanded}
|
||||
allowExpand={allowExpand}
|
||||
maxLength={maxLength}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<ConditionallyRender
|
||||
condition={result !== undefined && !Boolean(result)}
|
||||
show={<CancelOutlined color="error" sx={{ mt: 1 }} />}
|
||||
/>
|
||||
</StyledHeaderWrapper>
|
||||
);
|
||||
};
|
@ -0,0 +1,85 @@
|
||||
import {ConditionallyRender} from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import {styled, Typography} from '@mui/material';
|
||||
import React, {useEffect, useMemo, useState} from 'react';
|
||||
import classnames from 'classnames';
|
||||
import {useStyles} from '../../PlaygroundConstraintAccordion.styles';
|
||||
import {PlaygroundConstraintSchema} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
|
||||
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(710)]: {
|
||||
margin: theme.spacing(1, 0),
|
||||
textAlign: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
interface ConstraintSingleValueProps {
|
||||
constraint: PlaygroundConstraintSchema;
|
||||
expanded: boolean;
|
||||
maxLength: number;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
}
|
||||
|
||||
export const PLaygroundConstraintAccordionViewHeaderMultipleValues = ({
|
||||
constraint,
|
||||
expanded,
|
||||
allowExpand,
|
||||
maxLength,
|
||||
}: ConstraintSingleValueProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
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 (
|
||||
<div className={styles.headerValuesContainerWrapper}>
|
||||
<div className={styles.headerValuesContainer}>
|
||||
<ConditionallyRender
|
||||
condition={!Boolean(constraint.result)}
|
||||
show={
|
||||
<Typography
|
||||
variant={'body2'}
|
||||
color={'error'}
|
||||
noWrap={true}
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
does not match any values{' '}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<StyledValuesSpan>{text}</StyledValuesSpan>
|
||||
<ConditionallyRender
|
||||
condition={expandable}
|
||||
show={
|
||||
<p
|
||||
className={classnames(
|
||||
styles.headerValuesExpand,
|
||||
'valuesExpandLabel'
|
||||
)}
|
||||
>
|
||||
{!expanded
|
||||
? `View all (${constraint?.values?.length})`
|
||||
: 'View less'}
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,47 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import {Chip, styled, Typography} from '@mui/material';
|
||||
import {formatConstraintValue} from 'utils/formatConstraintValue';
|
||||
import {useStyles} from '../../PlaygroundConstraintAccordion.styles';
|
||||
import {useLocationSettings} from 'hooks/useLocationSettings';
|
||||
import {PlaygroundConstraintSchema} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import {ConditionallyRender} from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
|
||||
const StyledSingleValueChip = styled(Chip)(({ theme }) => ({
|
||||
margin: 'auto 0',
|
||||
[theme.breakpoints.down(710)]: {
|
||||
margin: theme.spacing(1, 0),
|
||||
},
|
||||
}));
|
||||
|
||||
interface ConstraintSingleValueProps {
|
||||
constraint: PlaygroundConstraintSchema;
|
||||
allowExpand: (shouldExpand: boolean) => void;
|
||||
}
|
||||
|
||||
export const PlaygroundConstraintAccordionViewHeaderSingleValue = ({
|
||||
constraint,
|
||||
allowExpand,
|
||||
}: ConstraintSingleValueProps) => {
|
||||
const { locationSettings } = useLocationSettings();
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
allowExpand(false);
|
||||
}, [allowExpand]);
|
||||
|
||||
return (
|
||||
<div className={styles.headerValuesContainerWrapper}>
|
||||
<ConditionallyRender
|
||||
condition={!Boolean(constraint.result)}
|
||||
show={
|
||||
<Typography variant={'body1'} color={'error'}>
|
||||
does not match any values{' '}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<StyledSingleValueChip
|
||||
label={formatConstraintValue(constraint, locationSettings)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,93 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
SxProps,
|
||||
Theme,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import { PlaygroundConstraintAccordionViewHeader } from './PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeader';
|
||||
import { oneOf } from 'utils/oneOf';
|
||||
import {
|
||||
dateOperators,
|
||||
numOperators,
|
||||
semVerOperators,
|
||||
} from 'constants/operators';
|
||||
import { useStyles } from './PlaygroundConstraintAccordion.styles';
|
||||
import {
|
||||
PlaygroundConstraintSchema,
|
||||
PlaygroundRequestSchema,
|
||||
} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import {
|
||||
ConstraintAccordionViewBody
|
||||
} from "component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewBody/ConstraintAccordionViewBody";
|
||||
|
||||
interface IConstraintAccordionViewProps {
|
||||
constraint: PlaygroundConstraintSchema;
|
||||
playgroundInput?: PlaygroundRequestSchema;
|
||||
maxLength?: number;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
|
||||
export const PlaygroundResultConstraintAccordionView = ({
|
||||
constraint,
|
||||
sx = undefined,
|
||||
maxLength,
|
||||
playgroundInput,
|
||||
}: IConstraintAccordionViewProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const [expandable, setExpandable] = useState(true);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const theme = useTheme();
|
||||
|
||||
const singleValue = oneOf(
|
||||
[...semVerOperators, ...numOperators, ...dateOperators],
|
||||
constraint.operator
|
||||
);
|
||||
const handleClick = () => {
|
||||
if (expandable) {
|
||||
setExpanded(!expanded);
|
||||
}
|
||||
};
|
||||
const backgroundColor = Boolean(playgroundInput)
|
||||
? !Boolean((constraint as PlaygroundConstraintSchema).result)
|
||||
? theme.palette.neutral.light
|
||||
: 'inherit'
|
||||
: 'inherit';
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
className={styles.accordion}
|
||||
classes={{ root: styles.accordionRoot }}
|
||||
expanded={expanded}
|
||||
sx={sx}
|
||||
>
|
||||
<AccordionSummary
|
||||
classes={{ root: styles.summary }}
|
||||
expandIcon={null}
|
||||
onClick={handleClick}
|
||||
sx={{
|
||||
cursor: expandable ? 'pointer' : 'default!important',
|
||||
'&:hover': {
|
||||
cursor: expandable ? 'pointer' : 'default!important',
|
||||
},
|
||||
backgroundColor: backgroundColor,
|
||||
}}
|
||||
>
|
||||
<PlaygroundConstraintAccordionViewHeader
|
||||
constraint={constraint}
|
||||
singleValue={singleValue}
|
||||
allowExpand={setExpandable}
|
||||
expanded={expanded}
|
||||
maxLength={maxLength ?? 112}
|
||||
playgroundInput={playgroundInput}
|
||||
/>
|
||||
</AccordionSummary>
|
||||
|
||||
<AccordionDetails className={styles.accordionDetails}>
|
||||
<ConstraintAccordionViewBody constraint={constraint} />
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
@ -3,11 +3,13 @@ import {
|
||||
PlaygroundRequestSchema,
|
||||
} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import React, { Fragment } from 'react';
|
||||
import { objectId } from '../../../../../../../../../utils/objectId';
|
||||
import { ConditionallyRender } from '../../../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from '../../../../../../../../common/StrategySeparator/StrategySeparator';
|
||||
import { ConstraintAccordionView } from '../../../../../../../../common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView';
|
||||
import { objectId } from '../../../../../../../../../../utils/objectId';
|
||||
import { ConditionallyRender } from '../../../../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from '../../../../../../../../../common/StrategySeparator/StrategySeparator';
|
||||
import { styled } from '@mui/material';
|
||||
import {
|
||||
PlaygroundResultConstraintAccordionView
|
||||
} from "./PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundResultConstraintAccordionView";
|
||||
|
||||
interface PlaygroundResultConstraintExecutionProps {
|
||||
constraints?: PlaygroundConstraintSchema[];
|
||||
@ -16,7 +18,7 @@ interface PlaygroundResultConstraintExecutionProps {
|
||||
}
|
||||
|
||||
export const PlaygroundResultConstraintExecutionWrapper = styled('div')(
|
||||
({ theme }) => ({
|
||||
() => ({
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@ -38,7 +40,7 @@ export const PlaygroundResultConstraintExecution = ({
|
||||
condition={index > 0}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
<ConstraintAccordionView
|
||||
<PlaygroundResultConstraintAccordionView
|
||||
constraint={constraint}
|
||||
playgroundInput={input}
|
||||
maxLength={compact ? 25 : 50}
|
@ -1,14 +1,14 @@
|
||||
import {
|
||||
PlaygroundSegmentSchema,
|
||||
PlaygroundRequestSchema,
|
||||
} from '../../../../../../../../../hooks/api/actions/usePlayground/playground.model';
|
||||
} from '../../../../../../../../../../hooks/api/actions/usePlayground/playground.model';
|
||||
import { PlaygroundResultConstraintExecution } from '../PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution';
|
||||
import { CancelOutlined, DonutLarge } from '@mui/icons-material';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { StrategySeparator } from '../../../../../../../../common/StrategySeparator/StrategySeparator';
|
||||
import { StrategySeparator } from '../../../../../../../../../common/StrategySeparator/StrategySeparator';
|
||||
import { useStyles } from './PlaygroundResultSegmentExecution.styles';
|
||||
import { styled, Typography } from '@mui/material';
|
||||
import { ConditionallyRender } from '../../../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||
import { ConditionallyRender } from '../../../../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||
|
||||
interface PlaygroundResultSegmentExecutionProps {
|
||||
segments?: PlaygroundSegmentSchema[];
|
||||
@ -43,7 +43,7 @@ const SegmentExecutionWrapper = styled('div')(({ theme }) => ({
|
||||
marginTop: theme.spacing(2),
|
||||
},
|
||||
background: theme.palette.neutral.light,
|
||||
marginBottom: '8px',
|
||||
marginBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const SegmentExecutionConstraintWrapper = styled('div')(({ theme }) => ({
|
||||
@ -55,7 +55,7 @@ const SegmentResultTextWrapper = styled('div')(({ theme }) => ({
|
||||
display: 'inline-flex',
|
||||
justifyContent: 'center',
|
||||
marginRight: '12px',
|
||||
gap: '8px',
|
||||
gap: theme.spacing(1),
|
||||
}));
|
||||
|
||||
export const PlaygroundResultSegmentExecution = ({
|
@ -1,24 +1,17 @@
|
||||
import { ConditionallyRender } from '../../../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from '../../../../../../../../common/StrategySeparator/StrategySeparator';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||
import { Box, Chip, styled } from '@mui/material';
|
||||
import { useStyles } from './PlaygroundResultStrategyExecution.styles';
|
||||
import {
|
||||
PlaygroundRequestSchema,
|
||||
PlaygroundStrategySchema,
|
||||
} from '../../../../../../../../../hooks/api/actions/usePlayground/playground.model';
|
||||
import useUiConfig from '../../../../../../../../../hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import React, { Fragment } from 'react';
|
||||
import { PlaygroundResultConstraintExecution } from '../PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution';
|
||||
import { PlaygroundResultSegmentExecution } from '../PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution';
|
||||
import {
|
||||
parseParameterNumber,
|
||||
parseParameterString,
|
||||
parseParameterStrings,
|
||||
} from '../../../../../../../../../utils/parseParameter';
|
||||
import PercentageCircle from '../../../../../../../../common/PercentageCircle/PercentageCircle';
|
||||
import StringTruncator from '../../../../../../../../common/StringTruncator/StringTruncator';
|
||||
import { useStrategies } from '../../../../../../../../../hooks/api/getters/useStrategies/useStrategies';
|
||||
import { PlaygroundConstraintItem } from '../PlaygroundConstraintItem/PlaygroundConstraintItem';
|
||||
} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import React from 'react';
|
||||
import { PlaygroundResultConstraintExecution } from './PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution';
|
||||
import { PlaygroundResultSegmentExecution } from './PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution';
|
||||
import { PlaygroundResultStrategyExecutionParameters } from './PlaygroundResultStrategyExecutionParameters/PlaygroundResultStrategyExecutionParameters';
|
||||
import { PlaygroundResultStrategyExecutionCustomStrategyParams } from './PlaygroundResultStrategyExecutionCustomStrategyParams./PlaygroundResultStrategyExecutionCustomStrategyParams';
|
||||
|
||||
interface PlaygroundResultStrategyExecutionProps {
|
||||
strategyResult: PlaygroundStrategySchema;
|
||||
@ -31,7 +24,7 @@ const StyledStrategyExecutionWrapper = styled('div')(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const StyledParamWrapper = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(2, 1),
|
||||
padding: theme.spacing(0, 0),
|
||||
}));
|
||||
|
||||
export const PlaygroundResultStrategyExecution = ({
|
||||
@ -39,7 +32,7 @@ export const PlaygroundResultStrategyExecution = ({
|
||||
input,
|
||||
}: PlaygroundResultStrategyExecutionProps) => {
|
||||
const { name, constraints, segments, parameters } = strategyResult;
|
||||
const { strategies } = useStrategies();
|
||||
|
||||
const { uiConfig } = useUiConfig();
|
||||
const { classes: styles } = useStyles();
|
||||
|
||||
@ -49,267 +42,6 @@ export const PlaygroundResultStrategyExecution = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const definition = strategies.find(strategyDefinition => {
|
||||
return strategyDefinition.name === strategyResult.name;
|
||||
});
|
||||
|
||||
const renderParameters = () => {
|
||||
return Object.keys(parameters).map(key => {
|
||||
switch (key) {
|
||||
case 'rollout':
|
||||
case 'Rollout':
|
||||
const percentage = parseParameterNumber(parameters[key]);
|
||||
return (
|
||||
<Box
|
||||
className={styles.summary}
|
||||
key={key}
|
||||
sx={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
<Box sx={{ mr: '1rem' }}>
|
||||
<PercentageCircle
|
||||
percentage={percentage}
|
||||
size="2rem"
|
||||
/>
|
||||
</Box>
|
||||
<div>
|
||||
<Chip
|
||||
color="success"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
label={`${percentage}%`}
|
||||
/>{' '}
|
||||
of your base{' '}
|
||||
{constraints.length > 0
|
||||
? 'who match constraints'
|
||||
: ''}{' '}
|
||||
is included.
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
case 'userIds':
|
||||
case 'UserIds':
|
||||
const users = parseParameterStrings(parameters[key]);
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={users}
|
||||
text="user"
|
||||
input={
|
||||
Boolean(input?.context?.[key])
|
||||
? input?.context?.[key]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[key])
|
||||
? !users.includes(input?.context?.[key])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'hostNames':
|
||||
case 'HostNames':
|
||||
const hosts = parseParameterStrings(parameters[key]);
|
||||
console.log(input?.context);
|
||||
console.log(key);
|
||||
console.log(input?.context?.[key]);
|
||||
console.log(hosts.includes(input?.context?.[key]));
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={hosts}
|
||||
text={'host'}
|
||||
input={
|
||||
Boolean(input?.context?.[key])
|
||||
? input?.context?.[key]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[key])
|
||||
? !hosts.includes(input?.context?.[key])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'IPs':
|
||||
const IPs = parseParameterStrings(parameters[key]);
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={IPs}
|
||||
text={'IP'}
|
||||
input={
|
||||
Boolean(input?.context?.[key])
|
||||
? input?.context?.[key]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[key])
|
||||
? !IPs.includes(input?.context?.[key])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'stickiness':
|
||||
case 'groupId':
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const renderCustomStrategyParameters = () => {
|
||||
if (!definition?.editable) return null;
|
||||
return definition?.parameters.map((param: any, index: number) => {
|
||||
const notLastItem = index !== definition?.parameters?.length - 1;
|
||||
switch (param?.type) {
|
||||
case 'list':
|
||||
const values = parseParameterStrings(
|
||||
strategyResult?.parameters[param.name]
|
||||
);
|
||||
return (
|
||||
<Fragment key={param?.name}>
|
||||
<PlaygroundConstraintItem
|
||||
value={values}
|
||||
text={param.name}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'percentage':
|
||||
return (
|
||||
<Fragment key={param?.name}>
|
||||
<div>
|
||||
<Chip
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="success"
|
||||
label={`${
|
||||
strategyResult?.parameters[param.name]
|
||||
}%`}
|
||||
/>{' '}
|
||||
of your base{' '}
|
||||
{constraints?.length > 0
|
||||
? 'who match constraints'
|
||||
: ''}{' '}
|
||||
is included.
|
||||
</div>
|
||||
<PercentageCircle
|
||||
percentage={parseParameterNumber(
|
||||
strategyResult.parameters[param.name]
|
||||
)}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'boolean':
|
||||
return (
|
||||
<Fragment key={param.name}>
|
||||
<p key={param.name}>
|
||||
<StringTruncator
|
||||
maxLength={15}
|
||||
maxWidth="150"
|
||||
text={param.name}
|
||||
/>{' '}
|
||||
{strategyResult.parameters[param.name]}
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
typeof strategyResult.parameters[
|
||||
param.name
|
||||
] !== 'undefined'
|
||||
}
|
||||
show={
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'string':
|
||||
const value = parseParameterString(
|
||||
strategyResult.parameters[param.name]
|
||||
);
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
typeof strategyResult.parameters[param.name] !==
|
||||
'undefined'
|
||||
}
|
||||
key={param.name}
|
||||
show={
|
||||
<>
|
||||
<p className={styles.valueContainer}>
|
||||
<StringTruncator
|
||||
maxWidth="150"
|
||||
maxLength={15}
|
||||
text={param.name}
|
||||
/>
|
||||
<span className={styles.valueSeparator}>
|
||||
is set to
|
||||
</span>
|
||||
<StringTruncator
|
||||
maxWidth="300"
|
||||
text={value}
|
||||
maxLength={50}
|
||||
/>
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'number':
|
||||
const number = parseParameterNumber(
|
||||
strategyResult.parameters[param.name]
|
||||
);
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={number !== undefined}
|
||||
key={param.name}
|
||||
show={
|
||||
<>
|
||||
<p className={styles.valueContainer}>
|
||||
<StringTruncator
|
||||
maxLength={15}
|
||||
maxWidth="150"
|
||||
text={param.name}
|
||||
/>
|
||||
<span className={styles.valueSeparator}>
|
||||
is set to
|
||||
</span>
|
||||
<StringTruncator
|
||||
maxWidth="300"
|
||||
text={String(number)}
|
||||
maxLength={50}
|
||||
/>
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'default':
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledStrategyExecutionWrapper>
|
||||
<ConditionallyRender
|
||||
@ -359,8 +91,18 @@ export const PlaygroundResultStrategyExecution = ({
|
||||
}
|
||||
/>
|
||||
<StyledParamWrapper>
|
||||
{renderParameters()}
|
||||
{renderCustomStrategyParameters()}
|
||||
<PlaygroundResultStrategyExecutionParameters
|
||||
parameters={parameters}
|
||||
constraints={constraints}
|
||||
input={input}
|
||||
/>
|
||||
<StyledParamWrapper sx={{ pt: 2}}>
|
||||
<PlaygroundResultStrategyExecutionCustomStrategyParams
|
||||
strategyName={strategyResult.name}
|
||||
parameters={parameters}
|
||||
constraints={constraints}
|
||||
/>
|
||||
</StyledParamWrapper>
|
||||
</StyledParamWrapper>
|
||||
</StyledStrategyExecutionWrapper>
|
||||
);
|
||||
|
@ -0,0 +1,181 @@
|
||||
import {
|
||||
parseParameterNumber,
|
||||
parseParameterString,
|
||||
parseParameterStrings,
|
||||
} from 'utils/parseParameter';
|
||||
import React, { Fragment } from 'react';
|
||||
import { PlaygroundConstraintItem } from '../PlaygroundConstraintItem/PlaygroundConstraintItem';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||
import { Chip } from '@mui/material';
|
||||
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
|
||||
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
||||
import { IStrategy } from 'interfaces/strategy';
|
||||
import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import { useStyles } from '../PlaygroundResultStrategyExecution.styles';
|
||||
import { useStrategies } from '../../../../../../../../../../hooks/api/getters/useStrategies/useStrategies';
|
||||
|
||||
interface PlaygroundResultStrategyExecutionCustomStrategyProps {
|
||||
parameters: { [key: string]: string };
|
||||
strategyName: string;
|
||||
constraints: PlaygroundConstraintSchema[];
|
||||
}
|
||||
|
||||
export const PlaygroundResultStrategyExecutionCustomStrategyParams = ({
|
||||
strategyName,
|
||||
constraints,
|
||||
parameters,
|
||||
}: PlaygroundResultStrategyExecutionCustomStrategyProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const { strategies } = useStrategies();
|
||||
|
||||
const definition = strategies.find(strategyDefinition => {
|
||||
return strategyDefinition.name === strategyName;
|
||||
});
|
||||
|
||||
const renderCustomStrategyParameters = () => {
|
||||
if (!definition?.editable) return null;
|
||||
return definition?.parameters.map((param: any, index: number) => {
|
||||
const notLastItem = index !== definition?.parameters?.length - 1;
|
||||
switch (param?.type) {
|
||||
case 'list':
|
||||
const values = parseParameterStrings(
|
||||
parameters[param.name]
|
||||
);
|
||||
return (
|
||||
<Fragment key={param?.name}>
|
||||
<PlaygroundConstraintItem
|
||||
value={values}
|
||||
text={param.name}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'percentage':
|
||||
return (
|
||||
<Fragment key={param?.name}>
|
||||
<div>
|
||||
<Chip
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="success"
|
||||
label={`${parameters[param.name]}%`}
|
||||
/>{' '}
|
||||
of your base{' '}
|
||||
{constraints?.length > 0
|
||||
? 'who match constraints'
|
||||
: ''}{' '}
|
||||
is included.
|
||||
</div>
|
||||
<PercentageCircle
|
||||
percentage={parseParameterNumber(
|
||||
parameters[param.name]
|
||||
)}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'boolean':
|
||||
return (
|
||||
<Fragment key={param.name}>
|
||||
<p key={param.name}>
|
||||
<StringTruncator
|
||||
maxLength={15}
|
||||
maxWidth="150"
|
||||
text={param.name}
|
||||
/>{' '}
|
||||
{parameters[param.name]}
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
typeof parameters[param.name] !==
|
||||
'undefined'
|
||||
}
|
||||
show={
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
case 'string':
|
||||
const value = parseParameterString(parameters[param.name]);
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={
|
||||
typeof parameters[param.name] !== 'undefined'
|
||||
}
|
||||
key={param.name}
|
||||
show={
|
||||
<>
|
||||
<p className={styles.valueContainer}>
|
||||
<StringTruncator
|
||||
maxWidth="150"
|
||||
maxLength={15}
|
||||
text={param.name}
|
||||
/>
|
||||
<span className={styles.valueSeparator}>
|
||||
is set to
|
||||
</span>
|
||||
<StringTruncator
|
||||
maxWidth="300"
|
||||
text={value}
|
||||
maxLength={50}
|
||||
/>
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'number':
|
||||
const number = parseParameterNumber(parameters[param.name]);
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={number !== undefined}
|
||||
key={param.name}
|
||||
show={
|
||||
<>
|
||||
<p className={styles.valueContainer}>
|
||||
<StringTruncator
|
||||
maxLength={15}
|
||||
maxWidth="150"
|
||||
text={param.name}
|
||||
/>
|
||||
<span className={styles.valueSeparator}>
|
||||
is set to
|
||||
</span>
|
||||
<StringTruncator
|
||||
maxWidth="300"
|
||||
text={String(number)}
|
||||
maxLength={50}
|
||||
/>
|
||||
</p>
|
||||
<ConditionallyRender
|
||||
condition={notLastItem}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'default':
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
return <>{renderCustomStrategyParameters()}</>;
|
||||
};
|
@ -0,0 +1,130 @@
|
||||
import {
|
||||
parseParameterNumber,
|
||||
parseParameterStrings,
|
||||
} from 'utils/parseParameter';
|
||||
import { Box, Chip } from '@mui/material';
|
||||
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
|
||||
import { PlaygroundConstraintItem } from '../PlaygroundConstraintItem/PlaygroundConstraintItem';
|
||||
import React from 'react';
|
||||
import { useStyles } from '../PlaygroundResultStrategyExecution.styles';
|
||||
import {
|
||||
PlaygroundConstraintSchema,
|
||||
PlaygroundRequestSchema,
|
||||
} from 'hooks/api/actions/usePlayground/playground.model';
|
||||
import {getMappedParam} from "../helepers";
|
||||
|
||||
export interface PlaygroundResultStrategyExecutionParametersProps {
|
||||
parameters: { [key: string]: string };
|
||||
constraints: PlaygroundConstraintSchema[];
|
||||
input?: PlaygroundRequestSchema;
|
||||
}
|
||||
|
||||
export const PlaygroundResultStrategyExecutionParameters = ({
|
||||
parameters,
|
||||
constraints,
|
||||
input,
|
||||
}: PlaygroundResultStrategyExecutionParametersProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const renderParameters = () => {
|
||||
return Object.keys(parameters).map(key => {
|
||||
switch (key) {
|
||||
case 'rollout':
|
||||
case 'Rollout':
|
||||
const percentage = parseParameterNumber(parameters[key]);
|
||||
return (
|
||||
<Box
|
||||
className={styles.summary}
|
||||
key={key}
|
||||
sx={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
<Box sx={{ mr: '1rem' }}>
|
||||
<PercentageCircle
|
||||
percentage={percentage}
|
||||
size="2rem"
|
||||
/>
|
||||
</Box>
|
||||
<div>
|
||||
<Chip
|
||||
color="success"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
label={`${percentage}%`}
|
||||
/>{' '}
|
||||
of your base{' '}
|
||||
{constraints.length > 0
|
||||
? 'who match constraints'
|
||||
: ''}{' '}
|
||||
is included.
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
case 'userIds':
|
||||
case 'UserIds':
|
||||
const users = parseParameterStrings(parameters[key]);
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={users}
|
||||
text="user"
|
||||
input={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? input?.context?.[getMappedParam(key)]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? !users.includes(input?.context?.[getMappedParam(key)])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'hostNames':
|
||||
case 'HostNames':
|
||||
const hosts = parseParameterStrings(parameters[key]);
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={hosts}
|
||||
text={'host'}
|
||||
input={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? input?.context?.[getMappedParam(key)]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? !hosts.includes(input?.context?.[getMappedParam(key)])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'IPs':
|
||||
const IPs = parseParameterStrings(parameters[key]);
|
||||
return (
|
||||
<PlaygroundConstraintItem
|
||||
key={key}
|
||||
value={IPs}
|
||||
text={'IP'}
|
||||
input={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? input?.context?.[getMappedParam(key)]
|
||||
: 'no value'
|
||||
}
|
||||
showReason={
|
||||
Boolean(input?.context?.[getMappedParam(key)])
|
||||
? !IPs.includes(input?.context?.[getMappedParam(key)])
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
case 'stickiness':
|
||||
case 'groupId':
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return <>{renderParameters()}</>;
|
||||
};
|
@ -0,0 +1,14 @@
|
||||
export const getMappedParam = (key: string) => {
|
||||
switch (key) {
|
||||
case 'userIds':
|
||||
case 'UserIds':
|
||||
return 'userId';
|
||||
case 'hostNames':
|
||||
case 'HostNames':
|
||||
return 'hostname';
|
||||
case 'IPs':
|
||||
return 'remoteAddress'
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}
|
@ -8,8 +8,8 @@ import { Alert, styled, Typography } from '@mui/material';
|
||||
import { PlaygroundResultFeatureStrategyItem } from './PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem';
|
||||
|
||||
const StyledAlertWrapper = styled('div')(({ theme }) => ({
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
padding: `0, 4px`,
|
||||
flexDirection: 'column',
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
border: `1px solid ${theme.palette.info.border}`,
|
||||
@ -70,10 +70,10 @@ export const WrappedPlaygroundResultStrategyList = ({
|
||||
input,
|
||||
}: WrappedPlaygroundResultStrategyListProps) => {
|
||||
return (
|
||||
<StyledAlertWrapper>
|
||||
<StyledAlertWrapper sx={{pb: 1}}>
|
||||
<StyledAlert severity={'info'} color={'info'}>
|
||||
If environment would be enabled then this feature would be{' '}
|
||||
{feature.isEnabled ? 'TRUE' : 'FALSE'} and the strategies would
|
||||
{feature.strategies.result ? 'TRUE' : 'FALSE'} and the strategies would
|
||||
evaluate like this:{' '}
|
||||
</StyledAlert>
|
||||
<StyledListWrapper>
|
||||
|
@ -3,7 +3,7 @@ import { Box, styled } from '@mui/material';
|
||||
import { PlaygroundResultChip } from '../PlaygroundResultChip/PlaygroundResultChip';
|
||||
|
||||
interface IFeatureStatusCellProps {
|
||||
enabled: boolean | 'unevaluated';
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
const StyledCellBox = styled(Box)(({ theme }) => ({
|
||||
@ -22,10 +22,7 @@ export const FeatureStatusCell = ({ enabled }: IFeatureStatusCellProps) => {
|
||||
<StyledChipWrapper data-loading>
|
||||
<PlaygroundResultChip
|
||||
enabled={enabled}
|
||||
label={
|
||||
enabled === 'unevaluated'
|
||||
? '?'
|
||||
: Boolean(enabled)
|
||||
label={enabled
|
||||
? 'True'
|
||||
: 'False'
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export interface PlaygroundConstraintSchema {
|
||||
*/
|
||||
operator: Operator;
|
||||
/**
|
||||
* Whether the operator should be case sensitive or not. Defaults to `false` (being case sensitive).
|
||||
* Whether the operator should be case-sensitive or not. Defaults to `false` (being case-sensitive).
|
||||
* @type {boolean}
|
||||
* @memberof PlaygroundConstraintSchema
|
||||
*/
|
||||
@ -64,7 +64,7 @@ export interface PlaygroundFeatureSchema {
|
||||
* @type {Array<PlaygroundStrategySchema>}
|
||||
* @memberof PlaygroundFeatureSchema
|
||||
*/
|
||||
strategies: Array<PlaygroundStrategySchema>;
|
||||
strategies: PlaygroundStrategyResultSchema;
|
||||
/**
|
||||
* Whether the feature is active and would be evaluated in the provided environment in a normal SDK context.
|
||||
* @type {boolean}
|
||||
@ -76,7 +76,7 @@ export interface PlaygroundFeatureSchema {
|
||||
* @type {boolean | 'unevaluated'}
|
||||
* @memberof PlaygroundFeatureSchema
|
||||
*/
|
||||
isEnabled: boolean | 'unevaluated';
|
||||
isEnabled: boolean;
|
||||
/**
|
||||
*
|
||||
* @type {PlaygroundFeatureSchemaVariant}
|
||||
@ -200,6 +200,11 @@ export interface PlaygroundSegmentSchema {
|
||||
constraints: Array<PlaygroundConstraintSchema>;
|
||||
}
|
||||
|
||||
export interface PlaygroundStrategyResultSchema {
|
||||
result: boolean | "unknown";
|
||||
data?: Array<PlaygroundStrategySchema>
|
||||
}
|
||||
|
||||
export interface PlaygroundStrategySchema {
|
||||
/**
|
||||
* The strategy's name.
|
||||
|
Loading…
Reference in New Issue
Block a user