impl status mirror list

This commit is contained in:
Miao Wang 2024-04-09 20:43:56 +08:00
parent 14ffc4b8d5
commit badddeec76
5 changed files with 220 additions and 230 deletions

View File

@ -0,0 +1,217 @@
<script setup>
import { useMirrorList } from "../lib/mirrorList";
import { ref, onMounted } from "vue";
const rawMirrorList = useMirrorList();
const rollMax = 6;
const rollCur = ref(0);
const SCROLL_INTERVAL = 2000;
const doScroll = function () {
rollCur.value += 1;
if (rollCur.value >= rollMax) rollCur.value = 0;
};
const freezedRows = ref({});
onMounted(() => {
setInterval(doScroll, SCROLL_INTERVAL);
});
</script>
<template>
<table class="table text-break table-hover table-borderless">
<thead>
<tr class="d-none d-lg-table-row">
<th class="col-2">Name</th>
<th class="col-4" colspan="2">Last Update</th>
<th class="col-4">Upstream</th>
<th class="col-1">Status</th>
<th class="col-1">Size</th>
</tr>
</thead>
<tbody
id="mirror-list"
:data-tuna-roll-cur="rollCur % rollMax"
:data-tuna-roll-max="rollMax"
class="table-group-divider"
>
<tr
v-for="mir in rawMirrorList"
:class="[
'row',
'd-lg-table-row',
'status-' + mir.status,
mir.last_ended_ts == mir.last_update_ts ? 'last-succ' : 'last-fail',
]"
:key="mir.name"
:data-tuna-roll-freeze="freezedRows[mir.name]"
@mouseenter="freezedRows[mir.name] = rollCur"
@mouseleave="freezedRows[mir.name] = undefined"
>
<th class="col-4 d-lg-none text-end">Name</th>
<td class="col-8 col-lg-2">
{{ mir.name }}{{ mir.is_master ? "" : " [slave]" }}
</td>
<th class="col-4 d-lg-none text-end">Last Success</th>
<td class="col-8 d-lg-none">
{{ mir.last_update }}, {{ mir.last_update_ago }}
</td>
<template v-if="mir.last_ended_ts != mir.last_update_ts">
<th class="col-4 d-lg-none text-end">Last Attempt</th>
<td class="col-8 d-lg-none">
{{ mir.last_ended }}, {{ mir.last_ended_ago }}
</td>
</template>
<th class="col-4 d-lg-none text-end">Next Sync</th>
<td class="col-8 d-lg-none" v-if="mir.status != 'syncing'">
{{ mir.next_schedule }}, {{ mir.next_schedule_ago }}
</td>
<td class="col-8 d-lg-none" v-else>Syncing Now</td>
<td class="col-2 rolling-3 d-none d-lg-table-cell">
<div class="tuna-roll">
&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1 2 3">Last Successful Sync</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0 1">Last Successful Sync</div>
<div data-tuna-roll-seq="2 3">Last Attempted Sync</div>
</template>
<div v-if="mir.status == 'syncing'" data-tuna-roll-seq="4 5">
Sync Started
</div>
<div v-else data-tuna-roll-seq="4 5">Next Scheduled Sync</div>
</div>
</td>
<td class="col-2 rolling-6 d-none d-lg-table-cell">
<div class="tuna-roll">
&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1 2 3">
{{ mir.last_update_ago }}
<div class="tooltiptext">{{ mir.last_update }}</div>
</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0 1">
{{ mir.last_update_ago }}
<div class="tooltiptext">{{ mir.last_update }}</div>
</div>
<div
data-tuna-roll-seq="2 3"
v-if="mir.last_ended_ts != mir.last_update_ts"
>
{{ mir.last_ended_ago }}
<div class="tooltiptext">{{ mir.last_ended }}</div>
</div>
</template>
<div v-if="mir.status == 'syncing'" data-tuna-roll-seq="4 5">
{{ mir.last_started_ago }}
<div class="tooltiptext">{{ mir.last_started }}</div>
</div>
<div v-else data-tuna-roll-seq="4 5">
{{ mir.next_schedule_ago }}
<div class="tooltiptext">{{ mir.next_schedule }}</div>
</div>
</div>
</td>
<th class="col-4 d-lg-none text-end">Upstream</th>
<td class="col-8 col-lg-4">{{ mir.upstream }}</td>
<th class="col-4 d-lg-none text-end">Status</th>
<td class="col-8 col-lg-1">{{ mir.status }}</td>
<th class="col-4 d-lg-none text-end">Size</th>
<td class="col-8 col-lg-1">{{ mir.size }}</td>
</tr>
</tbody>
</table>
</template>
<style lang="scss" scoped>
@use "../styles/sync-status.scss";
table {
& > tbody > tr {
border-bottom-width: var(--bs-border-width);
}
& > thead > tr {
border-bottom-width: calc(var(--bs-border-width) * 2);
border-bottom-style: solid;
border-bottom-color: currentColor;
}
}
.tuna-roll {
position: relative;
overflow: hidden;
> div {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
animation-timing-function: ease;
animation-duration: 1s;
animation-iteration-count: 1;
/* Tooltip text */
> .tooltiptext {
visibility: hidden;
width: auto;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 5px;
/* Position the tooltip text - see examples below! */
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
&:hover > .tooltiptext {
visibility: visible;
}
}
@keyframes tuna-roll-enter {
0% {
transform: translateY(100%);
}
100% {
transform: none;
}
}
@keyframes tuna-roll-leave {
0% {
transform: none;
}
100% {
transform: translateY(-100%);
}
}
}
@each $attrib in ("[data-tuna-roll-cur", ".row[data-tuna-roll-freeze") {
@for $i from 0 to 7 {
#{$attrib}="#{$i}"] {
.tuna-roll > div {
animation-name: tuna-roll-leave;
transform: translateY(100%);
}
.tuna-roll > div[data-tuna-roll-seq~="#{$i}"] {
animation-name: tuna-roll-enter;
transform: none;
}
}
}
}
</style>

