feat(reports-p7): subtitle override field in dashboard builder
- DashboardReportBuilder gains an optional Subtitle input alongside Title. Persisted in the config payload sent to /api/v1/reports/runs + /api/v1/reports/generate + threaded through the preview payload's useMemo dep list so live preview reflects the override. - Cover-page brand picker (admin-only) — deferred. Today the renderer uses the active port's brand kit; cross-port branding swap needs a permission gate, port-pick UI, and a renderer override and is queued for a follow-up. Subtitle alone covers the most common ad-hoc need (custom cover-page subtext like "Board pack — March 2026"). Verified: tsc clean, 1493/1493 vitest. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,7 @@ interface Props {
|
||||
export function DashboardReportBuilder({ portSlug, initialFrom, initialTo }: Props) {
|
||||
const router = useRouter();
|
||||
const [title, setTitle] = useState(`Report - ${new Date().toLocaleDateString(undefined)}`);
|
||||
const [subtitle, setSubtitle] = useState('');
|
||||
const [selected, setSelected] = useState<PdfDashboardWidgetId[]>(
|
||||
PDF_DASHBOARD_WIDGETS.map((w) => w.id),
|
||||
);
|
||||
@@ -69,11 +70,12 @@ export function DashboardReportBuilder({ portSlug, initialFrom, initialTo }: Pro
|
||||
config: {
|
||||
kind: 'dashboard' as const,
|
||||
widgetIds: selected,
|
||||
...(subtitle.trim() ? { subtitle: subtitle.trim() } : {}),
|
||||
...(dateFrom ? { dateFrom } : {}),
|
||||
...(dateTo ? { dateTo } : {}),
|
||||
},
|
||||
}),
|
||||
[title, selected, dateFrom, dateTo],
|
||||
[title, subtitle, selected, dateFrom, dateTo],
|
||||
);
|
||||
|
||||
function toggle(id: PdfDashboardWidgetId) {
|
||||
@@ -102,6 +104,7 @@ export function DashboardReportBuilder({ portSlug, initialFrom, initialTo }: Pro
|
||||
config: {
|
||||
kind: 'dashboard',
|
||||
widgetIds: selected,
|
||||
...(subtitle.trim() ? { subtitle: subtitle.trim() } : {}),
|
||||
...(dateFrom ? { dateFrom } : {}),
|
||||
...(dateTo ? { dateTo } : {}),
|
||||
},
|
||||
@@ -142,6 +145,8 @@ export function DashboardReportBuilder({ portSlug, initialFrom, initialTo }: Pro
|
||||
config: {
|
||||
kind: 'dashboard',
|
||||
widgetIds: selected,
|
||||
title: title.trim() || 'Report',
|
||||
...(subtitle.trim() ? { subtitle: subtitle.trim() } : {}),
|
||||
...(dateFrom ? { dateFrom } : {}),
|
||||
...(dateTo ? { dateTo } : {}),
|
||||
},
|
||||
@@ -193,6 +198,18 @@ export function DashboardReportBuilder({ portSlug, initialFrom, initialTo }: Pro
|
||||
className="max-w-md"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="export-subtitle">
|
||||
Subtitle <span className="text-xs font-normal text-muted-foreground">(optional)</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="export-subtitle"
|
||||
value={subtitle}
|
||||
onChange={(e) => setSubtitle(e.target.value)}
|
||||
className="max-w-md"
|
||||
placeholder="e.g. Board pack — March 2026"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label>Report window</Label>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user