feat(selfhost): show sanitized update logs in admin UI
This commit is contained in:
@@ -7,9 +7,11 @@ export type UpdateJob = UpdateState & {
|
||||
plan?: { version: string; revision: string; previousVersion?: string; updateAvailable: boolean;
|
||||
requiresComposeAdoption: boolean; estimatedBackupBytes?: number; retiredServices: string[] };
|
||||
}
|
||||
export type UpdateLogs = { requestId: string; logs: { source: 'service' | 'events' | 'commands'; content: string; truncated: boolean }[] }
|
||||
type Overview = {
|
||||
acceptingRequests: boolean; engine: UpdateState; request?: UpdateJob;
|
||||
installed: { version?: string }; backend: { version: string; revision: string };
|
||||
capabilities?: { requestLogs: boolean };
|
||||
}
|
||||
type Submission = { command: 'check' | 'apply'; body: { requestId: string; version?: string; checkRequestId?: string } }
|
||||
|
||||
@@ -24,6 +26,12 @@ export const useSelfhostUpdates = () => {
|
||||
const refreshing = ref(false)
|
||||
const message = ref('')
|
||||
const accessDenied = ref(false)
|
||||
const logs = ref<UpdateLogs | null>(null)
|
||||
const logsOpen = ref(false)
|
||||
const logsLoading = ref(false)
|
||||
const logsMessage = ref('')
|
||||
const logEntries = computed(() => logs.value?.requestId === job.value?.requestId ? logs.value?.logs || [] : [])
|
||||
let openedFailureId: string | undefined
|
||||
let stopped = false
|
||||
let generation = 0
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
@@ -55,6 +63,28 @@ export const useSelfhostUpdates = () => {
|
||||
message.value = error?.data?.error?.message || 'Der Update-Dienst ist nicht erreichbar. Dienst und Socket-Einbindung auf dem Host prüfen.'
|
||||
}
|
||||
}
|
||||
const refreshLogs = async () => {
|
||||
const id = job.value?.requestId
|
||||
if (!logsOpen.value || !id || stopped || accessDenied.value || logsLoading.value) return
|
||||
if (logs.value?.requestId !== id) { logs.value = null; logsMessage.value = '' }
|
||||
if (!overview.value?.capabilities?.requestLogs) {
|
||||
logsMessage.value = 'Dieser Host-Update-Dienst unterstützt die Protokollansicht noch nicht. Die zusammengehörigen Host-Update-Dateien aktualisieren und den Dienstinstaller erneut ausführen. Bis dahin liegen die Protokolle auf dem Host unter .updates/.'
|
||||
return
|
||||
}
|
||||
const currentGeneration = generation
|
||||
logsLoading.value = true
|
||||
try {
|
||||
const result = await api<UpdateLogs>(`requests/${encodeURIComponent(id)}/logs`)
|
||||
if (stopped || currentGeneration !== generation || job.value?.requestId !== id) return
|
||||
logs.value = result
|
||||
logsMessage.value = ''
|
||||
} catch (error: any) {
|
||||
if (stopped || currentGeneration !== generation || job.value?.requestId !== id) return
|
||||
logsMessage.value = error?.data?.error?.message || 'Das Update-Protokoll konnte nicht geladen werden. Die Abfrage wird automatisch wiederholt.'
|
||||
if ([401, 403].includes(errorStatus(error))) { logs.value = null; report(error) }
|
||||
} finally { logsLoading.value = false }
|
||||
}
|
||||
const toggleLogs = async () => { logsOpen.value = !logsOpen.value; await refreshLogs() }
|
||||
const refresh = async () => {
|
||||
if (refreshing.value || stopped || accessDenied.value) return
|
||||
refreshing.value = true
|
||||
@@ -81,6 +111,11 @@ export const useSelfhostUpdates = () => {
|
||||
connected.value = true
|
||||
message.value = pending.value ? 'Start noch nicht bestätigt. Du kannst denselben Auftrag erneut senden.' : ''
|
||||
persist()
|
||||
if (['failed', 'interrupted'].includes(job.value?.status || '') && openedFailureId !== job.value?.requestId) {
|
||||
openedFailureId = job.value?.requestId
|
||||
logsOpen.value = true
|
||||
}
|
||||
await refreshLogs()
|
||||
} catch (error) {
|
||||
if (currentGeneration !== generation || stopped) return
|
||||
connected.value = false
|
||||
@@ -90,6 +125,8 @@ export const useSelfhostUpdates = () => {
|
||||
const sendPending = async () => {
|
||||
if (!pending.value || submitting.value || accessDenied.value) return
|
||||
generation++
|
||||
logs.value = null
|
||||
logsMessage.value = ''
|
||||
submitting.value = true
|
||||
const submission = pending.value
|
||||
try {
|
||||
@@ -109,6 +146,7 @@ export const useSelfhostUpdates = () => {
|
||||
report(error)
|
||||
}
|
||||
} finally { submitting.value = false; persist() }
|
||||
await refreshLogs()
|
||||
}
|
||||
const check = async () => {
|
||||
if (!available.value) return
|
||||
@@ -145,5 +183,5 @@ export const useSelfhostUpdates = () => {
|
||||
})
|
||||
onBeforeUnmount(() => { stopped = true; clearTimeout(timer) })
|
||||
return { overview, job, pending, connected, submitting, refreshing, message, accessDenied, recovery, busy, available, canApply,
|
||||
check, apply, refresh, sendPending }
|
||||
logsOpen, logsLoading, logsMessage, logEntries, refreshLogs, toggleLogs, check, apply, refresh, sendPending }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user