sqlite-hub 1.1.1 → 1.1.2
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/README.md +17 -196
- package/bin/sqlite-hub.js +7 -2
- package/frontend/js/api.js +60 -0
- package/frontend/js/app.js +110 -0
- package/frontend/js/components/dropdownButton.js +92 -0
- package/frontend/js/components/modal.js +991 -876
- package/frontend/js/components/queryEditor.js +24 -15
- package/frontend/js/components/queryHistoryDetail.js +20 -1
- package/frontend/js/components/queryHistoryHeader.js +3 -2
- package/frontend/js/components/rowEditorPanel.js +1 -0
- package/frontend/js/components/sidebar.js +1 -0
- package/frontend/js/router.js +2 -0
- package/frontend/js/store.js +383 -37
- package/frontend/js/utils/riskySql.js +165 -0
- package/frontend/js/views/backups.js +176 -0
- package/frontend/js/views/charts.js +1 -1
- package/frontend/js/views/documents.js +184 -154
- package/frontend/js/views/structure.js +26 -24
- package/frontend/styles/components.css +128 -0
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/views.css +33 -21
- package/package.json +2 -1
- package/server/routes/backups.js +120 -0
- package/server/routes/connections.js +26 -3
- package/server/routes/externalApi.js +6 -2
- package/server/server.js +3 -1
- package/server/services/databaseCommandService.js +4 -3
- package/server/services/sqlite/backupService.js +497 -66
- package/server/services/sqlite/connectionManager.js +2 -2
- package/server/services/sqlite/importService.js +25 -0
- package/server/services/sqlite/sqlExecutor.js +2 -0
- package/server/services/storage/appStateStore.js +379 -88
- package/tests/api-token-auth.test.js +45 -2
- package/tests/backup-manager.test.js +140 -0
- package/tests/backups-view.test.js +64 -0
- package/tests/charts-height-preset-storage.test.js +60 -0
- package/tests/charts-route-state.test.js +144 -0
- package/tests/cli-service-delegation.test.js +97 -0
- package/tests/connection-removal.test.js +52 -0
- package/tests/database-command-service.test.js +37 -2
- package/tests/documents-view.test.js +132 -0
- package/tests/dropdown-button.test.js +75 -0
- package/tests/query-editor.test.js +28 -0
- package/tests/query-history-detail.test.js +37 -0
- package/tests/query-history-header.test.js +30 -0
- package/tests/risky-sql.test.js +30 -0
- package/tests/row-editor-null-values.test.js +24 -0
- package/tests/structure-view.test.js +56 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderDropdownButton } from "./dropdownButton.js";
|
|
1
2
|
import { escapeHtml, highlightSql } from "../utils/format.js";
|
|
2
3
|
|
|
3
4
|
function renderLineNumbers(query) {
|
|
@@ -57,21 +58,29 @@ export function renderQueryEditor({
|
|
|
57
58
|
`;
|
|
58
59
|
|
|
59
60
|
const center = `
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
${renderDropdownButton({
|
|
62
|
+
icon: "edit_note",
|
|
63
|
+
label: "Editor",
|
|
64
|
+
title: "Editor actions",
|
|
65
|
+
items: [
|
|
66
|
+
{
|
|
67
|
+
action: "format-current-query",
|
|
68
|
+
icon: "format_align_left",
|
|
69
|
+
label: "Format",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
action: "clear-query",
|
|
73
|
+
icon: "delete_sweep",
|
|
74
|
+
label: "Clear",
|
|
75
|
+
danger: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
action: "copy-current-query",
|
|
79
|
+
icon: "content_copy",
|
|
80
|
+
label: "Copy to Clipboard",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
})}
|
|
75
84
|
<button
|
|
76
85
|
class="${secondaryButtonClass}"
|
|
77
86
|
data-action="open-query-export-modal"
|
|
@@ -35,11 +35,30 @@ function getQueryTypeTone(queryType) {
|
|
|
35
35
|
return "muted";
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function getExecutionSourceTone(source) {
|
|
39
|
+
if (source === "api") {
|
|
40
|
+
return "primary";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (source === "cli") {
|
|
44
|
+
return "warning";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (source === "mcp") {
|
|
48
|
+
return "muted";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return "success";
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
function renderRunItem(run) {
|
|
55
|
+
const executedBy = String(run.executedBy ?? "user").trim().toLowerCase() || "user";
|
|
56
|
+
|
|
39
57
|
return `
|
|
40
58
|
<div class="border border-outline-variant/10 bg-surface-container px-3 py-3">
|
|
41
59
|
<div class="flex flex-wrap items-center gap-2">
|
|
42
60
|
${renderStatusBadge(run.status, run.status === "error" ? "alert" : "success")}
|
|
61
|
+
${renderStatusBadge(executedBy, getExecutionSourceTone(executedBy))}
|
|
43
62
|
<span class="text-[10px] font-mono uppercase tracking-[0.16em] text-on-surface-variant/55">
|
|
44
63
|
${escapeHtml(formatCompactDateTime(run.executedAt))}
|
|
45
64
|
</span>
|
|
@@ -199,7 +218,7 @@ export function renderQueryHistoryDetail({
|
|
|
199
218
|
"</button>",
|
|
200
219
|
'<button class="delete-button" data-action="open-delete-query-history-modal" data-history-id="',
|
|
201
220
|
escapeHtml(item.id),
|
|
202
|
-
'" type="button">Delete</button></div>',
|
|
221
|
+
'" type="button"><span class="material-symbols-outlined text-sm">delete</span>Delete</button></div>',
|
|
203
222
|
'<div class="mt-6"><div class="text-[10px] font-mono uppercase tracking-[0.16em] text-on-surface-variant/55">SQL</div>',
|
|
204
223
|
'<pre class="query-history-detail-sql custom-scrollbar mt-2 overflow-auto border border-outline-variant/10 bg-surface-container-lowest p-4 font-mono text-sm leading-6 text-on-surface"><code>',
|
|
205
224
|
highlightSql(item.rawSql),
|
|
@@ -34,10 +34,11 @@ export function renderQueryHistorySearch({
|
|
|
34
34
|
placeholder = 'Search SQL, titles, notes...',
|
|
35
35
|
} = {}) {
|
|
36
36
|
return `
|
|
37
|
-
<label class="
|
|
37
|
+
<label class="query-history-search">
|
|
38
38
|
<span class="sr-only">Search query history</span>
|
|
39
|
+
<span class="material-symbols-outlined query-history-search__icon" aria-hidden="true">search</span>
|
|
39
40
|
<input
|
|
40
|
-
class="control-input w-full border border-outline-variant/20 bg-surface-container text-sm text-on-surface outline-none placeholder:text-on-surface-variant/35 focus:border-primary-container"
|
|
41
|
+
class="control-input query-history-search__input w-full border border-outline-variant/20 bg-surface-container text-sm text-on-surface outline-none placeholder:text-on-surface-variant/35 focus:border-primary-container"
|
|
41
42
|
data-bind="${escapeHtml(bind)}"
|
|
42
43
|
placeholder="${escapeHtml(placeholder)}"
|
|
43
44
|
type="search"
|
|
@@ -521,6 +521,7 @@ export function renderRowEditorPanel({
|
|
|
521
521
|
' type="button" ',
|
|
522
522
|
saving || deleting ? "disabled" : "",
|
|
523
523
|
">",
|
|
524
|
+
'<span class="material-symbols-outlined text-sm">delete</span>',
|
|
524
525
|
escapeHtml(deleting ? "Deleting..." : deleteLabel),
|
|
525
526
|
"</button>",
|
|
526
527
|
].join("")
|
|
@@ -19,6 +19,7 @@ const sidebarItems = [
|
|
|
19
19
|
{ label: 'TAGGING_QUEUE', href: '#/media-tagging/queue', key: 'mediaTaggingQueue' },
|
|
20
20
|
],
|
|
21
21
|
},
|
|
22
|
+
{ label: 'Backups', href: '#/backups', key: 'backups', icon: 'inventory_2' },
|
|
22
23
|
{ label: 'Settings', href: '#/settings', key: 'settings', icon: 'settings' },
|
|
23
24
|
];
|
|
24
25
|
|
package/frontend/js/router.js
CHANGED
|
@@ -11,6 +11,8 @@ export function parseHash(hash = window.location.hash) {
|
|
|
11
11
|
switch (segments[0]) {
|
|
12
12
|
case 'connections':
|
|
13
13
|
return { name: 'connections', path: '/connections', params: {} };
|
|
14
|
+
case 'backups':
|
|
15
|
+
return { name: 'backups', path: '/backups', params: {} };
|
|
14
16
|
case 'overview':
|
|
15
17
|
return { name: 'overview', path: '/overview', params: {} };
|
|
16
18
|
case 'charts':
|