Files
skills/orchestrator/templates/page-board.js
T

80 lines
3.5 KiB
JavaScript
Raw Normal View History

async function act(action, label, payload) {
ui.busy = true;
const result = await sendJson(`/api/board/${action}`, payload);
ui.busy = false;
if (result.data && result.data.runs) {
toast(`${label}: ${result.data.ok ? "done" : "failed"}`, runLines(result.data), result.data.ok);
} else {
toast(`${label}: failed`, [`${result.status} ${result.text}`.trim()], false);
}
await load();
return result.ok && result.data && result.data.ok;
}
async function confirmAct(action) {
const [, label, question] = ACTIONS.find(([id]) => id === action);
if (!window.confirm(question)) {
return;
}
const signed = await signedProof("/api/board/sign", {action}, label);
if (signed) {
await act(action, label, {proof: signed.proof});
}
}
function choice(name, options, picked) {
return h("div", {class: "classes", role: "radiogroup", "aria-label": "Class"}, options.map(([id, label]) => h("label", {class: "check"},
h("input", {type: "radio", name, value: id, checked: id === picked}), label)));
}
const picked = (group) => group.querySelector("input:checked").value;
function toAll() {
const text = h("textarea", {"aria-label": "Radio to all", placeholder: "Message to all agents …", on: {input: (event) => {
ui.draft = event.target.value;
}}});
text.value = ui.draft;
const classes = choice("to-all", TO_ALL, "newsletter");
const send = async () => {
const cls = picked(classes);
if (!ui.draft.trim() || (cls === "mayday" && !confirmMayday())) {
return;
}
if (await radioSend({to: "*", text: ui.draft, upload: "", cls, voice: ""})) {
ui.draft = "";
text.value = "";
}
};
return h("details", {class: "menu", id: "to-all"}, h("summary", named("Radio to all"), icon("bi-broadcast-pin"), caret()), h("div", {class: "menu-box"},
text, classes, h("p", {class: "muted"}, "Newsletter arrives as post at the end of the turn; Broadcast, Pan-Pan, Security and Mayday at once. Your passkey signs every message."),
h("div", {class: "actions"}, h("span", {class: "spacer"}), iconBtn("bi-send", "Send", "btn soft", send, "Send to all"))));
}
function openToAll() {
go("agents", null);
window.setTimeout(() => {
const menu = document.getElementById("to-all");
if (menu) {
menu.open = true;
menu.querySelector("textarea").focus();
}
}, 50);
}
function agentsToolbar() {
const clear = iconBtn("bi-life-preserver", "Cancel mayday", "btn small danger", () => confirmAct("clear-mayday"));
const mode = h("span", {});
const night = h("details", {class: "menu"}, h("summary", named("Day/Night"), icon("bi-moon-stars"), caret()), h("div", {class: "menu-box"}, mode,
h("p", {class: "muted"}, "Evening: agents finish their task. Sunset: they sleep. Sunrise: all wake up."),
h("div", {class: "actions"}, ACTIONS.slice(1).map(([id, label]) => btn(label, "btn small", () => confirmAct(id))))));
return {bar: h("div", {class: "toolbar", role: "toolbar", "aria-label": "Controls"}, toAll(), clear, iconBtn("bi-sort-down", "Priority", "btn small", openAgentOrder, "Priority: agent order in the hierarchy"), night), clear, mode};
}
function drawToolbar() {
if (!graphDom || !graphDom.toolbar) {
return;
}
const [mode, tone] = NIGHT[state.night] || [state.night, "neutral"];
graphDom.toolbar.clear.disabled = !state.silence;
graphDom.toolbar.mode.replaceChildren(pill(mode, tone));
}