2022-06-20 04:17:48 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<link rel="stylesheet" href="style.css">
|
|
|
|
<style>
|
|
|
|
table {
|
|
|
|
height: 100vh;
|
|
|
|
width: 100vw;
|
2022-07-23 23:44:47 +00:00
|
|
|
display: block;
|
2022-06-20 04:17:48 +00:00
|
|
|
}
|
|
|
|
td.status {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
tr.failed td.status {
|
|
|
|
color: #ff0055;
|
|
|
|
}
|
|
|
|
tr.success td.status {
|
|
|
|
color: #009e73;
|
|
|
|
}
|
|
|
|
tr.running td.status {
|
|
|
|
color: #56b4e9;
|
|
|
|
}
|
|
|
|
td.retry {
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body>
|
|
|
|
<table>
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th>Pipeline</th>
|
|
|
|
<th>Job name</th>
|
|
|
|
<th>Created at</th>
|
|
|
|
<th class="status">Status</th>
|
|
|
|
<th>Project</th>
|
|
|
|
<th>Runner</th>
|
|
|
|
<th>Actions</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody></tbody>
|
|
|
|
</table>
|
|
|
|
|
2022-06-20 12:46:39 +00:00
|
|
|
<div class="template">
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<td class="pipeline"><a target="_blank"></a></td>
|
|
|
|
<td class="name"><a target="_blank"></a></td>
|
|
|
|
<td class="created_at"></td>
|
|
|
|
<td class="status"></td>
|
|
|
|
<td class="project"><a target="_blank"></a></td>
|
|
|
|
<td class="runner"></td>
|
|
|
|
<td class="retry">retry</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</div>
|
2022-06-20 04:17:48 +00:00
|
|
|
|
|
|
|
<script src="common.js"></script>
|
|
|
|
<script>
|
|
|
|
const runnerId = new URLSearchParams(window.location.search).get('id')
|
|
|
|
// $('h2').textContent = runnerId
|
|
|
|
|
2022-06-20 12:46:39 +00:00
|
|
|
const template = $('.template')
|
2022-06-20 04:17:48 +00:00
|
|
|
const table = $('tbody')
|
|
|
|
|
2022-07-23 23:44:47 +00:00
|
|
|
let notifications = false
|
2022-06-20 04:17:48 +00:00
|
|
|
|
|
|
|
$('th.status').addEventListener('click', ev => {
|
|
|
|
notifications = !notifications
|
2022-07-23 23:44:47 +00:00
|
|
|
sendNotification({
|
2022-06-20 04:17:48 +00:00
|
|
|
title: 'GitLab Jobs',
|
|
|
|
body: `Notifications are now ${notifications ? 'enabled' : 'disabled'}`
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
async function updateJobs() {
|
|
|
|
try {
|
|
|
|
let jobs
|
|
|
|
if (runnerId) {
|
|
|
|
jobs = await listJobsForRunner(runnerId)
|
|
|
|
} else {
|
|
|
|
const runners = await listRunners()
|
|
|
|
const promises = runners.map(runner => listJobsForRunner(runner.id.toString()).then(jobs => jobs.map(job => ({ ...job, runner }))))
|
|
|
|
jobs = (await Promise.all(promises)).flat()
|
|
|
|
}
|
|
|
|
|
|
|
|
jobs.forEach(job => {
|
|
|
|
const existing = $('#job' + job.id)
|
|
|
|
if (existing != null) {
|
|
|
|
const status = $(existing, '.status')
|
|
|
|
if (job.status !== status.textContent) {
|
|
|
|
status.textContent = job.status
|
|
|
|
existing.className = ''
|
|
|
|
existing.classList.add(job.status)
|
|
|
|
if (['success', 'failed'].includes(job.status)) {
|
2022-07-23 23:44:47 +00:00
|
|
|
sendNotification({
|
2022-06-20 04:17:48 +00:00
|
|
|
title: 'GitLab Jobs',
|
|
|
|
body: `Job ${job.name} for ${job.project.name}: ${job.status}`
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const fragment = initTemplate(template, {
|
|
|
|
pipeline: {
|
|
|
|
link: job.pipeline.web_url,
|
|
|
|
text: '#' + job.pipeline.id.toString()
|
|
|
|
},
|
|
|
|
status: job.status,
|
|
|
|
name: {
|
|
|
|
link: job.web_url,
|
|
|
|
text: job.name
|
|
|
|
},
|
|
|
|
created_at: job.created_at.substr(0, 19).replace('T', ' '),
|
|
|
|
project: {
|
|
|
|
link: 'https://gitlab.com/' + job.project.path_with_namespace,
|
|
|
|
text: job.project.name
|
|
|
|
},
|
2022-06-20 12:45:00 +00:00
|
|
|
runner: job.runner?.description || ''
|
2022-06-20 04:17:48 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
const row = $(fragment, 'tr')
|
|
|
|
row.id = 'job' + job.id
|
|
|
|
row.classList.add(job.status)
|
|
|
|
|
|
|
|
$(row, '.retry').addEventListener('click', ev => {
|
|
|
|
try {
|
|
|
|
retryJob(job.project.id.toString(), job.id)
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err)
|
2022-06-20 12:45:59 +00:00
|
|
|
alert(err.toString())
|
2022-06-20 04:17:48 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const before = Array.from(table.children).find(child => {
|
|
|
|
return parseInt(child.id.substr(3)) < job.id
|
|
|
|
})
|
|
|
|
|
|
|
|
if (before) {
|
|
|
|
table.insertBefore(row, before)
|
|
|
|
} else {
|
|
|
|
table.appendChild(row)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err)
|
2022-06-20 12:45:59 +00:00
|
|
|
alert(err.toString())
|
2022-06-20 04:17:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateJobs()
|
|
|
|
|
|
|
|
setInterval(updateJobs, 5000)
|
|
|
|
</script>
|
|
|
|
</body>
|
2022-07-23 23:44:47 +00:00
|
|
|
</html>
|