review remains

This commit is contained in:
Evgenii Alekseev 2024-09-03 18:31:05 +03:00
parent b67e246ea9
commit bd926de740
10 changed files with 159 additions and 193 deletions

View File

@ -44,28 +44,28 @@
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li> <li>
<button id="package-add-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-add-modal" hidden> <button id="package-add-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-add-modal">
<i class="bi bi-plus"></i> add <i class="bi bi-plus"></i> add
</button> </button>
</li> </li>
<li> <li>
<button id="package-update-button" class="btn dropdown-item" onclick="packagesUpdate()" hidden> <button id="package-update-button" class="btn dropdown-item" onclick="packagesUpdate()">
<i class="bi bi-play"></i> update <i class="bi bi-play"></i> update
</button> </button>
</li> </li>
<li> <li>
<button id="package-rebuild-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-rebuild-modal" hidden> <button id="package-rebuild-button" class="btn dropdown-item" data-bs-toggle="modal" data-bs-target="#package-rebuild-modal">
<i class="bi bi-arrow-clockwise"></i> rebuild <i class="bi bi-arrow-clockwise"></i> rebuild
</button> </button>
</li> </li>
<li> <li>
<button id="package-remove-button" class="btn dropdown-item" onclick="packagesRemove()" disabled hidden> <button id="package-remove-button" class="btn dropdown-item" onclick="packagesRemove()" disabled>
<i class="bi bi-trash"></i> remove <i class="bi bi-trash"></i> remove
</button> </button>
</li> </li>
</ul> </ul>
<button id="key-import-button" type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#key-import-modal" hidden> <button id="key-import-button" type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#key-import-modal">
<i class="bi bi-key"></i><span class="d-none d-sm-inline"> import key</span> <i class="bi bi-key"></i><span class="d-none d-sm-inline"> import key</span>
</button> </button>
{% endif %} {% endif %}

View File

