WebUI module split; docs

This commit is contained in:
2026-06-24 10:19:21 +02:00
parent 7f25a3ccdf
commit 841d0b4024
3 changed files with 100 additions and 12 deletions

View File

@@ -1,5 +1,17 @@
import { Activity, FileText, Form, MailCheck, Users } from "lucide-react";
import type { PlatformWebModule } from "@govoplan/core-webui";
import { createElement, lazy, useCallback } from "react";
import { useParams } from "react-router-dom";
import { Card, ResourceAccessBoundary, type ApiSettings, type AuthInfo, type PlatformWebModule } from "@govoplan/core-webui";
import { getCampaign } from "./api/campaigns";
const AddressBookPage = lazy(() => import("./features/addressbook/AddressBookPage"));
const CampaignListPage = lazy(() => import("./features/campaigns/CampaignListPage"));
const CampaignWorkspace = lazy(() => import("./features/campaigns/CampaignWorkspace"));
const OperatorQueuePage = lazy(() => import("./features/operator/OperatorQueuePage"));
const TemplatesPage = lazy(() => import("./features/templates/TemplatesPage"));
const campaignRead = ["campaigns:campaign:read"];
const operatorScopes = ["campaigns:campaign:queue", "campaigns:campaign:retry", "campaigns:campaign:reconcile", "campaigns:campaign:control", "campaigns:campaign:send"];
export const campaignModule: PlatformWebModule = {
id: "campaigns",
@@ -8,18 +20,53 @@ export const campaignModule: PlatformWebModule = {
dependencies: ["access"],
optionalDependencies: ["files", "mail"],
navItems: [
{ to: "/campaigns", label: "Campaigns", icon: MailCheck, anyOf: ["campaigns:campaign:read"], order: 20 },
{ to: "/campaigns", label: "Campaigns", icon: MailCheck, anyOf: campaignRead, order: 20 },
{
to: "/operator",
label: "Operator Queue",
icon: Activity,
anyOf: ["campaigns:campaign:queue", "campaigns:campaign:retry", "campaigns:campaign:reconcile", "campaigns:campaign:control", "campaigns:campaign:send"],
anyOf: operatorScopes,
order: 30
},
{ to: "/reports", label: "Reports", icon: FileText, anyOf: ["campaigns:report:read"], order: 70 },
{ to: "/address-book", label: "Address Book", icon: Users, order: 80 },
{ to: "/templates", label: "Templates", icon: Form, order: 90 }
],
routes: [
{ path: "/campaigns", anyOf: campaignRead, order: 20, render: ({ settings }) => createElement(CampaignListPage, { settings }) },
{ path: "/campaigns/:campaignId/*", anyOf: campaignRead, order: 21, render: ({ settings, auth }) => createElement(CampaignResourceRoute, { settings, auth }) },
{ path: "/operator", anyOf: operatorScopes, order: 30, render: ({ settings }) => createElement(OperatorQueuePage, { settings }) },
{ path: "/reports", anyOf: ["campaigns:report:read"], order: 70, render: () => createElement(ReportsPage) },
{ path: "/address-book", order: 80, render: () => createElement(AddressBookPage) },
{ path: "/templates", order: 90, render: () => createElement(TemplatesPage) }
]
};
function CampaignResourceRoute({ settings, auth }: { settings: ApiSettings; auth: AuthInfo }) {
const { campaignId = "" } = useParams();
const tenantId = (auth.active_tenant ?? auth.tenant).id;
const probe = useCallback(() => getCampaign(settings, campaignId), [settings.apiBaseUrl, settings.apiKey, settings.accessToken, campaignId, tenantId]);
return createElement(ResourceAccessBoundary, {
probe,
resetKey: `${tenantId}:${campaignId}`,
fallback: "/campaigns",
children: createElement(CampaignWorkspace, { settings, auth })
});
}
function ReportsPage() {
return createElement(
"div",
{ className: "content-pad" },
createElement(
"div",
{ className: "page-heading" },
createElement("h1", null, "Reports"),
createElement("p", null, "This module is prepared but not implemented yet.")
),
createElement(Card, null, createElement("p", { className: "muted" }, "Next passes will add functionality here."))
);
}
export default campaignModule;