1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-18 01:18:23 +02:00

Merge remote-tracking branch 'origin/task/Add_strategy_information_to_playground_results' into task/Add_strategy_information_to_playground_results

# Conflicts:
#	src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx
This commit is contained in:
andreas-unleash 2022-08-08 13:46:38 +03:00
commit 3b2947e9af
27 changed files with 303 additions and 296 deletions

View File

@ -26,6 +26,8 @@ export const useStyles = makeStyles()(theme => ({
actions: { actions: {
marginLeft: 'auto', marginLeft: 'auto',
display: 'flex', display: 'flex',
minHeight: theme.spacing(6),
alignItems: 'center',
}, },
resultChip: { resultChip: {
marginLeft: 'auto', marginLeft: 'auto',

View File

@ -0,0 +1,96 @@
import { DragEventHandler, FC, ReactNode } from 'react';
import { DragIndicator } from '@mui/icons-material';
import { styled, IconButton, Box } from '@mui/material';
import classNames from 'classnames';
import { IFeatureStrategy } from 'interfaces/strategy';
import {
getFeatureStrategyIcon,
formatStrategyName,
} from 'utils/strategyNames';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './StrategyItemContainer.styles';
interface IStrategyItemContainerProps {
strategy: IFeatureStrategy;
onDragStart?: DragEventHandler<HTMLButtonElement>;
onDragEnd?: DragEventHandler<HTMLButtonElement>;
actions?: ReactNode;
orderNumber?: number;
className?: string;
}
const DragIcon = styled(IconButton)(({ theme }) => ({
padding: 0,
cursor: 'inherit',
transition: 'color 0.2s ease-in-out',
}));
const StyledIndexLabel = styled('div')(({ theme }) => ({
fontSize: theme.typography.fontSize,
color: theme.palette.text.secondary,
position: 'absolute',
display: 'none',
right: 'calc(100% + 6px)',
top: theme.spacing(2.5),
[theme.breakpoints.up('md')]: {
display: 'block',
},
}));
export const StrategyItemContainer: FC<IStrategyItemContainerProps> = ({
strategy,
onDragStart,
onDragEnd,
actions,
children,
orderNumber,
className,
}) => {
const { classes: styles } = useStyles();
const Icon = getFeatureStrategyIcon(strategy.name);
return (
<Box sx={{ position: 'relative' }}>
<ConditionallyRender
condition={orderNumber !== undefined}
show={<StyledIndexLabel>{orderNumber}</StyledIndexLabel>}
/>
<Box className={classNames(styles.container, className)}>
<div
className={classNames(styles.header, {
[styles.headerDraggable]: Boolean(onDragStart),
})}
>
<ConditionallyRender
condition={Boolean(onDragStart)}
show={() => (
<DragIcon
draggable
disableRipple
size="small"
onDragStart={onDragStart}
onDragEnd={onDragEnd}
sx={{ cursor: 'move' }}
>
<DragIndicator
titleAccess="Drag to reorder"
cursor="grab"
sx={{ color: 'neutral.main' }}
/>
</DragIcon>
)}
/>
<Icon className={styles.icon} />
<StringTruncator
maxWidth="150"
maxLength={15}
text={formatStrategyName(strategy.name)}
/>
<div className={styles.actions}>{actions}</div>
</div>
<div className={styles.body}>{children}</div>
</Box>
</Box>
);
};

View File

@ -1,9 +1,9 @@
import { Box, styled } from '@mui/material'; import { DragEventHandler, RefObject, useRef } from 'react';
import { Box } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { IFeatureEnvironment } from 'interfaces/featureToggle'; import { IFeatureEnvironment } from 'interfaces/featureToggle';
import { IFeatureStrategy } from 'interfaces/strategy'; import { IFeatureStrategy } from 'interfaces/strategy';
import { DragEventHandler, RefObject, useRef } from 'react';
import { StrategyItem } from './StrategyItem/StrategyItem'; import { StrategyItem } from './StrategyItem/StrategyItem';
interface IStrategyDraggableItemProps { interface IStrategyDraggableItemProps {
@ -22,19 +22,6 @@ interface IStrategyDraggableItemProps {
) => DragEventHandler<HTMLDivElement>; ) => DragEventHandler<HTMLDivElement>;
onDragEnd: () => void; onDragEnd: () => void;
} }
const StyledIndexLabel = styled('div')(({ theme }) => ({
fontSize: theme.typography.fontSize,
color: theme.palette.text.secondary,
position: 'absolute',
display: 'none',
right: 'calc(100% + 6px)',
top: theme.spacing(2.5),
[theme.breakpoints.up('md')]: {
display: 'block',
},
}));
export const StrategyDraggableItem = ({ export const StrategyDraggableItem = ({
strategy, strategy,
index, index,
@ -58,16 +45,15 @@ export const StrategyDraggableItem = ({
condition={index > 0} condition={index > 0}
show={<StrategySeparator text="OR" />} show={<StrategySeparator text="OR" />}
/> />
<Box sx={{ position: 'relative' }}>
<StyledIndexLabel>{index + 1}</StyledIndexLabel>
<StrategyItem <StrategyItem
strategy={strategy} strategy={strategy}
environmentId={environmentName} environmentId={environmentName}
otherEnvironments={otherEnvironments} otherEnvironments={otherEnvironments}
onDragStart={onDragStartRef(ref, index)} onDragStart={onDragStartRef(ref, index)}
onDragEnd={onDragEnd} onDragEnd={onDragEnd}
orderNumber={index + 1}
/> />
</Box> </Box>
</Box>
); );
}; };

View File

@ -20,7 +20,6 @@ import StringTruncator from 'component/common/StringTruncator/StringTruncator';
interface IStrategyExecutionProps { interface IStrategyExecutionProps {
strategy: IFeatureStrategy; strategy: IFeatureStrategy;
percentageFill?: string;
} }
const NoItems: VFC = () => ( const NoItems: VFC = () => (

View File

@ -1,24 +1,17 @@
import { DragEventHandler } from 'react'; import { DragEventHandler, VFC } from 'react';
import { DragIndicator, Edit } from '@mui/icons-material'; import { Edit } from '@mui/icons-material';
import { styled, useTheme, IconButton } from '@mui/material';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { IFeatureEnvironment } from 'interfaces/featureToggle'; import { IFeatureEnvironment } from 'interfaces/featureToggle';
import { IFeatureStrategy } from 'interfaces/strategy'; import { IFeatureStrategy } from 'interfaces/strategy';
import {
getFeatureStrategyIcon,
formatStrategyName,
} from 'utils/strategyNames';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { UPDATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions'; import { UPDATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import { formatEditStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit'; import { formatEditStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
import { FeatureStrategyRemove } from 'component/feature/FeatureStrategy/FeatureStrategyRemove/FeatureStrategyRemove'; import { FeatureStrategyRemove } from 'component/feature/FeatureStrategy/FeatureStrategyRemove/FeatureStrategyRemove';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { StrategyExecution } from './StrategyExecution/StrategyExecution'; import { StrategyExecution } from './StrategyExecution/StrategyExecution';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu'; import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu';
import { useStyles } from './StrategyItem.styles'; import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
interface IStrategyItemProps { interface IStrategyItemProps {
environmentId: string; environmentId: string;
@ -26,26 +19,19 @@ interface IStrategyItemProps {
onDragStart?: DragEventHandler<HTMLButtonElement>; onDragStart?: DragEventHandler<HTMLButtonElement>;
onDragEnd?: DragEventHandler<HTMLButtonElement>; onDragEnd?: DragEventHandler<HTMLButtonElement>;
otherEnvironments?: IFeatureEnvironment['name'][]; otherEnvironments?: IFeatureEnvironment['name'][];
orderNumber?: number;
} }
const DragIcon = styled(IconButton)(({ theme }) => ({ export const StrategyItem: VFC<IStrategyItemProps> = ({
padding: 0,
cursor: 'inherit',
transition: 'color 0.2s ease-in-out',
}));
export const StrategyItem = ({
environmentId, environmentId,
strategy, strategy,
onDragStart, onDragStart,
onDragEnd, onDragEnd,
otherEnvironments, otherEnvironments,
}: IStrategyItemProps) => { orderNumber,
}) => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId'); const featureId = useRequiredPathParam('featureId');
const theme = useTheme();
const { classes: styles } = useStyles();
const Icon = getFeatureStrategyIcon(strategy.name);
const editStrategyPath = formatEditStrategyPath( const editStrategyPath = formatEditStrategyPath(
projectId, projectId,
@ -55,38 +41,13 @@ export const StrategyItem = ({
); );
return ( return (
<div className={styles.container}> <StrategyItemContainer
<div strategy={strategy}
className={classNames(styles.header, {
[styles.headerDraggable]: Boolean(onDragStart),
})}
>
<ConditionallyRender
condition={Boolean(onDragStart)}
show={() => (
<DragIcon
draggable
disableRipple
size="small"
onDragStart={onDragStart} onDragStart={onDragStart}
onDragEnd={onDragEnd} onDragEnd={onDragEnd}
sx={{ cursor: 'move' }} orderNumber={orderNumber}
> actions={
<DragIndicator <>
titleAccess="Drag to reorder"
cursor="grab"
sx={{ color: 'neutral.main' }}
/>
</DragIcon>
)}
/>
<Icon className={styles.icon} />
<StringTruncator
maxWidth="150"
maxLength={15}
text={formatStrategyName(strategy.name)}
/>
<div className={styles.actions}>
<ConditionallyRender <ConditionallyRender
condition={Boolean( condition={Boolean(
otherEnvironments && otherEnvironments?.length > 0 otherEnvironments && otherEnvironments?.length > 0
@ -115,14 +76,10 @@ export const StrategyItem = ({
strategyId={strategy.id} strategyId={strategy.id}
icon icon
/> />
</div> </>
</div> }
<div className={styles.body}> >
<StrategyExecution <StrategyExecution strategy={strategy} />
strategy={strategy} </StrategyItemContainer>
percentageFill={theme.palette.grey[200]}
/>
</div>
</div>
); );
}; };

View File

@ -4,11 +4,11 @@ export const useStyles = makeStyles()(theme => ({
popoverPaper: { popoverPaper: {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'flex-start',
padding: theme.spacing(6), padding: theme.spacing(6),
maxWidth: '728px', width: 728,
maxWidth: '100%',
height: 'auto', height: 'auto',
overflowY: 'scroll', overflowY: 'auto',
backgroundColor: theme.palette.tertiary.light, backgroundColor: theme.palette.tertiary.light,
}, },
})); }));

View File

@ -1,13 +1,10 @@
import { import { PlaygroundResultStrategyLists } from './PlaygroundResultStrategyList/playgroundResultStrategyLists';
PlaygroundResultStrategyLists, import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
WrappedPlaygroundResultStrategyList,
} from './PlaygroundResultStrategyList/playgroundResultStrategyLists';
import { ConditionallyRender } from '../../../../../common/ConditionallyRender/ConditionallyRender';
import React from 'react';
import { import {
PlaygroundFeatureSchema, PlaygroundFeatureSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
} from '../../../../../../hooks/api/actions/usePlayground/playground.model'; } from 'hooks/api/actions/usePlayground/playground.model';
import { Alert } from '@mui/material';
interface PlaygroundResultFeatureStrategyListProps { interface PlaygroundResultFeatureStrategyListProps {
feature: PlaygroundFeatureSchema; feature: PlaygroundFeatureSchema;
@ -19,24 +16,24 @@ export const PlaygroundResultFeatureStrategyList = ({
input, input,
}: PlaygroundResultFeatureStrategyListProps) => { }: PlaygroundResultFeatureStrategyListProps) => {
return ( return (
<>
<ConditionallyRender <ConditionallyRender
condition={ condition={
!feature.isEnabledInCurrentEnvironment && !feature.isEnabledInCurrentEnvironment &&
Boolean(feature?.strategies?.data) Boolean(feature?.strategies?.data)
} }
show={ show={
<WrappedPlaygroundResultStrategyList <Alert severity={'info'} color={'info'}>
strategies={feature?.strategies?.data!} If environment would be enabled then this feature would
feature={feature} be {feature.strategies?.result ? 'TRUE' : 'FALSE'} and
input={input} the strategies would evaluate like this:{' '}
/> </Alert>
} }
elseShow={ />
<PlaygroundResultStrategyLists <PlaygroundResultStrategyLists
strategies={feature?.strategies?.data!} strategies={feature?.strategies?.data || []}
input={input} input={input}
/> />
} </>
/>
); );
}; };

View File

@ -1,106 +0,0 @@
import { Box, styled, Typography, useTheme } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import {
formatStrategyName,
getFeatureStrategyIcon,
} from 'utils/strategyNames';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { PlaygroundResultChip } from '../../../../PlaygroundResultChip/PlaygroundResultChip';
import {
PlaygroundStrategySchema,
PlaygroundRequestSchema,
} from 'hooks/api/actions/usePlayground/playground.model';
import { PlaygroundResultStrategyExecution } from './PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution';
import { useStyles } from './PlaygroundResultFeatureStrategyItem.styles';
interface IPlaygroundResultFeatureStrategyItemProps {
strategy: PlaygroundStrategySchema;
index: number;
input?: PlaygroundRequestSchema;
compact: boolean;
}
const StyledItemWrapper = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
margin: theme.spacing(0.5, 0),
gap: theme.spacing(1),
}));
export const PlaygroundResultFeatureStrategyItem = ({
strategy,
input,
index,
compact,
}: IPlaygroundResultFeatureStrategyItemProps) => {
const { result, name } = strategy;
const { classes: styles } = useStyles();
const theme = useTheme();
const Icon = getFeatureStrategyIcon(strategy.name);
const label =
result.evaluationStatus === 'incomplete'
? 'Unevaluated'
: result.enabled
? 'True'
: 'False';
const border =
result.enabled && result.evaluationStatus === 'complete'
? `1px solid ${theme.palette.success.main}`
: `1px solid ${theme.palette.divider}`;
return (
<Box
sx={{
width: '100%',
position: 'relative',
paddingRight: compact ? '12px' : 0,
ml: '-12px',
}}
>
<ConditionallyRender
condition={index > 0}
show={<StrategySeparator text="OR" />}
/>
<StyledItemWrapper sx={{ mr: 3 }}>
<Typography
variant={'subtitle1'}
color={'text.secondary'}
sx={{ ml: 2 }}
>
{index + 1}
</Typography>
<Box className={styles.innerContainer} sx={{ border }}>
<div className={styles.header}>
<div className={styles.headerName}>
<Icon className={styles.icon} />
<StringTruncator
maxWidth="150"
maxLength={15}
text={formatStrategyName(name)}
/>
</div>
<PlaygroundResultChip
showIcon={false}
enabled={result.enabled}
label={label}
size={
result.evaluationStatus === 'incomplete'
? 'large'
: 'default'
}
/>
</div>
<div className={styles.body}>
<PlaygroundResultStrategyExecution
strategyResult={strategy}
input={input}
percentageFill={theme.palette.tertiary.light}
/>
</div>
</Box>
</StyledItemWrapper>
</Box>
);
};

View File

@ -34,4 +34,7 @@ export const useStyles = makeStyles()(theme => ({
borderRadius: theme.shape.borderRadiusMedium, borderRadius: theme.shape.borderRadiusMedium,
background: theme.palette.background.default, background: theme.palette.background.default,
}, },
successBorder: {
border: `1px solid ${theme.palette.success.main}`,
},
})); }));

View File

@ -0,0 +1,64 @@
import { useTheme } from '@mui/material';
import { PlaygroundResultChip } from '../../../../PlaygroundResultChip/PlaygroundResultChip';
import {
PlaygroundStrategySchema,
PlaygroundRequestSchema,
} from 'hooks/api/actions/usePlayground/playground.model';
import { StrategyExecution } from './StrategyExecution/StrategyExecution';
import { useStyles } from './FeatureStrategyItem.styles';
import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer';
import { objectId } from 'utils/objectId';
interface IFeatureStrategyItemProps {
strategy: PlaygroundStrategySchema;
index: number;
input?: PlaygroundRequestSchema;
compact: boolean;
}
export const FeatureStrategyItem = ({
strategy,
input,
index,
compact,
}: IFeatureStrategyItemProps) => {
const { result } = strategy;
const { classes: styles } = useStyles();
const theme = useTheme();
const label =
result.evaluationStatus === 'incomplete'
? 'Unevaluated'
: result.enabled
? 'True'
: 'False';
return (
<StrategyItemContainer
className={
result.enabled && result.evaluationStatus === 'complete'
? styles.successBorder
: undefined
}
strategy={{ ...strategy, id: `${objectId(strategy)}` }}
orderNumber={index + 1}
actions={
<PlaygroundResultChip
showIcon={false}
enabled={result.enabled}
label={label}
size={
result.evaluationStatus === 'incomplete'
? 'large'
: 'default'
}
/>
}
>
<StrategyExecution
strategyResult={strategy}
input={input}
percentageFill={theme.palette.tertiary.light}
/>
</StrategyItemContainer>
);
};

View File

@ -1,4 +1,4 @@
import { useState } from 'react'; import { useState, VFC } from 'react';
import { import {
Accordion, Accordion,
AccordionSummary, AccordionSummary,
@ -14,7 +14,7 @@ import {
numOperators, numOperators,
semVerOperators, semVerOperators,
} from 'constants/operators'; } from 'constants/operators';
import { useStyles } from './PlaygroundConstraintAccordion.styles'; import { useStyles } from './ConstraintAccordion.styles';
import { import {
PlaygroundConstraintSchema, PlaygroundConstraintSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
@ -28,12 +28,12 @@ interface IConstraintAccordionViewProps {
sx?: SxProps<Theme>; sx?: SxProps<Theme>;
} }
export const PlaygroundResultConstraintAccordionView = ({ export const ConstraintAccordionView: VFC<IConstraintAccordionViewProps> = ({
constraint, constraint,
sx = undefined, sx = undefined,
maxLength, maxLength,
playgroundInput, playgroundInput,
}: IConstraintAccordionViewProps) => { }) => {
const { classes: styles } = useStyles(); const { classes: styles } = useStyles();
const [expandable, setExpandable] = useState(true); const [expandable, setExpandable] = useState(true);
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);

View File

@ -3,7 +3,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { PlaygroundConstraintAccordionViewHeaderSingleValue } from './PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue'; import { PlaygroundConstraintAccordionViewHeaderSingleValue } from './PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue';
import { PLaygroundConstraintAccordionViewHeaderMultipleValues } from './PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues'; import { PLaygroundConstraintAccordionViewHeaderMultipleValues } from './PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues';
import React from 'react'; import React from 'react';
import { useStyles } from '../../PlaygroundConstraintAccordion.styles'; import { useStyles } from '../../ConstraintAccordion.styles';
import { CancelOutlined } from '@mui/icons-material'; import { CancelOutlined } from '@mui/icons-material';
import { import {
PlaygroundConstraintSchema, PlaygroundConstraintSchema,

View File

@ -2,7 +2,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { styled, Typography } from '@mui/material'; import { styled, Typography } from '@mui/material';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import { useStyles } from '../../../PlaygroundConstraintAccordion.styles'; import { useStyles } from '../../../ConstraintAccordion.styles';
import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model'; import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model';
const StyledValuesSpan = styled('span')(({ theme }) => ({ const StyledValuesSpan = styled('span')(({ theme }) => ({

View File

@ -1,7 +1,7 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Chip, styled, Typography } from '@mui/material'; import { Chip, styled, Typography } from '@mui/material';
import { formatConstraintValue } from 'utils/formatConstraintValue'; import { formatConstraintValue } from 'utils/formatConstraintValue';
import { useStyles } from '../../../PlaygroundConstraintAccordion.styles'; import { useStyles } from '../../../ConstraintAccordion.styles';
import { useLocationSettings } from 'hooks/useLocationSettings'; import { useLocationSettings } from 'hooks/useLocationSettings';
import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model'; import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';

View File

@ -1,42 +1,42 @@
import { Fragment, VFC } from 'react';
import { import {
PlaygroundConstraintSchema, PlaygroundConstraintSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
} from 'hooks/api/actions/usePlayground/playground.model'; } from 'hooks/api/actions/usePlayground/playground.model';
import React, { Fragment } from 'react'; import { objectId } from 'utils/objectId';
import { objectId } from '../../../../../../../../../../utils/objectId'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ConditionallyRender } from '../../../../../../../../../common/ConditionallyRender/ConditionallyRender'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { StrategySeparator } from '../../../../../../../../../common/StrategySeparator/StrategySeparator';
import { styled } from '@mui/material'; import { styled } from '@mui/material';
import { PlaygroundResultConstraintAccordionView } from './PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundResultConstraintAccordionView'; import { ConstraintAccordionView } from './ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView';
interface PlaygroundResultConstraintExecutionProps { interface IConstraintExecutionProps {
constraints?: PlaygroundConstraintSchema[]; constraints?: PlaygroundConstraintSchema[];
compact: boolean; compact: boolean;
input?: PlaygroundRequestSchema; input?: PlaygroundRequestSchema;
} }
export const PlaygroundResultConstraintExecutionWrapper = styled('div')(() => ({ export const ConstraintExecutionWrapper = styled('div')(() => ({
width: '100%', width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
})); }));
export const PlaygroundResultConstraintExecution = ({ export const ConstraintExecution: VFC<IConstraintExecutionProps> = ({
constraints, constraints,
compact, compact,
input, input,
}: PlaygroundResultConstraintExecutionProps) => { }) => {
if (!constraints) return null; if (!constraints) return null;
return ( return (
<PlaygroundResultConstraintExecutionWrapper> <ConstraintExecutionWrapper>
{constraints?.map((constraint, index) => ( {constraints?.map((constraint, index) => (
<Fragment key={objectId(constraint)}> <Fragment key={objectId(constraint)}>
<ConditionallyRender <ConditionallyRender
condition={index > 0 && constraints?.length > 1} condition={index > 0 && constraints?.length > 1}
show={<StrategySeparator text="AND" />} show={<StrategySeparator text="AND" />}
/> />
<PlaygroundResultConstraintAccordionView <ConstraintAccordionView
constraint={constraint} constraint={constraint}
playgroundInput={input} playgroundInput={input}
maxLength={compact ? 25 : 50} maxLength={compact ? 25 : 50}
@ -46,6 +46,6 @@ export const PlaygroundResultConstraintExecution = ({
/> />
</Fragment> </Fragment>
))} ))}
</PlaygroundResultConstraintExecutionWrapper> </ConstraintExecutionWrapper>
); );
}; };

View File

@ -1,10 +1,10 @@
import React, { Fragment, VFC } from 'react';
import { import {
parseParameterNumber, parseParameterNumber,
parseParameterString, parseParameterString,
parseParameterStrings, parseParameterStrings,
} from 'utils/parseParameter'; } from 'utils/parseParameter';
import React, { Fragment } from 'react'; import { PlaygroundParameterItem } from '../PlaygroundParameterItem/PlaygroundParameterItem';
import { PlaygroundParameterItem } from '../PlaygroundParamteterItem/PlaygroundParameterItem';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { Chip } from '@mui/material'; import { Chip } from '@mui/material';
@ -12,17 +12,17 @@ import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle
import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model'; import { PlaygroundConstraintSchema } from 'hooks/api/actions/usePlayground/playground.model';
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies'; import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
interface PlaygroundResultStrategyExecutionCustomStrategyProps { interface ICustomStrategyProps {
parameters: { [key: string]: string }; parameters: { [key: string]: string };
strategyName: string; strategyName: string;
constraints: PlaygroundConstraintSchema[]; constraints: PlaygroundConstraintSchema[];
} }
export const PlaygroundResultStrategyExecutionCustomStrategyParams = ({ export const CustomStrategyParams: VFC<ICustomStrategyProps> = ({
strategyName, strategyName,
constraints, constraints,
parameters, parameters,
}: PlaygroundResultStrategyExecutionCustomStrategyProps) => { }) => {
const { strategies } = useStrategies(); const { strategies } = useStrategies();
const definition = strategies.find(strategyDefinition => { const definition = strategies.find(strategyDefinition => {
return strategyDefinition.name === strategyName; return strategyDefinition.name === strategyName;

View File

@ -1,16 +1,17 @@
import { VFC } from 'react';
import { import {
PlaygroundSegmentSchema, PlaygroundSegmentSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
} from '../../../../../../../../../../hooks/api/actions/usePlayground/playground.model'; } from 'hooks/api/actions/usePlayground/playground.model';
import { PlaygroundResultConstraintExecution } from '../PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution'; import { ConstraintExecution } from '../ConstraintExecution/ConstraintExecution';
import { CancelOutlined, DonutLarge } from '@mui/icons-material'; import { CancelOutlined, DonutLarge } from '@mui/icons-material';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { StrategySeparator } from '../../../../../../../../../common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { useStyles } from './PlaygroundResultSegmentExecution.styles'; import { useStyles } from './SegmentExecution.styles';
import { styled, Typography } from '@mui/material'; import { styled, Typography } from '@mui/material';
import { ConditionallyRender } from '../../../../../../../../../common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
interface PlaygroundResultSegmentExecutionProps { interface ISegmentExecutionProps {
segments?: PlaygroundSegmentSchema[]; segments?: PlaygroundSegmentSchema[];
input?: PlaygroundRequestSchema; input?: PlaygroundRequestSchema;
hasConstraints: boolean; hasConstraints: boolean;
@ -58,11 +59,11 @@ const SegmentResultTextWrapper = styled('div')(({ theme }) => ({
gap: theme.spacing(1), gap: theme.spacing(1),
})); }));
export const PlaygroundResultSegmentExecution = ({ export const SegmentExecution: VFC<ISegmentExecutionProps> = ({
segments, segments,
input, input,
hasConstraints, hasConstraints,
}: PlaygroundResultSegmentExecutionProps) => { }) => {
const { classes: styles } = useStyles(); const { classes: styles } = useStyles();
if (!segments) return null; if (!segments) return null;
@ -99,7 +100,7 @@ export const PlaygroundResultSegmentExecution = ({
/> />
</SegmentExecutionHeader> </SegmentExecutionHeader>
<SegmentExecutionConstraintWrapper> <SegmentExecutionConstraintWrapper>
<PlaygroundResultConstraintExecution <ConstraintExecution
constraints={segment.constraints} constraints={segment.constraints}
input={input} input={input}
compact compact

View File

@ -1,19 +1,19 @@
import { VFC } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { Box, Chip, styled } from '@mui/material'; import { Box, Chip, styled } from '@mui/material';
import { useStyles } from './PlaygroundResultStrategyExecution.styles'; import { useStyles } from './StrategyExecution.styles';
import { import {
PlaygroundRequestSchema, PlaygroundRequestSchema,
PlaygroundStrategySchema, PlaygroundStrategySchema,
} from 'hooks/api/actions/usePlayground/playground.model'; } from 'hooks/api/actions/usePlayground/playground.model';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import React from 'react'; import { ConstraintExecution } from './ConstraintExecution/ConstraintExecution';
import { PlaygroundResultConstraintExecution } from './PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution'; import { SegmentExecution } from './SegmentExecution/SegmentExecution';
import { PlaygroundResultSegmentExecution } from './PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution'; import { PlaygroundResultStrategyExecutionParameters } from './StrategyExecutionParameters/StrategyExecutionParameters';
import { PlaygroundResultStrategyExecutionParameters } from './PlaygroundResultStrategyExecutionParameters/PlaygroundResultStrategyExecutionParameters'; import { CustomStrategyParams } from './CustomStrategyParams/CustomStrategyParams';
import { PlaygroundResultStrategyExecutionCustomStrategyParams } from './PlaygroundResultStrategyExecutionCustomStrategyParams/PlaygroundResultStrategyExecutionCustomStrategyParams';
interface PlaygroundResultStrategyExecutionProps { interface IStrategyExecutionProps {
strategyResult: PlaygroundStrategySchema; strategyResult: PlaygroundStrategySchema;
percentageFill?: string; percentageFill?: string;
input?: PlaygroundRequestSchema; input?: PlaygroundRequestSchema;
@ -27,10 +27,10 @@ const StyledParamWrapper = styled('div')(({ theme }) => ({
padding: theme.spacing(0, 0), padding: theme.spacing(0, 0),
})); }));
export const PlaygroundResultStrategyExecution = ({ export const StrategyExecution: VFC<IStrategyExecutionProps> = ({
strategyResult, strategyResult,
input, input,
}: PlaygroundResultStrategyExecutionProps) => { }) => {
const { name, constraints, segments, parameters } = strategyResult; const { name, constraints, segments, parameters } = strategyResult;
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
@ -51,7 +51,7 @@ export const PlaygroundResultStrategyExecution = ({
Boolean(segments && segments.length > 0) Boolean(segments && segments.length > 0)
} }
show={ show={
<PlaygroundResultSegmentExecution <SegmentExecution
segments={segments} segments={segments}
hasConstraints={hasConstraints} hasConstraints={hasConstraints}
input={input} input={input}
@ -62,7 +62,7 @@ export const PlaygroundResultStrategyExecution = ({
condition={Boolean(constraints && constraints.length > 0)} condition={Boolean(constraints && constraints.length > 0)}
show={ show={
<> <>
<PlaygroundResultConstraintExecution <ConstraintExecution
constraints={constraints} constraints={constraints}
compact={true} compact={true}
input={input} input={input}
@ -100,7 +100,7 @@ export const PlaygroundResultStrategyExecution = ({
input={input} input={input}
/> />
<StyledParamWrapper sx={{ pt: 2 }}> <StyledParamWrapper sx={{ pt: 2 }}>
<PlaygroundResultStrategyExecutionCustomStrategyParams <CustomStrategyParams
strategyName={strategyResult.name} strategyName={strategyResult.name}
parameters={parameters} parameters={parameters}
constraints={constraints} constraints={constraints}

View File

@ -4,9 +4,9 @@ import {
} from 'utils/parseParameter'; } from 'utils/parseParameter';
import { Box, Chip } from '@mui/material'; import { Box, Chip } from '@mui/material';
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle'; import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
import { PlaygroundParameterItem } from '../PlaygroundParamteterItem/PlaygroundParameterItem'; import { PlaygroundParameterItem } from '../PlaygroundParameterItem/PlaygroundParameterItem';
import React from 'react'; import React from 'react';
import { useStyles } from '../PlaygroundResultStrategyExecution.styles'; import { useStyles } from '../StrategyExecution.styles';
import { import {
PlaygroundConstraintSchema, PlaygroundConstraintSchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,

View File

@ -1,11 +1,13 @@
import { Fragment } from 'react';
import { Alert, Box, styled, Typography } from '@mui/material';
import { import {
PlaygroundFeatureSchema, PlaygroundFeatureSchema,
PlaygroundStrategySchema, PlaygroundStrategySchema,
PlaygroundRequestSchema, PlaygroundRequestSchema,
} from '../../../../../../../hooks/api/actions/usePlayground/playground.model'; } from 'hooks/api/actions/usePlayground/playground.model';
import { ConditionallyRender } from '../../../../../../common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Alert, styled, Typography } from '@mui/material'; import { FeatureStrategyItem } from './StrategyItem/FeatureStrategyItem';
import { PlaygroundResultFeatureStrategyItem } from './PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
const StyledAlertWrapper = styled('div')(({ theme }) => ({ const StyledAlertWrapper = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
@ -34,8 +36,7 @@ export const PlaygroundResultStrategyLists = ({
strategies, strategies,
input, input,
compact = false, compact = false,
}: PlaygroundResultStrategyListProps) => { }: PlaygroundResultStrategyListProps) => (
return (
<ConditionallyRender <ConditionallyRender
condition={strategies.length > 0} condition={strategies.length > 0}
show={ show={
@ -44,20 +45,27 @@ export const PlaygroundResultStrategyLists = ({
variant={'subtitle1'} variant={'subtitle1'}
sx={{ mt: 2, ml: 1, mb: 2, color: 'text.secondary' }} sx={{ mt: 2, ml: 1, mb: 2, color: 'text.secondary' }}
>{`Strategies (${strategies.length})`}</Typography> >{`Strategies (${strategies.length})`}</Typography>
<Box sx={{ width: '100%' }}>
{strategies.map((strategy, index) => ( {strategies.map((strategy, index) => (
<PlaygroundResultFeatureStrategyItem <Fragment key={strategy.id}>
<ConditionallyRender
condition={index > 0}
show={<StrategySeparator text="OR" />}
/>
<FeatureStrategyItem
key={strategy.id} key={strategy.id}
strategy={strategy} strategy={strategy}
index={index} index={index}
compact={compact} compact={compact}
input={input} input={input}
/> />
</Fragment>
))} ))}
</Box>
</> </>
} }
/> />
); );
};
interface WrappedPlaygroundResultStrategyListProps interface WrappedPlaygroundResultStrategyListProps
extends PlaygroundResultStrategyListProps { extends PlaygroundResultStrategyListProps {