feat(ui): add A1 dashboard and resumable onboarding

This commit is contained in:
cesnimda
2026-11-03 09:45:57 +01:00
parent 5e8a07d13e
commit c7d26d354c
61 changed files with 1522 additions and 23 deletions
@@ -20,6 +20,7 @@ import { WIDGETS, defaultDashboardLayout, WidgetId } from "../dashboardLayout";
import { useDashboardLayout } from "../hooks/useDashboardLayout";
import DashboardLayoutEditor, { DashboardNavigationGuard } from "./DashboardLayoutEditor";
import DashboardGrid from "./DashboardGrid";
import DashboardWeek from "./DashboardWeek";
import { useOptionalToast } from "../toast";
import { useI18n } from "../i18n/I18nProvider";
import { statusLabel, statusTone } from "../pipeline";
@@ -177,7 +178,7 @@ export default function DashboardView({ mode = "dashboard" }: { mode?: "dashboar
</Box>;
const detailsSx = { mt: 2, "& summary": { cursor: "pointer", color: "text.primary", fontWeight: 600, py: 1 }, "& th, & td": { px: 1, py: 0.75, overflowWrap: "anywhere" } };
const prefsButton = !layoutState.editing ? <Button ref={customizeButton} variant="outlined" startIcon={<TuneIcon />} disabled={layoutState.loading || Boolean(layoutState.loadError)} onClick={() => { setSavedMessage(false); layoutState.startEditing(); }}>{t("dashboardCustomize")}</Button> : null;
const pipelineReport = <PageSection surface title={t("dashboardCurrentPipeline")} description={t("dashboardPipelineBody")}>
const pipelineReport = <PageSection surface={reporting} title={t("dashboardCurrentPipeline")} description={t("dashboardPipelineBody")}>
<Box sx={reporting ? grid : undefined}>
<Stack spacing={1.5}>
{funnel.map(item => <Box key={item.label}>
@@ -199,6 +200,7 @@ export default function DashboardView({ mode = "dashboard" }: { mode?: "dashboar
</PageSection>;
const reports: Record<WidgetId, React.ReactNode> = {
agenda: summaryReady && hasJobs ? <DashboardWeek jobs={reminderJobs} /> : null,
cards: summaryReady && hasJobs ? <Box component="dl" aria-label={t("dashboardSummaryCards")} sx={{ m: 0, display: "grid", gridTemplateColumns: { xs: "1fr", sm: "repeat(2, minmax(0, 1fr))", lg: "repeat(4, minmax(0, 1fr))" }, borderBlock: "1px solid", borderColor: "divider", py: 1, gap: 1 }}>
{[
{ label: t("dashboardTrackedJobs"), value: stats!.active, caption: t("dashboardTrackedBody"), to: "/jobs" },
@@ -324,7 +326,6 @@ export default function DashboardView({ mode = "dashboard" }: { mode?: "dashboar
return (
<Box sx={{ display: "grid", gap: 3, minWidth: 0, "& p, & h2, & h3": { overflowWrap: "anywhere" } }}>
{!reporting ? <OnboardingChecklist hasJobs={summaryReady ? hasJobs : null} /> : null}
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}>
<Typography variant="body2" color="text.secondary">{t(reporting ? "analyticsScope" : "dashboardSnapshotScope")}</Typography>
{reporting ? <Button component={RouterLink} to="/dashboard">{t("goToDashboard")}</Button> : prefsButton}
@@ -371,6 +372,7 @@ export default function DashboardView({ mode = "dashboard" }: { mode?: "dashboar
if (!content && !(ready && (hasJobs || layoutState.editing))) return null;
return content ?? <PageSection title={t(WIDGETS.find(item => item.id === widget.id)!.titleKey)}><Typography color="text.secondary">{t("dashboardNoSample")}</Typography></PageSection>;
}} />}
{!reporting ? <OnboardingChecklist hasJobs={summaryReady ? hasJobs : null} /> : null}
</Box>
);
}