pilotwings/frontend/views/Container.vue

169 lines
4.7 KiB
Vue

<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 class="button ml-2" @click="restart">
<Icon name="refresh">Restart</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'
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 } {
if (!this.container) return { name: 'question-circle', type: 'warning' }
switch (this.container.status) {
case 'running':
return { name: 'play', type: 'success' }
case 'restarting':
return { name: 'refresh', type: 'danger' }
case 'paused':
return { name: 'pause', type: 'warning' }
case 'exited':
return { name: 'stop', type: 'danger' }
default:
return { name: 'question-circle', type: 'warning' }
}
},
},
async mounted() {
await this.refresh()
},
methods: {
async pull() {
try {
this.loading = true
const response = await axios.post<Container>(
`/api/container/${this.container_name}/pull`,
)
this.container = response.data
} catch (error) {
console.error(error)
this.error =
error instanceof AxiosError
? error.message
: 'Error pulling container'
} finally {
this.loading = false
}
},
async refresh() {
try {
this.loading = true
const response = await axios.get<Container>(
`/api/container/${this.container_name}`,
)
this.container = response.data
} catch (error) {
console.error(error)
this.error =
error instanceof AxiosError
? error.message
: 'Error loading container'
} finally {
this.loading = false
}
},
async remove() {
if (!confirm('Are you sure you want to remove this container?')) return
try {
this.loading = true
await axios.delete(`/api/container/${this.container_name}`)
this.$router.push('/')
} catch (error) {
console.error(error)
this.error =
error instanceof AxiosError
? error.message
: 'Error deleting container'
} finally {
this.loading = false
}
},
async restart() {
try {
this.loading = true
const response = await axios.post<Container>(
`/api/container/${this.container_name}/restart`,
)
this.container = response.data
} catch (error) {
console.error(error)
this.error =
error instanceof AxiosError
? error.message
: 'Error restarting container'
} finally {
this.loading = false
}
},
},
}
</script>