|
|
@@ -31,9 +31,27 @@
|
|
|
|
#admin-content article > .admin-story-reply { display: none; }
|
|
|
|
#admin-content article > .admin-story-reply { display: none; }
|
|
|
|
#admin-content .admin-simple-conversation > h2,
|
|
|
|
#admin-content .admin-simple-conversation > h2,
|
|
|
|
#admin-content .admin-simple-conversation > p:not(.admin-story-empty),
|
|
|
|
#admin-content .admin-simple-conversation > p:not(.admin-story-empty),
|
|
|
|
#admin-content .admin-simple-conversation article > :not(.admin-story-reply) { display: none; }
|
|
|
|
#admin-content .admin-simple-conversation article > :not(.admin-story-player):not(.admin-story-reply) { display: none; }
|
|
|
|
|
|
|
|
#admin-content .admin-simple-conversation article > .admin-story-player,
|
|
|
|
#admin-content .admin-simple-conversation article > .admin-story-reply { display: block; margin-block: .85rem; white-space: pre-wrap; }
|
|
|
|
#admin-content .admin-simple-conversation article > .admin-story-reply { display: block; margin-block: .85rem; white-space: pre-wrap; }
|
|
|
|
#admin-content pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; }
|
|
|
|
#admin-content .admin-simple-conversation article > .admin-story-player { font-weight: 650; }
|
|
|
|
|
|
|
|
#admin-content pre, #debug-trace pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 32rem; overflow: auto; }
|
|
|
|
|
|
|
|
.json-view { box-sizing: border-box; margin-block: .65rem; padding: .8rem; border: 1px solid #cbd5e1; border-radius: .4rem; background: #f8fafc; color: #1e293b; tab-size: 2; font: .84rem/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
|
|
|
|
|
|
.json-token-key { color: #075985; font-weight: 700; }
|
|
|
|
|
|
|
|
.json-token-string { color: #166534; }
|
|
|
|
|
|
|
|
.json-token-number { color: #6d28d9; font-weight: 650; }
|
|
|
|
|
|
|
|
.json-token-boolean { color: #b45309; font-weight: 750; }
|
|
|
|
|
|
|
|
.json-token-null { color: #be123c; font-style: italic; }
|
|
|
|
|
|
|
|
.json-token-punctuation { color: #64748b; }
|
|
|
|
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
|
|
|
|
|
|
.json-view { border-color: #475569; background: #111827; color: #e5e7eb; }
|
|
|
|
|
|
|
|
.json-token-key { color: #7dd3fc; }
|
|
|
|
|
|
|
|
.json-token-string { color: #86efac; }
|
|
|
|
|
|
|
|
.json-token-number { color: #c4b5fd; }
|
|
|
|
|
|
|
|
.json-token-boolean { color: #fcd34d; }
|
|
|
|
|
|
|
|
.json-token-null { color: #fda4af; }
|
|
|
|
|
|
|
|
.json-token-punctuation { color: #94a3b8; }
|
|
|
|
|
|
|
|
}
|
|
|
|
#admin-toolbar { display: flex; flex-wrap: wrap; gap: .5rem; margin-block: 1rem; }
|
|
|
|
#admin-toolbar { display: flex; flex-wrap: wrap; gap: .5rem; margin-block: 1rem; }
|
|
|
|
#player-search { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; }
|
|
|
|
#player-search { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; }
|
|
|
|
body.debug-layout { max-width: none; margin: 0; padding: .5rem; height: 100vh; overflow: hidden; }
|
|
|
|
body.debug-layout { max-width: none; margin: 0; padding: .5rem; height: 100vh; overflow: hidden; }
|
|
|
@@ -620,10 +638,43 @@
|
|
|
|
parent.append(element);
|
|
|
|
parent.append(element);
|
|
|
|
return element;
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function appendFormattedJson(pre, value, stringAsText = false) {
|
|
|
|
|
|
|
|
pre.className = 'json-view';
|
|
|
|
|
|
|
|
pre.setAttribute('aria-label', 'Formaterat JSON-svar');
|
|
|
|
|
|
|
|
const code = document.createElement('code');
|
|
|
|
|
|
|
|
if (stringAsText && typeof value === 'string') {
|
|
|
|
|
|
|
|
code.textContent = value;
|
|
|
|
|
|
|
|
pre.replaceChildren(code);
|
|
|
|
|
|
|
|
return pre;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const source = JSON.stringify(value, null, '\t') ?? 'null';
|
|
|
|
|
|
|
|
const tokens = /(\"(?:\\.|[^\"\\])*\"(?=\s*:))|(\"(?:\\.|[^\"\\])*\")|(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b)|(\bnull\b)|([{}\[\],:])|(\s+)/g;
|
|
|
|
|
|
|
|
let offset = 0;
|
|
|
|
|
|
|
|
for (const match of source.matchAll(tokens)) {
|
|
|
|
|
|
|
|
if (match.index > offset) code.append(document.createTextNode(source.slice(offset, match.index)));
|
|
|
|
|
|
|
|
const token = match[0];
|
|
|
|
|
|
|
|
if (match[7]) {
|
|
|
|
|
|
|
|
code.append(document.createTextNode(token));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const span = document.createElement('span');
|
|
|
|
|
|
|
|
span.className = match[1] ? 'json-token-key'
|
|
|
|
|
|
|
|
: match[2] ? 'json-token-string'
|
|
|
|
|
|
|
|
: match[3] ? 'json-token-number'
|
|
|
|
|
|
|
|
: match[4] ? 'json-token-boolean'
|
|
|
|
|
|
|
|
: match[5] ? 'json-token-null' : 'json-token-punctuation';
|
|
|
|
|
|
|
|
span.textContent = token;
|
|
|
|
|
|
|
|
code.append(span);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = match.index + token.length;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset < source.length) code.append(document.createTextNode(source.slice(offset)));
|
|
|
|
|
|
|
|
pre.replaceChildren(code);
|
|
|
|
|
|
|
|
return pre;
|
|
|
|
|
|
|
|
}
|
|
|
|
function adminJson(title, value, parent = adminContent) {
|
|
|
|
function adminJson(title, value, parent = adminContent) {
|
|
|
|
const details = adminElement('details', undefined, parent);
|
|
|
|
const details = adminElement('details', undefined, parent);
|
|
|
|
adminElement('summary', title, details);
|
|
|
|
adminElement('summary', title, details);
|
|
|
|
adminElement('pre', JSON.stringify(value, null, 2), details);
|
|
|
|
appendFormattedJson(adminElement('pre', undefined, details), value);
|
|
|
|
return details;
|
|
|
|
return details;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async function loadAdminPlayers(query = '', offset = 0) {
|
|
|
|
async function loadAdminPlayers(query = '', offset = 0) {
|
|
|
@@ -717,7 +768,11 @@
|
|
|
|
let showedPlayerInput = false;
|
|
|
|
let showedPlayerInput = false;
|
|
|
|
for (const event of group.events) {
|
|
|
|
for (const event of group.events) {
|
|
|
|
const payload = event.payload || {};
|
|
|
|
const payload = event.payload || {};
|
|
|
|
if (payload.player_message) { adminElement('p', `Spelaren: ${payload.player_message}`, card); showedPlayerInput = true; }
|
|
|
|
if (payload.player_message) {
|
|
|
|
|
|
|
|
const playerLine = adminElement('p', `Spelaren: ${payload.player_message}`, card);
|
|
|
|
|
|
|
|
playerLine.className = 'admin-story-player';
|
|
|
|
|
|
|
|
showedPlayerInput = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
const reply = payload.reply || payload.npc_reply;
|
|
|
|
const reply = payload.reply || payload.npc_reply;
|
|
|
|
if (reply) {
|
|
|
|
if (reply) {
|
|
|
|
const story = adminElement('p', `Berättelsen: ${reply}`, card);
|
|
|
|
const story = adminElement('p', `Berättelsen: ${reply}`, card);
|
|
|
@@ -738,9 +793,15 @@
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!showedPlayerInput) {
|
|
|
|
if (!showedPlayerInput) {
|
|
|
|
const failedTurnInput = [...group.interactions].reverse().map(latestPlayerText).find(Boolean);
|
|
|
|
const failedTurnInput = [...group.interactions].reverse().map(latestPlayerText).find(Boolean);
|
|
|
|
if (failedTurnInput) adminElement('p', `Spelaren: ${failedTurnInput}`, card);
|
|
|
|
if (failedTurnInput) {
|
|
|
|
|
|
|
|
const playerLine = adminElement('p', `Spelaren: ${failedTurnInput}`, card);
|
|
|
|
|
|
|
|
playerLine.className = 'admin-story-player';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const message of group.messages) {
|
|
|
|
|
|
|
|
const playerLine = adminElement('p', `Spelare: ${message.message}`, card);
|
|
|
|
|
|
|
|
playerLine.className = 'admin-story-player';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const message of group.messages) adminElement('p', `Spelarmeddelande: ${message.message}`, card);
|
|
|
|
|
|
|
|
for (const interaction of group.interactions) {
|
|
|
|
for (const interaction of group.interactions) {
|
|
|
|
if (!interaction.response) continue;
|
|
|
|
if (!interaction.response) continue;
|
|
|
|
const button = adminElement('button', `AI-svar · ${interaction.prompt_id} · ${interaction.outcome}: ${interaction.response}`, card);
|
|
|
|
const button = adminElement('button', `AI-svar · ${interaction.prompt_id} · ${interaction.outcome}: ${interaction.response}`, card);
|
|
|
@@ -1151,7 +1212,7 @@
|
|
|
|
const valueHeading = document.createElement('strong');
|
|
|
|
const valueHeading = document.createElement('strong');
|
|
|
|
valueHeading.textContent = name;
|
|
|
|
valueHeading.textContent = name;
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
pre.textContent = typeof value === 'string' ? value : JSON.stringify(value ?? 'Ingen uppgift sparad', null, 2);
|
|
|
|
appendFormattedJson(pre, value ?? 'Ingen uppgift sparad', true);
|
|
|
|
card.append(valueHeading, pre);
|
|
|
|
card.append(valueHeading, pre);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
addValue('Indata', input);
|
|
|
|
addValue('Indata', input);
|
|
|
@@ -1212,7 +1273,7 @@
|
|
|
|
const rawSummary = document.createElement('summary');
|
|
|
|
const rawSummary = document.createElement('summary');
|
|
|
|
rawSummary.textContent = 'Visa all rå spårdata';
|
|
|
|
rawSummary.textContent = 'Visa all rå spårdata';
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
pre.textContent = JSON.stringify(group, null, 2);
|
|
|
|
appendFormattedJson(pre, group);
|
|
|
|
raw.append(rawSummary, pre);
|
|
|
|
raw.append(rawSummary, pre);
|
|
|
|
details.append(summary, chain, raw);
|
|
|
|
details.append(summary, chain, raw);
|
|
|
|
debugTrace.append(details);
|
|
|
|
debugTrace.append(details);
|
|
|
|