Last active
April 2, 2024 18:56
-
-
Save DeflateAwning/d8d42a082cb27b7d01df751d0dc26f31 to your computer and use it in GitHub Desktop.
Tampermonkey script to modify the AWS Batch run page to add an execution time field to the "Job attempts" tab
This file contains 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
// ==UserScript== | |
// @name AWS Batch Upgrades | |
// @namespace https://gist.github.com/DeflateAwning/d8d42a082cb27b7d01df751d0dc26f31 | |
// @version 0.2.3 | |
// @description Calculate AWS Batch job time since started and total execution time (on the "Job attempts" tab). Set the tab title to include the job name and execution status. | |
// @author DeflateAwning | |
// @match https://us-east-1.console.aws.amazon.com/batch/home?region=* | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
const PRERUN_STATUS_VALUES = ['Runnable', 'Submitted', 'Starting', 'Ready']; | |
function calculateTimeDifference(startedAt, stoppedAt) { | |
if (!startedAt || !stoppedAt) { | |
return "N/A"; | |
} | |
const timeDifference = stoppedAt.getTime() - startedAt.getTime(); | |
const hours = Math.floor(timeDifference / (1000 * 60 * 60)); | |
const minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60)); | |
const seconds = Math.floor((timeDifference % (1000 * 60)) / 1000); | |
return `${hours}h ${minutes}m ${seconds}s`; | |
} | |
// Function to create and append the result field | |
function appendExecutionTimeField() { | |
// Get the "Started at" and "Stopped at" elements | |
const startedAtElement = document.querySelector('[data-test-id="startedAt"]').querySelector('div:last-child'); | |
const stoppedAtElement = document.querySelector('[data-test-id="stoppedAt"]').querySelector('div:last-child'); | |
// Extract the text content from the elements | |
const startedAtText = startedAtElement.textContent.trim(); | |
const stoppedAtText = stoppedAtElement.textContent.trim(); | |
// Create date objects | |
const startedAtDate = new Date(startedAtText); | |
const stoppedAtDate = new Date(stoppedAtText); | |
const timeSinceStarted = calculateTimeDifference(startedAtDate, new Date()); | |
const totalExecutionTime = calculateTimeDifference(startedAtDate, stoppedAtDate); | |
// remove existing "tamper-time-summary" objects | |
document.querySelectorAll('.tamper-time-summary').forEach(e => e.remove()); | |
const newElementHTML = ` | |
<div style="color: rgb(139,0,0);" class="tamper-time-summary"> | |
<div> | |
<span style="color: #545b64;">Time Since Start:</span> | |
${timeSinceStarted} | |
</div> | |
<div> | |
<span style="color: #545b64;">Total Execution Time:</span> | |
${totalExecutionTime} | |
</div> | |
<div style="color: #545b64;">Note: Times are in local time.</div> | |
</div> | |
`; | |
// Find the target element by its data-test-id | |
const targetElement = document.querySelector('[data-test-id="stoppedAt"]'); | |
// append newElementHTML right after targetElement | |
targetElement.insertAdjacentHTML('afterend', newElementHTML); | |
} | |
function getJobName() { | |
// let jobNameElement = document.evaluate('//*[@id="heading:rm:"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; | |
let jobNameElement = document.evaluate('//*[@id="app"]/div/div/div/main/div/div[2]/div/div/nav/ol/li[4]/div/span/span', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; | |
if (jobNameElement) { | |
let jobName = jobNameElement.textContent.trim(); | |
return jobName; | |
} | |
} | |
function getJobStatus() { | |
let jobStatusElement = document.evaluate("//*[contains(@class, 'awsui_content-wrapper')]/div[2]/div/div/div/div/div[1]/div/div/div[2]/span/span/text()", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; | |
if (jobStatusElement) { | |
let jobStatus = jobStatusElement.textContent.trim(); | |
return jobStatus; | |
} | |
} | |
function checkAndUpdatePageTitle() { | |
var currentUrl = window.location.href; | |
// Check if the URL ends with "#jobs" and contains "/batch/home" | |
if (currentUrl.endsWith("#jobs") && currentUrl.includes("/batch/home")) { | |
// Set the page title | |
document.title = "JOB LIST | AWS Batch"; | |
// console.log("Set job title."); | |
} | |
else if (currentUrl.includes("/batch/home") && currentUrl.includes("#jobs/fargate/detail/")) { | |
let job_name = getJobName(); | |
let job_status = getJobStatus(); | |
let new_title = ''; | |
if (job_status == 'Running') { | |
new_title += '🕙'; | |
} | |
else if (job_status == 'Success' || job_status == 'Succeeded') { | |
new_title += '✅'; | |
} | |
else if (job_status == 'Failed') { | |
new_title += '❌'; | |
} | |
else if (PRERUN_STATUS_VALUES.includes(job_status)) { // like 'Starting' | |
new_title += '🏁'; | |
} | |
else if (job_status) { | |
new_title += '🤷'; // non-null but unknown | |
} | |
else { | |
new_title += '🫙'; // null jar | |
} | |
new_title += ' | '; | |
if (job_name) { | |
new_title += job_name; | |
} | |
else { | |
new_title += 'JOB'; | |
//console.log("getJobName() returned empty job name."); | |
} | |
new_title += ' | BATCH'; | |
document.title = new_title; | |
} | |
} | |
function run_ignore_error() { | |
try { | |
appendExecutionTimeField(); | |
} catch (error) { | |
console.error('appendExecutionTimeField: An error occurred:', error); | |
} | |
try { | |
checkAndUpdatePageTitle(); | |
} catch (error) { | |
console.error('checkAndUpdatePageTitle: An error occurred:', error); | |
} | |
} | |
// run every 5 seconds to keep time updated | |
setInterval(run_ignore_error, 2000); | |
// auto-reload the page if it says the job is Running | |
setInterval(function() { | |
let job_status = getJobStatus(); | |
if (job_status == 'Running' || PRERUN_STATUS_VALUES.includes(job_status)) { | |
location.reload(); | |
} | |
}, 60 * 4 * 1000); // 4 minutes | |
// debug run | |
// appendExecutionTimeField(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment