add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
# Frontend JavaScript
|
|
|
|
|
|
|
feat: extend module platform with UI slots, runtime components, CLI tooling and {{userId}} search support
Completes the generic module platform that enables modules to contribute
UI elements, runtime JS components, and search resources without any
core hardcoding.
New generic UI slot types:
- topbar.right_item: module-contributed topbar buttons
- layout.body_end_template: module-contributed dialog/overlay templates
- layout.head_style: module-contributed global CSS
- runtime.component: declarative JS component registration with phase ordering
New infrastructure:
- ModuleAutoloader: PSR-4 autoloading for module-local PHP classes
- ModuleRuntimePageBuilder: symlinks module pages into runtime directory
- ModuleRuntimeAssetPublisher: publishes module CSS/JS to web/modules/
- ModulePermissionSynchronizer: syncs module permissions to DB
- CLI scripts: module-runtime-sync, module-build, module-migrate,
module-permissions-sync, module-assets-sync
- {{userId}} placeholder in SearchDataService for user-scoped search queries
- Component runtime with phased initialization (early/default/late)
- AppContainer.protectExistingBindings() to prevent module→core overwrites
- Architecture tests: ModuleStructureContractTest, CoreTemplateIsolationTest,
FrontendComponentRuntimeContractTest, AppContainerIsolationContractTest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:19:56 +01:00
|
|
|
|
Letzte Aktualisierung: 2026-03-18
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
|
|
## Ordnerstruktur
|
|
|
|
|
|
|
|
|
|
|
|
- `/web/js/core`
|
|
|
|
|
|
- technische Basismodule (DOM/Factories)
|
|
|
|
|
|
- `/web/js/components`
|
|
|
|
|
|
- wiederverwendbare UI-Features
|
|
|
|
|
|
- `/web/js/pages`
|
|
|
|
|
|
- seitenspezifische Hilfen (z. B. Listeninitialisierung)
|
|
|
|
|
|
|
|
|
|
|
|
## Initialisierung
|
|
|
|
|
|
|
|
|
|
|
|
- `/web/js/app-boot.js`
|
|
|
|
|
|
- wird im `<head>` geladen
|
|
|
|
|
|
- setzt früh UI-States (no-js/js, Sidebar-/Contrast-LocalStorage)
|
|
|
|
|
|
- `/web/js/app-init.js`
|
|
|
|
|
|
- Modul-Entrypoint für Standardseiten
|
feat: extend module platform with UI slots, runtime components, CLI tooling and {{userId}} search support
Completes the generic module platform that enables modules to contribute
UI elements, runtime JS components, and search resources without any
core hardcoding.
New generic UI slot types:
- topbar.right_item: module-contributed topbar buttons
- layout.body_end_template: module-contributed dialog/overlay templates
- layout.head_style: module-contributed global CSS
- runtime.component: declarative JS component registration with phase ordering
New infrastructure:
- ModuleAutoloader: PSR-4 autoloading for module-local PHP classes
- ModuleRuntimePageBuilder: symlinks module pages into runtime directory
- ModuleRuntimeAssetPublisher: publishes module CSS/JS to web/modules/
- ModulePermissionSynchronizer: syncs module permissions to DB
- CLI scripts: module-runtime-sync, module-build, module-migrate,
module-permissions-sync, module-assets-sync
- {{userId}} placeholder in SearchDataService for user-scoped search queries
- Component runtime with phased initialization (early/default/late)
- AppContainer.protectExistingBindings() to prevent module→core overwrites
- Architecture tests: ModuleStructureContractTest, CoreTemplateIsolationTest,
FrontendComponentRuntimeContractTest, AppContainerIsolationContractTest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:19:56 +01:00
|
|
|
|
- initialisiert Runtime + globale Komponenten zentral
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
- `/web/js/app-login-init.js`
|
|
|
|
|
|
- reduzierter Entrypoint für Loginseiten
|
|
|
|
|
|
|
|
|
|
|
|
## Modulkonvention (components/pages)
|
|
|
|
|
|
|
|
|
|
|
|
Empfohlenes Muster:
|
|
|
|
|
|
|
|
|
|
|
|
1. `init...()` Funktion exportieren
|
|
|
|
|
|
2. Früher Guard auf fehlende Elemente
|
|
|
|
|
|
3. Keine stillen Fehler verschlucken
|
|
|
|
|
|
4. Nur DOM/UI-Verhalten, keine Fachlogik
|
feat: extend module platform with UI slots, runtime components, CLI tooling and {{userId}} search support
Completes the generic module platform that enables modules to contribute
UI elements, runtime JS components, and search resources without any
core hardcoding.
New generic UI slot types:
- topbar.right_item: module-contributed topbar buttons
- layout.body_end_template: module-contributed dialog/overlay templates
- layout.head_style: module-contributed global CSS
- runtime.component: declarative JS component registration with phase ordering
New infrastructure:
- ModuleAutoloader: PSR-4 autoloading for module-local PHP classes
- ModuleRuntimePageBuilder: symlinks module pages into runtime directory
- ModuleRuntimeAssetPublisher: publishes module CSS/JS to web/modules/
- ModulePermissionSynchronizer: syncs module permissions to DB
- CLI scripts: module-runtime-sync, module-build, module-migrate,
module-permissions-sync, module-assets-sync
- {{userId}} placeholder in SearchDataService for user-scoped search queries
- Component runtime with phased initialization (early/default/late)
- AppContainer.protectExistingBindings() to prevent module→core overwrites
- Architecture tests: ModuleStructureContractTest, CoreTemplateIsolationTest,
FrontendComponentRuntimeContractTest, AppContainerIsolationContractTest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:19:56 +01:00
|
|
|
|
5. Lifecycle-Contract für Runtime-Komponenten: `init(root, config)` gibt API mit `destroy()` zurück
|
|
|
|
|
|
6. Runtime-Komponenten dürfen keinen eigenen Auto-Init via `DOMContentLoaded`/Sideeffect enthalten
|
|
|
|
|
|
|
|
|
|
|
|
## Component Runtime (Restmigration)
|
|
|
|
|
|
|
|
|
|
|
|
- Zentrale Runtime: `web/js/core/app-component-runtime.js`.
|
|
|
|
|
|
- Runtime-Page-Configs:
|
|
|
|
|
|
- Standardseiten: `<script type="application/json" id="page-config-app-components">...</script>`
|
|
|
|
|
|
- Loginseiten: `<script type="application/json" id="page-config-login-components">...</script>`
|
|
|
|
|
|
- Runtime liest Config über `readPageConfig(...)` und mountet registrierte Komponenten pro Entrypoint:
|
|
|
|
|
|
- `web/js/app-init.js` (default)
|
|
|
|
|
|
- `web/js/app-login-init.js` (login)
|
|
|
|
|
|
- Komponenteninterner Contract:
|
|
|
|
|
|
- Init-Signatur: `initX(root, config)`
|
|
|
|
|
|
- Rueckgabe: `{ destroy() }`
|
|
|
|
|
|
- `destroy()` muss alle Listener/Timer/Observer abbauen.
|
|
|
|
|
|
- Hybrid Host-Policy:
|
|
|
|
|
|
- Host-gebundene UI-Komponenten nutzen explizite `data-app-component`-Hosts im Markup.
|
|
|
|
|
|
- Tabs sind host-gebunden und laufen ausschliesslich ueber `data-app-component="tabs"`.
|
|
|
|
|
|
- Globale Utilities ohne natuerliches Host-Element werden runtime-global (`scope: 'global'`) registriert, aber mit demselben Lifecycle-Contract.
|
|
|
|
|
|
- Root-Strict gilt fuer host-gebundene Komponenten: keine `document.querySelector`-Fallback-Pfade.
|
|
|
|
|
|
- Projektseitige Custom-Globals auf `window.*` sind verboten; Komponenten kommunizieren ueber Core-Channels.
|
|
|
|
|
|
|
|
|
|
|
|
## UI Storage Contract
|
|
|
|
|
|
|
|
|
|
|
|
- Persistente UI-States laufen fuer Runtime-Komponenten ueber `web/js/core/app-ui-storage.js`.
|
|
|
|
|
|
- Storage-Keys sind namespaced (`namespace:version:scope:*`) statt ungeordnet verteilt.
|
|
|
|
|
|
- Hard-Cut-Policy: keine Legacy-Key-Fallbacks und kein Legacy-Key-Sync in migrierten Runtime-Komponenten/Core-Modulen.
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
|
|
Template für neue Komponenten:
|
|
|
|
|
|
|
2026-03-05 08:26:51 +01:00
|
|
|
|
- bestehende Komponenten als Referenz verwenden (`/web/js/components/*.js`)
|
|
|
|
|
|
|
|
|
|
|
|
## Page Module Contract (Hard Cut)
|
|
|
|
|
|
|
|
|
|
|
|
Für seitenbezogene Initialisierung gilt verbindlich:
|
|
|
|
|
|
|
|
|
|
|
|
- Kein inline `<script type="module">` in `pages/**` oder `templates/**`.
|
|
|
|
|
|
- Pro Seite genau ein externes Modul unter `web/js/pages/*` laden.
|
|
|
|
|
|
- Serverseitige Daten für dieses Modul über
|
|
|
|
|
|
`<script type="application/json" id="page-config-...">...</script>` bereitstellen.
|
|
|
|
|
|
- Page-Module lesen Config zentral über `readPageConfig(...)` aus `web/js/core/app-page-config.js`.
|
|
|
|
|
|
- JS-`src` in `pages/**` und `templates/**` nur über `assetVersion('...js...')`.
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
|
|
## Defensive DOM-Nutzung
|
|
|
|
|
|
|
|
|
|
|
|
Nicht jede Seite hat jedes Element.
|
|
|
|
|
|
|
|
|
|
|
|
- Vor Zugriff immer Element-Existenz prüfen.
|
|
|
|
|
|
- Optional zentrale Helper (`app-dom.js`) verwenden.
|
|
|
|
|
|
- Module sollen auf nicht-passenden Seiten sauber no-op sein.
|
|
|
|
|
|
|
|
|
|
|
|
## Grid.js-Integration
|
|
|
|
|
|
|
|
|
|
|
|
- Gemeinsame Initialisierung über Core/Page-Utilities.
|
|
|
|
|
|
- Vendor-spezifische CSS-Anpassungen in:
|
|
|
|
|
|
- `/web/css/vendor-overrides/gridjs.css`
|
|
|
|
|
|
- Bei dynamischen Rows mit Lightbox/Tooltips: nach Render Refresh triggern.
|
|
|
|
|
|
|
|
|
|
|
|
### Grid URL State Sync
|
|
|
|
|
|
|
|
|
|
|
|
`createServerGrid(...)` synchronisiert bei `urlSync: true` den Grid-Zustand zentral in die URL.
|
|
|
|
|
|
|
|
|
|
|
|
- Search + Filter (bestehendes Verhalten)
|
|
|
|
|
|
- Sortierung über `order` + `dir`
|
|
|
|
|
|
- Pagination über `page` (1-basiert)
|
|
|
|
|
|
|
|
|
|
|
|
Optionale Konfiguration:
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
createServerGrid({
|
|
|
|
|
|
// ...
|
|
|
|
|
|
urlSync: true,
|
|
|
|
|
|
urlState: {
|
|
|
|
|
|
pageParam: 'page',
|
|
|
|
|
|
sortOrderParam: 'order',
|
|
|
|
|
|
sortDirParam: 'dir',
|
|
|
|
|
|
cleanFirstPage: true,
|
|
|
|
|
|
syncPage: true,
|
|
|
|
|
|
syncSort: true
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Hinweise:
|
|
|
|
|
|
|
|
|
|
|
|
- `page=1` wird bei `cleanFirstPage: true` nicht in der URL gehalten.
|
|
|
|
|
|
- Übernommene URL-Werte werden validiert:
|
|
|
|
|
|
- `page >= 1`
|
|
|
|
|
|
- `dir` nur `asc|desc`
|
|
|
|
|
|
- `order` nur bekannte Sort-Key-Spalten
|
|
|
|
|
|
- Bei Search-/Filter-Änderung wird auf Seite 1 zurückgesetzt.
|
|
|
|
|
|
|
2026-03-05 11:17:42 +01:00
|
|
|
|
### Row Interaction (Globaler Standard)
|
|
|
|
|
|
|
|
|
|
|
|
Listen mit `rowDblClick.getUrl(...)` nutzen standardmäßig eine zugängliche Row-Interaktion:
|
|
|
|
|
|
|
|
|
|
|
|
- sichtbare Action-Spalte rechts (`Open`/`Edit`)
|
|
|
|
|
|
- Doppelklick bleibt als Fallback aktiv
|
|
|
|
|
|
- `Enter` auf fokussierter Zeile navigiert zur selben URL
|
2026-03-05 12:51:53 +01:00
|
|
|
|
- Action-Header/Tooltip zeigt den Enter-Hinweis
|
2026-03-05 11:17:42 +01:00
|
|
|
|
|
|
|
|
|
|
Optionale Konfiguration über `createServerGrid(...)`:
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
createServerGrid({
|
|
|
|
|
|
// ...
|
|
|
|
|
|
rowDblClick: {
|
|
|
|
|
|
getUrl: (rowData) => new URL(`admin/users/edit/${rowData?.cells?.[1]?.data}`, appBase).toString(),
|
|
|
|
|
|
},
|
|
|
|
|
|
rowInteraction: {
|
|
|
|
|
|
enabled: true,
|
|
|
|
|
|
showActionButton: true,
|
|
|
|
|
|
keepDblClick: true,
|
|
|
|
|
|
enableEnterOnRow: true,
|
|
|
|
|
|
actionColumnLabel: 'Actions',
|
|
|
|
|
|
resolveActionLabel: (url) => (url.includes('/edit/') ? 'Edit' : 'Open'),
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Defaults:
|
|
|
|
|
|
|
|
|
|
|
|
- `rowInteraction.enabled`: `true`, wenn `rowDblClick.getUrl` vorhanden ist
|
|
|
|
|
|
- `showActionButton`: `true`
|
|
|
|
|
|
- `keepDblClick`: `true`
|
|
|
|
|
|
- `enableEnterOnRow`: `true`
|
|
|
|
|
|
- `actionColumnLabel`: `language.actions.column` oder `'Actions'`
|
|
|
|
|
|
|
|
|
|
|
|
Hinweis:
|
|
|
|
|
|
|
|
|
|
|
|
- Falls eine Seite `actions.enabled: true` explizit setzt, wird keine zusätzliche automatische Row-Action-Spalte injiziert.
|
|
|
|
|
|
|
2026-03-05 12:51:53 +01:00
|
|
|
|
### Grid Error Recovery
|
|
|
|
|
|
|
|
|
|
|
|
Bei Grid-Fehlern rendert die Factory automatisch einen Retry-CTA im Error-State.
|
|
|
|
|
|
|
|
|
|
|
|
- Label kommt aus `language.errorRetry` (Fallback: `Retry`).
|
|
|
|
|
|
- Klick auf Retry lädt den Grid-Server-Request erneut.
|
|
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
### Filter UX 2.0 (Globaler Standard)
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
Für Listen gilt standardmäßig:
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
1. Quick Search sichtbar außerhalb des Drawers.
|
|
|
|
|
|
2. Restliche Filter im rechten Drawer (`data-filter-drawer-*`).
|
|
|
|
|
|
3. Drawer arbeitet `apply-first` (Draft bis `Apply`).
|
|
|
|
|
|
4. Aktive Filter werden als Chips angezeigt (`data-active-filter-chips`).
|
|
|
|
|
|
5. Filter-Reset erfolgt über Chips (`Clear all filters`), nicht im Drawer.
|
|
|
|
|
|
|
|
|
|
|
|
JS-Verkabelung:
|
|
|
|
|
|
|
|
|
|
|
|
- Standard-Entrypoint ist `initStandardListPage(...)` aus `web/js/core/app-grid-factory.js`.
|
|
|
|
|
|
- Der Wrapper kapselt intern `createServerGrid(...)` + (bei `mode: 'drawer'`) `initListFilterExperience(...)`.
|
|
|
|
|
|
- Bei Apply/Clear wird URL mit `pushState` fortgeschrieben.
|
|
|
|
|
|
- Save-Filter-Usecases lesen den angewandten Zustand über `gridConfig.baseUrl()`.
|
|
|
|
|
|
- Chip-State-Logik ist zentral im Wrapper verdrahtet (Default: `app-list-filter-state.js`).
|
|
|
|
|
|
|
|
|
|
|
|
Search-only-Ausnahme:
|
|
|
|
|
|
|
|
|
|
|
|
- Listen ohne zusätzliche Filter initialisieren über denselben Wrapper mit `mode: 'search-only'` (ohne Drawer/Chips).
|
|
|
|
|
|
|
|
|
|
|
|
### Standard-List-API
|
|
|
|
|
|
|
|
|
|
|
|
Für Listen-Templates gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- `initStandardListPage({ grid, filters, hooks })` verwenden.
|
|
|
|
|
|
- `grid.filterSchema` serverseitig aus `filter-schema.php` (`gridSchemaClientFilters(...)`) übergeben.
|
|
|
|
|
|
- Optional zusätzliche Spezialfilter über `grid.extraFilters`.
|
|
|
|
|
|
- Bei Drawer-Listen `filters.mode: 'drawer'`, bei Search-only `filters.mode: 'search-only'`.
|
|
|
|
|
|
|
|
|
|
|
|
Regel:
|
|
|
|
|
|
|
|
|
|
|
|
- keine direkten Aufrufe von `gridFiltersFromSchema(...)` in Listen-Templates
|
|
|
|
|
|
- keine direkten Aufrufe von `initListFilterExperience(...)` in Listen-Templates
|
|
|
|
|
|
- keine inline `filters: [...]`-Arrays in Listen-Templates
|
|
|
|
|
|
- MultiSelect-Filter immer als CSV-Key (`*_ids`, `actions`, `event_types` etc.)
|
|
|
|
|
|
|
|
|
|
|
|
Serverseitig passendes Template-Markup:
|
|
|
|
|
|
|
|
|
|
|
|
- normale Select-Filter über `selectFilter(...)`
|
|
|
|
|
|
- MultiSelect-Filter über `multiSelectFilter(...)`
|
|
|
|
|
|
|
|
|
|
|
|
### List Titlebar Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für Listen-Titlebars gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Titlebar über `templates/partials/app-list-titlebar.phtml` rendern.
|
|
|
|
|
|
- Titel über `$listTitle` setzen.
|
|
|
|
|
|
- Aktionen über `$listTitleActionsHtml` als Slot (captured HTML) übergeben.
|
|
|
|
|
|
|
|
|
|
|
|
Beispiel:
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$listTitle = t('Users');
|
|
|
|
|
|
ob_start();
|
|
|
|
|
|
?>
|
|
|
|
|
|
<a role="button" class="primary" href="admin/users/create"><?php e(t('Create user')); ?></a>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$listTitleActionsHtml = ob_get_clean();
|
|
|
|
|
|
require templatePath('partials/app-list-titlebar.phtml');
|
|
|
|
|
|
?>
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
### List Tabs Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für Tenant- oder Kontext-Tabs in Listen gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Tabs über `templates/partials/app-list-tabs.phtml` rendern.
|
|
|
|
|
|
- Tab-Items über `$listTabsItems` mit `href`, `label`, `active` übergeben.
|
|
|
|
|
|
- Optional `id` über `$listTabsId` setzen.
|
|
|
|
|
|
|
|
|
|
|
|
### List Purge Action Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für Purge-Buttons in Titlebar-Actions gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Purge-Markup über `templates/partials/app-list-purge-action.phtml` rendern.
|
|
|
|
|
|
- Formular/CSRF/Button/Confirm werden zentral übergeben via:
|
|
|
|
|
|
- `$listPurgeEnabled`
|
|
|
|
|
|
- `$listPurgeFormId`
|
|
|
|
|
|
- `$listPurgeAction`
|
|
|
|
|
|
- `$listPurgeConfirmMessage`
|
|
|
|
|
|
- `$listPurgeButtonLabel`
|
|
|
|
|
|
|
|
|
|
|
|
### Aside Grouped Navigation + Persisted Details State
|
|
|
|
|
|
|
|
|
|
|
|
Für gruppierte Sidebar-Navigation mit einklappbaren `details` gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Zentraler Storage-Helper: `web/js/core/app-details-open-state.js` (`initPersistedDetailsGroup(...)`).
|
|
|
|
|
|
- Standardgruppen über `details[data-details-key]`.
|
|
|
|
|
|
- Persistenz-Aktivierung über:
|
|
|
|
|
|
- `data-details-storage="..."` (allgemein, z. B. Detailseiten)
|
|
|
|
|
|
- `data-aside-details-storage="..."` (Aside-Panels)
|
|
|
|
|
|
- Optionales Aktiv-Verhalten im Aside über `data-aside-details-open-active="1"`:
|
|
|
|
|
|
- aktive Gruppe bleibt immer offen
|
|
|
|
|
|
- effektive Open-Keys = `persistedOpenKeys ∪ activeOpenKeys`
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
Admin-Aside-Standard:
|
|
|
|
|
|
|
|
|
|
|
|
- Storage-Key: `aside-admin-sections-v1`
|
|
|
|
|
|
- Gruppenkeys:
|
|
|
|
|
|
- `admin-organization`
|
|
|
|
|
|
- `admin-roles-permissions`
|
|
|
|
|
|
- `admin-automation`
|
|
|
|
|
|
- `admin-monitoring`
|
|
|
|
|
|
- `admin-logs`
|
|
|
|
|
|
- `admin-system`
|
|
|
|
|
|
|
|
|
|
|
|
### Detail Page Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für Create/Edit-Detailseiten gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Hauptformular über `data-standard-detail-form="1"` explizit opt-in markieren.
|
|
|
|
|
|
- Initialisierung läuft zentral über `initStandardDetailPage(...)` aus `web/js/core/app-detail-page-factory.js`.
|
feat: extend module platform with UI slots, runtime components, CLI tooling and {{userId}} search support
Completes the generic module platform that enables modules to contribute
UI elements, runtime JS components, and search resources without any
core hardcoding.
New generic UI slot types:
- topbar.right_item: module-contributed topbar buttons
- layout.body_end_template: module-contributed dialog/overlay templates
- layout.head_style: module-contributed global CSS
- runtime.component: declarative JS component registration with phase ordering
New infrastructure:
- ModuleAutoloader: PSR-4 autoloading for module-local PHP classes
- ModuleRuntimePageBuilder: symlinks module pages into runtime directory
- ModuleRuntimeAssetPublisher: publishes module CSS/JS to web/modules/
- ModulePermissionSynchronizer: syncs module permissions to DB
- CLI scripts: module-runtime-sync, module-build, module-migrate,
module-permissions-sync, module-assets-sync
- {{userId}} placeholder in SearchDataService for user-scoped search queries
- Component runtime with phased initialization (early/default/late)
- AppContainer.protectExistingBindings() to prevent module→core overwrites
- Architecture tests: ModuleStructureContractTest, CoreTemplateIsolationTest,
FrontendComponentRuntimeContractTest, AppContainerIsolationContractTest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:19:56 +01:00
|
|
|
|
- Runtime-Init erfolgt über `web/js/app-init.js` (Komponente `standard-detail-page`).
|
2026-03-04 15:56:58 +01:00
|
|
|
|
|
|
|
|
|
|
Standardverhalten:
|
|
|
|
|
|
|
|
|
|
|
|
- Dirty-State über serialisierte `FormData`-Diffs (initial vs. aktuell).
|
|
|
|
|
|
- `beforeunload`-Warnung nur bei ungespeicherten Änderungen.
|
|
|
|
|
|
- Back/Cancel-Link in `.app-details-titlebar h1 a` fragt bei Dirty-State per Confirm.
|
|
|
|
|
|
- `Cmd/Ctrl+S` triggert primären Save/Create-Button (`data-detail-save-primary="1"`).
|
|
|
|
|
|
- Submit-Lock/Confirm laufen zentral über die Detail-Action-Policy.
|
|
|
|
|
|
- Bei Dirty-State wird in der Titlebar automatisch ein kleiner Hinweis mit Feldanzahl gezeigt.
|
|
|
|
|
|
|
|
|
|
|
|
### Detail Action Policy
|
|
|
|
|
|
|
|
|
|
|
|
Für standardisierte Detailseiten gilt zusätzlich:
|
|
|
|
|
|
|
|
|
|
|
|
- `initStandardDetailPage(...)` bindet intern `initDetailActionPolicy(...)` aus `web/js/core/app-details-action-policy.js`.
|
|
|
|
|
|
- Aktivierung pro Seite über `data-detail-action-policy="1"` auf `.app-details-titlebar` (Default im Shared-Partial aktiv).
|
|
|
|
|
|
- Confirm nicht mehr inline per `onclick/onsubmit`, sondern über `data-detail-confirm-message`.
|
|
|
|
|
|
- Aktionssemantik über `data-detail-action-kind` (z. B. `save`, `save-close`, `delete`, `danger`).
|
|
|
|
|
|
- Optionaler Lock-Override über `data-detail-submit-lock="none"` (Default: `form`).
|
|
|
|
|
|
|
2026-04-24 21:26:11 +02:00
|
|
|
|
### Copy-to-Clipboard Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für kopierbare Inhalte (Werte, Feld-Inhalte, Badges) gilt eine einzige
|
|
|
|
|
|
Component: `web/js/components/app-copy-field.js` — ein Button mit
|
|
|
|
|
|
`data-copy-button` bekommt automatisch einen Click-Handler, der in die
|
|
|
|
|
|
Zwischenablage schreibt und 1,2 s lang ein Check-Icon statt des Copy-Icons
|
|
|
|
|
|
anzeigt (Klasse `is-copied` wird am Button getoggelt).
|
|
|
|
|
|
|
|
|
|
|
|
Zwei Quell-Modi:
|
|
|
|
|
|
|
|
|
|
|
|
- **Statischer Wert** (fix im Markup):
|
|
|
|
|
|
```html
|
|
|
|
|
|
<button type="button" data-copy-button data-copy-value="max@acme.com"
|
|
|
|
|
|
aria-label="Copy email">
|
|
|
|
|
|
<i class="bi bi-copy" data-copy-icon-idle></i>
|
|
|
|
|
|
<i class="bi bi-check-lg" data-copy-icon-done></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **Live Input-Wert** (liest `input.value` beim Klick):
|
|
|
|
|
|
```html
|
|
|
|
|
|
<input id="privacy_url" …>
|
|
|
|
|
|
<button type="button" data-copy-button data-copy-target="privacy_url" …>…</button>
|
|
|
|
|
|
```
|
|
|
|
|
|
Der Live-Modus ist vorzuziehen, wenn der User das Feld editieren kann —
|
|
|
|
|
|
der Button kopiert dann immer den aktuellen Wert, nicht den beim ersten
|
|
|
|
|
|
Render gesetzten.
|
|
|
|
|
|
|
|
|
|
|
|
### Copyable Input Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für Text-Inputs, bei denen ein Copy-Button *im* Feld sitzen soll (z. B. URLs,
|
|
|
|
|
|
IDs, Tokens) existiert die Core-Partial **`templates/partials/app-input-copy.phtml`**.
|
|
|
|
|
|
|
|
|
|
|
|
Verwendung im Form:
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$name = 'privacy_url';
|
|
|
|
|
|
$label = t('Privacy URL');
|
|
|
|
|
|
$type = 'url';
|
|
|
|
|
|
$value = (string) ($values['privacy_url'] ?? '');
|
|
|
|
|
|
$readonly = $isReadOnly;
|
|
|
|
|
|
require templatePath('partials/app-input-copy.phtml');
|
|
|
|
|
|
?>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Optionale Vars: `$id` (Default = `$name`), `$placeholder`, `$required`,
|
|
|
|
|
|
`$disabled`. Die Partial rendert:
|
|
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
|
<label for="privacy_url">
|
|
|
|
|
|
<span>Privacy URL</span>
|
|
|
|
|
|
<div class="app-input-copy">
|
|
|
|
|
|
<input type="url" name="privacy_url" id="privacy_url" value="…">
|
|
|
|
|
|
<button class="app-input-copy-button" data-copy-button
|
|
|
|
|
|
data-copy-target="privacy_url" …>
|
|
|
|
|
|
<i class="bi bi-clipboard" data-copy-icon-idle></i>
|
|
|
|
|
|
<i class="bi bi-check-lg" data-copy-icon-done></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
CSS-Kontrakt (`web/css/components/app-input-copy.css`):
|
|
|
|
|
|
|
|
|
|
|
|
- `.app-input-copy` — Positioning-Wrapper, `position: relative`
|
|
|
|
|
|
- `.app-input-copy > input` — Native Form-Styling, `padding-right: 2.5rem`
|
|
|
|
|
|
für den Overlay-Button
|
|
|
|
|
|
- `.app-input-copy > .app-input-copy-button` — absolute positioniert rechts,
|
|
|
|
|
|
vertikal zentriert via `inset 0/auto + margin-block: auto`. Spezifität
|
|
|
|
|
|
`(0,2,0)` beim Descendant-Selector nötig, damit die globale
|
|
|
|
|
|
`[data-tooltip] { position: relative }`-Regel nicht gewinnt.
|
|
|
|
|
|
- `.is-copied` (wird vom Copy-Field-Component gesetzt) — tauscht Copy-Icon
|
|
|
|
|
|
gegen Check, färbt Button in `--app-action-success-border`.
|
|
|
|
|
|
|
|
|
|
|
|
Nicht selbst die Markup-Struktur nachbauen — immer die Partial verwenden,
|
|
|
|
|
|
damit Spacing, Vertical-Centering und A11y (`aria-label`, Tooltip) konsistent
|
|
|
|
|
|
bleiben.
|
|
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
### Global Confirm Actions
|
|
|
|
|
|
|
|
|
|
|
|
Für allgemeine Form-/Button-Confirms außerhalb der Detail-Policy gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- zentral über `web/js/components/app-confirm-actions.js`
|
2026-03-06 00:44:52 +01:00
|
|
|
|
- Dialog-Engine zentral über `web/js/core/app-confirm-dialog.js` (`confirmDialog.confirm(...)`)
|
|
|
|
|
|
- Confirm-Text über `data-confirm-message` bzw. auf Detail-Aktionen `data-detail-confirm-message`
|
|
|
|
|
|
- optionale Dialog-Meta über
|
|
|
|
|
|
- `data-confirm-title`, `data-confirm-confirm-label`, `data-confirm-cancel-label`, `data-confirm-variant`, `data-confirm-focus`
|
|
|
|
|
|
- analog für Detail-Aktionen: `data-detail-confirm-*`
|
|
|
|
|
|
- kein direktes `window.confirm(...)` in App-JS
|
2026-03-04 15:56:58 +01:00
|
|
|
|
- keine inline `onclick="return confirm(...)"` / `onsubmit="return confirm(...)"` verwenden
|
|
|
|
|
|
|
2026-03-06 00:44:52 +01:00
|
|
|
|
### Frontend Telemetry Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für UX-/Fehler-Telemetrie im Frontend gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- zentral über `web/js/core/app-telemetry.js` (`telemetry.capture(...)`)
|
|
|
|
|
|
- `warnOnce(...)` sendet standardisiert `frontend.warn_once`
|
|
|
|
|
|
- AJAX-/Fetch-Fehler laufen zentral über den globalen Fetch-Hook als `frontend.ajax_error`
|
|
|
|
|
|
- keine neuen Console-only-Warnpfade für relevante UX-Probleme ohne Telemetrie
|
|
|
|
|
|
- Payloads nur mit Whitelist-Feldern und ohne sensitive Rohdaten (keine Tokens/Query-Parameter/Stacktraces)
|
|
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
### Detail Validation Summary Standard
|
|
|
|
|
|
|
|
|
|
|
|
Für serverseitige Formularfehler in Create/Edit-Templates gilt:
|
|
|
|
|
|
|
|
|
|
|
|
- Fehlerausgabe über `templates/partials/app-details-validation-summary.phtml`.
|
|
|
|
|
|
- Keine inline `<div class="notice" data-variant="error">`-Blöcke mit `foreach ($errors as $error)` mehr.
|
|
|
|
|
|
- Standardtitel kommt aus `t('Please review the following errors')`.
|
|
|
|
|
|
- In Action-Handlern strukturierte Feld-Errors als `$validationSummaryErrors = $errorBag->toArray();` bereitstellen.
|
|
|
|
|
|
|
|
|
|
|
|
Template-Beispiel:
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$validationSummaryErrors = $validationSummaryErrors ?? ($errors ?? []);
|
|
|
|
|
|
require templatePath('partials/app-details-validation-summary.phtml');
|
|
|
|
|
|
?>
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-04 15:56:58 +01:00
|
|
|
|
Optional strukturierte Einträge:
|
|
|
|
|
|
|
|
|
|
|
|
- `['message' => '...', 'fieldName' => 'email']`
|
|
|
|
|
|
- `['message' => '...', 'fieldId' => 'email']`
|
|
|
|
|
|
- `['email' => ['Required']]` (FormErrors-ähnliche Map)
|
|
|
|
|
|
|
|
|
|
|
|
JS-Verhalten über `initStandardDetailPage(...)`:
|
|
|
|
|
|
|
|
|
|
|
|
- Klick auf Validation-Link fokussiert das passende Feld.
|
|
|
|
|
|
- Bei vorhandener Summary wird initial das erste betroffene Feld (oder Summary) fokussiert.
|
|
|
|
|
|
- Betroffene Felder werden zentral mit `aria-invalid="true"` und `aria-describedby` (Summary-ID) markiert.
|
|
|
|
|
|
|
|
|
|
|
|
## Laufzeit-Check (ohne Node)
|
|
|
|
|
|
|
|
|
|
|
|
Prüfen im Browser:
|
|
|
|
|
|
|
|
|
|
|
|
1. DevTools öffnen (Console, optional Preserve log aktivieren).
|
|
|
|
|
|
2. Kernseiten laden (`/admin/users`, `/address-book`, Audit-Listen).
|
2026-03-05 11:17:42 +01:00
|
|
|
|
3. Filter setzen/zurücksetzen, Row-Action-Button + Enter + Doppelklick sowie Bulk-Aktionen testen.
|
2026-03-04 15:56:58 +01:00
|
|
|
|
4. Erwartung: keine JavaScript-Errors und keine Unhandled Promise Rejections.
|