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

feat: show the metrics summary chart (#6297)

Creates the impressions summary chart 
<img width="1358" alt="Screenshot 2024-02-21 at 13 25 05"
src="https://github.com/Unleash/unleash/assets/104830839/ddf15637-34de-4883-9ef7-517e37eab331">

Closes #
[1-2060](https://linear.app/unleash/issue/1-2060/impressions-summary-widget-frontend)

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
Co-authored-by: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
This commit is contained in:
andreas-unleash 2024-02-23 15:17:58 +02:00 committed by GitHub
parent 153c60d335
commit bae195add9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 128 additions and 16 deletions

View File

@ -18,6 +18,11 @@ import { ProjectHealthChart } from './ProjectHealthChart/ProjectHealthChart';
import { TimeToProductionChart } from './TimeToProductionChart/TimeToProductionChart';
import { TimeToProduction } from './TimeToProduction/TimeToProduction';
import { ProjectSelect, allOption } from './ProjectSelect/ProjectSelect';
import { MetricsSummaryChart } from './MetricsSummaryChart/MetricsSummaryChart';
import {
ExecutiveSummarySchemaMetricsSummaryTrendsItem,
ExecutiveSummarySchemaProjectFlagTrendsItem,
} from '../../openapi';
import { HealthStats } from './HealthStats/HealthStats';
const StyledGrid = styled(Box)(({ theme }) => ({
@ -61,6 +66,11 @@ const useDashboardGrid = () => {
};
};
interface FilteredProjectData {
filteredProjectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[];
filteredMetricsSummaryTrends: ExecutiveSummarySchemaMetricsSummaryTrendsItem[];
}
export const ExecutiveDashboard: VFC = () => {
const { executiveDashboardData, loading, error } = useExecutiveDashboard();
const [projects, setProjects] = useState([allOption.id]);
@ -78,14 +88,31 @@ export const ExecutiveDashboard: VFC = () => {
).toFixed(1);
}, [executiveDashboardData]);
const filteredProjectFlagTrends = useMemo(() => {
const { filteredProjectFlagTrends, filteredMetricsSummaryTrends } =
useMemo<FilteredProjectData>(() => {
if (projects[0] === allOption.id) {
return executiveDashboardData.projectFlagTrends;
return {
filteredProjectFlagTrends:
executiveDashboardData.projectFlagTrends,
filteredMetricsSummaryTrends:
executiveDashboardData.metricsSummaryTrends,
};
}
return executiveDashboardData.projectFlagTrends.filter((trend) =>
const filteredProjectFlagTrends =
executiveDashboardData.projectFlagTrends.filter((trend) =>
projects.includes(trend.project),
);
) as ExecutiveSummarySchemaProjectFlagTrendsItem[];
const filteredImpressionsSummary =
executiveDashboardData.metricsSummaryTrends.filter((summary) =>
projects.includes(summary.project),
) as ExecutiveSummarySchemaMetricsSummaryTrendsItem[];
return {
filteredProjectFlagTrends,
filteredMetricsSummaryTrends: filteredImpressionsSummary,
};
}, [executiveDashboardData, projects]);
const {
@ -159,13 +186,23 @@ export const ExecutiveDashboard: VFC = () => {
projectFlagTrends={filteredProjectFlagTrends}
/>
</Widget>
<Widget title='Average time to production' order={8}>
<Widget
title='Metrics over time per project'
order={8}
span={largeChartSpan}
>
<MetricsSummaryChart
metricsSummaryTrends={filteredMetricsSummaryTrends}
/>
</Widget>
<Widget title='Average time to production' order={9}>
<TimeToProduction
//FIXME: data from API
daysToProduction={12}
/>
</Widget>
<Widget title='Time to production' order={9} span={chartSpan}>
<Widget title='Time to production' order={10} span={chartSpan}>
<TimeToProductionChart
projectFlagTrends={filteredProjectFlagTrends}
/>

View File

@ -0,0 +1,17 @@
import { type VFC } from 'react';
import 'chartjs-adapter-date-fns';
import { ExecutiveSummarySchema } from 'openapi';
import { LineChart } from '../LineChart/LineChart';
import { useMetricsSummary } from '../useMetricsSummary';
interface IMetricsSummaryChartProps {
metricsSummaryTrends: ExecutiveSummarySchema['metricsSummaryTrends'];
}
export const MetricsSummaryChart: VFC<IMetricsSummaryChartProps> = ({
metricsSummaryTrends,
}) => {
const data = useMetricsSummary(metricsSummaryTrends, 'total');
return <LineChart data={data} />;
};

View File

@ -0,0 +1,58 @@
import { useMemo } from 'react';
import { getProjectColor } from './executive-dashboard-utils';
import { useTheme } from '@mui/material';
import {
ExecutiveSummarySchema,
ExecutiveSummarySchemaMetricsSummaryTrendsItem,
} from '../../openapi';
type MetricsSummaryTrends = ExecutiveSummarySchema['metricsSummaryTrends'];
export const useMetricsSummary = (
metricsSummaryTrends: MetricsSummaryTrends,
field: 'total' | 'totalYes' | 'totalNo' | 'totalApps',
) => {
const theme = useTheme();
const data = useMemo(() => {
const groupedFlagTrends = metricsSummaryTrends.reduce<
Record<string, ExecutiveSummarySchemaMetricsSummaryTrendsItem[]>
>((groups, item) => {
if (!groups[item.project]) {
groups[item.project] = [];
}
groups[item.project].push(item);
return groups;
}, {});
const datasets = Object.entries(groupedFlagTrends).map(
([project, metricsSummaryTrends]) => {
const color = getProjectColor(project);
return {
label: project,
data: metricsSummaryTrends.map((item) => {
if (field !== 'total') {
return item[field] || 0;
}
return item.totalYes + item.totalNo || 0;
}),
borderColor: color,
backgroundColor: color,
fill: false,
};
},
);
const objectKeys = Object.keys(groupedFlagTrends);
const firstElementSummary = groupedFlagTrends[objectKeys[0]] || [];
const firstElementsDates = firstElementSummary.map((item) => item.date);
return {
labels: firstElementsDates,
datasets,
};
}, [theme, metricsSummaryTrends]);
return data;
};

View File

@ -33,7 +33,7 @@ export const useExecutiveDashboard = (
userTrends: [],
flagTrends: [],
projectFlagTrends: [],
impressionsSummary: [],
metricsSummaryTrends: [],
},
refetchExecutiveDashboard,
loading: !error && !data,

View File

@ -5,7 +5,7 @@
*/
import type { ExecutiveSummarySchemaFlags } from './executiveSummarySchemaFlags';
import type { ExecutiveSummarySchemaFlagTrendsItem } from './executiveSummarySchemaFlagTrendsItem';
import type { ExecutiveSummarySchemaImpressionsSummaryItem } from './executiveSummarySchemaImpressionsSummaryItem';
import type { ExecutiveSummarySchemaMetricsSummaryTrendsItem } from './executiveSummarySchemaMetricsSummaryTrendsItem';
import type { ExecutiveSummarySchemaProjectFlagTrendsItem } from './executiveSummarySchemaProjectFlagTrendsItem';
import type { ExecutiveSummarySchemaUsers } from './executiveSummarySchemaUsers';
import type { ExecutiveSummarySchemaUserTrendsItem } from './executiveSummarySchemaUserTrendsItem';
@ -18,8 +18,8 @@ export interface ExecutiveSummarySchema {
flags: ExecutiveSummarySchemaFlags;
/** How number of flags changed over time */
flagTrends: ExecutiveSummarySchemaFlagTrendsItem[];
/** How impression data per project changed over time */
impressionsSummary: ExecutiveSummarySchemaImpressionsSummaryItem[];
/** How metrics data per project changed over time */
metricsSummaryTrends: ExecutiveSummarySchemaMetricsSummaryTrendsItem[];
/** How number of flags per project changed over time */
projectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[];
/** High level user count statistics */

View File

@ -4,7 +4,7 @@
* See `gen:api` script in package.json
*/
export type ExecutiveSummarySchemaImpressionsSummaryItem = {
export type ExecutiveSummarySchemaMetricsSummaryTrendsItem = {
/** Date the impressions summary were calculated */
date: string;
/** Project id of the project the impressions summary belong to */

View File

@ -512,7 +512,7 @@ export * from './eventsSchemaVersion';
export * from './executiveSummarySchema';
export * from './executiveSummarySchemaFlagTrendsItem';
export * from './executiveSummarySchemaFlags';
export * from './executiveSummarySchemaImpressionsSummaryItem';
export * from './executiveSummarySchemaMetricsSummaryTrendsItem';
export * from './executiveSummarySchemaProjectFlagTrendsItem';
export * from './executiveSummarySchemaUserTrendsItem';
export * from './executiveSummarySchemaUsers';