1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: initial status box implementation (#2913)

First iteration of new status boxes
This commit is contained in:
Fredrik Strand Oseberg 2023-01-18 10:10:41 +01:00 committed by GitHub
parent 16bca1260c
commit bf7ef62059
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 144 additions and 7 deletions

View File

@ -1,13 +1,17 @@
import useProject, {
useProjectNameOrId,
} from 'hooks/api/getters/useProject/useProject';
import { styled } from '@mui/material';
import { Box, styled } from '@mui/material';
import { ProjectFeatureToggles } from './ProjectFeatureToggles/ProjectFeatureToggles';
import ProjectInfo from './ProjectInfo/ProjectInfo';
import { usePageTitle } from 'hooks/usePageTitle';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useLastViewedProject } from '../../../hooks/useLastViewedProject';
import { useEffect } from 'react';
import { StatusBox } from './ProjectStatus/StatusBox';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ProjectStatus } from './ProjectStatus/ProjectStatus';
const refreshInterval = 15 * 1000;
@ -23,6 +27,12 @@ const StyledProjectToggles = styled('div')(() => ({
minWidth: 0,
}));
const StyledContentContainer = styled(Box)(() => ({
display: 'flex',
flexDirection: 'column',
width: '100%',
}));
const ProjectOverview = () => {
const projectId = useRequiredPathParam('projectId');
const projectName = useProjectNameOrId(projectId);
@ -30,6 +40,7 @@ const ProjectOverview = () => {
const { members, features, health, description, environments } = project;
usePageTitle(`Project overview ${projectName}`);
const { setLastViewed } = useLastViewedProject();
const { uiConfig } = useUiConfig();
useEffect(() => {
setLastViewed(projectId);
@ -44,13 +55,19 @@ const ProjectOverview = () => {
health={health}
featureCount={features?.length}
/>
<StyledProjectToggles>
<ProjectFeatureToggles
features={features}
environments={environments}
loading={loading}
<StyledContentContainer>
<ConditionallyRender
condition={Boolean(uiConfig?.flags.newProjectOverview)}
show={<ProjectStatus />}
/>
</StyledProjectToggles>
<StyledProjectToggles>
<ProjectFeatureToggles
features={features}
environments={environments}
loading={loading}
/>
</StyledProjectToggles>
</StyledContentContainer>
</StyledContainer>
);
};

View File

@ -0,0 +1,24 @@
import { Box, styled } from '@mui/material';
import { StatusBox } from './StatusBox';
const StyledBox = styled(Box)(({ theme }) => ({
padding: theme.spacing(0, 0, 2, 2),
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
}));
export const ProjectStatus = () => {
return (
<StyledBox>
<StatusBox title="Total changes" boxText={'86'} change={-24} />
<StatusBox
title="Total changes"
boxText={'6 days'}
change={-12}
/>{' '}
<StatusBox title="Total changes" boxText={'86'} change={-24} />
<StatusBox title="Total changes" boxText={'86'} change={-24} />
</StyledBox>
);
};

View File

@ -0,0 +1,85 @@
import { ArrowOutward, SouthEast } from '@mui/icons-material';
import { Box, Typography, styled } from '@mui/material';
import { flexRow } from 'themes/themeStyles';
const StyledBox = styled(Box)(({ theme }) => ({
padding: theme.spacing(4, 2),
backgroundColor: theme.palette.background.paper,
minWidth: '240px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
borderRadius: `${theme.shape.borderRadiusLarge}px`,
}));
const StyledTypographyHeader = styled(Typography)(({ theme }) => ({
marginBottom: theme.spacing(2),
}));
const StyledTypographyCount = styled(Typography)(({ theme }) => ({
fontSize: theme.fontSizes.largeHeader,
fontWeight: 'bold',
}));
const StyledBoxChangeContainer = styled(Box)(({ theme }) => ({
...flexRow,
flexDirection: 'column',
alignItems: 'center',
marginLeft: theme.spacing(1.5),
}));
const StyledTypographySubtext = styled(Typography)(({ theme }) => ({
color: theme.palette.neutral.main,
fontSize: theme.fontSizes.smallBody,
}));
const StyledTypographyChange = styled(Typography)(({ theme }) => ({
marginLeft: theme.spacing(1),
fontSize: theme.fontSizes.smallBody,
}));
interface IStatusBoxProps {
title: string;
boxText: string;
change: number;
}
const resolveIcon = (change: number) => {
if (change > 0) {
return (
<ArrowOutward
sx={{ color: 'success.main', height: 18, width: 18 }}
/>
);
}
return <SouthEast sx={{ color: 'warning.dark', height: 18, width: 18 }} />;
};
const resolveColor = (change: number) => {
if (change > 0) {
return 'success.main';
}
return 'error.main';
};
export const StatusBox = ({ title, boxText, change }: IStatusBoxProps) => {
return (
<StyledBox>
<StyledTypographyHeader>{title}</StyledTypographyHeader>
<Box sx={{ ...flexRow }}>
<StyledTypographyCount>{boxText}</StyledTypographyCount>
<StyledBoxChangeContainer>
<Box sx={{ ...flexRow }}>
{resolveIcon(change)}
<StyledTypographyChange color={resolveColor(change)}>
{change}
</StyledTypographyChange>
</Box>
<StyledTypographySubtext>
this month
</StyledTypographySubtext>
</StyledBoxChangeContainer>
</Box>
</StyledBox>
);
};

View File

@ -45,6 +45,7 @@ export interface IFlags {
messageBanner?: boolean;
serviceAccounts?: boolean;
featuresExportImport?: boolean;
newProjectOverview?: boolean;
}
export interface IVersionInfo {

View File

@ -44,6 +44,7 @@ export default createTheme({
},
},
fontSizes: {
largeHeader: '2.25rem',
mainHeader: '1.25rem',
bodySize: '1rem',
smallBody: `${14 / 16}rem`,

View File

@ -41,6 +41,7 @@ export default createTheme({
},
},
fontSizes: {
largeHeader: '2rem',
mainHeader: '1.25rem',
bodySize: '1rem',
smallBody: `${14 / 16}rem`,

View File

@ -4,6 +4,7 @@ declare module '@mui/material/styles' {
* @deprecated
*/
fontSizes: {
largeHeader: string;
mainHeader: string;
bodySize: string;
smallBody: string;

View File

@ -77,6 +77,7 @@ exports[`should create default config 1`] = `
"maintenanceMode": false,
"messageBanner": false,
"networkView": false,
"newProjectOverview": false,
"proxyReturnAllToggles": false,
"responseTimeWithAppName": false,
"serviceAccounts": false,
@ -95,6 +96,7 @@ exports[`should create default config 1`] = `
"maintenanceMode": false,
"messageBanner": false,
"networkView": false,
"newProjectOverview": false,
"proxyReturnAllToggles": false,
"responseTimeWithAppName": false,
"serviceAccounts": false,

View File

@ -10,6 +10,10 @@ const flags = {
process.env.UNLEASH_EXPERIMENTAL_EMBED_PROXY,
true,
),
newProjectOverview: parseEnvVarBoolean(
process.env.NEW_PROJECT_OVERVIEW,
false,
),
embedProxyFrontend: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_EMBED_PROXY_FRONTEND,
true,

View File

@ -42,6 +42,7 @@ process.nextTick(async () => {
variantsPerEnvironment: true,
maintenance: false,
featuresExportImport: true,
newProjectOverview: true,
},
},
authentication: {