feat: dashboard auto-refresh, collapsible sidebar, error retry
- Dashboard: auto-refresh toggle (30s interval, spins when live) - Dashboard: responsive grid (6 cols mobile, 12 cols desktop) - Sidebar: Dashboards, Saved views, Queues sections now collapsible with chevron toggle - Error banner: added Retry button next to error message Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,7 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
|
||||
const [views, setViews] = useState<SavedView[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [autoRefresh, setAutoRefresh] = useState(false);
|
||||
|
||||
// Add widget dialog
|
||||
const [addOpen, setAddOpen] = useState(false);
|
||||
@@ -94,6 +95,23 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
|
||||
});
|
||||
}, [fetchDashboard]);
|
||||
|
||||
// Auto-refresh: only refresh widget data, not structure
|
||||
useEffect(() => {
|
||||
if (!autoRefresh || !dashboard) return;
|
||||
const interval = setInterval(() => {
|
||||
for (const widget of widgets) {
|
||||
getWidgetData(dashboard.id, widget.id).then(({ data: wData }) => {
|
||||
if (wData) {
|
||||
setWidgets((prev) =>
|
||||
prev.map((w) => (w.id === widget.id ? { ...w, data: wData } : w))
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 30_000);
|
||||
return () => clearInterval(interval);
|
||||
}, [autoRefresh, dashboard?.id]);
|
||||
|
||||
const handleAddWidget = async () => {
|
||||
if (!addViewId || !addTitle.trim()) return;
|
||||
setAdding(true);
|
||||
@@ -194,6 +212,15 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setAutoRefresh((v) => !v)}
|
||||
className={cn("h-8 border-border/80", autoRefresh ? "bg-primary/20 text-primary" : "bg-card/70")}
|
||||
>
|
||||
<RefreshCwIcon className={cn("h-4 w-4", autoRefresh && "animate-spin")} />
|
||||
{autoRefresh ? "Live" : "Auto"}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -222,7 +249,7 @@ export default function DashboardPage({ params }: { params: Promise<{ id: string
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid auto-rows-[minmax(120px,auto)] grid-cols-12 gap-4">
|
||||
<div className="grid auto-rows-[minmax(100px,auto)] grid-cols-6 gap-3 md:grid-cols-12 md:gap-4">
|
||||
{widgets.map((widget) => (
|
||||
<div
|
||||
key={widget.id}
|
||||
|
||||
Reference in New Issue
Block a user