diff --git a/src/lib/core/InfoBroker.mjs b/src/lib/core/InfoBroker.mjs index bfdc971..7df82dc 100644 --- a/src/lib/core/InfoBroker.mjs +++ b/src/lib/core/InfoBroker.mjs @@ -53,6 +53,11 @@ class InfoBroker { pid: process.pid, uptime: process.uptime(), memory: process.memoryUsage(), + peers_connected: this.sysquery.agent.connected_peers() + .map(peer => { return { + id: peer.id, + name: peer.name + }}) }; } diff --git a/src/static/app.css b/src/static/app.css index 37c5bec..732f2be 100644 --- a/src/static/app.css +++ b/src/static/app.css @@ -127,6 +127,34 @@ h2 { text-shadow: 0 0 0.25em var(--text); } +th, td { + border-collapse: collapse; +} +th { border: 0.1em solid red; } +td { border: 0.1em solid green; } + +.peer-name { + display: flex; + flex-direction: column; + + background: var(--tech-a1); + padding: 0.25em 0.45em; +} +.peer-name-name { + cursor: pointer; +} +.peer-name-id { + background: var(--tech-a2); + cursor: copy; +} +.peer-name-id::before { + content: "🔑"; + padding-right: 0.2em; +} + +.invisible-gone { + display: none; +} /* ███████ ██████ ██████ ████████ ███████ ██████ diff --git a/src/static/esbuild.mjs b/src/static/esbuild.mjs index 12a87a2..8050e92 100755 --- a/src/static/esbuild.mjs +++ b/src/static/esbuild.mjs @@ -61,7 +61,7 @@ async function do_html() { ].map(filepath => path.resolve(__dirname, filepath)), outdir, bundle: true, - minify: true, + minify: typeof process.env.NO_MINIFY === "undefined", sourcemap: true, treeShaking: true, watch: typeof process.env.ESBUILD_WATCH === "undefined" ? false : { diff --git a/src/static/js/ui/TableView.mjs b/src/static/js/ui/TableView.mjs index cda9be0..aa504f6 100644 --- a/src/static/js/ui/TableView.mjs +++ b/src/static/js/ui/TableView.mjs @@ -42,15 +42,20 @@ class TableView { for(let def of tabledef.items) { let el = document.createElement("div"); el.classList.add("data-item"); - el_dataitems.appendChild(el); - if(ui_item_index[def.type] instanceof AbstractUIItem) { + console.log(ui_item_index[def.type]); + if(typeof ui_item_index[def.type] !== "undefined") { let item_manager = new ui_item_index[def.type](el, def); this.el_parts.set(def.name, item_manager); + console.log(`TableView:UIItem create`, item_manager); } else { - console.warn(`Unknown item definition type '${def.type}', ignoring. This is probably a bug.`); + console.warn(`Unknown item definition type '${def.type}', ignoring. This is probably a bug.`, def); + continue; } + + // Only append the item to the display if we actually found a manager for it + el_dataitems.appendChild(el); } this.el.replaceChildren(parts); @@ -80,9 +85,9 @@ class TableView { * @return {void} */ append_table(peer, table) { + console.log(`TableView:append PEER`, peer, `TABLE`, table); for(let [ def_name, item_manager ] of this.el_parts) { if(item_manager === null) continue; - item_manager.append(peer, table); } } diff --git a/src/static/js/ui/UITable.mjs b/src/static/js/ui/UITable.mjs index 207268c..bd52adf 100644 --- a/src/static/js/ui/UITable.mjs +++ b/src/static/js/ui/UITable.mjs @@ -12,9 +12,15 @@ class UITable extends AbstractUIItem { this.emel = new Emel().emel; - this.el.replaceChildren(this.emel(`table>(thead>(tr>th{Peer}+${ - Object.keys(def.content).map(header => `th{${header}}`).join("+") - })+tbody`)); + switch(typeof def.content) { + case "string": + this.el.replaceChildren(this.emel(`table>(thead>tr>th{Peer}+th{Value})+tbody`)) + break; + default: + this.el.replaceChildren(this.emel(`table>(thead>tr>th{Peer}+${ + Object.keys(def.content).map(header => `th{${header}}`).join("+") + })+tbody`)); + } } clear() { @@ -32,10 +38,28 @@ class UITable extends AbstractUIItem { new_row.appendChild(peer_name(peer)); // Note here that the comma is *important*. This is a destructuring assignment where we ignore the first value. - for(let [ , template ] of Object.entries(this.def.content)) { - let table_cell = document.createElement("td"); - table_cell.appendChild(document.createTextNode(nightink(template, table))); - new_row.appendChild(table_cell); + switch(typeof this.def.content) { + case "string": + let cell_value = document.createElement("td"); + cell_value.appendChild(document.createTextNode(nightink(this.def.content, table))); + new_row.appendChild(cell_value); + break; + default: + for(let [ , template ] of Object.entries(this.def.content)) { + let table_cell = document.createElement("td"); + let value = null; + switch(typeof template) { + case "function": + value = template(table); + break; + case "string": + value = nightink(template, table); + break; + } + table_cell.appendChild(document.createTextNode(value)); + new_row.appendChild(table_cell); + } + break; } new_row.dataset.peer_name = peer.name; diff --git a/src/static/js/ui/peer_name.mjs b/src/static/js/ui/peer_name.mjs index 601070f..e474bd7 100644 --- a/src/static/js/ui/peer_name.mjs +++ b/src/static/js/ui/peer_name.mjs @@ -1,17 +1,37 @@ "use strict"; +function handle_toggle_id(event) { + event.target.closest(`.peer-name`) + .querySelector(`.peer-name-id`) + .classList.toggle(`invisible-gone`); +} + +async function handle_copy_id(event) { + await navigator.clipboard.writeText(event.target + .closest(`.peer-name`) + .dataset.peer_id); + + // TODO: Show notification here +} + export default function peer_name(peer) { const result = document.createElement("span"); - result.classList.append(`peer-name`); + result.classList.add(`peer-name`); result.dataset.peer_id = peer.id; result.dataset.peer_name = peer.name; const peer_name = document.createElement("span"); + peer_name.classList.add(`peer-name-name`); peer_name.appendChild(document.createTextNode(peer.name)); const peer_id = document.createElement("span"); - peer_id.appendChild(document.createTextNode(peer.id)); + peer_id.classList.add(`peer-name-id`, `invisible-gone`); + peer_id.appendChild(document.createTextNode( + peer.id.substring(0, 7) + )); + peer_name.addEventListener("click", handle_toggle_id); + peer_id.addEventListener("click", handle_copy_id); // TODO: When the id is clicked, copy it to the clipboard - we may need a fancy tooltip library for this // text-overflow: ellipsis; may be useful here