All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
Reviewed-on: #1 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
97 lines
3.6 KiB
Vue
97 lines
3.6 KiB
Vue
<script setup lang="ts">
|
|
import type { DashboardResponse } from '~/services/dto/dashboard'
|
|
import { getDashboard } from '~/services/dashboard'
|
|
|
|
const { t } = useI18n()
|
|
|
|
const data = ref<DashboardResponse | null>(null)
|
|
const loading = ref(true)
|
|
|
|
async function loadDashboard() {
|
|
loading.value = true
|
|
try {
|
|
data.value = await getDashboard()
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function statusClass(status: string): string {
|
|
switch (status) {
|
|
case 'running': return 'bg-green-100 text-green-700'
|
|
case 'exited': return 'bg-red-100 text-red-700'
|
|
case 'restarting': return 'bg-orange-100 text-orange-700'
|
|
default: return 'bg-neutral-100 text-neutral-500'
|
|
}
|
|
}
|
|
|
|
function statusLabel(status: string): string {
|
|
return t(`dashboard.status.${status}`)
|
|
}
|
|
|
|
onMounted(loadDashboard)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="px-4 py-8 sm:px-8 lg:px-16">
|
|
<div class="flex items-center justify-between pb-6">
|
|
<h1 class="text-2xl font-bold text-primary-500 sm:text-4xl">{{ t('dashboard.title') }}</h1>
|
|
<MalioButtonIcon
|
|
icon="mdi:refresh"
|
|
:aria-label="t('dashboard.refresh')"
|
|
icon-size="22"
|
|
@click="loadDashboard"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Loading -->
|
|
<div v-if="loading && !data" class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<div v-for="i in 3" :key="i" class="rounded-lg bg-tertiary-500 p-5 animate-pulse">
|
|
<div class="h-6 bg-neutral-300 rounded w-1/3 mb-4" />
|
|
<div class="h-4 bg-neutral-300 rounded w-2/3 mb-2" />
|
|
<div class="h-4 bg-neutral-300 rounded w-1/2" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dashboard cards -->
|
|
<div v-else-if="data" class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<NuxtLink
|
|
v-for="app in data.applications"
|
|
:key="app.slug"
|
|
:to="`/applications/${app.slug}`"
|
|
class="rounded-lg bg-tertiary-500 p-5 transition hover:shadow-md"
|
|
>
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold text-neutral-900">{{ app.name }}</h3>
|
|
<a
|
|
v-if="app.giteaUrl"
|
|
:href="app.giteaUrl"
|
|
target="_blank"
|
|
class="text-neutral-400 hover:text-primary-500"
|
|
@click.stop
|
|
>
|
|
<Icon name="mdi:open-in-new" size="18" />
|
|
</a>
|
|
</div>
|
|
|
|
<div v-for="env in app.environments" :key="env.id" class="flex items-center justify-between py-2 border-t border-neutral-200 first:border-t-0">
|
|
<span class="text-sm text-neutral-700">{{ env.name }}</span>
|
|
<div class="flex items-center gap-3">
|
|
<span class="text-xs font-mono text-neutral-400">{{ env.version }}</span>
|
|
<span
|
|
class="inline-block rounded-full px-2.5 py-0.5 text-xs font-semibold"
|
|
:class="statusClass(env.status)"
|
|
>
|
|
{{ statusLabel(env.status) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="!app.environments.length" class="text-sm text-neutral-400">
|
|
{{ t('applications.card.noEnvironments') }}
|
|
</div>
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</template>
|