diff --git a/frontend/src/assets/icons/projectStatus.svg b/frontend/src/assets/icons/projectStatus.svg
index 713e29eb62..8872e15086 100644
--- a/frontend/src/assets/icons/projectStatus.svg
+++ b/frontend/src/assets/icons/projectStatus.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx
index 79145f662d..4b8bb253b4 100644
--- a/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx
@@ -7,16 +7,9 @@ import { styled, Tooltip } from '@mui/material';
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
- justifyContent: 'center',
alignItems: 'center',
- gap: theme.spacing(2),
}));
-const TitleContainer = styled('h4')({
- margin: 0,
- width: '100%',
-});
-
type Output = { date: string; count: number; level: number };
const ensureFullYearData = (data: Output[]): Output[] => {
@@ -93,7 +86,6 @@ export const ProjectActivity = () => {
<>
{data.activityCountByDate.length > 0 ? (
- Activity in project
({
- backgroundColor: theme.palette.envAccordion.expanded,
- padding: theme.spacing(3),
- borderRadius: theme.shape.borderRadiusExtraLarge,
- minWidth: '300px',
- gridArea: 'health',
-}));
+import { HealthGridTile } from './ProjectHealthGrid.styles';
const TextContainer = styled('div')(({ theme }) => ({
display: 'flex',
@@ -63,7 +56,7 @@ export const ProjectHealth = () => {
: theme.palette.success.border;
return (
-
+
@@ -111,6 +104,6 @@ export const ProjectHealth = () => {
)}
-
+
);
};
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx
new file mode 100644
index 0000000000..2102a9ebb5
--- /dev/null
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.styles.tsx
@@ -0,0 +1,7 @@
+import { styled } from '@mui/material';
+
+export const HealthGridTile = styled('article')(({ theme }) => ({
+ backgroundColor: theme.palette.envAccordion.expanded,
+ padding: theme.spacing(3),
+ borderRadius: theme.shape.borderRadiusExtraLarge,
+}));
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx
new file mode 100644
index 0000000000..bc6517a306
--- /dev/null
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectHealthGrid.tsx
@@ -0,0 +1,57 @@
+import { ProjectHealth } from './ProjectHealth';
+import { styled } from '@mui/material';
+import { StaleFlags } from './StaleFlags';
+import { ProjectResources } from './ProjectResources';
+
+const onNarrowGrid = (css: object) => ({
+ '@container (max-width: 650px)': css,
+ '@supports not (container-type: inline-size)': {
+ '@media (max-width: 712px)': css,
+ },
+});
+
+const HealthContainer = styled('div')({
+ containerType: 'inline-size',
+});
+
+const HealthGrid = styled('div')(({ theme }) => ({
+ display: 'grid',
+ gridTemplateAreas: `
+ "health resources"
+ "stale resources"
+ `,
+ gridTemplateColumns: 'repeat(2, minmax(300px, 1fr))',
+ gap: theme.spacing(1, 2),
+ ...onNarrowGrid({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: theme.spacing(1),
+ }),
+}));
+
+const Tile = styled('div', {
+ shouldForwardProp: (prop) => prop !== 'gridArea',
+})<{ gridArea: string }>(({ theme, gridArea }) => ({
+ gridArea,
+ '&>*': {
+ height: '100%',
+ },
+}));
+
+export const ProjectHealthGrid = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx
index b59a48111d..ba90284837 100644
--- a/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectLifecycleSummary.tsx
@@ -6,26 +6,10 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import type { FC } from 'react';
import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber';
import type { ProjectStatusSchemaLifecycleSummary } from 'openapi';
-import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import { lifecycleMessages } from './LifecycleMessages';
import InfoIcon from '@mui/icons-material/Info';
-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 LifecycleBoxContent = styled('div')(({ theme }) => ({
padding: theme.spacing(2),
gap: theme.spacing(4),
@@ -87,6 +71,7 @@ const LifecycleList = styled('ul')(({ theme }) => ({
justifyContent: 'center',
padding: 0,
flex: 'auto',
+ margin: 0,
}));
const Counter = styled('span')({
@@ -146,44 +131,6 @@ 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);
@@ -200,119 +147,103 @@ 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
+
+
+
+
);
};
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectResources.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectResources.tsx
index 9130458a07..d8b7bfdd17 100644
--- a/frontend/src/component/project/Project/ProjectStatus/ProjectResources.tsx
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectResources.tsx
@@ -8,14 +8,7 @@ import SegmentsIcon from '@mui/icons-material/DonutLarge';
import ConnectedIcon from '@mui/icons-material/Cable';
import { useProjectStatus } from 'hooks/api/getters/useProjectStatus/useProjectStatus';
import useLoading from 'hooks/useLoading';
-
-const Wrapper = styled('article')(({ theme }) => ({
- backgroundColor: theme.palette.envAccordion.expanded,
- padding: theme.spacing(3),
- borderRadius: theme.shape.borderRadiusExtraLarge,
- minWidth: '300px',
- gridArea: 'resources',
-}));
+import { HealthGridTile } from './ProjectHealthGrid.styles';
const ProjectResourcesInner = styled('div')(({ theme }) => ({
display: 'flex',
@@ -115,7 +108,7 @@ export const ProjectResources = () => {
const loadingRef = useLoading(loading, '[data-loading-resources=true]');
return (
-
+
Project resources
@@ -155,6 +148,6 @@ export const ProjectResources = () => {
-
+
);
};
diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectStatusModal.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectStatusModal.tsx
index 1d199c3c9f..b6e79c12b5 100644
--- a/frontend/src/component/project/Project/ProjectStatus/ProjectStatusModal.tsx
+++ b/frontend/src/component/project/Project/ProjectStatus/ProjectStatusModal.tsx
@@ -1,20 +1,28 @@
-import { styled } from '@mui/material';
+import { Button, styled } from '@mui/material';
import { DynamicSidebarModal } from 'component/common/SidebarModal/SidebarModal';
-import { ProjectResources } from './ProjectResources';
+import { ReactComponent as ProjectStatusSvg } from 'assets/icons/projectStatus.svg';
import { ProjectActivity } from './ProjectActivity';
-import { ProjectHealth } from './ProjectHealth';
import { ProjectLifecycleSummary } from './ProjectLifecycleSummary';
-import { StaleFlags } from './StaleFlags';
+import type { FC } from 'react';
+import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
+import { ProjectHealthGrid } from './ProjectHealthGrid';
const ModalContentContainer = styled('section')(({ theme }) => ({
minHeight: '100vh',
maxWidth: 1100,
width: '95vw',
backgroundColor: theme.palette.background.default,
- padding: theme.spacing(4),
display: 'flex',
flexFlow: 'column',
gap: theme.spacing(4),
+ paddingInline: theme.spacing(4),
+ paddingBlock: theme.spacing(10),
+}));
+
+const WidgetContainer = styled('div')(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: theme.spacing(9),
}));
type Props = {
@@ -22,47 +30,112 @@ type Props = {
close: () => void;
};
-const onNarrowGrid = (css: object) => ({
- '@container (max-width: 650px)': css,
- '@supports not (container-type: inline-size)': {
- '@media (max-width: 712px)': css,
+const LifecycleHeaderRow = styled('div')(({ theme }) => ({
+ display: 'flex',
+ alignItems: 'end',
+}));
+
+const HeaderRow = styled('div')(({ theme }) => ({
+ display: 'flex',
+ alignItems: 'center',
+ gap: theme.spacing(1.5),
+}));
+
+const StyledProjectStatusSvg = styled(ProjectStatusSvg)(({ theme }) => ({
+ fill: theme.palette.primary.main,
+}));
+
+const ModalHeader = styled('h3')(({ theme }) => ({
+ fontSize: theme.typography.h2.fontSize,
+ margin: 0,
+}));
+
+const RowHeader = styled('h4')(({ theme }) => ({
+ margin: 0,
+ fontWeight: 'normal',
+}));
+
+const Row = styled('div')(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: theme.spacing(2),
+}));
+
+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 HealthContainer = styled('div')({
- containerType: 'inline-size',
-});
+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.
+
-const HealthGrid = styled('div')(({ theme }) => ({
- display: 'grid',
- gridTemplateAreas: `
- "health resources"
- "stale resources"
- `,
- gridTemplateColumns: '1fr 1fr',
- gap: theme.spacing(1, 2),
- ...onNarrowGrid({
- display: 'flex',
- flexDirection: 'column',
- gap: theme.spacing(1),
- }),
+
+
+ Read more in our documentation
+
+
+
+ }
+ />
+ );
+};
+
+const CloseRow = styled('div')(({ theme }) => ({
+ display: 'flex',
+ justifyContent: 'flex-end',
+ marginBlockStart: 'auto',
}));
export const ProjectStatusModal = ({ open, close }: Props) => {
return (
-
-
-
-
-
-
-
+
+
+ Project status
+
+
+
+ Health
+
+
-
+
+ Activity in project
+
+
-
+
+
+ Flag lifecycle
+
+
+
+
+
+
+
+
);
diff --git a/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx b/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx
index ab91009567..a0e7c0ec30 100644
--- a/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx
+++ b/frontend/src/component/project/Project/ProjectStatus/StaleFlags.tsx
@@ -4,13 +4,9 @@ import { PrettifyLargeNumber } from 'component/common/PrettifyLargeNumber/Pretti
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import type { FC } from 'react';
import { Link } from 'react-router-dom';
+import { HealthGridTile } from './ProjectHealthGrid.styles';
-const Wrapper = styled('article')(({ theme }) => ({
- backgroundColor: theme.palette.envAccordion.expanded,
- padding: theme.spacing(3),
- borderRadius: theme.shape.borderRadiusExtraLarge,
- minWidth: '300px',
- gridArea: 'stale',
+const Wrapper = styled(HealthGridTile)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),