adsdad
This commit is contained in:
@@ -105,8 +105,10 @@ Aus [README.md](/home/lars/Schreibtisch/Projekte/desktop.kusche.berlin/docs/READ
|
|||||||
- `partials/desktop/` enthaelt Shell-Templates
|
- `partials/desktop/` enthaelt Shell-Templates
|
||||||
- `custom/apps/` bleibt Zielort fuer installierbare Fach-Apps
|
- `custom/apps/` bleibt Zielort fuer installierbare Fach-Apps
|
||||||
- `system/apps/` bleibt Zielort fuer System-Tools
|
- `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
|
- `temp/nexus-module-import/` ist Rohbasis fuer importierte Nexus-Module
|
||||||
- Keycloak bleibt das Auth-System
|
- Keycloak bleibt das Auth-System
|
||||||
|
- das globale Desktop-Debug ist als Shell-Werkzeug unter `system/shell/desktop-debug/` definiert
|
||||||
|
|
||||||
### Module
|
### Module
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ Zentraler Dokumentationsindex fuer das Projekt.
|
|||||||
- `partials/desktop/` Shell-Template
|
- `partials/desktop/` Shell-Template
|
||||||
- `custom/apps/` Zielort fuer installierbare Fach-Apps
|
- `custom/apps/` Zielort fuer installierbare Fach-Apps
|
||||||
- `system/apps/` Zielort fuer nicht installierbare System-Tools
|
- `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
|
- `temp/nexus-module-import/` Rohbasis fuer importierte Nexus-Module
|
||||||
|
|
||||||
## Fachliche Hinweise
|
## 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/...`.
|
- 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.
|
- 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
|
- 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
|
## Dokumentationsregel
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Die Ordnerstruktur soll sich so nah wie sinnvoll an der bestehenden Nexus-Strukt
|
|||||||
- `/config/` -> Umgebungs-Configs
|
- `/config/` -> Umgebungs-Configs
|
||||||
- `/custom/apps/<app>/` -> installierbare Fach-Apps
|
- `/custom/apps/<app>/` -> installierbare Fach-Apps
|
||||||
- `/system/apps/<app>/` -> System-Tools und interne App-Quellen
|
- `/system/apps/<app>/` -> System-Tools und interne App-Quellen
|
||||||
|
- `/system/shell/<tool>/` -> globale Shell-Werkzeuge und shell-nahe Desktop-Helfer
|
||||||
- `/partials/structure/` -> globale Layout-Bausteine
|
- `/partials/structure/` -> globale Layout-Bausteine
|
||||||
- `/partials/landingpages/` -> Seiten oder Views
|
- `/partials/landingpages/` -> Seiten oder Views
|
||||||
- `/tools/` -> Worker, CLI, Hilfstools
|
- `/tools/` -> Worker, CLI, Hilfstools
|
||||||
@@ -54,6 +55,7 @@ Das bedeutet:
|
|||||||
- Module dürfen nicht ungeordnet in den Desktop-Core verschoben werden
|
- Module dürfen nicht ungeordnet in den Desktop-Core verschoben werden
|
||||||
- gemeinsame Desktop-Mechaniken liegen nicht in Modulen, sondern im globalen Kern
|
- gemeinsame Desktop-Mechaniken liegen nicht in Modulen, sondern im globalen Kern
|
||||||
- gemeinsame Debug-Grundlogik liegt ebenfalls nicht in Modulen, sondern im globalen Desktop-Core
|
- 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
|
## Trennung
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,11 @@ Verbindlich ist:
|
|||||||
|
|
||||||
- `custom/apps/<app>/` bleibt Ort fuer installierbare Fach-Apps
|
- `custom/apps/<app>/` bleibt Ort fuer installierbare Fach-Apps
|
||||||
- `system/apps/<app>/` bleibt Ort fuer System-Tools und nicht installierbare App-Quellen
|
- `system/apps/<app>/` bleibt Ort fuer System-Tools und nicht installierbare App-Quellen
|
||||||
|
- `system/shell/<tool>/` bleibt Ort fuer globale Shell-Werkzeuge und shell-nahe Desktop-Helfer
|
||||||
- globale Desktop-Mechaniken liegen im gemeinsamen Kern
|
- globale Desktop-Mechaniken liegen im gemeinsamen Kern
|
||||||
- globale Modul-Helfer duerfen im gemeinsamen Kern liegen, Fachlogik aber nicht
|
- 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
|
- 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/...`
|
- 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
|
- 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
|
- die Trennung `core` / `system_tool` / `module` ist in Metadaten, Startmenue und Benutzer-Setup konsistent zu halten
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ $activeSkin = $desktopPayload['meta']['active_skin'];
|
|||||||
$baseSkinProfile = $desktopPayload['meta']['base_skin_profile'];
|
$baseSkinProfile = $desktopPayload['meta']['base_skin_profile'];
|
||||||
$skinProfile = $desktopPayload['meta']['skin_profile'];
|
$skinProfile = $desktopPayload['meta']['skin_profile'];
|
||||||
$wallpaper = $desktopPayload['desktop']['wallpaper'];
|
$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 {
|
$assetVersion = static function (string $publicPath): string {
|
||||||
$filesystemPath = dirname(__DIR__, 2) . '/public' . $publicPath;
|
$filesystemPath = dirname(__DIR__, 2) . '/public' . $publicPath;
|
||||||
@@ -88,7 +90,7 @@ $renderStartIcon = static function (array $profile): string {
|
|||||||
</div>
|
</div>
|
||||||
<div class="system-bar-right">
|
<div class="system-bar-right">
|
||||||
<?php if (($desktopPayload['session']['is_admin'] ?? false) === true): ?>
|
<?php if (($desktopPayload['session']['is_admin'] ?? false) === true): ?>
|
||||||
<button class="tray-pill tray-pill-button tray-pill-debug" id="debug-toggle-top" type="button" aria-expanded="false">Debug</button>
|
<button class="tray-pill tray-pill-button tray-pill-debug" id="debug-toggle-top" type="button" aria-expanded="false"><?= htmlspecialchars($debugShellLabel, ENT_QUOTES) ?></button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<time id="clock-top"></time>
|
<time id="clock-top"></time>
|
||||||
</div>
|
</div>
|
||||||
@@ -166,7 +168,7 @@ $renderStartIcon = static function (array $profile): string {
|
|||||||
><?= htmlspecialchars($trayItem['label'], ENT_QUOTES) ?></button>
|
><?= htmlspecialchars($trayItem['label'], ENT_QUOTES) ?></button>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php if (($desktopPayload['session']['is_admin'] ?? false) === true): ?>
|
<?php if (($desktopPayload['session']['is_admin'] ?? false) === true): ?>
|
||||||
<button class="tray-pill tray-pill-button tray-pill-debug" id="debug-toggle" type="button" aria-expanded="false">Debug</button>
|
<button class="tray-pill tray-pill-button tray-pill-debug" id="debug-toggle" type="button" aria-expanded="false"><?= htmlspecialchars($debugShellLabel, ENT_QUOTES) ?></button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<time id="clock"></time>
|
<time id="clock"></time>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ if (payloadNode) {
|
|||||||
const activeSkin = payload.meta.active_skin;
|
const activeSkin = payload.meta.active_skin;
|
||||||
const skinProfile = payload.meta.skin_profile || {};
|
const skinProfile = payload.meta.skin_profile || {};
|
||||||
const settingsApi = payload.desktop.settings_api || '';
|
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 || {};
|
let currentUserPreferences = payload.desktop.user_preferences || {};
|
||||||
const maximizeOverSystemBar = Boolean(skinProfile.maximize_over_system_bar);
|
const maximizeOverSystemBar = Boolean(skinProfile.maximize_over_system_bar);
|
||||||
const storageScope = payload.desktop.storage_scope || 'guest';
|
const storageScope = payload.desktop.storage_scope || 'guest';
|
||||||
@@ -168,7 +175,9 @@ if (payloadNode) {
|
|||||||
|
|
||||||
node.setAttribute('aria-expanded', String(debugState.open === true));
|
node.setAttribute('aria-expanded', String(debugState.open === true));
|
||||||
node.classList.toggle('is-active', 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) => {
|
const buildWindowBody = (definition) => {
|
||||||
if (definition.content_mode === 'desktop-debug') {
|
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 `
|
return `
|
||||||
<div class="window-content window-content--desktop-debug">
|
<div class="window-content window-content--desktop-debug">
|
||||||
<div class="desktop-debug-window" data-debug-window="1">
|
<div class="desktop-debug-window" data-debug-window="1">
|
||||||
<div class="desktop-debug-toolbar">
|
<div class="desktop-debug-toolbar">
|
||||||
<p class="desktop-debug-copy">Live-Debug fuer Desktop und Native-Module. Tracking laeuft nur, solange dieses Fenster offen ist.</p>
|
<p class="desktop-debug-copy">${debugCopy}</p>
|
||||||
<div class="desktop-debug-actions">
|
<div class="desktop-debug-actions">
|
||||||
<button class="window-app-button desktop-debug-action" type="button" data-debug-action="clear">Log leeren</button>
|
<button class="window-app-button desktop-debug-action" type="button" data-debug-action="clear">${clearLabel}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="desktop-debug-log" data-debug-log></div>
|
<div class="desktop-debug-log" data-debug-log></div>
|
||||||
@@ -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 closeDebugWindow = () => {
|
||||||
const existing = findDebugWindow();
|
const existing = findDebugWindow();
|
||||||
@@ -1050,17 +1061,19 @@ if (payloadNode) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const windowDefaults = debugShellApp && typeof debugShellApp.window === 'object' ? debugShellApp.window : {};
|
||||||
createWindow({
|
createWindow({
|
||||||
window_id: `window-desktop-debug-${Date.now()}`,
|
window_id: `window-${debugShellAppId}-${Date.now()}`,
|
||||||
app_id: 'desktop-debug',
|
app_id: debugShellAppId,
|
||||||
title: 'Desktop Debug',
|
title: String(debugShellApp?.title || 'Desktop Debug'),
|
||||||
x: 120,
|
x: Number(windowDefaults.x ?? 120),
|
||||||
y: 88,
|
y: Number(windowDefaults.y ?? 88),
|
||||||
width: 720,
|
width: Number(windowDefaults.width ?? 720),
|
||||||
height: 520,
|
height: Number(windowDefaults.height ?? 520),
|
||||||
content: '',
|
content: String(debugShellApp?.content || ''),
|
||||||
entry_route: '',
|
entry_route: String(debugShellApp?.entry_route || ''),
|
||||||
content_mode: 'desktop-debug',
|
content_mode: String(debugShellApp?.content_mode || 'desktop-debug'),
|
||||||
|
ui: debugShellApp && typeof debugShellApp.ui === 'object' ? debugShellApp.ui : {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1153,7 +1166,7 @@ if (payloadNode) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record.definition.app_id === 'desktop-debug') {
|
if (record.definition.app_id === debugShellAppId) {
|
||||||
debugState.open = false;
|
debugState.open = false;
|
||||||
saveDebugState();
|
saveDebugState();
|
||||||
debugBus.setEnabled(false);
|
debugBus.setEnabled(false);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Desktop\AppRegistry;
|
|||||||
use Desktop\AppIconResolver;
|
use Desktop\AppIconResolver;
|
||||||
use Desktop\AppVisibility;
|
use Desktop\AppVisibility;
|
||||||
use Desktop\DesktopState;
|
use Desktop\DesktopState;
|
||||||
|
use Desktop\ShellAppRegistry;
|
||||||
use Desktop\SkinResolver;
|
use Desktop\SkinResolver;
|
||||||
use Desktop\WidgetRegistry;
|
use Desktop\WidgetRegistry;
|
||||||
use Desktop\WindowManager;
|
use Desktop\WindowManager;
|
||||||
@@ -30,6 +31,7 @@ final class App
|
|||||||
$moduleRegistry = new ModuleRegistry(AppPaths::customAppsRoot($this->projectRoot));
|
$moduleRegistry = new ModuleRegistry(AppPaths::customAppsRoot($this->projectRoot));
|
||||||
$registry = new AppRegistry($this->projectRoot . '/config/apps.php', $moduleRegistry->desktopApps());
|
$registry = new AppRegistry($this->projectRoot . '/config/apps.php', $moduleRegistry->desktopApps());
|
||||||
$widgetRegistry = new WidgetRegistry($this->projectRoot . '/config/widgets.php', $moduleRegistry->widgets());
|
$widgetRegistry = new WidgetRegistry($this->projectRoot . '/config/widgets.php', $moduleRegistry->widgets());
|
||||||
|
$shellRegistry = new ShellAppRegistry(AppPaths::systemShellRoot($this->projectRoot));
|
||||||
$skins = SkinResolver::all();
|
$skins = SkinResolver::all();
|
||||||
$isAuthenticated = isset($_SESSION['desktop_auth']) && is_array($_SESSION['desktop_auth']);
|
$isAuthenticated = isset($_SESSION['desktop_auth']) && is_array($_SESSION['desktop_auth']);
|
||||||
$authUser = $isAuthenticated && is_array($_SESSION['desktop_auth']['user'] ?? null)
|
$authUser = $isAuthenticated && is_array($_SESSION['desktop_auth']['user'] ?? null)
|
||||||
@@ -113,6 +115,10 @@ final class App
|
|||||||
'active_ids' => $activeWidgetIds,
|
'active_ids' => $activeWidgetIds,
|
||||||
],
|
],
|
||||||
'tray' => $trayItems,
|
'tray' => $trayItems,
|
||||||
|
'shell' => [
|
||||||
|
'apps' => $shellRegistry->all(),
|
||||||
|
'debug_app' => $shellRegistry->find('desktop-debug'),
|
||||||
|
],
|
||||||
'session' => [
|
'session' => [
|
||||||
'display_name' => $displayName,
|
'display_name' => $displayName,
|
||||||
'authenticated' => $isAuthenticated,
|
'authenticated' => $isAuthenticated,
|
||||||
|
|||||||
@@ -25,4 +25,14 @@ final class AppPaths
|
|||||||
{
|
{
|
||||||
return self::systemAppsRoot($projectRoot) . '/' . trim($appName, '/');
|
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, '/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
82
src/Desktop/ShellAppRegistry.php
Normal file
82
src/Desktop/ShellAppRegistry.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Desktop;
|
||||||
|
|
||||||
|
final class ShellAppRegistry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<int, array<string, mixed>>|null
|
||||||
|
*/
|
||||||
|
private ?array $apps = null;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly string $shellRoot,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, array<string, mixed>>
|
||||||
|
*/
|
||||||
|
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<string, mixed>|null
|
||||||
|
*/
|
||||||
|
public function find(string $appId): ?array
|
||||||
|
{
|
||||||
|
foreach ($this->all() as $app) {
|
||||||
|
if ((string) ($app['app_id'] ?? '') === $appId) {
|
||||||
|
return $app;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,3 +20,8 @@ Aktuelle Beispiele:
|
|||||||
- `user-management`
|
- `user-management`
|
||||||
- `user-self-management`
|
- `user-self-management`
|
||||||
- `cron-management`
|
- `cron-management`
|
||||||
|
|
||||||
|
Verwandte, aber getrennte Struktur:
|
||||||
|
|
||||||
|
- globale Shell-Werkzeuge und shell-nahe Desktop-Helfer liegen unter `system/shell/`
|
||||||
|
- Beispiel: `system/shell/desktop-debug/`
|
||||||
|
|||||||
24
system/shell/README.md
Normal file
24
system/shell/README.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# System Shell
|
||||||
|
|
||||||
|
Shell-nahe Werkzeuge und Shell-Skripte liegen in diesem Projekt unter `system/shell/<tool>/`.
|
||||||
|
|
||||||
|
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/`
|
||||||
21
system/shell/desktop-debug/definition.php
Normal file
21
system/shell/desktop-debug/definition.php
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'app_id' => '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',
|
||||||
|
],
|
||||||
|
];
|
||||||
Reference in New Issue
Block a user