' + esc(job?.error?.message || job?.message || run.error || 'The job returned no safe result.') + '
' : '') + stats + health + '
Run log
' + log + '
Results
' + cards + '
';
}
- async function discoveryAction(action,run){ if(action==='pause'||action==='resume'){message('directDiscoveryMessage',`${action[0].toUpperCase()+action.slice(1)} is not available in the current backend contract. Expected POST /api/v1/jobs/:id/${action}.`,true);return;} if(!run?.job_id)return; if(!window.confirm('Cancel this discovery run? The current partial result will remain reviewable.'))return; try{await jsonRequest(`/api/v1/jobs/${encodeURIComponent(run.job_id)}/cancel`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({})});await loadDiscoveryRuns();}catch(error){if(error.message!=='unauthorized')message('directDiscoveryMessage',error.message,true);} }
+ async function discoveryAction(action,run){ if(!run?.id)return; if(action!=='cancel'&&!['pause','resume'].includes(action))return; if(action==='cancel'&&!window.confirm('Cancel this discovery run? The current partial result will remain reviewable.'))return; try{await jsonRequest(`/api/v1/discovery-runs/${encodeURIComponent(run.id)}/${action}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({})});message('directDiscoveryMessage',`Discovery run ${action} requested.`);await loadDiscoveryRuns();}catch(error){if(error.message!=='unauthorized')message('directDiscoveryMessage',error.message,true);} }
async function loadDiscoveryRun(run) { selectedDiscoveryRunId=run.id; renderDiscoveryResult(run); try { const job=await jsonRequest(`/api/v1/jobs/${encodeURIComponent(run.job_id)}`); renderDiscoveryResult(run,job); if(['queued','running','paused'].includes(discoveryStatus(job))){clearTimeout(discoveryPollTimer);discoveryPollTimer=setTimeout(loadDiscoveryRuns,3000);} } catch(error){if(error.message!=='unauthorized')renderDiscoveryResult(run,{status:'error',message:error.message});} }
function renderDiscoveryRuns() { const el=$('directDiscoveryRunsState'); if(!discoveryRuns.length){el.innerHTML='
No discovery runs yet. Start with a market brief and approved sources.
';return;} el.innerHTML=discoveryRuns.map(run=>``).join(''); }
async function loadDiscoveryRuns() { const state=$('directDiscoveryRunsState'); if(state)state.innerHTML='