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
|
@@ -1,16 +1,87 @@
|
|
|
1
1
|
import { escapeHtml } from "../utils/format.js";
|
|
2
2
|
|
|
3
|
+
function getJsonPreview(value) {
|
|
4
|
+
if (value === null || value === undefined) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof value === "object") {
|
|
9
|
+
return JSON.stringify(value, null, 2);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const text = String(value).trim();
|
|
13
|
+
|
|
14
|
+
if (!text || !["{", "["].includes(text[0])) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(text);
|
|
20
|
+
|
|
21
|
+
if (!parsed || typeof parsed !== "object") {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return JSON.stringify(parsed, null, 2);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function renderJsonViewer(prettyJson, title = "JSON Viewer") {
|
|
32
|
+
return `
|
|
33
|
+
<div class="border border-outline-variant/10 bg-surface-container px-4 py-4">
|
|
34
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.18em] text-primary-container/75">
|
|
35
|
+
${escapeHtml(title)}
|
|
36
|
+
</div>
|
|
37
|
+
<pre class="custom-scrollbar mt-3 max-h-[18rem] overflow-auto whitespace-pre-wrap break-words border border-outline-variant/10 bg-surface-container-lowest px-4 py-4 font-mono text-xs leading-6 text-on-surface">${escapeHtml(
|
|
38
|
+
prettyJson
|
|
39
|
+
)}</pre>
|
|
40
|
+
</div>
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
|
|
3
44
|
function renderReadonlyField(label, value) {
|
|
45
|
+
const jsonPreview = getJsonPreview(value);
|
|
46
|
+
|
|
4
47
|
return `
|
|
5
48
|
<div class="border border-outline-variant/10 bg-surface-container-lowest px-4 py-3">
|
|
6
49
|
<div class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">
|
|
7
50
|
${escapeHtml(label)}
|
|
8
51
|
</div>
|
|
9
|
-
|
|
52
|
+
${
|
|
53
|
+
jsonPreview
|
|
54
|
+
? `<div class="mt-2">${renderJsonViewer(jsonPreview)}</div>`
|
|
55
|
+
: `<div class="mt-2 text-sm text-on-surface">${escapeHtml(value)}</div>`
|
|
56
|
+
}
|
|
10
57
|
</div>
|
|
11
58
|
`;
|
|
12
59
|
}
|
|
13
60
|
|
|
61
|
+
function renderEditableField(field) {
|
|
62
|
+
const jsonPreview = getJsonPreview(field.value);
|
|
63
|
+
|
|
64
|
+
return `
|
|
65
|
+
<label class="block space-y-2">
|
|
66
|
+
<span class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">
|
|
67
|
+
${escapeHtml(field.label ?? field.name)}
|
|
68
|
+
</span>
|
|
69
|
+
${
|
|
70
|
+
jsonPreview
|
|
71
|
+
? renderJsonViewer(jsonPreview, "JSON Preview")
|
|
72
|
+
: ""
|
|
73
|
+
}
|
|
74
|
+
<textarea
|
|
75
|
+
class="w-full border border-outline-variant/20 bg-surface-container-lowest px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary-container ${
|
|
76
|
+
jsonPreview ? "min-h-[14rem] font-mono leading-6" : "min-h-[56px]"
|
|
77
|
+
}"
|
|
78
|
+
name="field:${escapeHtml(field.name)}"
|
|
79
|
+
spellcheck="false"
|
|
80
|
+
>${escapeHtml(field.value ?? "")}</textarea>
|
|
81
|
+
</label>
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
|
|
14
85
|
export function renderRowEditorPanel({
|
|
15
86
|
title,
|
|
16
87
|
sectionLabel = "Row Editor",
|
|
@@ -137,19 +208,7 @@ export function renderRowEditorPanel({
|
|
|
137
208
|
? `
|
|
138
209
|
<div class="space-y-4">
|
|
139
210
|
${editableFields
|
|
140
|
-
.map(
|
|
141
|
-
(field) => `
|
|
142
|
-
<label class="block space-y-2">
|
|
143
|
-
<span class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">
|
|
144
|
-
${escapeHtml(field.label ?? field.name)}
|
|
145
|
-
</span>
|
|
146
|
-
<textarea
|
|
147
|
-
class="min-h-[56px] w-full border border-outline-variant/20 bg-surface-container-lowest px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary-container"
|
|
148
|
-
name="field:${escapeHtml(field.name)}"
|
|
149
|
-
>${escapeHtml(field.value ?? "")}</textarea>
|
|
150
|
-
</label>
|
|
151
|
-
`
|
|
152
|
-
)
|
|
211
|
+
.map((field) => renderEditableField(field))
|
|
153
212
|
.join("")}
|
|
154
213
|
</div>
|
|
155
214
|
`
|