Created
May 13, 2016 18:42
-
-
Save indygreg/cbb68fe1aab0c877a559f64b92fb3065 to your computer and use it in GitHub Desktop.
Draw Gantt Charts of Firefox Automation Scheduling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Automation Job Scheduling</title> | |
</head> | |
<body> | |
<script type="application/javascript;version=1.8"> | |
// Perform a Treeherder API request and obtain the JSON. | |
function thRequest(path) { | |
return new Promise((resolve, reject) => { | |
let req = new Request('https://treeherder.mozilla.org/api/' + path, | |
{mode: "cors"}); | |
fetch(req).then((res) => { | |
res.json().then((data) => { | |
resolve(data); | |
}); | |
}); | |
}); | |
} | |
function renderProjectRevision(project, revision) { | |
thRequest('project/' + project + '/resultset/?revision=' + revision).then((data) => { | |
if (data.meta.count != 1) { | |
alert('could not find data for requested revision'); | |
return; | |
} | |
let rsid = data.results[0].id; | |
thRequest('project/' + project + '/jobs/?result_set_id=' + rsid + '&count=5000').then((data) => { | |
renderData(data.results); | |
}); | |
}); | |
} | |
let SCHEDULE_COLOR = "rgb(230, 230, 255)"; | |
let RUN_COLOR = "rgb(255, 0, 0)"; | |
let RUN_ETA_COLOR = "rgb(255, 179, 179)"; | |
let ROW_HEIGHT = 20; | |
function renderData(data) { | |
let earliestTime = 999999999999999; | |
let latestTime = 0; | |
for (let job of data) { | |
if (job.submit_timestamp < earliestTime) { | |
earliestTime = job.submit_timestamp; | |
} | |
if (job.start_timestamp > latestTime) { | |
latestTime = job.start_timestamp; | |
} | |
if (job.end_timestamp > latestTime) { | |
latestTime = job.end_timestamp; | |
} | |
if (job.end_timestamp == 0 && job.start_timestamp > 0) { | |
if (job.start_timestamp + job.running_eta > latestTime) { | |
latestTime = job.start_timestamp + job.running_eta; | |
} | |
} | |
} | |
let totalDuration = latestTime - earliestTime; | |
let canvas = document.getElementById('timeline'); | |
canvas.height = data.length * (ROW_HEIGHT + 1); | |
let drawWidth = canvas.offsetWidth; | |
let drawHeight = canvas.offsetHeight; | |
let secondsPerPixel = totalDuration / drawWidth; | |
let now = Date.now() / 1000; | |
let nowX = (now - earliestTime) / secondsPerPixel; | |
let ctx = canvas.getContext('2d'); | |
ctx.clearRect(0, 0, drawWidth, drawHeight); | |
let yOffset = 0; | |
for (let job of data) { | |
let submitTime = job.submit_timestamp; | |
let startTime = job.start_timestamp; | |
let endTime = job.end_timestamp; | |
let endX = (endTime - earliestTime) / secondsPerPixel; | |
// let submitX = (submitTime - earliestTime) / secondsPerPixel; | |
//ctx.fillStyle = SCHEDULE_COLOR; | |
//ctx.fillRect(submitX, yOffset, startX - submitX, ROW_HEIGHT); | |
if (startTime > 0) { | |
let startX = (startTime - earliestTime) / secondsPerPixel; | |
let runEndX; | |
if (endTime > 0) { | |
runEndX = (endTime - earliestTime) / secondsPerPixel; | |
} | |
// Job is still running. Only use the run color for part that has | |
// completed. | |
else { | |
runEndX = (now - earliestTime) / secondsPerPixel; | |
let eta = startTime + job.running_eta; | |
let etaX = (eta - earliestTime) / secondsPerPixel; | |
ctx.fillStyle = RUN_ETA_COLOR; | |
ctx.fillRect(runEndX, yOffset, etaX - runEndX, ROW_HEIGHT); | |
} | |
ctx.fillStyle = RUN_COLOR; | |
ctx.fillRect(startX, yOffset, runEndX - startX, ROW_HEIGHT); | |
} | |
ctx.fillStyle = "rgb(0, 0, 0)"; | |
ctx.fillText(job.ref_data_name, 5, yOffset + 12); | |
yOffset += ROW_HEIGHT + 1; | |
} | |
} | |
function populateProjects() { | |
thRequest("repository/").then((data) => { | |
let projects = document.getElementById('projects'); | |
for (let repo of data) { | |
let opt = document.createElement('option'); | |
opt.text = repo.name; | |
opt.value = repo.name; | |
projects.options.add(opt); | |
} | |
}); | |
} | |
document.addEventListener('DOMContentLoaded', function() { | |
populateProjects(); | |
let renderButton = document.getElementById('renderButton'); | |
renderButton.onclick = function() { | |
let projects = document.getElementById('projects'); | |
let revision = document.getElementById('revision'); | |
let project = projects[projects.selectedIndex].value; | |
renderProjectRevision(project, revision.value); | |
}; | |
}, false); | |
</script> | |
<div> | |
<select id="projects"></select> | |
<input id="revision" type="text" /> | |
<input id="renderButton" type="button" value="Show Timeline" /> | |
</div> | |
<canvas id="timeline" width="1024" height="2000"></canvas> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment