from __future__ import annotations from pathlib import Path from govoplan_core.core.access import ( CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER, ) from govoplan_core.core.module_guards import ( drop_table_retirement_provider, persistent_table_uninstall_guard, ) from govoplan_core.core.modules import ( DocumentationLink, DocumentationTopic, FrontendModule, MigrationSpec, ModuleContext, ModuleInterfaceProvider, ModuleManifest, PermissionDefinition, RoleTemplate, ) from govoplan_core.core.provider_governance import declared_module_architecture from govoplan_core.core.views import ViewSurface from govoplan_core.db.base import Base from govoplan_quick_access.backend.db import models as quick_access_models MODULE_ID = "quick_access" MODULE_NAME = "Quick Access" MODULE_VERSION = "0.1.18" READ_SCOPE = "quick_access:profile:read" WRITE_SCOPE = "quick_access:profile:write" TENANT_ADMIN_SCOPE = "quick_access:profile:admin" SYSTEM_ADMIN_SCOPE = "quick_access:system:admin" def _permission( scope: str, label: str, description: str, *, level: str = "tenant", ) -> PermissionDefinition: module_id, resource, action = scope.split(":", 2) return PermissionDefinition( scope=scope, label=label, description=description, category="Quick Access", level=level, module_id=module_id, resource=resource, action=action, ) PERMISSIONS = ( _permission( READ_SCOPE, "Use Quick Access", "Read the effective Quick Access catalogue and preferences.", ), _permission( WRITE_SCOPE, "Configure personal Quick Access", "Enable, disable, and order available Quick Access categories and tools.", ), _permission( TENANT_ADMIN_SCOPE, "Manage tenant Quick Access", "Set tenant availability, forced items, and default ordering.", ), _permission( SYSTEM_ADMIN_SCOPE, "Manage system Quick Access", "Set system-wide availability, forced items, and default ordering.", level="system", ), ) ROLE_TEMPLATES = ( RoleTemplate( slug="quick_access_user", name="Quick Access user", description="Use and arrange the Quick Access rail.", permissions=(READ_SCOPE, WRITE_SCOPE), default_authenticated=True, ), RoleTemplate( slug="quick_access_manager", name="Quick Access manager", description="Manage tenant Quick Access policy and defaults.", permissions=(READ_SCOPE, WRITE_SCOPE, TENANT_ADMIN_SCOPE), ), RoleTemplate( slug="quick_access_system_manager", name="Quick Access system manager", description="Manage system-wide Quick Access policy and defaults.", permissions=(SYSTEM_ADMIN_SCOPE,), level="system", ), ) def _router(context: ModuleContext): from govoplan_quick_access.backend.router import create_router return create_router(context.registry) DOCUMENTATION = ( DocumentationTopic( id="quick-access.user", title="Quick Access rail", summary="Keep selected work, calendar, message, and file tools available beside the current page.", body=( "Open a category on the right rail to use compact tools without leaving the current task. " "Messages combines enabled Mail, Postbox, and future chat contributions in one overlay. " "Personal settings can reorder or hide items that remain available under system, tenant, " "permission, and View policy. Every item retains a link to its complete owning page. " "When a View focuses the rail, the rail names that View and offers a temporary All available tools escape that " "shows the complete permission-derived catalogue without changing the View or personal settings. If none of a " "View's focused tools is currently available, Quick Access explains the stale focus and falls back to that catalogue. " "Launch-context version 2 carries only versioned, bounded references to the current object, acting assignment, " "temporal selection, exact View revision, and return location. Owner modules recheck access when a tool opens and " "before each effect. A tool returns either an explicit version-1 completion with a typed owner reference or an " "explicit cancellation; closing the drawer does not imply success. The overlay preserves unsaved host-page work, " "and the complete owning page remains the fallback for work that exceeds the compact surface." ), layer="configured", documentation_types=("user",), audience=("user",), links=( DocumentationLink( label="Quick Access architecture", href="govoplan-quick-access/docs/QUICK_ACCESS.md", kind="repository", ), ), translations={ "de": { "title": "Schnellzugriffsleiste", "summary": "Ausgewaehlte Werkzeuge fuer Arbeit, Kalender, Nachrichten und Dateien neben der aktuellen Seite verwenden.", "body": ( "Eine Kategorie in der rechten Leiste oeffnet kompakte Werkzeuge, ohne die aktuelle Aufgabe zu verlassen. " "Nachrichten fuehrt Beitraege aus Mail, Postfach und kuenftigen Chat-Modulen in einer Einblendung zusammen. " "Persoenliche Einstellungen koennen alle durch System, Mandant, Berechtigungen und Ansicht zugelassenen Eintraege ordnen oder ausblenden. " "Wenn eine Ansicht die Leiste fokussiert, benennt die Leiste diese Ansicht und bietet voruebergehend alle " "verfuegbaren Werkzeuge an, ohne Ansicht oder persoenliche Einstellungen zu aendern. Ist keines der fokussierten " "Werkzeuge verfuegbar, wird der veraltete Fokus erklaert und der berechtigungsabgeleitete Katalog angezeigt. " "Startkontext Version 2 uebergibt nur versionierte, begrenzte Verweise auf Objekt, handelnde Zuordnung, " "Zeitbezug, genaue Ansichtsversion und Ruecksprungort. Das besitzende Modul prueft den Zugriff beim Oeffnen " "und vor jeder Wirkung erneut. Ein Werkzeug meldet entweder einen ausdruecklichen Abschluss mit typisiertem " "Besitzerverweis oder einen ausdruecklichen Abbruch; das Schliessen gilt nicht als Erfolg. Die Einblendung " "erhaelt ungespeicherte Arbeit auf der Ausgangsseite, die vollstaendige Besitzerseite bleibt das Ausweichziel." ), } }, metadata={ "help_contexts": [ "quick_access.rail", "quick_access.drawer", "quick_access.settings.personal", ] }, ), DocumentationTopic( id="quick-access.admin", title="Quick Access policy", summary="Govern which registered compact tools lower scopes may use and how they are ordered by default.", body=( "The catalogue follows installed module registrations. System settings constrain tenants; " "tenant settings constrain users. An item may remain available, be blocked, or be forced. " "Views and permissions form additional ceilings and Quick Access never grants access to domain data. " "A View may recommend tools or focus the rail to a subset, but only currently enabled, context-compatible, authorized " "tools participate. The All available tools escape only restores that permission-derived set for the current session; " "it never broadens authorization or persists an override. Workflow receives that same presentation from the exact resolved View revision. Launch-context " "version 2, reference contract version 1, and result contract version 1 fail closed on unknown versions; cross-tenant " "active-object and result references are rejected." ), layer="configured", documentation_types=("admin",), audience=("system_admin", "tenant_admin", "module_admin"), translations={ "de": { "title": "Richtlinien fuer den Schnellzugriff", "summary": "Verfuegbarkeit und Standardreihenfolge registrierter kompakter Werkzeuge steuern.", "body": ( "Der Katalog folgt den Registrierungen installierter Module. Systemeinstellungen begrenzen Mandanten, " "Mandanteneinstellungen begrenzen Benutzer. Ein Eintrag kann verfuegbar, gesperrt oder erzwungen sein. " "Ansichten und Berechtigungen bilden weitere Grenzen; Schnellzugriff erteilt selbst keinen Datenzugriff. " "Eine Ansicht darf Werkzeuge empfehlen oder die Leiste auf eine Teilmenge fokussieren, jedoch nur innerhalb " "der aktivierten, kontextgeeigneten und berechtigten Werkzeuge. Alle verfuegbaren Werkzeuge stellt nur diese " "berechtigungsabgeleitete Menge fuer die laufende Sitzung wieder her und speichert keine Umgehung. Workflow verwendet dieselbe Darstellung aus " "der genau aufgeloesten Ansichtsversion. Startkontext Version 2 sowie Verweis- und Ergebniskontrakt Version 1 " "lehnen unbekannte Versionen ab; mandantenfremde Objekt- und Ergebnisverweise werden verworfen." ), } }, metadata={ "help_contexts": [ "quick_access.admin.system", "quick_access.admin.tenant", "quick_access.field.availability", "quick_access.field.order", ] }, ), ) manifest = ModuleManifest( id=MODULE_ID, name=MODULE_NAME, version=MODULE_VERSION, dependencies=("access",), optional_dependencies=("views", "policy"), required_capabilities=( CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR, ), provides_interfaces=( ModuleInterfaceProvider(name="quick_access.runtime", version="1.0.0"), ModuleInterfaceProvider(name="quick_access.preferences", version="1.0.0"), ), permissions=PERMISSIONS, role_templates=ROLE_TEMPLATES, route_factory=_router, frontend=FrontendModule( module_id=MODULE_ID, package_name="@govoplan/quick-access-webui", view_surfaces=( ViewSurface( id="quick_access.rail", module_id=MODULE_ID, kind="quick_access", label="Quick Access rail", description="Optional right-side rail and overlay host.", order=5, required=True, ), ViewSurface( id="quick_access.drawer", module_id=MODULE_ID, kind="quick_access", label="Quick Access drawer", parent_id="quick_access.rail", order=10, required=True, ), ViewSurface( id="quick_access.settings.personal", module_id=MODULE_ID, kind="section", label="Personal Quick Access settings", order=20, ), ViewSurface( id="quick_access.admin.tenant", module_id=MODULE_ID, kind="section", label="Tenant Quick Access policy", order=30, ), ViewSurface( id="quick_access.admin.system", module_id=MODULE_ID, kind="section", label="System Quick Access policy", order=40, ), ), ), migration_spec=MigrationSpec( module_id=MODULE_ID, metadata=Base.metadata, script_location=str(Path(__file__).with_name("migrations") / "versions"), retirement_supported=True, retirement_provider=drop_table_retirement_provider( quick_access_models.QuickAccessProfile, label="Quick Access preferences", ), retirement_notes=( "Destructive retirement removes presentation preferences only; " "contributing module data and full-page routes remain unchanged." ), ), uninstall_guard_providers=( persistent_table_uninstall_guard( quick_access_models.QuickAccessProfile, label="Quick Access preferences", ), ), documentation=DOCUMENTATION, architecture=declared_module_architecture( layer="runtime_meta", kind="presentation", maturity="vertical_slice", documentation_ref="docs/QUICK_ACCESS.md", test_ref="tests/test_quick_access.py", known_limits=( "The first slice provides four stable categories; administrators cannot yet define additional category identities.", ), supported_authority_modes=("native_authoritative",), owned_concepts=( "Quick Access profile", "Quick Access rail", "Quick Access category ordering", ), non_owned_concepts=( "task", "calendar event", "mail message", "postbox message", "file", "authorization decision", ), reference_packages=("product.task-focused-workspace",), migration_docs=("docs/QUICK_ACCESS.md",), recovery_docs=("docs/QUICK_ACCESS.md",), security_docs=("docs/QUICK_ACCESS.md",), operations_docs=("docs/QUICK_ACCESS.md",), ), ) def get_manifest() -> ModuleManifest: return manifest __all__ = [ "MODULE_ID", "MODULE_VERSION", "READ_SCOPE", "SYSTEM_ADMIN_SCOPE", "TENANT_ADMIN_SCOPE", "WRITE_SCOPE", "get_manifest", "manifest", ]