graphvault-studio 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/admin-ui.js +71 -37
- package/dist/admin-ui.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.6
|
|
4
|
+
|
|
5
|
+
- Remove the global KPI strip from every Studio tab; summary signals now stay in Overview and Operations instead of occupying the main workspace everywhere.
|
|
6
|
+
|
|
7
|
+
## 0.1.5
|
|
8
|
+
|
|
9
|
+
- Restore the Object Hierarchy view as an expandable lazy tree with persistent root context instead of a drilldown-only list.
|
|
10
|
+
|
|
3
11
|
## 0.1.4
|
|
4
12
|
|
|
5
13
|
- Add production safety status and score to the summary API, Overview, KPI bar, and Operations view.
|
package/dist/admin-ui.js
CHANGED
|
@@ -25,7 +25,7 @@ export const ADMIN_HTML = `<!doctype html>
|
|
|
25
25
|
}
|
|
26
26
|
* { box-sizing: border-box; }
|
|
27
27
|
body { margin: 0; min-height: 100vh; }
|
|
28
|
-
strong, b, .status, .panel-title, .mutation summary, .object-id, .tag, .field-name
|
|
28
|
+
strong, b, .status, .panel-title, .mutation summary, .object-id, .tag, .field-name { text-shadow: none; }
|
|
29
29
|
button, input, select, textarea { font: inherit; }
|
|
30
30
|
button { border: 1px solid var(--line); background: #fff; border-radius: 7px; cursor: pointer; }
|
|
31
31
|
button:hover { border-color: #98aab3; background: #f6fafb; }
|
|
@@ -51,11 +51,7 @@ export const ADMIN_HTML = `<!doctype html>
|
|
|
51
51
|
.topbar h1 { margin: 0; font-family: "Avenir Next", "SF Pro Display", "Aptos Display", "Inter", ui-sans-serif, system-ui, sans-serif; font-size: 24px; letter-spacing: 0; font-weight: 600; }
|
|
52
52
|
.auth { display: none; grid-template-columns: minmax(160px, 280px) auto; gap: 8px; }
|
|
53
53
|
.workspace { padding: 18px; display: grid; gap: 14px; }
|
|
54
|
-
.
|
|
55
|
-
.kpi, .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 10px 28px rgba(15, 35, 45, 0.05); }
|
|
56
|
-
.kpi { padding: 14px; display: grid; gap: 8px; min-height: 94px; }
|
|
57
|
-
.kpi span { color: var(--muted); font-size: 13px; }
|
|
58
|
-
.kpi strong { font-size: 28px; line-height: 1; overflow-wrap: anywhere; font-weight: 600; }
|
|
54
|
+
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 10px 28px rgba(15, 35, 45, 0.05); }
|
|
59
55
|
.workgrid { display: grid; grid-template-columns: minmax(330px, 500px) minmax(560px, 1fr); gap: 14px; min-height: 0; }
|
|
60
56
|
.panel { min-width: 0; overflow: hidden; }
|
|
61
57
|
.panel-head { padding: 13px 14px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--line); background: #fbfdfd; }
|
|
@@ -118,7 +114,7 @@ export const ADMIN_HTML = `<!doctype html>
|
|
|
118
114
|
.field-actions { grid-area: actions; justify-content: flex-start; }
|
|
119
115
|
}
|
|
120
116
|
@media (max-width: 980px) {
|
|
121
|
-
.shell, .
|
|
117
|
+
.shell, .mutation-grid, .audit-grid, .topbar, .fields-head { grid-template-columns: 1fr; }
|
|
122
118
|
.gvql-actions, .gvql-parameter-row { grid-template-columns: 1fr; }
|
|
123
119
|
nav { grid-template-rows: auto; gap: 10px; padding: 12px; }
|
|
124
120
|
.brand { grid-template-columns: 42px 1fr; padding-bottom: 2px; }
|
|
@@ -167,7 +163,6 @@ export const ADMIN_HTML = `<!doctype html>
|
|
|
167
163
|
<span class="status" id="status">loading</span>
|
|
168
164
|
</header>
|
|
169
165
|
<main class="workspace">
|
|
170
|
-
<div class="kpis" id="kpis"></div>
|
|
171
166
|
<div class="workgrid">
|
|
172
167
|
<div class="panel">
|
|
173
168
|
<div class="panel-head"><span class="panel-title" id="listTitle">Objects</span><span class="hint" id="listHint">Select a record</span></div>
|
|
@@ -220,7 +215,6 @@ OFFSET 0</textarea>
|
|
|
220
215
|
const viz = document.getElementById('viz');
|
|
221
216
|
const fields = document.getElementById('fields');
|
|
222
217
|
const list = document.getElementById('list');
|
|
223
|
-
const kpis = document.getElementById('kpis');
|
|
224
218
|
const status = document.getElementById('status');
|
|
225
219
|
const title = document.getElementById('title');
|
|
226
220
|
const subtitle = document.getElementById('subtitle');
|
|
@@ -231,7 +225,11 @@ OFFSET 0</textarea>
|
|
|
231
225
|
const authTokenInput = document.getElementById('authToken');
|
|
232
226
|
const objectPageSize = 100;
|
|
233
227
|
let objectPageOffset = 0;
|
|
234
|
-
let
|
|
228
|
+
let hierarchyRootId = '';
|
|
229
|
+
let selectedHierarchyId = '';
|
|
230
|
+
const hierarchyExpanded = new Set();
|
|
231
|
+
const hierarchyRecords = new Map();
|
|
232
|
+
const hierarchyChildren = new Map();
|
|
235
233
|
let gvqlEditorWired = false;
|
|
236
234
|
const viewText = {
|
|
237
235
|
hierarchy: ['Object Hierarchy', 'Root-first graph view with references you can follow.'],
|
|
@@ -296,7 +294,6 @@ OFFSET 0</textarea>
|
|
|
296
294
|
return value;
|
|
297
295
|
};
|
|
298
296
|
const postJson = (url, body) => requestJson(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
|
|
299
|
-
const kpi = (label, value) => '<div class="kpi"><span>' + esc(label) + '</span><strong>' + esc(value) + '</strong></div>';
|
|
300
297
|
function setRows(rows, emptyText) {
|
|
301
298
|
if (!rows.length) {
|
|
302
299
|
const empty = document.createElement('div');
|
|
@@ -322,21 +319,12 @@ OFFSET 0</textarea>
|
|
|
322
319
|
}));
|
|
323
320
|
}
|
|
324
321
|
async function refreshKpis() {
|
|
325
|
-
|
|
326
|
-
const hardening = summary.hardening || {};
|
|
327
|
-
const ops = summary.operations || {};
|
|
328
|
-
const library = summary.library || {};
|
|
329
|
-
const safety = summary.productionSafety || {};
|
|
330
|
-
const walLabel = (hardening.transactionLog || '-') + (typeof ops.pendingWalCommits === 'number' ? ' / ' + ops.pendingWalCommits + ' pending' : '');
|
|
331
|
-
const libraryLabel = (library.installedVersion || '-') + (library.status === 'warning' ? ' warning' : '');
|
|
332
|
-
const safetyLabel = (safety.status || '-') + (typeof safety.score === 'number' ? ' / ' + safety.score : '');
|
|
333
|
-
kpis.innerHTML = kpi('Objects', summary.objectCount) + kpi('Transaction', summary.transactionId) + kpi('Safety', safetyLabel) + kpi('Library', libraryLabel) + kpi('WAL', walLabel) + kpi('Lock', hardening.writerLock || '-') + kpi('Ops', ops.status || '-') + kpi('Snapshot', summary.currentSnapshot || '-');
|
|
334
|
-
return summary;
|
|
322
|
+
return apiJson('/api/summary?verify=false');
|
|
335
323
|
}
|
|
336
324
|
async function showHierarchy() {
|
|
337
325
|
setView('hierarchy');
|
|
338
326
|
listTitle.textContent = 'Object hierarchy';
|
|
339
|
-
listHint.textContent = '
|
|
327
|
+
listHint.textContent = 'Expandable lazy tree';
|
|
340
328
|
await refreshKpis();
|
|
341
329
|
const root = await apiJson('/api/root');
|
|
342
330
|
if (!root.rootObjectId) {
|
|
@@ -344,29 +332,75 @@ OFFSET 0</textarea>
|
|
|
344
332
|
show(root);
|
|
345
333
|
return;
|
|
346
334
|
}
|
|
347
|
-
|
|
348
|
-
|
|
335
|
+
hierarchyRootId = root.rootObjectId;
|
|
336
|
+
selectedHierarchyId = selectedHierarchyId || hierarchyRootId;
|
|
337
|
+
hierarchyExpanded.add(hierarchyRootId);
|
|
338
|
+
await ensureHierarchyNode(hierarchyRootId);
|
|
339
|
+
await renderHierarchyTree();
|
|
340
|
+
await selectHierarchyObject(selectedHierarchyId, 'root');
|
|
341
|
+
}
|
|
342
|
+
async function ensureHierarchyNode(id) {
|
|
343
|
+
if (!hierarchyRecords.has(id)) {
|
|
344
|
+
hierarchyRecords.set(id, await apiJson('/api/objects/' + encodeURIComponent(id)));
|
|
345
|
+
}
|
|
346
|
+
if (!hierarchyChildren.has(id)) {
|
|
347
|
+
hierarchyChildren.set(id, await apiJson('/api/objects/' + encodeURIComponent(id) + '/children'));
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
record: hierarchyRecords.get(id),
|
|
351
|
+
children: hierarchyChildren.get(id) || []
|
|
352
|
+
};
|
|
349
353
|
}
|
|
350
|
-
async function
|
|
354
|
+
async function selectHierarchyObject(id, label) {
|
|
351
355
|
document.getElementById('graphRoot').value = id;
|
|
352
|
-
|
|
353
|
-
|
|
356
|
+
selectedHierarchyId = id;
|
|
357
|
+
const data = await ensureHierarchyNode(id);
|
|
358
|
+
const record = data.record;
|
|
354
359
|
renderEditableFields(record);
|
|
355
360
|
document.getElementById('mid').value = id;
|
|
356
361
|
document.getElementById('detailHint').textContent = 'Object #' + id;
|
|
357
362
|
out.textContent = JSON.stringify(record, null, 2);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
363
|
+
}
|
|
364
|
+
async function toggleHierarchyObject(id, label) {
|
|
365
|
+
const data = await ensureHierarchyNode(id);
|
|
366
|
+
if (data.children.length) {
|
|
367
|
+
if (hierarchyExpanded.has(id)) hierarchyExpanded.delete(id);
|
|
368
|
+
else hierarchyExpanded.add(id);
|
|
369
|
+
}
|
|
370
|
+
await selectHierarchyObject(id, label);
|
|
371
|
+
await renderHierarchyTree();
|
|
372
|
+
}
|
|
373
|
+
async function renderHierarchyTree() {
|
|
374
|
+
if (!hierarchyRootId) return;
|
|
375
|
+
const rows = [];
|
|
376
|
+
await appendHierarchyRows(rows, hierarchyRootId, 'root', 0, []);
|
|
368
377
|
setRows(rows, 'No children');
|
|
369
378
|
}
|
|
379
|
+
async function appendHierarchyRows(rows, id, label, depth, path) {
|
|
380
|
+
const data = await ensureHierarchyNode(id);
|
|
381
|
+
const record = data.record;
|
|
382
|
+
const children = data.children;
|
|
383
|
+
const isExpanded = hierarchyExpanded.has(id);
|
|
384
|
+
const marker = children.length ? (isExpanded ? '[-] ' : '[+] ') : ' ';
|
|
385
|
+
rows.push({
|
|
386
|
+
depth,
|
|
387
|
+
columns: [marker + '#' + record.objectId, record.node.type || record.node.kind, label + ' -> ' + summarizeRecord(record), id === selectedHierarchyId ? 'selected' : children.length + ' children'],
|
|
388
|
+
onclick: () => toggleHierarchyObject(id, label)
|
|
389
|
+
});
|
|
390
|
+
if (!isExpanded) return;
|
|
391
|
+
const nextPath = path.concat(id);
|
|
392
|
+
for (const child of children) {
|
|
393
|
+
if (nextPath.includes(child.to)) {
|
|
394
|
+
rows.push({
|
|
395
|
+
depth: depth + 1,
|
|
396
|
+
columns: ['[ref] #' + child.to, child.type || child.kind, child.path + ' -> cycle/shared reference', 'linked'],
|
|
397
|
+
onclick: () => selectHierarchyObject(child.to, child.path)
|
|
398
|
+
});
|
|
399
|
+
} else {
|
|
400
|
+
await appendHierarchyRows(rows, child.to, child.path, depth + 1, nextPath);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
370
404
|
async function showObjectInHierarchyPath(id) {
|
|
371
405
|
document.getElementById('graphRoot').value = id;
|
|
372
406
|
setView('hierarchy');
|
package/dist/admin-ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-ui.js","sourceRoot":"","sources":["../src/admin-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,CAAC,MAAM,UAAU,GAAG
|
|
1
|
+
{"version":3,"file":"admin-ui.js","sourceRoot":"","sources":["../src/admin-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA6NC,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwxBvD,CAAC"}
|