CxWebApp/static/js/panes/items.js
CxAI Agent d057e09fa2
Some checks are pending
build-and-push / image (push) Waiting to run
feat: add new panes for demand, diffusion, inbox, items, lang, mac, slack, system, tools, and websocket
- Implemented demand pane for managing trend-driven design jobs.
- Created diffusion pane for generating images via Stable Diffusion.
- Added inbox pane for sweeping and routing artifacts through the CxAI inbox classifier.
- Developed items pane for CRUD operations against /api/items.
- Introduced lang pane for running language pipelines.
- Established mac pane for macOS app distribution information.
- Integrated slack pane for sending messages and displaying diagnostics.
- Built system pane for process introspection and version information.
- Launched tools pane for browsing and invoking MCP tools.
- Set up websocket pane for connecting to the /ws/echo service.
2026-05-16 19:23:30 -05:00

77 lines
2.9 KiB
JavaScript

// panes/items.js — CRUD against /api/items.
import { registerPane } from '../app.js';
import { jget, jpost, jdelete, escapeHtml } from '../lib/api.js';
import { ok, err } from '../lib/ui.js';
const TPL = `
<div class="pane-head">
<div><div class="title">Items</div><div class="sub">Backend-managed records (/api/items).</div></div>
<div class="grow"></div>
<button class="btn btn-secondary" id="items-refresh">Refresh</button>
</div>
<div class="grid cols-2">
<div class="card">
<div class="card-title"><h2>New item</h2></div>
<form id="items-form" class="grid gap-3">
<label class="field"><span class="lbl">Name</span><input class="input" id="items-name" required /></label>
<label class="field"><span class="lbl">Description</span><textarea class="input" id="items-desc" rows="3"></textarea></label>
<button class="btn btn-primary" type="submit">Add item</button>
</form>
</div>
<div class="card">
<div class="card-title"><h2>List</h2><span class="muted mono" id="items-count">—</span></div>
<div id="items-list">loading…</div>
</div>
</div>
`;
async function load(host) {
try {
const j = await jget('/api/items');
const items = j.items || [];
host.querySelector('#items-count').textContent = String(j.count ?? items.length);
host.querySelector('#items-list').innerHTML = items.length ? items.map(it => `
<div class="row" data-id="${it.id}">
<span class="mono muted">#${it.id}</span>
<div class="grow">
<div class="ttl">${escapeHtml(it.name)}</div>
<div class="desc">${escapeHtml(it.description || '')}</div>
</div>
<span class="act" data-del="${it.id}">delete</span>
</div>
`).join('') : '<div class="muted" style="padding:12px">no items</div>';
host.querySelectorAll('[data-del]').forEach(b => {
b.addEventListener('click', async () => {
try { await jdelete('/api/items/' + b.dataset.del); ok('deleted'); load(host); }
catch (e) { err(e.message); }
});
});
} catch (e) {
host.querySelector('#items-list').innerHTML = `<div class="muted">${escapeHtml(e.message)}</div>`;
}
}
registerPane('items', {
label: 'Items',
init(host) {
host.innerHTML = TPL;
host.querySelector('#items-refresh').addEventListener('click', () => load(host));
host.querySelector('#items-form').addEventListener('submit', async (e) => {
e.preventDefault();
const name = host.querySelector('#items-name').value.trim();
const description = host.querySelector('#items-desc').value.trim();
if (!name) return;
try {
await jpost('/api/items', { name, description });
host.querySelector('#items-name').value = '';
host.querySelector('#items-desc').value = '';
ok('added');
load(host);
} catch (e) { err(e.message); }
});
load(host);
},
refresh: load,
});