@ -35,7 +35,7 @@
function showFailure(title, description, jqXHR, errorThrown) { function showFailure(title, description, jqXHR, errorThrown) {
let details; let details;
try { try {
details = $.parseJSON(jqXHR.responseText).error; // execution handler json error response details = JSON.parse(jqXHR.responseText).error; // execution handler json error response
} catch (_) { } catch (_) {
details = errorThrown; details = errorThrown;
} }

View File

@ -76,7 +76,7 @@
type: "POST", type: "POST",
contentType: "application/json", contentType: "application/json",
success: _ => { success: _ => {
bootstrap.Modal.getInstance(keyImportModal).hide(); bootstrap.Modal.getOrCreateInstance(keyImportModal).hide();
showSuccess("Success", `Key ${key} has been imported`); showSuccess("Success", `Key ${key} has been imported`);
}, },
error: (jqXHR, _, errorThrown) => { error: (jqXHR, _, errorThrown) => {
@ -87,7 +87,7 @@
} }
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
keyImportModal.addEventListener("hidden.bs.modal", _ => { keyImportModal.addEventListener("hidden.bs.modal", _ => {
keyImportBodyInput.textContent = ""; keyImportBodyInput.textContent = "";
keyImportForm.reset(); keyImportForm.reset();

View File

@ -52,7 +52,7 @@
type: "POST", type: "POST",
contentType: "application/json", contentType: "application/json",
success: _ => { success: _ => {
bootstrap.Modal.getInstance(loginModal).hide(); bootstrap.Modal.getOrCreateInstance(loginModal).hide();
showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/"); showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/");
}, },
error: (jqXHR, _, errorThrown) => { error: (jqXHR, _, errorThrown) => {
@ -78,7 +78,7 @@
} }
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
loginModal.addEventListener("hidden.bs.modal", _ => { loginModal.addEventListener("hidden.bs.modal", _ => {
loginForm.reset(); loginForm.reset();
}); });

View File

@ -41,14 +41,14 @@
</div> </div>
<script> <script>
const packageAddModal = $("#package-add-modal"); const packageAddModal = document.getElementById("package-add-modal");
const packageAddForm = $("#package-add-form"); const packageAddForm = document.getElementById("package-add-form");
const packageAddInput = $("#package-add-input"); const packageAddInput = document.getElementById("package-add-input");
const packageAddRepositoryInput = $("#package-add-repository-input"); const packageAddRepositoryInput = document.getElementById("package-add-repository-input");
const packageAddKnownPackagesList = $("#package-add-known-packages-dlist"); const packageAddKnownPackagesList = document.getElementById("package-add-known-packages-dlist");
const packageAddVariablesDiv = $("#package-add-variables-div"); const packageAddVariablesDiv = document.getElementById("package-add-variables-div");
function packageAddVariableInputCreate() { function packageAddVariableInputCreate() {
const variableInput = document.createElement("div"); const variableInput = document.createElement("div");
@ -78,7 +78,7 @@
variableButtonRemove.classList.add("btn"); variableButtonRemove.classList.add("btn");
variableButtonRemove.classList.add("btn-outline-danger"); variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>"; variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => { return variableInput.remove(); }; variableButtonRemove.onclick = _ => { variableInput.remove(); };
// bring them together // bring them together
variableInput.appendChild(variableNameInput); variableInput.appendChild(variableNameInput);
@ -86,27 +86,26 @@
variableInput.appendChild(variableValueInput); variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove); variableInput.appendChild(variableButtonRemove);
packageAddVariablesDiv.append(variableInput); packageAddVariablesDiv.appendChild(variableInput);
} }
function patchesParse() { function patchesParse() {
const patches = packageAddVariablesDiv.find(".package-add-variable").map((_, element) => { const patches = Array.from(packageAddVariablesDiv.getElementsByClassName("package-add-variable")).map(element => {
const richElement = $(element);
return { return {
key: richElement.find(".package-add-variable-name").val(), key: element.querySelector(".package-add-variable-name").value,
value: richElement.find(".package-add-variable-value").val(), value: element.querySelector(".package-add-variable-value").value,
}; };
}).filter((_, patch) => patch.key).get(); }).filter(patch => patch.key);
return {patches: patches}; return {patches: patches};
} }
function packagesAdd(packages, patches, repository) { function packagesAdd(packages, patches, repository) {
packages = packages ?? packageAddInput.val(); packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse(); patches = patches ?? patchesParse();
repository = repository ?? getRepositorySelector(packageAddRepositoryInput); repository = repository ?? getRepositorySelector(packageAddRepositoryInput);
if (packages) { if (packages) {
packageAddModal.modal("hide"); bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been added`; const onSuccess = update => `Packages ${update} have been added`;
const onFailure = error => `Package addition failed: ${error}`; const onFailure = error => `Package addition failed: ${error}`;
doPackageAction("/api/v1/service/add", [packages], repository, onSuccess, onFailure, patches); doPackageAction("/api/v1/service/add", [packages], repository, onSuccess, onFailure, patches);
@ -114,50 +113,49 @@
} }
function packagesRequest(packages, patches) { function packagesRequest(packages, patches) {
packages = packages ?? packageAddInput.val(); packages = packages ?? packageAddInput.value;
patches = patches ?? patchesParse(); patches = patches ?? patchesParse();
const repository = getRepositorySelector(packageAddRepositoryInput); const repository = getRepositorySelector(packageAddRepositoryInput);
if (packages) { if (packages) {
packageAddModal.modal("hide"); bootstrap.Modal.getOrCreateInstance(packageAddModal).hide();
const onSuccess = update => `Packages ${update} have been requested`; const onSuccess = update => `Packages ${update} have been requested`;
const onFailure = error => `Package request failed: ${error}`; const onFailure = error => `Package request failed: ${error}`;
doPackageAction("/api/v1/service/request", [packages], repository, onSuccess, onFailure, patches); doPackageAction("/api/v1/service/request", [packages], repository, onSuccess, onFailure, patches);
} }
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
packageAddModal.on("shown.bs.modal", _ => { packageAddModal.addEventListener("shown.bs.modal", _ => {
$(`#package-add-repository-input option[value="${repository.architecture}-${repository.repository}"]`).prop("selected", true); const option = packageAddRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
if (option) option.selected = "selected";
}); });
packageAddModal.on("hidden.bs.modal", _ => { packageAddModal.addEventListener("hidden.bs.modal", _ => {
packageAddVariablesDiv.empty(); packageAddVariablesDiv.replaceChildren();
packageAddForm.trigger("reset"); packageAddForm.reset();
}); });
packageAddInput.keyup(_ => { packageAddInput.addEventListener("keyup", _ => {
clearTimeout(packageAddInput.data("timeout")); clearTimeout(packageAddInput.requestTimeout);
packageAddInput.data("timeout", setTimeout($.proxy(_ => { packageAddInput.requestTimeout = setTimeout(_ => {
const value = packageAddInput.val(); const value = packageAddInput.value;
if (value.length >= 3) { if (value.length >= 3) {
$.ajax({ const query = new URLSearchParams({for: value});
url: "/api/v1/service/search", fetch(`/api/v1/service/search?${query.toString()}`)
data: {"for": value}, .then(response => response.json())
type: "GET", .then(data => {
dataType: "json", const options = data.map(pkg => {
success: response => {
const options = response.map(pkg => {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = pkg.package; option.value = pkg.package;
option.innerText = `${pkg.package} (${pkg.description})`; option.innerText = `${pkg.package} (${pkg.description})`;
return option; return option;
}); });
packageAddKnownPackagesList.empty().append(options); packageAddKnownPackagesList.replaceChildren(...options);
}, })
}); .catch(_ => {});
} }
}, this), 500)); }, 500);
}); });
}); });
</script> </script>

