improve query presentation

This commit is contained in:
nate 2026-04-08 14:03:52 +04:00
parent 7da67364c4
commit a415dab320
1 changed files with 39 additions and 3 deletions

View File

@ -205,7 +205,7 @@ class QueryBuilder {
<span class="text-xs text-gray-500 font-mono">Query JSON</span>
<button id="qb-copy" class="text-xs text-blue-400 hover:text-blue-300">Copy</button>
</div>
<pre id="qb-preview" class="text-xs text-gray-300 font-mono whitespace-pre-wrap overflow-x-auto">${query ? escapeHtml(JSON.stringify(query, null, 2)) : '<span class="text-gray-600">No conditions set</span>'}</pre>
<pre id="qb-preview" class="text-xs text-gray-300 font-mono whitespace-pre-wrap overflow-x-auto">${query ? escapeHtml(formatQueryJson(query)) : '<span class="text-gray-600">No conditions set</span>'}</pre>
</div>
</div>
`;
@ -230,7 +230,7 @@ class QueryBuilder {
this.container.querySelector('#qb-copy').addEventListener('click', () => {
const q = this.getQuery();
navigator.clipboard.writeText(q ? JSON.stringify(q, null, 2) : '{}');
navigator.clipboard.writeText(q ? formatQueryJson(q) : '{}');
const btn = this.container.querySelector('#qb-copy');
btn.textContent = 'Copied!';
setTimeout(() => { btn.textContent = 'Copy'; }, 1500);
@ -326,7 +326,43 @@ class QueryBuilder {
const q = this.getQuery();
const preview = this.container.querySelector('#qb-preview');
if (preview) {
preview.textContent = q ? JSON.stringify(q, null, 2) : 'No conditions set';
preview.textContent = q ? formatQueryJson(q) : 'No conditions set';
}
}
}
// Compact-but-readable JSON formatter. Inlines any subtree that fits on a single
// line within MAX_INLINE chars; otherwise breaks across lines with 2-space indent.
const MAX_INLINE = 60;
function formatQueryJson(value, indent = 0) {
const inline = inlineForm(value);
if (inline.length + indent <= MAX_INLINE) return inline;
if (Array.isArray(value)) {
if (value.length === 0) return '[]';
const pad = ' '.repeat(indent + 2);
const close = ' '.repeat(indent);
const items = value.map(v => pad + formatQueryJson(v, indent + 2));
return '[\n' + items.join(',\n') + '\n' + close + ']';
}
if (value && typeof value === 'object') {
const entries = Object.entries(value);
if (entries.length === 0) return '{}';
const pad = ' '.repeat(indent + 2);
const close = ' '.repeat(indent);
const items = entries.map(([k, v]) => pad + JSON.stringify(k) + ': ' + formatQueryJson(v, indent + 2 + JSON.stringify(k).length + 2));
return '{\n' + items.join(',\n') + '\n' + close + '}';
}
return JSON.stringify(value);
}
function inlineForm(value) {
if (value === null || typeof value !== 'object') return JSON.stringify(value);
if (Array.isArray(value)) {
if (value.length === 0) return '[]';
return '[ ' + value.map(inlineForm).join(', ') + ' ]';
}
const entries = Object.entries(value);
if (entries.length === 0) return '{}';
return '{ ' + entries.map(([k, v]) => JSON.stringify(k) + ': ' + inlineForm(v)).join(', ') + ' }';
}