1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-09 01:17:06 +02: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 { TimeToProductionChart } from './TimeToProductionChart/TimeToProductionChart';
import { TimeToProduction } from './TimeToProduction/TimeToProduction'; import { TimeToProduction } from './TimeToProduction/TimeToProduction';
import { ProjectSelect, allOption } from './ProjectSelect/ProjectSelect'; import { ProjectSelect, allOption } from './ProjectSelect/ProjectSelect';
import { MetricsSummaryChart } from './MetricsSummaryChart/MetricsSummaryChart';
import {
ExecutiveSummarySchemaMetricsSummaryTrendsItem,
ExecutiveSummarySchemaProjectFlagTrendsItem,
} from '../../openapi';
import { HealthStats } from './HealthStats/HealthStats'; import { HealthStats } from './HealthStats/HealthStats';
const StyledGrid = styled(Box)(({ theme }) => ({ const StyledGrid = styled(Box)(({ theme }) => ({
@ -61,6 +66,11 @@ const useDashboardGrid = () => {
}; };
}; };
interface FilteredProjectData {
filteredProjectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[];
filteredMetricsSummaryTrends: ExecutiveSummarySchemaMetricsSummaryTrendsItem[];
}
export const ExecutiveDashboard: VFC = () => { export const ExecutiveDashboard: VFC = () => {
const { executiveDashboardData, loading, error } = useExecutiveDashboard(); const { executiveDashboardData, loading, error } = useExecutiveDashboard();
const [projects, setProjects] = useState([allOption.id]); const [projects, setProjects] = useState([allOption.id]);
@ -78,15 +88,32 @@ export const ExecutiveDashboard: VFC = () => {
).toFixed(1); ).toFixed(1);
}, [executiveDashboardData]); }, [executiveDashboardData]);
const filteredProjectFlagTrends = useMemo(() => { const { filteredProjectFlagTrends, filteredMetricsSummaryTrends } =
if (projects[0] === allOption.id) { useMemo<FilteredProjectData>(() => {
return executiveDashboardData.projectFlagTrends; if (projects[0] === allOption.id) {
} return {
filteredProjectFlagTrends:
executiveDashboardData.projectFlagTrends,
filteredMetricsSummaryTrends:
executiveDashboardData.metricsSummaryTrends,
};
}
return executiveDashboardData.projectFlagTrends.filter((trend) => const filteredProjectFlagTrends =
projects.includes(trend.project), executiveDashboardData.projectFlagTrends.filter((trend) =>
); projects.includes(trend.project),
}, [executiveDashboardData, projects]); ) as ExecutiveSummarySchemaProjectFlagTrendsItem[];
const filteredImpressionsSummary =
executiveDashboardData.metricsSummaryTrends.filter((summary) =>
projects.includes(summary.project),
) as ExecutiveSummarySchemaMetricsSummaryTrendsItem[];
return {
filteredProjectFlagTrends,
filteredMetricsSummaryTrends: filteredImpressionsSummary,
};
}, [executiveDashboardData, projects]);
const { const {
gridTemplateColumns, gridTemplateColumns,
@ -159,13 +186,23 @@ export const ExecutiveDashboard: VFC = () => {
projectFlagTrends={filteredProjectFlagTrends} projectFlagTrends={filteredProjectFlagTrends}
/> />
</Widget> </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 <TimeToProduction
//FIXME: data from API //FIXME: data from API
daysToProduction={12} daysToProduction={12}
/> />
</Widget> </Widget>
<Widget title='Time to production' order={9} span={chartSpan}> <Widget title='Time to production' order={10} span={chartSpan}>
<TimeToProductionChart <TimeToProductionChart
projectFlagTrends={filteredProjectFlagTrends} 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: [], userTrends: [],
flagTrends: [], flagTrends: [],
projectFlagTrends: [], projectFlagTrends: [],
impressionsSummary: [], metricsSummaryTrends: [],
}, },
refetchExecutiveDashboard, refetchExecutiveDashboard,
loading: !error && !data, loading: !error && !data,

View File

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

View File

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

View File

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