De-clutter each component into sub-system folders (apps: core/ port-manager/
services/ tools/ routing/; admin: config/ overview/ system/ ssh/ peers/) with
the standard js/ css/ html/ icons/ layout inside; single-page components
(backup/dashboard/tasks/updater) get js/ css/ html/. Single-feature icon sets
moved into their sub-system (vpn -> apps/core/icons, config/cpu/os ->
admin/{config,system}/icons); shared app + category icons stay in core/icons.
feature.json + index.js stay at each component root (the scanned descriptor +
entry). Every controller/CSS/fragment/icon path reference rewritten; verified
no stale refs, all JS valid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
204 lines
9.4 KiB
HTML
Executable File
204 lines
9.4 KiB
HTML
Executable File
<!-- Tasks Content - Sidebar Layout -->
|
|
<div class="tasks-layout">
|
|
<!-- Mobile overlay -->
|
|
<div class="mobile-overlay" id="mobile-overlay"></div>
|
|
|
|
<!-- Sidebar Container -->
|
|
<div class="sidebar-container">
|
|
<div class="sidebar" id="sidebar">
|
|
<!-- Task Categories -->
|
|
<div class="sidebar-section">
|
|
<div class="sidebar-category">
|
|
<h3>📋 All Tasks</h3>
|
|
<div class="sidebar-items">
|
|
<a href="#" class="sidebar-item active" data-category="all" onclick="filterTasksByCategory('all')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
<line x1="9" y1="9" x2="15" y2="9"></line>
|
|
<line x1="9" y1="15" x2="15" y2="15"></line>
|
|
</svg>
|
|
All Tasks
|
|
<span class="task-count" id="count-all">0</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sidebar-category">
|
|
<h3>📊 By Status</h3>
|
|
<div class="sidebar-items">
|
|
<a href="#" class="sidebar-item" data-category="queued" onclick="filterTasksByCategory('queued')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="stroke: var(--status-warning);" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<polyline points="12 6 12 12 16 14"></polyline>
|
|
</svg>
|
|
Queued
|
|
<span class="task-count" id="count-queued">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="running" onclick="filterTasksByCategory('running')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="stroke: var(--status-success);" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<polyline points="12 6 12 12 16 14"></polyline>
|
|
</svg>
|
|
Running
|
|
<span class="task-count" id="count-running">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="completed" onclick="filterTasksByCategory('completed')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="stroke: var(--status-success);" stroke-width="2">
|
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
|
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
|
</svg>
|
|
Completed
|
|
<span class="task-count" id="count-completed">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="failed" onclick="filterTasksByCategory('failed')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="stroke: var(--status-danger);" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<line x1="15" y1="9" x2="9" y2="15"></line>
|
|
<line x1="9" y1="9" x2="15" y2="15"></line>
|
|
</svg>
|
|
Failed
|
|
<span class="task-count" id="count-failed">0</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sidebar-category">
|
|
<h3>🏷️ By Type</h3>
|
|
<div class="sidebar-items">
|
|
<a href="#" class="sidebar-item" data-category="install" onclick="filterTasksByCategory('install')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
<polyline points="7 10 12 15 17 10"></polyline>
|
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
</svg>
|
|
Install
|
|
<span class="task-count" id="count-install">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="uninstall" onclick="filterTasksByCategory('uninstall')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 6h18"></path>
|
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
|
</svg>
|
|
Uninstall
|
|
<span class="task-count" id="count-uninstall">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="management" onclick="filterTasksByCategory('management')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M12 1v6m0 6v6m4.22-13.22l4.24 4.24M1.54 9.96l4.24 4.24M1.54 14.04l4.24-4.24M18.46 14.04l4.24-4.24"></path>
|
|
</svg>
|
|
Management
|
|
<span class="task-count" id="count-management">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="backup" onclick="filterTasksByCategory('backup')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path>
|
|
<polyline points="17 21 17 13 7 13 7 21"></polyline>
|
|
<polyline points="7 3 7 8 15 8"></polyline>
|
|
</svg>
|
|
Backups
|
|
<span class="task-count" id="count-backup">0</span>
|
|
</a>
|
|
<a href="#" class="sidebar-item" data-category="config" onclick="filterTasksByCategory('config')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M12 1v6m0 6v6m4.22-13.22l4.24 4.24M1.54 9.96l4.24 4.24M1.54 14.04l4.24-4.24M18.46 14.04l4.24-4.24"></path>
|
|
</svg>
|
|
Configuration
|
|
<span class="task-count" id="count-config">0</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sidebar-category">
|
|
<h3>📱 By App</h3>
|
|
<div class="sidebar-items" id="app-categories">
|
|
<!-- App categories will be dynamically generated here -->
|
|
<div class="loading-categories">
|
|
<div class="loading-spinner"></div>
|
|
<p style="color: var(--text-primary);">Loading apps...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Main Content Area -->
|
|
<div class="main-content">
|
|
<!-- Status Bar -->
|
|
<div class="terminal-status-bar">
|
|
<div class="status-item">
|
|
<span class="status-indicator status-queued"></span>
|
|
Queued: <span id="queued-count">0</span>
|
|
</div>
|
|
<div class="status-item">
|
|
<span class="status-indicator status-running"></span>
|
|
Running: <span id="running-count">0</span>
|
|
</div>
|
|
<div class="status-item">
|
|
<span class="status-indicator status-completed"></span>
|
|
Completed: <span id="completed-count">0</span>
|
|
</div>
|
|
<div class="status-item">
|
|
<span class="status-indicator status-failed"></span>
|
|
Failed: <span id="failed-count">0</span>
|
|
</div>
|
|
<div class="status-item">
|
|
<button class="refresh-btn" onclick="refreshTasks()">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"></path>
|
|
</svg>
|
|
Refresh
|
|
</button>
|
|
<button class="clear-btn" id="tasks-clear-btn" onclick="clearAllTasks()" title="Clear All Tasks">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 6h18"></path>
|
|
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
|
</svg>
|
|
<span class="clear-btn-label">Clear All</span>
|
|
</button>
|
|
<label class="task-select-all" title="Select all visible tasks">
|
|
<input type="checkbox" id="tasks-select-all" onchange="window.tasksManager && tasksManager.toggleSelectAll(this.checked)">
|
|
<span class="task-select-box" aria-hidden="true"></span>
|
|
<span class="task-select-all-label">Select all</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tasks List -->
|
|
<div class="tasks-terminal">
|
|
<div class="tasks-list" id="tasks-list">
|
|
<!-- Modern loading spinner -->
|
|
<div class="loading-content" style="
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
color: var(--text-primary);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 400px;
|
|
background: var(--surface-sunken);
|
|
border-radius: 8px;
|
|
border: 1px solid var(--border-subtle);
|
|
margin: 16px;
|
|
">
|
|
<div class="loading-spinner" style="
|
|
width: 32px;
|
|
height: 32px;
|
|
border: 4px solid rgba(var(--accent-rgb), 0.3);
|
|
border-top: 4px solid var(--accent);
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin-bottom: 20px;
|
|
"></div>
|
|
<p style="font-size: 16px; margin-bottom: 8px;">Loading tasks...</p>
|
|
<p style="font-size: 12px; opacity: 0.7;">Please wait while we fetch your tasks</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|