diff --git a/apps/web/app.js b/apps/web/app.js index 99eab5d..87f3b81 100644 --- a/apps/web/app.js +++ b/apps/web/app.js @@ -265,7 +265,7 @@ $('jobDetailPanel').innerHTML = `

JOB DETAIL

${esc(job.name || job.type || `Job ${job.id}`)}

ID ${esc(job.id)}

${esc(jobLabel(status))}
${status === 'running' ? `${progress}% complete` : jobLabel(status)}${esc(job.progress_message || job.message || '')}
${error ? `` : ''}
${canCancel ? '' : ''}${canRetry ? '' : ''}${!canCancel && !canRetry && !canManageJobs() ? 'Your role cannot change jobs.' : ''}

Event timeline

${Array.isArray(events) && events.length ? `
    ${events.map(event => `
  1. ${esc(eventText(event))}${esc(event.created_at || event.timestamp || event.at || '')}${event.progress != null ? `${esc(event.progress)}%` : ''}
  2. `).join('')}
` : '

No events returned yet.

'}
`; } async function loadJobDetail(id) { selectedJobId = id; renderJobsList(); $('jobDetailPanel').innerHTML = '
Loading job detail…
'; try { const job = await jobsRequest(`/api/v1/jobs/${encodeURIComponent(id)}`); let events = job.events || job.event_timeline; if (!events) { const eventPayload = await jobsRequest(`/api/v1/jobs/${encodeURIComponent(id)}/events`); events = eventPayload.events || eventPayload.items || eventPayload; } renderJobDetail(job, events); } catch (error) { if (error.message !== 'unauthorized') $('jobDetailPanel').innerHTML = ``; } } - async function loadJobs({silent = false} = {}) { if (!silent) { jobMessage('Loading jobs…'); resetJobCounts(); } try { const payload = await jobsRequest('/api/v1/jobs'); jobs = Array.isArray(payload) ? payload : (payload.jobs || payload.items || []); renderJobCounts(payload); renderJobsList(); $('jobsUpdatedAt').textContent = `Updated ${new Date().toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}`; jobMessage(''); const active = jobs.some(job => ['queued','running'].includes(jobStatus(job))); if (active && !jobPollTimer) jobPollTimer = setInterval(() => loadJobs({silent:true}), 5000); if (!active && jobPollTimer) { clearInterval(jobPollTimer); jobPollTimer = null; } if (selectedJobId) { const selected = jobs.find(job => String(job.id) === String(selectedJobId)); if (selected) await loadJobDetail(selectedJobId); } } catch (error) { jobs = []; resetJobCounts(); renderJobsList(); if (error.message !== 'unauthorized') jobMessage(error.message || 'Unable to load jobs.', true); } } + async function loadJobs({silent = false} = {}) { if (!silent) { jobMessage('Loading jobs…'); resetJobCounts(); } try { const payload = await jobsRequest('/api/v1/jobs'); jobs = Array.isArray(payload) ? payload : (payload.jobs || payload.items || []); renderJobCounts(payload); renderJobsList(); $('jobsUpdatedAt').textContent = `Updated ${new Date().toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}`; jobMessage(''); const active = jobs.some(job => ['queued','running'].includes(jobStatus(job))); if (active && !jobPollTimer) jobPollTimer = setInterval(() => loadJobs({silent:true}), 5000); if (!active && jobPollTimer) { clearInterval(jobPollTimer); jobPollTimer = null; } if (selectedJobId) { const selected = jobs.find(job => String(job.id) === String(selectedJobId)); if (selected) await loadJobDetail(selectedJobId); } } catch (error) { jobs = []; resetJobCounts(); renderJobsList(); if (error.message === 'unauthorized') { showLogin('Your session expired. Please sign in again.'); } else { jobMessage(error.message || 'Unable to load jobs.', true); } } } function updateJobPermissions() {} let sources = [], selectedSourceId = null; diff --git a/apps/web/asset-manifest.json b/apps/web/asset-manifest.json index ee5f8e1..aa893a4 100644 --- a/apps/web/asset-manifest.json +++ b/apps/web/asset-manifest.json @@ -14,7 +14,7 @@ ], "integrity": { "config.js": "sha256-7310c02ad6a24ab7d1b49536bfea169ef28f7eb55ccbfe77cb8b0ee1918319ca", - "app.js": "sha256-4956869c375eda23362c2345ee951a322693295b3eeba8a9481c754fb4fa2103", + "app.js": "sha256-dc030f75621e40194f98dc5bf94a2dd262fec44a0a43f2b0e1b97de3526b1033", "styles.css": "sha256-c1b192a15de735819fbb7ec3cddc9574808ae366a8255b4f690a7a40bc21caba", "index.html": "sha256-3a6a3f7e0d4780c1fadfbd77671e6a2472d99c5e891d08c86759d8475bf38986", "health.html": "sha256-c352a6f37aa24628cfc8d5709a70ff2d94181d192ed5fe00916cca9378a61d81",