View File

@ -1,7 +1,8 @@
import "./default";
import "../styles/status.scss";
import DiskBar from "../components/DiskBar.vue";
import StatusMirrorList from "../components/StatusMirrorList.vue";
import { createApp } from "vue";
createApp(DiskBar).mount("#disk-usage");
createApp(StatusMirrorList).mount("#mirror-list");

View File

@ -1,100 +0,0 @@
table.flat {
&>tbody>tr {
border-bottom-width: var(--bs-border-width);
}
&>thead>tr {
border-bottom-width: calc(var(--bs-border-width) * 2);
border-bottom-style: solid;
border-bottom-color: currentColor;
}
}
// Scrolling columns in status page
.tuna-roll {
position: relative;
overflow: hidden;
>div {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
animation-timing-function: ease;
animation-duration: 1s;
animation-iteration-count: 1;
/* Tooltip text */
>.tooltiptext {
visibility: hidden;
width: auto;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 5px;
/* Position the tooltip text - see examples below! */
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
&:hover>.tooltiptext {
visibility: visible;
}
}
@keyframes tuna-roll-enter {
0% {
transform: translateY(100%);
}
100% {
transform: none;
}
}
@keyframes tuna-roll-leave {
0% {
transform: none;
}
100% {
transform: translateY(-100%);
}
}
}
@each $attrib in ("[data-tuna-roll-cur", ".row[data-tuna-roll-freeze") {
@for $i from 0 to 7 {
#{$attrib}="#{$i}"] {
.tuna-roll>div {
animation-name: tuna-roll-leave;
transform: translateY(100%);
}
.tuna-roll>div[data-tuna-roll-seq~="#{$i}"] {
animation-name: tuna-roll-enter;
transform: none;
}
}
}
#{$attrib}="-1"] {
.tuna-roll>div {
transform: translateY(100%);
animation-name: tuna-roll-leave;
animation-duration: 0s;
}
.tuna-roll>div[data-tuna-roll-seq~="0"] {
transform: none;
animation-name: tuna-roll-enter;
animation-duration: 0s;
}
}
}

View File

@ -1,26 +0,0 @@
---
---
document.addEventListener("DOMContentLoaded", () => {
const SCROLL_INTERVAL = 2000;
var step = 0;
const doScroll = function() {
const target = document.getElementById('mirror-list');
const max = parseInt(target.attributes['data-tuna-roll-max'].value, 10);
Array.from(target.querySelectorAll(".row:hover:not([data-tuna-roll-freeze])")).forEach((el) => {
const attr = document.createAttribute('data-tuna-roll-freeze');
attr.value = String((step) % max);
el.attributes.setNamedItem(attr);
})
Array.from(target.querySelectorAll(".row:not(:hover)[data-tuna-roll-freeze]")).forEach((el) => {
el.removeAttribute('data-tuna-roll-freeze');
});
step += 1;
if(step < 0) step = 0;
const attr = document.createAttribute('data-tuna-roll-cur');
attr.value = String(step % max);
target.attributes.setNamedItem(attr);
}
setInterval(doScroll, SCROLL_INTERVAL);
});

View File

