Files
hermes-command-center/static/index.html
T
shawn 54af25d2da feat: config file editor with API endpoints, frontend UI, and tests
- 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
2026-06-01 23:49:30 -04:00

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">&larr; 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 &#10003;</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>