bmc_hub/app/workflows/frontend/operations.html

15 lines
5.7 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "shared/frontend/base.html" %}
{% set wp = workflow_permissions|default({}) %}
{% block title %}Workflowdrift – BMC Hub{% endblock %}
{% block extra_css %}{% include "workflows/frontend/_style.html" %}{% endblock %}
{% block content %}<div class="container-fluid workflow-page"><header class="workflow-heading"><div><div class="workflow-eyebrow">Administration · drift</div><h1>Workflowdrift</h1><p>Følg hændelser og afstem uafklarede eksporter.</p></div><button id="ops-refresh" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-clockwise me-1"></i>Opdatér</button></header>{% include "workflows/frontend/_nav.html" %}<div id="ops-message" role="status" class="my-2"></div><div id="ops-runtime" class="alert alert-info mt-3" aria-live="polite">Henter motorstatus…</div><h5>Hændelseskø</h5><div id="ops-queues" class="mb-3"><div class="workflow-empty">Henter hændelseskø…</div></div><h5>Fejlede hændelser</h5><div id="ops-failed"></div><h5 class="mt-4">Eksport og afstemning</h5><p>Ved en uafklaret eksport: find den eksisterende ordre i e-conomic og indtast ordrenummeret. Afstemning læser og kontrollerer ordren; den opretter ingen ny ordre.</p><div id="ops-exports"></div></div>{% endblock %}
{% block extra_js %}<script>
(()=>{'use strict';const canManage={{ wp.get('manage',false)|tojson }},canExport={{ wp.get('economic_export',false)|tojson }};const $=name=>document.getElementById('ops-'+name),statusLabels={pending:'Afventer',processing:'Behandles',done:'Færdig',failed:'Fejlet',superseded:'Erstattet',sending:'Sendes',uncertain:'Uafklaret'};
function el(tag,text,cls){const e=document.createElement(tag);if(text!==undefined)e.textContent=text;if(cls)e.className=cls;return e;}
async function api(path,body){const r=await fetch('/api/v1/workflows'+path,{method:body?'POST':'GET',credentials:'same-origin',headers:{'Content-Type':'application/json'},body:body?JSON.stringify(body):undefined});const data=await r.json();if(!r.ok)throw Error(typeof data.detail==='string'?data.detail:JSON.stringify(data.detail));return data;}
let requestBusy=false;async function run(fn){if(requestBusy)return;requestBusy=true;document.querySelector('.workflow-page').setAttribute('aria-busy','true');try{await fn();}catch(e){$('message').className='alert alert-danger';$('message').textContent=e.message;}finally{requestBusy=false;document.querySelector('.workflow-page').setAttribute('aria-busy','false');}}
async function load(){const runtime=await api('/runtime/status');$('runtime').className='alert '+(!runtime.enabled?'alert-secondary':runtime.mode==='shadow'?'alert-info':'alert-warning');$('runtime').textContent=!runtime.enabled?'Workflowmotoren er slukket. Ingen nye workflows behandles.':`Motoren kører i ${runtime.mode==='shadow'?'skyggetilstand – ingen afregning ændres':'aktiv tilstand'}. Aktive kunder: ${(runtime.customer_ids||[]).join(', ')||'ingen'}${runtime.internal_enabled?' · Intern tid aktiveret':''} · AI: ${runtime.ai_enabled?'til':'fra'}`;$('queues').replaceChildren();if(!runtime.queues?.length)$('queues').append(el('div','Hændelseskøen er tom.','workflow-empty'));for(const q of runtime.queues||[])$('queues').append(el('div',`${statusLabels[q.status]||q.status}: ${q.count}${q.oldest?' · ældste '+q.oldest:''}`));$('failed').replaceChildren();if(!runtime.failed?.length)$('failed').append(el('p','Ingen fejlede hændelser.','text-muted'));for(const f of runtime.failed||[]){const card=el('section',undefined,'card p-3 my-2');card.append(el('strong',`${f.trigger} · ${f.entity_type} #${f.entity_id}`),el('p',f.error||'Ukendt fejl','text-danger'),el('span',`Forsøg: ${f.attempts} · ${f.created_at}`,'small text-muted'));const retry=el('button','Genforsøg','btn btn-sm btn-outline-primary mt-2');retry.disabled=!runtime.enabled;retry.onclick=()=>run(async()=>{retry.disabled=true;try{await api('/runtime/events/'+encodeURIComponent(f.id)+'/retry',{});$('message').className='alert alert-success';$('message').textContent='Et nyt genforsøg er lagt i kø. Den tidligere hændelse bevares.';await load();}finally{retry.disabled=!runtime.enabled;}});if(canManage)card.append(retry);$('failed').append(card);}await loadExports();}
async function loadExports(){if(!canExport){$('exports').replaceChildren(el('div','Eksportoversigten kræver adgang til e-conomic-eksport.','workflow-empty'));return;}try{const rows=await api('/exports');$('exports').replaceChildren();if(!rows.length)$('exports').append(el('p','Ingen workfloweksporter registreret.','text-muted'));for(const row of rows){const card=el('section',undefined,'card p-3 my-2'),link=el('a','Åbn ordrekladde #'+row.draft_id);link.href='/ordre/'+Number(row.draft_id);card.append(link,el('p',`Status: ${statusLabels[row.status]||row.status} · Reference: ${row.reference}`));if(row.error)card.append(el('p',row.error,'text-danger'));if(canManage&&['sending','uncertain'].includes(row.status)){const label=el('label','Eksisterende e-conomic-ordrenummer'),input=el('input',undefined,'form-control');input.type='number';input.min='1';label.append(input);card.append(label);const btn=el('button','Kontrollér og afstem eksisterende ordre','btn btn-outline-primary mt-2');btn.onclick=()=>run(async()=>{if(!Number.isInteger(Number(input.value))||Number(input.value)<=0)throw Error('Angiv et gyldigt ordrenummer');btn.disabled=true;try{await api('/exports/'+Number(row.draft_id)+'/reconcile',{economic_order_number:Number(input.value)});$('message').className='alert alert-success';$('message').textContent='Den eksisterende ordre er verificeret og knyttet til kladden.';await loadExports();}finally{btn.disabled=false;}});card.append(btn);}$('exports').append(card);}}catch(e){$('exports').replaceChildren(el('p',e.message,'text-muted'));}}
$('refresh').onclick=()=>run(load);run(load);
})();</script>{% endblock %}