feat: add job runs chart and scrollable reading lists on dashboard
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 1m5s

- Add multi-line chart showing job runs over time by type (scan,
  rebuild, thumbnails, other) with the same day/week/month toggle
- Limit currently reading and recently read lists to 3 visible items
  with a scrollbar for overflow
- Fix NUMERIC→BIGINT cast for SUM/COALESCE in jobs SQL queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 10:43:45 +01:00
parent 5d33a35407
commit e26219989f
6 changed files with 223 additions and 5 deletions

View File

@@ -3,7 +3,7 @@
import {
PieChart, Pie, Cell, ResponsiveContainer, Tooltip,
BarChart, Bar, XAxis, YAxis, CartesianGrid,
AreaChart, Area,
AreaChart, Area, Line, LineChart,
Legend,
} from "recharts";
@@ -186,3 +186,46 @@ export function RcHorizontalBar({
</ResponsiveContainer>
);
}
// ---------------------------------------------------------------------------
// Multi-line chart (jobs over time)
// ---------------------------------------------------------------------------
export function RcMultiLineChart({
data,
lines,
noDataLabel,
}: {
data: Record<string, unknown>[];
lines: { key: string; label: string; color: string }[];
noDataLabel?: string;
}) {
const hasData = data.some((d) => lines.some((l) => (d[l.key] as number) > 0));
if (data.length === 0 || !hasData)
return <p className="text-muted-foreground text-sm text-center py-8">{noDataLabel}</p>;
return (
<ResponsiveContainer width="100%" height={180}>
<LineChart data={data} margin={{ top: 5, right: 5, bottom: 0, left: -20 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="var(--color-border)" opacity={0.3} />
<XAxis dataKey="label" tick={{ fontSize: 11, fill: "var(--color-muted-foreground)" }} axisLine={false} tickLine={false} />
<YAxis tick={{ fontSize: 11, fill: "var(--color-muted-foreground)" }} axisLine={false} tickLine={false} allowDecimals={false} />
<Tooltip
contentStyle={{ backgroundColor: "var(--color-card)", border: "1px solid var(--color-border)", borderRadius: 8, fontSize: 12 }}
/>
<Legend wrapperStyle={{ fontSize: 11 }} />
{lines.map((l) => (
<Line
key={l.key}
type="monotone"
dataKey={l.key}
name={l.label}
stroke={l.color}
strokeWidth={2}
dot={{ r: 3, fill: l.color }}
/>
))}
</LineChart>
</ResponsiveContainer>
);
}