traxxx-web/pages/admin/entities/+Page.vue

188 lines
3.5 KiB
Vue

<template>
<Admin class="page">
<div class="header">
<div class="params">
<label>
Alert: <input
v-model="alertThreshold"
type="number"
placeholder="Alert threshold"
class="input"
> weeks
</label>
<label>
Dead: <input
v-model="deadThreshold"
type="number"
placeholder="Alert threshold"
class="input"
> months
</label>
</div>
<span class="attention">{{ alertEntities.length }} entities might require your attention</span>
</div>
<table class="table">
<thead>
<tr>
<th class="table-header">Entity</th>
<th class="table-header">Network</th>
<th
class="table-header noselect"
@click="sort('releases')"
>Releases</th>
<th
class="table-header noselect"
@click="sort('latest')"
>Latest release</th>
</tr>
</thead>
<tbody>
<tr
v-for="entity in alertEntities"
:key="`entity-${entity.id}`"
>
<td
:title="entity.id"
class="table-cell table-name ellipsis"
>
<a
:href="`/${entity.type}/${entity.slug}`"
target="_blank"
class="link"
>{{ entity.name }}</a>
</td>
<td
v-if="entity.parent"
:title="entity.paren?.id"
class="table-cell table-name ellipsis"
>
<a
:href="`/network/${entity.parent.slug}`"
target="_blank"
class="link"
>{{ entity.parent.name }}</a>
</td>
<td v-else />
<td class="table-cell table-total">{{ entity.totalReleases }}</td>
<td
class="table-cell table-date"
:class="{ alert: entity.latestReleaseDate && entity.latestReleaseDate < alertDate }"
>{{ entity.latestReleaseDate && format(entity.latestReleaseDate, 'yyyy-MM-dd hh:mm') }}</td>
</tr>
</tbody>
</table>
</Admin>
</template>
<script setup>
import {
ref,
computed,
watch,
inject,
} from 'vue';
import { format, subMonths, subWeeks } from 'date-fns';
import navigate from '#/src/navigate.js';
import Admin from '#/components/admin/admin.vue';
const {
pageProps,
urlParsed,
meta,
} = inject('pageContext');
const { entities } = pageProps;
const alertThreshold = ref(Number(urlParsed.search.alert) || 12);
const deadThreshold = ref(Number(urlParsed.search.dead) || 36);
const order = urlParsed.search.order || 'desc';
const alertDate = computed(() => subWeeks(meta.now, alertThreshold.value));
const deadDate = computed(() => subMonths(meta.now, deadThreshold.value));
const alertEntities = computed(() => entities.filter((entity) => entity.latestReleaseDate > deadDate.value && entity.latestReleaseDate < alertDate.value));
function sort(sorting) {
navigate('/admin/entities', {
sort: sorting,
order: order === 'desc' ? 'asc' : 'desc',
alert: alertThreshold.value,
dead: deadThreshold.value,
}, {
redirect: true,
});
}
watch([alertThreshold, deadThreshold], () => {
navigate('/admin/entities', {
...urlParsed.search,
alert: alertThreshold.value,
dead: deadThreshold.value,
}, {
redirect: false,
});
});
</script>
<style scoped>
.page {
flex-grow: 1;
}
.header {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
.params {
display: flex;
align-items: center;
gap: 2rem;
.input {
width: 5rem;
}
}
.attention {
margin-left: 2rem;
color: var(--warn);
font-weight: bold;
}
.table-header {
text-align: left;
}
.table-name {
width: 12rem;
}
.table-total {
width: 6rem;
}
.alert {
color: var(--warn);
font-weight: bold;
}
.link {
color: var(--text);
}
</style>