seperate out WOL publication codes, offer GUI for viewing, and add new KC publication source #6
@ -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>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user