feat(dashboard): add revision-safe interactive widget grid

This commit is contained in:
cesnimda
2026-10-28 15:32:47 +01:00
parent aea7c29e70
commit 0bd290e788
21 changed files with 696 additions and 108 deletions
@@ -19,6 +19,7 @@ import OnboardingChecklist from "./OnboardingChecklist";
import { WIDGETS, defaultDashboardLayout, WidgetId } from "../dashboardLayout";
import { useDashboardLayout } from "../hooks/useDashboardLayout";
import DashboardLayoutEditor, { DashboardNavigationGuard } from "./DashboardLayoutEditor";
import DashboardGrid from "./DashboardGrid";
import { useOptionalToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";
import { statusLabel, statusTone } from "../pipeline";
@@ -363,16 +364,13 @@ export default function DashboardView({ mode = "dashboard" }: { mode?: "dashboar
{summaryReady && hasJobs ? <Box sx={grid}>{reports.stageAge}{reports.sources}</Box> : null}
{reports.salary}
<Box sx={grid}>{reports.companies}{reports.skills}</Box>
</> : <Box role={layoutState.editing ? "region" : undefined} aria-label={layoutState.editing ? t("dashboardPreview") : undefined} sx={{ display: "grid", gridTemplateColumns: { xs: "minmax(0, 1fr)", md: "repeat(2, minmax(0, 1fr))" }, gap: 3, alignItems: "start" }}>
{activeLayout.widgets.filter(widget => widget.visible).map(widget => {
</> : <DashboardGrid layout={activeLayout} editing={layoutState.editing} disabled={layoutState.saving || layoutState.conflict || layoutState.loading}
onChange={layoutState.setDraft} childrenFor={widget => {
const content = reports[widget.id];
const ready = widget.id === "activity" || widget.id === "skills" ? trendsReady : summaryReady;
if (!content && !(ready && (hasJobs || layoutState.editing))) return null;
return <Box key={widget.id} data-dashboard-widget={widget.id} data-widget-size={widget.size} sx={{ minWidth: 0, gridColumn: { xs: "auto", md: widget.size === "full" ? "1 / -1" : "auto" } }}>
{content ?? <PageSection title={t(WIDGETS.find(item => item.id === widget.id)!.titleKey)}><Typography color="text.secondary">{t("dashboardNoSample")}</Typography></PageSection>}
</Box>;
})}
</Box>}
return content ?? <PageSection title={t(WIDGETS.find(item => item.id === widget.id)!.titleKey)}><Typography color="text.secondary">{t("dashboardNoSample")}</Typography></PageSection>;
}} />}
</Box>
);
}