seperate out WOL publication codes, offer GUI for viewing, and add new KC publication source #6

Merged
joshlaymon merged 21 commits from develop into main 2025-09-09 00:52:21 +00:00
Showing only changes of commit 6d63a736cd - Show all commits

View File

@ -162,6 +162,26 @@
</div>
</section>
<!-- Publication Codes (JSON) superusers only -->
<section class="card cc-panel">
<div class="cc-panel-head">
<div class="cc-kicker">Comms</div>
<h2 class="cc-panel-title">Publication Codes (JSON)</h2>
</div>
<div class="cc-panel-body">
<div class="cc-row">
<label class="cc-label">Edit <code>web/static/data/wol-pub-codes.v1.json</code></label>
<textarea id="pubCodesEditor" class="tool-input" rows="14"
style="width:100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;"></textarea>
</div>
<div class="cc-actions">
<button type="button" id="pubCodesReloadBtn" class="btn">Reload</button>
<button type="button" id="pubCodesSaveBtn" class="btn btn-primary">Save</button>
</div>
<div id="pubCodesStatus" class="tiny" style="margin-top:6px; color:#64748b;"></div>
</div>
</section>
{% endif %}
</div>
</div>
@ -335,6 +355,71 @@ textarea.tool-input{min-height:140px;resize:vertical;width:100%;}
});
window.addEventListener('keydown', (e)=>{ if (e.key === 'Escape' && modal.style.display === 'flex') closeModal(); });
})();
// === Publication Codes Editor (superuser) ===
(function(){
const ta = document.getElementById('pubCodesEditor');
const btnR = document.getElementById('pubCodesReloadBtn');
const btnS = document.getElementById('pubCodesSaveBtn');
const stat = document.getElementById('pubCodesStatus');
if (!ta || !btnR || !btnS) return; // not superuser or card missing
function setStatus(msg, ok=true){
if (!stat) return;
stat.textContent = msg;
stat.style.color = ok ? '#64748b' : '#b91c1c';
}
async function reloadJSON(){
try{
setStatus('Loading…');
const r = await fetch('/static/data/wol-pub-codes.v1.json', { cache:'no-store' });
if (!r.ok) throw new Error('HTTP '+r.status);
const data = await r.json();
ta.value = JSON.stringify(data, null, 2);
setStatus('Loaded.');
}catch(err){
setStatus('Failed to load JSON: ' + (err?.message||err), false);
}
}
async function saveJSON(){
let parsed;
try{
parsed = JSON.parse(ta.value);
if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.pub_codes))
throw new Error('JSON must be an object with a "pub_codes" array.');
}catch(err){
setStatus('Invalid JSON: ' + (err?.message||err), false);
return;
}
try{
setStatus('Saving…');
const fd = new FormData();
fd.append('json', JSON.stringify(parsed));
const r = await fetch("{% url 'api_update_pub_codes' %}", {
method: 'POST',
body: fd,
credentials: 'same-origin',
headers: { 'X-CSRFToken': (document.cookie.match(/(^|;)\s*csrftoken\s*=\s*([^;]+)/)||[]).pop() || '' }
});
if (!r.ok) {
const txt = await r.text().catch(()=>String(r.status));
throw new Error(txt.slice(0,200));
}
const out = await r.json().catch(()=>({ok:false}));
if (!out.ok) throw new Error('Server rejected the update.');
setStatus('Saved. ' + out.count + ' codes.');
}catch(err){
setStatus('Save failed: ' + (err?.message||err), false);
}
}
btnR.addEventListener('click', reloadJSON);
btnS.addEventListener('click', saveJSON);
reloadJSON(); // initial load
})();
})();
</script>