From 8955a9906dccfa36a0758a5ad06c3d07d821159b Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Mon, 8 Jan 2024 14:49:41 +0100 Subject: [PATCH] feat: extended metrics options ui (#5786) --- .../FeatureMetrics/FeatureMetrics.tsx | 6 +-- .../FeatureMetricsHours.test.tsx | 39 +++++++++++++++ .../FeatureMetricsHours.tsx | 47 ++++++++++++------- frontend/src/interfaces/uiConfig.ts | 1 + .../__snapshots__/create-config.test.ts.snap | 1 + src/lib/types/experimental.ts | 7 ++- 6 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.test.tsx diff --git a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetrics.tsx b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetrics.tsx index d646bc0b94..d2506a7748 100644 --- a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetrics.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetrics.tsx @@ -2,7 +2,7 @@ import { useFeatureMetricsRaw } from 'hooks/api/getters/useFeatureMetricsRaw/use import { PageContent } from 'component/common/PageContent/PageContent'; import { useEffect, useMemo, useState } from 'react'; import { - FEATURE_METRIC_HOURS_BACK_MAX, + FEATURE_METRIC_HOURS_BACK_DEFAULT, FeatureMetricsHours, } from './FeatureMetricsHours/FeatureMetricsHours'; import { IFeatureMetricsRaw } from 'interfaces/featureToggle'; @@ -23,7 +23,7 @@ export const FeatureMetrics = () => { const applications = useFeatureMetricsApplications(featureId); usePageTitle('Metrics'); - const [hoursBack = FEATURE_METRIC_HOURS_BACK_MAX, setHoursBack] = + const [hoursBack = FEATURE_METRIC_HOURS_BACK_DEFAULT, setHoursBack] = useQueryStringNumberState('hoursBack'); const { featureMetrics } = useFeatureMetricsRaw(featureId, hoursBack); @@ -118,7 +118,7 @@ const useFeatureMetricsEnvironments = ( const useFeatureMetricsApplications = (featureId: string): Set => { const { featureMetrics = [] } = useFeatureMetricsRaw( featureId, - FEATURE_METRIC_HOURS_BACK_MAX, + FEATURE_METRIC_HOURS_BACK_DEFAULT, ); const applications = featureMetrics.map((metric) => { diff --git a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.test.tsx b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.test.tsx new file mode 100644 index 0000000000..8a84e515e1 --- /dev/null +++ b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.test.tsx @@ -0,0 +1,39 @@ +import { screen, waitFor } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { testServerRoute, testServerSetup } from 'utils/testServer'; +import { FeatureMetricsHours } from './FeatureMetricsHours'; +import userEvent from '@testing-library/user-event'; + +const server = testServerSetup(); + +test('Display extended daily metrics', async () => { + testServerRoute(server, '/api/admin/ui-config', { + flags: { + extendedUsageMetrics: true, + }, + versionInfo: { + current: { oss: 'irrelevant', enterprise: 'some value' }, + }, + }); + let recordedHoursBack: number | null = null; + render( + { + recordedHoursBack = hoursBack; + }} + />, + ); + + const intialSelectedValue = await screen.findByText('Last 48 hours'); + + userEvent.click(intialSelectedValue); + + const newSelectedValue = await screen.findByText('Last week'); + + userEvent.click(newSelectedValue); + + await waitFor(() => { + expect(recordedHoursBack).toBe(7 * 24); + }); +}); diff --git a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.tsx b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.tsx index 1d0f7da96c..4482320920 100644 --- a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureMetricsHours/FeatureMetricsHours.tsx @@ -2,6 +2,9 @@ import { styled } from '@mui/material'; import GeneralSelect, { IGeneralSelectProps, } from 'component/common/GeneralSelect/GeneralSelect'; +import { subWeeks, subMonths, differenceInHours } from 'date-fns'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { useUiFlag } from 'hooks/useUiFlag'; const StyledTitle = styled('h2')(({ theme }) => ({ margin: 0, @@ -16,15 +19,21 @@ interface IFeatureMetricsHoursProps { setHoursBack: (value: number) => void; } -export const FEATURE_METRIC_HOURS_BACK_MAX = 48; +export const FEATURE_METRIC_HOURS_BACK_DEFAULT = 48; export const FeatureMetricsHours = ({ hoursBack, setHoursBack, }: IFeatureMetricsHoursProps) => { const onChange: IGeneralSelectProps['onChange'] = (key) => { - setHoursBack(parseFeatureMetricsHour(key)); + setHoursBack(parseInt(key)); }; + const { isEnterprise } = useUiConfig(); + const extendedUsageMetrics = useUiFlag('extendedUsageMetrics'); + const extendedOptions = isEnterprise() && extendedUsageMetrics; + const options = extendedOptions + ? [...hourOptions, ...daysOptions] + : hourOptions; return (
@@ -32,7 +41,7 @@ export const FeatureMetricsHours = ({ { - switch (value) { - case '1': - return 1; - case '24': - return 24; - default: - return FEATURE_METRIC_HOURS_BACK_MAX; - } -}; - const hourOptions: { key: `${number}`; label: string }[] = [ { key: '1', @@ -62,7 +60,24 @@ const hourOptions: { key: `${number}`; label: string }[] = [ label: 'Last 24 hours', }, { - key: `${FEATURE_METRIC_HOURS_BACK_MAX}`, - label: `Last ${FEATURE_METRIC_HOURS_BACK_MAX} hours`, + key: '48', + label: 'Last 48 hours', + }, +]; + +const now = new Date(); + +const daysOptions: { key: `${number}`; label: string }[] = [ + { + key: `${differenceInHours(now, subWeeks(now, 1))}`, + label: 'Last week', + }, + { + key: `${differenceInHours(now, subMonths(now, 1))}`, + label: 'Last month', + }, + { + key: `${differenceInHours(now, subMonths(now, 3))}`, + label: 'Last 3 months', }, ]; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index df75ca7733..332d563223 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -73,6 +73,7 @@ export type UiFlags = { featureSearchFeedback?: boolean; enableLicense?: boolean; newStrategyConfigurationFeedback?: boolean; + extendedUsageMetrics?: boolean; }; export interface IVersionInfo { diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index e8e30c828a..65e8849f64 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -86,6 +86,7 @@ exports[`should create default config 1`] = ` "embedProxyFrontend": true, "enableLicense": false, "encryptEmails": false, + "extendedUsageMetrics": false, "featureSearchAPI": false, "featureSearchFeedback": false, "featureSearchFeedbackPosting": false, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 63fba69aba..1f41d2f882 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -39,7 +39,8 @@ export type IFlagKey = | 'featureSearchFeedback' | 'featureSearchFeedbackPosting' | 'newStrategyConfigurationFeedback' - | 'edgeBulkMetricsKillSwitch'; + | 'edgeBulkMetricsKillSwitch' + | 'extendedUsageMetrics'; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; @@ -178,6 +179,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_EDGE_BULK_METRICS_KILL_SWITCH, false, ), + extendedUsageMetrics: parseEnvVarBoolean( + process.env.UNLEASH_EXPERIMENTAL_EXTENDED_USAGE_METRICS, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = {