bmc_hub/script_11.js
Christian bc504b9257 feat: Add subscription management functionality and AnyDesk API integration
- Implemented subscription creation, updating, and rendering in script_9.js.
- Added functions for handling subscription line items, product selection, and total calculations.
- Integrated AnyDesk API for session management in test_anydesk.py.
- Created REST client test requests for API endpoints in api.http.
- Developed a script to check ESET machine status and save details in tmp_check_eset_machine.py.
2026-03-30 07:50:15 +02:00

186 lines
9.4 KiB
JavaScript

(function () {
const SAG_ID = {{ case.id }};
let _historyLoaded = false;
window.rewriteCaseDescriptionWithApproval = async function () {
const ta = document.getElementById('beskrivelse-textarea');
const rewriteBtn = document.getElementById('beskrivelse-rewrite-btn');
if (!ta) return;
const source = (ta.value || '').trim();
if (!source) {
if (typeof showNotification === 'function') showNotification('Skriv en beskrivelse først', 'warning');
else alert('Skriv en beskrivelse først');
return;
}
const originalHtml = rewriteBtn?.innerHTML || '';
if (rewriteBtn) {
rewriteBtn.disabled = true;
rewriteBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Renskriver...';
}
try {
const rewriteEndpoints = ['/api/v1/rewrite-text', '/api/v1/sag/rewrite-text', '/api/v1/emails/rewrite-text'];
let payload = null;
let lastError = null;
for (const endpoint of rewriteEndpoints) {
const response = await fetch(endpoint, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: source, context: 'case' })
});
if (response.ok) {
payload = await response.json();
lastError = null;
break;
}
let detail = `HTTP ${response.status}`;
try {
const err = await response.json();
if (err?.detail) detail = err.detail;
} catch (_) {}
lastError = new Error(detail);
// Retry next endpoint for common route mismatch cases.
if (![404, 405].includes(response.status)) {
break;
}
}
if (!payload) {
throw lastError || new Error('Kunne ikke hente renskrivningsforslag');
}
const rewrittenRaw = String(payload?.rewritten_text || '').trim();
const descMatch = rewrittenRaw.match(/(?:^|\n)Beskrivelse:\s*\n([\s\S]*)$/i);
const rewritten = descMatch?.[1] ? descMatch[1].trim() : rewrittenRaw;
openRewriteReviewModal({
title: 'Sagsbeskrivelse',
originalText: source,
rewrittenText: rewritten,
applyToTarget: (nextText) => {
ta.value = nextText;
bootstrap.Modal.getOrCreateInstance(document.getElementById('rewritePreviewModal')).hide();
}
});
} catch (e) {
console.error(e);
if (typeof showNotification === 'function') showNotification('Kunne ikke renskrive beskrivelse', 'error');
else alert(`Kunne ikke renskrive beskrivelse: ${e.message || 'Ukendt fejl'}`);
} finally {
if (rewriteBtn) {
rewriteBtn.disabled = false;
rewriteBtn.innerHTML = originalHtml;
}
}
};
window.startBeskrivelsEdit = function () {
const current = document.getElementById('beskrivelse-text').innerText.trim();
document.getElementById('beskrivelse-textarea').value = current;
document.getElementById('beskrivelse-view').classList.add('d-none');
document.getElementById('beskrivelse-edit-btn')?.classList.add('d-none');
document.getElementById('beskrivelse-editor').classList.remove('d-none');
document.getElementById('beskrivelse-textarea').focus();
};
window.cancelBeskrivelsEdit = function () {
document.getElementById('beskrivelse-editor').classList.add('d-none');
document.getElementById('beskrivelse-view').classList.remove('d-none');
document.getElementById('beskrivelse-edit-btn')?.classList.remove('d-none');
};
window.saveBeskrivelsEdit = async function () {
const ta = document.getElementById('beskrivelse-textarea');
const saveBtn = document.getElementById('beskrivelse-save-btn');
const newVal = ta.value;
if (saveBtn) { saveBtn.disabled = true; saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Gemmer...'; }
try {
const res = await fetch(`/api/v1/sag/${SAG_ID}/beskrivelse`, {
method: 'PATCH',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ beskrivelse: newVal })
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
// Update view
const textEl = document.getElementById('beskrivelse-text');
textEl.innerText = data.beskrivelse || '';
const emptyEl = document.getElementById('beskrivelse-empty');
if (emptyEl) emptyEl.style.display = data.beskrivelse ? 'none' : '';
cancelBeskrivelsEdit();
// Show history and mark stale
document.getElementById('beskrivelse-history-wrap').classList.remove('d-none');
_historyLoaded = false;
if (typeof showNotification === 'function') showNotification('Beskrivelse gemt', 'success');
} catch (e) {
console.error(e);
if (typeof showNotification === 'function') showNotification('Kunne ikke gemme beskrivelse', 'error');
} finally {
if (saveBtn) { saveBtn.disabled = false; saveBtn.innerHTML = '<i class="bi bi-check2 me-1"></i>Gem'; }
}
};
window.loadBeskrivelsHistory = async function () {
if (_historyLoaded) return;
const list = document.getElementById('beskrivelse-history-list');
try {
const res = await fetch(`/api/v1/sag/${SAG_ID}/beskrivelse/history`, { credentials: 'include' });
if (!res.ok) throw new Error('failed');
const rows = await res.json();
_historyLoaded = true;
const label = document.getElementById('beskrivelse-history-label');
if (!rows.length) {
label.textContent = 'Historik (0)';
list.innerHTML = '<div class="list-group-item text-muted text-center py-2 small">Ingen historik endnu.</div>';
return;
}
label.textContent = `Historik (${rows.length})`;
const esc = s => String(s || '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
const trunc = (s, n) => s && s.length > n ? s.substring(0, n) + '…' : (s || '');
list.innerHTML = rows.map(h => {
const d = new Date(h.changed_at);
const when = d.toLocaleDateString('da-DK', {day:'2-digit',month:'2-digit',year:'numeric'})
+ ' ' + d.toLocaleTimeString('da-DK', {hour:'2-digit',minute:'2-digit'});
const who = esc(h.changed_by_name || 'Ukendt');
const before = h.beskrivelse_before ? esc(trunc(h.beskrivelse_before, 150)) : '<em class="text-muted">tom</em>';
const after = h.beskrivelse_after ? esc(trunc(h.beskrivelse_after, 150)) : '<em class="text-muted">tom</em>';
return `<div class="list-group-item px-3 py-2">
<div class="d-flex justify-content-between mb-1">
<span class="fw-semibold small">${who}</span>
<span class="text-muted small">${when}</span>
</div>
<div class="d-flex gap-3" style="font-size:.85rem">
<div style="flex:1"><span class="badge text-bg-danger me-1" style="font-size:.7rem">Før</span>${before}</div>
<div style="flex:1"><span class="badge text-bg-success me-1" style="font-size:.7rem">Efter</span>${after}</div>
</div>
</div>`;
}).join('');
} catch (e) {
list.innerHTML = '<div class="list-group-item text-muted text-center py-2 small">Kunne ikke indlæse historik.</div>';
}
};
// Keyboard shortcuts
document.addEventListener('keydown', function (e) {
const editor = document.getElementById('beskrivelse-editor');
if (!editor || editor.classList.contains('d-none')) return;
if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); saveBeskrivelsEdit(); }
if (e.key === 'Escape') { e.preventDefault(); cancelBeskrivelsEdit(); }
});
// Show history toggle if description already exists on page load
if ((document.getElementById('beskrivelse-text').innerText || '').trim()) {
document.getElementById('beskrivelse-history-wrap').classList.remove('d-none');
}
})();