3 Commits
Author SHA1 Message Date
zemion 3274d30665 fix(packaging): expose immutable WebUI Git package for v0.1.23
Module Package Release / publish-packages (push) Successful in 10s
2026-09-08 02:06:10 +02:00
zemion aff2623496 feat: contribute Messages product surface
Module Package Release / publish-packages (push) Successful in 13s
2026-08-24 12:53:44 +02:00
zemion 4bdc3ab60c fix(webui): bind consequential postbox controls to help
Module Package Release / publish-packages (push) Successful in 12s
2026-08-24 11:36:42 +02:00
9 changed files with 114 additions and 11 deletions
+18
View File
@@ -158,3 +158,21 @@ Run focused checks with:
/mnt/DATA/git/govoplan/.venv/bin/python -m unittest discover -s tests
cd webui && npm run test:ui-structure
```
## Git-source WebUI package
The repository root exposes `@govoplan/postbox-webui` for Git-tagged release
dependencies. It mirrors the owning `webui/package.json` version, public
TypeScript/CSS exports and peer requirements, with entry paths under
`webui/src`. Consumers provide the shared Core/React peers; the facade runs no
development or install scripts. The source archive contains `webui/src`, this
README and any repository license file. Run module development checks from `webui/`; Python
installation remains governed by `pyproject.toml`.
Das Repository stellt `@govoplan/postbox-webui` am Wurzelpfad für versionierte
Git-Abhängigkeiten bereit. Version, öffentliche TypeScript-/CSS-Exporte und
Peer-Anforderungen entsprechen `webui/package.json`; die Einstiegspfade liegen
unter `webui/src`. Gemeinsame Core-/React-Peers stellt die einbindende Anwendung
bereit. Die Fassade führt keine Entwicklungs- oder Installationsskripte aus.
Entwicklungsprüfungen bleiben in `webui/`, die Python-Installation weiterhin in
`pyproject.toml` definiert.
+33
View File
@@ -0,0 +1,33 @@
{
"name": "@govoplan/postbox-webui",
"version": "0.1.23",
"private": true,
"type": "module",
"main": "webui/src/index.ts",
"module": "webui/src/index.ts",
"types": "webui/src/index.ts",
"exports": {
".": {
"types": "./webui/src/index.ts",
"import": "./webui/src/index.ts"
},
"./styles/postbox.css": "./webui/src/styles/postbox.css"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.18",
"lucide-react": "^1.23.0",
"react": ">=19.2.7 <20",
"react-dom": ">=19.2.7 <20",
"react-router": ">=8.3.0 <9"
},
"peerDependenciesMeta": {
"@govoplan/core-webui": {
"optional": true
}
},
"files": [
"webui/src",
"README.md",
"LICENSE"
]
}
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-postbox"
version = "0.1.20"
version = "0.1.23"
description = "Function-bound institutional postboxes for GovOPlaN."
readme = "README.md"
requires-python = ">=3.12"
+1 -1
View File
@@ -1,3 +1,3 @@
"""GovOPlaN Postbox module."""
__version__ = "0.1.20"
__version__ = "0.1.23"
+45 -2
View File
@@ -34,7 +34,9 @@ from govoplan_core.core.modules import (
ModuleManifest,
NavItem,
PermissionDefinition,
ProductAvailabilityExplanation,
ProductAreaContribution,
ProductSurfaceContribution,
QuickAccessTool,
RoleTemplate,
)
@@ -75,7 +77,7 @@ from govoplan_postbox.backend.permissions import (
MODULE_ID = "postbox"
MODULE_NAME = "Postbox"
MODULE_VERSION = "0.1.20"
MODULE_VERSION = "0.1.23"
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
@@ -404,6 +406,40 @@ manifest = ModuleManifest(
order=40,
),
),
product_surfaces=(
ProductSurfaceContribution(
id="communication.messages",
module_id=MODULE_ID,
label="i18n:govoplan-core.product_surface.messages",
description="i18n:govoplan-core.product_surface.messages_description",
icon="mail",
entry_path="/messages",
route_path="/postbox",
surface_ids=("postbox.nav.postbox", "postbox.route.postbox"),
presentations=("task", "reader"),
capability_ids=(CAPABILITY_POSTBOX_MESSAGES,),
search_source_ids=("postbox.messages",),
help_context_ids=("postbox.quick_access.messages",),
documentation_topic_ids=("postbox.quick-access-and-product-area",),
required_any=(READ_SCOPE,),
aliases=("/inbox",),
order=20,
unavailable=ProductAvailabilityExplanation(
reason="authorization",
title="i18n:govoplan-core.product_surface.messages_unavailable",
description="i18n:govoplan-core.product_surface.messages_unavailable_description",
resolution="i18n:govoplan-core.product_surface.messages_unavailable_resolution",
responsible_role="i18n:govoplan-core.access_administrator",
),
degraded=ProductAvailabilityExplanation(
reason="provider_degraded",
title="i18n:govoplan-core.product_surface.messages_degraded",
description="i18n:govoplan-core.product_surface.messages_degraded_description",
resolution="i18n:govoplan-core.product_surface.messages_degraded_resolution",
responsible_role="i18n:govoplan-core.integration_operator",
),
),
),
quick_access_tools=(
QuickAccessTool(
id="postbox.messages",
@@ -623,7 +659,11 @@ manifest = ModuleManifest(
summary="Use function-bound Postboxes in Communication and the shared Messages Quick Access drawer.",
body=(
"Postbox contributes its inbox to Communication. With Quick Access enabled, its owner-rendered surface lists at most "
"seven currently readable unread messages beside independent Mail and future chat providers. Selecting or opening a "
"seven currently readable unread messages beside independent Mail and future chat providers. "
"The stable `/messages` product entry and `/inbox` migration alias select Postbox only when its route is "
"currently authorized and visible in the effective View; otherwise another Messages owner is selected or the shell "
"explains how access can be restored. "
"Selecting or opening a "
"message returns a typed Postbox reference; accounts with message-write permission can launch the full owner-rendered "
"composer for a currently accessible function Postbox. Directory, message, and submission calls recheck the active "
"assignment or acting context. Function assignment, classification, read-receipt, retention, encryption, and evidence "
@@ -640,6 +680,9 @@ manifest = ModuleManifest(
"body": (
"Postbox ordnet seinen Eingang Kommunikation zu. Ist der Schnellzugriff aktiviert, erscheint die vom Modul gerenderte "
"Oberfläche mit höchstens sieben aktuell lesbaren ungelesenen Nachrichten neben unabhängigen Beiträgen aus Mail. "
"Der stabile Produkteinstieg `/messages` und der Migrationsalias `/inbox` wählen Postbox nur, wenn seine Route "
"aktuell berechtigt und in der wirksamen View sichtbar ist. Andernfalls wird ein anderer Nachrichten-Eigentümer "
"gewählt oder die Shell erklärt die Wiederherstellung des Zugriffs. "
"Auswahl oder Öffnen liefert eine typisierte Postbox-Referenz; mit Schreibberechtigung lässt sich der vollständige "
"Editor für ein aktuell zugängliches Funktionspostfach öffnen. Verzeichnis, Nachricht und Versand prüfen die aktive "
"Zuweisung beziehungsweise den Handlungskontext erneut. Klassifikation, Lesestatus, Aufbewahrung, Verschlüsselung "
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/postbox-webui",
"version": "0.1.20",
"version": "0.1.23",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -1038,6 +1038,8 @@ function TemplateWorkspace({
</Button>
<Button
onClick={onPublish}
helpContextId="postbox.admin.templates"
helpModuleId="postbox"
disabled={busy || selected.status === "retired" || Boolean(revision.published_at)}
disabledReason={postboxBusyReason(false, busy) ?? (selected.status === "retired" ? POSTBOX_INTERFACE_I18N.retiredTemplate : revision.published_at ? POSTBOX_INTERFACE_I18N.publishedRevision : undefined)}
>
@@ -1678,7 +1680,7 @@ function TemplateDialog({
onChange={(require_expiry) => updateLinkedCopy({ require_expiry })}
/>
</div>
<FormField label="Maximum retention days" documentation={POSTBOX_FIELD_DOCUMENTATION}>
<FormField label="Maximum retention days" documentation={POSTBOX_FIELD_DOCUMENTATION} helpContextId="postbox.field.retention" helpModuleId="postbox">
<input
type="number"
min={1}
@@ -1970,7 +1972,7 @@ function ProtectionConfigurationFields({
<small>{selected?.description}</small>
</FormField>
{profile === "server_envelope_v1" ? (
<FormField label="Encryption vault" documentation={POSTBOX_FIELD_DOCUMENTATION}>
<FormField label="Encryption vault" documentation={POSTBOX_FIELD_DOCUMENTATION} helpContextId="postbox.field.protection-profile" helpModuleId="postbox">
<input
value={vaultId}
disabled={profileLocked}
@@ -2410,7 +2412,7 @@ function ProtectionTransitionDialog({
<small>{selected?.description}</small>
</FormField>
{draft.target_profile === "server_envelope_v1" ? (
<FormField label="Target encryption vault" documentation={POSTBOX_FIELD_DOCUMENTATION}>
<FormField label="Target encryption vault" documentation={POSTBOX_FIELD_DOCUMENTATION} helpContextId="postbox.action.protection-transition" helpModuleId="postbox">
<input
value={draft.target_vault_id}
onChange={(event) => onChange({ ...draft, target_vault_id: event.target.value })}
@@ -2482,6 +2484,8 @@ function ProtectionTransitionDialog({
<div className="postbox-toggle-field">
<ToggleSwitch
label="Acknowledge residual disclosure"
helpContextId="postbox.action.protection-transition"
helpModuleId="postbox"
help="Previously decrypted, copied, or exported content cannot be recalled by changing the storage profile."
checked={draft.acknowledge_irreversibility}
onChange={(acknowledge_irreversibility) => onChange({
@@ -997,6 +997,8 @@ export default function PostboxPage({
{groupingDraft.id ? (
<Button
variant="danger"
helpContextId="postbox.action.delete-grouping"
helpModuleId="postbox"
onClick={() => setDeleteGroupingTarget(groupingDraft)}
disabled={busy}
disabledReason={postboxBusyReason(false, busy)}
@@ -1104,6 +1106,8 @@ export default function PostboxPage({
</Button>
<Button
variant="primary"
helpContextId="postbox.inbox.messages"
helpModuleId="postbox"
onClick={() => void submitMessage()}
disabled={
busy ||
+3 -2
View File
@@ -1,6 +1,7 @@
import { createElement, lazy } from "react";
import {
hasScope,
messagesProductSurfaceTranslations,
type AdminSectionsUiCapability,
type DashboardWidgetsUiCapability,
type PlatformWebModule,
@@ -18,8 +19,8 @@ const PostboxAdminPanel = lazy(
);
const translations = {
en: generatedTranslations.en,
de: generatedTranslations.de
en: { ...generatedTranslations.en, ...messagesProductSurfaceTranslations.en },
de: { ...generatedTranslations.de, ...messagesProductSurfaceTranslations.de }
};
const readScope = ["postbox:postbox:read"];