feat: add asynchronous inventory exports
Quality / test (push) Canceled after 0s

This commit is contained in:
2026-09-10 01:25:11 -04:00
parent abb0b64217
commit 7c4885cf65
16 changed files with 269 additions and 1 deletions
@@ -58,6 +58,16 @@ export const InventoryExcelExport = {
},
};
export const AsyncInventoryExport = {
parameters: {
docs: {
description: {
story: 'The admin workspace can queue a large inventory JSON export and report its job status.',
},
},
},
};
export const BulkTagSelection = {
parameters: {
docs: {
+27
View File
@@ -14,6 +14,8 @@ import {
listAdminProducts,
refreshAdminInventoryPricing,
updateAdminInventoryTags,
enqueueAdminInventoryExport,
getAdminInventoryExportJob,
} from "@/services/admin-catalog-service.js";
import {
createAdminListing,
@@ -52,6 +54,7 @@ const products = ref([]);
const inventory = ref([]);
const selectedInventoryIds = ref([]);
const inventoryTags = ref("");
const exportStatus = ref("");
const listings = ref([]);
const sales = ref([]);
const acquisitions = ref([]);
@@ -254,6 +257,21 @@ async function updateSelectedTags(action) {
}
}
async function enqueueInventoryExport() {
isSaving.value = true;
exportStatus.value = "Starting export...";
try {
const job = await enqueueAdminInventoryExport(csrfToken());
const completed = await getAdminInventoryExportJob(job.id);
exportStatus.value = `Export ${completed.status.toLowerCase()}.`;
} catch (requestError) {
error.value = requestError;
exportStatus.value = "Inventory export failed.";
} finally {
isSaving.value = false;
}
}
async function createListing() {
const item = inventory.value.find(
(candidate) => candidate.id === listingInventoryId.value,
@@ -515,6 +533,15 @@ onMounted(load);
>
Download inventory Excel
</a>
<button
class="button button--secondary"
type="button"
:disabled="isSaving"
@click="enqueueInventoryExport"
>
Queue JSON export
</button>
<span v-if="exportStatus" role="status">{{ exportStatus }}</span>
</p>
<p v-if="isLoading" class="state state--loading" role="status">
Loading inventory...
@@ -46,4 +46,15 @@ export function updateAdminInventoryTags(inventoryItemIds, add, remove, csrfToke
headers: { 'x-csrf-token': csrfToken },
body: JSON.stringify({ action: 'TAGS', inventoryItemIds, add, remove }),
});
}
export function enqueueAdminInventoryExport(csrfToken) {
return request('/admin/exports/inventory.json/jobs', {
method: 'POST',
headers: { 'x-csrf-token': csrfToken },
});
}
export function getAdminInventoryExportJob(jobId) {
return request(`/admin/exports/jobs/${jobId}`);
}
+15
View File
@@ -70,6 +70,21 @@ test('archives selected admin inventory items through the bulk API', async () =>
}
});
test('fetches an admin inventory export job through the bulk job API', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => {
assert.equal(url, '/api/v1/admin/exports/jobs/job-1');
return { ok: true, async json() { return { data: { id: 'job-1', status: 'COMPLETED' } }; } };
};
try {
const { getAdminInventoryExportJob } = await import('../src/services/admin-catalog-service.js');
assert.deepEqual(await getAdminInventoryExportJob('job-1'), { id: 'job-1', status: 'COMPLETED' });
} finally {
globalThis.fetch = originalFetch;
}
});
test('enqueues selected admin inventory pricing refreshes through the bulk API', async () => {
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options) => {