From 4c20e21a453fe610ef7ebfdb666fefefa92fde98 Mon Sep 17 00:00:00 2001 From: Richard R Date: Sun, 7 Jun 2026 12:14:01 -0600 Subject: [PATCH] refactor(admin): add loading skeleton to tasks panel for improved UX Introduce a TasksSkeleton component to display animated placeholders while scheduled tasks are loading. Replace direct rendering of empty task rows with the skeleton when data is pending, enhancing perceived responsiveness and user experience in the admin tasks panel. --- src/components/admin/AdminTasksPanel.tsx | 70 +++++++++++++++++------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/src/components/admin/AdminTasksPanel.tsx b/src/components/admin/AdminTasksPanel.tsx index ffcb879..f386feb 100644 --- a/src/components/admin/AdminTasksPanel.tsx +++ b/src/components/admin/AdminTasksPanel.tsx @@ -75,7 +75,7 @@ function formatDuration(ms: number | null): string { export function AdminTasksPanel() { const queryClient = useQueryClient(); - const { data, error } = useQuery({ + const { data, error, isPending: isLoading } = useQuery({ queryKey: TASKS_QUERY_KEY, queryFn: fetchTasks, refetchInterval: 5000, @@ -122,28 +122,60 @@ export function AdminTasksPanel() { Vercel Hobby invokes scheduled tasks once daily. Shorter intervals are unavailable on this deployment.

)} -
- {(data?.tasks ?? []).map((task) => ( - patchTask.mutate({ key: task.key, patch: { enabled } })} - onSaveInterval={(intervalMs) => patchTask.mutate({ key: task.key, patch: { intervalMs } })} - onRun={() => runTask.mutate(task.key)} - /> - ))} - {data && data.tasks.length === 0 && ( -

No tasks registered.

- )} -
+ {isLoading ? ( + + ) : ( +
+ {(data?.tasks ?? []).map((task) => ( + patchTask.mutate({ key: task.key, patch: { enabled } })} + onSaveInterval={(intervalMs) => patchTask.mutate({ key: task.key, patch: { intervalMs } })} + onRun={() => runTask.mutate(task.key)} + /> + ))} + {data && data.tasks.length === 0 && ( +

No tasks registered.

+ )} +
+ )} ); } +function TasksSkeleton() { + const rows = Array.from({ length: 2 }); + return ( +
+ {rows.map((_, index) => ( + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + ))} +
+ ); +} + function TaskRow({ task, schedulerMode,