View File

@ -58,7 +58,7 @@
<pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre> <pre class="language-diff"><code id="package-info-changes-input" class="pre-scrollable language-diff"></code><button id="package-info-changes-copy-button" type="button" class="btn language-diff" onclick="copyChanges()"><i class="bi bi-clipboard"></i> copy</button></pre>
</div> </div>
<div id="package-info-events" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-events-button" tabindex="0"> <div id="package-info-events" class="tab-pane fade" role="tabpanel" aria-labelledby="package-info-events-button" tabindex="0">
<canvas id="package-info-events-update-chart"></canvas> <canvas id="package-info-events-update-chart" hidden></canvas>
<table id="package-info-events-table" <table id="package-info-events-table"
data-classes="table table-hover" data-classes="table table-hover"
data-sortable="true" data-sortable="true"
@ -77,8 +77,10 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal" hidden><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button> {% if not auth.enabled or auth.username is not none %}
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal" hidden><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button> <button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
{% endif %}
<button type="button" class="btn btn-secondary" onclick="showPackageInfo()"><i class="bi bi-arrow-clockwise"></i><span class="d-none d-sm-inline"> reload</span></button> <button type="button" class="btn btn-secondary" onclick="showPackageInfo()"><i class="bi bi-arrow-clockwise"></i><span class="d-none d-sm-inline"> reload</span></button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button> <button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bi bi-x"></i><span class="d-none d-sm-inline"> close</span></button>
</div> </div>
@ -87,33 +89,35 @@
</div> </div>
<script> <script>
const packageInfoModal = $("#package-info-modal"); const packageInfoModal = document.getElementById("package-info-modal");
const packageInfoModalHeader = $("#package-info-modal-header"); const packageInfoModalHeader = document.getElementById("package-info-modal-header");
const packageInfo = $("#package-info"); const packageInfo = document.getElementById("package-info");
const packageInfoLogsInput = $("#package-info-logs-input"); const packageInfoLogsInput = document.getElementById("package-info-logs-input");
const packageInfoLogsCopyButton = $("#package-info-logs-copy-button"); const packageInfoLogsCopyButton = document.getElementById("package-info-logs-copy-button");
const packageInfoChangesInput = $("#package-info-changes-input"); const packageInfoChangesInput = document.getElementById("package-info-changes-input");
const packageInfoChangesCopyButton = $("#package-info-changes-copy-button"); const packageInfoChangesCopyButton = document.getElementById("package-info-changes-copy-button");
const packageInfoEventsTable = $("#package-info-events-table"); // so far bootstrap-table only operates with jquery elements
const packageInfoEventsTable = $(document.getElementById("package-info-events-table"));
const packageInfoEventsUpdateChartCanvas = document.getElementById("package-info-events-update-chart"); const packageInfoEventsUpdateChartCanvas = document.getElementById("package-info-events-update-chart");
let packageInfoEventsUpdateChart = null; let packageInfoEventsUpdateChart = null;
const packageInfoAurUrl = $("#package-info-aur-url"); const packageInfoAurUrl = document.getElementById("package-info-aur-url");
const packageInfoDepends = $("#package-info-depends"); const packageInfoDepends = document.getElementById("package-info-depends");
const packageInfoGroups = $("#package-info-groups"); const packageInfoGroups = document.getElementById("package-info-groups");
const packageInfoLicenses = $("#package-info-licenses"); const packageInfoLicenses = document.getElementById("package-info-licenses");
const packageInfoPackager = $("#package-info-packager"); const packageInfoPackager = document.getElementById("package-info-packager");
const packageInfoPackages = $("#package-info-packages"); const packageInfoPackages = document.getElementById("package-info-packages");
const packageInfoUpstreamUrl = $("#package-info-upstream-url"); const packageInfoUpstreamUrl = document.getElementById("package-info-upstream-url");
const packageInfoVersion = $("#package-info-version"); const packageInfoVersion = document.getElementById("package-info-version");
const packageInfoVariablesBlock = $("#package-info-variables-block"); const packageInfoVariablesBlock = document.getElementById("package-info-variables-block");
const packageInfoVariablesDiv = $("#package-info-variables-div"); const packageInfoVariablesDiv = document.getElementById("package-info-variables-div");
function clearChart() { function clearChart() {
packageInfoEventsUpdateChartCanvas.hidden = true;
if (packageInfoEventsUpdateChart) { if (packageInfoEventsUpdateChart) {
packageInfoEventsUpdateChart.data = {}; packageInfoEventsUpdateChart.data = {};
packageInfoEventsUpdateChart.update(); packageInfoEventsUpdateChart.update();
@ -121,20 +125,15 @@
} }
async function copyChanges() { async function copyChanges() {
const changes = packageInfoChangesInput.text(); const changes = packageInfoChangesInput.textContent;
await copyToClipboard(changes, packageInfoChangesCopyButton); await copyToClipboard(changes, packageInfoChangesCopyButton);
} }
async function copyLogs() { async function copyLogs() {
const logs = packageInfoLogsInput.text(); const logs = packageInfoLogsInput.textContent;
await copyToClipboard(logs, packageInfoLogsCopyButton); await copyToClipboard(logs, packageInfoLogsCopyButton);
} }
function hideInfoControls(hidden) {
packageInfoRemoveButton.attr("hidden", hidden);
packageInfoUpdateButton.attr("hidden", hidden);
}
function highlight(element) { function highlight(element) {
delete element.dataset.highlighted; delete element.dataset.highlighted;
hljs.highlightElement(element); hljs.highlightElement(element);
@ -178,7 +177,7 @@
variableInput.appendChild(variableValueInput); variableInput.appendChild(variableValueInput);
variableInput.appendChild(variableButtonRemove); variableInput.appendChild(variableButtonRemove);
packageInfoVariablesDiv.append(variableInput); packageInfoVariablesDiv.appendChild(variableInput);
} }
function loadChanges(packageBase, onFailure) { function loadChanges(packageBase, onFailure) {
@ -192,8 +191,8 @@
dataType: "json", dataType: "json",
success: response => { success: response => {
const changes = response.changes; const changes = response.changes;
packageInfoChangesInput.text(changes || ""); packageInfoChangesInput.textContent = changes ?? "";
packageInfoChangesInput.map((_, el) => highlight(el)); highlight(packageInfoChangesInput);
}, },
error: onFailure, error: onFailure,
}); });
@ -222,6 +221,9 @@
}; };
}); });
packageInfoEventsTable.bootstrapTable("load", events);
packageInfoEventsTable.bootstrapTable("hideLoading");
if (packageInfoEventsUpdateChart) { if (packageInfoEventsUpdateChart) {
const chart = response.filter(event => event.event === "package-updated"); const chart = response.filter(event => event.event === "package-updated");
packageInfoEventsUpdateChart.config.data = { packageInfoEventsUpdateChart.config.data = {
@ -235,9 +237,7 @@
}; };
packageInfoEventsUpdateChart.update(); packageInfoEventsUpdateChart.update();
} }
packageInfoEventsUpdateChart.hidden = !events.length;
packageInfoEventsTable.bootstrapTable("load", events);
packageInfoEventsTable.bootstrapTable("hideLoading");
}, },
error: onFailure, error: onFailure,
}); });
@ -256,8 +256,8 @@
const logs = response.map(log_record => { const logs = response.map(log_record => {
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`; return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`;
}); });
packageInfoLogsInput.text(logs.join("\n")); packageInfoLogsInput.textContent = logs.join("\n");
packageInfoLogsInput.map((_, el) => highlight(el)); highlight(packageInfoLogsInput);
}, },
error: onFailure, error: onFailure,
}); });
@ -291,34 +291,29 @@
) )
).sort(); ).sort();
packageInfo.text(`${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`); packageInfo.textContent = `${description.package.base} ${description.status.status} at ${new Date(1000 * description.status.timestamp).toISOStringShort()}`;
packageInfoModalHeader.removeClass(); packageInfoModalHeader.classList.remove(...packageInfoModalHeader.classList);
packageInfoModalHeader.addClass("modal-header"); packageInfoModalHeader.classList.add("modal-header");
headerClass(description.status.status).forEach(clz => packageInfoModalHeader.addClass(clz)); headerClass(description.status.status).forEach(clz => packageInfoModalHeader.classList.add(clz));
packageInfoAurUrl.html(aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : ""); packageInfoAurUrl.innerHTML = aurUrl ? safeLink(aurUrl, aurUrl, "AUR link").outerHTML : "";
packageInfoDepends.html(listToTable( packageInfoDepends.innerHTML = listToTable(
Object.values(description.package.packages) Object.values(description.package.packages)
.reduce((accumulator, currentValue) => { .reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue.depends.filter(v => packages.indexOf(v) === -1)) return accumulator.concat(currentValue.depends.filter(v => packages.indexOf(v) === -1))
.concat(currentValue.make_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (make)`)) .concat(currentValue.make_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (make)`))
.concat(currentValue.opt_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (optional)`)); .concat(currentValue.opt_depends.filter(v => packages.indexOf(v) === -1).map(v => `${v} (optional)`));
}, []) }, [])
)); );
packageInfoGroups.html(listToTable(extractListProperties(description.package, "groups"))); packageInfoGroups.innerHTML = listToTable(extractListProperties(description.package, "groups"));
packageInfoLicenses.html(listToTable(extractListProperties(description.package, "licenses"))); packageInfoLicenses.innerHTML = listToTable(extractListProperties(description.package, "licenses"));
packageInfoPackager.text(description.package.packager); packageInfoPackager.textContent = description.package.packager;
packageInfoPackages.html(listToTable(packages)); packageInfoPackages.innerHTML = listToTable(packages);
packageInfoUpstreamUrl.html(upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>")); packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>");
packageInfoVersion.text(description.package.version); packageInfoVersion.textContent = description.package.version;
hideInfoControls(false);
},
error: (jqXHR, _, errorThrown) => {
hideInfoControls(true);
onFailure(jqXHR, null, errorThrown);
}, },
error: onFailure,
}); });
} }
@ -328,30 +323,30 @@
type: "GET", type: "GET",
dataType: "json", dataType: "json",
success: response => { success: response => {
packageInfoVariablesDiv.empty(); packageInfoVariablesDiv.replaceChildren();
response.map(patch => insertVariable(packageBase, patch)); response.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.attr("hidden", response.length === 0); packageInfoVariablesBlock.hidden = !response.length;
}, },
error: onFailure, error: onFailure,
}); });
} }
function packageInfoRemove() { function packageInfoRemove() {
const packageBase = packageInfoModal.data("package"); const packageBase = packageInfoModal.package;
if (packageBase) return packagesRemove([packageBase]); if (packageBase) return packagesRemove([packageBase]);
} }
function packageInfoUpdate() { function packageInfoUpdate() {
const packageBase = packageInfoModal.data("package"); const packageBase = packageInfoModal.package;
if (packageBase) return packagesAdd(packageBase, [], repository); if (packageBase) return packagesAdd(packageBase, [], repository);
} }
function showPackageInfo(packageBase) { function showPackageInfo(packageBase) {
const isPackageBaseSet = packageBase !== undefined; const isPackageBaseSet = packageBase !== undefined;
if (isPackageBaseSet) if (isPackageBaseSet)
packageInfoModal.data("package", packageBase); // set package base as currently used packageInfoModal.package = packageBase; // set package base as currently used
else else
packageBase = packageInfoModal.data("package"); // read package base from the current window attribute packageBase = packageInfoModal.package; // read package base from the current window attribute
const onFailure = (jqXHR, _, errorThrown) => { const onFailure = (jqXHR, _, errorThrown) => {
if (isPackageBaseSet) { if (isPackageBaseSet) {
@ -366,10 +361,11 @@
loadChanges(packageBase, onFailure); loadChanges(packageBase, onFailure);
loadEvents(packageBase, onFailure); loadEvents(packageBase, onFailure);
if (isPackageBaseSet) packageInfoModal.modal("show"); if (isPackageBaseSet)
bootstrap.Modal.getOrCreateInstance(packageInfoModal).show();
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
packageInfoEventsUpdateChart = new Chart(packageInfoEventsUpdateChartCanvas, { packageInfoEventsUpdateChart = new Chart(packageInfoEventsUpdateChartCanvas, {
type: "line", type: "line",
data: {}, data: {},
@ -378,27 +374,23 @@
}, },
}); });
packageInfoModal.on("hidden.bs.modal", _ => { packageInfoModal.addEventListener("hidden.bs.modal", _ => {
packageInfoAurUrl.empty(); packageInfoAurUrl.textContent = "";
packageInfoDepends.empty(); packageInfoDepends.textContent = "";
packageInfoGroups.empty(); packageInfoGroups.textContent = "";
packageInfoLicenses.empty(); packageInfoLicenses.textContent = "";
packageInfoPackager.empty(); packageInfoPackager.textContent = "";
packageInfoPackages.empty(); packageInfoPackages.textContent = "";
packageInfoUpstreamUrl.empty(); packageInfoUpstreamUrl.textContent = "";
packageInfoVersion.empty(); packageInfoVersion.textContent = "";
packageInfoVariablesBlock.attr("hidden", true); packageInfoVariablesBlock.hidden = true;
packageInfoVariablesDiv.empty(); packageInfoVariablesDiv.replaceChildren();
packageInfoLogsInput.empty(); packageInfoLogsInput.textContent = "";
packageInfoChangesInput.empty(); packageInfoChangesInput.textContent = "";
packageInfoEventsTable.bootstrapTable("load", []); packageInfoEventsTable.bootstrapTable("load", []);
clearChart(); clearChart();
packageInfoModal.trigger("reset");
hideInfoControls(true);
}); });
}); });
</script> </script>

View File

@ -43,14 +43,14 @@
const packages = packageRebuildDependencyInput.value; const packages = packageRebuildDependencyInput.value;
const repository = getRepositorySelector(packageRebuildRepositoryInput); const repository = getRepositorySelector(packageRebuildRepositoryInput);
if (packages) { if (packages) {
bootstrap.Modal.getInstance(packageRebuildModal).hide(); bootstrap.Modal.getOrCreateInstance(packageRebuildModal).hide();
const onSuccess = update => `Repository rebuild has been run for packages which depend on ${update}`; const onSuccess = update => `Repository rebuild has been run for packages which depend on ${update}`;
const onFailure = error => `Repository rebuild failed: ${error}`; const onFailure = error => `Repository rebuild failed: ${error}`;
doPackageAction("/api/v1/service/rebuild", [packages], repository, onSuccess, onFailure); doPackageAction("/api/v1/service/rebuild", [packages], repository, onSuccess, onFailure);
} }
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
packageRebuildModal.addEventListener("shown.bs.modal", _ => { packageRebuildModal.addEventListener("shown.bs.modal", _ => {
const option = packageRebuildRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`); const option = packageRebuildRepositoryInput.querySelector(`option[value="${repository.architecture}-${repository.repository}"]`);
if (option) option.selected = "selected"; if (option) option.selected = "selected";

View File

@ -1,19 +1,14 @@
<script> <script>
const keyImportButton = $("#key-import-button"); const packageRemoveButton = document.getElementById("package-remove-button");
const packageAddButton = $("#package-add-button"); const packageUpdateButton = document.getElementById("package-update-button");
const packageRebuildButton = $("#package-rebuild-button");
const packageRemoveButton = $("#package-remove-button");
const packageUpdateButton = $("#package-update-button");
const packageInfoRemoveButton = $("#package-info-remove-button");
const packageInfoUpdateButton = $("#package-info-update-button");
let repository = null; let repository = null;
const table = $("#packages"); // so far bootstrap-table only operates with jquery elements
const table = $(document.getElementById("packages"));
const statusBadge = $("#badge-status"); const statusBadge = document.getElementById("badge-status");
const versionBadge = $("#badge-version"); const versionBadge = document.getElementById("badge-version");
function doPackageAction(uri, packages, repository, successText, failureText, data) { function doPackageAction(uri, packages, repository, successText, failureText, data) {
const queryParams = $.param({ const queryParams = $.param({
@ -49,10 +44,10 @@
} }
function getRepositorySelector(selector) { function getRepositorySelector(selector) {
const selected = selector.find(":selected"); const selected = selector.options[selector.selectedIndex];
return { return {
architecture: selected.data("architecture"), architecture: selected.getAttribute("data-architecture"),
repository: selected.data("repository"), repository: selected.getAttribute("data-repository"),
}; };
} }
@ -60,14 +55,6 @@
return table.bootstrapTable("getSelections").map(row => row.id); return table.bootstrapTable("getSelections").map(row => row.id);
} }
function hideControls(hidden) {
keyImportButton.attr("hidden", hidden);
packageAddButton.attr("hidden", hidden);
packageRebuildButton.attr("hidden", hidden);
packageRemoveButton.attr("hidden", hidden);
packageUpdateButton.attr("hidden", hidden);
}
function packagesRemove(packages) { function packagesRemove(packages) {
packages = packages ?? getSelection(); packages = packages ?? getSelection();
const onSuccess = update => `Packages ${update} have been removed`; const onSuccess = update => `Packages ${update} have been removed`;
@ -125,7 +112,6 @@
table.bootstrapTable("load", payload); table.bootstrapTable("load", payload);
table.bootstrapTable("uncheckAll"); table.bootstrapTable("uncheckAll");
table.bootstrapTable("hideLoading"); table.bootstrapTable("hideLoading");
hideControls(false);
}, },
error: (jqXHR, _, errorThrown) => { error: (jqXHR, _, errorThrown) => {
if ((jqXHR.status === 401) || (jqXHR.status === 403)) { if ((jqXHR.status === 401) || (jqXHR.status === 403)) {
@ -139,7 +125,6 @@
const message = error => `Could not load list of packages: ${error}`; const message = error => `Could not load list of packages: ${error}`;
showFailure("Load failure", message, jqXHR, errorThrown); showFailure("Load failure", message, jqXHR, errorThrown);
} }
hideControls(true);
}, },
}); });
@ -152,23 +137,23 @@
type: "GET", type: "GET",
dataType: "json", dataType: "json",
success: response => { success: response => {
versionBadge.html(`<i class="bi bi-github"></i> ahriman ${safe(response.version)}`); versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(response.version)}`;
statusBadge statusBadge.classList.remove(...statusBadge.classList);
.popover("dispose") statusBadge.classList.add("btn");
.attr("data-bs-content", `${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOStringShort()}`) statusBadge.classList.add(badgeClass(response.status.status));
.popover();
statusBadge.removeClass(); const popover = bootstrap.Popover.getOrCreateInstance(statusBadge);
statusBadge.addClass("btn"); popover.dispose();
statusBadge.addClass(badgeClass(response.status.status)); statusBadge.dataset.bsContent = `${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOStringShort()}`;
bootstrap.Popover.getOrCreateInstance(statusBadge);
}, },
}); });
} }
function selectRepository() { function selectRepository() {
const fragment = window.location.hash.replace("#", "") || "{{ repositories[0].id }}"; const fragment = window.location.hash.replace("#", "") || "{{ repositories[0].id }}";
const element = $(`#${fragment}-link`); document.getElementById(`${fragment}-link`).click();
element.click();
} }
function statusFormat(value) { function statusFormat(value) {
@ -182,20 +167,21 @@
return {classes: cellClass(value)}; return {classes: cellClass(value)};
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
$("#repositories a").on("click", event => { document.querySelectorAll("#repositories a").forEach(element => {
const element = event.target; element.onclick = _ => {
repository = { repository = {
architecture: element.dataset.architecture, architecture: element.dataset.architecture,
repository: element.dataset.repository, repository: element.dataset.repository,
};
if (packageUpdateButton) packageUpdateButton.innerHTML = `<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`;
bootstrap.Tab.getOrCreateInstance(document.getElementById(element.id)).show();
reload();
}; };
packageUpdateButton.html(`<i class="bi bi-play"></i> update<span class="d-none d-sm-inline"> ${safe(repository.repository)} (${safe(repository.architecture)})</span>`);
$(`#${element.id}`).tab("show");
reload();
}); });
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", _ => { table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", _ => {
packageRemoveButton.prop("disabled", !table.bootstrapTable("getSelections").length); if (packageRemoveButton) packageRemoveButton.disabled = !table.bootstrapTable("getSelections").length;
}); });
table.on("click-row.bs.table", (self, data, row, cell) => { table.on("click-row.bs.table", (self, data, row, cell) => {
if (0 === cell || "base" === cell) { if (0 === cell || "base" === cell) {
@ -204,7 +190,7 @@
} else showPackageInfo(data.id); } else showPackageInfo(data.id);
}); });
table.on("created-controls.bs.table", _ => { table.on("created-controls.bs.table", _ => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp"); const pickerInput = $(document.querySelector(".bootstrap-table-filter-control-timestamp"));
pickerInput.daterangepicker({ pickerInput.daterangepicker({
autoUpdateInput: false, autoUpdateInput: false,
locale: { locale: {
@ -223,7 +209,7 @@
}); });
}); });
statusBadge.popover(); bootstrap.Popover.getOrCreateInstance(statusBadge);
selectRepository(); selectRepository();
}); });
</script> </script>

