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,