Adopt semantic dashboard action states

This commit is contained in:
2026-08-19 14:26:26 +02:00
parent d0df0b146f
commit c8a7a155aa
2 changed files with 40 additions and 43 deletions
+4 -1
View File
@@ -156,7 +156,10 @@ manifest = ModuleManifest(
body=(
"A Dashboard layout belongs to the active tenant, account, and focused View. "
"Configuring changes only a local draft until Save layout is selected; Cancel or "
"Discard restores the last saved arrangement. Widget removal removes only the placement, "
"Discard restores the last saved arrangement. The page action bar always reports whether "
"the draft is saved, unsaved, or currently saving; Save and Cancel remain visible in stable "
"positions and are disabled with an explanation when no draft change exists. Leaving while "
"dirty invokes the shared save-or-discard guard. Widget removal removes only the placement, "
"not the module data represented by the widget. Reset restores the defaults announced by "
"currently active modules and remains reversible until save. A widget is offered only when "
"its module, focused View surface, and permission contract are available. Widgets never grant "
+36 -42
View File
@@ -16,6 +16,7 @@ import {
DocumentationHelpLink,
LoadingFrame,
MetricCard,
PageActionBar,
PageLayout,
dashboardWidgetsForModules,
hasAnyScope,
@@ -443,53 +444,46 @@ export default function DashboardPage({
return (
<PageLayout
archetype={configuring ? "editor" : "overview"}
className="dashboard-page"
title="i18n:govoplan-dashboard.dashboard.3f8b4df2"
description="Personal workspace assembled from installed module widgets."
error={error}
success={error ? "" : notice}
actions={
<>
<DocumentationHelpLink reference={DASHBOARD_DOCUMENTATION} />
{!configuring && (
<>
<Button
onClick={() => setRefreshKey((value) => value + 1)}
disabled={loading}
disabledReason={loading ? DASHBOARD_I18N.loading : undefined}
>
<RefreshCw size={16} /> Refresh
</Button>
<Button
onClick={beginConfiguration}
disabled={loading}
disabledReason={loading ? DASHBOARD_I18N.loading : undefined}
>
<SlidersHorizontal size={16} /> Configure
</Button>
</>
)}
{configuring && (
<>
<Button
onClick={discardChanges}
disabled={saving}
disabledReason={saving ? DASHBOARD_I18N.saving : undefined}
>
<X size={16} /> Cancel
</Button>
<Button
variant="primary"
onClick={() => void persistLayout()}
disabled={saving || !dirty}
disabledReason={saving ? DASHBOARD_I18N.saving : !dirty ? DASHBOARD_I18N.noChanges : undefined}
>
<Save size={16} /> {saving ? "Saving..." : "Save layout"}
</Button>
</>
)}
</>
}
actions={configuring ? (
<PageActionBar
variant="editor"
dirty={dirty}
saving={saving}
helpAction={<DocumentationHelpLink reference={DASHBOARD_DOCUMENTATION} />}
discardAction={{ label: <><X size={16} /> Cancel</>, onClick: discardChanges }}
saveAction={{ label: <><Save size={16} /> Save layout</>, onClick: () => void persistLayout() }}
/>
) : (
<PageActionBar
variant="overview"
refreshable
reloadAction={(
<Button
onClick={() => setRefreshKey((value) => value + 1)}
disabled={loading}
disabledReason={loading ? DASHBOARD_I18N.loading : undefined}
>
<RefreshCw size={16} /> Refresh
</Button>
)}
helpAction={<DocumentationHelpLink reference={DASHBOARD_DOCUMENTATION} />}
primaryActions={(
<Button
onClick={beginConfiguration}
disabled={loading}
disabledReason={loading ? DASHBOARD_I18N.loading : undefined}
>
<SlidersHorizontal size={16} /> Configure
</Button>
)}
/>
)}
>
<MetricGrid className="dashboard-summary-metrics">