Adopt shared WebUI structural primitives

This commit is contained in:
2026-08-18 13:17:31 +02:00
parent cb824749a4
commit e494cff561
3 changed files with 20 additions and 106 deletions
@@ -18,6 +18,7 @@ import { ActionToolbar,
usePlatformModuleInstalled, usePlatformModuleInstalled,
usePlatformLanguage, usePlatformLanguage,
useUnsavedDraftGuard, useUnsavedDraftGuard,
WorkspaceFrame,
type PlatformRouteContext type PlatformRouteContext
} from "@govoplan/core-webui"; } from "@govoplan/core-webui";
import { import {
@@ -310,8 +311,8 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
return ( return (
<main className="forms-runtime-page"> <main className="forms-runtime-page">
<div className="form-instance-shell"> <WorkspaceFrame className="form-instance-shell" label="Form instance" interfaceId="forms-runtime.instance" helpContextId="forms-runtime.page.instance" helpModuleId="forms-runtime">
<ActionToolbar className="form-instance-toolbar"> <ActionToolbar surface="panel-header" className="form-instance-toolbar">
<Button onClick={() => navigate("/forms-runtime")}> <Button onClick={() => navigate("/forms-runtime")}>
<ArrowLeft size={16} aria-hidden="true" /> <ArrowLeft size={16} aria-hidden="true" />
Forms Forms
@@ -527,7 +528,7 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
</div> </div>
} }
</PageScrollViewport> </PageScrollViewport>
</div> </WorkspaceFrame>
<ConfirmDialog <ConfirmDialog
open={confirmingAcknowledgement} open={confirmingAcknowledgement}
title="Record acknowledgement" title="Record acknowledgement"
+15 -16
View File
@@ -6,11 +6,16 @@ import { ActionToolbar,
DismissibleAlert, DismissibleAlert,
LoadingIndicator, LoadingIndicator,
PageScrollViewport, PageScrollViewport,
SelectionList,
SelectionListItem,
SelectionListItemContent,
StatePanel,
StatusBadge, StatusBadge,
hasScope, hasScope,
i18nMessage, i18nMessage,
useGuardedNavigate, useGuardedNavigate,
usePlatformLanguage, usePlatformLanguage,
WorkspaceFrame,
type PlatformRouteContext type PlatformRouteContext
} from "@govoplan/core-webui"; } from "@govoplan/core-webui";
import { listFormInstances, type FormInstance } from "../../api/formsRuntime"; import { listFormInstances, type FormInstance } from "../../api/formsRuntime";
@@ -57,8 +62,8 @@ export default function FormsRuntimePage({ settings, auth }: PlatformRouteContex
return ( return (
<main className="forms-runtime-page"> <main className="forms-runtime-page">
<div className="forms-runtime-shell"> <WorkspaceFrame className="forms-runtime-shell" label="Forms runtime" interfaceId="forms-runtime.workspace" helpContextId="forms-runtime.page.workspace" helpModuleId="forms-runtime">
<ActionToolbar className="forms-runtime-toolbar"> <ActionToolbar surface="panel-header" className="forms-runtime-toolbar">
<Button onClick={() => void load()} disabled={loading} disabledReason={loading ? FORMS_RUNTIME_I18N.loading : undefined}> <Button onClick={() => void load()} disabled={loading} disabledReason={loading ? FORMS_RUNTIME_I18N.loading : undefined}>
<RefreshCw size={16} aria-hidden="true" /> <RefreshCw size={16} aria-hidden="true" />
Refresh Refresh
@@ -94,29 +99,23 @@ export default function FormsRuntimePage({ settings, auth }: PlatformRouteContex
} }
{loading && <LoadingIndicator label="Loading forms" />} {loading && <LoadingIndicator label="Loading forms" />}
{!loading && !error && items.length === 0 && {!loading && !error && items.length === 0 &&
<div className="forms-runtime-empty">No matching Forms.</div> <StatePanel size="compact" description="No matching Forms." />
} }
{!loading && items.length > 0 && {!loading && items.length > 0 &&
<div className="forms-runtime-list" role="list"> <SelectionList variant="navigation" label="Forms">
{items.map((item) => {items.map((item) =>
<button <SelectionListItem
type="button"
role="listitem"
className="forms-runtime-row"
key={item.instance_id} key={item.instance_id}
selected={false}
onClick={() => navigate(`/forms-runtime/${encodeURIComponent(item.instance_id)}`)}> onClick={() => navigate(`/forms-runtime/${encodeURIComponent(item.instance_id)}`)}>
<span className="forms-runtime-row-main"> <SelectionListItemContent title={item.definition_ref.label ?? humanize(item.definition_ref.object_id)} description={`Revision ${item.definition_ref.version ?? "-"} · ${formatDateTime(item.recorded_at, language)}`} />
<strong>{item.definition_ref.label ?? humanize(item.definition_ref.object_id)}</strong>
<span>Revision {item.definition_ref.version ?? "-"}</span>
</span>
<span>{formatDateTime(item.recorded_at, language)}</span>
<StatusBadge status={isOpen(item.status) ? "active" : "inactive"} label={stateLabel(item.status)} /> <StatusBadge status={isOpen(item.status) ? "active" : "inactive"} label={stateLabel(item.status)} />
</button> </SelectionListItem>
)} )}
</div> </SelectionList>
} }
</PageScrollViewport> </PageScrollViewport>
</div> </WorkspaceFrame>
<IntakeProfilesDialog open={intakeOpen} settings={settings} onClose={() => setIntakeOpen(false)} /> <IntakeProfilesDialog open={intakeOpen} settings={settings} onClose={() => setIntakeOpen(false)} />
</main> </main>
); );
+1 -87
View File
@@ -1,29 +1,9 @@
.forms-runtime-page, .forms-runtime-page {
.forms-runtime-shell,
.form-instance-shell {
height: 100%; height: 100%;
min-height: 0; min-height: 0;
overflow: hidden; overflow: hidden;
} }
.forms-runtime-shell,
.form-instance-shell {
display: flex;
flex-direction: column;
background: var(--surface);
}
.forms-runtime-toolbar,
.form-instance-toolbar {
display: flex;
align-items: center;
gap: 14px;
min-height: 58px;
padding: 10px 18px;
border-bottom: 1px solid var(--border);
background: var(--surface-raised);
}
.forms-runtime-toolbar label { .forms-runtime-toolbar label {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -53,64 +33,6 @@
margin: 0 auto 16px; margin: 0 auto 16px;
} }
.forms-runtime-list {
overflow: hidden;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--surface-raised);
}
.forms-runtime-row {
display: grid;
grid-template-columns: minmax(260px, 1fr) minmax(170px, auto) auto;
align-items: center;
gap: 16px;
width: 100%;
min-height: 64px;
padding: 10px 14px;
border: 0;
border-bottom: 1px solid var(--border);
background: transparent;
color: inherit;
text-align: left;
cursor: pointer;
}
.forms-runtime-row:last-child {
border-bottom: 0;
}
.forms-runtime-row:hover,
.forms-runtime-row:focus-visible {
background: var(--hover-bg);
}
.forms-runtime-row-main {
display: flex;
min-width: 0;
flex-direction: column;
gap: 3px;
}
.forms-runtime-row-main strong,
.forms-runtime-row-main span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.forms-runtime-row-main span,
.forms-runtime-row > span:not(.status-badge) {
color: var(--text-soft);
font-size: 0.84rem;
}
.forms-runtime-empty {
padding: 36px 0;
color: var(--text-soft);
text-align: center;
}
.form-instance-content { .form-instance-content {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) minmax(280px, 360px); grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
@@ -545,14 +467,6 @@
} }
@media (max-width: 860px) { @media (max-width: 860px) {
.forms-runtime-row {
grid-template-columns: minmax(0, 1fr) auto;
}
.forms-runtime-row > span:not(.forms-runtime-row-main, .status-badge) {
display: none;
}
.form-instance-content { .form-instance-content {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }