diff --git a/apps/web/app.js b/apps/web/app.js
index 545b6fb..897fac2 100644
--- a/apps/web/app.js
+++ b/apps/web/app.js
@@ -240,6 +240,7 @@
function renderReport(id,title,payload){const el=$(id);if(!el)return;const rows=reportRows(payload);const obj=payload?.summary||payload?.counts||payload||{};const fallback=Object.entries(obj).filter(([,v])=>typeof v==='number').slice(0,8);const entries=rows.length?rows.map(r=>[r.label||r.name||r.stage||r.outcome||r.type||'Metric',r.count??r.total??r.value??0]):fallback;if(!entries.length){el.innerHTML=`
${title}
No ${title.toLowerCase()} data returned.
`;return;}el.innerHTML=`${entries.map(([label,value])=>`
${esc(crmLabel(label))}${esc(value)}
`).join('')}
Tenant-scoped API results. Loading, unavailable, and empty are distinct states.
`;}
async function loadReports(){[['pipelineReport','pipeline report'],['outcomesReport','outcomes report'],['activityReport','activity report']].forEach(([id,title])=>{const el=$(id);if(el)el.innerHTML=`Loading ${title}…
`;});try{const [pipeline,outcomes,activity]=await Promise.all([jsonRequest('/api/v1/reports/pipeline'),jsonRequest('/api/v1/reports/outcomes'),jsonRequest('/api/v1/reports/activity')]);renderReport('pipelineReport','Pipeline',pipeline);renderReport('outcomesReport','Outcomes',outcomes);renderReport('activityReport','Activity',activity);}catch(error){if(error.message!=='unauthorized')[['pipelineReport','pipeline'],['outcomesReport','outcomes'],['activityReport','activity']].forEach(([id,label])=>{const el=$(id);if(el)el.innerHTML=`Unable to load ${label} report${esc(error.message)}
`;});}}
+ let jobs = [], selectedJobId = null, jobPollTimer = null;
const jobStatuses = ['queued','running','succeeded','failed','cancelled'];
const jobRole = () => String(currentUser?.role || currentUser?.roles?.[0] || '').toLowerCase();
const canManageJobs = () => ['admin','owner','operator','manager'].includes(jobRole()) || Boolean(currentUser?.permissions?.includes?.('jobs:manage'));
diff --git a/apps/web/asset-manifest.json b/apps/web/asset-manifest.json
index 3bc9f64..a9470cb 100644
--- a/apps/web/asset-manifest.json
+++ b/apps/web/asset-manifest.json
@@ -13,10 +13,10 @@
"healthz"
],
"integrity": {
- "config.js": "sha256-6d49ab0825feb44111d960cd8d676e005c4f1a06271265277c0d00458236a441",
- "app.js": "sha256-450c2041d7a87465e5471e5b96faf9d3c27e973d49cbc9a5bdc19fd42a3ec339",
+ "config.js": "sha256-26e69a9af2abda4ac16d5b7c7eed5d69ad578c7f386af5fa62b42475a7318ea6",
+ "app.js": "sha256-7a2a8c1275f97d4485a2c833cbdb205ac163c5b7f4a52c131484fabfa6a6e29d",
"styles.css": "sha256-c1b192a15de735819fbb7ec3cddc9574808ae366a8255b4f690a7a40bc21caba",
- "index.html": "sha256-b8665be623e6e093e9a2d7532276289ebaeaaa0a905263ac3bbd9a3c595f4120",
+ "index.html": "sha256-83f010d3c68cef9b1f3a5ae8a50960156b52ef342944ef906804266e76220227",
"health.html": "sha256-c352a6f37aa24628cfc8d5709a70ff2d94181d192ed5fe00916cca9378a61d81",
"error.html": "sha256-f3cc28d2dfc9e8af112d0257c6ee47b9e9146e5da8590a754dd589bf43702aaf",
"healthz": "sha256-dc51b8c96c2d745df3bd5590d990230a482fd247123599548e0632fdbf97fc22"
diff --git a/apps/web/config.js b/apps/web/config.js
index 650f905..4a34c4a 100644
--- a/apps/web/config.js
+++ b/apps/web/config.js
@@ -1,5 +1,5 @@
/* Public, non-secret runtime configuration. Replace this file at deploy time if needed. */
window.__PROSPECT_CONFIG__ = Object.freeze({
apiBase: '',
- assetVersion: 'phase-36'
+ assetVersion: 'phase-40'
});
diff --git a/apps/web/index.html b/apps/web/index.html
index 978533e..01bae53 100644
--- a/apps/web/index.html
+++ b/apps/web/index.html
@@ -135,7 +135,7 @@
REVIEW REQUIRED
Confirm merge
This action is reversible. The merge will be recorded in history and can be reversed later.
-
-
+
+