diff --git a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx index 3345e0ece9..5d1e457159 100644 --- a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx +++ b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx @@ -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; } @@ -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 ( diff --git a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx index 0b1cd2b6bd..897304438d 100644 --- a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx +++ b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionViewHeader/ConstraintAccordionViewHeader.tsx @@ -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} /> ({ 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 ( @@ -69,23 +57,6 @@ export const ConstraintAccordionViewHeaderInfo = ({ {constraint.contextName} - - {playgroundInput?.context[ - constraint.contextName - ] || 'no value'} - - } - /> @@ -107,10 +78,6 @@ export const ConstraintAccordionViewHeaderInfo = ({ } /> - } - /> ); }; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx index 82739bda37..84bb71ee26 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx @@ -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); }; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.styles.ts index c1dbc23cf6..bb59b48574 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.styles.ts +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.styles.ts @@ -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), }, diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.tsx index d571461bfa..98a5d45278 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails.tsx @@ -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 = ({ { return ( } elseShow={ } diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx index 03c0da7d14..4776a8b5ee 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx @@ -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={} /> - - + + {index + 1} diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundConstraintItem/PlaygroundConstraintItem.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundConstraintItem/PlaygroundConstraintItem.styles.ts similarity index 100% rename from frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundConstraintItem/PlaygroundConstraintItem.styles.ts rename to frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundConstraintItem/PlaygroundConstraintItem.styles.ts diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundConstraintItem/PlaygroundConstraintItem.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundConstraintItem/PlaygroundConstraintItem.tsx similarity index 100% rename from frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundConstraintItem/PlaygroundConstraintItem.tsx rename to frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundConstraintItem/PlaygroundConstraintItem.tsx diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordion.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordion.styles.ts new file mode 100644 index 0000000000..bceadae3df --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordion.styles.ts @@ -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%' }, +})); diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeader.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeader.tsx new file mode 100644 index 0000000000..85d40bf5a6 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeader.tsx @@ -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 ( +
+ + +
+ ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeaderInfo/PlaygroundConstraintAccordionViewHeaderInfo.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeaderInfo/PlaygroundConstraintAccordionViewHeaderInfo.tsx new file mode 100644 index 0000000000..a36adfc171 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundConstraintAccordionViewHeaderInfo/PlaygroundConstraintAccordionViewHeaderInfo.tsx @@ -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 ( + +
+ + + {constraint.contextName} + + {playgroundInput?.context[ + constraint.contextName + ] || 'no value'} + + + + + + } + elseShow={ + + } + /> +
+ } + /> +
+ ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues.tsx new file mode 100644 index 0000000000..adeca0b91e --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderMultipleValues/PLaygroundConstraintAccordionViewHeaderMultipleValues.tsx @@ -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 ( +
+
+ + does not match any values{' '} + + } + /> + {text} + + {!expanded + ? `View all (${constraint?.values?.length})` + : 'View less'} +

+ } + /> +
+
+ ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue.tsx new file mode 100644 index 0000000000..9d7ac3b66e --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundConstraintAccordionViewHeader/PlaygroundContraintAccordionViewHeaderSingleValue/PlaygroundConstraintAccordionViewHeaderSingleValue.tsx @@ -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 ( +
+ + does not match any values{' '} + + } + /> + +
+ ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundResultConstraintAccordionView.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundResultConstraintAccordionView.tsx new file mode 100644 index 0000000000..95f2f516f6 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintAccordion/PlaygroundResultConstraintAccordionView/PlaygroundResultConstraintAccordionView.tsx @@ -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; +} + +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 ( + + + + + + + + + + ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx similarity index 72% rename from frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx rename to frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx index 888ac22e9c..d5f3c6d7b1 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx @@ -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={} /> - ({ 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 = ({ diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx index 4d111e1479..1ebb66b8e4 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx @@ -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 ( - - - - -
- {' '} - of your base{' '} - {constraints.length > 0 - ? 'who match constraints' - : ''}{' '} - is included. -
-
- ); - case 'userIds': - case 'UserIds': - const users = parseParameterStrings(parameters[key]); - return ( - - ); - 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 ( - - ); - case 'IPs': - const IPs = parseParameterStrings(parameters[key]); - return ( - - ); - 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 ( - - - } - /> - - ); - case 'percentage': - return ( - -
- {' '} - of your base{' '} - {constraints?.length > 0 - ? 'who match constraints' - : ''}{' '} - is included. -
- - } - /> -
- ); - case 'boolean': - return ( - -

- {' '} - {strategyResult.parameters[param.name]} -

- } - /> - } - /> -
- ); - case 'string': - const value = parseParameterString( - strategyResult.parameters[param.name] - ); - return ( - -

- - - is set to - - -

- } - /> - - } - /> - ); - case 'number': - const number = parseParameterNumber( - strategyResult.parameters[param.name] - ); - return ( - -

- - - is set to - - -

- } - /> - - } - /> - ); - case 'default': - return null; - } - return null; - }); - }; - return ( - {renderParameters()} - {renderCustomStrategyParameters()} + + + + ); diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionCustomStrategyParams./PlaygroundResultStrategyExecutionCustomStrategyParams.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionCustomStrategyParams./PlaygroundResultStrategyExecutionCustomStrategyParams.tsx new file mode 100644 index 0000000000..9520117a4d --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionCustomStrategyParams./PlaygroundResultStrategyExecutionCustomStrategyParams.tsx @@ -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 ( + + + } + /> + + ); + case 'percentage': + return ( + +
+ {' '} + of your base{' '} + {constraints?.length > 0 + ? 'who match constraints' + : ''}{' '} + is included. +
+ + } + /> +
+ ); + case 'boolean': + return ( + +

+ {' '} + {parameters[param.name]} +

+ } + /> + } + /> +
+ ); + case 'string': + const value = parseParameterString(parameters[param.name]); + return ( + +

+ + + is set to + + +

+ } + /> + + } + /> + ); + case 'number': + const number = parseParameterNumber(parameters[param.name]); + return ( + +

+ + + is set to + + +

+ } + /> + + } + /> + ); + case 'default': + return null; + } + return null; + }); + }; + + return <>{renderCustomStrategyParameters()}; +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionParameters/PlaygroundResultStrategyExecutionParameters.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionParameters/PlaygroundResultStrategyExecutionParameters.tsx new file mode 100644 index 0000000000..f31501b9aa --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecutionParameters/PlaygroundResultStrategyExecutionParameters.tsx @@ -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 ( + + + + +
+ {' '} + of your base{' '} + {constraints.length > 0 + ? 'who match constraints' + : ''}{' '} + is included. +
+
+ ); + case 'userIds': + case 'UserIds': + const users = parseParameterStrings(parameters[key]); + return ( + + ); + case 'hostNames': + case 'HostNames': + const hosts = parseParameterStrings(parameters[key]); + return ( + + ); + case 'IPs': + const IPs = parseParameterStrings(parameters[key]); + return ( + + ); + case 'stickiness': + case 'groupId': + return null; + default: + return null; + } + }); + }; + + return <>{renderParameters()}; +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/helepers.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/helepers.ts new file mode 100644 index 0000000000..862e7178ba --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/PlaygroundResultFeatureStrategyItem/PlaygroundResultStrategyExecution/helepers.ts @@ -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; + } +} diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/playgroundResultStrategyLists.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/playgroundResultStrategyLists.tsx index 60c62e10c1..c5eea38425 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/playgroundResultStrategyLists.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyList/PlaygroundResultStrategyList/playgroundResultStrategyLists.tsx @@ -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 ( - + 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:{' '} diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx index 31cb8d7f35..2296124420 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx @@ -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) => { } * @memberof PlaygroundFeatureSchema */ - strategies: Array; + 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; } +export interface PlaygroundStrategyResultSchema { + result: boolean | "unknown"; + data?: Array +} + export interface PlaygroundStrategySchema { /** * The strategy's name.