refactor(webui): adopt semantic workspace actions

This commit is contained in:
2026-08-19 18:47:45 +02:00
parent 3f1177abbd
commit bcc6bdd2d7
@@ -14,7 +14,7 @@ import {
useRef, useRef,
useState useState
} from "react"; } from "react";
import { DialogSection, ToolbarGroup, FormGrid, ActionToolbar, import { DialogSection, FormGrid, ActionToolbar,
ApiError, ApiError,
Button, Button,
ConfirmDialog, ConfirmDialog,
@@ -38,6 +38,7 @@ import { DialogSection, ToolbarGroup, FormGrid, ActionToolbar,
StatePanel, StatePanel,
StatusBadge, StatusBadge,
ToggleSwitch, ToggleSwitch,
WorkspaceActionBar,
WorkspaceFrame, WorkspaceFrame,
WorkspaceLayout, WorkspaceLayout,
formatDateTime, formatDateTime,
@@ -549,27 +550,21 @@ export default function DistributionListsPage({ settings, auth }: Props) {
contentLabel="Distribution list workspace" contentLabel="Distribution list workspace"
contentClassName="dist-lists-workspace" contentClassName="dist-lists-workspace"
primary={<> primary={<>
<ActionToolbar surface="panel-header"> <WorkspaceActionBar
<strong>Distribution Lists</strong> scope="collection-pane"
<span> variant="collection"
<IconButton refreshable
label="Refresh" reloadAction={{ onReload: () => void reload(selectedId), loading: loading || busy }}
icon={<RefreshCw size={16} />} contextActions={<strong>Distribution Lists</strong>}
variant="ghost" createAction={<IconButton
disabled={loading || busy} label="New distribution list"
disabledReason={loading ? DIST_LISTS_I18N.loading : busy ? DIST_LISTS_I18N.busy : undefined} icon={<Plus size={17} />}
onClick={() => void reload(selectedId)} variant="primary"
/> disabled={!canWrite}
<IconButton disabledReason={!canWrite ? DIST_LISTS_I18N.writeReason : undefined}
label="New distribution list" onClick={() => requestDiscard(() => setCreateOpen(true))}
icon={<Plus size={17} />} />}
variant="primary" />
disabled={!canWrite}
disabledReason={!canWrite ? DIST_LISTS_I18N.writeReason : undefined}
onClick={() => requestDiscard(() => setCreateOpen(true))}
/>
</span>
</ActionToolbar>
<FilterBar surface="panel"> <FilterBar surface="panel">
<input <input
type="search" type="search"
@@ -596,14 +591,17 @@ export default function DistributionListsPage({ settings, auth }: Props) {
</LoadingFrame> </LoadingFrame>
</>} </>}
> >
<ActionToolbar surface="panel-header" className="dist-lists-workspace-toolbar"> <WorkspaceActionBar
<span className="dist-lists-current-title"> scope="editor-pane"
variant="editor"
state={busy ? "saving" : dirty ? "dirty" : "clean"}
className="dist-lists-workspace-toolbar"
contextActions={<span className="dist-lists-current-title">
<strong>{selected?.name ?? "No distribution list selected"}</strong> <strong>{selected?.name ?? "No distribution list selected"}</strong>
{selected ? <small>Revision {selected.current_revision} · {selected.scope_type} scope</small> : null} {selected ? <small>Revision {selected.current_revision} · {selected.scope_type} scope</small> : null}
</span> </span>}
<ToolbarGroup align="end" className="dist-lists-toolbar-actions"> helpAction={<DocumentationHelpLink reference={DIST_LISTS_DOCUMENTATION} />}
<DocumentationHelpLink reference={DIST_LISTS_DOCUMENTATION} /> primaryActions={<SegmentedControl<WorkspaceView>
<SegmentedControl<WorkspaceView>
ariaLabel="Distribution-list workspace" ariaLabel="Distribution-list workspace"
value={view} value={view}
onChange={(next) => next === "snapshots" ? void openSnapshots() : setView(next)} onChange={(next) => next === "snapshots" ? void openSnapshots() : setView(next)}
@@ -612,25 +610,27 @@ export default function DistributionListsPage({ settings, auth }: Props) {
{ id: "preview", label: "Preview" }, { id: "preview", label: "Preview" },
{ id: "snapshots", label: "Snapshots" } { id: "snapshots", label: "Snapshots" }
]} ]}
/> />}
<Button destructiveActions={<IconButton
variant="primary"
disabled={!selected || !dirty || busy || !canWrite}
disabledReason={busy ? DIST_LISTS_I18N.busy : !canWrite ? DIST_LISTS_I18N.writeReason : !selected ? DIST_LISTS_I18N.noSelection : !dirty ? DIST_LISTS_I18N.noChanges : undefined}
onClick={() => void saveItem()}
>
<Save size={16} /> Save revision
</Button>
<IconButton
label="Delete distribution list" label="Delete distribution list"
icon={<Trash2 size={16} />} icon={<Trash2 size={16} />}
variant="danger" variant="danger"
disabled={!selected || !canWrite} disabled={!selected || !canWrite}
disabledReason={!canWrite ? DIST_LISTS_I18N.writeReason : !selected ? DIST_LISTS_I18N.noSelection : undefined} disabledReason={!canWrite ? DIST_LISTS_I18N.writeReason : !selected ? DIST_LISTS_I18N.noSelection : undefined}
onClick={() => setDeleteOpen(true)} onClick={() => setDeleteOpen(true)}
/> />}
</ToolbarGroup> discardAction={{
</ActionToolbar> label: "Discard changes",
onClick: () => requestDiscard(() => void reload(selectedId)),
disabled: !selected
}}
saveAction={{
label: <><Save size={16} /> Save revision</>,
disabled: !selected || busy || !canWrite,
disabledReason: busy ? DIST_LISTS_I18N.busy : !canWrite ? DIST_LISTS_I18N.writeReason : !selected ? DIST_LISTS_I18N.noSelection : undefined,
onClick: () => void saveItem()
}}
/>
<div className="dist-lists-alerts"> <div className="dist-lists-alerts">
{error ? <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert> : null} {error ? <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert> : null}