Skip to content

Commit

Permalink
feat: placeholder flag metrics chart (#8197)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Sep 20, 2024
1 parent 0587203 commit 87b9976
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import {
Title,
Tooltip,
Legend,
type Chart,
type Tick,
} from 'chart.js';

import { Bar } from 'react-chartjs-2';
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions frontend/src/component/common/Chart/customHighlightPlugin.ts
Original file line number Diff line number Diff line change
@@ -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();
}
},
};
16 changes: 16 additions & 0 deletions frontend/src/component/common/Chart/formatTickValue.ts
Original file line number Diff line number Diff line change
@@ -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;
};
126 changes: 126 additions & 0 deletions frontend/src/component/personalDashboard/FlagMetricsChart.tsx
Original file line number Diff line number Diff line change
@@ -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,
);
53 changes: 35 additions & 18 deletions frontend/src/component/personalDashboard/PersonalDashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
import {
Box,
Grid,
IconButton,
Link,
List,
ListItem,
ListItemButton,
styled,
Typography,
Grid,
} from '@mui/material';
import type { Theme } from '@mui/material/styles/createTheme';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
Expand All @@ -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),
Expand All @@ -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`,
}));
Expand Down Expand Up @@ -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}`,
}));
Expand Down Expand Up @@ -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' }}
Expand Down Expand Up @@ -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}
Expand All @@ -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>
);
};

0 comments on commit 87b9976

Please sign in to comment.