Use skeleton loading where possible

This commit is contained in:
viown
2025-06-27 05:53:39 +03:00
parent d227ec86ed
commit e929a21e37
7 changed files with 90 additions and 98 deletions
@@ -1,29 +1,48 @@
import React from 'react';
import React, { useMemo } from 'react';
import globalize from 'lib/globalize';
import Widget from './Widget';
import List from '@mui/material/List';
import ActivityListItem from 'apps/dashboard/features/activity/components/ActivityListItem';
import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry';
import { useLogEntries } from 'apps/dashboard/features/activity/api/useLogEntries';
import subSeconds from 'date-fns/subSeconds';
import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack';
type IProps = {
logs?: ActivityLogEntry[];
};
const ActivityLogWidget = () => {
const dayBefore = useMemo(() => (
subSeconds(new Date(), 24 * 60 * 60).toISOString()
), []);
const { data: logs, isPending } = useLogEntries({
startIndex: 0,
limit: 7,
minDate: dayBefore,
hasUserId: true
});
const ActivityLogWidget = ({ logs }: IProps) => {
return (
<Widget
title={globalize.translate('HeaderActivity')}
href='/dashboard/activity?useractivity=true'
>
<List sx={{ bgcolor: 'background.paper' }}>
{logs?.map(entry => (
<ActivityListItem
key={entry.Id}
item={entry}
displayShortOverview={true}
/>
))}
</List>
{isPending ? (
<Stack spacing={2}>
<Skeleton variant='rounded' height={60} />
<Skeleton variant='rounded' height={60} />
<Skeleton variant='rounded' height={60} />
<Skeleton variant='rounded' height={60} />
</Stack>
) : (
<List sx={{ bgcolor: 'background.paper' }}>
{logs?.Items?.map(entry => (
<ActivityListItem
key={entry.Id}
item={entry}
displayShortOverview={true}
/>
))}
</List>
)}
</Widget>
);
};
@@ -1,16 +1,24 @@
import React from 'react';
import React, { useMemo } from 'react';
import globalize from 'lib/globalize';
import Widget from './Widget';
import List from '@mui/material/List';
import ActivityListItem from 'apps/dashboard/features/activity/components/ActivityListItem';
import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models';
import subSeconds from 'date-fns/subSeconds';
import { useLogEntries } from 'apps/dashboard/features/activity/api/useLogEntries';
type IProps = {
alerts?: ActivityLogEntry[];
};
const AlertsLogWidget = () => {
const weekBefore = useMemo(() => (
subSeconds(new Date(), 7 * 24 * 60 * 60).toISOString()
), []);
const AlertsLogWidget = ({ alerts }: IProps) => {
if (alerts?.length == 0) return null;
const { data: alerts, isPending } = useLogEntries({
startIndex: 0,
limit: 4,
minDate: weekBefore,
hasUserId: false
});
if (isPending || alerts?.Items?.length == 0) return null;
return (
<Widget
@@ -18,7 +26,7 @@ const AlertsLogWidget = ({ alerts }: IProps) => {
href='/dashboard/activity?useractivity=false'
>
<List sx={{ bgcolor: 'background.paper' }}>
{alerts?.map(entry => (
{alerts?.Items?.map(entry => (
<ActivityListItem
key={entry.Id}
item={entry}
@@ -1,15 +1,13 @@
import React from 'react';
import globalize from 'lib/globalize';
import Widget from './Widget';
import type { SessionInfo } from '@jellyfin/sdk/lib/generated-client/models/session-info';
import DeviceCard from 'apps/dashboard/features/devices/components/DeviceCard';
import Stack from '@mui/material/Stack';
import useLiveSessions from 'apps/dashboard/features/sessions/hooks/useLiveSessions';
type IProps = {
devices?: SessionInfo[];
};
const DevicesWidget = () => {
const { data: devices } = useLiveSessions();
const DevicesWidget = ({ devices }: IProps) => {
return (
<Widget
title={globalize.translate('HeaderDevices')}
@@ -9,13 +9,11 @@ import React from 'react';
import MetricCard from 'apps/dashboard/features/metrics/components/MetricCard';
import globalize from 'lib/globalize';
import type { ItemCounts } from '@jellyfin/sdk/lib/generated-client/models/item-counts';
import { useItemCounts } from 'apps/dashboard/features/metrics/api/useItemCounts';
type IProps = {
counts?: ItemCounts;
};
const ItemCountsWidget = () => {
const { data: counts } = useItemCounts();
const ItemCountsWidget = ({ counts }: IProps) => {
return (
<Grid
container
@@ -6,6 +6,8 @@ import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import type { SystemInfo } from '@jellyfin/sdk/lib/generated-client/models';
import Skeleton from '@mui/material/Skeleton';
import { useSystemInfo } from 'hooks/useSystemInfo';
type IProps = {
systemInfo?: SystemInfo;
@@ -14,7 +16,9 @@ type IProps = {
onShutdownClick?: () => void;
};
const ServerInfoWidget = ({ systemInfo, onScanLibrariesClick, onRestartClick, onShutdownClick }: IProps) => {
const ServerInfoWidget = ({ onScanLibrariesClick, onRestartClick, onShutdownClick }: IProps) => {
const { data: systemInfo, isPending } = useSystemInfo();
return (
<Widget
title={globalize.translate('TabServer')}
@@ -32,10 +36,21 @@ const ServerInfoWidget = ({ systemInfo, onScanLibrariesClick, onRestartClick, on
<Typography fontWeight='bold'>{globalize.translate('LabelBuildVersion')}</Typography>
</Stack>
<Stack flexGrow={5} gap={1}>
<Typography>{systemInfo?.ServerName}</Typography>
<Typography>{systemInfo?.Version}</Typography>
<Typography>{__PACKAGE_JSON_VERSION__}</Typography>
<Typography>{__JF_BUILD_VERSION__}</Typography>
{isPending ? (
<>
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
</>
) : (
<>
<Typography>{systemInfo?.ServerName}</Typography>
<Typography>{systemInfo?.Version}</Typography>
<Typography>{__PACKAGE_JSON_VERSION__}</Typography>
<Typography>{__JF_BUILD_VERSION__}</Typography>
</>
)}
</Stack>
</Stack>
</Paper>
@@ -3,13 +3,11 @@ import React from 'react';
import StorageListItem from 'apps/dashboard/features/storage/components/StorageListItem';
import globalize from 'lib/globalize';
import Widget from './Widget';
import type { SystemStorageDto } from '@jellyfin/sdk/lib/generated-client/models/system-storage-dto';
import { useSystemStorage } from 'apps/dashboard/features/storage/api/useSystemStorage';
type IProps = {
systemStorage?: SystemStorageDto;
};
const ServerPathWidget = () => {
const { data: systemStorage } = useSystemStorage();
const ServerPathWidget = ({ systemStorage }: IProps) => {
return (
<Widget
title={globalize.translate('HeaderPaths')}
+11 -55
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useState } from 'react';
import Page from 'components/Page';
import globalize from 'lib/globalize';
import Box from '@mui/material/Box';
@@ -10,21 +10,14 @@ import AlertsLogWidget from '../components/widgets/AlertsLogWidget';
import useTheme from '@mui/material/styles/useTheme';
import useMediaQuery from '@mui/material/useMediaQuery';
import Stack from '@mui/material/Stack';
import { useSystemStorage } from '../features/storage/api/useSystemStorage';
import subSeconds from 'date-fns/subSeconds';
import { useLogEntries } from '../features/activity/api/useLogEntries';
import { useSystemInfo } from 'hooks/useSystemInfo';
import Loading from 'components/loading/LoadingComponent';
import useShutdownServer from '../features/system/api/useShutdownServer';
import useRestartServer from '../features/system/api/useRestartServer';
import ConfirmDialog from 'components/ConfirmDialog';
import useLiveTasks from '../features/tasks/hooks/useLiveTasks';
import RunningTasksWidget from '../components/widgets/RunningTasksWidget';
import DevicesWidget from '../components/widgets/DevicesWidget';
import useLiveSessions from '../features/sessions/hooks/useLiveSessions';
import { useStartTask } from '../features/tasks/api/useStartTask';
import ItemCountsWidget from '../components/widgets/ItemCountsWidget';
import { useItemCounts } from '../features/metrics/api/useItemCounts';
export const Component = () => {
const theme = useTheme();
@@ -36,34 +29,7 @@ export const Component = () => {
const restartServer = useRestartServer();
const shutdownServer = useShutdownServer();
const { data: tasks, isPending: isTasksPending } = useLiveTasks({ isHidden: false });
const { data: devices } = useLiveSessions();
const dayBefore = useMemo(() => (
subSeconds(new Date(), 24 * 60 * 60).toISOString()
), []);
const weekBefore = useMemo(() => (
subSeconds(new Date(), 7 * 24 * 60 * 60).toISOString()
), []);
const { data: logs, isPending: isLogsPending } = useLogEntries({
startIndex: 0,
limit: 7,
minDate: dayBefore,
hasUserId: true
});
const { data: alerts, isPending: isAlertsPending } = useLogEntries({
startIndex: 0,
limit: 4,
minDate: weekBefore,
hasUserId: false
});
const { data: systemStorage, isPending: isSystemStoragePending } = useSystemStorage();
const { data: systemInfo, isPending: isSystemInfoPending } = useSystemInfo();
const { data: itemCounts, isPending: isItemCountsPending } = useItemCounts();
const { data: tasks } = useLiveTasks({ isHidden: false });
const promptRestart = useCallback(() => {
setIsRestartConfirmDialogOpen(true);
@@ -101,13 +67,6 @@ export const Component = () => {
setIsShutdownConfirmDialogOpen(false);
}, [ shutdownServer ]);
const isPending = isLogsPending || isAlertsPending || isSystemStoragePending
|| isSystemInfoPending || isTasksPending || isItemCountsPending;
if (isPending) {
return <Loading />;
}
return (
<Page
id='dashboardPage'
@@ -137,35 +96,32 @@ export const Component = () => {
<Grid size={{ xs: 12, md: 12, xl: 6 }}>
<Stack spacing={3}>
<ServerInfoWidget
systemInfo={systemInfo}
onScanLibrariesClick={onScanLibraries}
onRestartClick={promptRestart}
onShutdownClick={promptShutdown}
/>
<ItemCountsWidget counts={itemCounts} />
<ItemCountsWidget />
<RunningTasksWidget tasks={tasks} />
<DevicesWidget devices={devices} />
<DevicesWidget />
</Stack>
</Grid>
<Grid size={{ xs: 12, md: 6, lg: 12, xl: 3 }}>
<ActivityLogWidget logs={logs?.Items} />
<ActivityLogWidget />
</Grid>
{isMedium || isExtraLarge ? (
<Grid size={{ md: 6, xl: 3 }}>
<Stack spacing={3}>
<AlertsLogWidget alerts={alerts?.Items} />
<ServerPathWidget systemStorage={systemStorage} />
<AlertsLogWidget />
<ServerPathWidget />
</Stack>
</Grid>
) : (
<>
{(alerts?.Items && alerts.Items.length > 0) && (
<Grid size={{ xs: 12, lg: 12 }}>
<AlertsLogWidget alerts={alerts?.Items} />
</Grid>
)}
<Grid size={{ xs: 12, lg: 12 }}>
<ServerPathWidget systemStorage={systemStorage} />
<AlertsLogWidget />
</Grid>
<Grid size={{ xs: 12, lg: 12 }}>
<ServerPathWidget />
</Grid>
</>
)}