mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-15 01:16:22 +02:00
feat: align insights charts (#7984)
Now the left widget will use the same that as the last data point on the right chart. With this change, flags/users object never needs to be passed in. **Next step is to remove the flags/users from the endpoint.** Previous  Now 
This commit is contained in:
parent
064744b18f
commit
fc86f5b2fe
@ -12,11 +12,7 @@ import { TimeToProduction } from './componentsStat/TimeToProduction/TimeToProduc
|
||||
import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart';
|
||||
import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart';
|
||||
import { UpdatesPerEnvironmentTypeChart } from './componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart';
|
||||
import type {
|
||||
InstanceInsightsSchema,
|
||||
InstanceInsightsSchemaFlags,
|
||||
InstanceInsightsSchemaUsers,
|
||||
} from 'openapi';
|
||||
import type { InstanceInsightsSchema } from 'openapi';
|
||||
import type { GroupedDataByProject } from './hooks/useGroupedProjectTrends';
|
||||
import { allOption } from 'component/common/ProjectSelect/ProjectSelect';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
@ -24,7 +20,6 @@ import { WidgetTitle } from './components/WidgetTitle/WidgetTitle';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
|
||||
export interface IChartsProps {
|
||||
flags: InstanceInsightsSchema['flags'];
|
||||
flagTrends: InstanceInsightsSchema['flagTrends'];
|
||||
projectsData: InstanceInsightsSchema['projectFlagTrends'];
|
||||
groupedProjectsData: GroupedDataByProject<
|
||||
@ -34,7 +29,6 @@ export interface IChartsProps {
|
||||
groupedMetricsData: GroupedDataByProject<
|
||||
InstanceInsightsSchema['metricsSummaryTrends']
|
||||
>;
|
||||
users: InstanceInsightsSchema['users'];
|
||||
userTrends: InstanceInsightsSchema['userTrends'];
|
||||
environmentTypeTrends: InstanceInsightsSchema['environmentTypeTrends'];
|
||||
summary: {
|
||||
@ -98,8 +92,6 @@ const StyledChartContainer = styled(Box)(({ theme }) => ({
|
||||
|
||||
export const InsightsCharts: FC<IChartsProps> = ({
|
||||
projects,
|
||||
flags,
|
||||
users,
|
||||
summary,
|
||||
userTrends,
|
||||
groupedProjectsData,
|
||||
@ -113,11 +105,16 @@ export const InsightsCharts: FC<IChartsProps> = ({
|
||||
const isOneProjectSelected = projects.length === 1;
|
||||
const { isEnterprise } = useUiConfig();
|
||||
|
||||
function getFlagsPerUser(
|
||||
flags: InstanceInsightsSchemaFlags,
|
||||
users: InstanceInsightsSchemaUsers,
|
||||
) {
|
||||
const flagsPerUserCalculation = flags.total / users.total;
|
||||
const lastUserTrend = userTrends[userTrends.length - 1];
|
||||
const lastFlagTrend = flagTrends[flagTrends.length - 1];
|
||||
|
||||
const usersTotal = lastUserTrend?.total ?? 0;
|
||||
const usersActive = lastUserTrend?.active ?? 0;
|
||||
const usersInactive = lastUserTrend?.inactive ?? 0;
|
||||
const flagsTotal = lastFlagTrend?.total ?? 0;
|
||||
|
||||
function getFlagsPerUser(flagsTotal: number, usersTotal: number) {
|
||||
const flagsPerUserCalculation = flagsTotal / usersTotal;
|
||||
return Number.isNaN(flagsPerUserCalculation)
|
||||
? 'N/A'
|
||||
: flagsPerUserCalculation.toFixed(2);
|
||||
@ -133,9 +130,9 @@ export const InsightsCharts: FC<IChartsProps> = ({
|
||||
<StyledWidgetStats>
|
||||
<WidgetTitle title='Total users' />
|
||||
<UserStats
|
||||
count={users.total}
|
||||
active={users.active}
|
||||
inactive={users.inactive}
|
||||
count={usersTotal}
|
||||
active={usersActive}
|
||||
inactive={usersInactive}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
@ -239,8 +236,11 @@ export const InsightsCharts: FC<IChartsProps> = ({
|
||||
<StyledWidgetStats width={275}>
|
||||
<WidgetTitle title='Flags' />
|
||||
<FlagStats
|
||||
count={flags.total}
|
||||
flagsPerUser={getFlagsPerUser(flags, users)}
|
||||
count={flagsTotal}
|
||||
flagsPerUser={getFlagsPerUser(
|
||||
flagsTotal,
|
||||
usersTotal,
|
||||
)}
|
||||
isLoading={loading}
|
||||
/>
|
||||
</StyledWidgetStats>
|
||||
|
@ -1,63 +1,59 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useFilteredFlagsSummary } from './useFilteredFlagsSummary';
|
||||
import type { InstanceInsightsSchemaUsers } from 'openapi';
|
||||
|
||||
describe('useFilteredFlagTrends', () => {
|
||||
it('should summarize only last week of project flag trends', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useFilteredFlagsSummary(
|
||||
[
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 1,
|
||||
active: 1,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 1,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 2,
|
||||
active: 2,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 2,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-02',
|
||||
project: 'project1',
|
||||
total: 4,
|
||||
active: 3,
|
||||
stale: 0,
|
||||
potentiallyStale: 1,
|
||||
users: 1,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 75,
|
||||
},
|
||||
{
|
||||
week: '2024-02',
|
||||
project: 'project3',
|
||||
total: 10,
|
||||
active: 8,
|
||||
stale: 2,
|
||||
potentiallyStale: 0,
|
||||
users: 3,
|
||||
date: '',
|
||||
timeToProduction: 2,
|
||||
health: 80,
|
||||
},
|
||||
],
|
||||
{ total: 1 } as unknown as InstanceInsightsSchemaUsers,
|
||||
),
|
||||
useFilteredFlagsSummary([
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 1,
|
||||
active: 1,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 1,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 2,
|
||||
active: 2,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 2,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-02',
|
||||
project: 'project1',
|
||||
total: 4,
|
||||
active: 3,
|
||||
stale: 0,
|
||||
potentiallyStale: 1,
|
||||
users: 1,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 75,
|
||||
},
|
||||
{
|
||||
week: '2024-02',
|
||||
project: 'project3',
|
||||
total: 10,
|
||||
active: 8,
|
||||
stale: 2,
|
||||
potentiallyStale: 0,
|
||||
users: 3,
|
||||
date: '',
|
||||
timeToProduction: 2,
|
||||
health: 80,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
@ -67,30 +63,26 @@ describe('useFilteredFlagTrends', () => {
|
||||
potentiallyStale: 1,
|
||||
averageUsers: 2,
|
||||
averageHealth: '79',
|
||||
flagsPerUser: '14.00',
|
||||
medianTimeToProduction: 3,
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with project with zero users', () => {
|
||||
const { result, rerender } = renderHook(() =>
|
||||
useFilteredFlagsSummary(
|
||||
[
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 100,
|
||||
},
|
||||
],
|
||||
{ total: 1 } as unknown as InstanceInsightsSchemaUsers,
|
||||
),
|
||||
useFilteredFlagsSummary([
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 4,
|
||||
health: 100,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
@ -100,42 +92,38 @@ describe('useFilteredFlagTrends', () => {
|
||||
potentiallyStale: 0,
|
||||
averageUsers: 0,
|
||||
averageHealth: '100',
|
||||
flagsPerUser: '5.00',
|
||||
medianTimeToProduction: 4,
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with projects where some have with zero users', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useFilteredFlagsSummary(
|
||||
[
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 2,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 3,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
],
|
||||
{ total: 1 } as unknown as InstanceInsightsSchemaUsers,
|
||||
),
|
||||
useFilteredFlagsSummary([
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 2,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 5,
|
||||
active: 5,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 3,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
@ -145,30 +133,26 @@ describe('useFilteredFlagTrends', () => {
|
||||
potentiallyStale: 0,
|
||||
averageUsers: 1.5,
|
||||
averageHealth: '100',
|
||||
flagsPerUser: '10.00',
|
||||
medianTimeToProduction: 3.5,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set health of a project without feature flags to undefined', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useFilteredFlagsSummary(
|
||||
[
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
],
|
||||
{ total: 1 } as unknown as InstanceInsightsSchemaUsers,
|
||||
),
|
||||
useFilteredFlagsSummary([
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
@ -178,54 +162,50 @@ describe('useFilteredFlagTrends', () => {
|
||||
potentiallyStale: 0,
|
||||
averageUsers: 0,
|
||||
averageHealth: undefined,
|
||||
flagsPerUser: '0.00',
|
||||
medianTimeToProduction: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not use 0 timeToProduction projects for median calculation', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useFilteredFlagsSummary(
|
||||
[
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project3',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
],
|
||||
{ total: 1 } as unknown as InstanceInsightsSchemaUsers,
|
||||
),
|
||||
useFilteredFlagsSummary([
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project1',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project2',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 0,
|
||||
health: 100,
|
||||
},
|
||||
{
|
||||
week: '2024-01',
|
||||
project: 'project3',
|
||||
total: 0,
|
||||
active: 0,
|
||||
stale: 0,
|
||||
potentiallyStale: 0,
|
||||
users: 0,
|
||||
date: '',
|
||||
timeToProduction: 5,
|
||||
health: 100,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
expect(result.current).toEqual({
|
||||
@ -235,7 +215,6 @@ describe('useFilteredFlagTrends', () => {
|
||||
potentiallyStale: 0,
|
||||
averageUsers: 0,
|
||||
averageHealth: undefined,
|
||||
flagsPerUser: '0.00',
|
||||
medianTimeToProduction: 5,
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
import type {
|
||||
InstanceInsightsSchemaProjectFlagTrendsItem,
|
||||
InstanceInsightsSchemaUsers,
|
||||
} from 'openapi';
|
||||
import type { InstanceInsightsSchemaProjectFlagTrendsItem } from 'openapi';
|
||||
|
||||
const validTimeToProduction = (
|
||||
item: InstanceInsightsSchemaProjectFlagTrendsItem,
|
||||
@ -14,7 +11,6 @@ const validTimeToProduction = (
|
||||
// NOTE: should we move project filtering to the backend?
|
||||
export const useFilteredFlagsSummary = (
|
||||
filteredProjectFlagTrends: InstanceInsightsSchemaProjectFlagTrendsItem[],
|
||||
users: InstanceInsightsSchemaUsers,
|
||||
) =>
|
||||
useMemo(() => {
|
||||
const lastWeekId = filteredProjectFlagTrends.reduce((prev, current) => {
|
||||
@ -69,14 +65,8 @@ export const useFilteredFlagsSummary = (
|
||||
? undefined
|
||||
: medianTimeToProductionCalculation;
|
||||
|
||||
const flagsPerUserCalculation = sum.total / users.total;
|
||||
const flagsPerUser = Number.isNaN(flagsPerUserCalculation)
|
||||
? 'N/A'
|
||||
: flagsPerUserCalculation.toFixed(2);
|
||||
|
||||
return {
|
||||
...sum,
|
||||
flagsPerUser,
|
||||
averageUsers,
|
||||
averageHealth: sum.total
|
||||
? ((sum.active / (sum.total || 1)) * 100).toFixed(0)
|
||||
|
@ -25,10 +25,7 @@ export const useInsightsData = (
|
||||
);
|
||||
const groupedMetricsData = useGroupedProjectTrends(metricsData);
|
||||
|
||||
const summary = useFilteredFlagsSummary(
|
||||
projectsData,
|
||||
instanceInsights.users,
|
||||
);
|
||||
const summary = useFilteredFlagsSummary(projectsData);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
@ -37,7 +34,6 @@ export const useInsightsData = (
|
||||
groupedProjectsData,
|
||||
metricsData,
|
||||
groupedMetricsData,
|
||||
users: instanceInsights.users,
|
||||
environmentTypeTrends: instanceInsights.environmentTypeTrends,
|
||||
summary,
|
||||
allMetricsDatapoints,
|
||||
|
@ -30,8 +30,6 @@ export const useInsights = (
|
||||
|
||||
return {
|
||||
insights: data || {
|
||||
users: { total: 0, inactive: 0, active: 0 },
|
||||
flags: { total: 0 },
|
||||
userTrends: [],
|
||||
flagTrends: [],
|
||||
projectFlagTrends: [],
|
||||
|
@ -4,11 +4,9 @@
|
||||
* See `gen:api` script in package.json
|
||||
*/
|
||||
import type { InstanceInsightsSchemaEnvironmentTypeTrendsItem } from './instanceInsightsSchemaEnvironmentTypeTrendsItem';
|
||||
import type { InstanceInsightsSchemaFlags } from './instanceInsightsSchemaFlags';
|
||||
import type { InstanceInsightsSchemaFlagTrendsItem } from './instanceInsightsSchemaFlagTrendsItem';
|
||||
import type { InstanceInsightsSchemaMetricsSummaryTrendsItem } from './instanceInsightsSchemaMetricsSummaryTrendsItem';
|
||||
import type { InstanceInsightsSchemaProjectFlagTrendsItem } from './instanceInsightsSchemaProjectFlagTrendsItem';
|
||||
import type { InstanceInsightsSchemaUsers } from './instanceInsightsSchemaUsers';
|
||||
import type { InstanceInsightsSchemaUserTrendsItem } from './instanceInsightsSchemaUserTrendsItem';
|
||||
|
||||
/**
|
||||
@ -17,16 +15,12 @@ import type { InstanceInsightsSchemaUserTrendsItem } from './instanceInsightsSch
|
||||
export interface InstanceInsightsSchema {
|
||||
/** How updates per environment type changed over time */
|
||||
environmentTypeTrends: InstanceInsightsSchemaEnvironmentTypeTrendsItem[];
|
||||
/** High level flag count statistics */
|
||||
flags: InstanceInsightsSchemaFlags;
|
||||
/** How number of flags changed over time */
|
||||
flagTrends: InstanceInsightsSchemaFlagTrendsItem[];
|
||||
/** How metrics data per project changed over time */
|
||||
metricsSummaryTrends: InstanceInsightsSchemaMetricsSummaryTrendsItem[];
|
||||
/** How number of flags per project changed over time */
|
||||
projectFlagTrends: InstanceInsightsSchemaProjectFlagTrendsItem[];
|
||||
/** High level user count statistics */
|
||||
users: InstanceInsightsSchemaUsers;
|
||||
/** How number of users changed over time */
|
||||
userTrends: InstanceInsightsSchemaUserTrendsItem[];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user