sqlite-hub 0.4.0 → 0.5.0
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 +7 -0
- package/frontend/js/api.js +99 -5
- package/frontend/js/app.js +90 -11
- package/frontend/js/components/bottomTabs.js +1 -1
- package/frontend/js/components/dataGrid.js +3 -3
- package/frontend/js/components/queryEditor.js +33 -55
- package/frontend/js/components/queryHistoryDetail.js +263 -0
- package/frontend/js/components/queryHistoryPanel.js +228 -0
- package/frontend/js/components/queryResults.js +32 -46
- package/frontend/js/components/rowEditorPanel.js +73 -14
- package/frontend/js/store.js +545 -21
- package/frontend/js/utils/format.js +23 -0
- package/frontend/js/views/data.js +34 -1
- package/frontend/js/views/editor.js +34 -10
- package/frontend/js/views/overview.js +15 -0
- package/frontend/styles/components.css +106 -0
- package/package.json +1 -1
- package/server/routes/data.js +2 -0
- package/server/routes/export.js +4 -1
- package/server/routes/overview.js +12 -0
- package/server/routes/sql.js +163 -5
- package/server/server.js +1 -1
- package/server/services/sqlite/dataBrowserService.js +4 -16
- package/server/services/sqlite/exportService.js +4 -16
- package/server/services/sqlite/overviewService.js +34 -0
- package/server/services/sqlite/sqlExecutor.js +83 -63
- package/server/services/sqlite/tableSort.js +63 -0
- package/server/services/storage/appStateStore.js +674 -1
- package/server/services/storage/queryHistoryUtils.js +169 -0
package/changelog.md
CHANGED
package/frontend/js/api.js
CHANGED
|
@@ -123,6 +123,12 @@ export function getOverview() {
|
|
|
123
123
|
return request("/api/db/overview");
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
export function openOverviewInFinder() {
|
|
127
|
+
return request("/api/db/overview/open-in-finder", {
|
|
128
|
+
method: "POST",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
export function getDbStatus() {
|
|
127
133
|
return request("/api/db/status");
|
|
128
134
|
}
|
|
@@ -134,16 +140,92 @@ export function executeSql(sql) {
|
|
|
134
140
|
});
|
|
135
141
|
}
|
|
136
142
|
|
|
137
|
-
export function
|
|
138
|
-
|
|
143
|
+
export function getQueryHistory(options = {}) {
|
|
144
|
+
const params = new URLSearchParams();
|
|
145
|
+
|
|
146
|
+
if (options.tab) {
|
|
147
|
+
params.set("tab", String(options.tab));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (options.limit !== undefined) {
|
|
151
|
+
params.set("limit", String(options.limit));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.offset !== undefined) {
|
|
155
|
+
params.set("offset", String(options.offset));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (options.search) {
|
|
159
|
+
params.set("search", String(options.search));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (options.queryType) {
|
|
163
|
+
params.set("queryType", String(options.queryType));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (options.onlySaved) {
|
|
167
|
+
params.set("onlySaved", "true");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (options.onlyFavorites) {
|
|
171
|
+
params.set("onlyFavorites", "true");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const query = params.toString();
|
|
175
|
+
return request(`/api/sql/history${query ? `?${query}` : ""}`);
|
|
139
176
|
}
|
|
140
177
|
|
|
141
|
-
export function
|
|
178
|
+
export function clearQueryHistory() {
|
|
142
179
|
return request("/api/sql/history", {
|
|
143
180
|
method: "DELETE",
|
|
144
181
|
});
|
|
145
182
|
}
|
|
146
183
|
|
|
184
|
+
export function getQueryHistoryItem(historyId) {
|
|
185
|
+
return request(`/api/sql/history/${encodeURIComponent(historyId)}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function getQueryHistoryRuns(historyId, options = {}) {
|
|
189
|
+
const params = new URLSearchParams();
|
|
190
|
+
|
|
191
|
+
if (options.limit !== undefined) {
|
|
192
|
+
params.set("limit", String(options.limit));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const query = params.toString();
|
|
196
|
+
|
|
197
|
+
return request(
|
|
198
|
+
`/api/sql/history/${encodeURIComponent(historyId)}/runs${query ? `?${query}` : ""}`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function toggleQueryHistorySaved(historyId, value) {
|
|
203
|
+
return request(`/api/sql/history/${encodeURIComponent(historyId)}/saved`, {
|
|
204
|
+
method: "PATCH",
|
|
205
|
+
body: { value },
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function renameQueryHistoryItem(historyId, title) {
|
|
210
|
+
return request(`/api/sql/history/${encodeURIComponent(historyId)}/title`, {
|
|
211
|
+
method: "PATCH",
|
|
212
|
+
body: { title },
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function updateQueryHistoryNotes(historyId, notes) {
|
|
217
|
+
return request(`/api/sql/history/${encodeURIComponent(historyId)}/notes`, {
|
|
218
|
+
method: "PATCH",
|
|
219
|
+
body: { notes },
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function deleteQueryHistoryItem(historyId) {
|
|
224
|
+
return request(`/api/sql/history/${encodeURIComponent(historyId)}`, {
|
|
225
|
+
method: "DELETE",
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
147
229
|
export function getStructureOverview() {
|
|
148
230
|
return request("/api/structure");
|
|
149
231
|
}
|
|
@@ -167,6 +249,14 @@ export function getDataTable(tableName, options = {}) {
|
|
|
167
249
|
params.set("offset", String(options.offset));
|
|
168
250
|
}
|
|
169
251
|
|
|
252
|
+
if (options.sortColumn) {
|
|
253
|
+
params.set("sortColumn", String(options.sortColumn));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (options.sortDirection) {
|
|
257
|
+
params.set("sortDirection", String(options.sortDirection));
|
|
258
|
+
}
|
|
259
|
+
|
|
170
260
|
const query = params.toString();
|
|
171
261
|
|
|
172
262
|
return request(`/api/data/${encodeURIComponent(tableName)}${query ? `?${query}` : ""}`);
|
|
@@ -205,10 +295,14 @@ export function downloadQueryCsv(sql) {
|
|
|
205
295
|
});
|
|
206
296
|
}
|
|
207
297
|
|
|
208
|
-
export function downloadTableCsv(tableName) {
|
|
298
|
+
export function downloadTableCsv(tableName, options = {}) {
|
|
209
299
|
return download("/api/export/table.csv", {
|
|
210
300
|
method: "POST",
|
|
211
|
-
body: {
|
|
301
|
+
body: {
|
|
302
|
+
tableName,
|
|
303
|
+
sortColumn: options.sortColumn,
|
|
304
|
+
sortDirection: options.sortDirection,
|
|
305
|
+
},
|
|
212
306
|
fallbackFilename: `${tableName || "table"}.csv`,
|
|
213
307
|
});
|
|
214
308
|
}
|
package/frontend/js/app.js
CHANGED
|
@@ -16,24 +16,29 @@ import {
|
|
|
16
16
|
clearDataRowSelection,
|
|
17
17
|
clearEditorRowSelection,
|
|
18
18
|
clearEditorResults,
|
|
19
|
-
|
|
19
|
+
clearQueryHistorySelection,
|
|
20
20
|
closeModal,
|
|
21
|
+
deleteQueryHistoryStateItem,
|
|
21
22
|
dismissToast,
|
|
22
23
|
executeCurrentQuery,
|
|
23
24
|
exportCurrentDataTableCsv,
|
|
24
25
|
exportCurrentQueryCsv,
|
|
25
26
|
getState,
|
|
26
27
|
initializeApp,
|
|
27
|
-
|
|
28
|
+
loadMoreQueryHistory,
|
|
28
29
|
openModal,
|
|
30
|
+
openOverviewInFinder,
|
|
31
|
+
openQueryHistoryInEditor,
|
|
29
32
|
openDeleteDataRowModal,
|
|
30
33
|
openDeleteEditorRowModal,
|
|
31
34
|
openEditConnectionModal,
|
|
32
35
|
refreshCurrentRoute,
|
|
33
36
|
removeConnection,
|
|
37
|
+
runQueryHistoryItem,
|
|
34
38
|
selectDataRow,
|
|
35
39
|
selectEditorRow,
|
|
36
40
|
selectConnection,
|
|
41
|
+
selectQueryHistoryItem,
|
|
37
42
|
selectStructureEntry,
|
|
38
43
|
setDataPage,
|
|
39
44
|
setDataPageSize,
|
|
@@ -41,7 +46,13 @@ import {
|
|
|
41
46
|
setDataSearchQuery,
|
|
42
47
|
setCurrentQuery,
|
|
43
48
|
setEditorTab,
|
|
49
|
+
sortDataTableByColumn,
|
|
50
|
+
sortEditorResultsByColumn,
|
|
51
|
+
setQueryHistorySearchInput,
|
|
52
|
+
setQueryHistoryTab,
|
|
44
53
|
setRoute,
|
|
54
|
+
saveQueryHistoryNotes,
|
|
55
|
+
saveQueryHistoryTitle,
|
|
45
56
|
submitCreateConnection,
|
|
46
57
|
submitDeleteRowConfirmation,
|
|
47
58
|
submitDataRowUpdate,
|
|
@@ -50,6 +61,7 @@ import {
|
|
|
50
61
|
submitImportSql,
|
|
51
62
|
submitOpenConnection,
|
|
52
63
|
subscribe,
|
|
64
|
+
toggleQueryHistorySavedState,
|
|
53
65
|
} from "./store.js";
|
|
54
66
|
import { renderConnectionsView } from "./views/connections.js";
|
|
55
67
|
import { renderDataView } from "./views/data.js";
|
|
@@ -338,6 +350,9 @@ async function handleAction(actionNode) {
|
|
|
338
350
|
case "create-backup":
|
|
339
351
|
await createActiveConnectionBackup();
|
|
340
352
|
return;
|
|
353
|
+
case "open-overview-in-finder":
|
|
354
|
+
await openOverviewInFinder();
|
|
355
|
+
return;
|
|
341
356
|
case "execute-query": {
|
|
342
357
|
await executeEditorQueryAndNavigate();
|
|
343
358
|
return;
|
|
@@ -350,11 +365,57 @@ async function handleAction(actionNode) {
|
|
|
350
365
|
return;
|
|
351
366
|
case "clear-query":
|
|
352
367
|
clearCurrentQuery();
|
|
368
|
+
if (getState().route.name === "editorResults") {
|
|
369
|
+
router.navigate("/editor");
|
|
370
|
+
}
|
|
353
371
|
return;
|
|
354
372
|
case "clear-results":
|
|
355
373
|
clearEditorResults();
|
|
356
374
|
router.navigate("/editor");
|
|
357
375
|
return;
|
|
376
|
+
case "select-query-history-item":
|
|
377
|
+
if (actionNode.dataset.historyId) {
|
|
378
|
+
await selectQueryHistoryItem(actionNode.dataset.historyId);
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
case "clear-query-history-selection":
|
|
382
|
+
clearQueryHistorySelection();
|
|
383
|
+
return;
|
|
384
|
+
case "set-query-history-tab":
|
|
385
|
+
if (actionNode.dataset.tab) {
|
|
386
|
+
await setQueryHistoryTab(actionNode.dataset.tab);
|
|
387
|
+
}
|
|
388
|
+
return;
|
|
389
|
+
case "load-more-query-history":
|
|
390
|
+
await loadMoreQueryHistory();
|
|
391
|
+
return;
|
|
392
|
+
case "open-query-history":
|
|
393
|
+
if (actionNode.dataset.historyId && openQueryHistoryInEditor(actionNode.dataset.historyId)) {
|
|
394
|
+
router.navigate("/editor");
|
|
395
|
+
}
|
|
396
|
+
return;
|
|
397
|
+
case "run-query-history":
|
|
398
|
+
if (actionNode.dataset.historyId) {
|
|
399
|
+
const success = await runQueryHistoryItem(actionNode.dataset.historyId);
|
|
400
|
+
router.navigate(success ? "/editor/results" : "/editor");
|
|
401
|
+
}
|
|
402
|
+
return;
|
|
403
|
+
case "toggle-query-history-saved":
|
|
404
|
+
if (actionNode.dataset.historyId) {
|
|
405
|
+
await toggleQueryHistorySavedState(
|
|
406
|
+
actionNode.dataset.historyId,
|
|
407
|
+
actionNode.dataset.nextValue === "true"
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
return;
|
|
411
|
+
case "delete-query-history":
|
|
412
|
+
if (
|
|
413
|
+
actionNode.dataset.historyId &&
|
|
414
|
+
window.confirm("Delete this query history item and all recorded runs?")
|
|
415
|
+
) {
|
|
416
|
+
await deleteQueryHistoryStateItem(actionNode.dataset.historyId);
|
|
417
|
+
}
|
|
418
|
+
return;
|
|
358
419
|
case "set-editor-tab": {
|
|
359
420
|
const tab = actionNode.dataset.tab;
|
|
360
421
|
if (!tab) {
|
|
@@ -364,9 +425,6 @@ async function handleAction(actionNode) {
|
|
|
364
425
|
router.navigate(tab === "results" ? "/editor/results" : "/editor");
|
|
365
426
|
return;
|
|
366
427
|
}
|
|
367
|
-
case "clear-sql-history":
|
|
368
|
-
await clearSqlHistoryStateAndData();
|
|
369
|
-
return;
|
|
370
428
|
case "export-query-csv":
|
|
371
429
|
await exportCurrentQueryCsv();
|
|
372
430
|
return;
|
|
@@ -399,6 +457,16 @@ async function handleAction(actionNode) {
|
|
|
399
457
|
await setDataPage(actionNode.dataset.page);
|
|
400
458
|
}
|
|
401
459
|
return;
|
|
460
|
+
case "sort-data-column":
|
|
461
|
+
if (actionNode.dataset.columnName) {
|
|
462
|
+
await sortDataTableByColumn(actionNode.dataset.columnName);
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
case "sort-editor-results-column":
|
|
466
|
+
if (actionNode.dataset.columnName) {
|
|
467
|
+
sortEditorResultsByColumn(actionNode.dataset.columnName);
|
|
468
|
+
}
|
|
469
|
+
return;
|
|
402
470
|
case "set-data-page-size":
|
|
403
471
|
if (actionNode.dataset.pageSize) {
|
|
404
472
|
await setDataPageSize(actionNode.dataset.pageSize);
|
|
@@ -483,6 +551,11 @@ document.addEventListener("input", (event) => {
|
|
|
483
551
|
|
|
484
552
|
if (bindNode.dataset.bind === "data-search-query") {
|
|
485
553
|
setDataSearchQuery(bindNode.value);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (bindNode.dataset.bind === "query-history-search") {
|
|
558
|
+
setQueryHistorySearchInput(bindNode.value);
|
|
486
559
|
}
|
|
487
560
|
});
|
|
488
561
|
|
|
@@ -507,12 +580,6 @@ document.addEventListener("change", (event) => {
|
|
|
507
580
|
return;
|
|
508
581
|
}
|
|
509
582
|
|
|
510
|
-
if (bindNode.dataset.bind === "history-entry" && bindNode.value) {
|
|
511
|
-
loadQueryFromHistory(bindNode.value);
|
|
512
|
-
bindNode.value = "";
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
583
|
if (bindNode.dataset.bind === "data-search-column") {
|
|
517
584
|
setDataSearchColumn(bindNode.value);
|
|
518
585
|
}
|
|
@@ -634,6 +701,18 @@ document.addEventListener("submit", async (event) => {
|
|
|
634
701
|
);
|
|
635
702
|
return;
|
|
636
703
|
}
|
|
704
|
+
case "save-query-history-title":
|
|
705
|
+
await saveQueryHistoryTitle(
|
|
706
|
+
String(formData.get("historyId") ?? ""),
|
|
707
|
+
String(formData.get("title") ?? "")
|
|
708
|
+
);
|
|
709
|
+
return;
|
|
710
|
+
case "save-query-history-notes":
|
|
711
|
+
await saveQueryHistoryNotes(
|
|
712
|
+
String(formData.get("historyId") ?? ""),
|
|
713
|
+
String(formData.get("notes") ?? "")
|
|
714
|
+
);
|
|
715
|
+
return;
|
|
637
716
|
default:
|
|
638
717
|
}
|
|
639
718
|
});
|
|
@@ -3,8 +3,8 @@ import { escapeHtml } from "../utils/format.js";
|
|
|
3
3
|
export function renderBottomTabs(activeTab, counts = {}) {
|
|
4
4
|
const tabs = [
|
|
5
5
|
{ key: "results", label: "results", meta: counts.resultRows ?? 0 },
|
|
6
|
-
{ key: "messages", label: "messages", meta: counts.messages ?? 0 },
|
|
7
6
|
{ key: "performance", label: "performance", meta: counts.statementCount ?? 0 },
|
|
7
|
+
{ key: "messages", label: "messages", meta: counts.messages ?? 0 },
|
|
8
8
|
];
|
|
9
9
|
|
|
10
10
|
return `
|
|
@@ -14,9 +14,9 @@ export function renderDataGrid({
|
|
|
14
14
|
<tr class="${headerRowClass}">
|
|
15
15
|
${columns
|
|
16
16
|
.map(
|
|
17
|
-
|
|
18
|
-
<th class="${column.headerClassName ?? ""}">
|
|
19
|
-
${column.label}
|
|
17
|
+
(column) => `
|
|
18
|
+
<th class="${column.headerClassName ?? ""}" ${column.headerAttrs ?? ""}>
|
|
19
|
+
${column.renderHeader ? column.renderHeader() : column.label}
|
|
20
20
|
</th>
|
|
21
21
|
`
|
|
22
22
|
)
|
|
@@ -9,23 +9,6 @@ function renderLineNumbers(query) {
|
|
|
9
9
|
.join("");
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
function renderHistoryOptions(history) {
|
|
13
|
-
if (!history.length) {
|
|
14
|
-
return '<option value="">No recent statements</option>';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return [
|
|
18
|
-
'<option value="">Load recent statement...</option>',
|
|
19
|
-
...history.map(
|
|
20
|
-
(entry) => `
|
|
21
|
-
<option value="${escapeHtml(entry.id)}">
|
|
22
|
-
${escapeHtml(entry.sql.replace(/\s+/g, " ").slice(0, 96))}
|
|
23
|
-
</option>
|
|
24
|
-
`
|
|
25
|
-
),
|
|
26
|
-
].join("");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
12
|
function renderHighlightedQuery(query) {
|
|
30
13
|
if (query) {
|
|
31
14
|
return highlightSql(query);
|
|
@@ -34,13 +17,41 @@ function renderHighlightedQuery(query) {
|
|
|
34
17
|
return '<span class="text-on-surface-variant/35">SELECT name FROM sqlite_master WHERE type = \'table\';</span>';
|
|
35
18
|
}
|
|
36
19
|
|
|
20
|
+
function renderEditorSurface({ query }) {
|
|
21
|
+
return `
|
|
22
|
+
<div class="flex min-h-0 flex-1 overflow-hidden">
|
|
23
|
+
<div class="flex w-12 flex-col items-center bg-surface-container-lowest py-4 font-mono text-xs select-none text-outline-variant/30">
|
|
24
|
+
${renderLineNumbers(query)}
|
|
25
|
+
</div>
|
|
26
|
+
<div class="relative flex-1 overflow-hidden bg-surface-container p-6 font-mono text-sm leading-relaxed">
|
|
27
|
+
<div class="pointer-events-none absolute right-0 top-0 p-4 opacity-5">
|
|
28
|
+
<span class="material-symbols-outlined text-[120px] font-thin">terminal</span>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="query-editor-layer relative z-10 h-full min-h-[140px]">
|
|
31
|
+
<pre
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
class="query-editor-highlight"
|
|
34
|
+
data-query-editor-highlight
|
|
35
|
+
>${renderHighlightedQuery(query)}</pre>
|
|
36
|
+
<textarea
|
|
37
|
+
class="query-editor-input custom-scrollbar relative z-10 h-full min-h-[140px] w-full resize-none border-none focus:ring-0"
|
|
38
|
+
data-bind="current-query"
|
|
39
|
+
placeholder="SELECT name FROM sqlite_master WHERE type = 'table';"
|
|
40
|
+
spellcheck="false"
|
|
41
|
+
>${escapeHtml(query)}</textarea>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
export function renderQueryEditor({
|
|
38
49
|
query,
|
|
39
50
|
title,
|
|
40
51
|
executing = false,
|
|
41
52
|
exporting = false,
|
|
42
|
-
history = [],
|
|
43
53
|
historyLoading = false,
|
|
54
|
+
historyTotal = 0,
|
|
44
55
|
}) {
|
|
45
56
|
const left = `
|
|
46
57
|
<div class="flex items-center gap-2 bg-surface-container-lowest px-3 py-1">
|
|
@@ -51,24 +62,11 @@ export function renderQueryEditor({
|
|
|
51
62
|
</div>
|
|
52
63
|
<div class="hidden items-center gap-2 text-[10px] font-mono uppercase tracking-widest text-on-surface-variant/40 md:flex">
|
|
53
64
|
<span class="material-symbols-outlined text-xs">history</span>
|
|
54
|
-
${historyLoading ? "Loading history..." : `${
|
|
65
|
+
${historyLoading ? "Loading history..." : `${historyTotal} queries tracked`}
|
|
55
66
|
</div>
|
|
56
67
|
`;
|
|
57
68
|
|
|
58
69
|
const right = `
|
|
59
|
-
<select
|
|
60
|
-
class="min-w-[220px] border border-outline-variant/20 bg-surface-container-lowest px-3 py-2 text-[10px] font-mono uppercase tracking-[0.14em] text-on-surface-variant outline-none"
|
|
61
|
-
data-bind="history-entry"
|
|
62
|
-
>
|
|
63
|
-
${renderHistoryOptions(history)}
|
|
64
|
-
</select>
|
|
65
|
-
<button
|
|
66
|
-
class="px-4 py-1.5 text-[10px] font-bold uppercase tracking-widest text-on-surface hover:bg-surface-container-highest transition-colors"
|
|
67
|
-
data-action="clear-sql-history"
|
|
68
|
-
type="button"
|
|
69
|
-
>
|
|
70
|
-
Clear History
|
|
71
|
-
</button>
|
|
72
70
|
<button
|
|
73
71
|
class="px-4 py-1.5 text-[10px] font-bold uppercase tracking-widest text-on-surface hover:bg-surface-container-highest transition-colors"
|
|
74
72
|
data-action="clear-query"
|
|
@@ -93,7 +91,7 @@ export function renderQueryEditor({
|
|
|
93
91
|
`;
|
|
94
92
|
|
|
95
93
|
return `
|
|
96
|
-
<div class="flex h-full flex-col">
|
|
94
|
+
<div class="flex h-full min-h-0 flex-col">
|
|
97
95
|
<div class="bg-surface-container-low px-6 py-3">
|
|
98
96
|
${renderActionBar({
|
|
99
97
|
left,
|
|
@@ -101,28 +99,8 @@ export function renderQueryEditor({
|
|
|
101
99
|
className: "flex-wrap",
|
|
102
100
|
})}
|
|
103
101
|
</div>
|
|
104
|
-
<div class="flex flex-1
|
|
105
|
-
|
|
106
|
-
${renderLineNumbers(query)}
|
|
107
|
-
</div>
|
|
108
|
-
<div class="relative flex-1 overflow-hidden bg-surface-container p-6 font-mono text-sm leading-relaxed">
|
|
109
|
-
<div class="pointer-events-none absolute right-0 top-0 p-4 opacity-5">
|
|
110
|
-
<span class="material-symbols-outlined text-[120px] font-thin">terminal</span>
|
|
111
|
-
</div>
|
|
112
|
-
<div class="query-editor-layer relative z-10 h-full min-h-[140px]">
|
|
113
|
-
<pre
|
|
114
|
-
aria-hidden="true"
|
|
115
|
-
class="query-editor-highlight"
|
|
116
|
-
data-query-editor-highlight
|
|
117
|
-
>${renderHighlightedQuery(query)}</pre>
|
|
118
|
-
<textarea
|
|
119
|
-
class="query-editor-input custom-scrollbar relative z-10 h-full min-h-[140px] w-full resize-none border-none focus:ring-0"
|
|
120
|
-
data-bind="current-query"
|
|
121
|
-
placeholder="SELECT name FROM sqlite_master WHERE type = 'table';"
|
|
122
|
-
spellcheck="false"
|
|
123
|
-
>${escapeHtml(query)}</textarea>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
102
|
+
<div class="flex min-h-0 flex-1 flex-col">
|
|
103
|
+
${renderEditorSurface({ query })}
|
|
126
104
|
</div>
|
|
127
105
|
</div>
|
|
128
106
|
`;
|