From 487f592ca3aa290453879b3ff8424f932d38cb3c Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Thu, 25 Jun 2026 00:36:14 +0200 Subject: [PATCH] adsdad --- docs/CONTENT.md | 2 + docs/README.md | 2 + .../02_ORDNERSTRUKTUR_UND_GRUNDREGELN.md | 2 + docs/WEITERENTWICKLUNG.md | 2 + partials/desktop/shell.php | 6 +- public/assets/desktop/desktop.js | 43 ++++++---- src/App/App.php | 6 ++ src/App/AppPaths.php | 10 +++ src/Desktop/ShellAppRegistry.php | 82 +++++++++++++++++++ system/apps/README.md | 5 ++ system/shell/README.md | 24 ++++++ system/shell/desktop-debug/definition.php | 21 +++++ 12 files changed, 188 insertions(+), 17 deletions(-) create mode 100644 src/Desktop/ShellAppRegistry.php create mode 100644 system/shell/README.md create mode 100644 system/shell/desktop-debug/definition.php diff --git a/docs/CONTENT.md b/docs/CONTENT.md index 99050114..2d0179f3 100644 --- a/docs/CONTENT.md +++ b/docs/CONTENT.md @@ -105,8 +105,10 @@ Aus [README.md](/home/lars/Schreibtisch/Projekte/desktop.kusche.berlin/docs/READ - `partials/desktop/` enthaelt Shell-Templates - `custom/apps/` bleibt Zielort fuer installierbare Fach-Apps - `system/apps/` bleibt Zielort fuer System-Tools +- `system/shell/` bleibt Zielort fuer globale Shell-Werkzeuge und shell-nahe Desktop-Helfer - `temp/nexus-module-import/` ist Rohbasis fuer importierte Nexus-Module - Keycloak bleibt das Auth-System +- das globale Desktop-Debug ist als Shell-Werkzeug unter `system/shell/desktop-debug/` definiert ### Module diff --git a/docs/README.md b/docs/README.md index 299e17f5..62dc0171 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,6 +27,7 @@ Zentraler Dokumentationsindex fuer das Projekt. - `partials/desktop/` Shell-Template - `custom/apps/` Zielort fuer installierbare Fach-Apps - `system/apps/` Zielort fuer nicht installierbare System-Tools +- `system/shell/` Zielort fuer globale Shell-Werkzeuge und shell-nahe Desktop-Helfer - `temp/nexus-module-import/` Rohbasis fuer importierte Nexus-Module ## Fachliche Hinweise @@ -37,6 +38,7 @@ Zentraler Dokumentationsindex fuer das Projekt. - API und Desktop laufen auf demselben Host. Zielpfad ist `(staging.)desktop.kusche.berlin/api/v1/...`. - der Theme-Handoff ist in [keycloak-theme-handoff.md](/home/lars/Schreibtisch/Projekte/desktop.kusche.berlin/docs/keycloak-theme-handoff.md) beschrieben. - das globale Admin-Debugging ist Teil der Desktop-Shell und wird nicht pro App als eigene Grundfunktion dupliziert +- die Definition globaler Shell-Werkzeuge liegt unter `system/shell/`; aktuelles Beispiel ist `system/shell/desktop-debug/` ## Dokumentationsregel diff --git a/docs/Umsetzungsanweisung/02_ORDNERSTRUKTUR_UND_GRUNDREGELN.md b/docs/Umsetzungsanweisung/02_ORDNERSTRUKTUR_UND_GRUNDREGELN.md index 57e1d5bd..79d6cafc 100644 --- a/docs/Umsetzungsanweisung/02_ORDNERSTRUKTUR_UND_GRUNDREGELN.md +++ b/docs/Umsetzungsanweisung/02_ORDNERSTRUKTUR_UND_GRUNDREGELN.md @@ -12,6 +12,7 @@ Die Ordnerstruktur soll sich so nah wie sinnvoll an der bestehenden Nexus-Strukt - `/config/` -> Umgebungs-Configs - `/custom/apps//` -> installierbare Fach-Apps - `/system/apps//` -> System-Tools und interne App-Quellen +- `/system/shell//` -> globale Shell-Werkzeuge und shell-nahe Desktop-Helfer - `/partials/structure/` -> globale Layout-Bausteine - `/partials/landingpages/` -> Seiten oder Views - `/tools/` -> Worker, CLI, Hilfstools @@ -54,6 +55,7 @@ Das bedeutet: - Module dürfen nicht ungeordnet in den Desktop-Core verschoben werden - gemeinsame Desktop-Mechaniken liegen nicht in Modulen, sondern im globalen Kern - gemeinsame Debug-Grundlogik liegt ebenfalls nicht in Modulen, sondern im globalen Desktop-Core +- globale Shell-Werkzeuge sollen als eigene Einheiten unter `/system/shell/` abgelegt werden ## Trennung diff --git a/docs/WEITERENTWICKLUNG.md b/docs/WEITERENTWICKLUNG.md index d0df8839..180a19e7 100644 --- a/docs/WEITERENTWICKLUNG.md +++ b/docs/WEITERENTWICKLUNG.md @@ -58,9 +58,11 @@ Verbindlich ist: - `custom/apps//` bleibt Ort fuer installierbare Fach-Apps - `system/apps//` bleibt Ort fuer System-Tools und nicht installierbare App-Quellen +- `system/shell//` bleibt Ort fuer globale Shell-Werkzeuge und shell-nahe Desktop-Helfer - globale Desktop-Mechaniken liegen im gemeinsamen Kern - globale Modul-Helfer duerfen im gemeinsamen Kern liegen, Fachlogik aber nicht - globale Debug-Steuerung fuer Admins liegt im Desktop-Core; Aktivierung erfolgt ueber das gemeinsame Debug-Widget neben der Uhr +- die Definition globaler Debug- und Shell-Werkzeuge soll in `system/shell/` liegen und nicht lose in `public/` oder verstreut im JS - API und Desktop teilen sich im aktuellen Zielbild denselben Host; offizielle Basis ist `/api/v1/...` - App, API und Widget einer Fachfunktion muessen dieselben Sperr- und Force-Regeln fuer externe Abrufe nutzen - die Trennung `core` / `system_tool` / `module` ist in Metadaten, Startmenue und Benutzer-Setup konsistent zu halten diff --git a/partials/desktop/shell.php b/partials/desktop/shell.php index 2807671a..3992be1b 100644 --- a/partials/desktop/shell.php +++ b/partials/desktop/shell.php @@ -7,6 +7,8 @@ $activeSkin = $desktopPayload['meta']['active_skin']; $baseSkinProfile = $desktopPayload['meta']['base_skin_profile']; $skinProfile = $desktopPayload['meta']['skin_profile']; $wallpaper = $desktopPayload['desktop']['wallpaper']; +$debugShellApp = is_array($desktopPayload['shell']['debug_app'] ?? null) ? $desktopPayload['shell']['debug_app'] : null; +$debugShellLabel = trim((string) ($debugShellApp['label'] ?? 'Debug')) ?: 'Debug'; $assetVersion = static function (string $publicPath): string { $filesystemPath = dirname(__DIR__, 2) . '/public' . $publicPath; @@ -88,7 +90,7 @@ $renderStartIcon = static function (array $profile): string {
- +
@@ -166,7 +168,7 @@ $renderStartIcon = static function (array $profile): string { > - + diff --git a/public/assets/desktop/desktop.js b/public/assets/desktop/desktop.js index 0a105762..12dbf2ac 100644 --- a/public/assets/desktop/desktop.js +++ b/public/assets/desktop/desktop.js @@ -49,6 +49,13 @@ if (payloadNode) { const activeSkin = payload.meta.active_skin; const skinProfile = payload.meta.skin_profile || {}; const settingsApi = payload.desktop.settings_api || ''; + const shellApps = Array.isArray(payload.shell?.apps) ? payload.shell.apps : []; + const debugShellApp = (payload.shell && typeof payload.shell.debug_app === 'object' && payload.shell.debug_app) + || shellApps.find((app) => app && app.app_id === 'desktop-debug') + || null; + const debugShellAppId = typeof debugShellApp?.app_id === 'string' && debugShellApp.app_id !== '' + ? debugShellApp.app_id + : 'desktop-debug'; let currentUserPreferences = payload.desktop.user_preferences || {}; const maximizeOverSystemBar = Boolean(skinProfile.maximize_over_system_bar); const storageScope = payload.desktop.storage_scope || 'guest'; @@ -168,7 +175,9 @@ if (payloadNode) { node.setAttribute('aria-expanded', String(debugState.open === true)); node.classList.toggle('is-active', debugState.open === true); - node.textContent = debugState.open === true ? 'Debug an' : 'Debug'; + node.textContent = debugState.open === true + ? `${String(debugShellApp?.label || 'Debug')} an` + : String(debugShellApp?.label || 'Debug'); }); }; @@ -571,13 +580,15 @@ if (payloadNode) { const buildWindowBody = (definition) => { if (definition.content_mode === 'desktop-debug') { + const debugCopy = escapeHtml(definition.ui?.copy || 'Live-Debug fuer Desktop und Native-Module. Tracking laeuft nur, solange dieses Fenster offen ist.'); + const clearLabel = escapeHtml(definition.ui?.clear_label || 'Log leeren'); return `
-

Live-Debug fuer Desktop und Native-Module. Tracking laeuft nur, solange dieses Fenster offen ist.

+

${debugCopy}

- +
@@ -1020,7 +1031,7 @@ if (payloadNode) { } }; - const findDebugWindow = () => Array.from(windows.values()).find((record) => record.definition.app_id === 'desktop-debug') || null; + const findDebugWindow = () => Array.from(windows.values()).find((record) => record.definition.app_id === debugShellAppId) || null; const closeDebugWindow = () => { const existing = findDebugWindow(); @@ -1050,17 +1061,19 @@ if (payloadNode) { return; } + const windowDefaults = debugShellApp && typeof debugShellApp.window === 'object' ? debugShellApp.window : {}; createWindow({ - window_id: `window-desktop-debug-${Date.now()}`, - app_id: 'desktop-debug', - title: 'Desktop Debug', - x: 120, - y: 88, - width: 720, - height: 520, - content: '', - entry_route: '', - content_mode: 'desktop-debug', + window_id: `window-${debugShellAppId}-${Date.now()}`, + app_id: debugShellAppId, + title: String(debugShellApp?.title || 'Desktop Debug'), + x: Number(windowDefaults.x ?? 120), + y: Number(windowDefaults.y ?? 88), + width: Number(windowDefaults.width ?? 720), + height: Number(windowDefaults.height ?? 520), + content: String(debugShellApp?.content || ''), + entry_route: String(debugShellApp?.entry_route || ''), + content_mode: String(debugShellApp?.content_mode || 'desktop-debug'), + ui: debugShellApp && typeof debugShellApp.ui === 'object' ? debugShellApp.ui : {}, }); }; @@ -1153,7 +1166,7 @@ if (payloadNode) { return; } - if (record.definition.app_id === 'desktop-debug') { + if (record.definition.app_id === debugShellAppId) { debugState.open = false; saveDebugState(); debugBus.setEnabled(false); diff --git a/src/App/App.php b/src/App/App.php index 6b748173..c9af9602 100644 --- a/src/App/App.php +++ b/src/App/App.php @@ -8,6 +8,7 @@ use Desktop\AppRegistry; use Desktop\AppIconResolver; use Desktop\AppVisibility; use Desktop\DesktopState; +use Desktop\ShellAppRegistry; use Desktop\SkinResolver; use Desktop\WidgetRegistry; use Desktop\WindowManager; @@ -30,6 +31,7 @@ final class App $moduleRegistry = new ModuleRegistry(AppPaths::customAppsRoot($this->projectRoot)); $registry = new AppRegistry($this->projectRoot . '/config/apps.php', $moduleRegistry->desktopApps()); $widgetRegistry = new WidgetRegistry($this->projectRoot . '/config/widgets.php', $moduleRegistry->widgets()); + $shellRegistry = new ShellAppRegistry(AppPaths::systemShellRoot($this->projectRoot)); $skins = SkinResolver::all(); $isAuthenticated = isset($_SESSION['desktop_auth']) && is_array($_SESSION['desktop_auth']); $authUser = $isAuthenticated && is_array($_SESSION['desktop_auth']['user'] ?? null) @@ -113,6 +115,10 @@ final class App 'active_ids' => $activeWidgetIds, ], 'tray' => $trayItems, + 'shell' => [ + 'apps' => $shellRegistry->all(), + 'debug_app' => $shellRegistry->find('desktop-debug'), + ], 'session' => [ 'display_name' => $displayName, 'authenticated' => $isAuthenticated, diff --git a/src/App/AppPaths.php b/src/App/AppPaths.php index 5cd4d4c6..54b4880e 100644 --- a/src/App/AppPaths.php +++ b/src/App/AppPaths.php @@ -25,4 +25,14 @@ final class AppPaths { return self::systemAppsRoot($projectRoot) . '/' . trim($appName, '/'); } + + public static function systemShellRoot(string $projectRoot): string + { + return rtrim($projectRoot, '/') . '/system/shell'; + } + + public static function systemShellPath(string $projectRoot, string $shellName): string + { + return self::systemShellRoot($projectRoot) . '/' . trim($shellName, '/'); + } } diff --git a/src/Desktop/ShellAppRegistry.php b/src/Desktop/ShellAppRegistry.php new file mode 100644 index 00000000..f22cd2a9 --- /dev/null +++ b/src/Desktop/ShellAppRegistry.php @@ -0,0 +1,82 @@ +>|null + */ + private ?array $apps = null; + + public function __construct( + private readonly string $shellRoot, + ) { + } + + /** + * @return array> + */ + public function all(): array + { + if ($this->apps !== null) { + return $this->apps; + } + + if (!is_dir($this->shellRoot)) { + return $this->apps = []; + } + + $apps = []; + foreach (glob($this->shellRoot . '/*/definition.php') ?: [] as $definitionPath) { + $app = require $definitionPath; + + if (!is_array($app)) { + continue; + } + + $appId = trim((string) ($app['app_id'] ?? '')); + if ($appId === '') { + continue; + } + + $apps[] = [ + 'app_id' => $appId, + 'title' => (string) ($app['title'] ?? $appId), + 'label' => (string) ($app['label'] ?? $appId), + 'content_mode' => (string) ($app['content_mode'] ?? 'shell'), + 'admin_only' => (bool) ($app['admin_only'] ?? false), + 'entry_route' => (string) ($app['entry_route'] ?? ''), + 'content' => (string) ($app['content'] ?? ''), + 'window' => is_array($app['window'] ?? null) ? $app['window'] : [], + 'ui' => is_array($app['ui'] ?? null) ? $app['ui'] : [], + ]; + } + + usort( + $apps, + static fn (array $left, array $right): int => strcmp( + (string) ($left['title'] ?? $left['app_id'] ?? ''), + (string) ($right['title'] ?? $right['app_id'] ?? '') + ) + ); + + return $this->apps = array_values($apps); + } + + /** + * @return array|null + */ + public function find(string $appId): ?array + { + foreach ($this->all() as $app) { + if ((string) ($app['app_id'] ?? '') === $appId) { + return $app; + } + } + + return null; + } +} diff --git a/system/apps/README.md b/system/apps/README.md index b10ab977..a595b6c1 100644 --- a/system/apps/README.md +++ b/system/apps/README.md @@ -20,3 +20,8 @@ Aktuelle Beispiele: - `user-management` - `user-self-management` - `cron-management` + +Verwandte, aber getrennte Struktur: + +- globale Shell-Werkzeuge und shell-nahe Desktop-Helfer liegen unter `system/shell/` +- Beispiel: `system/shell/desktop-debug/` diff --git a/system/shell/README.md b/system/shell/README.md new file mode 100644 index 00000000..8b4a5c55 --- /dev/null +++ b/system/shell/README.md @@ -0,0 +1,24 @@ +# System Shell + +Shell-nahe Werkzeuge und Shell-Skripte liegen in diesem Projekt unter `system/shell//`. + +Ziel der Struktur: + +- globale Desktop-Werkzeuge klar von `system/apps/` und `custom/apps/` trennen +- Shell-spezifische Helfer als eigenstaendige Einheiten sichtbar machen +- Metadaten fuer den Desktop zentral ueber `definition.php` ablegen + +Typische Bestandteile eines Shell-Tools: + +- `definition.php` fuer Titel, Kennung, Content-Mode und Fenster-Defaults +- optionale Zusatzdateien wie `README.md`, Shell-Skripte oder Hilfsdateien + +Aktuelles Beispiel: + +- `desktop-debug` + +Regel: + +- `system/shell/` ist fuer globale Shell-Werkzeuge reserviert +- installierbare Fach-Apps bleiben unter `custom/apps/` +- nicht installierbare Oberflaechen-Apps bleiben unter `system/apps/` diff --git a/system/shell/desktop-debug/definition.php b/system/shell/desktop-debug/definition.php new file mode 100644 index 00000000..bad7907d --- /dev/null +++ b/system/shell/desktop-debug/definition.php @@ -0,0 +1,21 @@ + 'desktop-debug', + 'title' => 'Desktop Debug', + 'label' => 'Debug', + 'content_mode' => 'desktop-debug', + 'admin_only' => true, + 'window' => [ + 'x' => 120, + 'y' => 88, + 'width' => 720, + 'height' => 520, + ], + 'ui' => [ + 'copy' => 'Live-Debug fuer Desktop und Native-Module. Tracking laeuft nur, solange dieses Fenster offen ist.', + 'clear_label' => 'Log leeren', + ], +];