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
-
-
-
-
+
+
+ {flagWord('archived')} in archived
+
+
+ This month
+
+ {data?.lifecycleSummary.archived.currentFlags ?? 0}{' '}
+ flags archived
+
+
+
+
+
);
};