adasdadad
This commit is contained in:
@@ -195,6 +195,37 @@
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-access-card {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-access-groups {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-group-item {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-group-item input {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-group-main strong {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#admin-apps-app .aa-message {
|
||||
padding: 14px 16px;
|
||||
border-radius: 14px;
|
||||
|
||||
@@ -53,7 +53,7 @@ $service = new AdminAppsService($projectRoot);
|
||||
$messages = [];
|
||||
$errors = [];
|
||||
$section = trim((string) ($_GET['section'] ?? $_POST['active_section'] ?? 'overview'));
|
||||
$allowedSections = ['overview', 'widgets', 'integrations'];
|
||||
$allowedSections = ['overview', 'installation', 'access', 'widgets', 'integrations'];
|
||||
if (!in_array($section, $allowedSections, true)) {
|
||||
$section = 'overview';
|
||||
}
|
||||
@@ -78,6 +78,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
]);
|
||||
$messages[] = 'Gitea-Deploy-Status-Konfiguration gespeichert.';
|
||||
$section = 'integrations';
|
||||
} elseif ($action === 'save-app-access') {
|
||||
$service->saveAppAccess(
|
||||
(string) ($_POST['app_id'] ?? ''),
|
||||
array_values(array_map('strval', (array) ($_POST['required_groups'] ?? [])))
|
||||
);
|
||||
$messages[] = 'LDAP-Gruppen fuer die App wurden gespeichert.';
|
||||
$section = 'access';
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$errors[] = $exception->getMessage();
|
||||
@@ -90,6 +97,7 @@ $apps = is_array($bootstrap['apps'] ?? null) ? $bootstrap['apps'] : [];
|
||||
$widgets = is_array($bootstrap['widgets'] ?? null) ? $bootstrap['widgets'] : [];
|
||||
$stats = is_array($bootstrap['stats'] ?? null) ? $bootstrap['stats'] : [];
|
||||
$meta = is_array($bootstrap['meta'] ?? null) ? $bootstrap['meta'] : [];
|
||||
$availableGroups = is_array($meta['available_groups'] ?? null) ? $meta['available_groups'] : [];
|
||||
$gitea = is_array($bootstrap['gitea'] ?? null) ? $bootstrap['gitea'] : [];
|
||||
$giteaConfig = is_array($gitea['config'] ?? null) ? $gitea['config'] : [];
|
||||
$giteaDiagnostics = is_array($gitea['diagnostics'] ?? null) ? $gitea['diagnostics'] : [];
|
||||
@@ -99,15 +107,27 @@ $sectionUrl = static fn (string $targetSection): string => '/admin/apps/?section
|
||||
$sectionMeta = [
|
||||
'overview' => [
|
||||
'label' => 'Apps',
|
||||
'title' => 'App-Bestand und Scope',
|
||||
'description' => 'Installierbare Fach-Apps, Systemtools und Core-Eintraege der Desktop-Shell im aktuellen Registry-Stand.',
|
||||
'nav' => 'Registry und Freigaben pruefen.',
|
||||
'title' => 'Apps und Bereitstellung',
|
||||
'description' => 'Apps sind allgemeine Anwendungen. Sie koennen als Menue-App, Tray-App, Widget-Quelle oder mit optionalem Desktop-Icon auftreten.',
|
||||
'nav' => 'Bestand und Installationsweg pruefen.',
|
||||
],
|
||||
'installation' => [
|
||||
'label' => 'Installation',
|
||||
'title' => 'Installationswege fuer Apps',
|
||||
'description' => 'Installierbare Fach-Apps liegen unter custom/apps/. Upload- und Importwege werden hier als naechster Ausbauschritt vorbereitet.',
|
||||
'nav' => 'ZIP-, Verzeichnis- und Server-Workflow beschreiben.',
|
||||
],
|
||||
'access' => [
|
||||
'label' => 'Berechtigungen',
|
||||
'title' => 'LDAP-Gruppen pro App',
|
||||
'description' => 'Admins steuern hier, welche LDAP-Gruppen eine App benutzen duerfen. Leere Auswahl bedeutet: fuer alle sichtbaren Benutzer.',
|
||||
'nav' => 'LDAP-Gruppen verwalten.',
|
||||
],
|
||||
'widgets' => [
|
||||
'label' => 'Widgets',
|
||||
'title' => 'Widget-Bereich und Quellen',
|
||||
'description' => 'Widget-Inventar aus globaler Registry und Modul-Manifesten mit Quellen, Launch-App und Sichtbarkeit.',
|
||||
'nav' => 'Widget-Quellen und Startpunkte pruefen.',
|
||||
'title' => 'Widgets und Quellen',
|
||||
'description' => 'Widgets sind kleine Desktop-Bereiche ohne klassische Fensterfunktionen. Sie koennen eigenstaendig oder Teil einer App sein.',
|
||||
'nav' => 'Widget-Quellen und Bedeutung pruefen.',
|
||||
],
|
||||
'integrations' => [
|
||||
'label' => 'Integrationen',
|
||||
@@ -230,6 +250,7 @@ ob_start();
|
||||
<th>Titel</th>
|
||||
<th>Scope</th>
|
||||
<th>Typ</th>
|
||||
<th>LDAP-Gruppen</th>
|
||||
<th>Route</th>
|
||||
<th>Flags</th>
|
||||
</tr>
|
||||
@@ -243,6 +264,7 @@ ob_start();
|
||||
</td>
|
||||
<td><?= $h((string) ($app['app_scope'] ?? '')) ?></td>
|
||||
<td><?= $h(!empty($app['installable']) ? 'Custom App' : 'System') ?></td>
|
||||
<td><?= $h((string) ($app['required_groups_display'] ?? '')) ?></td>
|
||||
<td><code><?= $h((string) ($app['entry_route'] ?? '')) ?></code></td>
|
||||
<td>
|
||||
<div class="aa-flag-list">
|
||||
@@ -259,6 +281,108 @@ ob_start();
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="window-app-card aa-card">
|
||||
<div class="aa-section-head">
|
||||
<div>
|
||||
<p class="window-app-kicker aa-kicker">Installation</p>
|
||||
<h3 class="aa-section-title">Aktueller Installationsweg</h3>
|
||||
<p class="aa-copy">Neue Apps koennen aktuell als Modul-Verzeichnis unter <code>custom/apps/</code> abgelegt werden. Ein eigener Upload-Bereich fuer ZIP-Dateien oder Verzeichnisse ist noch offen und wird als naechster Ausbauschritt vorbereitet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($section === 'installation'): ?>
|
||||
<section class="aa-grid aa-grid--stats">
|
||||
<article class="window-app-card aa-card aa-stat-card">
|
||||
<span>Installierbare Apps</span>
|
||||
<strong><?= (int) ($stats['installable_apps'] ?? 0) ?></strong>
|
||||
</article>
|
||||
<article class="window-app-card aa-card aa-stat-card">
|
||||
<span>Systemtools</span>
|
||||
<strong><?= (int) ($stats['system_tools'] ?? 0) ?></strong>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="window-app-card aa-card">
|
||||
<div class="aa-section-head">
|
||||
<div>
|
||||
<p class="window-app-kicker aa-kicker">Installationswege</p>
|
||||
<h3 class="aa-section-title">Aktueller und geplanter Ablauf</h3>
|
||||
<p class="aa-copy">Installierbare Apps liegen im Projekt unter <code>custom/apps/</code>. Der Desktop erkennt neue Module automatisch ueber deren Desktop-Metadaten.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aa-grid">
|
||||
<article class="window-app-card aa-card aa-inline-card">
|
||||
<strong>1. Manuell ueber den Server</strong>
|
||||
<p>Ein Modul-Verzeichnis wird nach <code>custom/apps/<app>/</code> kopiert. Das ist der aktuell gueltige produktive Weg.</p>
|
||||
</article>
|
||||
<article class="window-app-card aa-card aa-inline-card">
|
||||
<strong>2. Verzeichnis-Upload</strong>
|
||||
<p>Ein Browser-Upload fuer ein vorbereitetes Modul-Verzeichnis ist fachlich vorgesehen, aber noch nicht implementiert.</p>
|
||||
</article>
|
||||
<article class="window-app-card aa-card aa-inline-card">
|
||||
<strong>3. ZIP-Upload</strong>
|
||||
<p>Ein ZIP-Import mit Entpacken und Validierung ist vorgesehen, benoetigt aber noch einen dedizierten Installations-Workflow.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($section === 'access'): ?>
|
||||
<section class="window-app-card aa-card">
|
||||
<div class="aa-section-head">
|
||||
<div>
|
||||
<p class="window-app-kicker aa-kicker">Access Control</p>
|
||||
<h3 class="aa-section-title">LDAP-Gruppen pro App</h3>
|
||||
<p class="aa-copy">Gespeichert wird in <?= $h((string) ($meta['app_access_config_path'] ?? '')) ?>. Die kurzen Gruppennamen entsprechen den LDAP-/Auth-Gruppen im Desktop.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aa-grid">
|
||||
<?php foreach ($apps as $app): ?>
|
||||
<form class="window-app-card aa-card aa-access-card" method="post" action="/admin/apps/">
|
||||
<input type="hidden" name="csrf_token" value="<?= $h($csrfToken) ?>">
|
||||
<input type="hidden" name="action" value="save-app-access">
|
||||
<input type="hidden" name="active_section" value="access">
|
||||
<input type="hidden" name="app_id" value="<?= $h((string) ($app['app_id'] ?? '')) ?>">
|
||||
|
||||
<div>
|
||||
<strong><?= $h((string) ($app['title'] ?? '')) ?></strong>
|
||||
<p class="aa-table-copy"><?= $h((string) ($app['summary'] ?? '')) ?></p>
|
||||
<p class="aa-table-copy">Aktuell: <?= $h((string) ($app['required_groups_display'] ?? '')) ?></p>
|
||||
</div>
|
||||
|
||||
<div class="aa-access-groups">
|
||||
<?php if ($availableGroups === []): ?>
|
||||
<p class="aa-copy">Keine LDAP-Gruppen aus der Registration-Konfiguration gefunden.</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($availableGroups as $group): ?>
|
||||
<label class="window-app-item aa-group-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="required_groups[]"
|
||||
value="<?= $h((string) ($group['id'] ?? '')) ?>"
|
||||
<?= in_array((string) ($group['id'] ?? ''), array_values(array_map('strval', (array) ($app['required_groups'] ?? []))), true) ? 'checked' : '' ?>
|
||||
>
|
||||
<span class="window-app-item-main aa-group-main">
|
||||
<strong><?= $h((string) ($group['label'] ?? '')) ?></strong>
|
||||
<span class="aa-meta"><?= $h((string) ($group['id'] ?? '')) ?></span>
|
||||
</span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="aa-actions">
|
||||
<button class="window-app-button aa-primary" type="submit">Berechtigungen speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($section === 'widgets'): ?>
|
||||
@@ -267,7 +391,7 @@ ob_start();
|
||||
<div>
|
||||
<p class="window-app-kicker aa-kicker">Widget Registry</p>
|
||||
<h3 class="aa-section-title">Alle Widgets</h3>
|
||||
<p class="aa-copy">Globale Widgets und modulbasierte Widgets werden hier gemeinsam sichtbar. Modul-Widgets kommen bevorzugt aus `module.json`.</p>
|
||||
<p class="aa-copy">Globale Widgets und modulbasierte Widgets werden hier gemeinsam sichtbar. Fachlich sind Widgets kleine Desktop-Elemente; technisch werden sie aktuell noch uebergangsweise im rechten Infobereich gerendert.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
require_once dirname(__DIR__, 3) . '/src/App/bootstrap.php';
|
||||
|
||||
use App\AppPaths;
|
||||
use App\AppAccessConfig;
|
||||
use App\ConfigLoader;
|
||||
use App\KeycloakAuth;
|
||||
use App\LdapProvisioner;
|
||||
@@ -30,7 +31,11 @@ if ($method === 'OPTIONS') {
|
||||
$keycloakConfig = ConfigLoader::load($projectRoot, 'keycloak');
|
||||
$auth = new KeycloakAuth($keycloakConfig);
|
||||
$moduleRegistry = new ModuleRegistry(AppPaths::customAppsRoot($projectRoot));
|
||||
$registry = new AppRegistry($projectRoot . '/config/apps.php', $moduleRegistry->desktopApps());
|
||||
$registry = new AppRegistry(
|
||||
$projectRoot . '/config/apps.php',
|
||||
$moduleRegistry->desktopApps(),
|
||||
AppAccessConfig::load($projectRoot)
|
||||
);
|
||||
$widgetRegistry = new WidgetRegistry($projectRoot . '/config/widgets.php', $moduleRegistry->widgets());
|
||||
$service = new UserSelfManagementService($projectRoot);
|
||||
$registrationConfig = ConfigLoader::load($projectRoot, 'registration');
|
||||
@@ -103,9 +108,25 @@ function requiresReload(array $before, array $after): bool
|
||||
$afterSkin = (string) ($after['desktop']['active_skin'] ?? '');
|
||||
$beforeApps = array_values(array_map('strval', (array) ($before['apps']['enabled_ids'] ?? [])));
|
||||
$afterApps = array_values(array_map('strval', (array) ($after['apps']['enabled_ids'] ?? [])));
|
||||
$beforeDesktopIcons = array_values(array_map('strval', (array) ($before['apps']['desktop_icon_ids'] ?? [])));
|
||||
$afterDesktopIcons = array_values(array_map('strval', (array) ($after['apps']['desktop_icon_ids'] ?? [])));
|
||||
$beforeTray = array_values(array_map('strval', (array) ($before['tray']['active_ids'] ?? [])));
|
||||
$afterTray = array_values(array_map('strval', (array) ($after['tray']['active_ids'] ?? [])));
|
||||
$beforeWidgets = array_values(array_map('strval', (array) ($before['widgets']['active_ids'] ?? [])));
|
||||
$afterWidgets = array_values(array_map('strval', (array) ($after['widgets']['active_ids'] ?? [])));
|
||||
|
||||
sort($beforeApps);
|
||||
sort($afterApps);
|
||||
sort($beforeDesktopIcons);
|
||||
sort($afterDesktopIcons);
|
||||
sort($beforeTray);
|
||||
sort($afterTray);
|
||||
sort($beforeWidgets);
|
||||
sort($afterWidgets);
|
||||
|
||||
return $beforeSkin !== $afterSkin || $beforeApps !== $afterApps;
|
||||
return $beforeSkin !== $afterSkin
|
||||
|| $beforeApps !== $afterApps
|
||||
|| $beforeDesktopIcons !== $afterDesktopIcons
|
||||
|| $beforeTray !== $afterTray
|
||||
|| $beforeWidgets !== $afterWidgets;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,29 @@
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
#user-self-management-app .usm-item--app {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
#user-self-management-app .usm-item-toggle {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
#user-self-management-app .usm-inline-check {
|
||||
display: inline-flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
#user-self-management-app .usm-inline-check input {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#user-self-management-app .usm-item-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
const SECTIONS = [
|
||||
{ id: 'desktop', label: 'Desktop Type' },
|
||||
{ id: 'profile', label: 'Benutzerdaten' },
|
||||
{ id: 'apps', label: 'App-Installation' },
|
||||
{ id: 'widgets', label: 'Infobereich' },
|
||||
{ id: 'apps', label: 'Apps' },
|
||||
{ id: 'tray', label: 'Tray-Apps' },
|
||||
{ id: 'widgets', label: 'Widgets' },
|
||||
];
|
||||
|
||||
const escapeHtml = (value) => String(value)
|
||||
@@ -32,10 +33,14 @@
|
||||
}
|
||||
|
||||
if (sectionId === 'apps') {
|
||||
return 'Bestimmt, welche Desktop-Apps fuer diesen Benutzer sichtbar bleiben.';
|
||||
return 'Aktiviert Anwendungen fuer das Startmenue und optional als Desktop-Icon.';
|
||||
}
|
||||
|
||||
return 'Steuert, welche Elemente im rechten Infobereich des Desktops aktiv sind.';
|
||||
if (sectionId === 'tray') {
|
||||
return 'Steuert Schnellaktionen und Visualisierungen neben der Uhr, sofern Zugriff besteht.';
|
||||
}
|
||||
|
||||
return 'Kleine Desktop-Bereiche ohne Fensterfunktionen, die separat aktiviert werden koennen.';
|
||||
};
|
||||
|
||||
const renderSkinChoices = (state) => state.bootstrap.options.skins.map((skin) => {
|
||||
@@ -68,20 +73,52 @@
|
||||
|
||||
const renderAppItems = (state) => state.bootstrap.options.apps.map((app) => {
|
||||
const checked = state.draft.apps.enabled_ids.includes(app.app_id);
|
||||
const desktopIconChecked = state.draft.apps.desktop_icon_ids.includes(app.app_id);
|
||||
|
||||
return `
|
||||
<div class="window-app-item usm-item usm-item--app">
|
||||
<label class="usm-item-toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-app-id="${escapeHtml(app.app_id)}"
|
||||
${checked ? 'checked' : ''}
|
||||
${app.required ? 'disabled' : ''}
|
||||
>
|
||||
<span class="window-app-item-main usm-item-main">
|
||||
<strong>${escapeHtml(app.title)}</strong>
|
||||
<p>${escapeHtml(app.summary || '')}</p>
|
||||
<span class="usm-item-meta">${app.required ? 'Pflicht-App im Menue' : 'Im Menue sichtbar'}</span>
|
||||
</span>
|
||||
</label>
|
||||
${app.can_show_on_desktop ? `
|
||||
<label class="usm-inline-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-app-desktop-icon-id="${escapeHtml(app.app_id)}"
|
||||
${desktopIconChecked ? 'checked' : ''}
|
||||
${checked ? '' : 'disabled'}
|
||||
>
|
||||
<span>Desktop-Icon anzeigen</span>
|
||||
</label>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
const renderTrayItems = (state) => state.bootstrap.options.tray_apps.map((app) => {
|
||||
const checked = state.draft.tray.active_ids.includes(app.app_id);
|
||||
|
||||
return `
|
||||
<label class="window-app-item usm-item">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-action="toggle-app"
|
||||
data-app-id="${escapeHtml(app.app_id)}"
|
||||
data-tray-app-id="${escapeHtml(app.app_id)}"
|
||||
${checked ? 'checked' : ''}
|
||||
${app.required ? 'disabled' : ''}
|
||||
>
|
||||
<span class="window-app-item-main usm-item-main">
|
||||
<strong>${escapeHtml(app.title)}</strong>
|
||||
<p>${escapeHtml(app.summary || '')}</p>
|
||||
<span class="usm-item-meta">${app.required ? 'Pflicht-App' : 'Optional sichtbar'}</span>
|
||||
<span class="usm-item-meta">Im Tray neben der Uhr</span>
|
||||
</span>
|
||||
</label>
|
||||
`;
|
||||
@@ -101,7 +138,7 @@
|
||||
<span class="window-app-item-main usm-item-main">
|
||||
<strong>${escapeHtml(widget.title)}</strong>
|
||||
<p>${escapeHtml(widget.summary || '')}</p>
|
||||
<span class="usm-item-meta">${widget.default_enabled ? 'Standardbereich' : 'Optionaler Bereich'}</span>
|
||||
<span class="usm-item-meta">${widget.default_enabled ? 'Standard-Widget' : 'Optionales Widget'}</span>
|
||||
</span>
|
||||
</label>
|
||||
`;
|
||||
@@ -166,8 +203,8 @@
|
||||
return `
|
||||
<section class="window-app-card usm-card">
|
||||
<p class="window-app-kicker usm-kicker">App-Auswahl</p>
|
||||
<h2>Sichtbare Desktop-Apps</h2>
|
||||
<p class="window-app-copy usm-copy">Aenderungen an der App-Auswahl werden nach dem Speichern mit einem Desktop-Reload sauber uebernommen.</p>
|
||||
<h2>Apps im Menue und auf dem Desktop</h2>
|
||||
<p class="window-app-copy usm-copy">Eine aktivierte App erscheint standardmaessig im Menue. Fuer geeignete Apps kann zusaetzlich ein Desktop-Icon aktiviert werden.</p>
|
||||
<div class="window-app-list usm-list">
|
||||
${renderAppItems(state)}
|
||||
</div>
|
||||
@@ -175,11 +212,24 @@
|
||||
`;
|
||||
}
|
||||
|
||||
if (state.activeSection === 'tray') {
|
||||
return `
|
||||
<section class="window-app-card usm-card">
|
||||
<p class="window-app-kicker usm-kicker">Tray-Apps</p>
|
||||
<h2>Bereich neben der Uhr</h2>
|
||||
<p class="window-app-copy usm-copy">Tray-Apps sind Schnellzugriffe oder Statusanzeigen im Bereich neben der Uhr. Sie koennen eigenstaendig oder zusammen mit der Haupt-App genutzt werden.</p>
|
||||
<div class="window-app-list usm-list">
|
||||
${renderTrayItems(state)}
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<section class="window-app-card usm-card">
|
||||
<p class="window-app-kicker usm-kicker">Infobereich</p>
|
||||
<h2>Rechter Desktopbereich</h2>
|
||||
<p class="window-app-copy usm-copy">Diese Inhalte liegen aktuell im rechten Infobereich des Desktops und werden hier benutzerbezogen ein- oder ausgeblendet.</p>
|
||||
<p class="window-app-kicker usm-kicker">Widgets</p>
|
||||
<h2>Kleine Desktop-Bereiche</h2>
|
||||
<p class="window-app-copy usm-copy">Widgets sind kleine Desktop-Bereiche ohne klassische Fensterfunktionen. Aktivierung und Positionierung werden schrittweise ausgebaut.</p>
|
||||
<div class="window-app-list usm-list">
|
||||
${renderWidgetItems(state)}
|
||||
</div>
|
||||
@@ -205,7 +255,7 @@
|
||||
<div class="window-app-brand usm-brand">
|
||||
<p class="window-app-kicker usm-kicker">Setup</p>
|
||||
<h1>User Self Management</h1>
|
||||
<p class="window-app-copy">Ein gemeinsamer Setup-Bereich fuer Desktop-Typ, Benutzerdaten, Apps und den rechten Infobereich.</p>
|
||||
<p class="window-app-copy">Ein gemeinsamer Setup-Bereich fuer Desktop-Typ, Benutzerdaten, Apps, Tray-Apps und Widgets.</p>
|
||||
</div>
|
||||
<div class="window-app-nav-list usm-nav-list">
|
||||
${SECTIONS.map((section) => `
|
||||
@@ -299,6 +349,10 @@
|
||||
},
|
||||
apps: {
|
||||
enabled_ids: state.draft.apps.enabled_ids,
|
||||
desktop_icon_ids: state.draft.apps.desktop_icon_ids,
|
||||
},
|
||||
tray: {
|
||||
active_ids: state.draft.tray.active_ids,
|
||||
},
|
||||
widgets: {
|
||||
active_ids: state.draft.widgets.active_ids,
|
||||
@@ -306,7 +360,10 @@
|
||||
});
|
||||
|
||||
const requiresReload = (before, after) => before.desktop.active_skin !== after.desktop.active_skin
|
||||
|| !sameSelection(before.apps.enabled_ids, after.apps.enabled_ids);
|
||||
|| !sameSelection(before.apps.enabled_ids, after.apps.enabled_ids)
|
||||
|| !sameSelection(before.apps.desktop_icon_ids, after.apps.desktop_icon_ids)
|
||||
|| !sameSelection(before.tray.active_ids, after.tray.active_ids)
|
||||
|| !sameSelection(before.widgets.active_ids, after.widgets.active_ids);
|
||||
|
||||
const attachInteractions = (root, state, options) => {
|
||||
root.addEventListener('click', async (event) => {
|
||||
@@ -405,6 +462,29 @@
|
||||
target.dataset.appId,
|
||||
target.checked
|
||||
);
|
||||
if (!target.checked) {
|
||||
state.draft.apps.desktop_icon_ids = state.draft.apps.desktop_icon_ids.filter((appId) => appId !== target.dataset.appId);
|
||||
}
|
||||
renderApp(root, state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.dataset.appDesktopIconId) {
|
||||
state.draft.apps.desktop_icon_ids = syncSelectionWithCheckedState(
|
||||
state.draft.apps.desktop_icon_ids,
|
||||
target.dataset.appDesktopIconId,
|
||||
target.checked
|
||||
);
|
||||
renderApp(root, state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.dataset.trayAppId) {
|
||||
state.draft.tray.active_ids = syncSelectionWithCheckedState(
|
||||
state.draft.tray.active_ids,
|
||||
target.dataset.trayAppId,
|
||||
target.checked
|
||||
);
|
||||
renderApp(root, state);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user