From dc64a81bb9488f1f07a79979d57f1ebc46672ca1 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Tue, 26 Mar 2024 14:50:37 +0200 Subject: [PATCH] feat: last usage metrics in project table (#6692) ![image](https://github.com/Unleash/unleash/assets/964450/342f43ed-ab81-4875-b855-5e59329288d8) --- .../FeatureEnvironmentSeenCell.tsx | 4 +- .../LastSeenProgress.test.tsx | 9 ++++ .../LastSeenProgress/LastSeenProgress.tsx | 52 +++++++++++++++++++ .../cells/FeatureSeenCell/LastSeenTooltip.tsx | 41 +++++++++------ .../FeatureEnvironmentSeen.tsx | 8 ++- frontend/src/interfaces/featureToggle.ts | 4 +- 6 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.test.tsx create mode 100644 frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.tsx diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx index 5a5eefd140..9defcae3c1 100644 --- a/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/FeatureEnvironmentSeenCell.tsx @@ -1,10 +1,10 @@ import React, { type VFC } from 'react'; import { FeatureEnvironmentSeen } from 'component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen'; -import type { FeatureEnvironmentSchema } from 'openapi'; +import type { FeatureSearchEnvironmentSchema } from 'openapi'; interface IFeatureSeenCellProps { feature: { - environments?: FeatureEnvironmentSchema[]; + environments?: FeatureSearchEnvironmentSchema[]; lastSeenAt?: string | null; }; } diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.test.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.test.tsx new file mode 100644 index 0000000000..6d6a97ef89 --- /dev/null +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.test.tsx @@ -0,0 +1,9 @@ +import { screen } from '@testing-library/react'; +import { render } from 'utils/testRenderer'; +import { LastSeenProgress } from './LastSeenProgress'; + +test('Show last seen progress bar', async () => { + render(); + + await screen.findByText('50%'); +}); diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.tsx new file mode 100644 index 0000000000..31a53b1475 --- /dev/null +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenProgress/LastSeenProgress.tsx @@ -0,0 +1,52 @@ +import { styled, CircularProgress, Box } from '@mui/material'; + +const ProgressContainer = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'row', + gap: theme.spacing(1), + width: '20%', + justifyContent: 'flex-end', +})); + +const BackgroundCircularProgress = styled(CircularProgress)(({ theme }) => ({ + color: theme.palette.divider, +})); + +const MainCircularProgress = styled(CircularProgress)(({ theme }) => ({ + color: theme.palette.primary.main, + position: 'absolute', + left: 0, +})); + +interface ILastSeenProgressProps { + yes: number | undefined; + no: number | undefined; +} + +export const LastSeenProgress = ({ yes, no }: ILastSeenProgressProps) => { + const noData = yes === undefined || no === undefined || yes + no === 0; + if (noData) { + return ; + } + + const progress = (yes / (yes + no)) * 100; + return ( + + + + + + {progress}% + + ); +}; diff --git a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx index 549580a6d3..7a864611a9 100644 --- a/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx +++ b/frontend/src/component/common/Table/cells/FeatureSeenCell/LastSeenTooltip.tsx @@ -3,6 +3,7 @@ import TimeAgo from 'react-timeago'; import type { ILastSeenEnvironments } from 'interfaces/featureToggle'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { useLastSeenColors } from 'component/feature/FeatureView/FeatureEnvironmentSeen/useLastSeenColors'; +import { LastSeenProgress } from './LastSeenProgress/LastSeenProgress'; const StyledDescription = styled( 'div', @@ -17,15 +18,14 @@ const StyledDescription = styled( borderRadius: theme.shape.borderRadiusMedium, })); -const StyledDescriptionBlock = styled('div')({ +const StyledDescriptionBlock = styled('div')(({ theme }) => ({ display: 'flex', - flexDirection: 'row', -}); + flexWrap: 'wrap', +})); const StyledDescriptionHeader = styled('p')(({ theme }) => ({ color: theme.palette.text.primary, fontSize: theme.fontSizes.smallBody, - fontWeight: theme.fontWeight.bold, marginBottom: theme.spacing(1), })); @@ -34,18 +34,18 @@ const StyledDescriptionBlockHeader = styled('p')(({ theme }) => ({ fontSize: theme.fontSizes.smallBody, fontWeight: theme.fontWeight.bold, marginBottom: theme.spacing(1), - width: '50%', + width: '40%', + justifyContent: 'flex-start', })); +const StyledValueContainer = styled('div')({ + width: '40%', + justifyContent: 'center', +}); const StyledDescriptionSubHeader = styled('p')(({ theme }) => ({ fontSize: theme.fontSizes.smallBody, - margin: theme.spacing(2, 0), })); -const StyledValueContainer = styled('div')({ - width: '50%', -}); - const StyledValue = styled('div', { shouldForwardProp: (prop) => prop !== 'color', })(({ color }) => ({ @@ -54,6 +54,12 @@ const StyledValue = styled('div', { color: color, })); +const StyledListContainer = styled('div')(({ theme }) => ({ + maxHeight: theme.spacing(24.5), + overflowY: 'auto', + paddingRight: theme.spacing(2), +})); + interface ILastSeenTooltipProps { featureLastSeen: string; environments?: ILastSeenEnvironments[]; @@ -73,19 +79,16 @@ export const LastSeenTooltip = ({ ); return ( - + Last usage reported - - Usage is reported from connected applications through metrics - - {environments?.map(({ name, lastSeenAt }) => ( + + {environments?.map(({ name, lastSeenAt, yes, no }) => ( {name} @@ -128,9 +131,10 @@ export const LastSeenTooltip = ({ } /> + ))} - + } elseShow={ } /> + + Usage is reported from connected applications through metrics + ); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx index bdaa7694bb..e10dc8a99d 100644 --- a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx @@ -46,6 +46,10 @@ const StyledIconWrapper = styled('div')(({ theme }) => ({ margin: '0 auto', })); +const StyledTooltipResolver = styled(TooltipResolver)(({ theme }) => ({ + maxWidth: theme.spacing(47.5), +})); + const TooltipContainer: FC<{ color?: string; tooltip: ReactElement | string; @@ -53,7 +57,7 @@ const TooltipContainer: FC<{ }> = ({ sx, tooltip, color, children }) => { return ( - - + ); }; diff --git a/frontend/src/interfaces/featureToggle.ts b/frontend/src/interfaces/featureToggle.ts index 76edbd5357..10f35b0db1 100644 --- a/frontend/src/interfaces/featureToggle.ts +++ b/frontend/src/interfaces/featureToggle.ts @@ -23,11 +23,13 @@ export interface IEnvironments { type?: string; hasStrategies?: boolean; hasEnabledStrategies?: boolean; + yes?: number; + no?: number; } export type ILastSeenEnvironments = Pick< IEnvironments, - 'name' | 'enabled' | 'lastSeenAt' + 'name' | 'enabled' | 'lastSeenAt' | 'yes' | 'no' >; export interface IFeatureToggle {