mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +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 
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