diff --git a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
index d3527b1cf7..a5fdc851a8 100644
--- a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
+++ b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
@@ -18,6 +18,19 @@ const StyledGrid = styled(Box)(({ theme }) => ({
export const ExecutiveDashboard: VFC = () => {
const { executiveDashboardData, loading, error } = useExecutiveDashboard();
+ const calculateFlagPerUsers = () => {
+ if (
+ executiveDashboardData.users.total === 0 ||
+ executiveDashboardData.flags.total === 0
+ )
+ return '0';
+
+ return (
+ executiveDashboardData.flags.total /
+ executiveDashboardData.users.total
+ ).toFixed(1);
+ };
+
return (
<>
({ paddingBottom: theme.spacing(4) })}>
@@ -30,14 +43,13 @@ export const ExecutiveDashboard: VFC = () => {
/>
-
-
-
-
+
+
+
>
);
diff --git a/frontend/src/component/executiveDashboard/FlagStats/FlagStats.tsx b/frontend/src/component/executiveDashboard/FlagStats/FlagStats.tsx
index 693c6e8091..846933254a 100644
--- a/frontend/src/component/executiveDashboard/FlagStats/FlagStats.tsx
+++ b/frontend/src/component/executiveDashboard/FlagStats/FlagStats.tsx
@@ -78,7 +78,15 @@ const StyledSettingsIcon = styled(Settings)(({ theme }) => ({
marginRight: theme.spacing(0.5),
}));
-export const FlagStats = () => {
+interface IFlagStatsProps {
+ count: number;
+ flagsPerUser: string;
+}
+
+export const FlagStats: React.FC = ({
+ count,
+ flagsPerUser,
+}) => {
return (
@@ -98,7 +106,7 @@ export const FlagStats = () => {
- 9999
+ {count}
@@ -116,7 +124,7 @@ export const FlagStats = () => {
Flags per user
- 3.5
+ {flagsPerUser}
);
diff --git a/frontend/src/component/executiveDashboard/FlagsChart/FlagsChartComponent.tsx b/frontend/src/component/executiveDashboard/FlagsChart/FlagsChartComponent.tsx
index 25e0e05adb..0f81ad499d 100644
--- a/frontend/src/component/executiveDashboard/FlagsChart/FlagsChartComponent.tsx
+++ b/frontend/src/component/executiveDashboard/FlagsChart/FlagsChartComponent.tsx
@@ -22,27 +22,27 @@ import { ExecutiveSummarySchema } from 'openapi';
const createData = (
theme: Theme,
- flagsTrends: ExecutiveSummarySchema['flagsTrends'] = [],
+ flagTrends: ExecutiveSummarySchema['flagTrends'] = [],
) => ({
- labels: flagsTrends.map((item) => item.date),
+ labels: flagTrends.map((item) => item.date),
datasets: [
{
label: 'Total flags',
- data: flagsTrends.map((item) => item.total),
+ data: flagTrends.map((item) => item.total),
borderColor: theme.palette.primary.main,
backgroundColor: theme.palette.primary.main,
fill: true,
},
{
- label: 'Archived flags',
- data: flagsTrends.map((item) => item.archived),
- borderColor: theme.palette.error.main,
- backgroundColor: theme.palette.error.main,
+ label: 'Stale',
+ data: flagTrends.map((item) => item.stale),
+ borderColor: theme.palette.warning.main,
+ backgroundColor: theme.palette.warning.main,
fill: true,
},
{
label: 'Active flags',
- data: flagsTrends.map((item) => item.active),
+ data: flagTrends.map((item) => item.active),
borderColor: theme.palette.success.main,
backgroundColor: theme.palette.success.main,
fill: true,
@@ -102,17 +102,17 @@ const createOptions = (theme: Theme, locationSettings: ILocationSettings) =>
}) as const;
interface IFlagsChartComponentProps {
- flagsTrends: ExecutiveSummarySchema['flagsTrends'];
+ flagTrends: ExecutiveSummarySchema['flagTrends'];
}
const FlagsChartComponent: VFC = ({
- flagsTrends,
+ flagTrends,
}) => {
const theme = useTheme();
const { locationSettings } = useLocationSettings();
const data = useMemo(
- () => createData(theme, flagsTrends),
- [theme, flagsTrends],
+ () => createData(theme, flagTrends),
+ [theme, flagTrends],
);
const options = createOptions(theme, locationSettings);
diff --git a/frontend/src/component/executiveDashboard/UserStats/UserStats.tsx b/frontend/src/component/executiveDashboard/UserStats/UserStats.tsx
index 0f13f64b06..4291e75d34 100644
--- a/frontend/src/component/executiveDashboard/UserStats/UserStats.tsx
+++ b/frontend/src/component/executiveDashboard/UserStats/UserStats.tsx
@@ -1,5 +1,8 @@
import { ChevronRight } from '@mui/icons-material';
import { Box, Typography, styled } from '@mui/material';
+import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
+import { useUiFlag } from 'hooks/useUiFlag';
+import React from 'react';
import { Link } from 'react-router-dom';
const StyledContent = styled(Box)(({ theme }) => ({
@@ -73,40 +76,59 @@ const StyledLink = styled(Link)({
justifyContent: 'center',
});
-export const UserStats = () => {
+interface IUserStatsProps {
+ count: number;
+}
+
+export const UserStats: React.FC = ({ count }) => {
+ const showInactiveUsers = useUiFlag('showInactiveUsers');
+
return (
-
- Total users
-
-
- 9999
-
-
-
+ <>
+
+
+ Total users
+
+
+
+ {count}
+
+
+
+
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
+ >
+ }
+ />
-
-
- View users
-
-
-
+
+
+ View users
+
+
+
+
+ >
);
};
diff --git a/frontend/src/hooks/api/getters/useExecutiveSummary/useExecutiveSummary.ts b/frontend/src/hooks/api/getters/useExecutiveSummary/useExecutiveSummary.ts
index 74b9780d70..9a29d66071 100644
--- a/frontend/src/hooks/api/getters/useExecutiveSummary/useExecutiveSummary.ts
+++ b/frontend/src/hooks/api/getters/useExecutiveSummary/useExecutiveSummary.ts
@@ -5,7 +5,7 @@ import handleErrorResponses from '../httpErrorResponseHandler';
import { ExecutiveSummarySchema } from 'openapi';
interface IUseExecutiveDashboardDataOutput {
- executiveDashboardData: ExecutiveSummarySchema | undefined;
+ executiveDashboardData: ExecutiveSummarySchema;
refetchExecutiveDashboard: () => void;
loading: boolean;
error?: Error;
@@ -27,7 +27,12 @@ export const useExecutiveDashboard = (
}, [path]);
return {
- executiveDashboardData: data,
+ executiveDashboardData: data || {
+ users: { total: 0, inactive: 0, active: 0 },
+ flags: { total: 0 },
+ userTrends: [],
+ flagTrends: [],
+ },
refetchExecutiveDashboard,
loading: !error && !data,
error,
diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts
index 3562790a0d..4e008270ba 100644
--- a/frontend/src/interfaces/uiConfig.ts
+++ b/frontend/src/interfaces/uiConfig.ts
@@ -80,6 +80,7 @@ export type UiFlags = {
changeRequestConflictHandling?: boolean;
feedbackComments?: Variant;
displayUpgradeEdgeBanner?: boolean;
+ showInactiveUsers?: boolean;
};
export interface IVersionInfo {
diff --git a/frontend/src/openapi/models/actionsListSchema.ts b/frontend/src/openapi/models/actionsListSchema.ts
index 9147746926..c541c92802 100644
--- a/frontend/src/openapi/models/actionsListSchema.ts
+++ b/frontend/src/openapi/models/actionsListSchema.ts
@@ -3,12 +3,12 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
-import type { CreateActionsSchema } from './createActionsSchema';
+import type { ActionsSchema } from './actionsSchema';
/**
* A response model with a list of action sets.
*/
export interface ActionsListSchema {
/** A list of action sets. */
- actions: CreateActionsSchema[];
+ actions: ActionsSchema[];
}
diff --git a/frontend/src/openapi/models/actionsSchema.ts b/frontend/src/openapi/models/actionsSchema.ts
index 43155306e1..b5c9de16a5 100644
--- a/frontend/src/openapi/models/actionsSchema.ts
+++ b/frontend/src/openapi/models/actionsSchema.ts
@@ -18,6 +18,8 @@ export interface ActionsSchema {
createdAt?: string;
/** The id of user that created this action set */
createdByUserId?: number;
+ /** Whether this action set is enabled or not */
+ enabled?: boolean;
/** The id of the action set */
id: number;
/** Defines a matching rule for the observable event that will trigger the action set */
diff --git a/frontend/src/openapi/models/createActionsSchema.ts b/frontend/src/openapi/models/createActionsSchema.ts
index 41a07bdcdf..e2829c9250 100644
--- a/frontend/src/openapi/models/createActionsSchema.ts
+++ b/frontend/src/openapi/models/createActionsSchema.ts
@@ -14,6 +14,8 @@ export interface CreateActionsSchema {
actions: CreateActionSchema[];
/** The id of the service account that will execute the action */
actorId: number;
+ /** Whether this action set is enabled or not */
+ enabled?: boolean;
/** Defines a matching rule for the observable event that will trigger the action set */
match: CreateActionsSchemaMatch;
/** The name of the action set */
diff --git a/frontend/src/openapi/models/executiveSummarySchema.ts b/frontend/src/openapi/models/executiveSummarySchema.ts
index 34de0c32a5..fec4155686 100644
--- a/frontend/src/openapi/models/executiveSummarySchema.ts
+++ b/frontend/src/openapi/models/executiveSummarySchema.ts
@@ -3,20 +3,21 @@
* Do not edit manually.
* See `gen:api` script in package.json
*/
-import type { ExecutiveSummarySchemaFlagsTrendsItem } from './executiveSummarySchemaFlagsTrendsItem';
-import type { ExecutiveSummarySchemaUserStats } from './executiveSummarySchemaUserStats';
+import type { ExecutiveSummarySchemaFlags } from './executiveSummarySchemaFlags';
+import type { ExecutiveSummarySchemaFlagTrendsItem } from './executiveSummarySchemaFlagTrendsItem';
+import type { ExecutiveSummarySchemaUsers } from './executiveSummarySchemaUsers';
import type { ExecutiveSummarySchemaUserTrendsItem } from './executiveSummarySchemaUserTrendsItem';
/**
* Executive summary of Unleash usage
*/
export interface ExecutiveSummarySchema {
+ /** High level flag count statistics */
+ flags: ExecutiveSummarySchemaFlags;
/** How number of flags changed over time */
- flagsTrends: ExecutiveSummarySchemaFlagsTrendsItem[];
- /** The type of single-sign option configured for the Unleash instance */
- ssoType?: string;
+ flagTrends: ExecutiveSummarySchemaFlagTrendsItem[];
/** High level user count statistics */
- userStats: ExecutiveSummarySchemaUserStats;
+ users: ExecutiveSummarySchemaUsers;
/** How number of users changed over time */
userTrends: ExecutiveSummarySchemaUserTrendsItem[];
}
diff --git a/frontend/src/openapi/models/executiveSummarySchemaFlagTrendsItem.ts b/frontend/src/openapi/models/executiveSummarySchemaFlagTrendsItem.ts
new file mode 100644
index 0000000000..72de2a7849
--- /dev/null
+++ b/frontend/src/openapi/models/executiveSummarySchemaFlagTrendsItem.ts
@@ -0,0 +1,18 @@
+/**
+ * Generated by Orval
+ * Do not edit manually.
+ * See `gen:api` script in package.json
+ */
+
+export type ExecutiveSummarySchemaFlagTrendsItem = {
+ /** 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;
+ /** The number of time calculated potentially stale flags on a particular day */
+ potentiallyStale?: number;
+ /** The number of user marked stale flags on a particular day */
+ stale: number;
+ /** The number of all flags on a particular day */
+ total: number;
+};
diff --git a/frontend/src/openapi/models/executiveSummarySchemaFlags.ts b/frontend/src/openapi/models/executiveSummarySchemaFlags.ts
new file mode 100644
index 0000000000..2a069ff9c3
--- /dev/null
+++ b/frontend/src/openapi/models/executiveSummarySchemaFlags.ts
@@ -0,0 +1,13 @@
+/**
+ * Generated by Orval
+ * Do not edit manually.
+ * See `gen:api` script in package.json
+ */
+
+/**
+ * High level flag count statistics
+ */
+export type ExecutiveSummarySchemaFlags = {
+ /** The number of non-archived flags */
+ total: number;
+};
diff --git a/frontend/src/openapi/models/executiveSummarySchemaFlagsTrendsItem.ts b/frontend/src/openapi/models/executiveSummarySchemaFlagsTrendsItem.ts
deleted file mode 100644
index c375526011..0000000000
--- a/frontend/src/openapi/models/executiveSummarySchemaFlagsTrendsItem.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Generated by Orval
- * Do not edit manually.
- * See `gen:api` script in package.json
- */
-
-export type ExecutiveSummarySchemaFlagsTrendsItem = {
- /** The number of non-archived flags on a particular day */
- active: number;
- /** The number of archived flags on a particular day */
- archived: number;
- /** A UTC date when the stats were captured. Time is the very end of a given day. */
- date: string;
- /** The number of all flags on a particular day */
- total: number;
-};
diff --git a/frontend/src/openapi/models/executiveSummarySchemaUserStats.ts b/frontend/src/openapi/models/executiveSummarySchemaUserStats.ts
deleted file mode 100644
index 1f65dfdcef..0000000000
--- a/frontend/src/openapi/models/executiveSummarySchemaUserStats.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Generated by Orval
- * Do not edit manually.
- * See `gen:api` script in package.json
- */
-import type { ExecutiveSummarySchemaUserStatsRoles } from './executiveSummarySchemaUserStatsRoles';
-
-/**
- * High level user count statistics
- */
-export type ExecutiveSummarySchemaUserStats = {
- /** The number of active Unleash users who have logged in in the past 90 days */
- active: number;
- /** The number of inactive Unleash users who have not logged in in the past 90 days. */
- inactive: number;
- /** The number of users licensed to use Unleash */
- licensed: number;
- /** The number of users with a given [root role](https://docs.getunleash.io/reference/rbac#predefined-roles) */
- roles: ExecutiveSummarySchemaUserStatsRoles;
- /** The number of actual Unleash users */
- total: number;
-};
diff --git a/frontend/src/openapi/models/executiveSummarySchemaUserStatsRoles.ts b/frontend/src/openapi/models/executiveSummarySchemaUserStatsRoles.ts
deleted file mode 100644
index 67f0bd17c0..0000000000
--- a/frontend/src/openapi/models/executiveSummarySchemaUserStatsRoles.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Generated by Orval
- * Do not edit manually.
- * See `gen:api` script in package.json
- */
-
-/**
- * The number of users with a given [root role](https://docs.getunleash.io/reference/rbac#predefined-roles)
- */
-export type ExecutiveSummarySchemaUserStatsRoles = {
- /** The number of users with the `admin` root role */
- admin: number;
- /** The number of users with the `editor` root role */
- editor: number;
- /** The number of users with the `viewer` root role */
- viewer: number;
-};
diff --git a/frontend/src/openapi/models/executiveSummarySchemaUsers.ts b/frontend/src/openapi/models/executiveSummarySchemaUsers.ts
new file mode 100644
index 0000000000..a524856f28
--- /dev/null
+++ b/frontend/src/openapi/models/executiveSummarySchemaUsers.ts
@@ -0,0 +1,17 @@
+/**
+ * Generated by Orval
+ * Do not edit manually.
+ * See `gen:api` script in package.json
+ */
+
+/**
+ * High level user count statistics
+ */
+export type ExecutiveSummarySchemaUsers = {
+ /** The number of active Unleash users who have user Unleash in the past 60 days */
+ active: number;
+ /** The number of inactive Unleash users who have not used Unleash in the past 60 days. */
+ inactive: number;
+ /** The number of actual Unleash users */
+ total: number;
+};
diff --git a/frontend/src/openapi/models/index.ts b/frontend/src/openapi/models/index.ts
index 7449137a17..3732a99d7e 100644
--- a/frontend/src/openapi/models/index.ts
+++ b/frontend/src/openapi/models/index.ts
@@ -495,10 +495,10 @@ export * from './eventSchemaType';
export * from './eventsSchema';
export * from './eventsSchemaVersion';
export * from './executiveSummarySchema';
-export * from './executiveSummarySchemaFlagsTrendsItem';
-export * from './executiveSummarySchemaUserStats';
-export * from './executiveSummarySchemaUserStatsRoles';
+export * from './executiveSummarySchemaFlagTrendsItem';
+export * from './executiveSummarySchemaFlags';
export * from './executiveSummarySchemaUserTrendsItem';
+export * from './executiveSummarySchemaUsers';
export * from './exportFeatures404';
export * from './exportQuerySchema';
export * from './exportQuerySchemaAnyOf';
diff --git a/frontend/src/openapi/models/playgroundFeatureSchemaVariant.ts b/frontend/src/openapi/models/playgroundFeatureSchemaVariant.ts
index 7d551c45e8..b38113ed67 100644
--- a/frontend/src/openapi/models/playgroundFeatureSchemaVariant.ts
+++ b/frontend/src/openapi/models/playgroundFeatureSchemaVariant.ts
@@ -14,6 +14,13 @@ import type { PlaygroundFeatureSchemaVariantPayload } from './playgroundFeatureS
export type PlaygroundFeatureSchemaVariant = {
/** Whether the variant is enabled or not. If the feature is disabled or if it doesn't have variants, this property will be `false` */
enabled: boolean;
+ /** Use `featureEnabled` instead. */
+ feature_enabled?: boolean;
+ /**
+ * Whether the feature is enabled or not.
+ * @deprecated
+ */
+ featureEnabled?: boolean;
/** The variant's name. If there is no variant or if the toggle is disabled, this will be `disabled` */
name: string;
/** An optional payload attached to the variant. */
diff --git a/frontend/src/openapi/models/projectSchema.ts b/frontend/src/openapi/models/projectSchema.ts
index 9df5784694..86fe979673 100644
--- a/frontend/src/openapi/models/projectSchema.ts
+++ b/frontend/src/openapi/models/projectSchema.ts
@@ -29,6 +29,10 @@ export interface ProjectSchema {
mode?: ProjectSchemaMode;
/** The name of this project */
name: string;
+ /** The number of potentially stale features this project has */
+ potentiallyStaleFeatureCount?: number;
+ /** The number of stale features this project has */
+ staleFeatureCount?: number;
/** When this project was last updated. */
updatedAt?: string | null;
}
diff --git a/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts b/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts
index 143aaa8e0b..47164856db 100644
--- a/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts
+++ b/frontend/src/openapi/models/proxyFeatureSchemaVariant.ts
@@ -13,6 +13,11 @@ export type ProxyFeatureSchemaVariant = {
enabled: boolean;
/** Whether the feature is enabled or not. */
feature_enabled?: boolean;
+ /**
+ * Use `feature_enabled` instead.
+ * @deprecated
+ */
+ featureEnabled?: boolean;
/** The variants name. Is unique for this feature toggle */
name: string;
/** Extra data configured for this variant */
diff --git a/frontend/src/openapi/models/variantFlagSchema.ts b/frontend/src/openapi/models/variantFlagSchema.ts
index e2472e2ee1..a88b346fe1 100644
--- a/frontend/src/openapi/models/variantFlagSchema.ts
+++ b/frontend/src/openapi/models/variantFlagSchema.ts
@@ -13,6 +13,11 @@ export interface VariantFlagSchema {
enabled?: boolean;
/** Whether the feature is enabled or not. */
feature_enabled?: boolean;
+ /**
+ * Use `feature_enabled` instead.
+ * @deprecated
+ */
+ featureEnabled?: boolean;
/** The name of the variant. Will always be disabled if `enabled` is false. */
name?: string;
/** Additional data associated with this variant. */
diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap
index f96b8c7962..038467708b 100644
--- a/src/lib/__snapshots__/create-config.test.ts.snap
+++ b/src/lib/__snapshots__/create-config.test.ts.snap
@@ -127,6 +127,7 @@ exports[`should create default config 1`] = `
"proPlanAutoCharge": false,
"responseTimeWithAppNameKillSwitch": false,
"scheduledConfigurationChanges": false,
+ "showInactiveUsers": false,
"strictSchemaValidation": false,
"stripClientHeadersOn304": false,
},
diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts
index 29755623ba..4fd63ab5fd 100644
--- a/src/lib/types/experimental.ts
+++ b/src/lib/types/experimental.ts
@@ -47,7 +47,8 @@ export type IFlagKey =
| 'changeRequestConflictHandling'
| 'executiveDashboard'
| 'feedbackComments'
- | 'createdByUserIdDataMigration';
+ | 'createdByUserIdDataMigration'
+ | 'showInactiveUsers';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@@ -227,6 +228,10 @@ const flags: IFlags = {
process.env.CREATED_BY_USERID_DATA_MIGRATION,
false,
),
+ showInactiveUsers: parseEnvVarBoolean(
+ process.env.UNLEASH_EXPERIMENTAL_SHOW_INACTIVE_USERS,
+ false,
+ ),
};
export const defaultExperimentalOptions: IExperimentalOptions = {