1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: application overview ux improvements (#6371)

1. Added navigation from environments to instances
2. Last seen is now shown as TimeAgo
3. Added icons for total environments and features
4. Fixed schema


![image](https://github.com/Unleash/unleash/assets/964450/4d0a51a9-7141-4854-ada9-72676e42239c)
This commit is contained in:
Jaanus Sellin 2024-02-28 12:39:33 +02:00 committed by GitHub
parent 9a12257568
commit 7af7b32bd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 69 additions and 8 deletions

View File

@ -5,12 +5,13 @@ import { useNavigate } from 'react-router-dom';
import { FC, useLayoutEffect, useRef, useState } from 'react';
import { ApplicationOverviewSchema } from '../../openapi';
import { useRequiredPathParam } from '../../hooks/useRequiredPathParam';
import { WarningAmberRounded } from '@mui/icons-material';
import { HelpIcon } from '../common/HelpIcon/HelpIcon';
import { CloudCircle, Flag, WarningAmberRounded } from '@mui/icons-material';
import TimeAgo from 'react-timeago';
const StyledTable = styled('table')(({ theme }) => ({
fontSize: theme.fontSizes.smallerBody,
marginTop: theme.spacing(2),
marginTop: theme.spacing(1),
}));
const StyledCell = styled('td')(({ theme }) => ({
@ -78,6 +79,23 @@ const StyledStatus = styled(Typography)<{
alignItems: 'center',
}));
const StyledIconRow = styled(Box)(({ theme }) => ({
display: 'flex',
gap: theme.spacing(3),
color: theme.palette.secondary.main,
paddingTop: theme.spacing(2),
}));
const StyledIconContainer = styled(Box)(({ theme }) => ({
display: 'flex',
gap: theme.spacing(0.5),
}));
const StyledText = styled(Box)(({ theme }) => ({
color: theme.palette.text.primary,
display: 'flex',
alignItems: 'center',
}));
const useElementWidth = () => {
const elementRef = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState('100%');
@ -117,6 +135,29 @@ interface IApplicationChartProps {
data: ApplicationOverviewSchema;
}
interface IApplicationCountersProps {
environmentCount: number;
featureCount: number;
}
const ApplicationCounters = ({
environmentCount,
featureCount,
}: IApplicationCountersProps) => {
return (
<StyledIconRow>
<StyledIconContainer>
<CloudCircle />
<StyledText>{environmentCount}</StyledText>
</StyledIconContainer>
<StyledIconContainer>
<Flag />
<StyledText>{featureCount}</StyledText>
</StyledIconContainer>
</StyledIconRow>
);
};
export const ApplicationChart = ({ data }: IApplicationChartProps) => {
const applicationName = useRequiredPathParam('name');
const { elementRef, width } = useElementWidth();
@ -164,6 +205,10 @@ export const ApplicationChart = ({ data }: IApplicationChartProps) => {
>
{applicationName}
</Typography>
<ApplicationCounters
environmentCount={data.environments.length}
featureCount={data.featureCount}
/>
<StyledDivider />
@ -189,6 +234,12 @@ export const ApplicationChart = ({ data }: IApplicationChartProps) => {
<StyledEnvironmentBox
mode={mode}
key={environment.name}
sx={{ cursor: 'pointer' }}
onClick={(e) => {
navigate(
`/applications/${applicationName}/instances?environment=${environment.name}`,
);
}}
>
<EnvironmentHeader>
{environment.name} environment
@ -224,7 +275,13 @@ export const ApplicationChart = ({ data }: IApplicationChartProps) => {
<tr>
<StyledCell>Last seen:</StyledCell>
<StyledCell>
{environment.lastSeen}
<TimeAgo
date={
new Date(
environment.lastSeen,
)
}
/>
</StyledCell>
</tr>
</tbody>

View File

@ -12,12 +12,13 @@ const WarningContainer = styled(Box)(({ theme }) => ({
const WarningHeader = styled(Box)(({ theme }) => ({
display: 'flex',
padding: theme.spacing(2, 3, 2, 3),
alignItems: 'flex-start',
alignItems: 'center',
gap: theme.spacing(1.5),
alignSelf: 'stretch',
borderRadius: `${theme.shape.borderRadiusLarge}px ${theme.shape.borderRadiusLarge}px 0 0`,
border: `1px solid ${theme.palette.warning.border}`,
background: theme.palette.warning.light,
color: theme.palette.warning.main,
}));
const SmallText = styled(Box)(({ theme }) => ({

View File

@ -22,7 +22,7 @@ test('Display application overview with environments', async () => {
{
name: 'development',
instanceCount: 999,
lastSeen: '2024-02-22T20:20:24.740',
lastSeen: new Date().toISOString(),
sdks: ['unleash-client-node:5.5.0-beta.0'],
},
],
@ -47,7 +47,7 @@ test('Display application overview with environments', async () => {
await screen.findByText('development environment');
await screen.findByText('999');
await screen.findByText('unleash-client-node:5.5.0-beta.0');
await screen.findByText('2024-02-22T20:20:24.740');
await screen.findByText('1 second ago');
});
test('Display application overview without environments', async () => {

View File

@ -48,6 +48,7 @@ const ApplicationOverview = () => {
{data.projects.map((project) => (
<Badge
sx={{ cursor: 'pointer' }}
key={project}
onClick={(e) => {
e.preventDefault();
navigate(`/projects/${project}`);

View File

@ -1,4 +1,4 @@
import { FC, useEffect, useMemo, useState } from 'react';
import { FC, useEffect, useMemo } from 'react';
import { formatDateYMDHMS } from 'utils/formatDate';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useConnectedInstancesTable } from './useConnectedInstancesTable';

View File

@ -2,6 +2,7 @@ import { useMemo } from 'react';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
import { useTable, useGlobalFilter, useSortBy } from 'react-table';
import { sortTypes } from 'utils/sortTypes';
import { TimeAgoCell } from '../../common/Table/cells/TimeAgoCell/TimeAgoCell';
type ConnectedInstancesTableData = {
instanceId: string;
@ -39,7 +40,7 @@ export const useConnectedInstancesTable = (
{
Header: 'Last seen',
accessor: 'lastSeen',
Cell: HighlightCell,
Cell: TimeAgoCell,
styles: {
width: '20%',
},

View File

@ -28,6 +28,7 @@ export const applicationOverviewEnvironmentSchema = {
},
lastSeen: {
type: 'string',
nullable: true,
format: 'date-time',
example: '2023-04-19T08:15:14.000Z',
description: 'The last time the application environment was seen',