1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

refactor: instance health cleanup (#4602)

## About the changes
Cleanup after hackathon. Discovered project on:
https://linear.app/unleash/project/active-users-and-instance-dashboard-67352abadf49
This commit is contained in:
Tymoteusz Czech 2023-09-04 13:10:23 +02:00 committed by GitHub
parent 5ae86ef196
commit 8aace7f93f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 12 additions and 265 deletions

View File

@ -18,7 +18,6 @@ import UsersAdmin from './users/UsersAdmin';
import NotFound from 'component/common/NotFound/NotFound';
import { AdminIndex } from './AdminIndex';
import { AdminTabsMenu } from './menu/AdminTabsMenu';
import { InstanceHealth } from './instance-health/InstanceHealth';
export const Admin = () => {
return (
@ -35,7 +34,6 @@ export const Admin = () => {
<Route path="groups/*" element={<GroupsAdmin />} />
<Route path="roles/*" element={<Roles />} />
<Route path="instance" element={<InstanceAdmin />} />
<Route path="instance-health" element={<InstanceHealth />} />
<Route path="network/*" element={<Network />} />
<Route path="maintenance" element={<MaintenanceAdmin />} />
<Route path="cors" element={<CorsAdmin />} />

View File

@ -80,13 +80,6 @@ export const adminRoutes: INavigationMenuItem[] = [
menu: { adminSettings: true },
group: 'instance',
},
{
path: '/admin/instance-health',
title: 'Instance health',
menu: { adminSettings: true },
group: 'instance',
flag: 'instanceHealthDashboard',
},
{
path: '/admin/instance-privacy',
title: 'Instance privacy',

View File

@ -30,24 +30,9 @@ export const InstanceStats: VFC = () => {
}
const rows = [
{ title: 'Instance Id', value: stats?.instanceId },
{ title: 'Instance Id', value: stats?.instanceId, offset: false },
{ title: versionTitle, value: version },
{ title: 'Users', value: stats?.users },
{
title: 'Active past 7 days',
value: stats?.activeUsers?.last7,
offset: true,
},
{
title: 'Active past 30 days',
value: stats?.activeUsers?.last30,
offset: true,
},
{
title: 'Active past 90 days',
value: stats?.activeUsers?.last90,
offset: true,
},
{ title: 'Feature toggles', value: stats?.featureToggles },
{ title: 'Projects', value: stats?.projects },
{ title: 'Environments', value: stats?.environments },
@ -80,22 +65,16 @@ export const InstanceStats: VFC = () => {
{rows.map(row => (
<TableRow key={row.title}>
<TableCell component="th" scope="row">
<ConditionallyRender
condition={Boolean(row.offset)}
show={
<Box
component="span"
sx={theme => ({
marginLeft: row.offset
? theme.spacing(2)
: 0,
})}
>
{row.title}
</Box>
}
elseShow={row.title}
/>
<Box
component="span"
sx={theme => ({
marginLeft: row.offset
? theme.spacing(2)
: 0,
})}
>
{row.title}
</Box>
</TableCell>
<TableCell align="right">{row.value}</TableCell>
</TableRow>

View File

@ -1,220 +0,0 @@
import { VFC, useMemo } from 'react';
import { useSortBy, useTable } from 'react-table';
import { styled, Typography, Box } from '@mui/material';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { useInstanceStats } from 'hooks/api/getters/useInstanceStats/useInstanceStats';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { sortTypes } from 'utils/sortTypes';
import {
SortableTableHeader,
Table,
TableBody,
TableRow,
TableCell,
} from 'component/common/Table';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { HelpPopper } from 'component/project/Project/ProjectStats/HelpPopper';
import { StatusBox } from 'component/project/Project/ProjectStats/StatusBox';
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
interface IInstanceHealthProps {}
const CardsGrid = styled('div')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
gap: theme.spacing(2),
paddingBottom: theme.spacing(2),
}));
const Card = styled('div')(({ theme }) => ({
padding: theme.spacing(2.5),
borderRadius: `${theme.shape.borderRadiusLarge}px`,
backgroundColor: `${theme.palette.background.paper}`,
border: `1px solid ${theme.palette.divider}`,
// boxShadow: theme.boxShadows.card,
display: 'flex',
flexDirection: 'column',
}));
/**
* @deprecated unify with project widget
*/
const StyledWidget = styled(Box)(({ theme }) => ({
position: 'relative',
padding: theme.spacing(3),
backgroundColor: theme.palette.background.paper,
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
borderRadius: `${theme.shape.borderRadiusLarge}px`,
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(2),
},
}));
export const InstanceHealth: VFC<IInstanceHealthProps> = () => {
const { stats } = useInstanceStats();
const { projects } = useProjects();
// FIXME: loading state
const initialState = useMemo(
() => ({
hiddenColumns: [],
sortBy: [{ id: 'createdAt' }],
}),
[]
);
const data = useMemo(() => projects, [projects]);
const dormantUsersPercentage =
(1 - stats?.activeUsers?.last90! / stats?.users!) * 100;
const dormantUsersColor =
dormantUsersPercentage < 30
? 'success.main'
: dormantUsersPercentage < 50
? 'warning.main'
: 'error.main';
const COLUMNS = useMemo(
() => [
{
accessor: 'name',
Header: 'Project name',
Cell: TextCell,
width: '80%',
},
{
Header: 'Feature toggles',
accessor: 'featureCount',
Cell: TextCell,
},
{
Header: 'Created at',
accessor: 'createdAt',
Cell: DateCell,
},
{
Header: 'Members',
accessor: 'memberCount',
Cell: TextCell,
},
{
Header: 'Health',
accessor: 'health',
Cell: ({ value }: { value: number }) => {
const healthRatingColor =
value < 50
? 'error.main'
: value < 75
? 'warning.main'
: 'success.main';
return (
<TextCell>
<Typography
component="span"
sx={{ color: healthRatingColor }}
>
{value}%
</Typography>
</TextCell>
);
},
},
],
[]
);
const { headerGroups, rows, prepareRow, getTableProps, getTableBodyProps } =
useTable(
{
columns: COLUMNS as any,
data: data as any,
initialState,
sortTypes,
autoResetGlobalFilter: false,
autoResetHiddenColumns: false,
autoResetSortBy: false,
disableSortRemove: true,
},
useSortBy
);
return (
<>
<CardsGrid>
<Card>
<StatusBox
title="User accounts"
boxText={String(stats?.users)}
customChangeElement={<></>}
>
{/* <HelpPopper id="user-accounts">
Sum of all configuration and state modifications in
the project.
</HelpPopper> */}
{/* FIXME: tooltip */}
</StatusBox>
</Card>
<Card>
<StatusBox
title="Dormant users"
boxText={String(
stats?.users! - stats?.activeUsers?.last90!
)}
customChangeElement={
<Typography
component="span"
sx={{ color: dormantUsersColor }}
>
({dormantUsersPercentage.toFixed(1)}%)
</Typography>
}
>
{/* <HelpPopper id="dormant-users">
Sum of all configuration and state modifications in
the project.
</HelpPopper> */}
</StatusBox>
</Card>
<Card>
<StatusBox
title="Number of projects"
boxText={String(projects?.length)}
customChangeElement={<></>}
></StatusBox>
</Card>
<Card>
<StatusBox
title="Number of feature toggles"
boxText={String(stats?.featureToggles)}
customChangeElement={<></>}
></StatusBox>
</Card>
</CardsGrid>
<PageContent header={<PageHeader title="Health per project" />}>
<Table {...getTableProps()} rowHeight="standard">
<SortableTableHeader headerGroups={headerGroups} />
<TableBody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
<TableRow hover {...row.getRowProps()}>
{row.cells.map(cell => (
<TableCell {...cell.getCellProps()}>
{cell.render('Cell')}
</TableCell>
))}
</TableRow>
);
})}
</TableBody>
</Table>
</PageContent>
</>
);
};

View File

@ -57,7 +57,6 @@ export interface IFlags {
integrationsRework?: boolean;
multipleRoles?: boolean;
doraMetrics?: boolean;
instanceHealthDashboard?: boolean;
[key: string]: boolean | Variant | undefined;
}

View File

@ -28,8 +28,7 @@ export type IFlagKey =
| 'newApplicationList'
| 'integrationsRework'
| 'multipleRoles'
| 'doraMetrics'
| 'instanceHealthDashboard';
| 'doraMetrics';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;

View File

@ -42,7 +42,6 @@ process.nextTick(async () => {
lastSeenByEnvironment: true,
newApplicationList: true,
doraMetrics: true,
instanceHealthDashboard: true,
},
},
authentication: {