Revamp of status page -> v2 here we go!!

This commit is contained in:
2023-12-17 20:59:04 +01:00
parent f76fba0b05
commit 0489edfa91

View File

@@ -8,9 +8,17 @@
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Scalesoft/s-pagination@3.0.1/dist/pagination.css" crossorigin="anonymous">
<style>
/* This style fixes the position of the pagination */
.pagination-container ul {
margin-top: 0 !important;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg sticky-top navbar-light bg-info">
<body style="background-color: #111217">
<nav class="navbar navbar-expand-lg sticky-top navbar-light bg-primary">
<div class="container">
<div class="d-flex justify-content-start">
<span class="navbar-brand align-middle">ALHP Status</span>
@@ -19,11 +27,6 @@
class="fa fa-gitea fs-4"></i></a>
</span>
</div>
<div class="d-flex justify-content-end">
<input type="search" placeholder="Search for packages.." class="form-control" id="table-sort-input"
title="Search for package"/>
</div>
</div>
</nav>
@@ -35,10 +38,44 @@
src="https://stats.itsh.dev/public-dashboards/0fb04abb0c5e4b7390cf26a98e6dead1"></iframe>
</div>
<h3 class="mt-5">Packages</h3>
<table class="table table-sorted">
<h3>Packages</h3>
<div class="d-flex justify-space-between mt-4" style="height: 37px">
<div class="d-flex gap-3 w-50">
<input type="text" class="form-control" id="input-pkgbase" placeholder="Search Pkgbase">
<select class="form-select" id="select-repository" aria-label="Repository select">
<option value="any" selected>Repository (any)</option>
<option value="core-x86-64-v2">core-x86-64-v2</option>
<option value="extra-x86-64-v2">extra-x86-64-v2</option>
<option value="multilib-x86-64-v2">multilib-x86-64-v2</option>
<option value="core-x86-64-v3">core-x86-64-v3</option>
<option value="extra-x86-64-v3">extra-x86-64-v3</option>
<option value="multilib-x86-64-v3">multilib-x86-64-v3</option>
<option value="core-x86-64-v4">core-x86-64-v4</option>
<option value="extra-x86-64-v4">extra-x86-64-v4</option>
<option value="multilib-x86-64-v4">multilib-x86-64-v4</option>
</select>
<select class="form-select" id="select-status" aria-label="Status select">
<option value="any" selected>Status (any)</option>
<option value="latest">Latest</option>
<option value="build">Built</option>
<option value="failed">Failed</option>
<option value="skipped">Skipped</option>
<option value="delayed">Delayed</option>
<option value="building">Building</option>
<option value="signing">Signing</option>
<option value="unknown">Unknown</option>
</select>
</div>
<div id="pagination" style="line-height: 27px; margin-left: auto"></div>
</div>
<table class="table mt-2" style="margin-bottom: 100px">
<thead>
<tr>
<th scope="col">Repository</th>
<th scope="col">Pkgbase</th>
<th scope="col">Status</th>
<th scope="col">Reason</th>
@@ -53,126 +90,341 @@
<th class="text-end" scope="col">Info</th>
</tr>
</thead>
<tbody id="main-tbody">
{{range $pkg := $repo.Packages}}
<tr class="table-{{$pkg.Class}}"
id="{{$repo.Name}}-{{$march.Name}}-{{$pkg.Pkgbase}}">
<td>{{$pkg.Pkgbase}}</td>
<td>{{$pkg.Status}}</td>
<td>{{$pkg.Skip}}</td>
<td class="text-center fs-6">
{{if $pkg.LTO}}<i class="fa fa-check fa-lg" style="color: var(--bs-success)"
title="build with LTO"></i>{{end}}
{{if $pkg.LTODisabled}}<i class="fa fa-times fa-lg" style="color: var(--bs-danger)"
title="LTO explicitly disabled"></i>{{end}}
{{if $pkg.LTOAutoDisabled}}<i class="fa fa-times-circle-o fa-lg"
style="color: var(--bs-danger)"
title="LTO automatically disabled"></i>{{end}}
{{if $pkg.LTOUnknown}}<i class="fa fa-hourglass-o fa-lg"
title="not build with LTO yet"></i>{{end}}
</td>
<td class="text-center fs-6">
{{if $pkg.DebugSym}}<i class="fa fa-check fa-lg" style="color: var(--bs-success)"
title="Debug symbols available"></i>{{end}}
{{if $pkg.DebugSymNotAvailable}}<i class="fa fa-times fa-lg"
style="color: var(--bs-danger)"
title="Not build with debug symbols"></i>{{end}}
{{if $pkg.DebugSymUnknown}}<i class="fa fa-hourglass-o fa-lg"
title="Not build yet"></i>{{end}}
</td>
<td>{{$pkg.Svn2GitVersion}}</td>
<td>{{$pkg.Version}}</td>
<td class="text-end info-box">
{{with $pkg.Log}}<a href="{{.}}" title="build log"
><i class="fa fa-file-text fa-lg"></i></a
>{{end}}
<a class="text-decoration-none fw-bold"
href="https://archlinux.org/packages/?q={{$pkg.Pkgbase}}" title="ArchWeb">AW</a>
<a data-bs-html="true" data-bs-placement="bottom" data-bs-toggle="tooltip"
href="#{{$repo.Name}}-{{$march.Name}}-{{$pkg.Pkgbase}}"
title="{{if $pkg.BuildDate}}Build on {{$pkg.BuildDate}}&#10;{{end}}{{if $pkg.BuildDuration}}CPU-Time: {{$pkg.BuildDuration}}&#10;{{end}}{{if $pkg.BuildMemory}}Peak-Memory: {{$pkg.BuildMemory}}&#10;{{end}}Last checked on {{$pkg.Checked}}">
<i class="fa fa-info-circle fa-lg"></i></a>
</td>
</tr>
{{end}}
</tbody>
<tbody id="main-tbody"></tbody>
</table>
</div>
<footer class="text-center text-lg-start bg-dark mt-3 fixed-bottom">
<div class="p-2 text-center">
{{.Latest}} <span class="text-primary">build</span>
{{.Queued}} <span class="text-warning">queued</span>
{{.Skipped}} <span class="text-secondary">skipped</span>
{{.Failed}} <span class="text-danger">failed</span>
||
LTO: {{.LTOEnabled}} <span class="text-success">enabled</span>
{{.LTODisabled}} <span class="text-danger">disabled</span>
{{.LTOUnknown}} <span class="text-secondary">unknown</span>
||
<span class="text-muted">{{.Generated}}</span>
<footer class="text-center text-lg-start fixed-bottom" style="background-color: #000000">
<div class="p-2 text-center ">
<span id="stats-latest"></span><span style="color: #084f46"> latest</span>
<span id="stats-queued"></span><span style="color: #5d2f03"> queued</span>
<span id="stats-skipped"></span><span style="color: #4c4c4c"> skipped</span>
<span id="stats-failed"></span><span style="color: #4f140f"> failed</span>
&#8214;
<span class="fw-bold">LTO: </span> <span id="stats-lto"></span><span style="color: #084f46"> enabled</span>
<span id="stats-lto-disabled"></span><span style="color: #4f140f"> disabled</span>
<span id="stats-lto-unknown"></span><span style="color: #646464"> unknown</span>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/Scalesoft/s-pagination@3.0.1/dist/pagination.js"></script>
<script>
let input = document.getElementById('table-sort-input');
let timeout = null;
const url = new URL(window.location)
function searchPackages() {
let new_tbody = document.createElement('tbody');
const pagination = new Pagination({
container: document.getElementById('pagination'),
pageClickCallback: function (pageNumber) {
searchPackages((pageNumber - 1) * 50)
}
})
axios.get('https://api.alhp.dev/packages', {
params: {
pkgbase: (input.value.toLowerCase() ? input.value.toLowerCase() : undefined),
page: 1,
const ref = {
totalItems: 0
}
const handler = {
get(target, prop, receiver) {
if (prop === 'totalItems') {
return target.totalItems
}
return Reflect.get(...arguments)
},
set(obj, prop, value) {
if (prop === 'totalItems') {
obj[prop] = value
}
pagination.make(value, 50)
return true
}
}
const pages = new Proxy(ref, handler)
const inputPkgbase = document.getElementById('input-pkgbase')
const selectRepo = document.getElementById('select-repository')
const selectStatus = document.getElementById('select-status')
function getStats() {
fetch('https://api.alhp.dev/stats')
.then(response => {
if (!response.ok) throw new Error(response.statusText)
return response.json()
}).then(stats => {
document.getElementById('stats-latest').innerText = stats.latest
document.getElementById('stats-queued').innerText = stats.queued
document.getElementById('stats-skipped').innerText = stats.skipped
document.getElementById('stats-failed').innerText = stats.failed
document.getElementById('stats-lto').innerText = stats.lto.enabled
document.getElementById('stats-lto-disabled').innerText = stats.lto.disabled
document.getElementById('stats-lto-unknown').innerText = stats.lto.unknown
}).catch(error => {
console.error(error)
}).finally(() => {})
}
function searchPackages(offset) {
const params = new URLSearchParams({
limit: 50,
}
offset
})
.then(function (response) {
console.log(response)
let jResp = JSON.parse(response)
for (const pkg of jResp.packages) {
let ntr = document.createElement('tr')
ntr.classList.add("")
}
})
.catch(function (error) {
console.log(error);
})
.finally(function () {
// always executed
});
if (inputPkgbase.value) params.append('pkgbase', inputPkgbase.value.toLowerCase())
if (selectRepo.value !== 'any') params.append('repo', selectRepo.value)
if (selectStatus.value !== 'any') params.append('status', selectStatus.value)
let input, filter, tr, td, i, txtValue;
input = document.getElementById('table-sort-input')
filter = input.value.toLowerCase()
const tables = document.getElementsByClassName('table-sorted');
for (let j = 0; j < tables.length; j++) {
tr = tables[j].getElementsByTagName('tr')
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName('td')[0]
if (td) {
txtValue = td.textContent || td.innerText
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = ''
fetch('https://api.alhp.dev/packages?' + params, {
method: 'GET',
}).then(response => {
if (response.ok) return response.json()
if (response.status === 404) {
const tableBody = document.getElementById('main-tbody')
const ntb = document.createElement('tbody')
ntb.id = 'main-tbody'
const ntr = document.createElement('tr')
const ntd = document.createElement('td')
ntd.innerText = 'No Packages found'
ntb.appendChild(ntr.appendChild(ntd))
tableBody.replaceWith(ntb)
pages.totalItems = 0
} else {
tr[i].style.display = 'none'
}
}
}
throw new Error(response.statusText)
}
}).then(packages => {
if (!packages) return
if (pages.totalItems !== packages.total) {
pages.totalItems = packages.total
}
input.addEventListener('input', function (e) {
clearTimeout(timeout);
const tableBody = document.getElementById('main-tbody')
const ntb = document.createElement('tbody')
ntb.id = 'main-tbody'
timeout = setTimeout(searchPackages, 200);
for (const pkg of packages.packages) {
const rowColor = getStatus(pkg.status)
const ntr = document.createElement('tr')
ntr.id = pkg.pkgbase + '-' + pkg.repo
// Create table cells
const Repository = document.createElement('td')
Repository.style.backgroundColor = rowColor
const repo = pkg.repo.split('-')
Repository.innerHTML = `<span class="fw-bold">${repo[0]}</span> <span style="width: 1.25rem; height: 1.25rem; border-radius: 5px; background-color: ${ getVersionColor(repo[repo.length - 1]) }; padding: 0 10px">${repo[repo.length - 1]}</span>`
ntr.appendChild(Repository)
const PkgBase = document.createElement('td')
PkgBase.style.backgroundColor = rowColor
PkgBase.innerText = pkg.pkgbase
ntr.appendChild(PkgBase)
const Status = document.createElement('td')
Status.style.backgroundColor = rowColor
Status.innerText = pkg.status.toLocaleUpperCase()
ntr.appendChild(Status)
const Reason = document.createElement('td')
Reason.style.backgroundColor = rowColor
Reason.innerText = pkg.skip_reason || ''
ntr.appendChild(Reason)
const LTO = document.createElement('td')
LTO.style.backgroundColor = rowColor
const ltoObj = getLto(pkg.lto)
LTO.innerHTML = `<i class="${ltoObj.class}" title="${ltoObj.title}"></i>`
ntr.appendChild(LTO)
const DS = document.createElement('td')
DS.style.backgroundColor = rowColor
const dsObj = getDs(pkg.debug_symbols)
DS.innerHTML = `<i class="${dsObj.class}" title="${dsObj.title}"></i>`
ntr.appendChild(DS)
const ArchLinuxVersion = document.createElement('td')
ArchLinuxVersion.style.backgroundColor = rowColor
ArchLinuxVersion.innerText = pkg.arch_version
ntr.appendChild(ArchLinuxVersion)
const AlhpVersion = document.createElement('td')
AlhpVersion.style.backgroundColor = rowColor
AlhpVersion.innerText = pkg.repo_version
ntr.appendChild(AlhpVersion)
const Info = document.createElement('td')
Info.style.backgroundColor = rowColor
const logFile = pkg.status === 'failed' ? '<a href="https://alhp.dev/logs/' + pkg.repo.slice(pkg.repo.indexOf('-') + 1) + '/' + pkg.pkgbase + '.log" class="text-decoration-none text-white-50"><i class="fa fa-file-text fa-lg"></i></a>' : ''
const aw = '<a href="https://archlinux.org/packages/?g=' + pkg.pkgbase + '" target="_blank" title="ArchWeb" class="text-decoration-none text-white-50 fw-bold">AW</a>'
const info = '<i class="fa fa-info-circle fa-lg text-white-50" data-bs-html="true" data-bs-placement="bottom" data-bs-toggle="tooltip" title="' + `${pkg.build_date ? 'Build on ' + pkg.build_date + '&#10;' : ''}${pkg.peak_mem ? 'Peak-Memory: ' + pkg.peak_mem : ''}` + '"></i>'
Info.classList.add('text-end')
Info.innerHTML = `${logFile} ${aw} ${info}`
ntr.appendChild(Info)
// Append Table Row to Table Body
ntb.appendChild(ntr)
}
tableBody.replaceWith(ntb)
}).catch(error => {
console.error(error)
})
}
const getVersionColor = (version) => {
let color = 'grey'
switch (version) {
case 'v2':
color = '#3498db'
break
case 'v3':
color = '#f39c12'
break
case 'v4':
color = '#2ecc71'
break
}
return color
}
const getStatus = (status) => {
let color = ''
switch (status) {
case 'skipped':
color = '#373737'
break
case 'queued':
color = '#5d2f03'
break
case 'latest':
color = ''
break
case 'failed':
color = '#4f140f'
break
case 'signing':
color = '#093372'
break
case 'building':
color ='#084f46'
break
case 'unknown':
color ='#191919'
break
}
return color
}
const getLto = (lto) => {
let icon = {
title: '',
class: ''
}
switch (lto) {
case 'enabled':
icon = {
title: 'build with LTO',
class: 'fa fa-check fa-lg text-success'
}
break
case 'unknown':
icon = {
title: 'not build with LTO yet',
class: 'fa fa-hourglass-o fa-lg text-black-50'
}
break
case 'disabled':
icon = {
title: 'LTO explicitly disabled',
class: 'fa fa-times fa-lg text-danger'
}
break
case 'auto_disabled':
icon = {
title: 'LTO automatically disabled',
class: 'fa fa-times-circle-o fa-lg text-warning'
}
break
}
return icon
}
const getDs = (lto) => {
let icon = {
title: '',
class: ''
}
switch (lto) {
case 'available':
icon = {
title: 'Debug symbols available',
class: 'fa fa-check fa-lg text-success'
}
break
case 'unknown':
icon = {
title: 'Not build yet',
class: 'fa fa-hourglass-o fa-lg text-black-50'
}
break
case 'not_available':
icon = {
title: 'Not build with debug symbols',
class: 'fa fa-times fa-lg text-danger'
}
break
}
return icon
}
window.addEventListener('load', () => {
inputPkgbase.value = url.searchParams.has('pkgbase') ? url.searchParams.get('pkgbase').toLowerCase() : ''
selectRepo.value = url.searchParams.has('repo') ? url.searchParams.get('repo').toLowerCase() : 'any'
selectStatus.value = url.searchParams.has('status') ? url.searchParams.get('status').toLowerCase() : 'any'
getStats()
searchPackages(0)
})
let delayTimer = null
inputPkgbase.addEventListener('input', () => {
if (delayTimer) clearTimeout(delayTimer);
delayTimer = setTimeout(function() {
if (inputPkgbase.value) {
url.searchParams.set('pkgbase', inputPkgbase.value.toLowerCase())
} else {
url.searchParams.delete('pkgbase')
}
window.history.pushState(null, '', url.toString())
searchPackages(0)
}, 250);
});
selectRepo.addEventListener('change', () => {
if (selectRepo.value) {
if (selectRepo.value === 'any') {
url.searchParams.delete('repo')
} else {
url.searchParams.set('repo', selectRepo.value)
}
window.history.pushState(null, '', url.toString())
}
searchPackages(0)
})
selectStatus.addEventListener('change', () => {
if (selectStatus.value) {
if (selectStatus.value === 'any') {
url.searchParams.delete('status')
} else {
url.searchParams.set('status', selectStatus.value)
}
window.history.pushState(null, '', url.toString())
}
searchPackages(0)
})
</script>
</body>
</html>