fix(CG6): loadChannels() matcher /notify/channels API-format (OQ-29)
This commit is contained in:
parent
bf366f89b0
commit
6367683d81
|
|
@ -310,7 +310,6 @@ function renderStats(sum, anomCount){
|
||||||
const cost = sum?.estimated_cost_usd ?? null
|
const cost = sum?.estimated_cost_usd ?? null
|
||||||
const budget = sum?.budget_limit ?? null
|
const budget = sum?.budget_limit ?? null
|
||||||
|
|
||||||
// Infer tier from cost (approximate GCP spend = cost * 100)
|
|
||||||
const gcpSpend = cost != null ? cost * 100 : 0
|
const gcpSpend = cost != null ? cost * 100 : 0
|
||||||
const tier = TIER_MAP.find(t => gcpSpend < t.max) || TIER_MAP[TIER_MAP.length-1]
|
const tier = TIER_MAP.find(t => gcpSpend < t.max) || TIER_MAP[TIER_MAP.length-1]
|
||||||
document.getElementById('tier-badge').textContent = tier.name
|
document.getElementById('tier-badge').textContent = tier.name
|
||||||
|
|
@ -394,7 +393,6 @@ function renderModules(data){
|
||||||
<tbody>${rows}</tbody>
|
<tbody>${rows}</tbody>
|
||||||
</table>`
|
</table>`
|
||||||
|
|
||||||
// Donut
|
|
||||||
const canvas = document.getElementById('donut-canvas')
|
const canvas = document.getElementById('donut-canvas')
|
||||||
if(donutChart) donutChart.destroy()
|
if(donutChart) donutChart.destroy()
|
||||||
donutChart = new Chart(canvas,{
|
donutChart = new Chart(canvas,{
|
||||||
|
|
@ -418,33 +416,41 @@ function renderModules(data){
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── DELIVERY CHANNELS ─────────────────────────────────────────────────────────
|
// ── DELIVERY CHANNELS ─────────────────────────────────────────────────────────
|
||||||
|
// Matcher /notify/channels respons: { channels: [{type, configured, target, url}] }
|
||||||
|
const CH_META = {
|
||||||
|
webhook: { icon:'🔗', name:'Webhook', tier:'Starter+' },
|
||||||
|
email: { icon:'📧', name:'E-post', tier:'Starter+' },
|
||||||
|
sms: { icon:'📱', name:'SMS', tier:'Guard+' },
|
||||||
|
}
|
||||||
|
|
||||||
async function loadChannels(){
|
async function loadChannels(){
|
||||||
const el = document.getElementById('ch-list')
|
const el = document.getElementById('ch-list')
|
||||||
// Fetch live channel config — falls back to defaults if endpoint not yet wired
|
let apiChannels = []
|
||||||
let channels = null
|
|
||||||
try{
|
try{
|
||||||
const r = await fetch('/notify/channels')
|
const r = await fetch('/notify/channels')
|
||||||
if(r.ok) channels = await r.json()
|
if(r.ok){
|
||||||
|
const data = await r.json()
|
||||||
|
apiChannels = data.channels || []
|
||||||
|
}
|
||||||
}catch(_){}
|
}catch(_){}
|
||||||
|
|
||||||
// Sensible defaults with live endpoint awareness
|
if(!apiChannels.length){
|
||||||
const defs = [
|
el.innerHTML = '<div class="loader" style="color:var(--text-faint)">Kanaler ikke tilgjengelig</div>'
|
||||||
{ icon:'🔗', name:'Webhook', key:'webhook', tier:'Starter+', endpoint:'POST /notify/webhook' },
|
return
|
||||||
{ icon:'📧', name:'E-post', key:'email', tier:'Starter+', endpoint:'POST /notify/email' },
|
}
|
||||||
{ icon:'📱', name:'SMS', key:'sms', tier:'Guard+', endpoint:'POST /notify/sms' },
|
|
||||||
]
|
el.innerHTML = '<div class="ch-list">' + apiChannels.map(ch => {
|
||||||
el.innerHTML = '<div class="ch-list">' + defs.map(ch => {
|
const meta = CH_META[ch.type] || { icon:'📡', name:ch.type, tier:'' }
|
||||||
const cfg = channels?.[ch.key]
|
const active = ch.configured === true
|
||||||
const active = cfg?.active ?? (ch.key==='webhook'||ch.key==='email') // CG5a+CG5b live
|
const detail = ch.url || ch.target || `POST /notify/${ch.type}`
|
||||||
const detail = cfg?.destination || cfg?.url || cfg?.address || ch.endpoint
|
|
||||||
return `<div class="ch-item">
|
return `<div class="ch-item">
|
||||||
<div class="ch-icon">${ch.icon}</div>
|
<div class="ch-icon">${meta.icon}</div>
|
||||||
<div class="ch-info">
|
<div class="ch-info">
|
||||||
<div class="ch-name">${ch.name} <span style="font-size:10px;color:var(--text-faint);font-family:var(--mono);font-weight:400">${ch.tier}</span></div>
|
<div class="ch-name">${meta.name} <span style="font-size:10px;color:var(--text-faint);font-family:var(--mono);font-weight:400">${meta.tier}</span></div>
|
||||||
<div class="ch-detail">${esc(detail)}</div>
|
<div class="ch-detail">${esc(detail)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ch-status ${active?'active':'inactive'}">${active?'Aktiv':'Ikke konfigurert'}</div>
|
<div class="ch-status ${active?'active':'inactive'}">${active?'Aktiv':'Ikke konfigurert'}</div>
|
||||||
${active?`<button class="ch-test-btn" onclick="testChannel('${ch.key}')">Test</button>`:''}
|
${active?`<button class="ch-test-btn" onclick="testChannel('${ch.type}')">Test</button>`:''}
|
||||||
</div>`
|
</div>`
|
||||||
}).join('') + '</div>'
|
}).join('') + '</div>'
|
||||||
}
|
}
|
||||||
|
|
@ -452,7 +458,10 @@ async function loadChannels(){
|
||||||
async function testChannel(key){
|
async function testChannel(key){
|
||||||
toast('Sender testmelding via '+key+'...')
|
toast('Sender testmelding via '+key+'...')
|
||||||
try{
|
try{
|
||||||
const r = await fetch('/notify/'+key,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({test:true,message:'CostGuard testmelding fra klient-dashboard'})})
|
const body = key==='webhook'
|
||||||
|
? JSON.stringify({url:'', event:'custom', title:'CostGuard testmelding', body:'Test fra klient-dashboard'})
|
||||||
|
: JSON.stringify({event:'custom', subject:'CostGuard testmelding', body_html:'<p>Test fra klient-dashboard</p>'})
|
||||||
|
const r = await fetch('/notify/'+key,{method:'POST',headers:{'Content-Type':'application/json'},body})
|
||||||
if(r.ok) toast('✅ Testmelding sendt via '+key)
|
if(r.ok) toast('✅ Testmelding sendt via '+key)
|
||||||
else toast('⚠️ Svarte '+r.status+' — sjekk konfig')
|
else toast('⚠️ Svarte '+r.status+' — sjekk konfig')
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user