From 8a9dc32badd0eb2be436ed1670c0d2635c166420 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Wed, 13 Oct 2021 10:20:34 +0200 Subject: [PATCH] Create hook for fetching featureMetrics (#414) * Create hook for fetching featureMetrics --- frontend/package.json | 4 +- .../FeatureEnvironmentMetrics.tsx | 15 +++- .../FeatureOverviewMetrics.tsx | 79 +++++-------------- .../useFeatureMetrics/useFeatureMetrics.ts | 57 +++++++++++++ frontend/src/interfaces/featureToggle.ts | 14 ++++ 5 files changed, 104 insertions(+), 65 deletions(-) create mode 100644 frontend/src/hooks/api/getters/useFeatureMetrics/useFeatureMetrics.ts diff --git a/frontend/package.json b/frontend/package.json index f7ed39dfe1..841355c1c6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -61,6 +61,7 @@ "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.6", "enzyme-to-json": "3.6.2", + "fast-json-patch": "3.1.0", "fetch-mock": "9.11.0", "http-proxy-middleware": "2.0.1", "immutable": "4.0.0", @@ -83,8 +84,7 @@ "sass": "1.42.1", "swr": "1.0.1", "typescript": "4.4.4", - "web-vitals": "2.1.2", - "fast-json-patch": "3.1.0" + "web-vitals": "2.1.2" }, "jest": { "moduleNameMapper": { diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureEnvironmentMetrics/FeatureEnvironmentMetrics.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureEnvironmentMetrics/FeatureEnvironmentMetrics.tsx index 08dbc95086..a02a307f3e 100644 --- a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureEnvironmentMetrics/FeatureEnvironmentMetrics.tsx +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureEnvironmentMetrics/FeatureEnvironmentMetrics.tsx @@ -1,13 +1,15 @@ import classNames from 'classnames'; import PercentageCircle from '../../../../common/PercentageCircle/PercentageCircle'; import { useStyles } from './FeatureEnvironmentMetrics.styles'; -import { IEnvironmentMetrics } from '../../../../../interfaces/environments'; import PieChartIcon from '@material-ui/icons/PieChart'; import { useMediaQuery } from '@material-ui/core'; +import { IFeatureEnvironmentMetrics } from '../../../../../interfaces/featureToggle'; +import { parseISO } from 'date-fns'; + interface IFeatureEnvironmentProps { className?: string; primaryMetric?: boolean; - metric: IEnvironmentMetrics; + metric: IFeatureEnvironmentMetrics; } const FeatureEnvironmentMetrics = ({ @@ -21,6 +23,11 @@ const FeatureEnvironmentMetrics = ({ const containerClasses = classNames(styles.container, className, { [styles.primaryMetric]: primaryMetric, }); + let hour = ''; + if (metric?.timestamp) { + const metricTime = parseISO(metric.timestamp); + hour = `since ${metricTime.getHours()}:${metricTime.getMinutes()}`; + } const calculatePercentage = () => { const total = metric.yes + metric.no; @@ -52,7 +59,7 @@ const FeatureEnvironmentMetrics = ({

- Traffic in {metric.name} + Traffic in {metric.environment} {hour}

@@ -75,7 +82,7 @@ const FeatureEnvironmentMetrics = ({

- Traffic in {metric.name} + Traffic in {metric.environment} {hour}

diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetrics/FeatureOverviewMetrics.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetrics/FeatureOverviewMetrics.tsx index 848a4b678e..629f93e178 100644 --- a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetrics/FeatureOverviewMetrics.tsx +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewMetrics/FeatureOverviewMetrics.tsx @@ -1,72 +1,33 @@ import { useParams } from 'react-router'; -import { useState, useEffect } from 'react'; import useFeature from '../../../../../hooks/api/getters/useFeature/useFeature'; import { IFeatureViewParams } from '../../../../../interfaces/params'; -import { IEnvironmentMetrics } from '../../../../../interfaces/environments'; import FeatureEnvironmentMetrics from '../FeatureEnvironmentMetrics/FeatureEnvironmentMetrics'; import { useStyles } from './FeatureOverviewMetrics.styles'; - -const data = { - version: 1, - maturity: 'experimental', - lastHourUsage: [ - { - environment: 'default', - timestamp: '2021-10-07 10:00:00', - yes: 250, - no: 60, - }, - { - environment: 'production', - timestamp: '2021-10-07 10:00:00', - yes: 200, - no: 500, - }, - { - environment: 'development', - timestamp: '2021-10-07 10:00:00', - yes: 0, - no: 0, - }, - ], - seenApplications: ['web', 'backend-api', 'commerce'], -}; +import useFeatureMetrics from '../../../../../hooks/api/getters/useFeatureMetrics/useFeatureMetrics'; const FeatureOverviewMetrics = () => { const styles = useStyles(); const { projectId, featureId } = useParams(); const { feature } = useFeature(projectId, featureId); - const [featureMetrics, setFeatureMetrics] = useState( - [] - ); + const { metrics } = useFeatureMetrics(projectId, featureId); - useEffect(() => { - const featureMetricList = feature?.environments.map(env => { - const metrics = data.lastHourUsage.find( - metric => metric.environment === env.name - ); - - if (!metrics) { - return { - name: env.name, - yes: 0, - no: 0, - timestamp: '', - }; - } + const featureMetrics = feature?.environments.map(env => { + const metric = metrics.lastHourUsage.find( + metric => metric.environment === env.name + ); + if (!metric) { return { - name: env.name, - yes: metrics.yes, - no: metrics.no, - timestamp: metrics.timestamp, + environment: env.name, + yes: 0, + no: 0, + timestamp: '' }; - }); + } + + return metric; + }); - setFeatureMetrics(featureMetricList); - /* Update on useSWR metrics change */ - /* eslint-disable-next-line */ - }, []); const renderFeatureMetrics = () => { if (featureMetrics.length === 0) { @@ -88,14 +49,14 @@ const FeatureOverviewMetrics = () => { return ( ); } return ( ); @@ -109,7 +70,7 @@ const FeatureOverviewMetrics = () => { return ( ); @@ -119,7 +80,7 @@ const FeatureOverviewMetrics = () => { return ( ); @@ -127,7 +88,7 @@ const FeatureOverviewMetrics = () => { return ( ); diff --git a/frontend/src/hooks/api/getters/useFeatureMetrics/useFeatureMetrics.ts b/frontend/src/hooks/api/getters/useFeatureMetrics/useFeatureMetrics.ts new file mode 100644 index 0000000000..c43ca34802 --- /dev/null +++ b/frontend/src/hooks/api/getters/useFeatureMetrics/useFeatureMetrics.ts @@ -0,0 +1,57 @@ +import { formatApiPath } from '../../../../utils/format-path'; +import { useEffect, useState } from 'react'; +import useSWR, { mutate } from 'swr'; +import { IFeatureMetrics } from '../../../../interfaces/featureToggle'; + +interface IUseFeatureMetricsOptions { + refreshInterval?: number; + revalidateOnFocus?: boolean; + revalidateOnReconnect?: boolean; + revalidateIfStale?: boolean; + revalidateOnMount?: boolean; +} + +const emptyMetrics = { lastHourUsage: [], seenApplications: [] }; + +const useFeatureMetrics = (projectId: string, featureId: string, options: IUseFeatureMetricsOptions = {}) => { + const fetcher = async () => { + const path = formatApiPath(`api/admin/client-metrics/features/${featureId}`); + const res = await fetch(path, { + method: 'GET' + }); + if (res.ok) { + return res.json(); + } else { + return emptyMetrics; + } + }; + + const FEATURE_METRICS_CACHE_KEY = `${projectId}_${featureId}_metrics`; + const { data, error } = useSWR( + FEATURE_METRICS_CACHE_KEY, + fetcher, + { + ...options + } + ); + + const [loading, setLoading] = useState(!error && !data); + + const refetch = () => { + mutate(FEATURE_METRICS_CACHE_KEY); + }; + + useEffect(() => { + setLoading(!error && !data); + }, [data, error]); + + return { + metrics: data || emptyMetrics, + error, + loading, + refetch, + FEATURE_METRICS_CACHE_KEY + }; +}; + +export default useFeatureMetrics; diff --git a/frontend/src/interfaces/featureToggle.ts b/frontend/src/interfaces/featureToggle.ts index df626478b2..ca2d54b86b 100644 --- a/frontend/src/interfaces/featureToggle.ts +++ b/frontend/src/interfaces/featureToggle.ts @@ -48,3 +48,17 @@ export interface IPayload { name: string; value: string; } + +export interface IFeatureEnvironmentMetrics { + environment: string; + timestamp: string; + yes: number; + no: number; +} + +export interface IFeatureMetrics { + version: number; + maturity: string; + lastHourUsage: IFeatureEnvironmentMetrics[], + seenApplication: string[] +}