refactor: rework async ServiceInfo

This commit is contained in:
axolotle 2024-08-13 00:28:06 +02:00
parent fe380005a5
commit e8b0e3b87c
2 changed files with 51 additions and 49 deletions

View file

@ -198,6 +198,17 @@ export type BackupList = {
}> }>
} }
// SERVICES
export type ServiceInfo = {
status: 'running' | 'stopped' | 'failed' | 'unknown'
start_on_boot: 'enabled' | 'disabled' | 'unknown'
last_state_change: string | 'unknown'
description: string
configuration: 'valid' | 'broken' | 'unknown'
}
export type ServiceLogs = Obj<string[]>
// DIAGNOSIS // DIAGNOSIS
export type Diagnosis = { export type Diagnosis = {

View file

@ -1,70 +1,61 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import api from '@/api' import api from '@/api'
import { useAutoModal } from '@/composables/useAutoModal' import { useAutoModal } from '@/composables/useAutoModal'
import { useInitialQueries } from '@/composables/useInitialQueries'
import { distanceToNow } from '@/helpers/filters/date' import { distanceToNow } from '@/helpers/filters/date'
import type { ServiceInfo, ServiceLogs } from '@/types/core/api'
const props = defineProps<{ const props = defineProps<{ name: string }>()
name: string
}>()
const { t } = useI18n() const { t } = useI18n()
const modalConfirm = useAutoModal() const modalConfirm = useAutoModal()
const { loading, refetch } = useInitialQueries(
[
{ uri: 'services/' + props.name },
{ uri: `services/${props.name}/log?number=50` },
],
{ onQueriesResponse },
)
const infos = ref() const { infos, upOrDownTime, isCritical, logs } = await api
const uptime = ref() .fetchAll<
const isCritical = ref() [ServiceInfo, ServiceLogs]
const logs = ref() >([{ uri: 'services/' + props.name }, { uri: `services/${props.name}/log?number=50` }])
const action = ref() .then(([service, logs]) => {
const { last_state_change, ...infos } = service
const criticalServices = ['nginx', 'ssh', 'slapd', 'yunohost-api']
function onQueriesResponse( return {
// eslint-disable-next-line infos,
{ status, description, start_on_boot, last_state_change, configuration }: any, upOrDownTime:
logs_: any, last_state_change === 'unknown'
) { ? t('unknown')
isCritical.value = ['nginx', 'ssh', 'slapd', 'yunohost-api'].includes( : distanceToNow(last_state_change, false),
props.name, isCritical: criticalServices.includes(props.name),
) logs: Object.keys(logs)
// eslint-disable-next-line
uptime.value = last_state_change === 'unknown' ? 0 : last_state_change
infos.value = { description, status, start_on_boot, configuration }
logs.value = Object.keys(logs_)
.sort((prev, curr) => { .sort((prev, curr) => {
if (prev === 'journalctl') return -1 if (prev === 'journalctl') return -1
else if (curr === 'journalctl') return 1 else if (curr === 'journalctl') return 1
else if (prev < curr) return -1 else if (prev < curr) return -1
else return 1 else return 1
}) })
.map((filename) => ({ content: logs_[filename].join('\n'), filename })) .map((filename) => ({
content: logs[filename].join('\n'),
filename,
})),
} }
})
async function updateService(action) { async function updateService(action: 'start' | 'stop' | 'restart') {
const confirmed = await modalConfirm( const confirmed = await modalConfirm(
t('confirm_service_' + action, { name: props.name }), t(`confirm_service_${action}`, { name: props.name }),
) )
if (!confirmed) return if (!confirmed) return
api api
.put({ .put({
uri: `services/${props.name}/${action}`, uri: `services/${props.name}/${action}`,
humanKey: { key: 'services.' + action, name: props.name }, humanKey: { key: `services.${action}`, name: props.name },
}) })
.then(() => refetch(false)) .then(() => api.refetch())
} }
function shareLogs() { function shareLogs() {
const logs = logs.value const logsContent = logs
.map(({ filename, content }) => { .map(({ filename, content }) => {
return `LOGFILE: ${filename}\n${content}` return `LOGFILE: ${filename}\n${content}`
}) })
@ -72,21 +63,21 @@ function shareLogs() {
fetch('https://paste.yunohost.org/documents', { fetch('https://paste.yunohost.org/documents', {
method: 'POST', method: 'POST',
body: logs, body: logsContent,
}) })
.then((response) => { .then((response) => {
if (response.ok) return response.json() if (response.ok) return response.json()
else console.error('error', response)
// FIXME flash error // FIXME flash error
/* eslint-disable-next-line */ else console.log('error', response)
}) })
.then(({ key }) => { .then(({ key }) => {
window.open('https://paste.yunohost.org/' + key, '_blank') window.open(`https://paste.yunohost.org/${key}`, '_blank')
}) })
} }
</script> </script>
<template> <template>
<ViewBase :loading="loading" skeleton="CardInfoSkeleton"> <div>
<!-- INFO CARD --> <!-- INFO CARD -->
<YCard :title="name" icon="info-circle" button-unbreak="sm"> <YCard :title="name" icon="info-circle" button-unbreak="sm">
<template #header-buttons> <template #header-buttons>
@ -129,7 +120,7 @@ function shareLogs() {
<YIcon :iname="value === 'running' ? 'check-circle' : 'times'" /> <YIcon :iname="value === 'running' ? 'check-circle' : 'times'" />
{{ $t(value) }} {{ $t(value) }}
</span> </span>
{{ $t('since') }} {{ distanceToNow(uptime) }} {{ $t('since') }} {{ upOrDownTime }}
</template> </template>
<span <span
@ -160,7 +151,7 @@ function shareLogs() {
<pre class="log"><code>{{ content }}</code></pre> <pre class="log"><code>{{ content }}</code></pre>
</template> </template>
</YCard> </YCard>
</ViewBase> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>