feat: align UI routes and menu with implemented screens
ci / backend (push) Failing after 0s
ci / static (push) Failing after 11s
ci / backend (pull_request) Failing after 1s
ci / static (pull_request) Failing after 12s
Build & Test with Secrets / build (pull_request) Failing after 2s
ci / publish (push) Has been cancelled
ci / frontend (push) Has been cancelled
Build & Test with Secrets / security-scan (pull_request) Has been cancelled
Build & Test with Secrets / notification (pull_request) Has been cancelled
Build & Test with Secrets / frontend (pull_request) Has been cancelled
ci / publish (pull_request) Has been cancelled
ci / frontend (pull_request) Has been cancelled

This commit is contained in:
2026-08-06 01:39:33 +09:00
parent 510a30eee0
commit dfa1680a19
10 changed files with 1093 additions and 68 deletions
@@ -76,49 +76,88 @@
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref, computed, onMounted } from 'vue'
interface IngestionJob {
jobId: string
status: string
rowsProcessed: number
rowsFailed: number
rowsSkipped?: number
durationSeconds?: number
completedAt?: string
errorMessage?: string
}
// Mock data (real implementation would fetch from API)
const job = ref<IngestionJob>({
jobId: '550e8400-e29b-41d4-a716-446655440000',
status: 'Completed',
rowsProcessed: 2048,
rowsFailed: 12,
durationSeconds: 45,
completedAt: new Date().toISOString(),
const job = ref<IngestionJob | null>(null)
const recentJobs = ref<IngestionJob[]>([])
const isLoading = ref(true)
const error = ref<string | null>(null)
// Fetch latest job status from API
const fetchLatestJob = async () => {
try {
// In a real app, this would fetch from /api/market/ingest/latest
// For now, we'll show a loading state
const response = await fetch('/api/market/ingest/latest', {
headers: {
'X-KArtSell-User': 'ingestion-user',
'X-KArtSell-Role': 'DataAdmin',
},
})
if (response.ok) {
job.value = await response.json()
} else if (response.status === 404) {
// No jobs yet - that's fine
job.value = null
} else {
throw new Error(`API error: ${response.status}`)
}
} catch (err) {
console.error('Failed to fetch latest job:', err)
// Don't fail the page, just show no data
job.value = null
}
}
// Fetch recent jobs history
const fetchRecentJobs = async () => {
try {
const response = await fetch('/api/market/ingest/history?limit=10', {
headers: {
'X-KArtSell-User': 'ingestion-user',
'X-KArtSell-Role': 'DataAdmin',
},
})
if (response.ok) {
recentJobs.value = await response.json()
}
} catch (err) {
console.error('Failed to fetch recent jobs:', err)
error.value = 'Failed to load job history'
} finally {
isLoading.value = false
}
}
onMounted(() => {
fetchLatestJob()
fetchRecentJobs()
// Auto-refresh every 10 seconds if there's an active job
const interval = setInterval(() => {
if (job.value?.status === 'Running' || job.value?.status === 'Queued') {
fetchLatestJob()
}
}, 10000)
return () => clearInterval(interval)
})
const recentJobs = ref<IngestionJob[]>([
{
jobId: '550e8400-e29b-41d4-a716-446655440000',
status: 'Completed',
rowsProcessed: 2048,
rowsFailed: 12,
durationSeconds: 45,
completedAt: new Date().toISOString(),
},
{
jobId: '550e8400-e29b-41d4-a716-446655440001',
status: 'Completed',
rowsProcessed: 2015,
rowsFailed: 8,
durationSeconds: 38,
completedAt: new Date(Date.now() - 86400000).toISOString(),
},
])
const calculateQualityScore = (job: IngestionJob): number => {
const total = job.rowsProcessed + job.rowsFailed
const total = job.rowsProcessed + job.rowsFailed + (job.rowsSkipped || 0)
if (total === 0) return 0
return Math.round((job.rowsProcessed / total) * 100)
}