From b87c47d7c4f8de0dee4dc07763857ec5e8522286 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 13 Nov 2024 10:16:35 +0100 Subject: [PATCH] 1-3083: add remaining lifecycle header + tooltip (#8722) This PR adds a header and a tooltip to the lifecycle widget. Most of the changes in ProjectLifecycleSummary is indentation changes due to wrapping the component in another row container. Additionally, this PR touches the `HelpIcon` component because we'd like the tooltip to be wider than what we currently set as the default for the help icon. The help icon uses the html tooltip component, which has a maxWidth prop, but it does not expose that. So I've adjusted it to let you do that. Header with tooltip: ![image](https://github.com/user-attachments/assets/6ae1984b-256b-4f09-8fa2-b86ac2c17558) --- .../component/common/HelpIcon/HelpIcon.tsx | 28 +- .../ProjectStatus/ProjectLifecycleSummary.tsx | 260 +++++++++++------- 2 files changed, 189 insertions(+), 99 deletions(-) diff --git a/frontend/src/component/common/HelpIcon/HelpIcon.tsx b/frontend/src/component/common/HelpIcon/HelpIcon.tsx index 1c54473b76..70177f828a 100644 --- a/frontend/src/component/common/HelpIcon/HelpIcon.tsx +++ b/frontend/src/component/common/HelpIcon/HelpIcon.tsx @@ -1,6 +1,9 @@ import { styled, Tooltip, type TooltipProps } from '@mui/material'; import HelpOutline from '@mui/icons-material/HelpOutline'; -import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip'; +import { + HtmlTooltip, + type IHtmlTooltipProps, +} from 'component/common/HtmlTooltip/HtmlTooltip'; const StyledContainer = styled('span')<{ size: string | undefined }>( ({ theme, size }) => ({ @@ -24,13 +27,18 @@ const StyledContainer = styled('span')<{ size: string | undefined }>( }), ); -interface IHelpIconProps { +type IHelpIconProps = { tooltip: React.ReactNode; - htmlTooltip?: boolean; placement?: TooltipProps['placement']; children?: React.ReactNode; size?: string; -} +} & ( + | { + htmlTooltip: true; + htmlTooltipMaxWidth?: IHtmlTooltipProps['maxWidth']; + } + | { htmlTooltip?: false } +); export const HelpIcon = ({ tooltip, @@ -38,10 +46,20 @@ export const HelpIcon = ({ placement, children, size, + ...props }: IHelpIconProps) => { if (htmlTooltip) { + const { htmlTooltipMaxWidth } = props as { + htmlTooltipMaxWidth?: IHtmlTooltipProps['maxWidth']; + }; + return ( - + {children ?? } diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx index ecf58ea9b1..89a122a053 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx @@ -6,6 +6,24 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import type { FC } from 'react'; import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber'; import type { ProjectStatusSchemaLifecycleSummary } from 'openapi'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { HelpIcon } from 'component/common/HelpIcon/HelpIcon'; + +const LifecycleRow = styled('div')(({ theme }) => ({ + display: 'flex', + flexFlow: 'column', + gap: theme.spacing(1), +})); + +const HeaderRow = styled('div')(({ theme }) => ({ + display: 'flex', + flex: 'auto', + '& > *': { + marginBlock: 0, + fontWeight: 'normal', + }, +})); + const LifecycleBox = styled('li')(({ theme }) => ({ padding: theme.spacing(2), borderRadius: theme.shape.borderRadiusExtraLarge, @@ -16,13 +34,14 @@ const LifecycleBox = styled('li')(({ theme }) => ({ justifyContent: 'space-between', })); -const Wrapper = styled('ul')(({ theme }) => ({ +const LifecycleList = styled('ul')(({ theme }) => ({ display: 'grid', listStyle: 'none', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: theme.spacing(1), justifyContent: 'center', padding: 0, + flex: 'auto', })); const Counter = styled('span')({ @@ -83,9 +102,47 @@ const BigNumber: FC<{ value?: number }> = ({ value }) => { ); }; +const TooltipContent = styled('div')(({ theme }) => ({ + padding: theme.spacing(0.5), +})); + +const TooltipText = styled('p')(({ theme }) => ({ + fontSize: theme.typography.body1.fontSize, + '& + p': { + marginTop: theme.spacing(1), + }, +})); + +const LifecycleTooltip: FC = () => { + return ( + + + Based on usage metrics and interactions with Unleash, + feature flags can go through five distinct lifecycle + stages. These stages mirror the typical software + development process and allow you to identify + bottlenecks at any stage of the lifecycle. + + + + + Read more in our documentation + + + + } + /> + ); +}; + export const ProjectLifecycleSummary = () => { const projectId = useRequiredPathParam('projectId'); const { data, loading } = useProjectStatus(projectId); + const { isEnterprise } = useUiConfig(); const loadingRef = useLoading( loading, @@ -99,103 +156,118 @@ export const ProjectLifecycleSummary = () => { } }; return ( - - -

- - + + +

Flag lifecycle

+ + + + +

+ + - - {flagWord('initial')} in initial -

- -
- -

- - + + {flagWord('initial')} in initial +

+ +
+ +

+ + - - {flagWord('preLive')} in pre-live -

- -
- -

- - + + {flagWord('preLive')} in pre-live +

+ +
+ +

+ + - - {flagWord('live')} in live -

- -
- -

- - + + {flagWord('live')} in live +

+ +
+ +

+ + - - {flagWord('completed')} in cleanup -

- -
- -

- - + + {flagWord('completed')} in cleanup +

+ +
+ +

+ + - - {flagWord('archived')} in archived -

- -
This month
-
- {data?.lifecycleSummary.archived.currentFlags ?? 0}{' '} - flags archived -
-
-
-
+