<template> <Loading class="content" :loading="loading" :message="error" type="danger"> <div class="block"> <h1> <Icon name="cube">{{ container_name }}</Icon> <router-link class="button ml-2" :to="`/update/${container_name}`"> <Icon name="edit">Update</Icon> </router-link> <button class="button ml-2" @click="refresh"> <Icon name="refresh">Refresh</Icon> </button> </h1> </div> <div class="box"> <div class="block is-flex is-align-items-baseline"> <Icon name="image"> <b>Image:</b> <span class="m-2">{{ container?.image }}</span> </Icon> <button class="button ml-2" @click="pull"> <Icon name="cloud-download">Pull</Icon> </button> <button class="button ml-2" @click="remove"> <Icon name="trash">Remove</Icon> </button> </div> <div class="block is-flex is-align-items-baseline"> <Icon name="support"> <b>Status:</b> </Icon> <Icon :class="`has-text-${status_icon.type} m-2`" :name="status_icon.name" > {{ container?.status }} </Icon> <button v-if="container?.status == 'running'" class="button ml-2" @click="restart" > <Icon name="refresh">Restart</Icon> </button> <button v-if="container?.status == 'running'" class="button ml-2" @click="stop" > <Icon name="stop">Stop</Icon> </button> <button v-if="container?.status != 'running'" class="button ml-2" @click="start" > <Icon name="play">Start</Icon> </button> </div> <div class="block is-flex is-align-items-baseline"> <Icon name="image"><b>Logs:</b></Icon> <a class="button ml-2" :download="`${container_name}_logs.txt`" :href="`/api/container/${container_name}/logs`" > <Icon name="download">Download</Icon> </a> </div> <pre>{{ container?.logs?.trim().split('\n').reverse().join('\n') }}</pre> </div> </Loading> </template> <script lang="ts"> import axios, { AxiosError } from 'axios' import type { Container } from '../types' import Icon from '../components/Icon.vue' import Loading from '../components/Loading.vue' import { get_status_icon } from '../utils' export default { name: 'Container', components: { Icon, Loading, }, data() { return { container: null as Container | null, error: '', loading: true, } }, computed: { container_name(): string { return this.$route.params.name as string }, status_icon(): { name: string; type: string } { return get_status_icon(this.container?.status ?? 'unknown') }, }, async mounted() { await this.refresh() }, methods: { async request(method: 'get' | 'post' | 'delete', path: string) { try { this.loading = true const response = await axios[method]<Container>(path) this.container = response.data } catch (error) { console.error(error) this.error = error instanceof AxiosError ? error.message : 'Error performing operation' } finally { this.loading = false } }, async pull() { await this.request('post', `/api/container/${this.container_name}/pull`) }, async refresh() { await this.request('get', `/api/container/${this.container_name}`) }, async remove() { if (!confirm('Are you sure you want to remove this container?')) return await this.request('delete', `/api/container/${this.container_name}`) this.$router.push('/') }, async restart() { this.request('post', `/api/container/${this.container_name}/restart`) }, async start() { this.request('post', `/api/container/${this.container_name}/start`) }, async stop() { this.request('post', `/api/container/${this.container_name}/stop`) }, }, } </script>