From 27c8de16b55dfe70180f0e17e12f442696708a53 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Thu, 13 Apr 2023 09:56:34 +0100 Subject: Initial commit --- assets/js/activity.js | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 assets/js/activity.js (limited to 'assets/js') 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 = ` +${event} +${content} +${timestamp}`; + + 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 = ` +${drv} +`; + + 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 += ` +${tag.key}: ${val} +`; + }); + + 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"); + + -- cgit v1.2.3