118 lines
2.5 KiB
Vue
118 lines
2.5 KiB
Vue
<script setup>
|
|
import { ref, onMounted, onUnmounted } from 'vue'
|
|
import DeployButton from './components/DeployButton.vue'
|
|
import DeployProgress from './components/DeployProgress.vue'
|
|
import DeployLogs from './components/DeployLogs.vue'
|
|
|
|
const status = ref({
|
|
running: false,
|
|
step: 0,
|
|
total_steps: 12,
|
|
current_step: '',
|
|
logs: [],
|
|
error: null,
|
|
})
|
|
|
|
let pollingInterval = null
|
|
|
|
const getCsrfToken = () => {
|
|
const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/)
|
|
return match ? decodeURIComponent(match[1]) : ''
|
|
}
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'X-XSRF-TOKEN': getCsrfToken(),
|
|
'Accept': 'application/json',
|
|
}
|
|
|
|
const fetchStatus = async () => {
|
|
try {
|
|
const response = await fetch('/api/deploy/status', {
|
|
credentials: 'same-origin',
|
|
headers,
|
|
})
|
|
const text = await response.text()
|
|
|
|
try {
|
|
status.value = JSON.parse(text)
|
|
} catch {
|
|
console.error('Status response is not JSON:', text.substring(0, 200))
|
|
return
|
|
}
|
|
|
|
if (!status.value.running && pollingInterval) {
|
|
clearInterval(pollingInterval)
|
|
pollingInterval = null
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch status:', error)
|
|
}
|
|
}
|
|
|
|
const startDeploy = async () => {
|
|
try {
|
|
const response = await fetch('/api/deploy', {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers,
|
|
})
|
|
const text = await response.text()
|
|
console.log('Deploy response:', response.status, text)
|
|
|
|
let data
|
|
try {
|
|
data = JSON.parse(text)
|
|
} catch {
|
|
alert('Server returned HTML instead of JSON. Check console.')
|
|
return
|
|
}
|
|
|
|
if (response.ok) {
|
|
startPolling()
|
|
} else {
|
|
alert(data.error || 'Failed to start deploy')
|
|
}
|
|
} catch (error) {
|
|
alert('Failed to start deploy: ' + error.message)
|
|
}
|
|
}
|
|
|
|
const startPolling = () => {
|
|
if (pollingInterval) return
|
|
pollingInterval = setInterval(fetchStatus, 2000)
|
|
}
|
|
|
|
onMounted(() => {
|
|
fetchStatus()
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="max-w-4xl mx-auto p-6">
|
|
<h1 class="text-2xl font-bold mb-6">Deploy</h1>
|
|
|
|
<DeployButton
|
|
:running="status.running"
|
|
@deploy="startDeploy"
|
|
/>
|
|
|
|
<DeployProgress
|
|
v-if="status.running || status.step > 0"
|
|
:step="status.step"
|
|
:total-steps="status.total_steps"
|
|
:current-step="status.current_step"
|
|
:success="status.success"
|
|
:error="status.error"
|
|
/>
|
|
|
|
<DeployLogs :logs="status.logs" />
|
|
</div>
|
|
</template>
|