1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

feat: add UI to variant metrics (#3697)

This commit is contained in:
Jaanus Sellin 2023-05-08 13:15:26 +03:00 committed by GitHub
parent 6053963750
commit bacb73667a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 50 additions and 19 deletions

View File

@ -7,7 +7,6 @@ import { Badge } from 'component/common/Badge/Badge';
import { GroupCardActions } from './GroupCardActions/GroupCardActions';
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
import { IProjectRole } from 'interfaces/role';
import { IProject } from 'interfaces/project';
const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',

View File

@ -34,7 +34,6 @@ import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/Archiv
import { IFeatureToggle } from 'interfaces/featureToggle';
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
import { RowSelectCell } from '../../project/Project/ProjectFeatureToggles/RowSelectCell/RowSelectCell';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { BatchSelectionActionsBar } from '../../common/BatchSelectionActionsBar/BatchSelectionActionsBar';
import { ArchiveBatchActions } from './ArchiveBatchActions';
@ -64,7 +63,6 @@ export const ArchiveTable = ({
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
const { setToastData, setToastApiError } = useToast();
const { uiConfig } = useUiConfig();
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [deletedFeature, setDeletedFeature] = useState<IFeatureToggle>();

View File

@ -5,7 +5,6 @@ import Input from 'component/common/Input/Input';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
interface IArchivedFeatureDeleteConfirmProps {
deletedFeatures: string[];
@ -35,8 +34,7 @@ export const ArchivedFeatureDeleteConfirm = ({
}: IArchivedFeatureDeleteConfirmProps) => {
const [confirmName, setConfirmName] = useState('');
const { setToastData, setToastApiError } = useToast();
const { deleteFeature, deleteFeatures } = useProjectApi();
const { uiConfig } = useUiConfig();
const { deleteFeatures } = useProjectApi();
const onDeleteFeatureToggle = async () => {
try {

View File

@ -13,9 +13,7 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
import { changesCount } from '../../../changesCount';
import {
Box,
IconButton,
Link,
ListItemIcon,
ListItemText,
MenuItem,
@ -25,7 +23,7 @@ import {
Tooltip,
Typography,
} from '@mui/material';
import { Delete, Edit, GroupRounded, MoreVert } from '@mui/icons-material';
import { Delete, Edit, MoreVert } from '@mui/icons-material';
import { EditChange } from './EditChange';
const useShowActions = (changeRequest: IChangeRequest, change: IChange) => {

View File

@ -1,7 +1,6 @@
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { Link, styled, Typography } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import { useTheme } from '@mui/system';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
interface IChangeRequestTitleCellProps {

View File

@ -4,9 +4,10 @@ import { ILocationSettings } from 'hooks/useLocationSettings';
import 'chartjs-adapter-date-fns';
import { Theme } from '@mui/material/styles/createTheme';
interface IPoint {
export interface IPoint {
x: string;
y: number;
variants: Record<string, number>;
}
export const createChartData = (
@ -15,7 +16,7 @@ export const createChartData = (
locationSettings: ILocationSettings
): ChartData<'line', IPoint[], string> => {
const requestsSeries = {
label: 'total requests',
label: 'Total requests',
borderColor: theme.palette.primary.main,
backgroundColor: theme.palette.primary.main,
data: createChartPoints(metrics, locationSettings, m => m.yes + m.no),
@ -31,7 +32,7 @@ export const createChartData = (
};
const yesSeries = {
label: 'exposed',
label: 'Exposed',
borderColor: theme.palette.success.main,
backgroundColor: theme.palette.success.main,
data: createChartPoints(metrics, locationSettings, m => m.yes),
@ -44,7 +45,7 @@ export const createChartData = (
};
const noSeries = {
label: 'not exposed',
label: 'Not exposed',
borderColor: theme.palette.error.main,
backgroundColor: theme.palette.error.main,
data: createChartPoints(metrics, locationSettings, m => m.no),
@ -57,7 +58,9 @@ export const createChartData = (
},
};
return { datasets: [yesSeries, noSeries, requestsSeries] };
return {
datasets: [yesSeries, noSeries, requestsSeries],
};
};
const createChartPoints = (
@ -68,5 +71,6 @@ const createChartPoints = (
return metrics.map(metric => ({
x: metric.timestamp,
y: y(metric),
variants: metric.variants,
}));
};

View File

@ -4,6 +4,17 @@ import { ChartOptions, defaults } from 'chart.js';
import { IFeatureMetricsRaw } from 'interfaces/featureToggle';
import { formatDateHM } from 'utils/formatDate';
import { Theme } from '@mui/material/styles/createTheme';
import { IPoint } from './createChartData';
const formatVariantEntry = (
variant: [string, number],
totalExposure: number
) => {
if (totalExposure === 0) return '';
const [key, value] = variant;
const percentage = Math.floor((Number(value) / totalExposure) * 100);
return `${value} (${percentage}%) - ${key}`;
};
export const createChartOptions = (
theme: Theme,
@ -30,15 +41,38 @@ export const createChartOptions = (
padding: 10,
boxPadding: 5,
usePointStyle: true,
itemSort: (a, b) => {
const order = ['Total requests', 'Exposed', 'Not exposed'];
const aIndex = order.indexOf(a.dataset.label!);
const bIndex = order.indexOf(b.dataset.label!);
return aIndex - bIndex;
},
callbacks: {
label: item => {
return `${item.formattedValue} - ${item.dataset.label}`;
},
afterLabel: item => {
const data = item.dataset.data[
item.dataIndex
] as unknown as IPoint;
if (
item.dataset.label !== 'Exposed' ||
data.variants === undefined
) {
return '';
}
const { disabled, ...actualVariants } = data.variants;
return Object.entries(actualVariants)
.map(entry => formatVariantEntry(entry, data.y))
.join('\n');
},
title: items =>
formatDateHM(
`Time: ${formatDateHM(
items[0].parsed.x,
locationSettings.locale
),
)}`,
},
// Sort tooltip items in the same order as the lines in the chart.
itemSort: (a, b) => b.parsed.y - a.parsed.y,
},
legend: {
position: 'top',

View File

@ -88,4 +88,5 @@ export interface IFeatureMetricsRaw {
timestamp: string;
yes: number;
no: number;
variants: Record<string, number>;
}