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

feat: Playground environment diff table (#4002)

This commit is contained in:
Mateusz Kwasniewski 2023-06-19 11:44:32 +02:00 committed by GitHub
parent eb8f16da8d
commit 16a3f6069c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 192 additions and 7 deletions

View File

@ -24,7 +24,7 @@ import { AdvancedPlaygroundResponseSchema } from 'openapi';
export const AdvancedPlayground: VFC<{}> = () => {
const { environments: availableEnvironments } = useEnvironments();
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down('lg'));
const matches = true;
const [environments, setEnvironments] = useState<string[]>([]);
const [projects, setProjects] = useState<string[]>([]);

View File

@ -0,0 +1,76 @@
import { Link, Popover, styled, Typography, useTheme } from '@mui/material';
import { flexRow } from '../../../../../themes/themeStyles';
import React, { useState } from 'react';
import {
AdvancedPlaygroundEnvironmentFeatureSchema,
AdvancedPlaygroundFeatureSchemaEnvironments,
} from 'openapi';
import { PlaygroundEnvironmentTable } from '../../PlaygroundEnvironmentTable/PlaygroundEnvironmentTable';
import { PlaygroundEnvironmentDiffTable } from '../../PlaygroundEnvironmentTable/PlaygroundEnvironmentDiffTable';
const StyledContainer = styled(
'div',
{}
)(({ theme }) => ({
flexGrow: 0,
...flexRow,
justifyContent: 'flex-start',
margin: theme.spacing(0, 1.5),
}));
const StyledButton = styled(Link)(({ theme }) => ({
textAlign: 'left',
textDecorationStyle: 'dotted',
textUnderlineOffset: theme.spacing(0.75),
color: theme.palette.neutral.dark,
}));
export interface IAdvancedPlaygroundEnvironmentCellProps {
value: AdvancedPlaygroundFeatureSchemaEnvironments;
}
export const AdvancedPlaygroundEnvironmentDiffCell = ({
value,
}: IAdvancedPlaygroundEnvironmentCellProps) => {
const theme = useTheme();
const [anchor, setAnchorEl] = useState<null | Element>(null);
const onOpen = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) =>
setAnchorEl(event.currentTarget);
const onClose = () => setAnchorEl(null);
const open = Boolean(anchor);
return (
<StyledContainer>
<>
<StyledButton variant={'body2'} onClick={onOpen}>
Preview diff
</StyledButton>
<Popover
open={open}
id={`${value}-result-details`}
PaperProps={{
sx: {
borderRadius: `${theme.shape.borderRadiusLarge}px`,
padding: theme.spacing(3),
},
}}
onClose={onClose}
anchorEl={anchor}
anchorOrigin={{
vertical: 'bottom',
horizontal: -320,
}}
>
<Typography variant="subtitle2" sx={{ mb: 3 }}>
Environments diff
</Typography>
<PlaygroundEnvironmentDiffTable features={value} />
</Popover>
</>
</StyledContainer>
);
};

View File

