fix: AMPP monitor duplicate ID, not-configured UX, and auto-refresh
- Fix duplicate id="ampp-status" collision between the monitor page and admin AMPP panel — admin panel now uses id="ampp-cfg-status" so the monitor status messages are no longer silently hijacked - AMPP monitor now shows a clear "not configured" card with a direct button to Admin → AMPP instead of a cryptic error when the API key hasn't been entered yet - Improve job field mapping to handle AMPP response variations (jobStatus, displayName, jobType, results array vs items array) - Add 30-second auto-refresh while on the Monitor tab; timer is cleared when navigating away to avoid ghost requests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
978d447b3d
commit
fa206ba21a
1 changed files with 38 additions and 13 deletions
|
|
@ -578,7 +578,7 @@ body::before{content:'';position:fixed;inset:0;background:radial-gradient(ellips
|
|||
<button class="btn-secondary" onclick="testAmpp()">🔍 Test Connection</button>
|
||||
<button class="btn-primary" onclick="saveAmpp()">💾 Save Configuration</button>
|
||||
</div>
|
||||
<div class="status-msg" id="ampp-status"></div>
|
||||
<div class="status-msg" id="ampp-cfg-status"></div>
|
||||
</div>
|
||||
|
||||
<!-- Extension -->
|
||||
|
|
@ -869,10 +869,16 @@ async function api(method, url, body) {
|
|||
// ============================================================
|
||||
// NAVIGATION
|
||||
// ============================================================
|
||||
let amppRefreshTimer = null;
|
||||
function switchPage(name) {
|
||||
document.querySelectorAll('.nav-tab').forEach(t => t.classList.toggle('active', t.dataset.page === name));
|
||||
document.querySelectorAll('.page').forEach(p => p.classList.toggle('active', p.id === `page-${name}`));
|
||||
if (name === 'monitor') loadAmppJobs();
|
||||
// Clear AMPP auto-refresh when leaving monitor page
|
||||
if (amppRefreshTimer) { clearInterval(amppRefreshTimer); amppRefreshTimer = null; }
|
||||
if (name === 'monitor') {
|
||||
loadAmppJobs();
|
||||
amppRefreshTimer = setInterval(loadAmppJobs, 30000);
|
||||
}
|
||||
if (name === 'admin') { loadUsers(); loadAdminFolders(); }
|
||||
}
|
||||
|
||||
|
|
@ -1126,21 +1132,40 @@ function setFileStatus(i,cls,text) { const el=document.getElementById(`stat-${i}
|
|||
async function loadAmppJobs() {
|
||||
const list=document.getElementById('job-list'); const status=document.getElementById('ampp-status');
|
||||
status.className='status-msg loading'; status.textContent='Loading jobs…';
|
||||
list.innerHTML='';
|
||||
try {
|
||||
const d = await api('GET','/api/ampp/jobs?limit=50');
|
||||
status.className='status-msg'; status.textContent='';
|
||||
if (!d.success) { status.className='status-msg error'; status.textContent=d.error||'Failed'; return; }
|
||||
const jobs=d.jobs?.items||d.jobs||[];
|
||||
if (!jobs.length) { list.innerHTML='<div style="color:var(--text-dim);text-align:center;padding:2rem;font-size:.85rem">No jobs found</div>'; return; }
|
||||
list.innerHTML='';
|
||||
status.className=''; status.textContent='';
|
||||
if (!d.success) {
|
||||
// Check for "not configured" specifically — show a helpful prompt
|
||||
if (d.error && d.error.toLowerCase().includes('not configured')) {
|
||||
list.innerHTML=`<div style="text-align:center;padding:2rem 1rem">
|
||||
<div style="font-size:2rem;margin-bottom:.75rem">📡</div>
|
||||
<div style="font-weight:600;color:var(--text-primary);margin-bottom:.4rem">AMPP not configured</div>
|
||||
<div style="font-size:.82rem;color:var(--text-dim);margin-bottom:1rem">Enter your AMPP base URL and API key in Admin settings to enable job monitoring.</div>
|
||||
<button class="btn-secondary" style="font-size:.8rem" onclick="switchPage('admin');switchAdminTab('ampp')">⚙️ Go to Admin → AMPP</button>
|
||||
</div>`;
|
||||
} else {
|
||||
status.className='status-msg error'; status.textContent=`❌ ${d.error||'Failed to load jobs'}`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// AMPP returns { items: [...], total: N } or an array directly
|
||||
const jobs=Array.isArray(d.jobs)?d.jobs:(d.jobs?.items||d.jobs?.results||[]);
|
||||
if (!jobs.length) {
|
||||
list.innerHTML='<div style="color:var(--text-dim);text-align:center;padding:2rem;font-size:.85rem">No jobs in queue</div>';
|
||||
return;
|
||||
}
|
||||
jobs.forEach(job => {
|
||||
const el=document.createElement('div'); el.className='job-item';
|
||||
const st=(job.status||job.state||'unknown').toLowerCase();
|
||||
const cls=st.includes('run')?'running':st.includes('complet')||st.includes('success')?'completed':st.includes('fail')||st.includes('error')?'failed':st.includes('queue')||st.includes('wait')?'queued':'unknown';
|
||||
el.innerHTML=`<div class="job-dot ${cls}"></div><div class="job-info"><div class="job-name">${esc(job.name||job.id||'Job')}</div><div class="job-meta">${job.created?new Date(job.created).toLocaleString():''}</div></div><span class="job-status ${cls}">${cls.charAt(0).toUpperCase()+cls.slice(1)}</span>`;
|
||||
const st=(job.status||job.state||job.jobStatus||'unknown').toLowerCase();
|
||||
const cls=st.includes('run')||st.includes('active')?'running':st.includes('complet')||st.includes('success')||st.includes('done')?'completed':st.includes('fail')||st.includes('error')?'failed':st.includes('queue')||st.includes('wait')||st.includes('pend')?'queued':'unknown';
|
||||
const name=job.name||job.displayName||job.id||'Job';
|
||||
const meta=[job.created?new Date(job.created).toLocaleString():'', job.type||job.jobType||''].filter(Boolean).join(' · ');
|
||||
el.innerHTML=`<div class="job-dot ${cls}"></div><div class="job-info"><div class="job-name">${esc(name)}</div><div class="job-meta">${esc(meta)}</div></div><span class="job-status ${cls}">${cls.charAt(0).toUpperCase()+cls.slice(1)}</span>`;
|
||||
list.appendChild(el);
|
||||
});
|
||||
} catch(e) { status.className='status-msg error'; status.textContent=e.message; list.innerHTML=''; }
|
||||
} catch(e) { status.className='status-msg error'; status.textContent=`❌ ${e.message}`; list.innerHTML=''; }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
|
@ -1214,7 +1239,7 @@ async function loadAmppConfig() {
|
|||
} catch(_){}
|
||||
}
|
||||
async function testAmpp() {
|
||||
const s=document.getElementById('ampp-status');
|
||||
const s=document.getElementById('ampp-cfg-status');
|
||||
s.className='status-msg loading'; s.textContent='🔍 Testing AMPP connection…';
|
||||
try {
|
||||
const body={baseUrl:document.getElementById('ampp-base-url').value.trim()};
|
||||
|
|
@ -1225,7 +1250,7 @@ async function testAmpp() {
|
|||
} catch(e){s.className='status-msg error';s.textContent=`❌ ${e.message}`;}
|
||||
}
|
||||
async function saveAmpp() {
|
||||
const s=document.getElementById('ampp-status');
|
||||
const s=document.getElementById('ampp-cfg-status');
|
||||
s.className='status-msg loading'; s.textContent='💾 Saving…';
|
||||
try {
|
||||
const body={baseUrl:document.getElementById('ampp-base-url').value.trim()};
|
||||
|
|
|
|||
Loading…
Reference in a new issue