diff --git a/src/govoplan_mail/backend/manifest.py b/src/govoplan_mail/backend/manifest.py index 618330a..a9ade49 100644 --- a/src/govoplan_mail/backend/manifest.py +++ b/src/govoplan_mail/backend/manifest.py @@ -26,6 +26,8 @@ from govoplan_core.core.modules import ( ModuleManifest, NavItem, PermissionDefinition, + ProductAreaContribution, + QuickAccessTool, RoleTemplate, ) from govoplan_core.core.provider_governance import ( @@ -376,6 +378,33 @@ manifest = ModuleManifest( ViewSurface(id="mail.admin.group-servers", module_id="mail", kind="section", label="Group mail servers", order=20), ViewSurface(id="mail.admin.user-servers", module_id="mail", kind="section", label="User mail servers", order=20), ViewSurface(id="mail.settings.profiles", module_id="mail", kind="section", label="Personal mail profiles", order=10), + ViewSurface(id="mail.quick_access.messages", module_id="mail", kind="quick_access", label="Mail Quick Access", order=80), + ), + product_areas=( + ProductAreaContribution( + id="communication", + module_id="mail", + label="i18n:govoplan-core.product_area.communication", + icon="mail", + description="i18n:govoplan-core.product_area.communication_description", + surface_ids=("mail.nav.mail", "mail.route.mail"), + order=40, + ), + ), + quick_access_tools=( + QuickAccessTool( + id="mail.messages", + module_id="mail", + category_id="messages", + label="i18n:govoplan-mail.mail.92379cbb", + description="i18n:govoplan-mail.quick_access_description", + surface_id="mail.quick_access.messages", + icon="mail", + full_page_path="/mail", + required_any=("mail:mailbox:read",), + order=10, + modes=("browse", "compose"), + ), ), ), migration_spec=MigrationSpec( @@ -418,6 +447,33 @@ manifest = ModuleManifest( ).SqlMailBounceProcessingProvider(), }, documentation=( + DocumentationTopic( + id="mail.quick-access-and-product-area", + title="Mail in Communication and Messages", + summary="Use Mail in the Communication product area and the shared Messages Quick Access drawer.", + body=( + "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. " + "The shared drawer does not merge channel state, credentials, custody, delivery semantics, or authorization." + ), + layer="configured", + documentation_types=("user", "admin"), + audience=("mail_user", "mail_admin", "administrator"), + related_modules=("quick_access", "views", "postbox"), + translations={ + "de": { + "title": "Mail in Kommunikation und Nachrichten", + "summary": "Mail im Produktbereich Kommunikation und in der gemeinsamen Schnellzugriffseinblendung Nachrichten verwenden.", + "body": ( + "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. " + "Die gemeinsame Darstellung führt weder Kanalzustand noch Zugangsdaten, Verwahrung oder Berechtigungen zusammen." + ), + } + }, + metadata={"kind": "reference", "help_contexts": ["mail.quick_access.messages"]}, + order=37, + ), DocumentationTopic( id="mail.search.mailbox-messages", title="Search authorized mailbox messages", diff --git a/webui/src/features/mail/MailQuickAccess.tsx b/webui/src/features/mail/MailQuickAccess.tsx new file mode 100644 index 0000000..39a7bf2 --- /dev/null +++ b/webui/src/features/mail/MailQuickAccess.tsx @@ -0,0 +1,70 @@ +import { useCallback } from "react"; +import { Mail } from "lucide-react"; +import { Link } from "react-router"; +import { + DashboardWidgetList, + DismissibleAlert, + LoadingFrame, + useDashboardWidgetData, + type ApiSettings +} from "@govoplan/core-webui"; +import { + bootstrapMailbox, + listMailServerProfiles, + type MailMailboxMessageSummary +} from "../../api/mail"; + + +type MailQuickAccessData = { + profileName?: string; + messages: MailMailboxMessageSummary[]; + available: boolean; +}; + +export default function MailQuickAccess({ settings }: { settings: ApiSettings }) { + const load = useCallback(async (): Promise => { + const profiles = await listMailServerProfiles(settings); + const profile = profiles.find((item) => item.is_active && item.imap); + if (!profile) return { messages: [], available: false }; + const response = await bootstrapMailbox(settings, profile.id, "INBOX", 7, 0, false); + return { + profileName: profile.name, + messages: response.messages.messages ?? [], + available: true + }; + }, [settings]); + const { data, loading, error } = useDashboardWidgetData(load, 0); + + return ( + + {error ? {error} : null} + ({ + id: `${message.folder}:${message.uid}`, + title: message.subject || "i18n:govoplan-mail.no_subject.49b20da0", + detail: message.from_header || data?.profileName, + meta: formatMessageDate(message.date), + leading: + ); +} + + +function formatMessageDate(value?: string | null): string | undefined { + if (!value) return undefined; + const parsed = new Date(value); + if (Number.isNaN(parsed.getTime())) return value; + return new Intl.DateTimeFormat(undefined, { + day: "2-digit", + month: "short", + hour: "2-digit", + minute: "2-digit" + }).format(parsed); +} diff --git a/webui/src/i18n/generatedTranslations.ts b/webui/src/i18n/generatedTranslations.ts index 4655aff..c663f45 100644 --- a/webui/src/i18n/generatedTranslations.ts +++ b/webui/src/i18n/generatedTranslations.ts @@ -95,6 +95,7 @@ export const generatedTranslations: PlatformTranslations = { "i18n:govoplan-mail.mail_profile_policy.f2ac4b92": "Mail profile policy", "i18n:govoplan-mail.mail_server_profiles.b1726682": "Mail server profiles", "i18n:govoplan-mail.mail.92379cbb": "Mail", + "i18n:govoplan-mail.quick_access_description": "Recent mailbox messages and mail actions.", "i18n:govoplan-mail.mailbox_folders_could_not_be_loaded.c3e3880e": "Mailbox folders could not be loaded.", "i18n:govoplan-mail.mailbox_folders.c92f6de4": "Mailbox folders", "i18n:govoplan-mail.mailbox_message_pagination.965407bf": "Mailbox message pagination", @@ -292,6 +293,7 @@ export const generatedTranslations: PlatformTranslations = { "i18n:govoplan-mail.mail_profile_policy.f2ac4b92": "Mail profile policy", "i18n:govoplan-mail.mail_server_profiles.b1726682": "Mail server profiles", "i18n:govoplan-mail.mail.92379cbb": "Mail", + "i18n:govoplan-mail.quick_access_description": "Aktuelle Posteingangsnachrichten und Mail-Aktionen.", "i18n:govoplan-mail.mailbox_folders_could_not_be_loaded.c3e3880e": "Mailbox folders could not be loaded.", "i18n:govoplan-mail.mailbox_folders.c92f6de4": "Mailbox folders", "i18n:govoplan-mail.mailbox_message_pagination.965407bf": "Mailbox message pagination", diff --git a/webui/src/module.ts b/webui/src/module.ts index 026bb58..d7f99cc 100644 --- a/webui/src/module.ts +++ b/webui/src/module.ts @@ -1,9 +1,10 @@ import { createElement, lazy } from "react"; -import type { MailDevMailboxUiCapability, MailProfilesUiCapability, PlatformWebModule } from "@govoplan/core-webui"; +import type { MailDevMailboxUiCapability, MailProfilesUiCapability, PlatformWebModule, QuickAccessToolsUiCapability } from "@govoplan/core-webui"; import { MailProfilePolicyEditor, MailProfileScopeManager } from "./features/mail/MailProfileManagement"; import { validateMailPolicy } from "./features/mail/mailPolicyValidation"; import { mailCredentialReferenceSelectors } from "./features/mail/mailReferenceProviders"; import { generatedTranslations } from "./i18n/generatedTranslations"; +import MailQuickAccess from "./features/mail/MailQuickAccess"; import "./styles/mail-profiles.css"; const MailboxPage = lazy(() => import("./features/mail/MailboxPage")); @@ -14,6 +15,14 @@ const translations = { en: generatedTranslations.en, de: generatedTranslations.de }; +const mailQuickAccessTools: QuickAccessToolsUiCapability = { + tools: [ + { + id: "mail.messages", + render: ({ settings }) => createElement(MailQuickAccess, { settings }) + } + ] +}; export const mailModule: PlatformWebModule = { id: "mail", @@ -27,7 +36,8 @@ export const mailModule: PlatformWebModule = { { id: "mail.admin.tenant-servers", moduleId: "mail", kind: "section", label: "Tenant mail servers", order: 60 }, { id: "mail.admin.group-servers", moduleId: "mail", kind: "section", label: "Group mail servers", order: 20 }, { id: "mail.admin.user-servers", moduleId: "mail", kind: "section", label: "User mail servers", order: 20 }, - { id: "mail.settings.profiles", moduleId: "mail", kind: "section", label: "Personal mail profiles", order: 10 } + { id: "mail.settings.profiles", moduleId: "mail", kind: "section", label: "Personal mail profiles", order: 10 }, + { id: "mail.quick_access.messages", moduleId: "mail", kind: "quick_access", label: "Mail Quick Access", order: 80 } ], navItems: [{ to: "/mail", label: "i18n:govoplan-mail.mail.92379cbb", iconName: "mail", anyOf: mailboxRead, order: 50 }], routes: [ @@ -36,7 +46,8 @@ export const mailModule: PlatformWebModule = { uiCapabilities: { "mail.profiles": { MailProfileScopeManager, MailProfilePolicyEditor, validateMailPolicy } satisfies MailProfilesUiCapability, - "core.credentialReferenceSelectors": mailCredentialReferenceSelectors + "core.credentialReferenceSelectors": mailCredentialReferenceSelectors, + "quickAccess.tools": mailQuickAccessTools }, runtimeUiCapabilities: { "mail.devMailbox": { enabled: true, label: "i18n:govoplan-mail.development_mock_mailbox.1a379865" } satisfies MailDevMailboxUiCapability