CxWebApp/static/js/panes/mac.js
CxAI Agent 75153b7fe9
Some checks are pending
build-and-push / image (push) Waiting to run
feat(cxwebapp): comprehensive pane enhancements
- All 14 panes rewritten with rich controls: KPIs, sparklines, meter
  gauges, presets, history sidebars, search/filter, bulk actions,
  schema-driven forms, copy buttons, auto-refresh.
- Backend /api/system enriched with cpu_count, rss_bytes, mem_total,
  mem_used_pct, loadavg[], user/system CPU times, max_rss_kb.
- CSS additions: .meter/.gauge, .seg, .chip(s), .spark, .slider, .dl,
  .link-card, details.card-d plus utility classes.
- ui.js helpers: copyToClipboard, withCopy/bindCopyButtons, sparkline,
  meterRow, fmtBytes/fmtNum, historyStore, inputFromSchema,
  collectSchemaForm.
- Files pane added; iCloud duplicate '*2' files removed.
2026-05-17 09:36:19 -05:00

94 lines
3.7 KiB
JavaScript

// panes/mac.js — macOS native app distribution.
import { registerPane } from '../app.js';
import { jget, escapeHtml, formatUptime } from '../lib/api.js';
import { fmtJSON, fmtBytes, copyToClipboard, ok, err } from '../lib/ui.js';
const TPL = `
<div class="pane-head">
<div><div class="title">macOS</div><div class="sub">Native CxLLM Desktop client distribution.</div></div>
<div class="grow"></div>
<button class="btn btn-secondary" id="mac-refresh">Refresh</button>
</div>
<div class="grid cols-2 mb-3">
<div class="card">
<div class="card-title"><h2>Latest build</h2>
<a class="btn btn-primary" id="mac-download" hidden>Download</a>
</div>
<dl class="dl" id="mac-build"></dl>
<div class="divider"></div>
<div class="card-title"><h2 style="font-size:14px">Checksum</h2>
<button class="btn btn-ghost" id="mac-copy-sha">Copy SHA-256</button>
</div>
<pre class="code" id="mac-sha" style="word-break:break-all">—</pre>
</div>
<div class="card">
<div class="card-title"><h2>Install instructions</h2></div>
<ol class="muted small" style="line-height:1.9">
<li>Click <b>Download</b> to grab the latest <code>.app.zip</code> bundle.</li>
<li>Unzip and drag <code>CxLLM.app</code> into <code>/Applications</code>.</li>
<li>First launch may show a Gatekeeper warning. To allow:
<pre class="code">xattr -dr com.apple.quarantine /Applications/CxLLM.app</pre>
</li>
<li>Or right-click the app and choose <b>Open</b>, then confirm.</li>
</ol>
<div class="divider"></div>
<div class="card-title"><h2 style="font-size:14px">System requirements</h2></div>
<ul class="muted small">
<li>macOS 13 Ventura or later</li>
<li>Apple silicon (arm64) or Intel (x86_64)</li>
<li>~120 MB disk · 200 MB RAM at idle</li>
</ul>
</div>
</div>
<div class="card">
<div class="card-title"><h2>Raw /api/mac/info</h2><button class="btn btn-ghost" id="mac-copy-json">Copy</button></div>
<pre class="code" id="mac-info" style="max-height:36vh">…</pre>
</div>
`;
function row(k, v) { return `<dt>${escapeHtml(k)}</dt><dd>${escapeHtml(v ?? '—')}</dd>`; }
async function load(host) {
try {
const r = await jget('/api/mac/info');
host.querySelector('#mac-info').textContent = fmtJSON(r);
const b = r.build || {};
host.querySelector('#mac-build').innerHTML =
row('Name', b.name) +
row('Version', b.version) +
row('Built', b.build_time) +
row('Channel', b.channel || 'stable') +
row('Size', b.size_bytes ? fmtBytes(b.size_bytes) : (b.size || '—')) +
row('Arch', (b.architectures || []).join(', ') || b.arch || '—');
host.querySelector('#mac-sha').textContent = b.sha256 || b.checksum || '—';
const a = host.querySelector('#mac-download');
if (r.download_url) {
a.href = r.download_url;
a.textContent = `Download ${b.name || 'CxLLM'} ${b.version || ''}`.trim();
a.hidden = false;
a.download = (r.download_url.split('/').pop() || 'cxllm.app.zip');
} else {
a.hidden = true;
}
} catch (e) {
host.querySelector('#mac-info').textContent = e.message;
err(e.message);
}
}
registerPane('mac', {
label: 'macOS',
init(host) {
host.innerHTML = TPL;
host.querySelector('#mac-refresh').addEventListener('click', () => load(host));
host.querySelector('#mac-copy-sha').addEventListener('click', () => copyToClipboard(host.querySelector('#mac-sha').textContent.trim(), 'sha copied'));
host.querySelector('#mac-copy-json').addEventListener('click', () => copyToClipboard(host.querySelector('#mac-info').textContent, 'copied'));
load(host);
},
refresh: load,
});