1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-06 01:15:28 +02:00
unleash.unleash/frontend/src/component/insights/componentsChart/MetricsSummaryChart/MetricsChartTooltip/MetricsChartTooltip.tsx
2024-09-02 17:15:28 +02:00

166 lines
5.9 KiB
TypeScript

import type { VFC } from 'react';
import type { InstanceInsightsSchemaMetricsSummaryTrendsItem } from 'openapi';
import { Box, Divider, Paper, styled, Typography } from '@mui/material';
import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { ConditionallyRender } from '../../../../common/ConditionallyRender/ConditionallyRender';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2),
}));
const StyledItemHeader = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
gap: theme.spacing(2),
alignItems: 'center',
}));
const InfoLine = ({
iconChar,
title,
color,
}: {
iconChar: string;
title: string;
color: 'info' | 'success' | 'error';
}) => (
<Typography
variant='body2'
component='p'
sx={{
color: (theme) => theme.palette[color].main,
}}
>
<Typography component='span'>{iconChar}</Typography>
<strong>{title}</strong>
</Typography>
);
export const InfoSummary = ({
data,
}: { data: { key: string; value: string | number }[] }) => (
<Box display={'flex'} flexDirection={'row'}>
{data.map(({ key, value }) => (
<div style={{ flex: 1, flexDirection: 'column' }} key={key}>
<div
style={{
flex: 1,
textAlign: 'center',
marginBottom: '4px',
}}
>
<Typography variant={'body1'} component={'p'}>
{key}
</Typography>
</div>
<div style={{ flex: 1, textAlign: 'center' }}>{value}</div>
</div>
))}
</Box>
);
export const MetricsSummaryTooltip: VFC<{ tooltip: TooltipState | null }> = ({
tooltip,
}) => {
const data = tooltip?.dataPoints.map((point) => {
return {
label: point.label,
title: point.dataset.label,
color: point.dataset.borderColor,
value: point.raw as InstanceInsightsSchemaMetricsSummaryTrendsItem & {
total: number;
},
};
});
const limitedData = data?.slice(0, 5);
return (
<Box
sx={(theme) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
width: '300px',
})}
>
{limitedData?.map((point, index) => (
<StyledTooltipItemContainer
elevation={3}
key={`${point.title}-${index}`}
>
<StyledItemHeader>
<Typography variant='body2' component='span'>
<Typography
sx={{ color: point.color }}
component='span'
>
{'● '}
</Typography>
<strong>{point.title}</strong>
</Typography>
<Typography
variant='body2'
color='textSecondary'
component='span'
>
{point.label}
</Typography>
</StyledItemHeader>
<Divider
sx={(theme) => ({ margin: theme.spacing(1.5, 0) })}
/>
<InfoLine
iconChar={'▣ '}
title={`Total requests: ${(point.value.totalRequests ?? 0).toLocaleString()}`}
color={'info'}
/>
<InfoLine
iconChar={'▲ '}
title={`Exposed: ${(point.value.totalYes ?? 0).toLocaleString()}`}
color={'success'}
/>
<InfoLine
iconChar={'▼ '}
title={`Not exposed: ${(point.value.totalNo ?? 0).toLocaleString()}`}
color={'error'}
/>
<ConditionallyRender
condition={
Boolean(point.value.totalApps) &&
Boolean(point.value.totalEnvironments) &&
Boolean(point.value.totalFlags)
}
show={
<>
<Divider
sx={(theme) => ({
margin: theme.spacing(1.5, 0),
})}
/>
<InfoSummary
data={[
{
key: 'Flags',
value: point.value.totalFlags,
},
{
key: 'Environments',
value: point.value
.totalEnvironments,
},
{
key: 'Apps',
value: point.value.totalApps,
},
]}
/>
</>
}
/>
</StyledTooltipItemContainer>
)) || null}
</Box>
);
};