Files
alhp-web/frontend/src/components/CurrentlyBuilding.vue
2024-01-24 16:20:48 +01:00

291 lines
7.3 KiB
Vue

<template>
<v-card
border
class="my-6"
rounded
style="border-radius: 10px; border: 2px solid grey"
variant="elevated">
<v-card-title class="d-flex align-center justify-space-between w-100">
<span v-if="packageCount.building > 0" class="d-flex">
<div class="pulsating-circle-amber me-4" style="transform: translateY(10px)" />
<span>Building</span>
</span>
<span v-else class="d-flex">
<div class="pulsating-circle-green me-4" style="transform: translateY(10px)" />
<span>Idle</span>
</span>
<v-sheet class="d-flex align-center w-100">
<v-progress-linear
:max="packageCount.built + packageCount.building + packageCount.queued"
:model-value="packageCount.built"
color="light-blue"
height="10"
rounded
striped
style="transform: translateX(-620px)"></v-progress-linear>
<span
class="text-grey me-2"
style="font-size: 13px; min-width: 220px; width: 220px; padding-left: 60px">
Last updated
{{
lastUpdatedSeconds > 59
? rtf.format(-Math.floor(lastUpdatedSeconds / 60), 'minutes')
: rtf.format(-lastUpdatedSeconds, 'seconds')
}}
</span>
</v-sheet>
</v-card-title>
<v-card-text v-if="packageCount.building > 0 || packageCount.queued > 0" class="d-flex">
<v-list width="50%">
<v-list-subheader>Building</v-list-subheader>
<v-list-item v-for="(pkg, index) in packages.building" :key="index">
<template v-slot:prepend>
<div class="pulsating-circle-amber me-4" />
</template>
<v-list-item-title>
{{ pkg.pkgbase }} <span class="text-grey">({{ pkg.repo }})</span>
</v-list-item-title>
<v-list-item-subtitle>{{ pkg.arch_version }}</v-list-item-subtitle>
</v-list-item>
</v-list>
<v-list width="50%">
<v-list-subheader>Queued</v-list-subheader>
<v-list-item
v-for="(pkg, index) in packages.queued.slice(0, packageCount.building)"
:key="index"
prepend-icon="mdi-chevron-right">
<v-list-item-title>
{{ pkg.pkgbase }} <span class="text-grey">({{ pkg.repo }})</span>
</v-list-item-title>
<v-list-item-subtitle>{{ pkg.arch_version }}</v-list-item-subtitle>
</v-list-item>
<v-list-item
v-if="packageCount.queued > packageCount.building"
prepend-icon="mdi-dots-horizontal">
<v-list-item-title>
<span v-if="packageCount.building > 0">+</span>
{{ packageCount.queued - packageCount.building }}
<span v-if="packageCount.building > 0">more</span><span v-else>in queue</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</template>
<script lang="ts" setup>
// built + building + queued = total
import { onMounted, ref } from 'vue'
import type { Packages } from '@/types/Packages'
import { Package } from '@/types/Package'
// This variable sets the update-interval
const updateIntervalInMinutes = 5
const lastUpdatedTime = ref(0)
const lastUpdatedSeconds = ref(0)
const rtf = new Intl.RelativeTimeFormat('en', {
localeMatcher: 'best fit',
numeric: 'always',
style: 'long'
})
const packageCount = ref({
total: 0,
building: 0,
built: 0,
queued: 0
})
const packages = ref<{
built: Array<Package>
building: Array<Package>
queued: Array<Package>
}>({
built: [],
building: [],
queued: []
})
const getTotalPackages = () => {
fetch('https://api.alhp.dev/packages?limit=1&offset=0', {
method: 'GET'
})
.then((response) => {
if (response.ok) return response.json()
})
.then((json: Packages) => {
if (!json) return
packageCount.value.total = json.total
})
.catch((error) => {
console.error(error)
})
}
const getBuiltPackages = () => {
fetch('https://api.alhp.dev/packages?limit=0&offset=0&status=build', {
method: 'GET'
})
.then((response) => {
if (response.ok) return response.json()
})
.then((json: Packages) => {
if (!json) return
packageCount.value.built = json.total
packages.value.built = json.packages
})
.catch((error) => {
console.error(error)
})
}
const getBuildingPackages = () => {
fetch('https://api.alhp.dev/packages?limit=0&offset=0&status=building', {
method: 'GET'
})
.then((response) => {
if (response.ok) return response.json()
})
.then((json: Packages) => {
if (!json) return
packageCount.value.building = json.total
packages.value.building = json.packages
})
.catch((error) => {
console.error(error)
})
}
const getQueuedPackages = () => {
fetch('https://api.alhp.dev/packages?limit=0&offset=0&status=queued', {
method: 'GET'
})
.then((response) => {
if (response.ok) return response.json()
})
.then((json: Packages) => {
if (!json) return
packageCount.value.queued = json.total
packages.value.queued = json.packages
})
.catch((error) => {
console.error(error)
})
}
onMounted(() => {
getTotalPackages()
getBuiltPackages()
getBuildingPackages()
getQueuedPackages()
lastUpdatedTime.value = Date.now()
lastUpdatedSeconds.value = Math.floor((Date.now() - lastUpdatedTime.value) / 1000)
const lastUpdatedInterval = setInterval(() => {
lastUpdatedSeconds.value = Math.floor((Date.now() - lastUpdatedTime.value) / 1000)
}, 1000)
const interval = setInterval(
() => {
getTotalPackages()
getBuiltPackages()
getBuildingPackages()
getQueuedPackages()
lastUpdatedTime.value = Date.now()
lastUpdatedSeconds.value = Math.floor((Date.now() - lastUpdatedTime.value) / 1000)
},
updateIntervalInMinutes * 60 * 1000
)
})
</script>
<style lang="scss">
.pulsating-circle-green {
background-color: rgba(126, 206, 5, 0.94);
border-radius: 50%;
width: 12px;
height: 12px;
}
.pulsating-circle-green:before {
content: '';
display: block;
width: 200%;
height: 200%;
box-sizing: border-box;
margin-left: -50%;
margin-top: -50%;
border-radius: 50%;
background-color: rgba(126, 206, 5, 0.94);
-webkit-animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}
.pulsating-circle-amber {
background-color: #f39c12f0;
border-radius: 50%;
width: 12px;
height: 12px;
}
.pulsating-circle-amber:before {
content: '';
display: block;
width: 200%;
height: 200%;
box-sizing: border-box;
margin-left: -50%;
margin-top: -50%;
border-radius: 50%;
background-color: #f39c12;
-webkit-animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}
@-webkit-keyframes pulse-ring {
0% {
transform: scale(0.33);
}
80%,
100% {
opacity: 0;
}
}
@keyframes pulse-ring {
0% {
transform: scale(0.33);
}
80%,
100% {
opacity: 0;
}
}
@-webkit-keyframes pulse-dot {
0% {
transform: scale(0.8);
}
50% {
transform: scale(1);
}
100% {
transform: scale(0.8);
}
}
@keyframes pulse-dot {
0% {
transform: scale(0.8);
}
50% {
transform: scale(1);
}
100% {
transform: scale(0.8);
}
}
</style>