aboutsummaryrefslogtreecommitdiff
path: root/assets/js/activity.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/activity.js')
-rw-r--r--assets/js/activity.js351
1 files changed, 351 insertions, 0 deletions
diff --git a/assets/js/activity.js b/assets/js/activity.js
new file mode 100644
index 0000000..719ec47
--- /dev/null
+++ b/assets/js/activity.js
@@ -0,0 +1,351 @@
+
+const recentActivityDiv = document.getElementById("recent-activity-body");
+const recentActivityDivLimit = 1000;
+
+function addRecentActivityEntry(event, content, timestamp) {
+ const eventRow = document.createElement('tr');
+ eventRow.className = "event";
+ eventRow.innerHTML = `
+<td width="10%">${event}</td>
+<td>${content}</td>
+<td width="10%">${timestamp}</td>`;
+
+ recentActivityDiv.prepend(eventRow);
+ animateElementAddition(eventRow);
+
+ const childCount = recentActivityDiv.childElementCount;
+
+ if (childCount > recentActivityDivLimit) {
+ for (let index = recentActivityDivLimit; index < childCount; index++) {
+ recentActivityDiv.removeChild(
+ recentActivityDiv.children[index]
+ )
+ }
+ }
+}
+
+function animateElementAddition(e, color = "lightblue") {
+ e.style.backgroundColor = color;
+ e.style.lineHeight = "0px";
+ e.style.overflow = "hidden";
+ e.style.opacity = 0;
+
+ setTimeout(function() {
+ e.style.transition =
+ "background-color 1.2s ease-out, line-height 6s, opacity 0.3s ease-out";
+ e.style.backgroundColor = "";
+ e.style.lineHeight = "";
+ e.style.opacity = "";
+ }, 50);
+}
+
+function animateElementChange(e, color = "lightblue") {
+ e.style.transition = "background-color 0.6s ease-out";
+
+ setTimeout(function() {
+ e.style.backgroundColor = color;
+
+ setTimeout(function() {
+ e.style.backgroundColor = "";
+ }, 600);
+ }, 50);
+}
+
+function animateElementAndRemove(e, color) {
+ // TODO: This needs more work, as it needs to fit in with keeping the
+ // related bits that reference the number of builds up to date
+ e.remove();
+
+ // e.style.borderWidth = "20px;";
+ // e.style.borderStyle = "solid";
+ // e.style.borderColor = color;
+ // e.style.transition = "border 10s";
+ // e.addEventListener("transitionend", function() {
+ // e.remove();
+ // }, {once: true});
+
+ // setTimeout(function() {
+ // e.style.borderColor = "";
+ // }, 1000);
+}
+
+function buildDetailsFromDom(id) {
+ return document.getElementById("build-" + id).dataset;
+}
+
+function agentDetailsFromDom(id) {
+ return document.getElementById("agent-" + id).dataset;
+}
+
+function updateAgentBuildRelatedElements(agentId) {
+ const agentBuildsElement = document.getElementById(
+ "agent-" + agentId + "-builds"
+ );
+ const childCount = agentBuildsElement.childElementCount;
+
+ const noAllocatedBuildsElement = document.getElementById(
+ "agent-" + agentId + "-no-allocated-builds"
+ );
+ const plusXBuildsElement = document.getElementById(
+ "agent-" + agentId + "-plus-x-builds"
+ );
+
+
+ if (childCount == 0) {
+ noAllocatedBuildsElement.style.display = "block";
+ plusXBuildsElement.style.display = "none";
+
+ animateElementChange(noAllocatedBuildsElement);
+ } else {
+ for (let index = 0; index < Math.min(childCount, 4); index++) {
+ agentBuildsElement.children[index].style.display = "block";
+ }
+
+ if (childCount > 4) {
+ noAllocatedBuildsElement.style.display = "none";
+
+ plusXBuildsElement.style.display = "block";
+
+ const otherBuildCount = childCount - 4;
+ if (otherBuildCount == 1) {
+ plusXBuildsElement.textContent = "Plus 1 other build";
+ } else {
+ plusXBuildsElement.textContent =
+ `Plus ${otherBuildCount} other builds`;
+ }
+
+ animateElementChange(plusXBuildsElement);
+ } else {
+ noAllocatedBuildsElement.style.display = "none";
+ plusXBuildsElement.style.display = "none";
+ }
+ }
+}
+
+function buildSubmittedHandler(e) {
+ const data = JSON.parse(e.data);
+ console.log("build-submitted", data);
+
+ addRecentActivityEntry(
+ "Build submitted",
+ `${data.derivation.slice(44, -4)}`,
+ data.timestamp
+ );
+}
+
+function buildCanceledHandler(e) {
+ console.log("build-canceled", e);
+
+ addRecentActivityEntry(
+ "Build canceled",
+ `${data.derivation.slice(44, -4)}, tags: ${data.tags}`,
+ data.timestamp
+ );
+}
+
+function buildSuccessHandler(e) {
+ const data = JSON.parse(e.data);
+ console.log("build-success", data);
+
+ const buildElement = document.getElementById(
+ "build-" + data.build_id
+ );
+ const buildDetails = buildDetailsFromDom(data.build_id);
+
+ addRecentActivityEntry(
+ "Build success",
+ `${buildDetails.derivation.slice(44, -4)}`,
+ data.timestamp
+ );
+
+ animateElementAndRemove(buildElement, "green");
+
+ updateAgentBuildRelatedElements(data.agent_id);
+}
+
+function buildFailureHandler(e) {
+ const data = JSON.parse(e.data);
+
+ console.log("build-failure", data);
+
+ const buildElement = document.getElementById(
+ "build-" + data.build_id
+ );
+
+ animateElementAndRemove(buildElement, "red");
+
+ updateAgentBuildRelatedElements(data.agent_id);
+}
+
+function buildStartedHandler(e) {
+ const data = JSON.parse(e.data);
+ console.log("build-started", data);
+
+ const buildDetails = buildDetailsFromDom(data.build_id);
+ const agentDetails = agentDetailsFromDom(data.agent_id);
+
+ addRecentActivityEntry(
+ "Build started",
+ `${buildDetails.derivation.slice(44, -4)}, agent: ${agentDetails.name}`,
+ data.timestamp
+ );
+}
+
+function buildSetupFailureHandler(e) {
+ const data = JSON.parse(e.data);
+ console.log("build-setup-failure", data);
+
+ const buildDetails = buildDetailsFromDom(data.build_id);
+ const agentDetails = agentDetailsFromDom(data.agent_id);
+
+ addRecentActivityEntry(
+ "Build setup failure",
+ `${buildDetails.derivation.slice(44, -4)}, agent: ${agentDetails.name}`,
+ data.timestamp
+ );
+
+ // Remove from agent with setup failure animation
+}
+
+function allocationPlanUpdateHandler(e) {
+ const data = JSON.parse(e.data);
+
+ console.log("allocation-plan-update", data);
+
+ for (const agentId in data.allocation_plan_counts) {
+ const planSizeElement = document.getElementById(
+ "agent-" + agentId + "-plan-size"
+ );
+
+ const updatedValue = data.allocation_plan_counts[agentId];
+ if (updatedValue != planSizeElement.dataset.value) {
+ planSizeElement.textContent = `Plan size: ${data.allocation_plan_counts[agentId]}`
+ planSizeElement.dataset.value = updatedValue;
+
+ animateElementChange(planSizeElement);
+ }
+ }
+}
+
+function agentBuildsAllocatedHandler(e) {
+ const data = JSON.parse(e.data);
+
+ console.log("agent-builds-allocated", data);
+
+ const agentBuildsElement = document.getElementById(
+ "agent-" + data.agent_id + "-builds"
+ );
+
+ var newElements = [];
+
+ data.builds.forEach(function(build) {
+ const buildElement = document.getElementById("build-" + build.uuid);
+
+ if (!buildElement) {
+ const buildElement = document.createElement('div');
+ buildElement.id = "build-" + build.uuid;
+ buildElement.className = "build";
+
+ buildElement.dataset.derivation = build.derivation_name;
+ const drv = build.derivation_name.slice(44, -4);
+
+ buildElement.innerHTML = `
+<span class="monospace" style="display:block;">${drv}</span>
+`;
+
+ build.tags.sort(function(a, b) {
+ return a.key > b.key;
+ }).forEach(function(tag) {
+ var val;
+
+ if (tag.value.length == 40) {
+ val = tag.value.substring(0, 8);
+ } else {
+ val = tag.value;
+ }
+
+ buildElement.innerHTML += `
+<span class="build-tag">${tag.key}: ${val}</span>
+`;
+ });
+
+ if (agentBuildsElement.childElementCount > 4) {
+ buildElement.style.display = "none";
+ }
+
+ agentBuildsElement.append(buildElement);
+
+ newElements.push(buildElement);
+ }
+ });
+
+ if (agentBuildsElement.childElementCount > 4) {
+ document.getElementById(
+ "agent-" + data.agent_id + "-no-allocated-builds"
+ ).style.display = "none";
+
+ const plusBuilds = document.getElementById(
+ "agent-" + data.agent_id + "-plus-x-builds"
+ )
+ plusBuilds.style.display = "block";
+
+ const otherBuildCount = agentBuildsElement.childElementCount - 4;
+ if (otherBuildCount == 1) {
+ plusBuilds.textContent = "Plus 1 other build";
+ } else {
+ plusBuilds.textContent =
+ `Plus ${otherBuildCount} other builds`;
+ }
+
+ animateElementChange(plusBuilds);
+ }
+
+ for (const element of newElements) {
+ setTimeout(
+ function() { animateElementChange(element); },
+ 50
+ );
+ }
+}
+
+function agentStatusUpdateHandler(e) {
+ const data = JSON.parse(e.data);
+
+ console.log("agent-status-update", data);
+
+ const loadElement = document.getElementById(
+ "agent-" + data.agent_id + "-load"
+ );
+
+ const loadPercentage = Math.round((100 * data.load_average["1"]) / data.processor_count);
+ loadElement.textContent = `Load: ${loadPercentage}%`;
+
+ var loadClass;
+ if (loadPercentage < 150) {
+ loadClass = "agent-load-normal";
+ } else if (loadPercentage < 250) {
+ loadClass = "agent-load-medium";
+ } else {
+ loadClass = "agent-load-high";
+ }
+ loadElement.className = `agent-load ${loadClass}`;
+
+ animateElementChange(loadElement);
+}
+
+const lastEventId = document.getElementById("main").dataset.stateid;
+const evtSource = new EventSource(`/events?last_event_id=${lastEventId}`);
+
+evtSource.addEventListener("build-submitted", buildSubmittedHandler);
+evtSource.addEventListener("build-success", buildSuccessHandler);
+evtSource.addEventListener("build-failure", buildFailureHandler);
+evtSource.addEventListener("build-started", buildStartedHandler);
+evtSource.addEventListener("build-setup-failure", buildSetupFailureHandler);
+evtSource.addEventListener("allocation-plan-update", allocationPlanUpdateHandler);
+evtSource.addEventListener("agent-builds-allocated", agentBuildsAllocatedHandler);
+evtSource.addEventListener("agent-status-update", agentStatusUpdateHandler);
+
+
+console.log("starting listening");
+
+