sqlite-hub 1.0.0 → 1.1.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/README.md +47 -33
- package/bin/sqlite-hub.js +127 -47
- package/frontend/js/api.js +6 -0
- package/frontend/js/app.js +199 -34
- package/frontend/js/components/modal.js +17 -1
- package/frontend/js/components/queryChartRenderer.js +28 -3
- package/frontend/js/components/queryEditor.js +20 -24
- package/frontend/js/components/queryHistoryDetail.js +1 -1
- package/frontend/js/components/queryHistoryHeader.js +48 -0
- package/frontend/js/components/queryHistoryList.js +132 -0
- package/frontend/js/components/queryHistoryPanel.js +72 -136
- package/frontend/js/components/structureGraph.js +699 -89
- package/frontend/js/components/tableDesignerEditor.js +3 -5
- package/frontend/js/store.js +73 -7
- package/frontend/js/utils/exportFilenames.js +3 -1
- package/frontend/js/views/charts.js +320 -169
- package/frontend/js/views/connections.js +59 -64
- package/frontend/js/views/data.js +12 -20
- package/frontend/js/views/editor.js +0 -2
- package/frontend/js/views/settings.js +78 -0
- package/frontend/js/views/structure.js +27 -13
- package/frontend/styles/components.css +155 -0
- package/frontend/styles/structure-graph.css +140 -35
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/views.css +12 -6
- package/package.json +3 -2
- package/server/routes/export.js +89 -22
- package/server/routes/externalApi.js +84 -2
- package/server/routes/settings.js +37 -28
- package/server/services/appInfoService.js +215 -0
- package/server/services/databaseCommandService.js +50 -6
- package/server/services/sqlite/exportService.js +307 -22
- package/tests/api-token-auth.test.js +110 -1
- package/tests/cli-args.test.js +16 -3
- package/tests/database-command-service.test.js +39 -2
- package/tests/export-blob.test.js +54 -1
- package/tests/export-filenames.test.js +4 -0
- package/tests/settings-api-tokens-route.test.js +22 -1
- package/tests/settings-metadata.test.js +99 -1
- package/tests/settings-view.test.js +28 -0
|
@@ -351,11 +351,9 @@ export function renderTableDesignerEditor(state) {
|
|
|
351
351
|
value="${escapeHtml(draft.tableName)}"
|
|
352
352
|
/>
|
|
353
353
|
${
|
|
354
|
-
draft.mode === "
|
|
355
|
-
? `<div class="status-badge status-badge--
|
|
356
|
-
|
|
357
|
-
)}</div>`
|
|
358
|
-
: `<div class="status-badge status-badge--primary">CREATE</div>`
|
|
354
|
+
draft.mode === "create"
|
|
355
|
+
? `<div class="status-badge status-badge--primary">CREATE</div>`
|
|
356
|
+
: ""
|
|
359
357
|
}
|
|
360
358
|
</div>
|
|
361
359
|
<div class="table-designer-main__subtitle">
|
package/frontend/js/store.js
CHANGED
|
@@ -49,6 +49,7 @@ const UI_PREFERENCE_STORAGE_KEYS = {
|
|
|
49
49
|
dataTablesVisible: 'sqlite_hub_data_tables_visible',
|
|
50
50
|
structureTablesVisible: 'sqlite_hub_structure_tables_visible',
|
|
51
51
|
chartsHistoryVisible: 'sqlite_hub_charts_history_visible',
|
|
52
|
+
chartsQueryVisible: 'sqlite_hub_charts_query_visible',
|
|
52
53
|
chartsResultsVisible: 'sqlite_hub_charts_results_visible',
|
|
53
54
|
tableDesignerSqlPreviewVisible: 'sqlite_hub_table_designer_sql_preview_visible',
|
|
54
55
|
documentsEditorVisible: 'sqlite_hub_documents_editor_visible',
|
|
@@ -63,6 +64,8 @@ const TEXT_EXPORT_FORMAT_LABELS = {
|
|
|
63
64
|
csv: 'CSV',
|
|
64
65
|
tsv: 'TSV',
|
|
65
66
|
md: 'Markdown',
|
|
67
|
+
json: 'JSON',
|
|
68
|
+
parquet: 'Parquet',
|
|
66
69
|
};
|
|
67
70
|
const MISSING_DATABASE_ERROR = {
|
|
68
71
|
code: 'ACTIVE_DATABASE_REQUIRED',
|
|
@@ -262,6 +265,9 @@ const state = {
|
|
|
262
265
|
error: null,
|
|
263
266
|
appVersion: null,
|
|
264
267
|
sqliteVersion: null,
|
|
268
|
+
versionCheck: null,
|
|
269
|
+
versionCheckLoading: false,
|
|
270
|
+
versionCheckError: null,
|
|
265
271
|
},
|
|
266
272
|
overview: {
|
|
267
273
|
data: null,
|
|
@@ -331,10 +337,13 @@ const state = {
|
|
|
331
337
|
loading: false,
|
|
332
338
|
error: null,
|
|
333
339
|
historyTab: readStoredChartsHistoryTab(),
|
|
340
|
+
historySearchInput: '',
|
|
341
|
+
historySearch: '',
|
|
334
342
|
historyPanelVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsHistoryVisible, true),
|
|
343
|
+
detailPanelVisible: false,
|
|
335
344
|
selectedHistoryId: null,
|
|
336
345
|
chartHeightPreset: 'medium',
|
|
337
|
-
|
|
346
|
+
queryVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsQueryVisible, true),
|
|
338
347
|
resultsVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true),
|
|
339
348
|
detail: null,
|
|
340
349
|
detailLoading: false,
|
|
@@ -929,10 +938,13 @@ function resetChartsState() {
|
|
|
929
938
|
state.charts.loading = false;
|
|
930
939
|
state.charts.error = null;
|
|
931
940
|
state.charts.historyTab = readStoredChartsHistoryTab(state.charts.historyTab);
|
|
941
|
+
state.charts.historySearchInput = '';
|
|
942
|
+
state.charts.historySearch = '';
|
|
932
943
|
state.charts.historyPanelVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsHistoryVisible, true);
|
|
944
|
+
state.charts.detailPanelVisible = false;
|
|
933
945
|
state.charts.selectedHistoryId = null;
|
|
934
946
|
state.charts.chartHeightPreset = 'medium';
|
|
935
|
-
state.charts.
|
|
947
|
+
state.charts.queryVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsQueryVisible, true);
|
|
936
948
|
state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
|
|
937
949
|
state.charts.detail = null;
|
|
938
950
|
state.charts.detailLoading = false;
|
|
@@ -1019,7 +1031,7 @@ function normalizeChartsHeightPreset(value) {
|
|
|
1019
1031
|
}
|
|
1020
1032
|
|
|
1021
1033
|
function normalizeChartsHistoryTab(value) {
|
|
1022
|
-
return ['recent', 'saved'].includes(value) ? value : 'recent';
|
|
1034
|
+
return ['recent', 'saved', 'unsaved'].includes(value) ? value : 'recent';
|
|
1023
1035
|
}
|
|
1024
1036
|
|
|
1025
1037
|
function mergeQueryHistoryItemWithChartSummary(updatedItem, fallbackItem = null) {
|
|
@@ -1358,6 +1370,33 @@ export function setSettingsSection(section) {
|
|
|
1358
1370
|
emitChange();
|
|
1359
1371
|
}
|
|
1360
1372
|
|
|
1373
|
+
export async function checkSettingsAppVersion() {
|
|
1374
|
+
state.settings.versionCheckLoading = true;
|
|
1375
|
+
state.settings.versionCheckError = null;
|
|
1376
|
+
emitChange();
|
|
1377
|
+
|
|
1378
|
+
try {
|
|
1379
|
+
const response = await api.checkAppVersion();
|
|
1380
|
+
const result = response.data ?? null;
|
|
1381
|
+
|
|
1382
|
+
state.settings.versionCheck = result;
|
|
1383
|
+
pushToast(
|
|
1384
|
+
result?.updateAvailable
|
|
1385
|
+
? `SQLite Hub v${result.latestVersion} is available.`
|
|
1386
|
+
: 'SQLite Hub is up to date.',
|
|
1387
|
+
'success',
|
|
1388
|
+
);
|
|
1389
|
+
return result;
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
state.settings.versionCheckError = normalizeError(error);
|
|
1392
|
+
pushToast('Version check failed.', 'alert');
|
|
1393
|
+
return null;
|
|
1394
|
+
} finally {
|
|
1395
|
+
state.settings.versionCheckLoading = false;
|
|
1396
|
+
emitChange();
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1361
1400
|
export async function deleteSettingsApiToken(tokenId) {
|
|
1362
1401
|
state.settings.tokenSaving = true;
|
|
1363
1402
|
state.settings.error = null;
|
|
@@ -1557,7 +1596,8 @@ async function loadChartsDetail(historyId) {
|
|
|
1557
1596
|
|
|
1558
1597
|
if (!Number.isInteger(numericId) || numericId < 1) {
|
|
1559
1598
|
state.charts.selectedHistoryId = null;
|
|
1560
|
-
state.charts.
|
|
1599
|
+
state.charts.detailPanelVisible = false;
|
|
1600
|
+
state.charts.queryVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsQueryVisible, true);
|
|
1561
1601
|
state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
|
|
1562
1602
|
state.charts.detail = null;
|
|
1563
1603
|
state.charts.detailLoading = false;
|
|
@@ -1570,7 +1610,7 @@ async function loadChartsDetail(historyId) {
|
|
|
1570
1610
|
}
|
|
1571
1611
|
|
|
1572
1612
|
state.charts.selectedHistoryId = numericId;
|
|
1573
|
-
state.charts.
|
|
1613
|
+
state.charts.queryVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsQueryVisible, true);
|
|
1574
1614
|
state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
|
|
1575
1615
|
state.charts.detail = null;
|
|
1576
1616
|
state.charts.detailLoading = true;
|
|
@@ -3448,7 +3488,8 @@ export async function openEditorRowUpdatePreview(rowIndex, values) {
|
|
|
3448
3488
|
}
|
|
3449
3489
|
|
|
3450
3490
|
export function toggleChartsSqlPanel() {
|
|
3451
|
-
state.charts.
|
|
3491
|
+
state.charts.queryVisible = !state.charts.queryVisible;
|
|
3492
|
+
storeBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsQueryVisible, state.charts.queryVisible);
|
|
3452
3493
|
emitChange();
|
|
3453
3494
|
}
|
|
3454
3495
|
|
|
@@ -3470,6 +3511,17 @@ export function setChartsHistoryPanelVisibility(visible) {
|
|
|
3470
3511
|
emitChange();
|
|
3471
3512
|
}
|
|
3472
3513
|
|
|
3514
|
+
export function setChartsDetailPanelVisibility(visible) {
|
|
3515
|
+
const nextValue = typeof visible === 'boolean' ? visible : !Boolean(state.charts.detailPanelVisible);
|
|
3516
|
+
|
|
3517
|
+
if (state.charts.detailPanelVisible === nextValue) {
|
|
3518
|
+
return;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
state.charts.detailPanelVisible = nextValue;
|
|
3522
|
+
emitChange();
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3473
3525
|
export function setChartsHeightPreset(preset) {
|
|
3474
3526
|
const nextPreset = normalizeChartsHeightPreset(preset);
|
|
3475
3527
|
|
|
@@ -3497,6 +3549,18 @@ export function setChartsHistoryTab(tab) {
|
|
|
3497
3549
|
emitChange();
|
|
3498
3550
|
}
|
|
3499
3551
|
|
|
3552
|
+
export function setChartsHistorySearchInput(query) {
|
|
3553
|
+
const nextQuery = String(query ?? '');
|
|
3554
|
+
|
|
3555
|
+
if (state.charts.historySearchInput === nextQuery && state.charts.historySearch === nextQuery.trim()) {
|
|
3556
|
+
return;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
state.charts.historySearchInput = nextQuery;
|
|
3560
|
+
state.charts.historySearch = nextQuery.trim();
|
|
3561
|
+
emitChange();
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3500
3564
|
export function updateCurrentQueryChartDraftField(field, value) {
|
|
3501
3565
|
if (state.modal?.kind !== 'chart-editor' || !state.modal.draft) {
|
|
3502
3566
|
return;
|
|
@@ -3935,7 +3999,9 @@ export function openQueryHistoryInEditor(historyId, options = {}) {
|
|
|
3935
3999
|
clearQueryHistoryDetailState();
|
|
3936
4000
|
state.editor.sqlText = options.append ? [state.editor.sqlText.trim(), rawSql].filter(Boolean).join('\n\n') : rawSql;
|
|
3937
4001
|
storeString(UI_PREFERENCE_STORAGE_KEYS.sqlEditorQueryDraft, state.editor.sqlText);
|
|
3938
|
-
|
|
4002
|
+
if (options.notify !== false) {
|
|
4003
|
+
emitChange();
|
|
4004
|
+
}
|
|
3939
4005
|
return true;
|
|
3940
4006
|
}
|
|
3941
4007
|
|
|
@@ -2,6 +2,8 @@ export const TEXT_EXPORT_EXTENSIONS = {
|
|
|
2
2
|
csv: "csv",
|
|
3
3
|
tsv: "tsv",
|
|
4
4
|
md: "md",
|
|
5
|
+
json: "json",
|
|
6
|
+
parquet: "parquet",
|
|
5
7
|
};
|
|
6
8
|
|
|
7
9
|
export function normalizeTextExportFormat(format = "csv") {
|
|
@@ -10,7 +12,7 @@ export function normalizeTextExportFormat(format = "csv") {
|
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
function stripKnownTextExportExtension(value = "") {
|
|
13
|
-
return String(value).replace(/\.(csv|tsv|md)$/i, "");
|
|
15
|
+
return String(value).replace(/\.(csv|tsv|md|json|parquet)$/i, "");
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function sanitizeExportFilenameBase(value, fallback = "export") {
|