From 9e38cf3ff9aac5e7d780314da460b36e22e53a64 Mon Sep 17 00:00:00 2001 From: andreas-unleash <104830839+andreas-unleash@users.noreply.github.com> Date: Fri, 29 Jul 2022 08:52:22 +0300 Subject: [PATCH] Playground result segments, constraints initial --- .../ConstraintAccordionView.tsx | 11 +- .../StrategySeparator/StrategySeparator.tsx | 7 +- .../FeatureResultInfoPopoverCell.styles.ts | 3 +- .../FeatureResultInfoPopoverCell.tsx | 36 +++--- .../PlaygroundResultConstraintExecution.tsx | 35 ++++++ .../PlaygroundResultFeatureStrategyItem.tsx | 14 +-- ...PlaygroundResultSegmentExecution.styles.ts | 12 ++ .../PlaygroundResultSegmentExecution.tsx | 103 ++++++++++++++++++ ...laygroundResultStrategyExecution.styles.ts | 18 +++ .../PlaygroundResultStrategyExecution.tsx | 61 +++++++++++ .../FeatureStatusCell/FeatureStatusCell.tsx | 6 +- .../PlaygroundResultsTable.tsx | 2 - 12 files changed, 275 insertions(+), 33 deletions(-) create mode 100644 frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx create mode 100644 frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.styles.ts create mode 100644 frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.tsx create mode 100644 frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.styles.ts create mode 100644 frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx diff --git a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx index d7df4b83d7..59130f58ae 100644 --- a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx +++ b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordionView/ConstraintAccordionView.tsx @@ -1,5 +1,11 @@ import { useState } from 'react'; -import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material'; +import { + Accordion, + AccordionSummary, + AccordionDetails, + SxProps, + Theme, +} from '@mui/material'; import { IConstraint } from 'interfaces/strategy'; import { ConstraintAccordionViewBody } from './ConstraintAccordionViewBody/ConstraintAccordionViewBody'; import { ConstraintAccordionViewHeader } from './ConstraintAccordionViewHeader/ConstraintAccordionViewHeader'; @@ -15,12 +21,14 @@ interface IConstraintAccordionViewProps { constraint: IConstraint; onDelete?: () => void; onEdit?: () => void; + sx?: SxProps; } export const ConstraintAccordionView = ({ constraint, onEdit, onDelete, + sx = undefined, }: IConstraintAccordionViewProps) => { const { classes: styles } = useStyles(); const [expandable, setExpandable] = useState(true); @@ -42,6 +50,7 @@ export const ConstraintAccordionView = ({ className={styles.accordion} classes={{ root: styles.accordionRoot }} expanded={expanded} + sx={sx} > ; } const StyledContainer = styled('div')(({ theme }) => ({ @@ -32,8 +33,8 @@ const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({ border: `1px solid ${theme.palette.primary.border}`, })); -export const StrategySeparator = ({ text }: IStrategySeparatorProps) => ( - +export const StrategySeparator = ({ text, sx }: IStrategySeparatorProps) => ( + {text}} diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.styles.ts index a702a2ddc6..12801e82b5 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.styles.ts +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.styles.ts @@ -9,6 +9,7 @@ export const useStyles = makeStyles()(theme => ({ gap: '24px', width: '728px', height: 'auto', - // overflowY: 'scroll', + overflowY: 'scroll', + backgroundColor: theme.palette.tertiary.light, }, })); diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx index 43c91711bc..52d9a2a02f 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell.tsx @@ -2,13 +2,10 @@ import { PlaygroundFeatureSchema, PlaygroundFeatureStrategyResult, } from '../../../../../hooks/api/actions/usePlayground/playground.model'; -import { Box, IconButton, Popover, Typography } from '@mui/material'; +import { IconButton, Popover, styled, Typography } from '@mui/material'; import { InfoOutlined } from '@mui/icons-material'; -import { IconCell } from '../../../../common/Table/cells/IconCell/IconCell'; import React, { useRef, useState } from 'react'; import { ConditionallyRender } from '../../../../common/ConditionallyRender/ConditionallyRender'; -import { StrategyDraggableItem } from '../../../../feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem'; -import { FeatureStrategyEmpty } from '../../../../feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty'; import { PlaygroundResultFeatureStrategyItem } from './PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem'; import { useStyles } from './FeatureResultInfoPopoverCell.styles'; import { PlaygroundResultFeatureDetails } from './PlaygroundResultFeatureDetails/PlaygroundResultFeatureDetails'; @@ -17,12 +14,14 @@ interface FeatureResultInfoPopoverCellProps { feature?: PlaygroundFeatureSchema; } +const FeatureResultPopoverWrapper = styled('div')(({ theme }) => ({ + alignItems: 'flex-end', + color: theme.palette.tertiary.main, +})); + export const FeatureResultInfoPopoverCell = ({ feature, }: FeatureResultInfoPopoverCellProps) => { - if (!feature) { - return null; - } const [open, setOpen] = useState(false); const { classes: styles } = useStyles(); const ref = useRef(null); @@ -36,7 +35,7 @@ export const FeatureResultInfoPopoverCell = ({ name: 'default', id: 'strategy-id', parameters: {}, - result: false, + result: true, constraints: [ { result: false, @@ -44,7 +43,12 @@ export const FeatureResultInfoPopoverCell = ({ operator: 'IN', caseInsensitive: true, inverted: false, - values: ['a', 'b'], + values: [ + 'a', + 'b', + 'sdlghigoiahr;g', + 'WOGIHwegoihwlwEGHLwgklWEGK;L', + ], }, ], segments: [ @@ -55,9 +59,9 @@ export const FeatureResultInfoPopoverCell = ({ constraints: [ { result: false, - contextName: 'appName', + contextName: 'environment', operator: 'IN', - caseInsensitive: true, + caseInsensitive: false, inverted: false, values: ['a', 'b'], }, @@ -67,8 +71,12 @@ export const FeatureResultInfoPopoverCell = ({ }, ]; + if (!feature) { + return null; + } + return ( - <> + @@ -92,7 +100,7 @@ export const FeatureResultInfoPopoverCell = ({ show={ <> {`Strategies (${strategies.length})`} {strategies.map((strategy, index) => ( - + ); }; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx new file mode 100644 index 0000000000..a68ab63404 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultConstraintExecution/PlaygroundResultConstraintExecution.tsx @@ -0,0 +1,35 @@ +import { PlaygroundFeatureStrategyConstraintResult } 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'; + +interface PlaygroundResultConstraintExecutionProps { + constraints?: PlaygroundFeatureStrategyConstraintResult[]; +} + +export const PlaygroundResultConstraintExecution = ({ + constraints, +}: PlaygroundResultConstraintExecutionProps) => { + if (!constraints) return null; + + return ( + <> + {constraints?.map((constraint, index) => ( + + 0} + show={} + /> + + + ))} + + ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx index 0ef0890ca9..aa86ffea67 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultFeatureStrategyItem/PlaygroundResultFeatureStrategyItem.tsx @@ -8,8 +8,8 @@ import { } from '../../../../../../utils/strategyNames'; import StringTruncator from '../../../../../common/StringTruncator/StringTruncator'; import { PlaygroundResultChip } from '../../PlaygroundResultChip/PlaygroundResultChip'; -import { StrategyExecution } from '../../../../../feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution'; import { PlaygroundFeatureStrategyResult } from 'hooks/api/actions/usePlayground/playground.model'; +import { PlaygroundResultStrategyExecution } from '../PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution'; interface IPlaygroundResultFeatureStrategyItemProps { strategy: PlaygroundFeatureStrategyResult; @@ -31,14 +31,14 @@ export const PlaygroundResultFeatureStrategyItem = ({ strategy, index, }: IPlaygroundResultFeatureStrategyItemProps) => { - const { result } = strategy; + const { result, name } = strategy; const { classes: styles } = useStyles(); const theme = useTheme(); const Icon = getFeatureStrategyIcon(strategy.name); const label = result === undefined ? 'Not found' : result ? 'True' : 'False'; const border = Boolean(result) - ? `2px solid ${theme.palette.success.main}` + ? `1px solid ${theme.palette.success.main}` : `1px solid ${theme.palette.divider}`; return ( @@ -54,7 +54,7 @@ export const PlaygroundResultFeatureStrategyItem = ({
-
diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.styles.ts new file mode 100644 index 0000000000..10b1dc7733 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.styles.ts @@ -0,0 +1,12 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useStyles = makeStyles()(theme => ({ + container: {}, + link: { + textDecoration: 'none', + marginLeft: theme.spacing(1), + '&:hover': { + textDecoration: 'underline', + }, + }, +})); diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.tsx new file mode 100644 index 0000000000..c20fa7ffe4 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultSegmentExecution/PlaygroundResultSegmentExecution.tsx @@ -0,0 +1,103 @@ +import { PlaygroundFeatureStrategySegmentResult } 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 { useStyles } from './PlaygroundResultSegmentExecution.styles'; +import { styled, Typography } from '@mui/material'; +import { ConditionallyRender } from '../../../../../common/ConditionallyRender/ConditionallyRender'; + +interface PlaygroundResultSegmentExecutionProps { + segments?: PlaygroundFeatureStrategySegmentResult[]; +} + +const SegmentExecutionLinkWrapper = styled('div')(({ theme }) => ({ + padding: theme.spacing(2, 3), + display: 'flex', + alignItems: 'center', + justifyContent: 'flex-start', + fontSize: theme.fontSizes.smallBody, + position: 'relative', +})); + +const SegmentExecutionHeader = styled('div')(({ theme }) => ({ + width: '100%', + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'space-between', + '& + &': { + margin: theme.spacing(2), + }, +})); + +const SegmentExecutionWrapper = styled('div')(({ theme }) => ({ + flexDirection: 'column', + borderRadius: theme.shape.borderRadiusMedium, + border: `1px solid ${theme.palette.dividerAlternative}`, + '& + &': { + marginTop: theme.spacing(2), + }, + background: theme.palette.neutral.light, + marginBottom: '8px', +})); + +const SegmentExecutionConstraintWrapper = styled('div')(({ theme }) => ({ + padding: '12px', +})); + +const SegmentResultTextWrapper = styled('div')(({ theme }) => ({ + color: theme.palette.error.main, + display: 'inline-flex', + justifyContent: 'center', + marginRight: '12px', + gap: '8px', +})); + +export const PlaygroundResultSegmentExecution = ({ + segments, +}: PlaygroundResultSegmentExecutionProps) => { + const { classes: styles } = useStyles(); + if (!segments) return null; + return ( + <> + {segments.map(segment => ( + + + + {' '} + Segment:{' '} + + {segment.name} + + + + + segment is false + + + + + + } + /> + + + + + + + ))} + + ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.styles.ts b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.styles.ts new file mode 100644 index 0000000000..e2d49389e1 --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.styles.ts @@ -0,0 +1,18 @@ +import { makeStyles } from 'tss-react/mui'; + +export const useStyles = makeStyles()(theme => ({ + valueContainer: { + display: 'flex', + alignItems: 'center', + gap: '1ch', + }, + valueSeparator: { + color: theme.palette.grey[700], + }, + summary: { + width: '100%', + padding: theme.spacing(2, 3), + borderRadius: theme.shape.borderRadius, + border: `1px solid ${theme.palette.divider}`, + }, +})); diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx new file mode 100644 index 0000000000..385ca77c4f --- /dev/null +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureResultInfoPopoverCell/PlaygroundResultStrategyExecution/PlaygroundResultStrategyExecution.tsx @@ -0,0 +1,61 @@ +import { ConditionallyRender } from '../../../../../common/ConditionallyRender/ConditionallyRender'; +import { StrategySeparator } from '../../../../../common/StrategySeparator/StrategySeparator'; +import { Box, Chip } from '@mui/material'; +import { useStyles } from './PlaygroundResultStrategyExecution.styles'; +import { PlaygroundFeatureStrategyResult } 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'; + +interface PlaygroundResultStrategyExecutionProps { + strategyResult: PlaygroundFeatureStrategyResult; + percentageFill?: string; +} + +export const PlaygroundResultStrategyExecution = ({ + strategyResult, +}: PlaygroundResultStrategyExecutionProps) => { + const { name, constraints, segments } = strategyResult; + + const { uiConfig } = useUiConfig(); + const { classes: styles } = useStyles(); + + return ( + <> + 0) + } + show={} + /> + 0)} + show={ + <> + + + + } + /> + + The standard strategy is{' '} + {' '} + for all users. + + } + /> + + ); +}; diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx index 4ff8a5a598..42a667da22 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell.tsx @@ -1,9 +1,5 @@ import React from 'react'; -import { colors } from 'themes/colors'; -import { ReactComponent as FeatureEnabledIcon } from 'assets/icons/isenabled-true.svg'; -import { ReactComponent as FeatureDisabledIcon } from 'assets/icons/isenabled-false.svg'; -import { Box, Chip, styled, useTheme } from '@mui/material'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { Box, styled } from '@mui/material'; import { PlaygroundResultChip } from '../PlaygroundResultChip/PlaygroundResultChip'; interface IFeatureStatusCellProps { diff --git a/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultsTable.tsx b/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultsTable.tsx index 5337251325..0dda1a42b5 100644 --- a/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultsTable.tsx +++ b/frontend/src/component/playground/Playground/PlaygroundResultsTable/PlaygroundResultsTable.tsx @@ -23,8 +23,6 @@ import { PlaygroundFeatureSchema } from 'hooks/api/actions/usePlayground/playgro import { Box, Typography, useMediaQuery, useTheme } from '@mui/material'; import useLoading from 'hooks/useLoading'; import { VariantCell } from './VariantCell/VariantCell'; -import { IconCell } from '../../../common/Table/cells/IconCell/IconCell'; -import { InfoOutlined } from '@mui/icons-material'; import { FeatureResultInfoPopoverCell } from './FeatureResultInfoPopoverCell/FeatureResultInfoPopoverCell'; const defaultSort: SortingRule = { id: 'name' };