diff --git a/package/share/ahriman/templates/build-status/alerts.jinja2 b/package/share/ahriman/templates/build-status/alerts.jinja2
index 54f98567..ec70d464 100644
--- a/package/share/ahriman/templates/build-status/alerts.jinja2
+++ b/package/share/ahriman/templates/build-status/alerts.jinja2
@@ -2,7 +2,7 @@
const alertPlaceholder = document.getElementById("alert-placeholder");
function createAlert(title, message, clz, action, id) {
- if (!id) id = $.md5(title + message); // MD5 id from the content
+ id ??= md5(title + message); // MD5 id from the content
if (alertPlaceholder.querySelector(`#alert-${id}`)) return; // check if there are duplicates
const wrapper = document.createElement("div");
@@ -32,12 +32,12 @@
toast.show();
}
- function showFailure(title, description, jqXHR, errorThrown) {
+ function showFailure(title, description, error) {
let details;
try {
- details = JSON.parse(jqXHR.responseText).error; // execution handler json error response
+ details = JSON.parse(error.text).error; // execution handler json error response
} catch (_) {
- details = errorThrown;
+ details = error.text ?? error;
}
createAlert(title, description(details), "text-bg-danger");
}
diff --git a/package/share/ahriman/templates/build-status/key-import-modal.jinja2 b/package/share/ahriman/templates/build-status/key-import-modal.jinja2
index 4a9f9bb3..ca18c0e4 100644
--- a/package/share/ahriman/templates/build-status/key-import-modal.jinja2
+++ b/package/share/ahriman/templates/build-status/key-import-modal.jinja2
@@ -55,13 +55,17 @@
const server = keyImportServerInput.value;
if (key && server) {
- $.ajax({
- url: "/api/v1/service/pgp",
- data: {"key": key, "server": server},
- type: "GET",
- dataType: "json",
- success: response => { keyImportBodyInput.textContent = response.key; },
- });
+ makeRequest(
+ "/api/v1/service/pgp",
+ {
+ query: {
+ key: key,
+ server: server,
+ },
+ convert: response => response.json(),
+ },
+ data => { keyImportBodyInput.textContent = data.key; },
+ );
}
}
@@ -70,20 +74,24 @@
const server = keyImportServerInput.value;
if (key && server) {
- $.ajax({
- url: "/api/v1/service/pgp",
- data: JSON.stringify({key: key, server: server}),
- type: "POST",
- contentType: "application/json",
- success: _ => {
+ makeRequest(
+ "/api/v1/service/pgp",
+ {
+ method: "POST",
+ json: {
+ key: key,
+ server: server,
+ },
+ },
+ _ => {
bootstrap.Modal.getOrCreateInstance(keyImportModal).hide();
showSuccess("Success", `Key ${key} has been imported`);
},
- error: (jqXHR, _, errorThrown) => {
+ error => {
const message = _ => `Could not import key ${key} from ${server}`;
- showFailure("Action failed", message, jqXHR, errorThrown);
+ showFailure("Action failed", message, error);
},
- });
+ );
}
}
diff --git a/package/share/ahriman/templates/build-status/login-modal.jinja2 b/package/share/ahriman/templates/build-status/login-modal.jinja2
index a4412ced..ec137d53 100644
--- a/package/share/ahriman/templates/build-status/login-modal.jinja2
+++ b/package/share/ahriman/templates/build-status/login-modal.jinja2
@@ -46,23 +46,27 @@
const username = loginUsernameInput.value;
if (username && password) {
- $.ajax({
- url: "/api/v1/login",
- data: JSON.stringify({username: username, password: password}),
- type: "POST",
- contentType: "application/json",
- success: _ => {
+ makeRequest(
+ "/api/v1/login",
+ {
+ method: "POST",
+ json: {
+ username: username,
+ password: password,
+ },
+ },
+ _ => {
bootstrap.Modal.getOrCreateInstance(loginModal).hide();
showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/");
},
- error: (jqXHR, _, errorThrown) => {
+ error => {
const message = _ =>
username === "admin" && password === "admin"
? "You've entered a password for user \"root\", did you make a typo in username?"
: `Could not login as ${username}`;
- showFailure("Login error", message, jqXHR, errorThrown);
+ showFailure("Login error", message, error);
},
- });
+ );
}
}
diff --git a/package/share/ahriman/templates/build-status/package-add-modal.jinja2 b/package/share/ahriman/templates/build-status/package-add-modal.jinja2
index 5a7638fa..328f6b19 100644
--- a/package/share/ahriman/templates/build-status/package-add-modal.jinja2
+++ b/package/share/ahriman/templates/build-status/package-add-modal.jinja2
@@ -141,10 +141,15 @@
const value = packageAddInput.value;
if (value.length >= 3) {
- const query = new URLSearchParams({for: value});
- fetch(`/api/v1/service/search?${query.toString()}`)
- .then(response => response.json())
- .then(data => {
+ makeRequest(
+ "/api/v1/service/search",
+ {
+ query: {
+ for: value,
+ },
+ convert: response => response.json(),
+ },
+ data => {
const options = data.map(pkg => {
const option = document.createElement("option");
option.value = pkg.package;
@@ -152,8 +157,8 @@
return option;
});
packageAddKnownPackagesList.replaceChildren(...options);
- })
- .catch(_ => {});
+ },
+ );
}
}, 500);
});
diff --git a/package/share/ahriman/templates/build-status/package-info-modal.jinja2 b/package/share/ahriman/templates/build-status/package-info-modal.jinja2
index f92eedfc..bde98ad3 100644
--- a/package/share/ahriman/templates/build-status/package-info-modal.jinja2
+++ b/package/share/ahriman/templates/build-status/package-info-modal.jinja2
@@ -163,12 +163,13 @@
variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "";
variableButtonRemove.onclick = _ => {
- $.ajax({
- url: `/api/v1/packages/${packageBase}/patches/${variable.key}`,
- type: "DELETE",
- dataType: "json",
- success: _ => variableInput.remove(),
- });
+ makeRequest(
+ `/api/v1/packages/${packageBase}/patches/${variable.key}`,
+ {
+ method: "DELETE",
+ },
+ _ => variableInput.remove(),
+ );
};
// bring them together
@@ -181,39 +182,41 @@
}
function loadChanges(packageBase, onFailure) {
- $.ajax({
- url: `/api/v1/packages/${packageBase}/changes`,
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
+ makeRequest(
+ `/api/v1/packages/${packageBase}/changes`,
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- const changes = response.changes;
+ data => {
+ const changes = data.changes;
packageInfoChangesInput.textContent = changes ?? "";
highlight(packageInfoChangesInput);
},
- error: onFailure,
- });
+ onFailure,
+ );
}
function loadEvents(packageBase, onFailure) {
packageInfoEventsTable.bootstrapTable("showLoading");
clearChart();
- $.ajax({
- url: `/api/v1/events`,
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
- object_id: packageBase,
- limit: 30,
+ makeRequest(
+ "/api/v1/events",
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ object_id: packageBase,
+ limit: 30,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- const events = response.map(event => {
+ data => {
+ const events = data.map(event => {
return {
timestamp: new Date(1000 * event.created).toISOStringShort(),
event: event.event,
@@ -225,7 +228,7 @@
packageInfoEventsTable.bootstrapTable("hideLoading");
if (packageInfoEventsUpdateChart) {
- const chart = response.filter(event => event.event === "package-updated");
+ const chart = data.filter(event => event.event === "package-updated");
packageInfoEventsUpdateChart.config.data = {
labels: chart.map(event => new Date(1000 * event.created).toISOStringShort()),
datasets: [{
@@ -237,30 +240,31 @@
};
packageInfoEventsUpdateChart.update();
}
- packageInfoEventsUpdateChart.hidden = !events.length;
+ packageInfoEventsUpdateChartCanvas.hidden = !events.length;
},
- error: onFailure,
- });
+ onFailure,
+ );
}
function loadLogs(packageBase, onFailure) {
- $.ajax({
- url: `/api/v2/packages/${packageBase}/logs`,
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
+ makeRequest(
+ `/api/v2/packages/${packageBase}/logs`,
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- const logs = response.map(log_record => {
+ data => {
+ const logs = data.map(log_record => {
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`;
});
packageInfoLogsInput.textContent = logs.join("\n");
highlight(packageInfoLogsInput);
},
- error: onFailure,
- });
+ onFailure,
+ );
}
function loadPackage(packageBase, onFailure) {
@@ -272,16 +276,17 @@
return ["bg-secondary", "text-white"];
};
- $.ajax({
- url: `/api/v1/packages/${packageBase}`,
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
+ makeRequest(
+ `/api/v1/packages/${packageBase}`,
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- const description = response.find(Boolean);
+ data => {
+ const description = data.find(Boolean);
const packages = Object.keys(description.package.packages);
const aurUrl = description.package.remote.web_url;
const upstreamUrls = Array.from(
@@ -313,22 +318,23 @@
packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("
");
packageInfoVersion.textContent = description.package.version;
},
- error: onFailure,
- });
+ onFailure,
+ );
}
function loadPatches(packageBase, onFailure) {
- $.ajax({
- url: `/api/v1/packages/${packageBase}/patches`,
- type: "GET",
- dataType: "json",
- success: response => {
- packageInfoVariablesDiv.replaceChildren();
- response.map(patch => insertVariable(packageBase, patch));
- packageInfoVariablesBlock.hidden = !response.length;
+ makeRequest(
+ `/api/v1/packages/${packageBase}/patches`,
+ {
+ convert: response => response.json(),
},
- error: onFailure,
- });
+ data => {
+ packageInfoVariablesDiv.replaceChildren();
+ data.map(patch => insertVariable(packageBase, patch));
+ packageInfoVariablesBlock.hidden = !data.length;
+ },
+ onFailure,
+ );
}
function packageInfoRemove() {
@@ -348,10 +354,10 @@
else
packageBase = packageInfoModal.package; // read package base from the current window attribute
- const onFailure = (jqXHR, _, errorThrown) => {
+ const onFailure = error => {
if (isPackageBaseSet) {
- const message = error => `Could not load package ${packageBase} info: ${error}`;
- showFailure("Load failure", message, jqXHR, errorThrown);
+ const message = details => `Could not load package ${packageBase} info: ${details}`;
+ showFailure("Load failure", message, error);
}
};
diff --git a/package/share/ahriman/templates/build-status/table.jinja2 b/package/share/ahriman/templates/build-status/table.jinja2
index b5f282b6..88dd1a78 100644
--- a/package/share/ahriman/templates/build-status/table.jinja2
+++ b/package/share/ahriman/templates/build-status/table.jinja2
@@ -11,24 +11,24 @@
const versionBadge = document.getElementById("badge-version");
function doPackageAction(uri, packages, repository, successText, failureText, data) {
- const queryParams = $.param({
- architecture: repository.architecture,
- repository: repository.repository,
- }); // it will never be empty btw
-
- $.ajax({
- url: `${uri}?${queryParams}`,
- data: JSON.stringify(Object.assign({}, {packages: packages}, data || {})),
- type: "POST",
- contentType: "application/json",
- success: _ => {
+ makeRequest(
+ uri,
+ {
+ method: "POST",
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ json: Object.assign({}, {packages: packages}, data || {}),
+ },
+ _ => {
const message = successText(packages.join(", "));
showSuccess("Success", message);
},
- error: (jqXHR, _, errorThrown) => {
- showFailure("Action failed", failureText, jqXHR, errorThrown);
+ error => {
+ showFailure("Action failed", failureText, error);
},
- });
+ );
}
function filterListGroups() {
@@ -84,16 +84,17 @@
return "btn-outline-secondary";
};
- $.ajax({
- url: "/api/v1/packages",
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
+ makeRequest(
+ "/api/v1/packages",
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- const payload = response.map(description => {
+ data => {
+ const payload = data.map(description => {
const package_base = description.package.base;
const web_url = description.package.remote.web_url;
return {
@@ -113,8 +114,8 @@
table.bootstrapTable("uncheckAll");
table.bootstrapTable("hideLoading");
},
- error: (jqXHR, _, errorThrown) => {
- if ((jqXHR.status === 401) || (jqXHR.status === 403)) {
+ error => {
+ if ((error.status === 401) || (error.status === 403)) {
// authorization error
const text = "In order to see statuses you must login first.";
table.find("tr.unauthorized").remove();
@@ -122,33 +123,34 @@
table.bootstrapTable("hideLoading");
} else {
// other errors
- const message = error => `Could not load list of packages: ${error}`;
- showFailure("Load failure", message, jqXHR, errorThrown);
+ const message = details => `Could not load list of packages: ${details}`;
+ showFailure("Load failure", message, error);
}
},
- });
+ );
- $.ajax({
- url: "/api/v1/status",
- data: {
- architecture: repository.architecture,
- repository: repository.repository,
+ makeRequest(
+ "/api/v1/status",
+ {
+ query: {
+ architecture: repository.architecture,
+ repository: repository.repository,
+ },
+ convert: response => response.json(),
},
- type: "GET",
- dataType: "json",
- success: response => {
- versionBadge.innerHTML = ` ahriman ${safe(response.version)}`;
+ data => {
+ versionBadge.innerHTML = ` ahriman ${safe(data.version)}`;
statusBadge.classList.remove(...statusBadge.classList);
statusBadge.classList.add("btn");
- statusBadge.classList.add(badgeClass(response.status.status));
+ statusBadge.classList.add(badgeClass(data.status.status));
const popover = bootstrap.Popover.getOrCreateInstance(statusBadge);
popover.dispose();
- statusBadge.dataset.bsContent = `${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOStringShort()}`;
+ statusBadge.dataset.bsContent = `${data.status.status} at ${new Date(1000 * data.status.timestamp).toISOStringShort()}`;
bootstrap.Popover.getOrCreateInstance(statusBadge);
},
- });
+ );
}
function selectRepository() {
diff --git a/package/share/ahriman/templates/utils/bootstrap-scripts.jinja2 b/package/share/ahriman/templates/utils/bootstrap-scripts.jinja2
index f2321486..b27f0de8 100644
--- a/package/share/ahriman/templates/utils/bootstrap-scripts.jinja2
+++ b/package/share/ahriman/templates/utils/bootstrap-scripts.jinja2
@@ -1,5 +1,5 @@
-
+
@@ -66,6 +66,39 @@
.join("
");
}
+ function makeRequest(url, params, onSuccess, onFailure) {
+ const requestParams = {
+ method: params.method,
+ body: params.json ? JSON.stringify(params.json) : params.json,
+ headers: {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ },
+ };
+ if (params.query) {
+ const query = new URLSearchParams(params.query);
+ url += `?${query.toString()}`;
+ }
+ convert = params.convert ?? (response => response.text());
+
+ return fetch(url, requestParams)
+ .then(response => {
+ if (response.ok) {
+ return convert(response);
+ } else {
+ const error = new Error("Network request error");
+ error.status = response.status;
+ error.statusText = response.statusText;
+ return response.text().then(text => {
+ error.text = text;
+ throw error;
+ });
+ }
+ })
+ .then(data => onSuccess && onSuccess(data))
+ .catch(error => onFailure && onFailure(error));
+ }
+
function safe(string) {
return String(string)
.replace(/&/g, "&")