@ -34,6 +34,7 @@ import {
AdvancedPlaygroundFeatureSchema,
} from 'openapi';
import { capitalizeFirst } from 'utils/capitalizeFirst';
import { AdvancedPlaygroundEnvironmentDiffCell } from './AdvancedPlaygroundEnvironmentCell/AdvancedPlaygroundEnvironmentDiffCell';
const defaultSort: SortingRule<string> = { id: 'name' };
const { value, setValue } = createLocalStorage(
@ -111,7 +112,9 @@ export const AdvancedPlaygroundResultsTable = ({
id: 'diff',
align: 'left',
Cell: ({ row }: any) => (
<StyledButton variant={'body2'}>Preview diff</StyledButton>
<AdvancedPlaygroundEnvironmentDiffCell
value={row.original.environments}
/>
),
},
];

View File

@ -0,0 +1,101 @@
import React, { useMemo, useRef } from 'react';
import {
useFlexLayout,
useGlobalFilter,
useSortBy,
useTable,
} from 'react-table';
import { VirtualizedTable } from 'component/common/Table';
import { sortTypes } from 'utils/sortTypes';
import { AdvancedPlaygroundFeatureSchemaEnvironments } from 'openapi';
import { Box } from '@mui/material';
import { FeatureStatusCell } from '../PlaygroundResultsTable/FeatureStatusCell/FeatureStatusCell';
import { HighlightCell } from '../../../common/Table/cells/HighlightCell/HighlightCell';
import { capitalizeFirst } from 'utils/capitalizeFirst';
interface IPlaygroundEnvironmentTableProps {
features: AdvancedPlaygroundFeatureSchemaEnvironments;
}
export const PlaygroundEnvironmentDiffTable = ({
features,
}: IPlaygroundEnvironmentTableProps) => {
const environments = Object.keys(features);
const firstEnvFeatures = features[environments[0]];
const firstContext = firstEnvFeatures[0].context;
const data = useMemo(
() =>
firstEnvFeatures.map((item, index) => ({
...Object.fromEntries(
environments.map(env => [env, features[env][index]])
),
})),
[JSON.stringify(features)]
);
type RowType = typeof data[0];
const contextFieldsHeaders = Object.keys(firstContext).map(
contextField => ({
Header: capitalizeFirst(contextField),
accessor: `${environments[0]}.context.${contextField}`,
minWidth: 160,
Cell: HighlightCell,
})
);
const environmentHeaders = environments.map(environment => ({
Header: environment,
accessor: (row: RowType) =>
row[environment]?.isEnabled
? 'true'
: row[environment]?.strategies?.result === 'unknown'
? 'unknown'
: 'false',
Cell: ({ row }: { row: { original: RowType } }) => {
return <FeatureStatusCell feature={row.original[environment]} />;
},
sortType: 'playgroundResultState',
maxWidth: 120,
}));
const COLUMNS = useMemo(() => {
return [...contextFieldsHeaders, ...environmentHeaders];
}, []);
const { headerGroups, rows, prepareRow } = useTable(
{
columns: COLUMNS as any[],
data,
sortTypes,
autoResetGlobalFilter: false,
autoResetHiddenColumns: false,
autoResetSortBy: false,
disableSortRemove: true,
disableMultiSort: true,
},
useGlobalFilter,
useFlexLayout,
useSortBy
);
const parentRef = useRef<HTMLElement | null>(null);
return (
<Box
ref={parentRef}
sx={{
overflow: 'auto',
maxHeight: '800px',
}}
>
<VirtualizedTable
parentRef={parentRef}
rows={rows}
headerGroups={headerGroups}
prepareRow={prepareRow}
/>
</Box>
);
};

View File

@ -42,5 +42,5 @@ test('should render environment table', async () => {
expect(screen.getByText('clientA')).toBeInTheDocument();
expect(screen.getByText('variantName')).toBeInTheDocument();
expect(screen.getByText('False')).toBeInTheDocument();
expect(screen.queryByText('myapp')).not.toBeInTheDocument();
expect(screen.getByText('myapp')).toBeInTheDocument();
});

View File

@ -30,14 +30,14 @@ export const PlaygroundEnvironmentTable = ({
const theme = useTheme();
const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
const dynamicHeaders = Object.keys(features[0].context)
.filter(contextField => contextField !== 'appName')
.map(contextField => ({
const dynamicHeaders = Object.keys(features[0].context).map(
contextField => ({
Header: capitalizeFirst(contextField),
accessor: `context.${contextField}`,
minWidth: 160,
Cell: HighlightCell,
}));
})
);
const COLUMNS = useMemo(() => {
return [
@ -108,6 +108,11 @@ export const PlaygroundEnvironmentTable = ({
columns: COLUMNS as any,
data: features,
sortTypes,
autoResetGlobalFilter: false,
autoResetHiddenColumns: false,
autoResetSortBy: false,
disableSortRemove: true,
disableMultiSort: true,
},
useGlobalFilter,
useFlexLayout,