mirror of
https://github.com/tuna/mirror-web.git
synced 2025-12-25 20:32:46 +00:00
impl status mirror list
This commit is contained in:
parent
14ffc4b8d5
commit
badddeec76
|
|
@ -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">
|
||||
|
||||
<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">
|
||||
|
||||
<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>
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
104
status.html
104
status.html
|
|
@ -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">
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<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>
|
||||
<!--
|
||||
|
|
|
|||
Loading…
Reference in New Issue