新增: DockerNode+CI状态读取+模板CRUD+CIStatus面板
- DockerNode: 环境检测(docker --version)+授权+容器内执行(12个测试) - ci_status.rs: Gitea commit status API 读取(7个测试,失败返回空不阻塞) - CIStatus.vue: CI检查面板(通过/失败/pending 汇总+可点击跳转) - 模板CRUD IPC: list/save/delete templates(内置只读+自定义KV持久化) - TemplateInfo 结构体(IPC传输用) - 零编译警告,vue-tsc+vite build 通过
This commit is contained in:
120
src/components/ai/CIStatus.vue
Normal file
120
src/components/ai/CIStatus.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="ci-status" v-if="statuses.length > 0">
|
||||
<div class="ci-header">
|
||||
<span class="ci-title">CI 检查</span>
|
||||
<span class="ci-summary" :class="summaryClass">{{ summaryText }}</span>
|
||||
</div>
|
||||
<div class="ci-list">
|
||||
<a
|
||||
v-for="check in statuses"
|
||||
:key="check.name"
|
||||
:href="check.url || undefined"
|
||||
class="ci-item"
|
||||
:class="'ci-item--' + check.status"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
<span class="ci-item-icon">{{ statusIcon(check.status) }}</span>
|
||||
<span class="ci-item-name">{{ check.name }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted } from 'vue'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
interface CheckStatus {
|
||||
name: string
|
||||
status: string
|
||||
url: string | null
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
repoUrl: string
|
||||
commitSha: string
|
||||
}>()
|
||||
|
||||
const statuses = ref<CheckStatus[]>([])
|
||||
|
||||
const summaryClass = computed(() => {
|
||||
const hasFailure = statuses.value.some(s => s.status === 'failure')
|
||||
const hasPending = statuses.value.some(s => s.status === 'pending')
|
||||
if (hasFailure) return 'ci-summary--fail'
|
||||
if (hasPending) return 'ci-summary--pending'
|
||||
return 'ci-summary--pass'
|
||||
})
|
||||
|
||||
const summaryText = computed(() => {
|
||||
const pass = statuses.value.filter(s => s.status === 'success').length
|
||||
const fail = statuses.value.filter(s => s.status === 'failure').length
|
||||
const pending = statuses.value.filter(s => s.status === 'pending').length
|
||||
if (fail > 0) return `${fail} 项失败`
|
||||
if (pending > 0) return `${pending} 项进行中`
|
||||
return `${pass} 项通过`
|
||||
})
|
||||
|
||||
function statusIcon(status: string): string {
|
||||
switch (status) {
|
||||
case 'success': return '✓'
|
||||
case 'failure': return '✗'
|
||||
case 'pending': return '⏳'
|
||||
default: return '○'
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
statuses.value = await invoke<CheckStatus[]>('get_commit_status', {
|
||||
repoUrl: props.repoUrl,
|
||||
commitSha: props.commitSha,
|
||||
})
|
||||
} catch {
|
||||
statuses.value = []
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ci-status {
|
||||
border: 1px solid var(--df-border);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
margin: 8px 0;
|
||||
background: var(--df-bg-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
.ci-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.ci-title { color: var(--df-text); }
|
||||
.ci-summary--pass { color: var(--df-success); }
|
||||
.ci-summary--fail { color: var(--df-danger); }
|
||||
.ci-summary--pending { color: var(--df-warning); }
|
||||
.ci-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
.ci-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
background: var(--df-bg);
|
||||
border: 1px solid var(--df-border);
|
||||
text-decoration: none;
|
||||
color: var(--df-text);
|
||||
}
|
||||
.ci-item--success { border-color: var(--df-success); }
|
||||
.ci-item--failure { border-color: var(--df-danger); }
|
||||
.ci-item--pending { border-color: var(--df-warning); }
|
||||
.ci-item-icon { font-size: 10px; font-weight: 700; }
|
||||
.ci-item:hover { opacity: 0.8; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user