1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: placeholder flag metrics chart (#8197)

This commit is contained in:
Mateusz Kwasniewski 2024-09-20 11:05:53 +02:00 committed by GitHub
parent 0587203ad6
commit 87b997698b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 212 additions and 65 deletions

View File

@ -17,8 +17,6 @@ import {
Title,
Tooltip,
Legend,
type Chart,
type Tick,
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
@ -32,43 +30,14 @@ import {
type ChartDatasetType,
useTrafficDataEstimation,
} from 'hooks/useTrafficData';
import { customHighlightPlugin } from 'component/common/Chart/customHighlightPlugin';
import { formatTickValue } from 'component/common/Chart/formatTickValue';
const StyledBox = styled(Box)(({ theme }) => ({
display: 'grid',
gap: theme.spacing(5),
}));
const customHighlightPlugin = {
id: 'customLine',
beforeDraw: (chart: Chart) => {
const width = 46;
if (chart.tooltip?.opacity && chart.tooltip.x) {
const x = chart.tooltip.caretX;
const yAxis = chart.scales.y;
const ctx = chart.ctx;
ctx.save();
const gradient = ctx.createLinearGradient(
x,
yAxis.top,
x,
yAxis.bottom + 34,
);
gradient.addColorStop(0, 'rgba(129, 122, 254, 0)');
gradient.addColorStop(1, 'rgba(129, 122, 254, 0.12)');
ctx.fillStyle = gradient;
ctx.roundRect(
x - width / 2,
yAxis.top,
width,
yAxis.bottom - yAxis.top + 34,
5,
);
ctx.fill();
ctx.restore();
}
},
};
const createBarChartOptions = (
theme: Theme,
tooltipTitleCallback: (tooltipItems: any) => string,
@ -150,20 +119,7 @@ const createBarChartOptions = (
ticks: {
color: theme.palette.text.secondary,
maxTicksLimit: 5,
callback: (
tickValue: string | number,
index: number,
ticks: Tick[],
) => {
if (typeof tickValue === 'string') {
return tickValue;
}
const value = Number.parseInt(tickValue.toString());
if (value > 999999) {
return `${value / 1000000}M`;
}
return value > 999 ? `${value / 1000}k` : value;
},
callback: formatTickValue,
},
grid: {
drawBorder: false,

View File

@ -0,0 +1,32 @@
import type { Chart } from 'chart.js';
export const customHighlightPlugin = {
id: 'customLine',
beforeDraw: (chart: Chart) => {
const width = 46;
if (chart.tooltip?.opacity && chart.tooltip.x) {
const x = chart.tooltip.caretX;
const yAxis = chart.scales.y;
const ctx = chart.ctx;
ctx.save();
const gradient = ctx.createLinearGradient(
x,
yAxis.top,
x,
yAxis.bottom + 34,
);
gradient.addColorStop(0, 'rgba(129, 122, 254, 0)');
gradient.addColorStop(1, 'rgba(129, 122, 254, 0.12)');
ctx.fillStyle = gradient;
ctx.roundRect(
x - width / 2,
yAxis.top,
width,
yAxis.bottom - yAxis.top + 34,
5,
);
ctx.fill();
ctx.restore();
}
},
};

View File

@ -0,0 +1,16 @@
import type { Tick } from 'chart.js';
export const formatTickValue = (
tickValue: string | number,
index: number,
ticks: Tick[],
) => {
if (typeof tickValue === 'string') {
return tickValue;
}
const value = Number.parseInt(tickValue.toString());
if (value > 999999) {
return `${value / 1000000}M`;
}
return value > 999 ? `${value / 1000}k` : value;
};

View File

@ -0,0 +1,126 @@
import {
BarElement,
CategoryScale,
Chart as ChartJS,
type ChartOptions,
Legend,
LinearScale,
Title,
Tooltip,
} from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { Bar } from 'react-chartjs-2';
import type { Theme } from '@mui/material/styles/createTheme';
import useTheme from '@mui/material/styles/useTheme';
import { useMemo } from 'react';
import { formatTickValue } from 'component/common/Chart/formatTickValue';
const defaultYes = [
45_000_000, 28_000_000, 28_000_000, 25_000_000, 50_000_000, 27_000_000,
26_000_000, 50_000_000, 32_000_000, 12_000_000, 13_000_000, 31_000_000,
12_000_000, 47_000_000, 29_000_000, 46_000_000, 45_000_000, 28_000_000,
28_000_000, 25_000_000, 50_000_000, 27_000_000, 26_000_000, 50_000_000,
32_000_000, 12_000_000, 13_000_000, 31_000_000, 12_000_000, 47_000_000,
];
const defaultNo = [
5_000_000, 8_000_000, 3_000_000, 2_000_000, 2_000_000, 5_000_000, 9_000_000,
3_000_000, 7_000_000, 2_000_000, 5_000_000, 8_000_000, 3_000_000, 2_000_000,
2_000_000, 5_000_000, 1_000_000, 3_000_000, 12_000_000, 2_000_000,
1_000_000, 1_000_000, 3_000_000, 2_000_000, 2_000_000, 5_000_000, 1_000_000,
3_000_000, 8_000_000, 2_000_000,
];
const data = {
labels: Array.from({ length: 30 }, (_, i) => i + 1),
datasets: [
{
data: defaultYes,
label: 'yes',
backgroundColor: '#BEBEBE',
hoverBackgroundColor: '#BEBEBE',
},
{
data: defaultNo,
label: 'no',
backgroundColor: '#9A9A9A',
hoverBackgroundColor: '#9A9A9A',
},
],
};
const createBarChartOptions = (theme: Theme): ChartOptions<'bar'> => ({
plugins: {
legend: {
position: 'bottom',
labels: {
color: theme.palette.text.primary,
pointStyle: 'circle',
usePointStyle: true,
boxHeight: 6,
padding: 15,
boxPadding: 5,
},
},
tooltip: {
enabled: false,
},
},
responsive: true,
scales: {
x: {
stacked: true,
ticks: {
color: theme.palette.text.secondary,
},
grid: {
display: false,
},
},
y: {
stacked: true,
ticks: {
color: theme.palette.text.secondary,
maxTicksLimit: 5,
callback: formatTickValue,
},
grid: {
drawBorder: false,
},
},
},
elements: {
bar: {
borderRadius: 5,
},
},
interaction: {
mode: 'index',
intersect: false,
},
});
export const PlaceholderFlagMetricsChart = () => {
const theme = useTheme();
const options = useMemo(() => {
return createBarChartOptions(theme);
}, [theme]);
return (
<Bar
data={data}
options={options}
aria-label='A bar chart with a single feature flag exposure metrics'
/>
);
};
ChartJS.register(
annotationPlugin,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
);

View File

@ -1,6 +1,7 @@
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
import {
Box,
Grid,
IconButton,
Link,
List,
@ -8,7 +9,6 @@ import {
ListItemButton,
styled,
Typography,
Grid,
} from '@mui/material';
import type { Theme } from '@mui/material/styles/createTheme';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
@ -17,6 +17,7 @@ import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
import LinkIcon from '@mui/icons-material/Link';
import { Badge } from '../common/Badge/Badge';
import { ConnectSDK, CreateFlag } from './ConnectSDK';
import { PlaceholderFlagMetricsChart } from './FlagMetricsChart';
const ScreenExplanation = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
@ -30,7 +31,7 @@ const StyledHeaderTitle = styled(Typography)(({ theme }) => ({
marginBottom: theme.spacing(2),
}));
const ProjectsGrid = styled(Grid)(({ theme }) => ({
const ContentGrid = styled(Grid)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
borderRadius: `${theme.shape.borderRadiusLarge}px`,
}));
@ -104,7 +105,7 @@ const ActiveProjectDetails: FC<{
);
};
const SpacedGrid = styled(Grid)(({ theme }) => ({
const SpacedGridItem = styled(Grid)(({ theme }) => ({
padding: theme.spacing(4),
border: `0.5px solid ${theme.palette.divider}`,
}));
@ -148,19 +149,19 @@ export const PersonalDashboard = () => {
most of Unleash
</ScreenExplanation>
<StyledHeaderTitle>Your resources</StyledHeaderTitle>
<ProjectsGrid container columns={{ lg: 12, md: 1 }}>
<SpacedGrid item lg={4} md={1}>
<ContentGrid container columns={{ lg: 12, md: 1 }}>
<SpacedGridItem item lg={4} md={1}>
<Typography variant='h3'>My projects</Typography>
</SpacedGrid>
<SpacedGrid
</SpacedGridItem>
<SpacedGridItem
item
lg={8}
md={1}
sx={{ display: 'flex', justifyContent: 'flex-end' }}
>
<Badge color='warning'>Setup incomplete</Badge>
</SpacedGrid>
<SpacedGrid item lg={4} md={1}>
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
<List
disablePadding={true}
sx={{ maxHeight: '400px', overflow: 'auto' }}
@ -207,19 +208,19 @@ export const PersonalDashboard = () => {
);
})}
</List>
</SpacedGrid>
<SpacedGrid item lg={4} md={1}>
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{activeProject ? (
<CreateFlag project={activeProject} />
) : null}
</SpacedGrid>
<SpacedGrid item lg={4} md={1}>
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{activeProject ? (
<ConnectSDK project={activeProject} />
) : null}
</SpacedGrid>
<SpacedGrid item lg={4} md={1} />
<SpacedGrid
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1} />
<SpacedGridItem
item
lg={8}
md={1}
@ -228,8 +229,24 @@ export const PersonalDashboard = () => {
<span>Your roles in this project:</span>{' '}
<Badge color='secondary'>Member</Badge>{' '}
<Badge color='secondary'>Another</Badge>
</SpacedGrid>
</ProjectsGrid>
</SpacedGridItem>
</ContentGrid>
<ContentGrid container columns={{ lg: 12, md: 1 }} sx={{ mt: 2 }}>
<SpacedGridItem item lg={4} md={1}>
<Typography variant='h3'>My feature flags</Typography>
</SpacedGridItem>
<SpacedGridItem item lg={8} md={1} />
<SpacedGridItem item lg={4} md={1}>
<Typography>
You have not created or favorited any feature flags.
Once you do, the will show up here.
</Typography>
</SpacedGridItem>
<SpacedGridItem item lg={8} md={1}>
<Typography sx={{ mb: 4 }}>Feature flag metrics</Typography>
<PlaceholderFlagMetricsChart />
</SpacedGridItem>
</ContentGrid>
</div>
);
};