johnandersen777.bsky.social/atlibs-socialweb-computer-requester
socialweb.computer market requester and policy modules for atlibs, with its web pages and lexicons
0
0
import { templated } from 'atlibs/component/index.js'
import { channelView } from './socialweb-cubit.js'
const Base = await templated(new URL('./swc-channel.html', import.meta.url));
const clone = (id) => Base.templates[id].content.cloneNode(true);
const time = (ts) => (ts ? new Date(ts).toLocaleTimeString() : "");
// The atirc channel as agents see it: who is talking, owner questions, VM requests from the
// account's agents (Approve emits approve {seq}), and every line tagged by kind. All channel
// text goes in through textContent. Renders {ui, atirc}.
customElements.define('swc-channel', class extends Base {
#view;
render({ ui, atirc }, previous) {
this.querySelector(".panel").style.display = atirc.session === "signed-in" ? "block" : "none";
this.querySelector(".channel").textContent = atirc.channel;
const { status, list, error } = atirc.messages;
this.querySelector(".lines").toggleAttribute("aria-busy", status === "loading" || status === "idle");
this.querySelector(".error").textContent = status === "error" ? `Error reading channel: ${error}` : "";
if (!this.#view || previous?.atirc.messages.list !== list || previous?.ui.did !== ui.did || previous?.atirc.channel !== atirc.channel) {
this.#view = channelView(list, { did: ui.did, handle: atirc.handle, channel: atirc.channel });
this.#lines(this.#view);
}
this.#requests(this.#view.requests, ui);
}
#lines({ lines, agents, questions }) {
this.querySelector(".agents").replaceChildren(...agents.map((a) => {
const li = clone("agent");
li.querySelector(".nick").textContent = a.nick;
li.querySelector(".nick").title = a.identity;
li.querySelector(".meta").textContent = `${a.lines} lines, ${a.scrobbles} scrobbles, last ${time(a.last)}`;
return li;
}));
this.querySelector(".questions").replaceChildren(...questions.map((q) => {
const li = clone("question");
li.querySelector(".status").textContent = q.status;
li.querySelector(".question").textContent = `${q.question} (${q.askedBy})`;
li.querySelector(".outcome").textContent = q.outcome ? `${q.status} by ${q.by}: ${q.outcome}` : "";
return li;
}));
this.querySelector(".lines").replaceChildren(...lines.map((m) => {
const li = clone("line");
li.firstElementChild.dataset.kind = m.kind;
li.querySelector(".ts").textContent = time(m.ts);
li.querySelector(".nick").textContent = m.nick;
li.querySelector(".nick").title = m.identity ?? "";
if (m.unverified) li.firstElementChild.dataset.unverified = "";
li.querySelector(".kind").textContent = m.unverified ? "unverified" : m.kind === "chat" ? "" : m.kind;
li.querySelector(".text").textContent = m.text;
return li;
}));
}
#requests(requests, ui) {
const allowed = ui.features.includes("agents") && ui.allowAgentRequests;
this.querySelector(".requests").replaceChildren(...requests.map((r) => {
const li = clone("request");
const approval = ui.approvals[r.seq];
li.querySelector(".who").textContent = `#${r.seq} ${r.identity}`;
li.querySelector(".input").textContent = JSON.stringify(r.input);
const button = li.querySelector(".approve");
button.disabled = !allowed || r.replied || Boolean(approval);
button.toggleAttribute("aria-busy", approval?.status === "running");
button.onclick = () => this.dispatchEvent(new CustomEvent("approve", { bubbles: true, detail: { seq: r.seq } }));
li.querySelector(".approval").textContent = approval?.error ?? (approval?.result ? `rfp ${approval.result.rfp?.uri}` : r.replied ? "answered" : "");
return li;
}));
}
});