From aacfcd1ec527b3d3c62e2c742918e0b837a09f15 Mon Sep 17 00:00:00 2001 From: Greg Soucy Date: Wed, 27 May 2026 00:21:31 -0400 Subject: [PATCH] Fix admin claim row click to load detail panel --- public/admin/claims.html | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/public/admin/claims.html b/public/admin/claims.html index 5721298..a51dc3c 100644 --- a/public/admin/claims.html +++ b/public/admin/claims.html @@ -31,7 +31,8 @@ .error-panel{border:1px solid #fecaca;background:#fef2f2;color:#991b1b;padding:10px;border-radius:10px;margin-bottom:12px;} .card-url-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto; gap:8px; align-items:center; padding:8px 0; border-bottom:1px solid #f1f5f9;} .claims-list { display:flex; flex-direction:column; gap:8px; } - .claim-item { border:1px solid #e5e7eb; border-radius:12px; padding:10px 12px; background:#fff; cursor:pointer; } + .claim-item { border:1px solid #e5e7eb; border-radius:12px; padding:10px 12px; background:#fff; cursor:pointer; transition:background .15s ease,border-color .15s ease; } + .claim-item:hover { border-color:#93c5fd; background:#f8fbff; } .claim-item.selected { border-color:#2563eb; background:#eef2ff; } .claim-head, .claim-meta { display:flex; justify-content:space-between; gap:12px; align-items:center; } .claim-meta { color:#6b7280; font-size:13px; } @@ -52,13 +53,13 @@

CommandLayer Claims Admin

Internal operator dashboard f (() => { const s={claims:[],selected:'',detail:null,error:null,checkoutLoading:false,checkoutUrl:null}; const apiKey=document.getElementById('apiKey'); apiKey.value=sessionStorage.getItem('cl_admin_api_key')||localStorage.getItem('cl_admin_api_key')||''; -const headers=()=>({Authorization:`Bearer ${apiKey.value.trim()}`,'Content-Type':'application/json'}); +const headers=()=>{const key=apiKey.value.trim();return {Authorization:`Bearer ${key}`,'x-admin-api-key':key,'Content-Type':'application/json'};}; const short=(v,n=10)=>v?`${v.slice(0,n)}…`:''; const dt=(v)=>v?new Date(v).toLocaleString():'-'; const badge=(status)=>`${status}`; const copyBtn=(txt)=>``; function renderClaims(){const b=document.getElementById('claimsBody');b.innerHTML='';document.getElementById('claimsCount').textContent=`(${s.claims.length} loaded)`;for(const c of s.claims){const row=document.createElement('button');row.type='button';row.className=`claim-item ${s.selected===c.claimId?'selected':''}`;row.innerHTML=`

${short(c.claimId,14)}${badge(c.status)}
${c.tenant||'-'}${c.packId||'-'} · ${c.agentCount||0} agents
${dt(c.createdAt)}
`;row.onclick=()=>loadDetail(c.claimId);b.appendChild(row);}} -async function loadClaims(){status('Loading claims...');const r=await fetch('/api/admin/claims',{headers:{Authorization:headers().Authorization}});const d=await r.json();if(!r.ok||!d.ok){status(`${r.status} ${d.status}`);return;}s.claims=d.claims||[];renderClaims();status(`Loaded ${s.claims.length} claims.`);} -async function loadDetail(id){s.selected=id;renderClaims();const r=await fetch(`/api/admin/claim?claimId=${encodeURIComponent(id)}`,{headers:{Authorization:headers().Authorization}});const d=await r.json();if(!r.ok||!d.ok)return; s.detail=d; renderDetail();} +async function loadClaims(){status('Loading claims...');const r=await fetch('/api/admin/claims',{headers:{Authorization:headers().Authorization,'x-admin-api-key':headers()['x-admin-api-key']}});const d=await r.json();if(!r.ok||d?.ok===false){status(`${r.status} ${d.status||d.error||'error'}`);return;}s.claims=d.claims||[];renderClaims();status(`Loaded ${s.claims.length} claims.`);} +async function loadDetail(id){s.selected=id;s.detail=null;s.error=null;renderClaims();renderDetail('Loading claim detail...');const endpoint=`/api/admin/claim?claimId=${encodeURIComponent(id)}`;console.debug('[claims-admin] selected claimId:',id);console.debug('[claims-admin] detail endpoint:',endpoint);const r=await fetch(endpoint,{headers:{Authorization:headers().Authorization,'x-admin-api-key':headers()['x-admin-api-key']}});console.debug('[claims-admin] detail HTTP status:',r.status);const d=await r.json().catch(()=>({}));console.debug('[claims-admin] detail response status/error:',d?.status||null,d?.error||null);if(!r.ok||d?.ok===false||!d?.claim){s.error=`Claim detail failed: ${r.status} — ${d?.error||d?.status||'Unknown error'}`;renderDetail();return;}s.detail=d;renderDetail();} async function action(action,p={}){const r=await fetch('/api/admin/claim-action',{method:'POST',headers:headers(),body:JSON.stringify({claimId:s.selected,action,actor:'admin',...p})});const d=await r.json();if(!r.ok||!d.ok){s.error=`${d.status}: ${d.error}`;renderDetail();return;}s.error=null;await loadClaims();await loadDetail(s.selected);} async function publish(){const r=await fetch('/api/admin/publish-agent-cards',{method:'POST',headers:headers(),body:JSON.stringify({claimId:s.selected})});const d=await r.json();if(!r.ok||!d.ok){s.error=`${d.status}: ${d.error}`;renderDetail();return;}s.error=null;await loadClaims();await loadDetail(s.selected);} async function createCheckoutSession(claimId,forceNew=false){if(!claimId){s.error='400 — claimId is required';renderDetail();return;}s.error=null;s.checkoutUrl=null;s.checkoutLoading=true;renderDetail();try{const r=await fetch('/api/admin/create-checkout-session',{method:'POST',headers:headers(),body:JSON.stringify({claimId,forceNew})});const d=await r.json().catch(()=>({}));if(!r.ok||!d.ok){const detail=d?.debug?.message?`\nDetails: ${d.debug.message}`:'';s.error=`Checkout failed:\n${d.status||r.status} — ${d.error||'Request failed'}${detail}`;return;}s.checkoutUrl=d.checkoutUrl||d.url||null;await loadClaims();await loadDetail(claimId);}catch(e){s.error=`500 — ${e?.message||'Request failed'}`;}finally{s.checkoutLoading=false;renderDetail();}} @@ -67,7 +68,7 @@

CommandLayer Claims Admin

Internal operator dashboard f function copyCheckout(claim){const url=checkoutUrlFromClaim(claim);if(url)navigator.clipboard.writeText(url);} function pipeline(status){const steps=['created','approved','cards_published','payment_pending','paid','erc8004','ens_provisioned','live'];return `

${steps.map(x=>`${x.replaceAll('_',' ')}`).join('')}

Future steps are coming next.

`} -function renderDetail(){const el=document.getElementById('detailPanel');if(!s.detail){el.innerHTML='

Select a claim to review.

';return;}const {claim,agents=[],events=[],transitions=[],cards=[]}=s.detail;const urls=cards.map(c=>c.card_url).filter(Boolean);const missing=claim.status==='cards_published'&&agents.some(a=>!a.card_url);const firstUrl=urls[0];el.innerHTML=`${s.error?`
${s.error}
`:''}

Claim ${short(claim.claim_id,16)} ${badge(claim.status)}

Tenant: ${claim.tenant||'-'} · Wallet: ${claim.authenticated_address||'-'} · Pack: ${claim.pack_id||'-'} · Agents: ${agents.length} · Created: ${dt(claim.created_at)}

Pipeline

${pipeline(claim.status)}

Next action

Agents

${agents.map(a=>``).join('')}
ENSCapabilityParentCardActions
${a.ens||'-'}${a.capability||'-'}${a.canonical_parent||'-'}${a.card_status||'-'}${a.card_url?`Open `:'-'}
${claim.status==='payment_pending'?`

Payment pending

Checkout has been created. Open it to complete payment.

${claim.stripe_checkout_session_id||'-'}

`:''}${claim.status==='paid'?`

Payment received

Next: ERC-8004 registration

`:''}${claim.status==='cards_published'?`

Agent cards published

Founding Activation: $20 first year for 10 Trust Verification namespaces.

${urls.length} cards${missing?' · Missing card URLs detected':''}

${s.checkoutUrl?`
Checkout created
Open checkout
${s.checkoutUrl}
`:''}
${firstUrl?``:''}
${urls.map(u=>`
${u.split('/').pop()?.replace(/\.json$/,'')||u}Open${copyBtn(u)}
`).join('')}
${missing?`

Some cards are missing URLs. Use Repair / Publish cards.

`:''}`:''}

Events

${events.map(e=>`
${e.event_type}
${e.message||''}
${dt(e.created_at)}
metadata
${JSON.stringify(e.event_json||{},null,2)}
`).join('')||'

No events.

'}

Transitions

${transitions.map(t=>`
${t.from_status||'-'} → ${t.to_status||'-'} · ${t.action||'-'} · ${t.actor||'-'}
${dt(t.created_at)} ${t.reason?`· ${t.reason}`:''}
`).join('')||'

No transitions.

'}
Show raw JSON
${JSON.stringify(s.detail,null,2)}
`; +function renderDetail(loadingMsg=''){const el=document.getElementById('detailPanel');if(loadingMsg){el.innerHTML=`

${loadingMsg}

`;return;}if(!s.detail){el.innerHTML=`

${s.error||'Select a claim to review.'}

`;return;}const payload=s.detail||{};const claim=payload.claim||{};const agents=payload.agents||[];const events=payload.events||[];const transitions=payload.transitions||[];const cards=payload.cards||[];const urls=cards.map(c=>c.card_url).filter(Boolean);const missing=claim.status==='cards_published'&&agents.some(a=>!a.card_url);const firstUrl=urls[0];el.innerHTML=`${s.error?`
${s.error}
`:''}

Claim ${short(claim.claim_id,16)} ${badge(claim.status)}

Tenant: ${claim.tenant||'-'} · Wallet: ${claim.authenticated_address||'-'} · Status: ${claim.status||'-'} · Payment: ${claim.payment_status||'-'} · Agents: ${agents.length} · Created: ${dt(claim.created_at)}

Pipeline

${pipeline(claim.status)}

Next action

Agents

${agents.map(a=>``).join('')}
ENSCapabilityParentCardActions
${a.ens||'-'}${a.capability||'-'}${a.canonical_parent||'-'}${a.card_status||'-'}${a.card_url?`Open `:'-'}
${claim.status==='payment_pending'?`

Payment pending

Checkout has been created. Open it to complete payment.

${claim.stripe_checkout_session_id||'-'}

`:''}${claim.status==='paid'?`

Payment received

Next: ERC-8004 registration

`:''}${claim.status==='cards_published'?`

Agent cards published

Founding Activation: $20 first year for 10 Trust Verification namespaces.

${urls.length} cards${missing?' · Missing card URLs detected':''}

${s.checkoutUrl?`
Checkout created
Open checkout
${s.checkoutUrl}
`:''}
${firstUrl?``:''}
${urls.map(u=>`
${u.split('/').pop()?.replace(/\.json$/,'')||u}Open${copyBtn(u)}
`).join('')}
${missing?`

Some cards are missing URLs. Use Repair / Publish cards.

`:''}`:''}

Events

${events.map(e=>`
${e.event_type}
${e.message||''}
${dt(e.created_at)}
metadata
${JSON.stringify(e.event_json||{},null,2)}
`).join('')||'

No events.

'}

Transitions

${transitions.map(t=>`
${t.from_status||'-'} → ${t.to_status||'-'} · ${t.action||'-'} · ${t.actor||'-'}
${dt(t.created_at)} ${t.reason?`· ${t.reason}`:''}
`).join('')||'

No transitions.

'}
Show raw JSON
${JSON.stringify(s.detail,null,2)}
`; const a=document.getElementById('actions');const mk=(t,c,cls='btn',opts={})=>{const b=document.createElement('button');b.type='button';b.textContent=t;b.className=cls;b.disabled=Boolean(opts.disabled);if(opts.id)b.id=opts.id;b.onclick=c;a.appendChild(b);}; if(claim.status==='created'){mk('Approve',()=>action('approve',{notes:document.getElementById('notesInput').value}),'btn btn-primary');mk('Reject',()=>action('reject',{reason:document.getElementById('reasonInput').value}),'btn btn-secondary');mk('Mark failed',()=>action('mark_failed',{reason:document.getElementById('reasonInput').value}),'btn btn-danger');} if(claim.status==='approved'){mk('Publish agent cards',()=>publish(),'btn btn-primary');mk('Mark failed',()=>action('mark_failed',{reason:document.getElementById('reasonInput').value}),'btn btn-danger');mk('Add note',()=>action('add_note',{notes:document.getElementById('notesInput').value,reason:document.getElementById('reasonInput').value}),'btn');}