Spaces:
Paused
Paused
File size: 3,450 Bytes
5e0b58b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | "use strict";
function byId(id) {
return document.getElementById(id);
}
function escapeHtml(value) {
if (!value) return "";
const div = document.createElement("div");
div.textContent = String(value);
return div.innerHTML;
}
/**
* Owns structural proposal rendering and approval actions.
*/
export class StructuralProposalPanel {
constructor({ api, logger, onChanged = async () => {} }) {
this.api = api;
this.logger = logger;
this.onChanged = onChanged;
this.commandInFlight = false;
this.proposals = [];
this.handleApprove = this.handleApprove.bind(this);
this.handleReject = this.handleReject.bind(this);
}
async load() {
try {
const data = await this.api.getProposals();
this.proposals = data.proposals || [];
this.render(this.proposals);
} catch (error) {
this.logger.log(`β οΈ Failed to load proposals: ${error.message}`, "warning");
}
}
render(proposals) {
const container = byId("b5d-proposals");
if (!container) return;
if (!proposals || proposals.length === 0) {
container.innerHTML = '<div class="proposal-empty">No pending proposals</div>';
return;
}
container.innerHTML = proposals.map((proposal) => {
const confidence = (proposal.confidence || 0) * 100;
const id = escapeHtml(proposal.proposal_id);
return `
<div class="proposal-item" data-id="${id}">
<span class="proposal-kind">${escapeHtml(proposal.kind || "unknown")}</span>
<span class="proposal-desc">Neuron ${proposal.neuron_id || "?"} β ${proposal.target_id || "?"}</span>
<span class="proposal-conf" style="--conf: ${confidence}%">${confidence.toFixed(0)}%</span>
<span class="proposal-reason">${escapeHtml(proposal.reason || "")}</span>
<div class="proposal-actions">
<button class="btn-approve" data-id="${id}">β Approve</button>
<button class="btn-reject" data-id="${id}">β Reject</button>
</div>
</div>
`;
}).join("");
container.querySelectorAll(".btn-approve").forEach((button) => {
button.addEventListener("click", () => this.handleApprove(button.dataset.id));
});
container.querySelectorAll(".btn-reject").forEach((button) => {
button.addEventListener("click", () => this.handleReject(button.dataset.id));
});
}
async handleApprove(proposalId) {
await this.execute(proposalId, "approve", () => this.api.approveProposal(proposalId));
}
async handleReject(proposalId) {
await this.execute(proposalId, "reject", () => this.api.rejectProposal(proposalId));
}
async execute(proposalId, action, request) {
if (this.commandInFlight) {
this.logger.log("β³ Command in progress...", "warning");
return;
}
this.commandInFlight = true;
this.logger.log(`${action === "approve" ? "β Approving" : "β Rejecting"} proposal ${proposalId}...`, "info");
try {
const result = await request();
if (result.ok) {
this.logger.log(`β
Proposal ${proposalId} ${action}d`, "success");
await this.load();
await this.onChanged();
} else {
this.logger.log(`β Failed to ${action}: ${result.message || "Unknown error"}`, "error");
}
} catch (error) {
this.logger.log(`β Failed to ${action}: ${error.message}`, "error");
} finally {
this.commandInFlight = false;
}
}
}
|