@ -32,113 +32,11 @@ jsEntry: status
</div>
{% endunless %}
<h3 id="syncing-status"># 同步状态</h3>
<table class="table text-break flat row d-table table-hover table-borderless">
<thead class="">
<tr class="d-none d-lg-table-row">
<th class="col-2">Name</th>
<th class="col-4" colspan=2>Last Update</th>
<th class="col-4">Upstream</th>
<th class="col-1">Status</th>
<th class="col-1">Size</th>
</tr>
</thead>
<tbody id="mirror-list" data-tuna-roll-cur="-1" data-tuna-roll-max="6" class="table-group-divider">
{% raw %}
<tr v-for="mir in rawMirrorList" :class="['row', 'd-lg-table-row', 'status-'+mir.status, mir.last_ended_ts == mir.last_update_ts ? 'last-succ' : 'last-fail']" :key="mir.name">
<th class="col-4 d-lg-none text-end">Name</th>
<td class="col-8 col-lg-2">{{mir.name}}{{mir.is_master ? '' : ' [slave]'}}</td>
<th class="col-4 d-lg-none text-end">Last Success</th>
<td class="col-8 d-lg-none">{{mir.last_update}}, {{mir.last_update_ago}}</td>
<template v-if="mir.last_ended_ts != mir.last_update_ts">
<th class="col-4 d-lg-none text-end">Last Attempt</th>
<td class="col-8 d-lg-none">{{mir.last_ended}}, {{mir.last_ended_ago}}</td>
</template>
<th class="col-4 d-lg-none text-end">Next Sync</th>
<td class="col-8 d-lg-none" v-if="mir.status != 'syncing'">{{mir.next_schedule}}, {{mir.next_schedule_ago}}</td>
<td class="col-8 d-lg-none" v-else>Syncing Now</td>
<td class="col-2 rolling-3 d-none d-lg-table-cell">
<div v-if="dateTooltip" class="tuna-roll">&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1 2 3">Last Successful Sync</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0 1">Last Successful Sync</div>
<div data-tuna-roll-seq="2 3">Last Attempted Sync</div>
</template>
<div v-if="mir.status == 'syncing'" data-tuna-roll-seq="4 5">Sync Started</div>
<div v-else data-tuna-roll-seq="4 5">Next Scheduled Sync</div>
</div>
<div v-else class="tuna-roll">&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1 2 3">Last Successful Sync</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0">Last Successful Sync</div>
<div data-tuna-roll-seq="1">Last Attempted Sync</div>
<div data-tuna-roll-seq="2">Last Successful Sync</div>
<div data-tuna-roll-seq="3">Last Attempted Sync</div>
</template>
<div data-tuna-roll-seq="4 5">Next Scheduled Sync</div>
</div>
</td>
<td class="col-2 rolling-6 d-none d-lg-table-cell">
<div v-if="dateTooltip" class="tuna-roll">&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1 2 3">{{mir.last_update_ago}}
<div class="tooltiptext">{{mir.last_update}}</div>
</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0 1">{{mir.last_update_ago}}
<div class="tooltiptext">{{mir.last_update}}</div>
</div>
<div data-tuna-roll-seq="2 3" v-if="mir.last_ended_ts != mir.last_update_ts">{{mir.last_ended_ago}}
<div class="tooltiptext">{{mir.last_ended}}</div>
</div>
</template>
<div v-if="mir.status == 'syncing'" data-tuna-roll-seq="4 5">{{mir.last_started_ago}}
<div class="tooltiptext">{{mir.last_started}}</div>
</div>
<div v-else data-tuna-roll-seq="4 5">{{mir.next_schedule_ago}}
<div class="tooltiptext">{{mir.next_schedule}}</div>
</div>
</div>
<div v-else class="tuna-roll">&nbsp;
<template v-if="mir.last_ended_ts == mir.last_update_ts">
<div data-tuna-roll-seq="0 1">{{mir.last_update}}</div>
<div data-tuna-roll-seq="2 3">{{mir.last_update_ago}}</div>
</template>
<template v-else>
<div data-tuna-roll-seq="0">{{mir.last_update}}</div>
<div data-tuna-roll-seq="1" v-if="mir.last_ended_ts != mir.last_update_ts">{{mir.last_ended}}</div>
<div data-tuna-roll-seq="2">{{mir.last_update_ago}}</div>
<div data-tuna-roll-seq="3" v-if="mir.last_ended_ts != mir.last_update_ts">{{mir.last_ended_ago}}</div>
</template>
<template v-if="mir.status == 'syncing'">
<div data-tuna-roll-seq="4 5">Syncing Now</div>
</template>
<template v-else>
<div data-tuna-roll-seq="4">{{mir.next_schedule}}</div>
<div data-tuna-roll-seq="5">{{mir.next_schedule_ago}}</div>
</template>
</div>
</td>
<th class="col-4 d-lg-none text-end">Upstream</th>
<td class="col-8 col-lg-4">{{mir.upstream}}</td>
<th class="col-4 d-lg-none text-end">Status</th>
<td class="col-8 col-lg-1">{{mir.status}}</td>
<th class="col-4 d-lg-none text-end">Size</th>
<td class="col-8 col-lg-1">{{mir.size}}</td>
</tr>
{% endraw %}
</tbody>
</table>
<div id="mirror-list" class="row"></div>
</div><!--/container -->
{% endunless %}
</div><!--/status -->
{% include footer.html %}
<script src="/static/js/status.js?{{ site.data['hash'] }}"></script>
<script src="/static/js/index.js?{{ site.data['hash'] }}"></script>
</body>
</html>
<!--