dynamic html load (#63)

* dynamic html load
* split by classes
This commit is contained in:
2022-05-20 22:29:36 +03:00
committed by GitHub
parent 5674b7b388
commit 47de715d7d
72 changed files with 720 additions and 706 deletions

View File

@ -0,0 +1,28 @@
<div id="failed-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-danger">
<h4 class="modal-title">failed</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<p>Packages update has failed.</p>
<p id="error-details"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
</div>
</div>
</div>
</div>
<script>
const failedForm = $("#failed-form");
const errorDetails = $("#error-details");
failedForm.on("hidden.bs.modal", () => { reload(); });
function showFailure(details) {
errorDetails.text(details);
failedForm.modal("show");
}
</script>

View File

@ -26,4 +26,4 @@
</form>
</div>
</div>
</div>
</div>

View File

@ -1,60 +0,0 @@
<div id="addForm" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">add new packages</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="package" class="col-sm-2 col-form-label">package</label>
<div class="col-sm-10">
<input id="package" type="text" list="knownPackages" class="form-control" placeholder="AUR package" name="package" required>
<datalist id="knownPackages"></datalist>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">close</button>
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="requestPackages()">request</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="addPackages()">add</button>
</div>
</div>
</div>
</div>
<div id="failedForm" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-danger">
<h4 class="modal-title">failed</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<p>Packages update has failed.</p>
<p id="errorDetails"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
</div>
</div>
</div>
</div>
<div id="successForm" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-success">
<h4 class="modal-title">success</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<p>Packages update has been run.</p>
<ul id="successDetails"></ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
</div>
</div>
</div>
</div>

View File

@ -1,95 +0,0 @@
<script>
const $remove = $("#remove");
const $update = $("#update");
const $table = $("#packages");
$table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table",
function () {
$remove.prop("disabled", !$table.bootstrapTable("getSelections").length);
$update.prop("disabled", !$table.bootstrapTable("getSelections").length);
})
const $successForm = $("#successForm");
const $successDetails = $("#successDetails");
$successForm.on("hidden.bs.modal", function() { window.location.reload(); });
const $failedForm = $("#failedForm");
const $errorDetails = $("#errorDetails");
$failedForm.on("hidden.bs.modal", function() { window.location.reload(); });
const $package = $("#package");
const $knownPackages = $("#knownPackages");
$package.keyup(function () {
const $this = $(this);
clearTimeout($this.data("timeout"));
$this.data("timeout", setTimeout($.proxy(function () {
const $value = $package.val();
$.ajax({
url: "/service-api/v1/search",
data: {"for": $value},
type: "GET",
dataType: "json",
success: function (resp) {
const $options = resp.map(function (pkg) {
const $option = document.createElement("option");
$option.value = pkg.package;
$option.innerText = `${pkg.package} (${pkg.description})`;
return $option;
});
$knownPackages.empty().append($options);
$this.focus();
},
})
}, this), 500));
})
function doPackageAction($uri, $packages) {
if ($packages.length === 0)
return;
$.ajax({
url: $uri,
data: JSON.stringify({packages: $packages}),
type: "POST",
contentType: "application/json",
success: function (_) {
const $details = $packages.map(function (pkg) {
const $li = document.createElement("li");
$li.innerText = pkg;
return $li;
});
$successDetails.empty().append($details);
$successForm.modal("show");
},
error: function (jqXHR, textStatus, errorThrown) {
$errorDetails.text(errorThrown);
$failedForm.modal("show");
},
})
}
function getSelection() {
return $.map($table.bootstrapTable("getSelections"), function(row) {
return row._data["package-base"];
})
}
function addPackages() {
const $packages = [$package.val()]
doPackageAction("/service-api/v1/add", $packages);
}
function requestPackages() {
const $packages = [$package.val()]
doPackageAction("/service-api/v1/request", $packages);
}
function removePackages() { doPackageAction("/service-api/v1/remove", getSelection()); }
function updatePackages() { doPackageAction("/service-api/v1/add", getSelection()); }
$(function () {
$table.bootstrapTable("uncheckAll");
})
</script>

View File

@ -0,0 +1,62 @@
<div id="add-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">add new packages</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="package" class="col-sm-2 col-form-label">package</label>
<div class="col-sm-10">
<input id="package-form" type="text" list="known-packages-dlist" class="form-control" placeholder="AUR package" name="package" required>
<datalist id="known-packages-dlist"></datalist>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">close</button>
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="requestPackages()">request</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="addPackages()">add</button>
</div>
</div>
</div>
</div>
<script>
const packageInput = $("#package-form");
const knownPackages = $("#known-packages-dlist");
packageInput.keyup(() => {
clearTimeout(packageInput.data("timeout"));
packageInput.data("timeout", setTimeout($.proxy(() => {
const value = packageInput.val();
$.ajax({
url: "/service-api/v1/search",
data: {"for": value},
type: "GET",
dataType: "json",
success: response => {
const options = response.map(pkg => {
const option = document.createElement("option");
option.value = pkg.package;
option.innerText = `${pkg.package} (${pkg.description})`;
return option;
});
knownPackages.empty().append(options);
packageInput.focus();
},
})
}, this), 500));
});
function addPackages() {
const packages = [packageInput.val()]
doPackageAction("/service-api/v1/add", packages);
}
function requestPackages() {
const packages = [packageInput.val()]
doPackageAction("/service-api/v1/request", packages);
}
</script>

