feat: add loading state to dashboard page

This commit is contained in:
Nicolas Meienberger 2023-06-10 12:03:49 +02:00 committed by Nicolas Meienberger
parent 0cd1a877f1
commit 2cd61c03b9
4 changed files with 20 additions and 12 deletions

View file

@ -22,7 +22,7 @@ export const EmptyPage: React.FC<IProps> = ({ title, subtitle, onAction, actionL
className={clsx(styles.emptyImage, 'mb-3')}
style={{
maxWidth: '100%',
height: 'auto',
height: '80px',
}}
/>
<p className="empty-title">{title}</p>

View file

@ -1,4 +1,5 @@
import { Icon } from '@tabler/icons-react';
import clsx from 'clsx';
import React from 'react';
interface IProps {
@ -7,18 +8,19 @@ interface IProps {
title: string;
subtitle: string;
metric: string;
isLoading?: boolean;
}
const SystemStat: React.FC<IProps> = ({ icon: IconComponent, progress, title, subtitle, metric }) => (
const SystemStat: React.FC<IProps> = ({ icon: IconComponent, progress, title, subtitle, metric, isLoading }) => (
<div className="col-sm-6 col-lg-4">
<div className="card">
<div className="card-body">
<div className="d-flex justify-content-between align-items-start">
<div className="h2 mb-3 font-weight-bold">{title}</div>
<div className={clsx('h2 mb-3 font-weight-bold', { placeholder: isLoading })}>{title}</div>
<IconComponent />
</div>
<div className="h2">{metric}</div>
<div className="mb-3 text-muted">{subtitle}</div>
<div className={clsx('h2', { 'placeholder col-3': isLoading })}>{metric}</div>
<div className={clsx('mb-3 text-muted', { 'placeholder col-11': isLoading })}>{subtitle}</div>
<div className="progress progress-sm">
<div
className="progress-bar bg-primary"

View file

@ -4,9 +4,15 @@ import { useTranslations } from 'next-intl';
import { SystemRouterOutput } from '../../../../server/routers/system/system.router';
import SystemStat from '../components/SystemStat';
type IProps = { data: SystemRouterOutput['systemInfo'] };
type IProps = { data?: SystemRouterOutput['systemInfo']; isLoading: boolean };
export const DashboardContainer: React.FC<IProps> = ({ data }) => {
const defaultData: SystemRouterOutput['systemInfo'] = {
cpu: { load: 0 },
disk: { available: 0, total: 0, used: 0 },
memory: { available: 0, total: 0, used: 0 },
};
export const DashboardContainer: React.FC<IProps> = ({ data = defaultData, isLoading }) => {
const { disk, memory, cpu } = data;
const t = useTranslations('dashboard');
// Convert bytes to GB
@ -21,9 +27,9 @@ export const DashboardContainer: React.FC<IProps> = ({ data }) => {
return (
<div className="row row-deck row-cards">
<SystemStat title={t('cards.disk.title')} metric={`${diskUsed} GB`} subtitle={t('cards.disk.subtitle', { total: diskSize })} icon={IconDatabase} progress={percentUsed} />
<SystemStat title={t('cards.cpu.title')} metric={`${cpu.load.toFixed(2)}%`} subtitle={t('cards.cpu.subtitle')} icon={IconCpu} progress={cpu.load} />
<SystemStat title={t('cards.memory.title')} metric={`${percentUsedMemory || 0}%`} subtitle={`${memoryTotal} GB`} icon={IconCircuitResistor} progress={percentUsedMemory} />
<SystemStat isLoading={isLoading} title={t('cards.disk.title')} metric={`${diskUsed} GB`} subtitle={t('cards.disk.subtitle', { total: diskSize })} icon={IconDatabase} progress={percentUsed} />
<SystemStat isLoading={isLoading} title={t('cards.cpu.title')} metric={`${cpu.load.toFixed(2)}%`} subtitle={t('cards.cpu.subtitle')} icon={IconCpu} progress={cpu.load} />
<SystemStat isLoading={isLoading} title={t('cards.memory.title')} metric={`${percentUsedMemory || 0}%`} subtitle={`${memoryTotal} GB`} icon={IconCircuitResistor} progress={percentUsedMemory} />
</div>
);
};

View file

@ -9,11 +9,11 @@ import { ErrorPage } from '../../../../components/ui/ErrorPage';
export const DashboardPage: NextPage = () => {
const t = useTranslations();
const { data, error } = trpc.system.systemInfo.useQuery();
const { data, error, isLoading } = trpc.system.systemInfo.useQuery();
return (
<Layout title={t('dashboard.title')}>
{data && <DashboardContainer data={data} />}
<DashboardContainer data={data} isLoading={isLoading} />
{error && <ErrorPage error={t(error.data?.tError.message as MessageKey, { ...error.data?.tError.variables })} />}
</Layout>
);