json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
219 lines (194 loc) • 9.11 kB
HTML
<html>
<head>
<meta charset="utf-8">
<title>JOE AI Jobs Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;margin:20px;}
label{display:block;margin:8px 0 4px}
select, input, textarea, button{font-size:14px;padding:6px 12px}
textarea{width:100%;height:160px;font-family:ui-monospace,Menlo,Consolas,monospace}
pre{background:#f6f8fa;border:1px solid #e1e4e8;padding:10px;overflow:auto;max-height:400px}
.row{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:8px 0}
.small{font-size:12px;color:#666}
.bad{color:#b00020}
.good{color:#0a7d00}
.section{margin:20px 0;padding:15px;border:1px solid #e1e4e8;border-radius:4px}
button{cursor:pointer;background:#0366d6;color:white;border:none;border-radius:4px}
button:hover{background:#0256c2}
button:disabled{background:#ccc;cursor:not-allowed}
input[type="text"]{min-width:300px;padding:6px}
</style>
</head>
<body>
<div id="mcp-nav"></div>
<script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
<h1>JOE AI Jobs Test</h1>
<div class="small">View and test active AI job tracking. Jobs are keyed by {objectId}_{identifier}.</div>
<div class="section">
<h3>All Active Jobs</h3>
<div class="row">
<button id="refreshAll">Refresh</button>
<span id="allStatus" class="small"></span>
</div>
<pre id="allJobsResult"></pre>
</div>
<div class="section">
<h3>View Active Jobs for Object</h3>
<div class="row">
<label for="objectId">Object ID:</label>
<input id="objectId" type="text" placeholder="e.g. 5ce3d147-f37d-4c8f-9c00-bc185182c4d5" />
<button id="loadJobs">Load Jobs</button>
<span id="loadStatus" class="small"></span>
</div>
<pre id="jobsResult"></pre>
</div>
<div class="section">
<h3>Example Job Tokens</h3>
<div class="small">Use these formats to understand token structure:</div>
<pre id="examples">select_prompt: {objectId}_select_prompt_{timestamp}_{random}
Example: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_select_prompt_1771022571836_abc123
Lookup Key: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_select_prompt
Job token (when prompt selected): {objectId}_{promptId}_{timestamp}_{random}
Example: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_promptId123_1771022571837_xyz789
Lookup Key: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_promptId123
ai:prompt (autofill): {objectId}_{fieldId}_{timestamp}_{random}
Example: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_description_1771022571838_def456
Lookup Key: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_description
proposeThought: {objectId}_proposeThought_{timestamp}_{random}
Example: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_proposeThought_1771022571839_ghi789
Lookup Key: 5ce3d147-f37d-4c8f-9c00-bc185182c4d5_proposeThought</pre>
</div>
<div class="section">
<h3>Example Job JSON</h3>
<div class="small">Example job data structure (for reference):</div>
<pre id="exampleJson">{
"token": "5ce3d147-f37d-4c8f-9c00-bc185182c4d5_promptId123_1771022571837_xyz789",
"startTime": "2025-01-15T10:30:00.000Z",
"status": "running",
"promptId": "promptId123",
"promptName": "Generate Summary",
"fieldId": null,
"progress": 45,
"total": 100,
"message": "Processing files..."
}</pre>
</div>
<div class="section">
<h3>Test extractKey Function</h3>
<div class="row">
<label for="testToken">Token:</label>
<input id="testToken" type="text" placeholder="Paste a token here" style="flex:1" />
<button id="testExtract">Test extractKey</button>
</div>
<pre id="extractResult"></pre>
</div>
<script>
// Load all active jobs on page load
function loadAllJobs() {
var statusEl = document.getElementById('allStatus');
var resultEl = document.getElementById('allJobsResult');
statusEl.textContent = 'Loading...';
statusEl.className = 'small';
resultEl.textContent = '';
fetch('/API/aijobs')
.then(function(res) {
if (!res.ok) {
throw new Error('HTTP ' + res.status + ': ' + res.statusText);
}
return res.json();
})
.then(function(data) {
var count = data.count || 0;
var lookupKeys = data.lookupKeys || 0;
var jobsArray = data.jobs || [];
statusEl.textContent = 'Success - ' + count + ' job(s) across ' + lookupKeys + ' lookup key(s)';
statusEl.className = 'small good';
// Format for display
var displayData = {
count: count,
lookupKeys: lookupKeys,
jobs: jobsArray
};
resultEl.textContent = JSON.stringify(displayData, null, 2);
})
.catch(function(e) {
statusEl.textContent = 'Error: ' + e.message;
statusEl.className = 'small bad';
resultEl.textContent = 'Error: ' + e.message;
});
}
// Load on page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadAllJobs);
} else {
loadAllJobs();
}
document.getElementById('refreshAll').addEventListener('click', loadAllJobs);
document.getElementById('loadJobs').addEventListener('click', async function() {
var objectId = document.getElementById('objectId').value.trim();
var statusEl = document.getElementById('loadStatus');
var resultEl = document.getElementById('jobsResult');
if (!objectId) {
statusEl.textContent = 'Please enter an object ID';
statusEl.className = 'small bad';
return;
}
statusEl.textContent = 'Loading...';
statusEl.className = 'small';
resultEl.textContent = '';
try {
var res = await fetch('/API/aijobs/' + encodeURIComponent(objectId));
if (!res.ok) {
throw new Error('HTTP ' + res.status + ': ' + res.statusText);
}
var data = await res.json();
statusEl.textContent = 'Success - ' + (data.count || 0) + ' job(s)';
statusEl.className = 'small good';
resultEl.textContent = JSON.stringify(data, null, 2);
} catch (e) {
statusEl.textContent = 'Error: ' + e.message;
statusEl.className = 'small bad';
resultEl.textContent = 'Error: ' + e.message;
}
});
document.getElementById('testExtract').addEventListener('click', function() {
var token = document.getElementById('testToken').value.trim();
var resultEl = document.getElementById('extractResult');
if (!token) {
resultEl.textContent = 'Please enter a token';
return;
}
// Token format: objectId_identifier_timestamp_random
// Extract: objectId_identifier (everything before last 2 underscores)
var parts = token.split('_');
if (parts.length < 3) {
resultEl.textContent = 'Invalid token format. Need at least 3 parts separated by underscores.';
return;
}
var lookupKey = parts.slice(0, -2).join('_');
var timestamp = parts[parts.length - 2];
var random = parts[parts.length - 1];
resultEl.textContent = JSON.stringify({
token: token,
lookupKey: lookupKey,
timestamp: timestamp,
random: random,
parts: parts.length
}, null, 2);
});
// Auto-load on Enter key
document.getElementById('objectId').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
document.getElementById('loadJobs').click();
}
});
document.getElementById('testToken').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
document.getElementById('testExtract').click();
}
});
</script>
</body>
</html>