Migrate Forms Runtime interface patterns
This commit is contained in:
@@ -2,15 +2,20 @@ import { ArrowLeft, ExternalLink, RefreshCw, Save, Send } from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import {
|
||||
ActionBlockerHint,
|
||||
Button,
|
||||
ConfirmDialog,
|
||||
DocumentationHelpLink,
|
||||
DismissibleAlert,
|
||||
LoadingIndicator,
|
||||
PageScrollViewport,
|
||||
StatusBadge,
|
||||
ToggleSwitch,
|
||||
hasScope,
|
||||
i18nMessage,
|
||||
useGuardedNavigate,
|
||||
usePlatformLanguage,
|
||||
useUnsavedDraftGuard,
|
||||
type PlatformRouteContext
|
||||
} from "@govoplan/core-webui";
|
||||
import {
|
||||
@@ -31,11 +36,17 @@ import {
|
||||
type FormHandoff,
|
||||
type ValidationResult
|
||||
} from "../../api/formsRuntime";
|
||||
import {
|
||||
FORMS_RUNTIME_DOCUMENTATION,
|
||||
FORMS_RUNTIME_FIELD_DOCUMENTATION,
|
||||
FORMS_RUNTIME_I18N
|
||||
} from "./interfacePatterns";
|
||||
|
||||
|
||||
export default function FormInstancePage({ settings, auth }: PlatformRouteContext) {
|
||||
const { instanceId = "" } = useParams();
|
||||
const navigate = useGuardedNavigate();
|
||||
const { language } = usePlatformLanguage();
|
||||
const [instance, setInstance] = useState<FormInstance | null>(null);
|
||||
const [definition, setDefinition] = useState<FormDefinition | null>(null);
|
||||
const [history, setHistory] = useState<FormInstance[]>([]);
|
||||
@@ -50,6 +61,8 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
const [handoffKind, setHandoffKind] = useState<"case" | "workflow">("case");
|
||||
const [handoffBinding, setHandoffBinding] = useState("");
|
||||
const [compensating, setCompensating] = useState<FormHandoff | null>(null);
|
||||
const [confirmingSubmit, setConfirmingSubmit] = useState(false);
|
||||
const [confirmingHandoff, setConfirmingHandoff] = useState(false);
|
||||
|
||||
const load = useCallback(async (signal?: AbortSignal) => {
|
||||
setLoading(true);
|
||||
@@ -91,8 +104,13 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
}
|
||||
}, [definition, handoffKind]);
|
||||
|
||||
const editable = instance?.status === "started" || instance?.status === "draft";
|
||||
const canSave = instance?.status === "draft" && definition?.allow_drafts;
|
||||
const editableLifecycle = instance?.status === "started" || instance?.status === "draft";
|
||||
const canParticipate = hasScope(auth, "forms_runtime:submission:participate");
|
||||
const canWrite = hasScope(auth, "forms_runtime:workspace:write");
|
||||
const canAdmin = hasScope(auth, "forms_runtime:workspace:admin");
|
||||
const canEditPermission = canParticipate || canWrite;
|
||||
const editable = Boolean(editableLifecycle && canEditPermission);
|
||||
const canSave = Boolean(instance?.status === "draft" && definition?.allow_drafts && canEditPermission);
|
||||
const changed = useMemo(
|
||||
() => Boolean(instance && JSON.stringify(values) !== JSON.stringify(instance.values)),
|
||||
[instance, values]
|
||||
@@ -106,30 +124,43 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
return grouped;
|
||||
}, [instance]);
|
||||
const localized = useMemo(
|
||||
() => localizeDefinition(definition),
|
||||
[definition]
|
||||
() => localizeDefinition(definition, language),
|
||||
[definition, language]
|
||||
);
|
||||
const groups = useMemo(
|
||||
() => definition ? visibleGroups(definition, values) : [],
|
||||
[definition, values]
|
||||
);
|
||||
const mayHandoff = Boolean(instance && ["submitted", "validated", "needs_review", "accepted"].includes(instance.status) && instance.service_ref);
|
||||
const canAdmin = hasScope(auth, "forms_runtime:workspace:admin");
|
||||
const canHandoff = canWrite || canAdmin;
|
||||
|
||||
async function save() {
|
||||
if (!instance || !canSave || !changed || !changeReason.trim()) return;
|
||||
async function save(): Promise<boolean> {
|
||||
if (!instance || !canSave || !changed || !changeReason.trim()) return false;
|
||||
setSaving(true);
|
||||
setError("");
|
||||
try {
|
||||
await saveFormDraft(settings, instance, values, changeReason.trim());
|
||||
await load();
|
||||
return true;
|
||||
} catch (reason) {
|
||||
setError(reason instanceof Error ? reason.message : "The draft could not be saved.");
|
||||
return false;
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
useUnsavedDraftGuard({
|
||||
dirty: Boolean(instance && (changed || changeReason)),
|
||||
onSave: save,
|
||||
onDiscard: () => {
|
||||
setValues(instance?.values ?? {});
|
||||
setChangeReason("");
|
||||
},
|
||||
title: "i18n:govoplan-forms-runtime.unsaved_title",
|
||||
message: "i18n:govoplan-forms-runtime.unsaved_message"
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
if (!instance || !editable) return;
|
||||
setSaving(true);
|
||||
@@ -195,7 +226,8 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
Forms
|
||||
</Button>
|
||||
{definition && <strong>{localized.title}</strong>}
|
||||
{instance && <StatusBadge status={editable ? "active" : "inactive"} label={humanize(instance.status)} />}
|
||||
{instance && <StatusBadge status={editableLifecycle ? "active" : "inactive"} label={stateLabel(instance.status)} />}
|
||||
<DocumentationHelpLink reference={FORMS_RUNTIME_DOCUMENTATION} />
|
||||
</div>
|
||||
<PageScrollViewport className="form-instance-viewport">
|
||||
{error &&
|
||||
@@ -204,6 +236,23 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
</DismissibleAlert>
|
||||
}
|
||||
{loading && <LoadingIndicator label="Loading Form" />}
|
||||
{!loading && instance && !editable &&
|
||||
<ActionBlockerHint
|
||||
tone="info"
|
||||
reason={canEditPermission ? {
|
||||
summary: "Read-only Form",
|
||||
details: FORMS_RUNTIME_I18N.lifecycleReason
|
||||
} : {
|
||||
summary: "Read-only Form",
|
||||
details: FORMS_RUNTIME_I18N.editReason,
|
||||
requiredAction: FORMS_RUNTIME_I18N.permissionAction,
|
||||
actor: FORMS_RUNTIME_I18N.permissionActor,
|
||||
target: FORMS_RUNTIME_I18N.permissionDestination
|
||||
}}
|
||||
labels={{ requiredAction: FORMS_RUNTIME_I18N.requiredAction, actor: FORMS_RUNTIME_I18N.actor, target: FORMS_RUNTIME_I18N.destination }}
|
||||
documentation={FORMS_RUNTIME_DOCUMENTATION}
|
||||
/>
|
||||
}
|
||||
{!loading && instance && definition &&
|
||||
<div className="form-instance-content">
|
||||
<section className="form-instance-main">
|
||||
@@ -226,7 +275,7 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
}}
|
||||
optionLabels={localized.optionLabels[field.key] ?? {}}
|
||||
value={values[field.key]}
|
||||
disabled={!editable || saving}
|
||||
disabled={!editable || saving}
|
||||
diagnostics={diagnostics.get(field.key) ?? []}
|
||||
onChange={(value) => setValues((current) => {
|
||||
const next = { ...current };
|
||||
@@ -247,6 +296,7 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
}
|
||||
{editable &&
|
||||
<div className="form-instance-actions">
|
||||
<DocumentationHelpLink reference={FORMS_RUNTIME_FIELD_DOCUMENTATION} />
|
||||
{canSave &&
|
||||
<label className="form-change-reason">
|
||||
<span>Change reason</span>
|
||||
@@ -260,12 +310,13 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
{canSave &&
|
||||
<Button
|
||||
onClick={() => void save()}
|
||||
disabled={!changed || !changeReason.trim() || saving}>
|
||||
disabled={!changed || !changeReason.trim() || saving}
|
||||
disabledReason={saving ? FORMS_RUNTIME_I18N.saving : !changed ? FORMS_RUNTIME_I18N.unchanged : !changeReason.trim() ? FORMS_RUNTIME_I18N.changeReason : undefined}>
|
||||
<Save size={16} aria-hidden="true" />
|
||||
Save draft
|
||||
</Button>
|
||||
}
|
||||
<Button variant="primary" onClick={() => void submit()} disabled={saving}>
|
||||
<Button variant="primary" onClick={() => setConfirmingSubmit(true)} disabled={saving} disabledReason={saving ? FORMS_RUNTIME_I18N.saving : undefined}>
|
||||
<Send size={16} aria-hidden="true" />
|
||||
Submit
|
||||
</Button>
|
||||
@@ -288,7 +339,7 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
{definition.handoff_kinds.includes("workflow") && <option value="workflow">Start Workflow</option>}
|
||||
</select>
|
||||
<input value={handoffBinding} disabled={handoffBusy} onChange={(event) => setHandoffBinding(event.target.value)} placeholder="Target binding (optional)" aria-label="Exact target binding" />
|
||||
<Button variant="primary" disabled={handoffBusy} onClick={() => void startHandoff()}><Send size={15} aria-hidden="true" />Start</Button>
|
||||
<Button variant="primary" disabled={handoffBusy || !canHandoff} disabledReason={handoffBusy ? FORMS_RUNTIME_I18N.saving : !canHandoff ? FORMS_RUNTIME_I18N.handoffReason : undefined} onClick={() => setConfirmingHandoff(true)}><Send size={15} aria-hidden="true" />Start</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -296,13 +347,13 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
<div className="form-handoff-list">
|
||||
{handoffs.map((item) =>
|
||||
<div className="form-handoff-row" key={item.effect_id}>
|
||||
<span><strong>{humanize(item.binding_kind)}</strong><small>{item.binding_reference}</small></span>
|
||||
<StatusBadge status={item.state === "accepted" || item.state === "reconciled" ? "active" : "inactive"} label={humanize(item.state)} />
|
||||
<span><strong>{domainLabel(item.binding_kind)}</strong><small>{item.binding_reference}</small></span>
|
||||
<StatusBadge status={item.state === "accepted" || item.state === "reconciled" ? "active" : "inactive"} label={stateLabel(item.state)} />
|
||||
{item.last_error && <span className="form-handoff-error">{item.last_error}</span>}
|
||||
<span className="form-handoff-actions">
|
||||
{item.href && <Button onClick={() => navigate(item.href!)}><ExternalLink size={15} aria-hidden="true" />Open</Button>}
|
||||
{item.state === "rejected" && <Button disabled={handoffBusy} onClick={() => void handoffAction(item, "retry")}><RefreshCw size={15} aria-hidden="true" />Retry</Button>}
|
||||
{item.state === "outcome_unknown" && <Button disabled={handoffBusy} onClick={() => void handoffAction(item, "reconcile")}><RefreshCw size={15} aria-hidden="true" />Reconcile</Button>}
|
||||
{item.state === "rejected" && <Button disabled={handoffBusy || !canHandoff} disabledReason={handoffBusy ? FORMS_RUNTIME_I18N.saving : !canHandoff ? FORMS_RUNTIME_I18N.handoffReason : undefined} onClick={() => void handoffAction(item, "retry")}><RefreshCw size={15} aria-hidden="true" />Retry</Button>}
|
||||
{item.state === "outcome_unknown" && <Button disabled={handoffBusy || !canHandoff} disabledReason={handoffBusy ? FORMS_RUNTIME_I18N.saving : !canHandoff ? FORMS_RUNTIME_I18N.handoffReason : undefined} onClick={() => void handoffAction(item, "reconcile")}><RefreshCw size={15} aria-hidden="true" />Reconcile</Button>}
|
||||
{canAdmin && (item.state === "rejected" || item.state === "outcome_unknown") && <Button variant="danger" disabled={handoffBusy} onClick={() => setCompensating(item)}>Compensate</Button>}
|
||||
</span>
|
||||
</div>
|
||||
@@ -317,9 +368,9 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
<ol>
|
||||
{events.map((event) =>
|
||||
<li key={event.event_id}>
|
||||
<strong>{humanize(event.status)}</strong>
|
||||
<strong>{stateLabel(event.status)}</strong>
|
||||
<span>{humanize(event.event_type)}</span>
|
||||
<time>{formatDateTime(event.occurred_at)}</time>
|
||||
<time>{formatDateTime(event.occurred_at, language)}</time>
|
||||
</li>
|
||||
)}
|
||||
</ol>
|
||||
@@ -331,7 +382,7 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
<li key={item.revision}>
|
||||
<strong>Revision {item.revision}</strong>
|
||||
<span>{item.change_reason}</span>
|
||||
<time>{formatDateTime(item.recorded_at)}</time>
|
||||
<time>{formatDateTime(item.recorded_at, language)}</time>
|
||||
</li>
|
||||
)}
|
||||
</ol>
|
||||
@@ -341,6 +392,30 @@ export default function FormInstancePage({ settings, auth }: PlatformRouteContex
|
||||
}
|
||||
</PageScrollViewport>
|
||||
</div>
|
||||
<ConfirmDialog
|
||||
open={confirmingSubmit}
|
||||
title="i18n:govoplan-forms-runtime.submit_title"
|
||||
message="i18n:govoplan-forms-runtime.submit_message"
|
||||
confirmLabel="Submit"
|
||||
busy={saving}
|
||||
onCancel={() => setConfirmingSubmit(false)}
|
||||
onConfirm={() => {
|
||||
setConfirmingSubmit(false);
|
||||
void submit();
|
||||
}}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
open={confirmingHandoff}
|
||||
title="i18n:govoplan-forms-runtime.handoff_title"
|
||||
message={i18nMessage("i18n:govoplan-forms-runtime.handoff_message", { kind: domainLabel(handoffKind) })}
|
||||
confirmLabel="Start"
|
||||
busy={handoffBusy}
|
||||
onCancel={() => setConfirmingHandoff(false)}
|
||||
onConfirm={() => {
|
||||
setConfirmingHandoff(false);
|
||||
void startHandoff();
|
||||
}}
|
||||
/>
|
||||
<ConfirmDialog
|
||||
open={Boolean(compensating)}
|
||||
title="Compensate handoff"
|
||||
@@ -565,7 +640,7 @@ function comparable(left: unknown, right: unknown, compare: (left: number | stri
|
||||
return false;
|
||||
}
|
||||
|
||||
function localizeDefinition(definition: FormDefinition | null) {
|
||||
function localizeDefinition(definition: FormDefinition | null, language: string) {
|
||||
const canonical = {
|
||||
title: definition?.title ?? "",
|
||||
description: definition?.description ?? null,
|
||||
@@ -575,8 +650,8 @@ function localizeDefinition(definition: FormDefinition | null) {
|
||||
sectionTitles: {} as Record<string, string>
|
||||
};
|
||||
if (!definition?.localizations?.length) return canonical;
|
||||
const browserLocales = navigator.languages.map((value) => value.toLowerCase());
|
||||
const localization = definition.localizations.find((item) => browserLocales.some((locale) => locale === item.locale.toLowerCase() || locale.startsWith(`${item.locale.toLowerCase()}-`)))
|
||||
const requestedLocale = language.toLowerCase();
|
||||
const localization = definition.localizations.find((item) => requestedLocale === item.locale.toLowerCase() || requestedLocale.startsWith(`${item.locale.toLowerCase()}-`))
|
||||
?? definition.localizations.find((item) => item.locale.toLowerCase() === definition.fallback_locale?.toLowerCase());
|
||||
if (!localization) return canonical;
|
||||
return {
|
||||
@@ -589,10 +664,18 @@ function localizeDefinition(definition: FormDefinition | null) {
|
||||
};
|
||||
}
|
||||
|
||||
function formatDateTime(value: string): string {
|
||||
return new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
||||
function formatDateTime(value: string, locale?: string): string {
|
||||
return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
||||
}
|
||||
|
||||
function humanize(value: string): string {
|
||||
return value.replace(/[_:.-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
||||
}
|
||||
|
||||
function stateLabel(value: string): string {
|
||||
return `i18n:govoplan-forms-runtime.state_${value}`;
|
||||
}
|
||||
|
||||
function domainLabel(value: string): string {
|
||||
return `i18n:govoplan-forms-runtime.domain_${value}`;
|
||||
}
|
||||
|
||||
@@ -2,20 +2,25 @@ import { RefreshCw } from "lucide-react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
DocumentationHelpLink,
|
||||
DismissibleAlert,
|
||||
LoadingIndicator,
|
||||
PageScrollViewport,
|
||||
StatusBadge,
|
||||
i18nMessage,
|
||||
useGuardedNavigate,
|
||||
usePlatformLanguage,
|
||||
type PlatformRouteContext
|
||||
} from "@govoplan/core-webui";
|
||||
import { listFormInstances, type FormInstance } from "../../api/formsRuntime";
|
||||
import { FORMS_RUNTIME_DOCUMENTATION, FORMS_RUNTIME_I18N } from "./interfacePatterns";
|
||||
|
||||
|
||||
const OPEN_STATUSES = ["started", "draft", "submitted", "validated", "needs_review"];
|
||||
|
||||
export default function FormsRuntimePage({ settings }: PlatformRouteContext) {
|
||||
const navigate = useGuardedNavigate();
|
||||
const { language } = usePlatformLanguage();
|
||||
const [items, setItems] = useState<FormInstance[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [status, setStatus] = useState("open");
|
||||
@@ -50,7 +55,7 @@ export default function FormsRuntimePage({ settings }: PlatformRouteContext) {
|
||||
<main className="forms-runtime-page">
|
||||
<div className="forms-runtime-shell">
|
||||
<div className="forms-runtime-toolbar">
|
||||
<Button onClick={() => void load()} disabled={loading}>
|
||||
<Button onClick={() => void load()} disabled={loading} disabledReason={loading ? FORMS_RUNTIME_I18N.loading : undefined}>
|
||||
<RefreshCw size={16} aria-hidden="true" />
|
||||
Refresh
|
||||
</Button>
|
||||
@@ -68,7 +73,8 @@ export default function FormsRuntimePage({ settings }: PlatformRouteContext) {
|
||||
<option value="archived">Archived</option>
|
||||
</select>
|
||||
</label>
|
||||
<span className="forms-runtime-count">{total} forms</span>
|
||||
<span className="forms-runtime-count">{i18nMessage("i18n:govoplan-forms-runtime.form_count", { total })}</span>
|
||||
<DocumentationHelpLink reference={FORMS_RUNTIME_DOCUMENTATION} />
|
||||
</div>
|
||||
<PageScrollViewport className="forms-runtime-list-viewport">
|
||||
{error &&
|
||||
@@ -93,8 +99,8 @@ export default function FormsRuntimePage({ settings }: PlatformRouteContext) {
|
||||
<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)}</span>
|
||||
<StatusBadge status={isOpen(item.status) ? "active" : "inactive"} label={humanize(item.status)} />
|
||||
<span>{formatDateTime(item.recorded_at, language)}</span>
|
||||
<StatusBadge status={isOpen(item.status) ? "active" : "inactive"} label={stateLabel(item.status)} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -109,10 +115,14 @@ function isOpen(status: string): boolean {
|
||||
return OPEN_STATUSES.includes(status);
|
||||
}
|
||||
|
||||
function formatDateTime(value: string): string {
|
||||
return new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
||||
function formatDateTime(value: string, locale?: string): string {
|
||||
return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
||||
}
|
||||
|
||||
function humanize(value: string): string {
|
||||
return value.replace(/[_:.-]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
||||
}
|
||||
|
||||
function stateLabel(value: string): string {
|
||||
return `i18n:govoplan-forms-runtime.state_${value}`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { DocumentationHelpReference } from "@govoplan/core-webui";
|
||||
|
||||
export const FORMS_RUNTIME_DOCUMENTATION = {
|
||||
topicId: "forms_runtime.submissions",
|
||||
documentationType: "user"
|
||||
} satisfies DocumentationHelpReference;
|
||||
|
||||
export const FORMS_RUNTIME_FIELD_DOCUMENTATION = {
|
||||
topicId: "forms_runtime.reference.fields-and-consequences",
|
||||
documentationType: "admin"
|
||||
} satisfies DocumentationHelpReference;
|
||||
|
||||
export const FORMS_RUNTIME_I18N = {
|
||||
loading: "i18n:govoplan-forms-runtime.loading_reason",
|
||||
saving: "i18n:govoplan-forms-runtime.saving_reason",
|
||||
editReason: "i18n:govoplan-forms-runtime.edit_permission_reason",
|
||||
handoffReason: "i18n:govoplan-forms-runtime.handoff_permission_reason",
|
||||
lifecycleReason: "i18n:govoplan-forms-runtime.lifecycle_reason",
|
||||
unchanged: "i18n:govoplan-forms-runtime.unchanged_reason",
|
||||
changeReason: "i18n:govoplan-forms-runtime.change_reason_required",
|
||||
requiredAction: "i18n:govoplan-forms-runtime.required_action",
|
||||
actor: "i18n:govoplan-forms-runtime.responsible_actor",
|
||||
destination: "i18n:govoplan-forms-runtime.destination",
|
||||
permissionAction: "i18n:govoplan-forms-runtime.permission_action",
|
||||
permissionActor: "i18n:govoplan-forms-runtime.permission_actor",
|
||||
permissionDestination: "i18n:govoplan-forms-runtime.permission_destination"
|
||||
} as const;
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { PlatformTranslations } from "@govoplan/core-webui";
|
||||
|
||||
const en = {
|
||||
"i18n:govoplan-forms-runtime.forms": "Forms",
|
||||
"i18n:govoplan-forms-runtime.loading_reason": "Form data is still loading.",
|
||||
"i18n:govoplan-forms-runtime.saving_reason": "A Form operation is still running.",
|
||||
"i18n:govoplan-forms-runtime.edit_permission_reason": "Your account may read this Form but may not change or submit it.",
|
||||
"i18n:govoplan-forms-runtime.handoff_permission_reason": "Your account may not create or recover Case and Workflow handoffs.",
|
||||
"i18n:govoplan-forms-runtime.lifecycle_reason": "This Form is immutable in its current lifecycle state.",
|
||||
"i18n:govoplan-forms-runtime.unchanged_reason": "There are no changed values to save.",
|
||||
"i18n:govoplan-forms-runtime.change_reason_required": "Enter a change reason before saving the draft.",
|
||||
"i18n:govoplan-forms-runtime.required_action": "Required action",
|
||||
"i18n:govoplan-forms-runtime.responsible_actor": "Responsible actor",
|
||||
"i18n:govoplan-forms-runtime.destination": "Destination",
|
||||
"i18n:govoplan-forms-runtime.permission_action": "Ask for the appropriate Forms Runtime permission or assignment.",
|
||||
"i18n:govoplan-forms-runtime.permission_actor": "An Access administrator or the responsible process owner",
|
||||
"i18n:govoplan-forms-runtime.permission_destination": "Access role assignments or the assigning workflow",
|
||||
"i18n:govoplan-forms-runtime.unsaved_title": "Unsaved Form",
|
||||
"i18n:govoplan-forms-runtime.unsaved_message": "Save or discard the changed Form values before leaving this surface.",
|
||||
"i18n:govoplan-forms-runtime.submit_title": "Submit Form",
|
||||
"i18n:govoplan-forms-runtime.submit_message": "Submit this Form? The server validates the exact published definition and records an immutable receipt.",
|
||||
"i18n:govoplan-forms-runtime.handoff_title": "Start governed handoff",
|
||||
"i18n:govoplan-forms-runtime.handoff_message": "Start the {kind} handoff? Intent is recorded before execution and an unknown outcome requires reconciliation.",
|
||||
"i18n:govoplan-forms-runtime.form_count": "{total} forms",
|
||||
"i18n:govoplan-forms-runtime.state_started": "Started",
|
||||
"i18n:govoplan-forms-runtime.state_draft": "Draft",
|
||||
"i18n:govoplan-forms-runtime.state_submitted": "Submitted",
|
||||
"i18n:govoplan-forms-runtime.state_validated": "Validated",
|
||||
"i18n:govoplan-forms-runtime.state_needs_review": "Needs review",
|
||||
"i18n:govoplan-forms-runtime.state_accepted": "Accepted",
|
||||
"i18n:govoplan-forms-runtime.state_rejected": "Rejected",
|
||||
"i18n:govoplan-forms-runtime.state_handed_off": "Handed off",
|
||||
"i18n:govoplan-forms-runtime.state_archived": "Archived",
|
||||
"i18n:govoplan-forms-runtime.state_reconciled": "Reconciled",
|
||||
"i18n:govoplan-forms-runtime.state_outcome_unknown": "Outcome unknown",
|
||||
"i18n:govoplan-forms-runtime.state_requested": "Requested",
|
||||
"i18n:govoplan-forms-runtime.state_compensated": "Compensated",
|
||||
"i18n:govoplan-forms-runtime.domain_case": "Case",
|
||||
"i18n:govoplan-forms-runtime.domain_workflow": "Workflow",
|
||||
"Forms": "Forms",
|
||||
"Refresh": "Refresh",
|
||||
"Status": "Status",
|
||||
"Open": "Open",
|
||||
"All": "All",
|
||||
"Draft": "Draft",
|
||||
"Submitted": "Submitted",
|
||||
"Needs review": "Needs review",
|
||||
"Accepted": "Accepted",
|
||||
"Rejected": "Rejected",
|
||||
"Handed off": "Handed off",
|
||||
"Archived": "Archived",
|
||||
"Loading forms": "Loading forms",
|
||||
"No matching Forms.": "No matching Forms.",
|
||||
"Revision": "Revision",
|
||||
"Loading Form": "Loading Form",
|
||||
"Change reason": "Change reason",
|
||||
"Save draft": "Save draft",
|
||||
"Submit": "Submit",
|
||||
"Submission receipt": "Submission receipt",
|
||||
"Case and workflow handoffs": "Case and workflow handoffs",
|
||||
"Create Case": "Create Case",
|
||||
"Start Workflow": "Start Workflow",
|
||||
"Target binding (optional)": "Target binding (optional)",
|
||||
"Exact target binding": "Exact target binding",
|
||||
"Start": "Start",
|
||||
"No handoff has been requested.": "No handoff has been requested.",
|
||||
"Open target": "Open target",
|
||||
"Retry": "Retry",
|
||||
"Reconcile": "Reconcile",
|
||||
"Compensate": "Compensate",
|
||||
"Status history": "Status history",
|
||||
"Revisions": "Revisions",
|
||||
"Select": "Select",
|
||||
"Compensate handoff": "Compensate handoff",
|
||||
"Confirm absent and compensate": "Confirm absent and compensate",
|
||||
"Read-only Form": "Read-only Form"
|
||||
} as const;
|
||||
|
||||
const de: Record<keyof typeof en, string> = {
|
||||
"i18n:govoplan-forms-runtime.forms": "Formulare",
|
||||
"i18n:govoplan-forms-runtime.loading_reason": "Formulardaten werden noch geladen.",
|
||||
"i18n:govoplan-forms-runtime.saving_reason": "Eine Formularaktion läuft noch.",
|
||||
"i18n:govoplan-forms-runtime.edit_permission_reason": "Ihr Konto darf dieses Formular lesen, aber nicht ändern oder absenden.",
|
||||
"i18n:govoplan-forms-runtime.handoff_permission_reason": "Ihr Konto darf keine Fall- oder Workflow-Übergaben erstellen oder wiederherstellen.",
|
||||
"i18n:govoplan-forms-runtime.lifecycle_reason": "Dieses Formular ist in seinem aktuellen Lebenszyklus unveränderlich.",
|
||||
"i18n:govoplan-forms-runtime.unchanged_reason": "Es gibt keine geänderten Werte zu speichern.",
|
||||
"i18n:govoplan-forms-runtime.change_reason_required": "Geben Sie vor dem Speichern des Entwurfs einen Änderungsgrund ein.",
|
||||
"i18n:govoplan-forms-runtime.required_action": "Erforderliche Aktion",
|
||||
"i18n:govoplan-forms-runtime.responsible_actor": "Verantwortliche Stelle",
|
||||
"i18n:govoplan-forms-runtime.destination": "Ziel",
|
||||
"i18n:govoplan-forms-runtime.permission_action": "Fordern Sie die passende Formularberechtigung oder Zuweisung an.",
|
||||
"i18n:govoplan-forms-runtime.permission_actor": "Eine Zugriffsadministration oder die verantwortliche Prozessstelle",
|
||||
"i18n:govoplan-forms-runtime.permission_destination": "Zugriff und Rollenzuweisungen oder der zuweisende Workflow",
|
||||
"i18n:govoplan-forms-runtime.unsaved_title": "Ungespeichertes Formular",
|
||||
"i18n:govoplan-forms-runtime.unsaved_message": "Speichern oder verwerfen Sie die geänderten Formularwerte, bevor Sie diese Oberfläche verlassen.",
|
||||
"i18n:govoplan-forms-runtime.submit_title": "Formular absenden",
|
||||
"i18n:govoplan-forms-runtime.submit_message": "Dieses Formular absenden? Der Server prüft die exakte veröffentlichte Definition und erfasst einen unveränderlichen Beleg.",
|
||||
"i18n:govoplan-forms-runtime.handoff_title": "Geregelte Übergabe starten",
|
||||
"i18n:govoplan-forms-runtime.handoff_message": "Die Übergabe an {kind} starten? Die Absicht wird vor der Ausführung erfasst; ein unbekanntes Ergebnis muss abgeglichen werden.",
|
||||
"i18n:govoplan-forms-runtime.form_count": "{total} Formulare",
|
||||
"i18n:govoplan-forms-runtime.state_started": "Gestartet",
|
||||
"i18n:govoplan-forms-runtime.state_draft": "Entwurf",
|
||||
"i18n:govoplan-forms-runtime.state_submitted": "Abgesendet",
|
||||
"i18n:govoplan-forms-runtime.state_validated": "Validiert",
|
||||
"i18n:govoplan-forms-runtime.state_needs_review": "Prüfung erforderlich",
|
||||
"i18n:govoplan-forms-runtime.state_accepted": "Angenommen",
|
||||
"i18n:govoplan-forms-runtime.state_rejected": "Abgelehnt",
|
||||
"i18n:govoplan-forms-runtime.state_handed_off": "Übergeben",
|
||||
"i18n:govoplan-forms-runtime.state_archived": "Archiviert",
|
||||
"i18n:govoplan-forms-runtime.state_reconciled": "Abgeglichen",
|
||||
"i18n:govoplan-forms-runtime.state_outcome_unknown": "Ergebnis unbekannt",
|
||||
"i18n:govoplan-forms-runtime.state_requested": "Angefordert",
|
||||
"i18n:govoplan-forms-runtime.state_compensated": "Kompensiert",
|
||||
"i18n:govoplan-forms-runtime.domain_case": "Fall",
|
||||
"i18n:govoplan-forms-runtime.domain_workflow": "Workflow",
|
||||
"Forms": "Formulare",
|
||||
"Refresh": "Aktualisieren",
|
||||
"Status": "Status",
|
||||
"Open": "Offen",
|
||||
"All": "Alle",
|
||||
"Draft": "Entwurf",
|
||||
"Submitted": "Abgesendet",
|
||||
"Needs review": "Prüfung erforderlich",
|
||||
"Accepted": "Angenommen",
|
||||
"Rejected": "Abgelehnt",
|
||||
"Handed off": "Übergeben",
|
||||
"Archived": "Archiviert",
|
||||
"Loading forms": "Formulare werden geladen",
|
||||
"No matching Forms.": "Keine passenden Formulare.",
|
||||
"Revision": "Revision",
|
||||
"Loading Form": "Formular wird geladen",
|
||||
"Change reason": "Änderungsgrund",
|
||||
"Save draft": "Entwurf speichern",
|
||||
"Submit": "Absenden",
|
||||
"Submission receipt": "Übermittlungsbeleg",
|
||||
"Case and workflow handoffs": "Fall- und Workflow-Übergaben",
|
||||
"Create Case": "Fall erstellen",
|
||||
"Start Workflow": "Workflow starten",
|
||||
"Target binding (optional)": "Zielbindung (optional)",
|
||||
"Exact target binding": "Exakte Zielbindung",
|
||||
"Start": "Starten",
|
||||
"No handoff has been requested.": "Es wurde keine Übergabe angefordert.",
|
||||
"Open target": "Ziel öffnen",
|
||||
"Retry": "Erneut versuchen",
|
||||
"Reconcile": "Abgleichen",
|
||||
"Compensate": "Kompensieren",
|
||||
"Status history": "Statusverlauf",
|
||||
"Revisions": "Revisionen",
|
||||
"Select": "Auswählen",
|
||||
"Compensate handoff": "Übergabe kompensieren",
|
||||
"Confirm absent and compensate": "Fehlen bestätigen und kompensieren",
|
||||
"Read-only Form": "Schreibgeschütztes Formular"
|
||||
};
|
||||
|
||||
export const generatedTranslations: PlatformTranslations = { en, de };
|
||||
+4
-2
@@ -1,5 +1,6 @@
|
||||
import { createElement, lazy } from "react";
|
||||
import type { PlatformWebModule } from "@govoplan/core-webui";
|
||||
import { generatedTranslations } from "./i18n/generatedTranslations";
|
||||
import "./styles/forms-runtime.css";
|
||||
|
||||
|
||||
@@ -12,10 +13,11 @@ const routeScopes = [
|
||||
|
||||
export const formsRuntimeModule: PlatformWebModule = {
|
||||
id: "forms_runtime",
|
||||
label: "Forms",
|
||||
label: "i18n:govoplan-forms-runtime.forms",
|
||||
version: "0.1.14",
|
||||
dependencies: ["access", "forms"],
|
||||
optionalDependencies: ["files", "approvals", "workflow_engine", "portal", "cases", "policy", "audit"],
|
||||
translations: generatedTranslations,
|
||||
routes: [
|
||||
{
|
||||
path: "/forms-runtime",
|
||||
@@ -35,7 +37,7 @@ export const formsRuntimeModule: PlatformWebModule = {
|
||||
navItems: [
|
||||
{
|
||||
to: "/forms-runtime",
|
||||
label: "Forms",
|
||||
label: "i18n:govoplan-forms-runtime.forms",
|
||||
iconName: "form",
|
||||
anyOf: routeScopes,
|
||||
order: 37,
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
padding: 16px 18px 24px;
|
||||
}
|
||||
|
||||
.form-instance-viewport > .action-blocker-hint {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
.forms-runtime-list {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--border);
|
||||
|
||||
Reference in New Issue
Block a user