Compare commits

...
2 Commits
Author SHA1 Message Date
zemion ecc1283de7 feat: contribute Messages product surface
Module Package Release / publish-packages (push) Successful in 11s
2026-08-24 12:53:44 +02:00
zemion 48205e6e46 fix(webui): bind reusable mail credentials to help
Module Package Release / publish-packages (push) Successful in 11s
2026-08-24 11:36:41 +02:00
8 changed files with 60 additions and 15 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"peerDependencies": { "peerDependencies": {
"@govoplan/core-webui": "^0.1.18", "@govoplan/core-webui": "^0.1.18",
"lucide-react": "^1.23.0", "lucide-react": "^1.23.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "webui/src/index.ts", "main": "webui/src/index.ts",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "govoplan-mail" name = "govoplan-mail"
version = "0.1.23" version = "0.1.25"
description = "GovOPlaN mail module with backend and WebUI integration." description = "GovOPlaN mail module with backend and WebUI integration."
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
+42 -1
View File
@@ -32,7 +32,9 @@ from govoplan_core.core.modules import (
ModuleManifest, ModuleManifest,
NavItem, NavItem,
PermissionDefinition, PermissionDefinition,
ProductAvailabilityExplanation,
ProductAreaContribution, ProductAreaContribution,
ProductSurfaceContribution,
QuickAccessTool, QuickAccessTool,
RoleTemplate, RoleTemplate,
) )
@@ -445,7 +447,7 @@ POP3_PROVIDER = ExternalProviderDeclaration(
manifest = ModuleManifest( manifest = ModuleManifest(
id="mail", id="mail",
name="Mail", name="Mail",
version="0.1.23", version="0.1.25",
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR), required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
optional_dependencies=("campaigns", "addresses", "calendar", "postbox", "search"), optional_dependencies=("campaigns", "addresses", "calendar", "postbox", "search"),
provides_interfaces=( provides_interfaces=(
@@ -562,6 +564,39 @@ manifest = ModuleManifest(
order=40, order=40,
), ),
), ),
product_surfaces=(
ProductSurfaceContribution(
id="communication.messages",
module_id="mail",
label="i18n:govoplan-core.product_surface.messages",
description="i18n:govoplan-core.product_surface.messages_description",
icon="mail",
entry_path="/messages",
route_path="/mail",
surface_ids=("mail.nav.mail", "mail.route.mail"),
presentations=("task", "reader"),
search_source_ids=("mail.mailbox_messages",),
help_context_ids=("mail.quick_access.messages",),
documentation_topic_ids=("mail.quick-access-and-product-area",),
required_any=("mail:mailbox:read",),
aliases=("/inbox",),
order=10,
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=( quick_access_tools=(
QuickAccessTool( QuickAccessTool(
id="mail.messages", id="mail.messages",
@@ -893,6 +928,9 @@ manifest = ModuleManifest(
body=( body=(
"Mail contributes its full mailbox to Communication. When Quick Access is enabled, its compact provider surface " "Mail contributes its full mailbox to Communication. When Quick Access is enabled, its compact provider surface "
"appears inside the shared Messages drawer alongside independent Postbox and future chat contributions. " "appears inside the shared Messages drawer alongside independent Postbox and future chat contributions. "
"Mail also contributes to the stable Messages product entry: `/messages` and its migration alias `/inbox` open "
"Mail only when its mailbox route is currently authorized and visible in the effective View; otherwise another "
"available Messages owner is selected or the shell explains how access can be restored. "
"Recent entries open the exact authorized profile, folder, and message; Drafts resolves the configured or " "Recent entries open the exact authorized profile, folder, and message; Drafts resolves the configured or "
"provider-detected Drafts folder, and the full Mail page keeps the versioned Quick Access return context. " "provider-detected Drafts folder, and the full Mail page keeps the versioned Quick Access return context. "
"When an active Case requests a selection, choosing a recent message returns only its tenant-bound profile, " "When an active Case requests a selection, choosing a recent message returns only its tenant-bound profile, "
@@ -914,6 +952,9 @@ manifest = ModuleManifest(
"body": ( "body": (
"Mail ordnet das vollständige Postfach Kommunikation zu. Ist der Schnellzugriff aktiviert, erscheint die kompakte " "Mail ordnet das vollständige Postfach Kommunikation zu. Ist der Schnellzugriff aktiviert, erscheint die kompakte "
"Mail-Oberfläche gemeinsam mit unabhängigen Beiträgen aus Postbox und künftig Chat unter Nachrichten. " "Mail-Oberfläche gemeinsam mit unabhängigen Beiträgen aus Postbox und künftig Chat unter Nachrichten. "
"Mail trägt außerdem zum stabilen Produkteinstieg Nachrichten bei: `/messages` und der Migrationsalias `/inbox` "
"öffnen Mail nur, wenn die Postfachroute aktuell berechtigt und in der wirksamen View sichtbar ist. Andernfalls "
"wählt die Shell einen anderen verfügbaren Nachrichten-Eigentümer oder erklärt die Wiederherstellung des Zugriffs. "
"Aktuelle Einträge öffnen das genaue berechtigte Profil, den Ordner und die Nachricht; Entwürfe verwendet " "Aktuelle Einträge öffnen das genaue berechtigte Profil, den Ordner und die Nachricht; Entwürfe verwendet "
"den konfigurierten oder vom Anbieter erkannten Entwurfsordner. Die vollständige Mail-Seite erhält den " "den konfigurierten oder vom Anbieter erkannten Entwurfsordner. Die vollständige Mail-Seite erhält den "
"versionierten Rücksprungkontext. Verfassen öffnet bewusst die konfigurierte Mail-Anwendung des Benutzers, " "versionierten Rücksprungkontext. Verfassen öffnet bewusst die konfigurierte Mail-Anwendung des Benutzers, "
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"devDependencies": { "devDependencies": {
"typescript": "^5.7.2" "typescript": "^5.7.2"
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@govoplan/mail-webui", "name": "@govoplan/mail-webui",
"version": "0.1.23", "version": "0.1.25",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
@@ -1495,7 +1495,7 @@ function ProfileForm({
{editTarget.kind === "credentials" && {editTarget.kind === "credentials" &&
<FormGrid columns={2} gap="small" collapseAt="workspace" className=""> <FormGrid columns={2} gap="small" collapseAt="workspace" className="">
{creatingCredential && {creatingCredential &&
<FormField label="Reusable credential" documentation={MAIL_PROFILE_WORKFLOW_DOCUMENTATION}> <FormField label="Reusable credential" documentation={MAIL_PROFILE_WORKFLOW_DOCUMENTATION} helpContextId="mail.profiles" helpModuleId="mail">
<select value={reuseCredentialId} disabled={credentialDisabled} onChange={(event) => setReuseCredentialId(event.target.value)}> <select value={reuseCredentialId} disabled={credentialDisabled} onChange={(event) => setReuseCredentialId(event.target.value)}>
<option value="">Create a new credential</option> <option value="">Create a new credential</option>
{availableCredentials.map((credential) => {availableCredentials.map((credential) =>
@@ -1509,13 +1509,13 @@ function ProfileForm({
{creatingCredential && <div />} {creatingCredential && <div />}
{!reuseCredentialId && {!reuseCredentialId &&
<> <>
<FormField label="Credential name" documentation={MAIL_PROFILE_DOCUMENTATION}> <FormField label="Credential name" documentation={MAIL_PROFILE_DOCUMENTATION} helpContextId="mail.profiles" helpModuleId="mail">
<input value={draft.credentialName} disabled={credentialDisabled} onChange={(event) => setDraft({ ...draft, credentialName: event.target.value })} /> <input value={draft.credentialName} disabled={credentialDisabled} onChange={(event) => setDraft({ ...draft, credentialName: event.target.value })} />
</FormField> </FormField>
<FormField label="Description"> <FormField label="Description">
<input value={draft.credentialDescription} disabled={credentialDisabled} onChange={(event) => setDraft({ ...draft, credentialDescription: event.target.value })} /> <input value={draft.credentialDescription} disabled={credentialDisabled} onChange={(event) => setDraft({ ...draft, credentialDescription: event.target.value })} />
</FormField> </FormField>
<FormField label="Available to modules" help="Choose installed modules. Keep Mail selected to use this credential here."> <FormField label="Available to modules" help="Choose installed modules. Keep Mail selected to use this credential here." helpContextId="mail.profiles" helpModuleId="mail">
<ReferenceMultiSelect <ReferenceMultiSelect
values={commaValues(draft.credentialAllowedModules)} values={commaValues(draft.credentialAllowedModules)}
onChange={(values) => setDraft({ ...draft, credentialAllowedModules: values.join(", ") })} onChange={(values) => setDraft({ ...draft, credentialAllowedModules: values.join(", ") })}
@@ -1527,7 +1527,9 @@ function ProfileForm({
</FormField> </FormField>
<FormField <FormField
label="Limited to servers" label="Limited to servers"
help="Choose an announced server or enter a module-qualified reference. Leave blank for every permitted server."> help="Choose an announced server or enter a module-qualified reference. Leave blank for every permitted server."
helpContextId="mail.profiles"
helpModuleId="mail">
<ReferenceMultiSelect <ReferenceMultiSelect
values={commaValues(draft.credentialAllowedServerRefs)} values={commaValues(draft.credentialAllowedServerRefs)}
onChange={(values) => setDraft({ ...draft, credentialAllowedServerRefs: values.join(", ") })} onChange={(values) => setDraft({ ...draft, credentialAllowedServerRefs: values.join(", ") })}
@@ -1540,6 +1542,8 @@ function ProfileForm({
</FormField> </FormField>
<ToggleSwitch <ToggleSwitch
checked={draft.credentialIsDefault} checked={draft.credentialIsDefault}
helpContextId="mail.profiles"
helpModuleId="mail"
disabled={credentialDisabled} disabled={credentialDisabled}
onChange={(checked) => setDraft({ ...draft, credentialIsDefault: checked })} onChange={(checked) => setDraft({ ...draft, credentialIsDefault: checked })}
label={`Default credential for this ${editTarget.protocol.toUpperCase()} server`} /> label={`Default credential for this ${editTarget.protocol.toUpperCase()} server`} />
+3 -3
View File
@@ -1,5 +1,5 @@
import { createElement, lazy } from "react"; import { createElement, lazy } from "react";
import type { MailDevMailboxUiCapability, MailProfilesUiCapability, PlatformWebModule, QuickAccessToolsUiCapability } from "@govoplan/core-webui"; import { messagesProductSurfaceTranslations, type MailDevMailboxUiCapability, type MailProfilesUiCapability, type PlatformWebModule, type QuickAccessToolsUiCapability } from "@govoplan/core-webui";
import { MailProfilePolicyEditor, MailProfileScopeManager } from "./features/mail/MailProfileManagement"; import { MailProfilePolicyEditor, MailProfileScopeManager } from "./features/mail/MailProfileManagement";
import { validateMailPolicy } from "./features/mail/mailPolicyValidation"; import { validateMailPolicy } from "./features/mail/mailPolicyValidation";
import { mailCredentialReferenceSelectors } from "./features/mail/mailReferenceProviders"; import { mailCredentialReferenceSelectors } from "./features/mail/mailReferenceProviders";
@@ -14,8 +14,8 @@ const mailboxRead = ["mail:mailbox:read"];
const bounceRead = ["mail:bounce:read", "mail:bounce:manage"]; const bounceRead = ["mail:bounce:read", "mail:bounce:manage"];
const legacyImportAccess = ["mail:pop3:import", "mail:pop3:manage"]; const legacyImportAccess = ["mail:pop3:import", "mail:pop3:manage"];
const translations = { const translations = {
en: generatedTranslations.en, en: { ...generatedTranslations.en, ...messagesProductSurfaceTranslations.en },
de: generatedTranslations.de de: { ...generatedTranslations.de, ...messagesProductSurfaceTranslations.de }
}; };
const mailQuickAccessTools: QuickAccessToolsUiCapability = { const mailQuickAccessTools: QuickAccessToolsUiCapability = {
tools: [ tools: [