mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
The dialog filled its texts with String.replace, which reads $& and $' in the replacement as patterns: a host named c$&1 showed as c%(hosts)s1. The values now go in through a function, which inserts them as they are.
121 lines
4.8 KiB
JavaScript
121 lines
4.8 KiB
JavaScript
// The Instances page's "Find by address" dialog: the running VMs that use an
|
|
// IP address or an address in a network (instances.views.find_address), with
|
|
// where each address came from and what the search could not check.
|
|
(function () {
|
|
var dialog = document.getElementById("find-address");
|
|
var form = document.getElementById("find-address-form");
|
|
var error = document.getElementById("find-address-error");
|
|
var table = document.getElementById("find-address-results");
|
|
var coverage = document.getElementById("find-address-coverage");
|
|
var button = form.querySelector("button[type=submit]");
|
|
var text = dialog.dataset;
|
|
var MAC = /^[0-9a-f]{2}([:-]?)[0-9a-f]{2}(\1[0-9a-f]{2}){4}$/i; // as instances/addresses.py reads one
|
|
|
|
// a text with its placeholder filled; a function keeps $& and $' in the value as they are
|
|
function fill(template, placeholder, value) {
|
|
return template.replace(placeholder, function () { return value; });
|
|
}
|
|
|
|
function cell(row, content) {
|
|
var td = document.createElement("td");
|
|
if (content instanceof Node) {
|
|
td.appendChild(content);
|
|
} else {
|
|
td.textContent = content;
|
|
}
|
|
row.appendChild(td);
|
|
return td;
|
|
}
|
|
|
|
function vmCell(match) {
|
|
if (match.url) {
|
|
var link = document.createElement("a");
|
|
link.href = match.url;
|
|
link.textContent = match.vm;
|
|
return link;
|
|
}
|
|
return document.createTextNode(match.vm + " " + text.unregistered);
|
|
}
|
|
|
|
function coverageText(c) {
|
|
var lines = [fill(text.checked, "%(n)s", c.checked)];
|
|
if (c.no_agent) {
|
|
lines.push(fill(text.noAgent, "%(n)s", c.no_agent));
|
|
}
|
|
if (c.unread) {
|
|
lines.push(fill(text.unread, "%(n)s", c.unread));
|
|
}
|
|
if (c.hosts_down && c.hosts_down.length) {
|
|
lines.push(fill(text.hostsDown, "%(hosts)s", c.hosts_down.join(", ")));
|
|
}
|
|
if (c.hosts_unfinished && c.hosts_unfinished.length) {
|
|
lines.push(fill(text.hostsUnfinished, "%(hosts)s", c.hosts_unfinished.join(", ")));
|
|
}
|
|
if (c.some_unchecked) {
|
|
lines.push(text.someUnchecked);
|
|
}
|
|
return lines.join(" ");
|
|
}
|
|
|
|
function show(answer) {
|
|
error.textContent = answer.error || "";
|
|
error.classList.toggle("d-none", !answer.error);
|
|
var body = table.tBodies[0];
|
|
body.replaceChildren();
|
|
var matches = answer.matches || [];
|
|
matches.forEach(function (match) {
|
|
var row = body.insertRow();
|
|
var address = cell(row, match.address || "\u2014"); // a NIC without an address
|
|
if (match.conflict) {
|
|
var badge = document.createElement("span");
|
|
badge.className = "badge bg-warning-subtle text-warning-emphasis ms-1";
|
|
badge.textContent = text.conflict;
|
|
address.appendChild(badge);
|
|
}
|
|
cell(row, vmCell(match));
|
|
cell(row, match.mac);
|
|
cell(row, match.sources.join(", "));
|
|
if ("host" in match) {
|
|
cell(row, match.host);
|
|
}
|
|
});
|
|
table.classList.toggle("d-none", matches.length === 0);
|
|
if (answer.coverage) {
|
|
var readAt = fill(text.readAt, "%(time)s", new Date(answer.read_at).toLocaleTimeString());
|
|
var none = MAC.test(form.elements.q.value.trim()) ? text.noneMac : text.none;
|
|
coverage.textContent = (matches.length ? "" : none + " ") + coverageText(answer.coverage) + " " + readAt;
|
|
} else {
|
|
coverage.textContent = "";
|
|
}
|
|
}
|
|
|
|
// an address typed in the list's search box is what the dialog looks for
|
|
dialog.addEventListener("show.bs.modal", function () {
|
|
var typed = document.getElementById("filter").value.trim();
|
|
if (MAC.test(typed) || (/^[0-9a-fA-F:.]+(\/[0-9]+)?$/.test(typed) && /[.:]/.test(typed))) {
|
|
form.elements.q.value = typed;
|
|
}
|
|
});
|
|
dialog.addEventListener("shown.bs.modal", function () {
|
|
form.elements.q.focus();
|
|
});
|
|
|
|
form.addEventListener("submit", function (event) {
|
|
event.preventDefault();
|
|
button.disabled = true;
|
|
var url = text.url + "?" + new URLSearchParams({q: form.elements.q.value});
|
|
fetch(url, {headers: {"X-Requested-With": "XMLHttpRequest"}}).then(function (response) {
|
|
if (response.redirected) {
|
|
// signed out meanwhile: reloading goes to the login form, then back here
|
|
location.reload();
|
|
return new Promise(function () {});
|
|
}
|
|
return response.json();
|
|
}).catch(function () {
|
|
return {error: text.failed};
|
|
}).then(function (answer) {
|
|
show(answer);
|
|
button.disabled = false;
|
|
});
|
|
});
|
|
})();
|