From 3bc9fe9a9a11495b94e0e9c91b5433cabb470ad8 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 12 Nov 2024 11:35:42 +0100 Subject: [PATCH] [wip] add data to ui (#8710) Hooks up the project status lifecycle data to the UI. Adds some minor refactoring as part of that effort. ## Other files There's been some small changes to `frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx` and `frontend/src/hooks/useLoading.ts` as well to accommodate their usage here and to remove unused stuff. The inline comments mention the same thing but for posterity (especially after this is merged), the comments are: For `frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx`: > The icon only needs the name to pick. https://github.com/Unleash/unleash/pull/7049 deliberately changed the logic so that the completed stage gets the same icon regardless of its status. As such, to make the icon easier to use other places (such as in the lifecycle widget), we'll only require the name. For `frontend/src/hooks/useLoading.ts`: > There's no reason we should only be able to put refs on divs, as far as I'm aware. TS was complaining that that a `ul` couldn't hold a div reference, so I gave it a type parameter that defaults to the old version. --- .../FeatureLifecycleStageIcon.tsx | 10 +- .../ProjectStatus/ProjectLifecycleSummary.tsx | 130 +++++++++--------- frontend/src/hooks/useLoading.ts | 9 +- 3 files changed, 76 insertions(+), 73 deletions(-) diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx index e8d79886c0..0b0ed1bb3f 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx @@ -6,18 +6,16 @@ import { ReactComponent as CompletedStageIcon } from 'assets/icons/stage-complet import { ReactComponent as ArchivedStageIcon } from 'assets/icons/stage-archived.svg'; import type { LifecycleStage } from './LifecycleStage'; -export const FeatureLifecycleStageIcon: FC<{ stage: LifecycleStage }> = ({ - stage, -}) => { +export const FeatureLifecycleStageIcon: FC<{ + stage: Pick; +}> = ({ stage }) => { if (stage.name === 'archived') { return ; } else if (stage.name === 'pre-live') { return ; } else if (stage.name === 'live') { return ; - } else if (stage.name === 'completed' && stage.status === 'kept') { - return ; - } else if (stage.name === 'completed' && stage.status === 'discarded') { + } else if (stage.name === 'completed') { return ; } else { return ; diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx index 9722693511..5bd0c60009 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx @@ -1,6 +1,9 @@ import { styled } from '@mui/material'; import { FeatureLifecycleStageIcon } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon'; +import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus'; +import useLoading from 'hooks/useLoading'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; +import type { FC } from 'react'; import { Link } from 'react-router-dom'; const LifecycleBox = styled('li')(({ theme }) => ({ @@ -41,10 +44,6 @@ const Stats = styled('dl')(({ theme }) => ({ }, })); -const NegativeStat = styled('span')(({ theme }) => ({ - color: theme.palette.warning.contrastText, -})); - const NoData = styled('span')({ fontWeight: 'normal', }); @@ -53,123 +52,128 @@ const LinkNoUnderline = styled(Link)({ textDecoration: 'none', }); +const AverageDaysStat: FC<{ averageDays?: number | null }> = ({ + averageDays, +}) => { + const Content = () => { + if (averageDays === null || averageDays === undefined) { + return No data; + } + + return `${averageDays} days`; + }; + return ( + +
Avg. time in stage
+
+ +
+
+ ); +}; + export const ProjectLifecycleSummary = () => { const projectId = useRequiredPathParam('projectId'); + const { data, loading } = useProjectStatus(projectId); + + const loadingRef = useLoading( + loading, + '[data-loading-project-lifecycle-summary=true]', + ); return ( - +

- 15 + + {data?.lifecycleSummary.initial.currentFlags ?? 0} + flags in initial

- -
Avg. time in stage
-
- 21 days -
-
+

- 3 + + {data?.lifecycleSummary.preLive.currentFlags ?? 0} + flags in pre-live

- -
Avg. time in stage
-
18 days
-
+

- 2 + + {data?.lifecycleSummary.live.currentFlags ?? 0} + flags in live

- -
Avg. time in stage
-
10 days
-
+

- 6 + + {data?.lifecycleSummary.completed.currentFlags ?? 0} + - - - flags - {' '} - in cleanup - + flags in cleanup

- -
Avg. time in stage
-
- No data -
-
+

- 15 + + {data?.lifecycleSummary.archived.currentFlags ?? 0} + flags in archived

This month
-
3 flags archived
+
+ {data?.lifecycleSummary.archived.currentFlags ?? 0}{' '} + flags archived +
diff --git a/frontend/src/hooks/useLoading.ts b/frontend/src/hooks/useLoading.ts index 9db84aff32..6e05e1f5b8 100644 --- a/frontend/src/hooks/useLoading.ts +++ b/frontend/src/hooks/useLoading.ts @@ -1,9 +1,10 @@ import { createRef, useLayoutEffect } from 'react'; -type refElement = HTMLDivElement; - -const useLoading = (loading: boolean, selector = '[data-loading=true]') => { - const ref = createRef(); +const useLoading = ( + loading: boolean, + selector = '[data-loading=true]', +) => { + const ref = createRef(); useLayoutEffect(() => { if (ref.current) { const elements = ref.current.querySelectorAll(selector);