refactor(webui): adopt semantic workspace actions

This commit is contained in:
2026-08-19 18:47:45 +02:00
parent 178d08c729
commit 0d7d18c486
+21 -15
View File
@@ -1,7 +1,6 @@
import { Download, Pencil, Plus, RefreshCw, Search, Upload } from "lucide-react"; import { Download, Pencil, Plus, Search, Upload } from "lucide-react";
import { useCallback, useEffect, useRef, useState, type FormEvent } from "react"; import { useCallback, useEffect, useRef, useState, type FormEvent } from "react";
import { ActionToolbar, import { ActionBlockerHint,
ActionBlockerHint,
Button, Button,
Dialog, Dialog,
DocumentationHelpLink, DocumentationHelpLink,
@@ -16,6 +15,7 @@ import { ActionToolbar,
hasScope, hasScope,
useUnsavedChanges, useUnsavedChanges,
useUnsavedDraftGuard, useUnsavedDraftGuard,
WorkspaceActionBar,
WorkspaceFrame, WorkspaceFrame,
type PlatformRouteContext type PlatformRouteContext
} from "@govoplan/core-webui"; } from "@govoplan/core-webui";
@@ -148,13 +148,19 @@ export default function FormsPage({ settings, auth }: PlatformRouteContext) {
return ( return (
<main className="forms-page"> <main className="forms-page">
<WorkspaceFrame className="forms-shell" label="Form definitions" interfaceId="forms.catalogue" helpContextId="forms.page.catalogue" helpModuleId="forms"> <WorkspaceFrame className="forms-shell" label="Form definitions" interfaceId="forms.catalogue" helpContextId="forms.page.catalogue" helpModuleId="forms">
<ActionToolbar surface="panel-header" className="forms-toolbar"> <WorkspaceActionBar
<FilterBar as="form" surface="control" wrap="never" width="default" onSubmit={search} className="forms-search"> scope="workspace"
variant="collection"
refreshable
reloadAction={{ onReload: () => void load(), loading, label: "Refresh definitions" }}
className="forms-toolbar"
contextActions={<>
<FilterBar as="form" surface="control" wrap="never" width="default" onSubmit={search} className="forms-search">
<Search size={17} aria-hidden="true" /> <Search size={17} aria-hidden="true" />
<input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search definitions" aria-label="Search Form definitions" /> <input value={query} onChange={(event) => setQuery(event.target.value)} placeholder="Search definitions" aria-label="Search Form definitions" />
<Button type="submit">Search</Button> <Button type="submit">Search</Button>
</FilterBar> </FilterBar>
<label> <label>
<span>State</span> <span>State</span>
<select value={state} onChange={(event) => setState(event.target.value)}> <select value={state} onChange={(event) => setState(event.target.value)}>
<option value="">All</option> <option value="">All</option>
@@ -162,14 +168,14 @@ export default function FormsPage({ settings, auth }: PlatformRouteContext) {
<option value="published">Published</option> <option value="published">Published</option>
<option value="retired">Retired</option> <option value="retired">Retired</option>
</select> </select>
</label> </label>
<IconButton label="Refresh definitions" icon={<RefreshCw size={16} />} onClick={() => void load()} disabled={loading} disabledReason={loading ? FORMS_I18N.loading : undefined} /> <IconButton label="Import Form package" icon={<Upload size={16} />} onClick={() => importInput.current?.click()} disabled={loading || !canWrite} disabledReason={loading ? FORMS_I18N.loading : !canWrite ? FORMS_I18N.writeReason : undefined} />
<IconButton label="Import Form package" icon={<Upload size={16} />} onClick={() => importInput.current?.click()} disabled={loading || !canWrite} disabledReason={loading ? FORMS_I18N.loading : !canWrite ? FORMS_I18N.writeReason : undefined} /> <input ref={importInput} className="forms-hidden-input" type="file" accept="application/json,.json" onChange={(event) => void choosePackage(event.target.files?.[0])} />
<input ref={importInput} className="forms-hidden-input" type="file" accept="application/json,.json" onChange={(event) => void choosePackage(event.target.files?.[0])} /> <span className="forms-count">{total}</span>
<Button variant="primary" disabled={!canWrite} disabledReason={!canWrite ? FORMS_I18N.writeReason : undefined} onClick={() => setEditing("new")}><Plus size={16} aria-hidden="true" />New definition</Button> </>}
<span className="forms-count">{total}</span> createAction={<Button variant="primary" disabled={!canWrite} disabledReason={!canWrite ? FORMS_I18N.writeReason : undefined} onClick={() => setEditing("new")}><Plus size={16} aria-hidden="true" />New definition</Button>}
<DocumentationHelpLink reference={FORMS_DOCUMENTATION} /> helpAction={<DocumentationHelpLink reference={FORMS_DOCUMENTATION} />}
</ActionToolbar> />
<PageScrollViewport className="forms-list-viewport"> <PageScrollViewport className="forms-list-viewport">
{error && <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert>} {error && <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert>}
{!canWrite && <ActionBlockerHint tone="info" reason={{ summary: "No Form management permission", details: FORMS_I18N.writeReason, requiredAction: FORMS_I18N.permissionAction, actor: FORMS_I18N.permissionActor, target: FORMS_I18N.permissionDestination }} labels={{ requiredAction: FORMS_I18N.requiredAction, actor: FORMS_I18N.actor, target: FORMS_I18N.destination }} documentation={FORMS_DOCUMENTATION} />} {!canWrite && <ActionBlockerHint tone="info" reason={{ summary: "No Form management permission", details: FORMS_I18N.writeReason, requiredAction: FORMS_I18N.permissionAction, actor: FORMS_I18N.permissionActor, target: FORMS_I18N.permissionDestination }} labels={{ requiredAction: FORMS_I18N.requiredAction, actor: FORMS_I18N.actor, target: FORMS_I18N.destination }} documentation={FORMS_DOCUMENTATION} />}