MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / buildDashboardHtml

Function buildDashboardHtml

src/cli/dashboard.ts:46–287  ·  view source on GitHub ↗
(d: DashboardData, opts: { token?: string } = {})

Source from the content-addressed store, hash-verified

44
45/** Render the dashboard as one self-contained HTML page (PURE). Chart.js via CDN; everything else
46 * inline. When `token` is given the page is a live CONTROL panel (toggles/buttons call the local
47 * API); without it the same page renders read-only. */
48export function buildDashboardHtml(d: DashboardData, opts: { token?: string } = {}): string {
49 const live = !!opts.token;
50 const card = (label: string, value: string, accent: string) =>
51 `<div class="card"><div class="v" style="color:${accent}">${value}</div><div class="l">${label}</div></div>`;
52
53 // ── Controls: config toggles/selects grouped, + scheduled tasks with enable/remove ──
54 const groups = [...new Set(d.controls.map(c => c.group))];
55 const controlPanel = d.controls.length === 0 ? '' : groups.map(g => {
56 const rows = d.controls.filter(c => c.group === g).map(c => {
57 if (c.type === 'bool') {
58 const on = c.current === 'true';
59 const btn = live
60 ? `<button class="tg ${on ? 'on' : ''}" onclick="act('config.set',{key:'${c.path}',value:${!on}})">${on ? 'ON' : 'OFF'}</button>`
61 : `<span class="${on ? 'ok' : 'dim'}">${on ? 'ON' : 'OFF'}</span>`;
62 return `<div class="ctl"><span>${esc(c.label)}</span>${btn}</div>`;
63 }
64 const sel = live
65 ? `<select onchange="act('config.set',{key:'${c.path}',value:this.value})">${(c.values ?? []).map(v => `<option${v === c.current ? ' selected' : ''}>${esc(v)}</option>`).join('')}</select>`
66 : `<span class="mono">${esc(c.current)}</span>`;
67 return `<div class="ctl"><span>${esc(c.label)}</span>${sel}</div>`;
68 }).join('');
69 return `<div class="panel"><h2>${esc(g)}</h2>${rows}</div>`;
70 }).join('');
71 // These knobs are read from config ONCE when a qodex session starts (config is not hot-
72 // reloaded mid-session). A toggle here writes the config file immediately, but a session
73 // that's already running keeps its old value until it restarts — the #1 "I turned it on
74 // but nothing changed" confusion. Say so, prominently, right above the toggles.
75 const controlNote = (live && d.controls.length)
76 ? `<p class="dim" style="margin:-4px 0 14px">Changes are written to <code>~/.qodex/config.yaml</code> and picked up on your <b>next message/task</b> — a running QodeX session hot-reloads these knobs at the start of each run (no restart needed).</p>`
77 : '';
78
79 const scheduleRows = d.schedules.length ? d.schedules.map(s => `<tr>
80 <td>${s.enabled ? '🟢' : '⚪'} <b>${esc(s.name)}</b>${s.recipe ? ` <span class="mono dim">${esc(s.recipe)}</span>` : ''}</td>
81 <td class="mono dim">${esc(s.cron)}</td>
82 <td class="r">${live ? `<button onclick="act('schedule.setEnabled',{id:'${esc(s.id)}',enabled:${!s.enabled}})">${s.enabled ? 'Disable' : 'Enable'}</button> <button class="danger" onclick="if(confirm('Remove ${esc(s.name)}?'))act('schedule.remove',{id:'${esc(s.id)}'})">Remove</button>` : `<span class="dim">${s.enabled ? 'enabled' : 'disabled'}</span>`}</td>
83 </tr>`).join('') : '<tr><td colspan="3" class="dim">No scheduled tasks. Add one with `qodex schedule add`.</td></tr>';
84 const addForm = live ? `<div class="addform">
85 <input id="s_name" placeholder="name (e.g. nightly-fix)">
86 <input id="s_cron" placeholder="cron (@daily, 0 3 * * *)">
87 <input id="s_prompt" placeholder="prompt — or maintain: dead-code | unused-imports/locals/params | lint-fix | dep-bump [--dry-run] [path]" style="flex:2">
88 <select id="s_recipe"><option value="">plain</option><option value="verified-pr">verified-pr</option><option value="maintain">maintain (self-improving → verified PR)</option></select>
89 <input id="s_deliver" placeholder="deliver (telegram:&lt;id&gt;)">
90 <button onclick="act('schedule.add',{name:s_name.value,cron:s_cron.value,prompt:s_prompt.value,recipe:s_recipe.value,deliver:s_deliver.value})">Schedule</button>
91 </div>` : '';
92 const schedulePanel = `<div class="panel"><h2>Scheduled tasks</h2><table><thead><tr><th>task</th><th>cron</th><th class="r">${live ? 'actions' : 'state'}</th></tr></thead><tbody>${scheduleRows}</tbody></table>${addForm}</div>`;
93
94 // Run history + trust receipts (proof-carrying autonomy, surfaced).
95 const runRows = d.runs.length ? d.runs.map(r => {
96 const rc = r.receipt;
97 const verdict = rc ? `<span class="${rc.status === 'opened' || rc.status === 'done' ? 'ok' : rc.status === 'blocked' ? 'warn' : 'dim'}">🧾 ${esc(rc.status)}</span>${rc.prUrl ? ` <a href="${esc(rc.prUrl)}" target="_blank" class="mono">PR</a>` : ''}${rc.verification?.length ? ` <span class="dim mono">${rc.verification.map(v => (v.passed ? '✓' : '✗') + v.command).join(' ')}</span>` : ''}` : '<span class="dim">—</span>';
98 return `<tr><td><b>${esc(r.schedule)}</b>${r.recipe ? ` <span class="mono dim">${esc(r.recipe)}</span>` : ''}</td><td class="dim">${esc(r.when)}</td><td>${esc(r.status)}</td><td>${verdict}</td></tr>`;
99 }).join('') : '<tr><td colspan="4" class="dim">No runs yet. A verified-pr / maintain schedule produces a 🧾 receipt.</td></tr>';
100 const runsPanel = `<div class="panel"><h2>Run history &amp; receipts</h2><table><thead><tr><th>schedule · recipe</th><th>when</th><th>status</th><th>receipt</th></tr></thead><tbody>${runRows}</tbody></table></div>`;
101
102 // Maintain status & analytics (self-improvement loop at a glance).
103 const ms = d.maintainStats;

Callers 4

dashboard.test.tsFile · 0.90
runDashboardFunction · 0.85
writeStaticDashboardFunction · 0.85

Calls 5

cardFunction · 0.85
modelSelectFunction · 0.85
absMethod · 0.80
escFunction · 0.70
numFunction · 0.70

Tested by

no test coverage detected