From 3d8272b28eacbf4b4415b3f64e49cadc7b0b25d8 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Mon, 3 Aug 2026 08:29:29 +0200 Subject: [PATCH] Apply guided scheduling interface patterns --- README.md | 18 ++++ src/govoplan_scheduling/backend/manifest.py | 30 +++++++ .../test-scheduling-page-structure.mjs | 6 ++ .../features/scheduling/SchedulingPage.tsx | 88 ++++++++++++++++++- .../scheduling/schedulingViewModel.ts | 46 ++++++++++ webui/src/i18n/generatedTranslations.ts | 12 +++ webui/tests/scheduling-view-model.test.ts | 29 ++++++ 7 files changed, 225 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8972081..d11c314 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,24 @@ poll-backed scheduling requests: - a first Scheduling WebUI package with request creation, slot matrix, Calendar actions, decisions, and notification-job creation +## Interface workflow and contextual guidance + +The request detail projects the existing backend lifecycle into three stable +user stages: prepare the request, collect participation, and decide. Draft, +collecting, closed, decided, handed-off, cancelled, and archived records remain +the authoritative backend states; the stage rail is only a readable projection +and does not invent a second workflow state machine. Cancelled requests keep the +reached stage visible as stopped, while later stages remain locked. + +Unavailable Calendar coordination and public guest participation use Core's +action-blocker pattern. The UI names the reason, required remediation, +responsible administrator, and destination instead of displaying a generic +disabled control. Stable help links resolve to the configured Docs module when +present and to the hosted documentation otherwise. Scheduling contributes the +`scheduling.find-and-decide-meeting-time`, `scheduling.calendar-coordination`, +and `scheduling.participation-governance` topics; it does not import Docs, +Calendar, Poll, Policy, or Access implementation code. + The next slices should add generic self-enrolment links after their abuse and identity policy is agreed, Calendar hold cleanup after decision, and advanced scoring constraints such as required participants and quorum rules. diff --git a/src/govoplan_scheduling/backend/manifest.py b/src/govoplan_scheduling/backend/manifest.py index 50e39f7..7e69028 100644 --- a/src/govoplan_scheduling/backend/manifest.py +++ b/src/govoplan_scheduling/backend/manifest.py @@ -111,6 +111,36 @@ DOCUMENTATION = ( related_modules=("poll", "calendar", "notifications", "mail"), metadata={"kind": "reference"}, ), + DocumentationTopic( + id="scheduling.calendar-coordination", + title="Configure scheduling calendar coordination", + summary="Understand the Calendar capability and permissions required for conflict checks, tentative holds, and final event handoff.", + body=( + "Calendar coordination remains optional. It is available only when Calendar contributes its picker capability and the actor can read calendars and availability and write events. " + "A disabled Calendar control therefore names the missing integration or authority instead of silently accepting a configuration that cannot run. " + "Administrators should enable the Calendar module and grant the bounded calendar, availability, and event permissions needed by the organizer; Scheduling never imports Calendar internals." + ), + layer="configured", + documentation_types=("admin", "user"), + audience=("organizer", "module_admin", "tenant_admin"), + related_modules=("calendar", "access", "policy"), + metadata={"kind": "reference", "context_ids": ["scheduling.calendar-integration"]}, + ), + DocumentationTopic( + id="scheduling.participation-governance", + title="Govern public scheduling participation", + summary="Resolve disabled guest invitations without weakening signed-link privacy or participation policy.", + body=( + "Public invitation links are issued only when the configured response, privacy, password, email, and update controls can be enforced by the public participation gateway. " + "When enforcement is unavailable, signed-in participants may continue to respond through their assigned request, but the system does not issue a weaker guest link. " + "A system or tenant administrator must restore the governed Poll/public-participation capability or keep the request limited to signed-in participation." + ), + layer="configured", + documentation_types=("admin",), + audience=("operator", "module_admin", "tenant_admin"), + related_modules=("poll", "policy", "access"), + metadata={"kind": "pattern", "context_ids": ["scheduling.public-participation-blocker"]}, + ), ) diff --git a/webui/scripts/test-scheduling-page-structure.mjs b/webui/scripts/test-scheduling-page-structure.mjs index f270c34..0bd8166 100644 --- a/webui/scripts/test-scheduling-page-structure.mjs +++ b/webui/scripts/test-scheduling-page-structure.mjs @@ -17,6 +17,7 @@ assert.match(page, /Boolean\(calendarPickerCapability\) && canReadCalendars && c assert.doesNotMatch(page, /@govoplan\/calendar-webui|govoplan-calendar\/webui/); assert.match(page, /Card,[\s\S]*DataGrid,[\s\S]*DataGridRowActions,[\s\S]*FormField,[\s\S]*MetricCard,[\s\S]*PasswordField,[\s\S]*PeoplePicker,[\s\S]*SelectionList,[\s\S]*ToggleSwitch,[\s\S]*from "@govoplan\/core-webui"/); assert.doesNotMatch(page, /@govoplan\/core-webui\/src\//); +assert.match(page, /ActionBlockerHint,[\s\S]*DocumentationHelpLink,[\s\S]*StageRail,[\s\S]*from "@govoplan\/core-webui"/); assert.match(page, /className="scheduling-workspace-layout"/); assert.match(page, /