View File

@ -0,0 +1,28 @@
<div id="success-form" tabindex="-1" role="dialog" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header bg-success">
<h4 class="modal-title">success</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
</div>
<div class="modal-body">
<p>Packages update has been run.</p>
<ul id="success-details"></ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">close</button>
</div>
</div>
</div>
</div>
<script>
const successForm = $("#success-form");
const successDetails = $("#success-details");
successForm.on("hidden.bs.modal", () => { reload(); });
function showSuccess(details) {
successDetails.empty().append(details);
successForm.modal("show");
}
</script>

View File

@ -0,0 +1,147 @@
<script>
const addButton = $("#add-btn");
const removeButton = $("#remove-btn");
const updateButton = $("#update-btn");
const table = $("#packages");
table.on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table",
() => {
removeButton.prop("disabled", !table.bootstrapTable("getSelections").length);
updateButton.prop("disabled", !table.bootstrapTable("getSelections").length);
});
const architectureBadge = $("#badge-architecture");
const repositoryBadge = $("#badge-repository");
const statusBadge = $("#badge-status");
const versionBadge = $("#badge-version");
function doPackageAction(uri, packages) {
if (packages.length === 0)
return;
$.ajax({
url: uri,
data: JSON.stringify({packages: packages}),
type: "POST",
contentType: "application/json",
success: _ => {
const details = packages.map(pkg => {
const li = document.createElement("li");
li.innerText = pkg;
return li;
});
showSuccess(details);
},
error: (jqXHR, _, errorThrown) => { showFailure(errorThrown); },
})
}
function getSelection() {
return table.bootstrapTable("getSelections").map(row => { return row.id; });
}
function removePackages() { doPackageAction("/service-api/v1/remove", getSelection()); }
function updatePackages() { doPackageAction("/service-api/v1/add", getSelection()); }
function hideControls(hidden) {
addButton.attr("hidden", hidden);
removeButton.attr("hidden", hidden);
updateButton.attr("hidden", hidden);
}
function reload() {
table.bootstrapTable("showLoading");
$.ajax({
url: "/status-api/v1/packages",
type: "GET",
dataType: "json",
success: response => {
const extractListProperties = (description, property) => {
return Object.values(description.packages).map(pkg => {
return pkg[property];
}).reduce((left, right) => { return left.concat(right); }, []);
};
const listToTable = data => { return Array.from(new Set(data)).sort().join("<br>"); };
const payload = response.map(description => {
const package_base = description.package.base;
const web_url = description.package.remote?.web_url;
return {
id: description.package.base,
base: web_url ? `<a href="${web_url}" title="${package_base}">${package_base}</a>` : package_base,
version: description.package.version,
packages: listToTable(Object.keys(description.package.packages)),
groups: listToTable(extractListProperties(description.package, "groups")),
licenses: listToTable(extractListProperties(description.package, "licenses")),
timestamp: new Date(1000 * description.status.timestamp).toISOString(),
status: description.status.status
}
});
table.bootstrapTable("load", payload);
table.bootstrapTable("uncheckAll");
table.bootstrapTable("hideLoading");
hideControls(false);
},
error: (jqXHR, _, errorThrown) => {
hideControls(true);
if ((jqXHR.status === 401) || (jqXHR.status === 403)) {
// authorization error
const text = "In order to see statuses you must login first.";
table.find("tr.unauthorized").remove();
table.find("tbody").append(`<tr class="unauthorized"><td colspan="100%">${text}</td></tr>`);
table.bootstrapTable("hideLoading");
} else {
// other errors
showFailure(errorThrown);
}
},
});
$.ajax({
url: "/status-api/v1/status",
type: "GET",
dataType: "json",
success: response => {
const badgeColor = status => {
if (status === "pending") return "yellow";
if (status === "building") return "yellow";
if (status === "failed") return "critical";
if (status === "success") return "success";
return "inactive";
};
architectureBadge
.attr("src", `https://img.shields.io/badge/architecture-${response.architecture}-informational`)
.attr("alt", response.architecture);
repositoryBadge
.attr("src", `https://img.shields.io/badge/repository-${response.repository.replace(/-/g, "--")}-informational`)
.attr("alt", response.repository);
statusBadge
.attr("src", `https://img.shields.io/badge/service%20status-${response.status.status}-${badgeColor(response.status.status)}`)
.attr("alt", response.status.status)
.attr("title", `at ${new Date(1000 * response.status.timestamp).toISOString()}`);
versionBadge
.attr("src", `https://img.shields.io/badge/version-${response.version}-informational`)
.attr("alt", response.version);
},
});
}
function statusFormat(value) {
const cellClass = status => {
if (status === "pending") return "table-warning";
if (status === "building") return "table-warning";
if (status === "failed") return "table-danger";
if (status === "success") return "table-success";
return "table-secondary";
};
return {classes: cellClass(value)};
}
$(() => {
table.bootstrapTable({});
reload();
})
</script>