54af25d2da
- Added GET /api/config/list - list whitelisted config files with metadata - Added GET /api/config/read - read file content with line numbers - Added POST /api/config/save - save with auto-backup and YAML validation - Added POST /api/config/backup - manual backup endpoint - Security: whitelist-based path validation, rejects paths outside whitelist - Auto-backup before save with .bak.<timestamp> naming - YAML validation for .yaml/.yml files - Frontend: file list sidebar, code editor with line numbers, status bar - Mobile-responsive layout (file list top, editor below) - Config panel in nav, lazy-loaded when navigated to - 13/13 tests passing
185 lines
9.2 KiB
HTML
185 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Hermes Command Center</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<nav class="sidebar">
|
|
<div class="logo">🎛️ Command Center</div>
|
|
<ul class="nav-links">
|
|
<li><a href="#agents" class="active">💬 Agents</a></li>
|
|
<li><a href="#config">⚙️ Config</a></li>
|
|
<li><a href="#vault">📚 Vault</a></li>
|
|
<li><a href="#network">🌐 Network</a></li>
|
|
</ul>
|
|
</nav>
|
|
<main class="content">
|
|
<section id="agents" class="panel">
|
|
<div id="chat-app">
|
|
<div class="chat-header">
|
|
<div class="chat-profile-strip">
|
|
<span class="chat-profiles-label">Agent:</span>
|
|
<div id="chat-profile-tabs" class="chat-profile-tabs"></div>
|
|
</div>
|
|
</div>
|
|
<div id="chat-messages" class="chat-messages">
|
|
<div class="chat-welcome">
|
|
<div class="chat-welcome-icon">💬</div>
|
|
<h3>Agent Chat</h3>
|
|
<p>Select an agent profile above and type a message to start a conversation.</p>
|
|
</div>
|
|
</div>
|
|
<div id="chat-typing" class="chat-typing" hidden>
|
|
<span class="typing-dot"></span>
|
|
<span class="typing-dot"></span>
|
|
<span class="typing-dot"></span>
|
|
<span class="typing-label">Agent is typing...</span>
|
|
</div>
|
|
<div class="chat-input-area">
|
|
<textarea id="chat-input" rows="1" placeholder="Type a message..." maxlength="2000"></textarea>
|
|
<button id="chat-send-btn" class="btn btn-primary" disabled>Send</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<section id="config" class="panel config-panel" hidden>
|
|
<div class="config-file-list" id="config-file-list">
|
|
<div class="config-header">
|
|
<h2>Config Editor</h2>
|
|
<span class="config-count" id="config-count">0 files</span>
|
|
</div>
|
|
<div class="config-files-container" id="config-files-container">
|
|
<p class="loading-text">Select a panel to open...</p>
|
|
</div>
|
|
</div>
|
|
<div class="config-editor" id="config-editor" hidden>
|
|
<div class="editor-header">
|
|
<button id="config-back-btn" class="btn btn-sm" title="Back to file list">← Back</button>
|
|
<span class="editor-filename" id="editor-filename"></span>
|
|
<div class="editor-actions">
|
|
<button id="config-save-btn" class="btn btn-primary btn-sm" disabled>Saved ✓</button>
|
|
</div>
|
|
</div>
|
|
<div class="editor-body">
|
|
<div class="editor-line-numbers" id="editor-line-numbers"></div>
|
|
<textarea class="editor-textarea" id="config-editor-textarea"
|
|
spellcheck="false" wrap="off" disabled
|
|
placeholder="Select a file to edit..."></textarea>
|
|
</div>
|
|
<div class="editor-status-bar">
|
|
<span id="status-path"></span>
|
|
<span id="status-meta"></span>
|
|
<span id="status-saved" class="status-saved"></span>
|
|
</div>
|
|
</div>
|
|
<div id="config-toast" class="config-toast" hidden></div>
|
|
</section>
|
|
<section id="vault" class="panel" hidden>
|
|
<div id="vault-app">
|
|
<div class="vault-toolbar">
|
|
<button id="vault-toggle-tree" class="vault-btn" title="Toggle file tree">📂</button>
|
|
<div class="vault-search-box">
|
|
<input type="text" id="vault-search-input" placeholder="Search vault..." />
|
|
<div id="vault-search-results" class="vault-search-dropdown" hidden></div>
|
|
</div>
|
|
</div>
|
|
<div class="vault-body">
|
|
<div id="vault-tree" class="vault-tree-panel"></div>
|
|
<div id="vault-content" class="vault-content-panel">
|
|
<div class="vault-welcome">
|
|
<h2>Obsidian Vault</h2>
|
|
<p>Select a file from the tree or search to get started.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<section id="network" class="panel network-panel" hidden>
|
|
<div class="network-header">
|
|
<h2>Network Status</h2>
|
|
<div class="network-controls">
|
|
<div class="countdown-bar" id="countdown-bar">
|
|
<div class="countdown-fill" id="countdown-fill"></div>
|
|
</div>
|
|
<button class="btn btn-sm btn-refresh" id="network-refresh-btn" title="Refresh now">⟳</button>
|
|
<label class="auto-refresh-toggle" title="Toggle auto-refresh">
|
|
<input type="checkbox" id="auto-refresh-toggle" checked>
|
|
<span>Auto</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary Bar -->
|
|
<div class="network-summary" id="network-summary">
|
|
<div class="summary-item online"><span class="summary-count" id="hosts-online">0</span> Online</div>
|
|
<div class="summary-item degraded"><span class="summary-count" id="hosts-degraded">0</span> Degraded</div>
|
|
<div class="summary-item offline"><span class="summary-count" id="hosts-offline">0</span> Offline</div>
|
|
<div class="summary-item total"><span class="summary-count" id="hosts-total">0</span> Total</div>
|
|
</div>
|
|
|
|
<div class="network-tabs">
|
|
<button class="tab-btn active" data-tab="hosts">Hosts</button>
|
|
<button class="tab-btn" data-tab="services">Services</button>
|
|
<button class="tab-btn" data-tab="local">Local Services</button>
|
|
</div>
|
|
|
|
<!-- Hosts Tab -->
|
|
<div class="tab-content active" id="tab-hosts">
|
|
<div class="hosts-grid" id="hosts-grid">
|
|
<div class="loading-text">Loading hosts...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Services Tab -->
|
|
<div class="tab-content" id="tab-services">
|
|
<div class="services-table-wrap">
|
|
<table class="services-table" id="services-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Service</th>
|
|
<th>Category</th>
|
|
<th>URL / Port</th>
|
|
<th>Status</th>
|
|
<th>Latency</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="services-tbody">
|
|
<tr><td colspan="5" class="loading-text">Loading services...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Local Services Tab -->
|
|
<div class="tab-content" id="tab-local">
|
|
<div class="services-table-wrap">
|
|
<table class="services-table" id="local-services-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Address</th>
|
|
<th>Port</th>
|
|
<th>Process</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="local-services-tbody">
|
|
<tr><td colspan="3" class="loading-text">Loading local services...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="network-footer">
|
|
<span class="last-updated" id="last-updated">Last updated: —</span>
|
|
<span class="cache-info" id="cache-info"></span>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
<script src="/static/app.js"></script>
|
|
<script src="/static/vault.js"></script>
|
|
</body>
|
|
</html>
|