1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-31 13:47:02 +02:00

Chore/rename dashboard files to insights (#6662)

Renames everything related to `executive dashboard` to `insights`

Closes: # [1-2213](https://linear.app/unleash/issue/1-2213/rename-in-fe)

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
andreas-unleash 2024-03-21 16:39:03 +02:00 committed by GitHub
parent 8532e08398
commit 9be15d4976
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 183 additions and 167 deletions

View File

@ -6,10 +6,10 @@ import {
allOption, allOption,
ProjectSelect, ProjectSelect,
} from 'component/common/ProjectSelect/ProjectSelect'; } from 'component/common/ProjectSelect/ProjectSelect';
import { useExecutiveDashboard } from 'hooks/api/getters/useExecutiveSummary/useExecutiveSummary'; import { useInsights } from 'hooks/api/getters/useInsights/useInsights';
import { DashboardHeader } from './components/DashboardHeader/DashboardHeader'; import { InsightsHeader } from './components/InsightsHeader/InsightsHeader';
import { useDashboardData } from './hooks/useDashboardData'; import { useInsightsData } from './hooks/useInsightsData';
import { Charts } from './Charts'; import { InsightsCharts } from './InsightsCharts';
const StickyWrapper = styled(Box, { const StickyWrapper = styled(Box, {
shouldForwardProp: (prop) => prop !== 'scrolled', shouldForwardProp: (prop) => prop !== 'scrolled',
@ -22,9 +22,9 @@ const StickyWrapper = styled(Box, {
transition: 'padding 0.3s ease', transition: 'padding 0.3s ease',
})); }));
export const ExecutiveDashboard: VFC = () => { export const Insights: VFC = () => {
const [scrolled, setScrolled] = useState(false); const [scrolled, setScrolled] = useState(false);
const { executiveDashboardData, loading, error } = useExecutiveDashboard(); const { insights, loading, error } = useInsights();
const stateConfig = { const stateConfig = {
projects: withDefault(ArrayParam, [allOption.id]), projects: withDefault(ArrayParam, [allOption.id]),
}; };
@ -36,7 +36,7 @@ export const ExecutiveDashboard: VFC = () => {
? (state.projects.filter(Boolean) as string[]) ? (state.projects.filter(Boolean) as string[])
: []; : [];
const dashboardData = useDashboardData(executiveDashboardData, projects); const insightsData = useInsightsData(insights, projects);
const handleScroll = () => { const handleScroll = () => {
if (!scrolled && window.scrollY > 0) { if (!scrolled && window.scrollY > 0) {
@ -53,7 +53,7 @@ export const ExecutiveDashboard: VFC = () => {
return ( return (
<> <>
<StickyWrapper scrolled={scrolled}> <StickyWrapper scrolled={scrolled}>
<DashboardHeader <InsightsHeader
actions={ actions={
<ProjectSelect <ProjectSelect
selectedProjects={projects} selectedProjects={projects}
@ -64,7 +64,11 @@ export const ExecutiveDashboard: VFC = () => {
} }
/> />
</StickyWrapper> </StickyWrapper>
<Charts loading={loading} projects={projects} {...dashboardData} /> <InsightsCharts
loading={loading}
projects={projects}
{...insightsData}
/>
</> </>
); );
}; };

View File

@ -12,7 +12,7 @@ import { TimeToProduction } from './componentsStat/TimeToProduction/TimeToProduc
import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart'; import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart';
import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart'; import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart';
import { UpdatesPerEnvironmentTypeChart } from './componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart'; import { UpdatesPerEnvironmentTypeChart } from './componentsChart/UpdatesPerEnvironmentTypeChart/UpdatesPerEnvironmentTypeChart';
import type { ExecutiveSummarySchema } from '../../openapi'; import type { InstanceInsightsSchema } from 'openapi';
import type { GroupedDataByProject } from './hooks/useGroupedProjectTrends'; import type { GroupedDataByProject } from './hooks/useGroupedProjectTrends';
import { Box, styled } from '@mui/material'; import { Box, styled } from '@mui/material';
import { allOption } from '../common/ProjectSelect/ProjectSelect'; import { allOption } from '../common/ProjectSelect/ProjectSelect';
@ -20,18 +20,18 @@ import type { VFC } from 'react';
import { chartInfo } from './chart-info'; import { chartInfo } from './chart-info';
interface IChartsProps { interface IChartsProps {
flagTrends: ExecutiveSummarySchema['flagTrends']; flagTrends: InstanceInsightsSchema['flagTrends'];
projectsData: ExecutiveSummarySchema['projectFlagTrends']; projectsData: InstanceInsightsSchema['projectFlagTrends'];
groupedProjectsData: GroupedDataByProject< groupedProjectsData: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>; >;
metricsData: ExecutiveSummarySchema['metricsSummaryTrends']; metricsData: InstanceInsightsSchema['metricsSummaryTrends'];
groupedMetricsData: GroupedDataByProject< groupedMetricsData: GroupedDataByProject<
ExecutiveSummarySchema['metricsSummaryTrends'] InstanceInsightsSchema['metricsSummaryTrends']
>; >;
users: ExecutiveSummarySchema['users']; users: InstanceInsightsSchema['users'];
userTrends: ExecutiveSummarySchema['userTrends']; userTrends: InstanceInsightsSchema['userTrends'];
environmentTypeTrends: ExecutiveSummarySchema['environmentTypeTrends']; environmentTypeTrends: InstanceInsightsSchema['environmentTypeTrends'];
summary: { summary: {
total: number; total: number;
active: number; active: number;
@ -64,7 +64,7 @@ const ChartWidget = styled(Widget)(({ theme }) => ({
}, },
})); }));
export const Charts: VFC<IChartsProps> = ({ export const InsightsCharts: VFC<IChartsProps> = ({
projects, projects,
users, users,
summary, summary,

View File

@ -49,7 +49,7 @@ const StyledActionsSmallScreen = styled('div')(({ theme }) => ({
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
})); }));
export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => { export const InsightsHeader: VFC<DashboardHeaderProps> = ({ actions }) => {
const showInactiveUsers = useUiFlag('showInactiveUsers'); const showInactiveUsers = useUiFlag('showInactiveUsers');
const theme = useTheme(); const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));

View File

@ -1,12 +1,15 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { LineChart, NotEnoughData } from '../../components/LineChart/LineChart'; import {
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; LineChart,
NotEnoughData,
} from 'component/insights/components/LineChart/LineChart';
import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
interface IFlagsChartProps { interface IFlagsChartProps {
flagTrends: ExecutiveSummarySchema['flagTrends']; flagTrends: InstanceInsightsSchema['flagTrends'];
isLoading?: boolean; isLoading?: boolean;
} }

View File

@ -1,14 +1,17 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { LineChart, NotEnoughData } from '../../components/LineChart/LineChart'; import {
import { useProjectChartData } from 'component/executiveDashboard/hooks/useProjectChartData'; LineChart,
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; NotEnoughData,
import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends'; } from 'component/insights/components/LineChart/LineChart';
import { useProjectChartData } from 'component/insights/hooks/useProjectChartData';
import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
interface IFlagsProjectChartProps { interface IFlagsProjectChartProps {
projectFlagTrends: GroupedDataByProject< projectFlagTrends: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>; >;
} }

View File

@ -1,7 +1,7 @@
import type { VFC } from 'react'; import type { VFC } from 'react';
import type { ExecutiveSummarySchemaMetricsSummaryTrendsItem } from 'openapi'; import type { InstanceInsightsSchemaMetricsSummaryTrendsItem } from 'openapi';
import { Box, Divider, Paper, styled, Typography } from '@mui/material'; import { Box, Divider, Paper, styled, Typography } from '@mui/material';
import type { TooltipState } from '../../../components/LineChart/ChartTooltip/ChartTooltip'; import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({ const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2), padding: theme.spacing(2),
@ -66,7 +66,7 @@ export const MetricsSummaryTooltip: VFC<{ tooltip: TooltipState | null }> = ({
label: point.label, label: point.label,
title: point.dataset.label, title: point.dataset.label,
color: point.dataset.borderColor, color: point.dataset.borderColor,
value: point.raw as ExecutiveSummarySchemaMetricsSummaryTrendsItem & { value: point.raw as InstanceInsightsSchemaMetricsSummaryTrendsItem & {
total: number; total: number;
}, },
}; };

View File

@ -1,7 +1,7 @@
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
export function aggregateDataPerDate( export function aggregateDataPerDate(
items: ExecutiveSummarySchema['metricsSummaryTrends'], items: InstanceInsightsSchema['metricsSummaryTrends'],
) { ) {
return items.reduce( return items.reduce(
(acc, item) => { (acc, item) => {

View File

@ -1,22 +1,22 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { import {
fillGradientPrimary, fillGradientPrimary,
LineChart, LineChart,
NotEnoughData, NotEnoughData,
} from '../../components/LineChart/LineChart'; } from 'component/insights/components/LineChart/LineChart';
import { MetricsSummaryTooltip } from './MetricsChartTooltip/MetricsChartTooltip'; import { MetricsSummaryTooltip } from './MetricsChartTooltip/MetricsChartTooltip';
import { useMetricsSummary } from '../../hooks/useMetricsSummary'; import { useMetricsSummary } from 'component/insights/hooks/useMetricsSummary';
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { aggregateDataPerDate } from './MetricsChartTooltip/aggregate-metrics-by-day'; import { aggregateDataPerDate } from './MetricsChartTooltip/aggregate-metrics-by-day';
interface IMetricsSummaryChartProps { interface IMetricsSummaryChartProps {
metricsSummaryTrends: GroupedDataByProject< metricsSummaryTrends: GroupedDataByProject<
ExecutiveSummarySchema['metricsSummaryTrends'] InstanceInsightsSchema['metricsSummaryTrends']
>; >;
isAggregate?: boolean; isAggregate?: boolean;
} }

View File

@ -1,9 +1,9 @@
import type { VFC } from 'react'; import type { VFC } from 'react';
import type { ExecutiveSummarySchemaProjectFlagTrendsItem } from 'openapi'; import type { InstanceInsightsSchemaProjectFlagTrendsItem } from 'openapi';
import { Box, Divider, Paper, Typography, styled } from '@mui/material'; import { Box, Divider, Paper, Typography, styled } from '@mui/material';
import { Badge } from 'component/common/Badge/Badge'; import { Badge } from 'component/common/Badge/Badge';
import type { TooltipState } from '../../../components/LineChart/ChartTooltip/ChartTooltip'; import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
import { HorizontalDistributionChart } from '../../../components/HorizontalDistributionChart/HorizontalDistributionChart'; import { HorizontalDistributionChart } from 'component/insights/components/HorizontalDistributionChart/HorizontalDistributionChart';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({ const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
@ -89,7 +89,7 @@ export const HealthTooltip: VFC<{ tooltip: TooltipState | null }> = ({
label: point.label, label: point.label,
title: point.dataset.label, title: point.dataset.label,
color: point.dataset.borderColor, color: point.dataset.borderColor,
value: point.raw as ExecutiveSummarySchemaProjectFlagTrendsItem, value: point.raw as InstanceInsightsSchemaProjectFlagTrendsItem,
}; };
}); });

View File

@ -1,19 +1,19 @@
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { HealthTooltip } from './HealthChartTooltip/HealthChartTooltip'; import { HealthTooltip } from './HealthChartTooltip/HealthChartTooltip';
import { useProjectChartData } from 'component/executiveDashboard/hooks/useProjectChartData'; import { useProjectChartData } from 'component/insights/hooks/useProjectChartData';
import { import {
fillGradientPrimary, fillGradientPrimary,
LineChart, LineChart,
NotEnoughData, NotEnoughData,
} from 'component/executiveDashboard/components/LineChart/LineChart'; } from 'component/insights/components/LineChart/LineChart';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
interface IProjectHealthChartProps { interface IProjectHealthChartProps {
projectFlagTrends: GroupedDataByProject< projectFlagTrends: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>; >;
isAggregate?: boolean; isAggregate?: boolean;
} }

View File

@ -1,21 +1,21 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { import {
fillGradientPrimary, fillGradientPrimary,
LineChart, LineChart,
NotEnoughData, NotEnoughData,
} from '../../components/LineChart/LineChart'; } from 'component/insights/components/LineChart/LineChart';
import { useProjectChartData } from '../../hooks/useProjectChartData'; import { useProjectChartData } from 'component/insights/hooks/useProjectChartData';
import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends'; import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
import { usePlaceholderData } from '../../hooks/usePlaceholderData'; import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import { TimeToProductionTooltip } from './TimeToProductionTooltip/TimeToProductionTooltip'; import { TimeToProductionTooltip } from './TimeToProductionTooltip/TimeToProductionTooltip';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import { medianTimeToProduction } from './median-time-to-production'; import { medianTimeToProduction } from './median-time-to-production';
interface ITimeToProductionChartProps { interface ITimeToProductionChartProps {
projectFlagTrends: GroupedDataByProject< projectFlagTrends: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>; >;
isAggregate?: boolean; isAggregate?: boolean;
} }

View File

@ -1,8 +1,8 @@
import type { VFC } from 'react'; import type { VFC } from 'react';
import type { ExecutiveSummarySchemaProjectFlagTrendsItem } from 'openapi'; import type { InstanceInsightsSchemaProjectFlagTrendsItem } from 'openapi';
import { Box, Paper, Typography, styled } from '@mui/material'; import { Box, Paper, Typography, styled } from '@mui/material';
import { Badge } from 'component/common/Badge/Badge'; import { Badge } from 'component/common/Badge/Badge';
import type { TooltipState } from '../../../components/LineChart/ChartTooltip/ChartTooltip'; import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({ const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2), padding: theme.spacing(2),
@ -62,7 +62,7 @@ export const TimeToProductionTooltip: VFC<{ tooltip: TooltipState | null }> = ({
label: point.label, label: point.label,
title: point.dataset.label, title: point.dataset.label,
color: point.dataset.borderColor, color: point.dataset.borderColor,
value: point.raw as ExecutiveSummarySchemaProjectFlagTrendsItem, value: point.raw as InstanceInsightsSchemaProjectFlagTrendsItem,
}; };
}); });

View File

@ -1,5 +1,5 @@
import { medianTimeToProduction } from './median-time-to-production'; import { medianTimeToProduction } from './median-time-to-production';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
describe('medianTimeToProduction', () => { describe('medianTimeToProduction', () => {
it('calculates the median with a single date and an odd number of projects', () => { it('calculates the median with a single date and an odd number of projects', () => {
@ -7,7 +7,7 @@ describe('medianTimeToProduction', () => {
{ date: '2023-03-21', timeToProduction: 10 }, { date: '2023-03-21', timeToProduction: 10 },
{ date: '2023-03-21', timeToProduction: 20 }, { date: '2023-03-21', timeToProduction: 20 },
{ date: '2023-03-21', timeToProduction: 30 }, { date: '2023-03-21', timeToProduction: 30 },
] as unknown as ExecutiveSummarySchema['projectFlagTrends']; ] as unknown as InstanceInsightsSchema['projectFlagTrends'];
const expected = { '2023-03-21': 20 }; const expected = { '2023-03-21': 20 };
expect(medianTimeToProduction(projectsData)).toEqual(expected); expect(medianTimeToProduction(projectsData)).toEqual(expected);
}); });
@ -18,7 +18,7 @@ describe('medianTimeToProduction', () => {
{ date: '2023-03-22', timeToProduction: 20 }, { date: '2023-03-22', timeToProduction: 20 },
{ date: '2023-03-22', timeToProduction: 30 }, { date: '2023-03-22', timeToProduction: 30 },
{ date: '2023-03-22', timeToProduction: 40 }, { date: '2023-03-22', timeToProduction: 40 },
] as unknown as ExecutiveSummarySchema['projectFlagTrends']; ] as unknown as InstanceInsightsSchema['projectFlagTrends'];
const expected = { '2023-03-22': 25 }; const expected = { '2023-03-22': 25 };
expect(medianTimeToProduction(projectsData)).toEqual(expected); expect(medianTimeToProduction(projectsData)).toEqual(expected);
}); });
@ -31,7 +31,7 @@ describe('medianTimeToProduction', () => {
{ date: '2023-03-24', timeToProduction: 20 }, { date: '2023-03-24', timeToProduction: 20 },
{ date: '2023-03-24', timeToProduction: 30 }, { date: '2023-03-24', timeToProduction: 30 },
{ date: '2023-03-25', timeToProduction: 25 }, { date: '2023-03-25', timeToProduction: 25 },
] as unknown as ExecutiveSummarySchema['projectFlagTrends']; ] as unknown as InstanceInsightsSchema['projectFlagTrends'];
const expected = { const expected = {
'2023-03-23': 10, '2023-03-23': 10,
'2023-03-24': 20, '2023-03-24': 20,

View File

@ -1,11 +1,11 @@
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
type GroupedDataByDate<T> = Record<string, T[]>; type GroupedDataByDate<T> = Record<string, T[]>;
type DateResult<T> = Record<string, T>; type DateResult<T> = Record<string, T>;
export function medianTimeToProduction( export function medianTimeToProduction(
projectsData: ExecutiveSummarySchema['projectFlagTrends'], projectsData: InstanceInsightsSchema['projectFlagTrends'],
): DateResult<number> { ): DateResult<number> {
const groupedData: GroupedDataByDate<number> = {}; const groupedData: GroupedDataByDate<number> = {};
projectsData.forEach((item) => { projectsData.forEach((item) => {

View File

@ -2,21 +2,24 @@ import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { import type {
ExecutiveSummarySchema, InstanceInsightsSchema,
ExecutiveSummarySchemaEnvironmentTypeTrendsItem, InstanceInsightsSchemaEnvironmentTypeTrendsItem,
} from 'openapi'; } from 'openapi';
import { LineChart, NotEnoughData } from '../../components/LineChart/LineChart'; import {
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; LineChart,
NotEnoughData,
} from 'component/insights/components/LineChart/LineChart';
import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import { UpdatesPerEnvironmentTypeChartTooltip } from './UpdatesPerEnvironmentTypeChartTooltip/UpdatesPerEnvironmentTypeChartTooltip'; import { UpdatesPerEnvironmentTypeChartTooltip } from './UpdatesPerEnvironmentTypeChartTooltip/UpdatesPerEnvironmentTypeChartTooltip';
interface IUpdatesPerEnvironmnetTypeChart { interface IUpdatesPerEnvironmnetTypeChart {
environmentTypeTrends: ExecutiveSummarySchema['environmentTypeTrends']; environmentTypeTrends: InstanceInsightsSchema['environmentTypeTrends'];
isLoading?: boolean; isLoading?: boolean;
} }
const groupByDate = ( const groupByDate = (
items: ExecutiveSummarySchemaEnvironmentTypeTrendsItem[], items: InstanceInsightsSchemaEnvironmentTypeTrendsItem[],
): Record<string, ExecutiveSummarySchemaEnvironmentTypeTrendsItem[]> => { ): Record<string, InstanceInsightsSchemaEnvironmentTypeTrendsItem[]> => {
if (!items) { if (!items) {
return {}; return {};
} }
@ -33,7 +36,7 @@ const groupByDate = (
return acc; return acc;
}, },
{} as Record<string, ExecutiveSummarySchemaEnvironmentTypeTrendsItem[]>, {} as Record<string, InstanceInsightsSchemaEnvironmentTypeTrendsItem[]>,
); );
return grouped; return grouped;

View File

@ -1,7 +1,7 @@
import type { VFC } from 'react'; import type { VFC } from 'react';
import type { ExecutiveSummarySchemaEnvironmentTypeTrendsItem } from 'openapi'; import type { InstanceInsightsSchemaEnvironmentTypeTrendsItem } from 'openapi';
import { Box, Divider, Paper, styled, Typography } from '@mui/material'; import { Box, Divider, Paper, styled, Typography } from '@mui/material';
import type { TooltipState } from '../../../components/LineChart/ChartTooltip/ChartTooltip'; import type { TooltipState } from 'component/insights/components/LineChart/ChartTooltip/ChartTooltip';
const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({ const StyledTooltipItemContainer = styled(Paper)(({ theme }) => ({
padding: theme.spacing(2), padding: theme.spacing(2),
@ -64,7 +64,7 @@ export const UpdatesPerEnvironmentTypeChartTooltip: VFC<{
label: point.label, label: point.label,
title: point.dataset.label, title: point.dataset.label,
color: point.dataset.borderColor, color: point.dataset.borderColor,
value: point.raw as ExecutiveSummarySchemaEnvironmentTypeTrendsItem, value: point.raw as InstanceInsightsSchemaEnvironmentTypeTrendsItem,
}; };
}); });

View File

@ -1,17 +1,17 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { import {
fillGradientPrimary, fillGradientPrimary,
LineChart, LineChart,
NotEnoughData, NotEnoughData,
} from '../../components/LineChart/LineChart'; } from 'component/insights/components/LineChart/LineChart';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
interface IUsersChartProps { interface IUsersChartProps {
userTrends: ExecutiveSummarySchema['userTrends']; userTrends: InstanceInsightsSchema['userTrends'];
isLoading?: boolean; isLoading?: boolean;
} }

View File

@ -1,14 +1,17 @@
import { useMemo, type VFC } from 'react'; import { useMemo, type VFC } from 'react';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { LineChart, NotEnoughData } from '../../components/LineChart/LineChart'; import {
import { useProjectChartData } from 'component/executiveDashboard/hooks/useProjectChartData'; LineChart,
import { usePlaceholderData } from 'component/executiveDashboard/hooks/usePlaceholderData'; NotEnoughData,
import type { GroupedDataByProject } from '../../hooks/useGroupedProjectTrends'; } from 'component/insights/components/LineChart/LineChart';
import { useProjectChartData } from 'component/insights/hooks/useProjectChartData';
import { usePlaceholderData } from 'component/insights/hooks/usePlaceholderData';
import type { GroupedDataByProject } from 'component/insights/hooks/useGroupedProjectTrends';
interface IUsersPerProjectChartProps { interface IUsersPerProjectChartProps {
projectFlagTrends: GroupedDataByProject< projectFlagTrends: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>; >;
} }

View File

@ -1,6 +1,6 @@
import type { VFC } from 'react'; import type { VFC } from 'react';
import { Typography, styled } from '@mui/material'; import { Typography, styled } from '@mui/material';
import { Gauge } from '../../components/Gauge/Gauge'; import { Gauge } from 'component/insights/components/Gauge/Gauge';
const StyledContainer = styled('div')(({ theme }) => ({ const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',

View File

@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react-hooks'; import { renderHook } from '@testing-library/react-hooks';
import { useFilteredFlagsSummary } from './useFilteredFlagsSummary'; import { useFilteredFlagsSummary } from './useFilteredFlagsSummary';
import type { ExecutiveSummarySchemaUsers } from '../../../openapi'; import type { InstanceInsightsSchemaUsers } from 'openapi';
describe('useFilteredFlagTrends', () => { describe('useFilteredFlagTrends', () => {
it('should summarize only last week of project flag trends', () => { it('should summarize only last week of project flag trends', () => {
@ -48,7 +48,7 @@ describe('useFilteredFlagTrends', () => {
date: '', date: '',
}, },
], ],
{ total: 1 } as unknown as ExecutiveSummarySchemaUsers, { total: 1 } as unknown as InstanceInsightsSchemaUsers,
), ),
); );
@ -78,7 +78,7 @@ describe('useFilteredFlagTrends', () => {
date: '', date: '',
}, },
], ],
{ total: 1 } as unknown as ExecutiveSummarySchemaUsers, { total: 1 } as unknown as InstanceInsightsSchemaUsers,
), ),
); );
@ -118,7 +118,7 @@ describe('useFilteredFlagTrends', () => {
date: '', date: '',
}, },
], ],
{ total: 1 } as unknown as ExecutiveSummarySchemaUsers, { total: 1 } as unknown as InstanceInsightsSchemaUsers,
), ),
); );
@ -148,7 +148,7 @@ describe('useFilteredFlagTrends', () => {
date: '', date: '',
}, },
], ],
{ total: 1 } as unknown as ExecutiveSummarySchemaUsers, { total: 1 } as unknown as InstanceInsightsSchemaUsers,
), ),
); );

View File

@ -1,13 +1,13 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { import type {
ExecutiveSummarySchemaProjectFlagTrendsItem, InstanceInsightsSchemaProjectFlagTrendsItem,
ExecutiveSummarySchemaUsers, InstanceInsightsSchemaUsers,
} from 'openapi'; } from 'openapi';
// NOTE: should we move project filtering to the backend? // NOTE: should we move project filtering to the backend?
export const useFilteredFlagsSummary = ( export const useFilteredFlagsSummary = (
filteredProjectFlagTrends: ExecutiveSummarySchemaProjectFlagTrendsItem[], filteredProjectFlagTrends: InstanceInsightsSchemaProjectFlagTrendsItem[],
users: ExecutiveSummarySchemaUsers, users: InstanceInsightsSchemaUsers,
) => ) =>
useMemo(() => { useMemo(() => {
const lastWeekId = filteredProjectFlagTrends.reduce((prev, current) => { const lastWeekId = filteredProjectFlagTrends.reduce((prev, current) => {

View File

@ -1,12 +1,12 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { useFilteredTrends } from './useFilteredTrends'; import { useFilteredTrends } from './useFilteredTrends';
import { useGroupedProjectTrends } from './useGroupedProjectTrends'; import { useGroupedProjectTrends } from './useGroupedProjectTrends';
import { useFilteredFlagsSummary } from './useFilteredFlagsSummary'; import { useFilteredFlagsSummary } from './useFilteredFlagsSummary';
import { useMedianTimeToProduction } from './useMedianTimeToProduction'; import { useMedianTimeToProduction } from './useMedianTimeToProduction';
export const useDashboardData = ( export const useInsightsData = (
executiveDashboardData: ExecutiveSummarySchema, executiveDashboardData: InstanceInsightsSchema,
projects: string[], projects: string[],
) => { ) => {
const projectsData = useFilteredTrends( const projectsData = useFilteredTrends(

View File

@ -1,16 +1,16 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { import type {
ExecutiveSummarySchema, InstanceInsightsSchema,
ExecutiveSummarySchemaProjectFlagTrendsItem, InstanceInsightsSchemaProjectFlagTrendsItem,
} from 'openapi'; } from 'openapi';
import type { GroupedDataByProject } from './useGroupedProjectTrends'; import type { GroupedDataByProject } from './useGroupedProjectTrends';
const validTrend = (trend: ExecutiveSummarySchemaProjectFlagTrendsItem) => const validTrend = (trend: InstanceInsightsSchemaProjectFlagTrendsItem) =>
Boolean(trend) && Boolean(trend.timeToProduction); Boolean(trend) && Boolean(trend.timeToProduction);
export const useMedianTimeToProduction = ( export const useMedianTimeToProduction = (
projectsData: GroupedDataByProject< projectsData: GroupedDataByProject<
ExecutiveSummarySchema['projectFlagTrends'] InstanceInsightsSchema['projectFlagTrends']
>, >,
) => ) =>
useMemo(() => { useMemo(() => {

View File

@ -1,10 +1,10 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { useProjectColor } from './useProjectColor'; import { useProjectColor } from './useProjectColor';
import type { GroupedDataByProject } from './useGroupedProjectTrends'; import type { GroupedDataByProject } from './useGroupedProjectTrends';
type MetricsSummaryTrends = ExecutiveSummarySchema['metricsSummaryTrends']; type MetricsSummaryTrends = InstanceInsightsSchema['metricsSummaryTrends'];
export const useMetricsSummary = ( export const useMetricsSummary = (
metricsSummaryTrends: GroupedDataByProject<MetricsSummaryTrends>, metricsSummaryTrends: GroupedDataByProject<MetricsSummaryTrends>,

View File

@ -1,10 +1,10 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
import { useProjectColor } from './useProjectColor'; import { useProjectColor } from './useProjectColor';
import { useTheme } from '@mui/material'; import { useTheme } from '@mui/material';
import type { GroupedDataByProject } from './useGroupedProjectTrends'; import type { GroupedDataByProject } from './useGroupedProjectTrends';
type ProjectFlagTrends = ExecutiveSummarySchema['projectFlagTrends']; type ProjectFlagTrends = InstanceInsightsSchema['projectFlagTrends'];
export const useProjectChartData = ( export const useProjectChartData = (
projectFlagTrends: GroupedDataByProject<ProjectFlagTrends>, projectFlagTrends: GroupedDataByProject<ProjectFlagTrends>,

View File

@ -44,7 +44,7 @@ import { FeatureTypesList } from 'component/featureTypes/FeatureTypesList';
import { ViewIntegration } from 'component/integrations/ViewIntegration/ViewIntegration'; import { ViewIntegration } from 'component/integrations/ViewIntegration/ViewIntegration';
import { PaginatedApplicationList } from '../application/ApplicationList/PaginatedApplicationList'; import { PaginatedApplicationList } from '../application/ApplicationList/PaginatedApplicationList';
import { AddonRedirect } from 'component/integrations/AddonRedirect/AddonRedirect'; import { AddonRedirect } from 'component/integrations/AddonRedirect/AddonRedirect';
import { ExecutiveDashboard } from 'component/executiveDashboard/ExecutiveDashboard'; import { Insights } from '../insights/Insights';
import { FeedbackList } from '../feedbackNew/FeedbackList'; import { FeedbackList } from '../feedbackNew/FeedbackList';
import { Application } from 'component/application/Application'; import { Application } from 'component/application/Application';
import { Signals } from 'component/signals/Signals'; import { Signals } from 'component/signals/Signals';
@ -64,7 +64,7 @@ export const routes: IRoute[] = [
{ {
path: '/insights', path: '/insights',
title: 'Insights', title: 'Insights',
component: ExecutiveDashboard, component: Insights,
type: 'protected', type: 'protected',
menu: { mobile: true }, menu: { mobile: true },
flag: 'executiveDashboardUI', flag: 'executiveDashboardUI',

View File

@ -2,32 +2,32 @@ import useSWR, { mutate, type SWRConfiguration } from 'swr';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { formatApiPath } from 'utils/formatPath'; import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler'; import handleErrorResponses from '../httpErrorResponseHandler';
import type { ExecutiveSummarySchema } from 'openapi'; import type { InstanceInsightsSchema } from 'openapi';
interface IUseExecutiveDashboardDataOutput { interface IUseInsightsDataOutput {
executiveDashboardData: ExecutiveSummarySchema; insights: InstanceInsightsSchema;
refetchExecutiveDashboard: () => void; refetchInsights: () => void;
loading: boolean; loading: boolean;
error?: Error; error?: Error;
} }
export const useExecutiveDashboard = ( export const useInsights = (
options?: SWRConfiguration, options?: SWRConfiguration,
): IUseExecutiveDashboardDataOutput => { ): IUseInsightsDataOutput => {
const path = formatApiPath('api/admin/dashboard/executive'); const path = formatApiPath('api/admin/dashboard/executive');
const { data, error } = useSWR<ExecutiveSummarySchema>( const { data, error } = useSWR<InstanceInsightsSchema>(
path, path,
fetchExecutiveDashboard, fetchExecutiveDashboard,
options, options,
); );
const refetchExecutiveDashboard = useCallback(() => { const refetchInsights = useCallback(() => {
mutate(path).catch(console.warn); mutate(path).catch(console.warn);
}, [path]); }, [path]);
return { return {
executiveDashboardData: data || { insights: data || {
users: { total: 0, inactive: 0, active: 0 }, users: { total: 0, inactive: 0, active: 0 },
flags: { total: 0 }, flags: { total: 0 },
userTrends: [], userTrends: [],
@ -36,7 +36,7 @@ export const useExecutiveDashboard = (
metricsSummaryTrends: [], metricsSummaryTrends: [],
environmentTypeTrends: [], environmentTypeTrends: [],
}, },
refetchExecutiveDashboard, refetchInsights,
loading: !error && !data, loading: !error && !data,
error, error,
}; };
@ -44,7 +44,7 @@ export const useExecutiveDashboard = (
const fetchExecutiveDashboard = ( const fetchExecutiveDashboard = (
path: string, path: string,
): Promise<ExecutiveSummarySchema> => { ): Promise<InstanceInsightsSchema> => {
return fetch(path) return fetch(path)
.then(handleErrorResponses('Executive Dashboard Data')) .then(handleErrorResponses('Executive Dashboard Data'))
.then((res) => res.json()); .then((res) => res.json());

View File

@ -1,32 +0,0 @@
/**
* Generated by Orval
* Do not edit manually.
* See `gen:api` script in package.json
*/
import type { ExecutiveSummarySchemaEnvironmentTypeTrendsItem } from './executiveSummarySchemaEnvironmentTypeTrendsItem';
import type { ExecutiveSummarySchemaFlags } from './executiveSummarySchemaFlags';
import type { ExecutiveSummarySchemaFlagTrendsItem } from './executiveSummarySchemaFlagTrendsItem';
import type { ExecutiveSummarySchemaMetricsSummaryTrendsItem } from './executiveSummarySchemaMetricsSummaryTrendsItem';
import type { ExecutiveSummarySchemaProjectFlagTrendsItem } from './executiveSummarySchemaProjectFlagTrendsItem';
import type { ExecutiveSummarySchemaUsers } from './executiveSummarySchemaUsers';
import type { ExecutiveSummarySchemaUserTrendsItem } from './executiveSummarySchemaUserTrendsItem';
/**
* Executive summary of Unleash usage
*/
export interface ExecutiveSummarySchema {
/** How updates per environment type changed over time */
environmentTypeTrends: ExecutiveSummarySchemaEnvironmentTypeTrendsItem[];
/** High level flag count statistics */
flags: ExecutiveSummarySchemaFlags;
/** How number of flags changed over time */
flagTrends: ExecutiveSummarySchemaFlagTrendsItem[];
/** 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 */
users: ExecutiveSummarySchemaUsers;
/** How number of users changed over time */
userTrends: ExecutiveSummarySchemaUserTrendsItem[];
}

View File

@ -521,14 +521,6 @@ export * from './eventSchemaPreData';
export * from './eventSchemaType'; export * from './eventSchemaType';
export * from './eventsSchema'; export * from './eventsSchema';
export * from './eventsSchemaVersion'; export * from './eventsSchemaVersion';
export * from './executiveSummarySchema';
export * from './executiveSummarySchemaEnvironmentTypeTrendsItem';
export * from './executiveSummarySchemaFlagTrendsItem';
export * from './executiveSummarySchemaFlags';
export * from './executiveSummarySchemaMetricsSummaryTrendsItem';
export * from './executiveSummarySchemaProjectFlagTrendsItem';
export * from './executiveSummarySchemaUserTrendsItem';
export * from './executiveSummarySchemaUsers';
export * from './exportFeatures404'; export * from './exportFeatures404';
export * from './exportQuerySchema'; export * from './exportQuerySchema';
export * from './exportQuerySchemaAnyOf'; export * from './exportQuerySchemaAnyOf';
@ -770,6 +762,14 @@ export * from './instanceAdminStatsSchemaClientAppsItem';
export * from './instanceAdminStatsSchemaClientAppsItemRange'; export * from './instanceAdminStatsSchemaClientAppsItemRange';
export * from './instanceAdminStatsSchemaPreviousDayMetricsBucketsCount'; export * from './instanceAdminStatsSchemaPreviousDayMetricsBucketsCount';
export * from './instanceAdminStatsSchemaProductionChanges'; export * from './instanceAdminStatsSchemaProductionChanges';
export * from './instanceInsightsSchema';
export * from './instanceInsightsSchemaEnvironmentTypeTrendsItem';
export * from './instanceInsightsSchemaFlagTrendsItem';
export * from './instanceInsightsSchemaFlags';
export * from './instanceInsightsSchemaMetricsSummaryTrendsItem';
export * from './instanceInsightsSchemaProjectFlagTrendsItem';
export * from './instanceInsightsSchemaUserTrendsItem';
export * from './instanceInsightsSchemaUsers';
export * from './invoicesSchema'; export * from './invoicesSchema';
export * from './invoicesSchemaItem'; export * from './invoicesSchemaItem';
export * from './legalValueSchema'; export * from './legalValueSchema';

View File

@ -0,0 +1,32 @@
/**
* Generated by Orval
* Do not edit manually.
* 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';
/**
* A summary of this Unleash instance's usage statistics, including user and flag counts, and trends over time.
*/
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[];
}

View File

@ -4,7 +4,7 @@
* See `gen:api` script in package.json * See `gen:api` script in package.json
*/ */
export type ExecutiveSummarySchemaEnvironmentTypeTrendsItem = { export type InstanceInsightsSchemaEnvironmentTypeTrendsItem = {
/** A UTC date when the stats were captured. Time is the very end of a given day. */ /** A UTC date when the stats were captured. Time is the very end of a given day. */
date: string; date: string;
/** Environment type the data belongs too */ /** Environment type the data belongs too */

View File

@ -4,7 +4,7 @@
* See `gen:api` script in package.json * See `gen:api` script in package.json
*/ */
export type ExecutiveSummarySchemaFlagTrendsItem = { export type InstanceInsightsSchemaFlagTrendsItem = {
/** The number of active flags on a particular day */ /** The number of active flags on a particular day */
active: number; active: number;
/** A UTC date when the stats were captured. Time is the very end of a given day. */ /** A UTC date when the stats were captured. Time is the very end of a given day. */

View File

@ -7,7 +7,7 @@
/** /**
* High level flag count statistics * High level flag count statistics
*/ */
export type ExecutiveSummarySchemaFlags = { export type InstanceInsightsSchemaFlags = {
/** The number of non-archived flags */ /** The number of non-archived flags */
total: number; total: number;
}; };

View File

@ -4,7 +4,7 @@
* See `gen:api` script in package.json * See `gen:api` script in package.json
*/ */
export type ExecutiveSummarySchemaMetricsSummaryTrendsItem = { export type InstanceInsightsSchemaMetricsSummaryTrendsItem = {
/** A UTC date when metrics summary was captured. Time is the very end of a given day. */ /** A UTC date when metrics summary was captured. Time is the very end of a given day. */
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

@ -4,7 +4,7 @@
* See `gen:api` script in package.json * See `gen:api` script in package.json
*/ */
export type ExecutiveSummarySchemaProjectFlagTrendsItem = { export type InstanceInsightsSchemaProjectFlagTrendsItem = {
/** The number of active flags on a particular day */ /** The number of active flags on a particular day */
active: number; active: number;
/** A UTC date when the stats were captured. Time is the very end of a given day. */ /** A UTC date when the stats were captured. Time is the very end of a given day. */

View File

@ -4,7 +4,7 @@
* See `gen:api` script in package.json * See `gen:api` script in package.json
*/ */
export type ExecutiveSummarySchemaUserTrendsItem = { export type InstanceInsightsSchemaUserTrendsItem = {
/** The number of active Unleash users on a particular day */ /** The number of active Unleash users on a particular day */
active: number; active: number;
/** A UTC date when the stats were captured. Time is the very end of a given day. */ /** A UTC date when the stats were captured. Time is the very end of a given day. */

View File

@ -7,7 +7,7 @@
/** /**
* High level user count statistics * High level user count statistics
*/ */
export type ExecutiveSummarySchemaUsers = { export type InstanceInsightsSchemaUsers = {
/** The number of active Unleash users who have user Unleash in the past 60 days */ /** The number of active Unleash users who have user Unleash in the past 60 days */
active: number; active: number;
/** The number of inactive Unleash users who have not used Unleash in the past 60 days. */ /** The number of inactive Unleash users who have not used Unleash in the past 60 days. */