feat: add pricing job activity view
Quality / test (push) Canceled after 0s

This commit is contained in:
2026-09-09 17:39:08 -04:00
parent af563b691d
commit 22d13af604
7 changed files with 109 additions and 2 deletions
+18 -1
View File
@@ -10,6 +10,7 @@ import { createAdminSale, listAdminSales, voidAdminSale } from '@/services/admin
import { createAdminAcquisition, listAdminAcquisitions } from '@/services/admin-acquisition-service.js';
import { getAdminDashboard } from '@/services/admin-dashboard-service.js';
import { addAdminPricingObservation, calculateAdminValuation, enqueueAdminPricingRefresh, getAdminPricingJob, overrideAdminValuation } from '@/services/admin-pricing-service.js';
import { listAdminPricingJobs, retryAdminPricingJob } from '@/services/admin-jobs-service.js';
import { createAdminProviderMapping, listAdminProviderMappings } from '@/services/admin-provider-mapping-service.js';
const { principal } = useAuth();
@@ -56,6 +57,7 @@ const mappingType = ref('PRODUCT');
const mappingExternalIdentifier = ref('');
const mappingSearchQuery = ref('');
const providerMappings = ref([]);
const pricingJobs = ref([]);
function csrfToken() {
return document.cookie.split('; ').find((value) => value.startsWith('pokemon_inventory_csrf='))?.split('=')[1] ?? '';
@@ -64,7 +66,7 @@ function csrfToken() {
async function load() {
isLoading.value = true;
try {
[products.value, inventory.value, categories.value, conditions.value, listings.value, sales.value, acquisitions.value, dashboard.value] = await Promise.all([listAdminProducts(), listAdminInventory(), listAdminCategories(), listAdminConditions(), listAdminListings(), listAdminSales(), listAdminAcquisitions(), getAdminDashboard()]);
[products.value, inventory.value, categories.value, conditions.value, listings.value, sales.value, acquisitions.value, dashboard.value, pricingJobs.value] = await Promise.all([listAdminProducts(), listAdminInventory(), listAdminCategories(), listAdminConditions(), listAdminListings(), listAdminSales(), listAdminAcquisitions(), getAdminDashboard(), listAdminPricingJobs()]);
} catch (requestError) { error.value = requestError; }
finally { isLoading.value = false; }
}
@@ -207,6 +209,15 @@ async function refreshPricing() {
} finally { isSaving.value = false; }
}
async function retryPricingJob(jobId) {
isSaving.value = true;
try {
await retryAdminPricingJob(jobId, csrfToken());
pricingJobs.value = await listAdminPricingJobs();
} catch (requestError) { error.value = requestError; }
finally { isSaving.value = false; }
}
async function overridePricing() {
isSaving.value = true;
try {
@@ -394,6 +405,12 @@ onMounted(load);
<span v-if="valuation.observations?.some(({ isOutlier }) => isOutlier)"> · OUTLIER FLAGGED</span>
</li>
</ul>
<ul v-if="pricingJobs.length" aria-label="Pricing jobs">
<li v-for="job in pricingJobs" :key="job.id">
{{ job.id }} · {{ job.providerId }} · {{ job.status }}<span v-if="job.error"> · {{ job.error }}</span>
<button v-if="job.status === 'FAILED'" class="button button--secondary" type="button" :disabled="isSaving" @click="retryPricingJob(job.id)">Retry job</button>
</li>
</ul>
</section>
<section class="admin-list" aria-labelledby="listings-title">
<h2 id="listings-title">Listings</h2>
@@ -0,0 +1,23 @@
const apiBaseUrl = import.meta.env?.VITE_API_BASE_URL ?? '/api/v1';
async function request(path, options = {}) {
const response = await fetch(`${apiBaseUrl}${path}`, {
credentials: 'include',
...options,
headers: { ...(options.body ? { 'content-type': 'application/json' } : {}), ...options.headers },
});
const payload = await response.json().catch(() => null);
if (!response.ok) throw new Error(payload?.error?.message ?? 'Job request failed.');
return payload?.data;
}
export function listAdminPricingJobs() {
return request('/admin/jobs');
}
export function retryAdminPricingJob(jobId, csrfToken) {
return request(`/admin/jobs/${encodeURIComponent(jobId)}/retry`, {
method: 'POST',
headers: { 'x-csrf-token': csrfToken },
});
}