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:
parent
9a12257568
commit
7af7b32bd5
@ -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>
|
||||
|
@ -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 }) => ({
|
||||
|
@ -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 () => {
|
||||
|
@ -48,6 +48,7 @@ const ApplicationOverview = () => {
|
||||
{data.projects.map((project) => (
|
||||
<Badge
|
||||
sx={{ cursor: 'pointer' }}
|
||||
key={project}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
navigate(`/projects/${project}`);
|
||||
|
@ -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';
|
||||
|
@ -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%',
|
||||
},
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user