// 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; }); }); })();