View File

@ -105,13 +105,13 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
</div> </div>
<script> <script>
const table = $("#packages"); const table = $(document.getElementById("packages"));
const pacmanConf = $("#pacman-conf"); const pacmanConf = document.getElementById("pacman-conf");
const pacmanConfCopyButton = $("#copy-btn"); const pacmanConfCopyButton = document.getElementById("copy-btn");
async function copyPacmanConf() { async function copyPacmanConf() {
const conf = pacmanConf.text(); const conf = pacmanConf.textContent;
await copyToClipboard(conf, pacmanConfCopyButton); await copyToClipboard(conf, pacmanConfCopyButton);
} }
@ -127,9 +127,9 @@ SigLevel = Database{% if has_repo_signed %}Required{% else %}Never{% endif %} Pa
return extractDataList(table.bootstrapTable("getData"), "licenses"); return extractDataList(table.bootstrapTable("getData"), "licenses");
} }
$(_ => { document.addEventListener("DOMContentLoaded", _ => {
table.on("created-controls.bs.table", _ => { table.on("created-controls.bs.table", _ => {
const pickerInput = $(".bootstrap-table-filter-control-timestamp"); const pickerInput = $(document.querySelector(".bootstrap-table-filter-control-timestamp"));
pickerInput.daterangepicker({ pickerInput.daterangepicker({
autoUpdateInput: false, autoUpdateInput: false,
locale: { locale: {

View File

@ -22,17 +22,7 @@
<script> <script>
async function copyToClipboard(text, button) { async function copyToClipboard(text, button) {
if (navigator.clipboard === undefined) { await navigator.clipboard.writeText(text);
const input = document.createElement("textarea");
input.innerHTML = text;
document.body.appendChild(input);
input.select();
document.execCommand("copy");
document.body.removeChild(input);
} else {
await navigator.clipboard.writeText(text);
}
button.innerHTML = "<i class=\"bi bi-clipboard-check\"></i> copied"; button.innerHTML = "<i class=\"bi bi-clipboard-check\"></i> copied";
setTimeout(()=> { setTimeout(()=> {
button.innerHTML = "<i class=\"bi bi-clipboard\"></i> copy"; button.innerHTML = "<i class=\"bi bi-clipboard\"></i> copy";