feat: consolidate shared UI and harden browser authority for release

This commit is contained in:
2026-09-08 01:35:05 +02:00
parent ac40774785
commit b75ca34295
143 changed files with 8664 additions and 752 deletions
+101
View File
@@ -1,6 +1,34 @@
import { useMemo, useState } from "react";
import { CalendarDays, FileText, Folder, GitBranch, Inbox, ListChecks, Mail, Search, ShieldCheck } from "lucide-react";
import { useLocation } from "react-router";
import DialogLayoutScenario from "./DialogLayoutScenario";
import DataGridLayoutScenario from "./DataGridLayoutScenario";
import NavigationLayoutScenario from "./NavigationLayoutScenario";
import ManagedArchiveScenario from "./ManagedArchiveScenario";
import FilesToolbarScenario from "./FilesToolbarScenario";
import CredentialReferencesScenario from "./CredentialReferencesScenario";
import FormControlLayoutScenario from "./FormControlLayoutScenario";
import CampaignWorkspaceScenario from "./CampaignWorkspaceScenario";
import CampaignReportScenario from "./CampaignReportScenario";
import ModuleLayoutScenario from "./ModuleLayoutScenario";
import HelpCenterScenario from "./HelpCenterScenario";
import NotificationFilterScenario from "./NotificationFilterScenario";
import MultiSelectFilterScenario from "./MultiSelectFilterScenario";
import SearchFiltersScenario from "./SearchFiltersScenario";
import AddressExplorerScenario from "./AddressExplorerScenario";
import MailFolderExplorerScenario from "./MailFolderExplorerScenario";
import MailToolbarScenario from "./MailToolbarScenario";
import CampaignDeliveryProgressScenario from "./CampaignDeliveryProgressScenario";
import CampaignSavingScenario from "./CampaignSavingScenario";
import CampaignMailSettingsScenario from "./CampaignMailSettingsScenario";
import CampaignAttachmentsScenario from "./CampaignAttachmentsScenario";
import CampaignRecipientOrderScenario from "./CampaignRecipientOrderScenario";
import CampaignReviewScenario from "./CampaignReviewScenario";
import CampaignBulkReviewScenario from "./CampaignBulkReviewScenario";
import CampaignReviewDetailsScenario from "./CampaignReviewDetailsScenario";
import CampaignDeliveryPolicyScenario from "./CampaignDeliveryPolicyScenario";
import MailCredentialPolicyScenario from "./MailCredentialPolicyScenario";
import type { NavigationPreferenceScope } from "../src/components/navigationPreferenceLayout";
import FormInstancePage from "../../../govoplan-forms-runtime/webui/src/features/forms/FormInstancePage";
import FormsRuntimePage from "../../../govoplan-forms-runtime/webui/src/features/forms/FormsRuntimePage";
import PublicFormPage from "../../../govoplan-forms-runtime/webui/src/features/forms/PublicFormPage";
@@ -28,6 +56,7 @@ import StatePanel from "../src/components/StatePanel";
import WorkspaceFrame from "../src/components/WorkspaceFrame";
import WorkspaceLayout from "../src/components/WorkspaceLayout";
import WorkspaceActionBar from "../src/components/WorkspaceActionBar";
import WysiwygEditor from "../src/components/WysiwygEditor";
import BreadcrumbBar from "../src/layout/BreadcrumbBar";
import HelpMenu from "../src/layout/HelpMenu";
import IconRail from "../src/layout/IconRail";
@@ -54,6 +83,49 @@ export default function ConformanceApp() {
const [editorDirty, setEditorDirty] = useState(true);
const [metricDrilldown, setMetricDrilldown] = useState("");
if (new URLSearchParams(location.search).has("credential-references")) return <CredentialReferencesScenario />;
if (new URLSearchParams(location.search).has("files-toolbar")) return <FilesToolbarScenario />;
if (new URLSearchParams(location.search).has("form-control-layout")) return <FormControlLayoutScenario />;
if (new URLSearchParams(location.search).has("campaign-workspace")) return <CampaignWorkspaceScenario />;
if (new URLSearchParams(location.search).has("campaign-report")) return <CampaignReportScenario />;
if (new URLSearchParams(location.search).has("module-layouts")) return <ModuleLayoutScenario />;
if (new URLSearchParams(location.search).has("help-center")) return <HelpCenterScenario />;
if (new URLSearchParams(location.search).has("notification-filter")) return <NotificationFilterScenario />;
if (new URLSearchParams(location.search).has("multi-select-filter")) return <MultiSelectFilterScenario />;
if (new URLSearchParams(location.search).has("search-filters")) return <SearchFiltersScenario />;
if (new URLSearchParams(location.search).has("address-explorer")) return <AddressExplorerScenario />;
if (new URLSearchParams(location.search).has("mail-folder-explorer")) return <MailFolderExplorerScenario />;
if (new URLSearchParams(location.search).has("mail-toolbar")) return <MailToolbarScenario />;
if (new URLSearchParams(location.search).has("campaign-delivery-progress")) return <CampaignDeliveryProgressScenario />;
if (new URLSearchParams(location.search).has("campaign-saving")) return <CampaignSavingScenario />;
if (new URLSearchParams(location.search).has("campaign-mail-settings")) return <CampaignMailSettingsScenario />;
if (new URLSearchParams(location.search).has("campaign-attachments")) return <CampaignAttachmentsScenario />;
if (new URLSearchParams(location.search).has("campaign-recipient-order")) return <CampaignRecipientOrderScenario />;
if (new URLSearchParams(location.search).has("campaign-review")) return <CampaignReviewScenario />;
if (new URLSearchParams(location.search).has("campaign-bulk-review")) return <CampaignBulkReviewScenario />;
if (new URLSearchParams(location.search).has("campaign-review-details")) return <CampaignReviewDetailsScenario />;
if (new URLSearchParams(location.search).has("campaign-delivery-policy")) return <CampaignDeliveryPolicyScenario />;
if (new URLSearchParams(location.search).has("mail-credential-policy")) return <MailCredentialPolicyScenario />;
if (new URLSearchParams(location.search).has("data-grid-layout")) return <DataGridLayoutScenario />;
if (new URLSearchParams(location.search).has("managed-archive")) {
const params = new URLSearchParams(location.search);
return <ManagedArchiveScenario language={params.get("language") ?? "en"} downloadAllowed={!params.has("no-download")} />;
}
if (new URLSearchParams(location.search).has("navigation-layout")) {
const params = new URLSearchParams(location.search);
return <NavigationLayoutScenario scope={(params.get("scope") ?? "user") as NavigationPreferenceScope} language={params.get("language") ?? "en"} disabled={params.has("disabled")} />;
}
if (new URLSearchParams(location.search).has("dialog-layout")) {
const params = new URLSearchParams(location.search);
return <DialogLayoutScenario templates={params.get("fixture") === "templates"} language={params.get("language") ?? "de"} />;
}
if (new URLSearchParams(location.search).has("wysiwyg-lifecycle")) {
return <WysiwygLifecycleScenario source={new URLSearchParams(location.search).get("mode") === "source"} />;
}
if (new URLSearchParams(location.search).has("product-navigation")) {
return <ProductNavigationScenario />;
}
@@ -200,6 +272,35 @@ export default function ConformanceApp() {
);
}
function WysiwygLifecycleScenario({ source }: { source: boolean }) {
const initialHtml = source
? '<table style="width: 100%"><tbody><tr><td>Legacy template</td></tr></tbody></table>'
: "<p>Legacy <i>template</i></p>";
const [value, setValue] = useState(initialHtml);
const [changeCount, setChangeCount] = useState(0);
const [disabled, setDisabled] = useState(false);
const [mounted, setMounted] = useState(true);
return <main className="conformance-root">
<h1>Rich-text lifecycle fixture</h1>
<Button onClick={() => setDisabled((current) => !current)}>Toggle read-only</Button>
<Button onClick={() => setMounted((current) => !current)}>Toggle editor mount</Button>
<Button onClick={() => setValue(initialHtml.replace("Legacy", "Reloaded"))}>Load another value</Button>
<output data-testid="wysiwyg-change-count">{changeCount}</output>
<pre data-testid="wysiwyg-controlled-value">{value}</pre>
{mounted && <WysiwygEditor
value={value}
disabled={disabled}
ariaLabel="Rich-text fixture content"
labels={{ visual: "Visual fixture mode", source: "Source fixture mode" }}
onChange={(nextValue) => {
setValue(nextValue);
setChangeCount((current) => current + 1);
}}
/>}
</main>;
}
function ProductNavigationScenario() {
const projection = useMemo(
() => projectProductNavigation(