mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add project flags component (#6070)
This PR adds project flags line chart component
This commit is contained in:
parent
c6a2303026
commit
aae1d0576f
@ -13,6 +13,7 @@ import { useExecutiveDashboard } from 'hooks/api/getters/useExecutiveSummary/use
|
||||
import { UserStats } from './UserStats/UserStats';
|
||||
import { FlagStats } from './FlagStats/FlagStats';
|
||||
import { Widget } from './Widget/Widget';
|
||||
import { FlagsProjectChart } from './FlagsProjectChart/FlagsProjectChart';
|
||||
|
||||
const StyledGrid = styled(Box)(({ theme }) => ({
|
||||
display: 'grid',
|
||||
@ -107,6 +108,10 @@ export const ExecutiveDashboard: VFC = () => {
|
||||
/>
|
||||
</Widget>
|
||||
</StyledGrid>
|
||||
|
||||
<FlagsProjectChart
|
||||
projectFlagTrends={executiveDashboardData.projectFlagTrends}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -64,7 +64,11 @@ const createOptions = (theme: Theme, locationSettings: ILocationSettings) =>
|
||||
const date =
|
||||
item?.chart?.data?.labels?.[item.dataIndex];
|
||||
return date
|
||||
? formatDateYMD(date, locationSettings.locale)
|
||||
? formatDateYMD(
|
||||
date,
|
||||
locationSettings.locale,
|
||||
'UTC',
|
||||
)
|
||||
: '';
|
||||
},
|
||||
},
|
||||
|
@ -0,0 +1,5 @@
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const FlagsProjectChart = lazy(
|
||||
() => import('./FlagsProjectChartComponent'),
|
||||
);
|
@ -0,0 +1,162 @@
|
||||
import { useMemo, type VFC } from 'react';
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
TimeScale,
|
||||
} from 'chart.js';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import 'chartjs-adapter-date-fns';
|
||||
import { Paper, Theme, Typography, useTheme } from '@mui/material';
|
||||
import {
|
||||
useLocationSettings,
|
||||
type ILocationSettings,
|
||||
} from 'hooks/useLocationSettings';
|
||||
import { formatDateYMD } from 'utils/formatDate';
|
||||
import {
|
||||
ExecutiveSummarySchema,
|
||||
ExecutiveSummarySchemaProjectFlagTrendsItem,
|
||||
} from 'openapi';
|
||||
|
||||
const getRandomColor = () => {
|
||||
const letters = '0123456789ABCDEF';
|
||||
let color = '#';
|
||||
for (let i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
};
|
||||
|
||||
const createData = (
|
||||
theme: Theme,
|
||||
flagTrends: ExecutiveSummarySchema['projectFlagTrends'] = [],
|
||||
) => {
|
||||
const groupedFlagTrends = flagTrends.reduce<
|
||||
Record<string, ExecutiveSummarySchemaProjectFlagTrendsItem[]>
|
||||
>((groups, item) => {
|
||||
if (!groups[item.project]) {
|
||||
groups[item.project] = [];
|
||||
}
|
||||
groups[item.project].push(item);
|
||||
return groups;
|
||||
}, {});
|
||||
|
||||
const datasets = Object.entries(groupedFlagTrends).map(
|
||||
([project, trends]) => {
|
||||
const color = getRandomColor();
|
||||
return {
|
||||
label: project,
|
||||
data: trends.map((item) => item.total),
|
||||
borderColor: color,
|
||||
backgroundColor: color,
|
||||
fill: true,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
labels: flagTrends.map((item) => item.date),
|
||||
datasets,
|
||||
};
|
||||
};
|
||||
|
||||
const createOptions = (theme: Theme, locationSettings: ILocationSettings) =>
|
||||
({
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: (tooltipItems: any) => {
|
||||
const item = tooltipItems?.[0];
|
||||
const date =
|
||||
item?.chart?.data?.labels?.[item.dataIndex];
|
||||
return date
|
||||
? formatDateYMD(
|
||||
date,
|
||||
locationSettings.locale,
|
||||
'UTC',
|
||||
)
|
||||
: '';
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
locale: locationSettings.locale,
|
||||
interaction: {
|
||||
intersect: false,
|
||||
axis: 'x',
|
||||
},
|
||||
color: theme.palette.text.secondary,
|
||||
scales: {
|
||||
y: {
|
||||
type: 'linear',
|
||||
grid: {
|
||||
color: theme.palette.divider,
|
||||
borderColor: theme.palette.divider,
|
||||
},
|
||||
ticks: { color: theme.palette.text.secondary },
|
||||
},
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'month',
|
||||
},
|
||||
grid: {
|
||||
color: theme.palette.divider,
|
||||
borderColor: theme.palette.divider,
|
||||
},
|
||||
ticks: {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
},
|
||||
},
|
||||
}) as const;
|
||||
|
||||
interface IFlagsChartComponentProps {
|
||||
projectFlagTrends: ExecutiveSummarySchema['projectFlagTrends'];
|
||||
}
|
||||
|
||||
const FlagsProjectChart: VFC<IFlagsChartComponentProps> = ({
|
||||
projectFlagTrends,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { locationSettings } = useLocationSettings();
|
||||
const data = useMemo(
|
||||
() => createData(theme, projectFlagTrends),
|
||||
[theme, projectFlagTrends],
|
||||
);
|
||||
const options = createOptions(theme, locationSettings);
|
||||
|
||||
return (
|
||||
<Paper sx={(theme) => ({ padding: theme.spacing(4) })}>
|
||||
<Typography
|
||||
variant='h3'
|
||||
sx={(theme) => ({ marginBottom: theme.spacing(3) })}
|
||||
>
|
||||
Number of flags per project
|
||||
</Typography>
|
||||
<Line options={options} data={data} />
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
TimeScale,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
|
||||
export default FlagsProjectChart;
|
@ -32,6 +32,7 @@ export const useExecutiveDashboard = (
|
||||
flags: { total: 0 },
|
||||
userTrends: [],
|
||||
flagTrends: [],
|
||||
projectFlagTrends: [],
|
||||
},
|
||||
refetchExecutiveDashboard,
|
||||
loading: !error && !data,
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
import type { ExecutiveSummarySchemaFlags } from './executiveSummarySchemaFlags';
|
||||
import type { ExecutiveSummarySchemaFlagTrendsItem } from './executiveSummarySchemaFlagTrendsItem';
|
||||
import type { ExecutiveSummarySchemaProjectFlagTrendsItem } from './executiveSummarySchemaProjectFlagTrendsItem';
|
||||
import type { ExecutiveSummarySchemaUsers } from './executiveSummarySchemaUsers';
|
||||
import type { ExecutiveSummarySchemaUserTrendsItem } from './executiveSummarySchemaUserTrendsItem';
|
||||
|
||||
@ -16,6 +17,8 @@ export interface ExecutiveSummarySchema {
|
||||
flags: ExecutiveSummarySchemaFlags;
|
||||
/** How number of flags changed over time */
|
||||
flagTrends: ExecutiveSummarySchemaFlagTrendsItem[];
|
||||
/** How number of flags per project changed over time */
|
||||
projectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[];
|
||||
/** High level user count statistics */
|
||||
users: ExecutiveSummarySchemaUsers;
|
||||
/** How number of users changed over time */
|
||||
|
@ -10,7 +10,7 @@ export type ExecutiveSummarySchemaFlagTrendsItem = {
|
||||
/** A UTC date when the stats were captured. Time is the very end of a given day. */
|
||||
date: string;
|
||||
/** The number of time calculated potentially stale flags on a particular day */
|
||||
potentiallyStale?: number;
|
||||
potentiallyStale: number;
|
||||
/** The number of user marked stale flags on a particular day */
|
||||
stale: number;
|
||||
/** The number of all flags on a particular day */
|
||||
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Generated by Orval
|
||||
* Do not edit manually.
|
||||
* See `gen:api` script in package.json
|
||||
*/
|
||||
|
||||
export type ExecutiveSummarySchemaProjectFlagTrendsItem = {
|
||||
/** The number of active flags on a particular day */
|
||||
active: number;
|
||||
/** A UTC date when the stats were captured. Time is the very end of a given day. */
|
||||
date: string;
|
||||
/** An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#health-rating) on a scale from 0 to 100 */
|
||||
health?: number;
|
||||
/** The number of time calculated potentially stale flags on a particular day */
|
||||
potentiallyStale: number;
|
||||
/** Project id of the project the flag trends belong to */
|
||||
project: string;
|
||||
/** The number of user marked stale flags on a particular day */
|
||||
stale: number;
|
||||
/** The average time from when a feature was created to when it was enabled in the "production" environment during the current window */
|
||||
timeToProduction?: number;
|
||||
/** The number of all flags on a particular day */
|
||||
total: number;
|
||||
};
|
@ -497,6 +497,7 @@ export * from './eventsSchemaVersion';
|
||||
export * from './executiveSummarySchema';
|
||||
export * from './executiveSummarySchemaFlagTrendsItem';
|
||||
export * from './executiveSummarySchemaFlags';
|
||||
export * from './executiveSummarySchemaProjectFlagTrendsItem';
|
||||
export * from './executiveSummarySchemaUserTrendsItem';
|
||||
export * from './executiveSummarySchemaUsers';
|
||||
export * from './exportFeatures404';
|
||||
|
Loading…
Reference in New Issue
Block a user