dfa1680a19
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
247 lines
10 KiB
JavaScript
247 lines
10 KiB
JavaScript
import { ref, onMounted } from 'vue';
|
|
const job = ref(null);
|
|
const recentJobs = ref([]);
|
|
const isLoading = ref(true);
|
|
const error = ref(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 calculateQualityScore = (job) => {
|
|
const total = job.rowsProcessed + job.rowsFailed + (job.rowsSkipped || 0);
|
|
if (total === 0)
|
|
return 0;
|
|
return Math.round((job.rowsProcessed / total) * 100);
|
|
};
|
|
const __VLS_ctx = {
|
|
...{},
|
|
...{},
|
|
};
|
|
let __VLS_components;
|
|
let __VLS_intrinsics;
|
|
let __VLS_directives;
|
|
/** @type {__VLS_StyleScopedClasses['header']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-header']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['value']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-completed']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['status-failed']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "ingestion-status" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['ingestion-status']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "header" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['header']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.h1, __VLS_intrinsics.h1)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({
|
|
...{ class: "subtitle" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['subtitle']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "content" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['content']} */ ;
|
|
if (__VLS_ctx.job) {
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "status-card" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['status-card']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "status-header" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['status-header']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.h2, __VLS_intrinsics.h2)({});
|
|
(__VLS_ctx.job.jobId.substring(0, 8));
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: (['status-badge', `status-${__VLS_ctx.job.status.toLowerCase()}`]) },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
(__VLS_ctx.job.status);
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "status-grid" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['status-grid']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "stat" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "label" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['label']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "value" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['value']} */ ;
|
|
(__VLS_ctx.job.rowsProcessed.toLocaleString());
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "stat" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "label" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['label']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "value error" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['value']} */ ;
|
|
/** @type {__VLS_StyleScopedClasses['error']} */ ;
|
|
(__VLS_ctx.job.rowsFailed);
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "stat" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "label" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['label']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "value" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['value']} */ ;
|
|
(__VLS_ctx.calculateQualityScore(__VLS_ctx.job));
|
|
if (__VLS_ctx.job.durationSeconds) {
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "stat" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['stat']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "label" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['label']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: "value" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['value']} */ ;
|
|
(__VLS_ctx.job.durationSeconds);
|
|
}
|
|
if (__VLS_ctx.job.errorMessage) {
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "error-section" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['error-section']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.strong, __VLS_intrinsics.strong)({});
|
|
(__VLS_ctx.job.errorMessage);
|
|
}
|
|
}
|
|
else {
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "loading" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['loading']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.p, __VLS_intrinsics.p)({});
|
|
}
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.div, __VLS_intrinsics.div)({
|
|
...{ class: "history-section" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['history-section']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.h3, __VLS_intrinsics.h3)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.table, __VLS_intrinsics.table)({
|
|
...{ class: "history-table" },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['history-table']} */ ;
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.thead, __VLS_intrinsics.thead)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.tr, __VLS_intrinsics.tr)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.th, __VLS_intrinsics.th)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.th, __VLS_intrinsics.th)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.th, __VLS_intrinsics.th)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.th, __VLS_intrinsics.th)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.th, __VLS_intrinsics.th)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.tbody, __VLS_intrinsics.tbody)({});
|
|
for (const [item, idx] of __VLS_vFor((__VLS_ctx.recentJobs))) {
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.tr, __VLS_intrinsics.tr)({
|
|
key: (idx),
|
|
...{ class: (`status-${item.status.toLowerCase()}`) },
|
|
});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.td, __VLS_intrinsics.td)({});
|
|
(item.jobId.substring(0, 8));
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.td, __VLS_intrinsics.td)({});
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.span, __VLS_intrinsics.span)({
|
|
...{ class: (['status-badge', `status-${item.status.toLowerCase()}`]) },
|
|
});
|
|
/** @type {__VLS_StyleScopedClasses['status-badge']} */ ;
|
|
(item.status);
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.td, __VLS_intrinsics.td)({});
|
|
(item.rowsProcessed);
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.td, __VLS_intrinsics.td)({});
|
|
(item.durationSeconds ? `${item.durationSeconds}s` : '—');
|
|
__VLS_asFunctionalElement1(__VLS_intrinsics.td, __VLS_intrinsics.td)({});
|
|
(item.completedAt ? new Date(item.completedAt).toLocaleDateString() : '—');
|
|
// @ts-ignore
|
|
[job, job, job, job, job, job, job, job, job, job, job, calculateQualityScore, recentJobs,];
|
|
}
|
|
// @ts-ignore
|
|
[];
|
|
const __VLS_export = (await import('vue')).defineComponent({});
|
|
export default {};
|