From f793f5d493a8b36b4b377d3d97e967fdda13c1d1 Mon Sep 17 00:00:00 2001 From: fs Date: Wed, 22 Apr 2026 17:25:07 +0200 Subject: [PATCH] chore(drawer): close consolidation gaps after three-consumer rollout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loose ends surfaced by comparing the three drawer consumers side by side: - Core i18n was missing `Open full page`, `Loading`, `Failed to load` — admin/users showed English strings in the German UI because those labels resolve from core, not module catalogs. - Helpdesk tickets page config did not pass drawer labels; the JS fell back to its hard-coded English defaults. Labels now wired via `t(...)`. - CLAUDE.md notes the `fetchUrl` single-expression convention (required so the architecture test can statically locate the fragment path) and documents the `onContentLoaded` hook for module-specific runtime (helpdesk's async communication feed uses it). Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 3 ++- i18n/default_de.json | 3 +++ i18n/default_en.json | 3 +++ modules/helpdesk/pages/helpdesk/debitor(default).phtml | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index f9e7fe3..208634b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -178,7 +178,8 @@ docker/ # Dockerfiles, Nginx configs, PHP configs - **Detail drawer**: Row-level detail views that slide in from the right use the core primitive — no per-module drawer implementation. - **Server:** Action `/-fragment($id).php` + view `/-fragment(none).phtml`. The `(none)` template renders without layout/topbar/breadcrumbs. Reuse the same partial that the full-page view uses (extract a `modules//templates/-profile.phtml` if needed). Must enforce auth + scope exactly like the full-page view. - **Route:** Declare `['path' => '/-fragment', 'target' => '/-fragment']` in the module manifest. - - **Client:** `initDetailDrawer({ gridConfig, fetchUrl: (uuid) => new URL('/-fragment/' + uuid, appBase).toString(), fullUrl, hashPrefix, rowProvider? })` from `/js/components/app-detail-drawer.js`. The drawer handles focus-trap, body-scroll-lock, session-expiry reload, and auto-initializes tabs/tooltips/fslightbox in the fragment via `initFragmentContent()`. Consumers do NOT need to call `initTabs`, `refreshFsLightbox`, etc. manually. + - **Client:** `initDetailDrawer({ gridConfig, fetchUrl: (uuid) => new URL(`/-fragment/${uuid}`, appBase).toString(), fullUrl, hashPrefix, rowProvider?, onContentLoaded? })` from `/js/components/app-detail-drawer.js`. The drawer handles focus-trap, body-scroll-lock, session-expiry reload, and auto-initializes tabs/tooltips/fslightbox in the fragment via `initFragmentContent()`. Consumers do NOT need to call `initTabs`, `refreshFsLightbox`, etc. manually. For module-specific runtime (e.g. async communication feeds) use `onContentLoaded(contentEl, uuid)`. + - **`fetchUrl` signature:** write it as a single-expression arrow (not a block body) so the architecture test can statically locate the fragment path. Pattern: ``(uuid) => new URL(`path/${uuid}...`, appBase).toString()``. - **Architecture test** `DetailDrawerFragmentContractTest` enforces that every `initDetailDrawer({ fetchUrl })` has matching `*-fragment($id).php` + `*-fragment(none).phtml`. - **Filename rule:** URL parameters go only into the `.php` action filename (`*-fragment($id).php`). The `(none).phtml` view filename must NOT contain `($id)` — MintyPHP's router parses paren groups and breaks silently on nested ones. diff --git a/i18n/default_de.json b/i18n/default_de.json index 0ec6519..1191c1f 100644 --- a/i18n/default_de.json +++ b/i18n/default_de.json @@ -2,6 +2,9 @@ "Login": "Login", "Login credentials": "Mit Zugangsdaten oder SSO anmelden", "Login provider": "Login-Anbieter", + "Open full page": "Vollseite öffnen", + "Loading": "Lädt", + "Failed to load": "Laden fehlgeschlagen", "Register": "Registrieren", "Password": "Passwort", "Or": "Oder", diff --git a/i18n/default_en.json b/i18n/default_en.json index d35b8a2..68ff459 100644 --- a/i18n/default_en.json +++ b/i18n/default_en.json @@ -2,6 +2,9 @@ "Login": "Login", "Login credentials": "Login credentials", "Login provider": "Login provider", + "Open full page": "Open full page", + "Loading": "Loading", + "Failed to load": "Failed to load", "Register": "Register", "Password": "Password", "Or": "Or", diff --git a/modules/helpdesk/pages/helpdesk/debitor(default).phtml b/modules/helpdesk/pages/helpdesk/debitor(default).phtml index 25b2109..34c6d06 100644 --- a/modules/helpdesk/pages/helpdesk/debitor(default).phtml +++ b/modules/helpdesk/pages/helpdesk/debitor(default).phtml @@ -351,6 +351,12 @@ $searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null; 'support' => t('Support'), 'created' => t('Created'), 'lastActivity' => t('Last activity'), + 'drawerClose' => t('Close'), + 'drawerPrev' => t('Previous'), + 'drawerNext' => t('Next'), + 'drawerOpenFull' => t('Open full page'), + 'drawerLoading' => t('Loading'), + 'drawerError' => t('Failed to load'), ], 'gridSearch' => $searchConfig, 'filterSchema' => $clientFilterSchema,