sqlite-hub 0.9.12 → 0.10.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.
@@ -34,9 +34,21 @@ const DATA_PAGE_SIZES = [25, 50, 100];
34
34
  const DATA_ROW_SIZE_STORAGE_KEY = 'data_row_size';
35
35
  const CHARTS_HISTORY_TAB_STORAGE_KEY = 'charts_history_tab';
36
36
  const QUERY_HISTORY_TAB_STORAGE_KEY = 'query_history_tab';
37
+ const UI_PREFERENCE_STORAGE_KEYS = {
38
+ sqlEditorHistoryVisible: 'sqlite_hub_sql_editor_history_visible',
39
+ sqlEditorEditorVisible: 'sqlite_hub_sql_editor_editor_visible',
40
+ sqlEditorActiveTab: 'sqlite_hub_sql_editor_active_tab',
41
+ sqlEditorQueryDraft: 'sqlite_hub_sql_editor_query_draft',
42
+ dataTablesVisible: 'sqlite_hub_data_tables_visible',
43
+ structureTablesVisible: 'sqlite_hub_structure_tables_visible',
44
+ chartsHistoryVisible: 'sqlite_hub_charts_history_visible',
45
+ chartsResultsVisible: 'sqlite_hub_charts_results_visible',
46
+ tableDesignerSqlPreviewVisible: 'sqlite_hub_table_designer_sql_preview_visible',
47
+ };
37
48
  const QUERY_HISTORY_PAGE_SIZE = 30;
38
49
  const QUERY_HISTORY_RUN_LIMIT = 8;
39
50
  const CHART_HEIGHT_PRESETS = new Set(['small', 'medium', 'large']);
51
+ const EDITOR_RESULT_TABS = new Set(['results', 'performance', 'messages']);
40
52
  const MISSING_DATABASE_ERROR = {
41
53
  code: 'ACTIVE_DATABASE_REQUIRED',
42
54
  message: 'No active SQLite database selected.',
@@ -66,6 +78,70 @@ function storeDataPageSize(pageSize) {
66
78
  }
67
79
  }
68
80
 
81
+ function readStoredBoolean(key, fallback) {
82
+ try {
83
+ const value = globalThis.localStorage?.getItem(key);
84
+
85
+ if (value === 'true') {
86
+ return true;
87
+ }
88
+
89
+ if (value === 'false') {
90
+ return false;
91
+ }
92
+
93
+ return fallback;
94
+ } catch {
95
+ return fallback;
96
+ }
97
+ }
98
+
99
+ function storeBoolean(key, value) {
100
+ try {
101
+ globalThis.localStorage?.setItem(key, String(Boolean(value)));
102
+ } catch {
103
+ // Ignore unavailable browser storage; the in-memory setting still applies.
104
+ }
105
+ }
106
+
107
+ function readStoredString(key, fallback = '') {
108
+ try {
109
+ const value = globalThis.localStorage?.getItem(key);
110
+ return value === null || value === undefined ? fallback : value;
111
+ } catch {
112
+ return fallback;
113
+ }
114
+ }
115
+
116
+ function storeString(key, value) {
117
+ try {
118
+ globalThis.localStorage?.setItem(key, String(value ?? ''));
119
+ } catch {
120
+ // Ignore unavailable browser storage; the in-memory value still applies.
121
+ }
122
+ }
123
+
124
+ function readStoredEditorActiveTab(fallback = 'messages') {
125
+ try {
126
+ const value = globalThis.localStorage?.getItem(UI_PREFERENCE_STORAGE_KEYS.sqlEditorActiveTab);
127
+ return EDITOR_RESULT_TABS.has(value) ? value : fallback;
128
+ } catch {
129
+ return fallback;
130
+ }
131
+ }
132
+
133
+ function storeEditorActiveTab(tab) {
134
+ if (!EDITOR_RESULT_TABS.has(tab)) {
135
+ return;
136
+ }
137
+
138
+ try {
139
+ globalThis.localStorage?.setItem(UI_PREFERENCE_STORAGE_KEYS.sqlEditorActiveTab, tab);
140
+ } catch {
141
+ // Ignore unavailable browser storage; the in-memory setting still applies.
142
+ }
143
+ }
144
+
69
145
  function readStoredChartsHistoryTab(fallback = 'recent') {
70
146
  try {
71
147
  return normalizeChartsHistoryTab(globalThis.localStorage?.getItem(CHARTS_HISTORY_TAB_STORAGE_KEY) ?? fallback);
@@ -124,7 +200,7 @@ const state = {
124
200
  dataBrowser: {
125
201
  tables: [],
126
202
  selectedTable: null,
127
- tablesVisible: true,
203
+ tablesVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.dataTablesVisible, true),
128
204
  table: null,
129
205
  loading: false,
130
206
  tableLoading: false,
@@ -135,6 +211,7 @@ const state = {
135
211
  sortColumn: null,
136
212
  sortDirection: null,
137
213
  searchQuery: '',
214
+ tableSearchQuery: '',
138
215
  searchColumn: '',
139
216
  selectedRowIndex: null,
140
217
  selectedRow: null,
@@ -144,10 +221,10 @@ const state = {
144
221
  saveError: null,
145
222
  },
146
223
  editor: {
147
- sqlText: '',
148
- editorPanelVisible: true,
224
+ sqlText: readStoredString(UI_PREFERENCE_STORAGE_KEYS.sqlEditorQueryDraft),
225
+ editorPanelVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.sqlEditorEditorVisible, true),
149
226
  history: [],
150
- historyPanelVisible: true,
227
+ historyPanelVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.sqlEditorHistoryVisible, true),
151
228
  historyLoading: false,
152
229
  historyLoadingMore: false,
153
230
  historyError: null,
@@ -163,9 +240,10 @@ const state = {
163
240
  historyRuns: [],
164
241
  historyDetailLoading: false,
165
242
  historyDetailError: null,
166
- activeTab: 'messages',
243
+ activeTab: readStoredEditorActiveTab(),
167
244
  executing: false,
168
245
  result: null,
246
+ lastExecutedSql: '',
169
247
  resultSortColumn: null,
170
248
  resultSortDirection: null,
171
249
  error: null,
@@ -181,10 +259,11 @@ const state = {
181
259
  loading: false,
182
260
  error: null,
183
261
  historyTab: readStoredChartsHistoryTab(),
262
+ historyPanelVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsHistoryVisible, true),
184
263
  selectedHistoryId: null,
185
264
  chartHeightPreset: 'medium',
186
265
  sqlExpanded: false,
187
- resultsVisible: true,
266
+ resultsVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true),
188
267
  detail: null,
189
268
  detailLoading: false,
190
269
  detailError: null,
@@ -196,7 +275,7 @@ const state = {
196
275
  tables: [],
197
276
  selectedTableName: null,
198
277
  draft: null,
199
- sqlPreviewVisible: true,
278
+ sqlPreviewVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.tableDesignerSqlPreviewVisible, true),
200
279
  pendingImportedDraft: null,
201
280
  loading: false,
202
281
  detailLoading: false,
@@ -210,7 +289,8 @@ const state = {
210
289
  data: null,
211
290
  selectedName: null,
212
291
  detail: null,
213
- tablesVisible: true,
292
+ tablesVisible: readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.structureTablesVisible, true),
293
+ tableSearchQuery: '',
214
294
  loading: false,
215
295
  detailLoading: false,
216
296
  error: null,
@@ -467,6 +547,10 @@ function resetDataBrowserSearch() {
467
547
  state.dataBrowser.searchColumn = '';
468
548
  }
469
549
 
550
+ function resetDataBrowserTableSearch() {
551
+ state.dataBrowser.tableSearchQuery = '';
552
+ }
553
+
470
554
  function resetDataBrowserSort() {
471
555
  state.dataBrowser.sortColumn = null;
472
556
  state.dataBrowser.sortDirection = null;
@@ -647,7 +731,11 @@ function clearDataBrowserRowSelectionState() {
647
731
  }
648
732
 
649
733
  function resolveDataBrowserRowSelection(rowIndex, identity = null) {
650
- const numericIndex = Number(rowIndex);
734
+ const hasRowIndex =
735
+ rowIndex !== null &&
736
+ rowIndex !== undefined &&
737
+ (typeof rowIndex !== 'string' || rowIndex.trim() !== '');
738
+ const numericIndex = hasRowIndex ? Number(rowIndex) : NaN;
651
739
 
652
740
  if (Number.isInteger(numericIndex) && numericIndex >= 0) {
653
741
  const indexedRow = state.dataBrowser.table?.rows?.[numericIndex] ?? null;
@@ -735,10 +823,11 @@ function resetChartsState() {
735
823
  state.charts.loading = false;
736
824
  state.charts.error = null;
737
825
  state.charts.historyTab = readStoredChartsHistoryTab(state.charts.historyTab);
826
+ state.charts.historyPanelVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsHistoryVisible, true);
738
827
  state.charts.selectedHistoryId = null;
739
828
  state.charts.chartHeightPreset = 'medium';
740
829
  state.charts.sqlExpanded = false;
741
- state.charts.resultsVisible = true;
830
+ state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
742
831
  state.charts.detail = null;
743
832
  state.charts.detailLoading = false;
744
833
  state.charts.detailError = null;
@@ -890,6 +979,7 @@ function setMissingDatabaseState() {
890
979
  state.dataBrowser.selectedTable = null;
891
980
  state.dataBrowser.table = null;
892
981
  state.dataBrowser.page = 1;
982
+ resetDataBrowserTableSearch();
893
983
  resetDataBrowserSort();
894
984
  resetDataBrowserSearch();
895
985
  clearDataBrowserRowSelectionState();
@@ -902,7 +992,8 @@ function setMissingDatabaseState() {
902
992
  state.structure.detailLoading = false;
903
993
  state.structure.data = null;
904
994
  state.structure.detail = null;
905
- state.structure.tablesVisible = true;
995
+ state.structure.tablesVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.structureTablesVisible, true);
996
+ state.structure.tableSearchQuery = '';
906
997
  state.structure.error = error;
907
998
 
908
999
  state.tableDesigner.loading = false;
@@ -910,7 +1001,7 @@ function setMissingDatabaseState() {
910
1001
  state.tableDesigner.tables = [];
911
1002
  state.tableDesigner.selectedTableName = null;
912
1003
  state.tableDesigner.draft = null;
913
- state.tableDesigner.sqlPreviewVisible = true;
1004
+ state.tableDesigner.sqlPreviewVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.tableDesignerSqlPreviewVisible, true);
914
1005
  state.tableDesigner.pendingImportedDraft = null;
915
1006
  state.tableDesigner.saving = false;
916
1007
  state.tableDesigner.searchQuery = '';
@@ -964,9 +1055,8 @@ function syncRouteContext() {
964
1055
 
965
1056
  if (route.name === 'editorResults') {
966
1057
  state.editor.activeTab = 'results';
1058
+ storeEditorActiveTab('results');
967
1059
  clearQueryHistoryDetailState();
968
- } else if (route.name === 'editor' && state.editor.activeTab === 'results') {
969
- state.editor.activeTab = 'messages';
970
1060
  }
971
1061
 
972
1062
  if (route.name !== 'editorResults') {
@@ -1184,7 +1274,7 @@ async function loadChartsDetail(historyId) {
1184
1274
  if (!Number.isInteger(numericId) || numericId < 1) {
1185
1275
  state.charts.selectedHistoryId = null;
1186
1276
  state.charts.sqlExpanded = false;
1187
- state.charts.resultsVisible = true;
1277
+ state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
1188
1278
  state.charts.detail = null;
1189
1279
  state.charts.detailLoading = false;
1190
1280
  state.charts.detailError = null;
@@ -1197,7 +1287,7 @@ async function loadChartsDetail(historyId) {
1197
1287
 
1198
1288
  state.charts.selectedHistoryId = numericId;
1199
1289
  state.charts.sqlExpanded = false;
1200
- state.charts.resultsVisible = true;
1290
+ state.charts.resultsVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, true);
1201
1291
  state.charts.detail = null;
1202
1292
  state.charts.detailLoading = true;
1203
1293
  state.charts.detailError = null;
@@ -1859,6 +1949,7 @@ function invalidateDatabaseCaches() {
1859
1949
  state.dataBrowser.selectedTable = null;
1860
1950
  state.dataBrowser.table = null;
1861
1951
  state.dataBrowser.page = 1;
1952
+ resetDataBrowserTableSearch();
1862
1953
  resetDataBrowserSearch();
1863
1954
  clearDataBrowserRowSelectionState();
1864
1955
  state.dataBrowser.pendingOpenRow = null;
@@ -1868,7 +1959,7 @@ function invalidateDatabaseCaches() {
1868
1959
  state.tableDesigner.tables = [];
1869
1960
  state.tableDesigner.selectedTableName = null;
1870
1961
  state.tableDesigner.draft = null;
1871
- state.tableDesigner.sqlPreviewVisible = true;
1962
+ state.tableDesigner.sqlPreviewVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.tableDesignerSqlPreviewVisible, true);
1872
1963
  state.tableDesigner.pendingImportedDraft = null;
1873
1964
  state.tableDesigner.saving = false;
1874
1965
  state.tableDesigner.searchQuery = '';
@@ -1878,7 +1969,8 @@ function invalidateDatabaseCaches() {
1878
1969
  resetChartsState();
1879
1970
  state.structure.data = null;
1880
1971
  state.structure.detail = null;
1881
- state.structure.tablesVisible = true;
1972
+ state.structure.tablesVisible = readStoredBoolean(UI_PREFERENCE_STORAGE_KEYS.structureTablesVisible, true);
1973
+ state.structure.tableSearchQuery = '';
1882
1974
  state.mediaTagging.loading = false;
1883
1975
  state.mediaTagging.previewLoading = false;
1884
1976
  state.mediaTagging.saving = false;
@@ -2296,6 +2388,92 @@ export function closeModal() {
2296
2388
  closeModalInternal();
2297
2389
  }
2298
2390
 
2391
+ export async function openDataRowUpdatePreview(rowIndex, values, identity = null) {
2392
+ const tableName = state.dataBrowser.selectedTable;
2393
+ const selected = resolveDataBrowserRowSelection(rowIndex, identity);
2394
+
2395
+ if (!tableName || !selected.identity) {
2396
+ pushToast('The selected row could not be loaded.', 'alert');
2397
+ return null;
2398
+ }
2399
+
2400
+ state.dataBrowser.saving = true;
2401
+ state.dataBrowser.saveError = null;
2402
+ emitChange();
2403
+
2404
+ try {
2405
+ const response = await api.previewDataTableRowUpdate(tableName, {
2406
+ identity: selected.identity,
2407
+ values,
2408
+ });
2409
+
2410
+ state.modal = {
2411
+ kind: 'row-update-preview',
2412
+ target: 'data',
2413
+ tableName,
2414
+ rowIndex: selected.rowIndex,
2415
+ identity: selected.identity,
2416
+ values,
2417
+ preview: response.data,
2418
+ error: null,
2419
+ submitting: false,
2420
+ };
2421
+ emitChange();
2422
+ return response.data;
2423
+ } catch (error) {
2424
+ state.dataBrowser.saveError = normalizeError(error);
2425
+ emitChange();
2426
+ return null;
2427
+ } finally {
2428
+ state.dataBrowser.saving = false;
2429
+ emitChange();
2430
+ }
2431
+ }
2432
+
2433
+ export async function openEditorRowUpdatePreview(rowIndex, values) {
2434
+ const numericIndex = Number(rowIndex);
2435
+ const result = state.editor.result;
2436
+ const row = result?.rows?.[numericIndex];
2437
+ const tableName = result?.editing?.tableName ?? null;
2438
+
2439
+ if (!tableName || !row || !canEditQueryResult()) {
2440
+ pushToast('The selected query result row could not be loaded.', 'alert');
2441
+ return null;
2442
+ }
2443
+
2444
+ state.editor.saving = true;
2445
+ state.editor.saveError = null;
2446
+ emitChange();
2447
+
2448
+ try {
2449
+ const response = await api.previewDataTableRowUpdate(tableName, {
2450
+ identity: row.__identity,
2451
+ values,
2452
+ });
2453
+
2454
+ state.modal = {
2455
+ kind: 'row-update-preview',
2456
+ target: 'editor',
2457
+ tableName,
2458
+ rowIndex: numericIndex,
2459
+ identity: row.__identity,
2460
+ values,
2461
+ preview: response.data,
2462
+ error: null,
2463
+ submitting: false,
2464
+ };
2465
+ emitChange();
2466
+ return response.data;
2467
+ } catch (error) {
2468
+ state.editor.saveError = normalizeError(error);
2469
+ emitChange();
2470
+ return null;
2471
+ } finally {
2472
+ state.editor.saving = false;
2473
+ emitChange();
2474
+ }
2475
+ }
2476
+
2299
2477
  export function toggleChartsSqlPanel() {
2300
2478
  state.charts.sqlExpanded = !state.charts.sqlExpanded;
2301
2479
  emitChange();
@@ -2303,6 +2481,19 @@ export function toggleChartsSqlPanel() {
2303
2481
 
2304
2482
  export function toggleChartsResultsPanel() {
2305
2483
  state.charts.resultsVisible = !state.charts.resultsVisible;
2484
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsResultsVisible, state.charts.resultsVisible);
2485
+ emitChange();
2486
+ }
2487
+
2488
+ export function setChartsHistoryPanelVisibility(visible) {
2489
+ const nextValue = typeof visible === 'boolean' ? visible : !Boolean(state.charts.historyPanelVisible);
2490
+
2491
+ if (state.charts.historyPanelVisible === nextValue) {
2492
+ return;
2493
+ }
2494
+
2495
+ state.charts.historyPanelVisible = nextValue;
2496
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.chartsHistoryVisible, nextValue);
2306
2497
  emitChange();
2307
2498
  }
2308
2499
 
@@ -2550,6 +2741,7 @@ export function setCurrentQuery(query) {
2550
2741
  const nextLineCount = Math.max(1, nextQuery.split('\n').length);
2551
2742
 
2552
2743
  state.editor.sqlText = nextQuery;
2744
+ storeString(UI_PREFERENCE_STORAGE_KEYS.sqlEditorQueryDraft, nextQuery);
2553
2745
 
2554
2746
  if (previousLineCount !== nextLineCount) {
2555
2747
  emitChange();
@@ -2558,7 +2750,9 @@ export function setCurrentQuery(query) {
2558
2750
 
2559
2751
  export function clearCurrentQuery() {
2560
2752
  state.editor.sqlText = '';
2753
+ storeString(UI_PREFERENCE_STORAGE_KEYS.sqlEditorQueryDraft, '');
2561
2754
  state.editor.result = null;
2755
+ state.editor.lastExecutedSql = '';
2562
2756
  resetEditorResultSort();
2563
2757
  state.editor.error = null;
2564
2758
  clearQueryHistoryDetailState();
@@ -2566,22 +2760,17 @@ export function clearCurrentQuery() {
2566
2760
  state.editor.saving = false;
2567
2761
  state.editor.deleting = false;
2568
2762
  state.editor.saveError = null;
2569
- if (state.editor.activeTab === 'results' || state.editor.activeTab === 'performance') {
2570
- state.editor.activeTab = 'messages';
2571
- }
2572
2763
  emitChange();
2573
2764
  }
2574
2765
 
2575
2766
  export function clearEditorResults() {
2576
2767
  state.editor.result = null;
2768
+ state.editor.lastExecutedSql = '';
2577
2769
  resetEditorResultSort();
2578
2770
  state.editor.error = null;
2579
2771
  state.editor.selectedRowIndex = null;
2580
2772
  state.editor.saving = false;
2581
2773
  state.editor.saveError = null;
2582
- if (state.editor.activeTab === 'results') {
2583
- state.editor.activeTab = 'messages';
2584
- }
2585
2774
  emitChange();
2586
2775
  }
2587
2776
 
@@ -2593,16 +2782,23 @@ export function setEditorPanelVisibility(visible) {
2593
2782
  }
2594
2783
 
2595
2784
  state.editor.editorPanelVisible = nextValue;
2785
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.sqlEditorEditorVisible, nextValue);
2596
2786
  emitChange();
2597
2787
  }
2598
2788
 
2599
2789
  export function setEditorTab(tab) {
2790
+ if (!EDITOR_RESULT_TABS.has(tab)) {
2791
+ return;
2792
+ }
2793
+
2600
2794
  state.editor.activeTab = tab;
2795
+ storeEditorActiveTab(tab);
2601
2796
  emitChange();
2602
2797
  }
2603
2798
 
2604
2799
  export async function executeCurrentQuery() {
2605
2800
  state.editor.executing = true;
2801
+ state.editor.lastExecutedSql = state.editor.sqlText;
2606
2802
  state.editor.error = null;
2607
2803
  state.editor.selectedRowIndex = null;
2608
2804
  state.editor.saving = false;
@@ -2614,7 +2810,6 @@ export async function executeCurrentQuery() {
2614
2810
  state.editor.result = response.data;
2615
2811
  resetEditorResultSort();
2616
2812
  state.editor.error = null;
2617
- state.editor.activeTab = 'results';
2618
2813
  invalidateDatabaseCaches();
2619
2814
  await refreshQueryHistoryState();
2620
2815
  pushToast(response.message || `Executed ${response.data.statementCount} SQL statement(s).`, 'success');
@@ -2622,6 +2817,7 @@ export async function executeCurrentQuery() {
2622
2817
  } catch (error) {
2623
2818
  state.editor.error = normalizeError(error);
2624
2819
  state.editor.activeTab = 'messages';
2820
+ storeEditorActiveTab('messages');
2625
2821
  await refreshQueryHistoryState();
2626
2822
  return false;
2627
2823
  } finally {
@@ -2676,6 +2872,7 @@ export function setQueryHistoryPanelVisibility(visible) {
2676
2872
  }
2677
2873
 
2678
2874
  state.editor.historyPanelVisible = nextValue;
2875
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.sqlEditorHistoryVisible, nextValue);
2679
2876
  emitChange();
2680
2877
  }
2681
2878
 
@@ -2744,6 +2941,7 @@ export function openQueryHistoryInEditor(historyId, options = {}) {
2744
2941
  setActiveQueryHistoryItem(historyId);
2745
2942
  clearQueryHistoryDetailState();
2746
2943
  state.editor.sqlText = options.append ? [state.editor.sqlText.trim(), rawSql].filter(Boolean).join('\n\n') : rawSql;
2944
+ storeString(UI_PREFERENCE_STORAGE_KEYS.sqlEditorQueryDraft, state.editor.sqlText);
2747
2945
  emitChange();
2748
2946
  return true;
2749
2947
  }
@@ -2842,6 +3040,7 @@ export async function selectStructureEntry(name) {
2842
3040
 
2843
3041
  export function toggleStructureTablesPanel() {
2844
3042
  state.structure.tablesVisible = state.structure.tablesVisible === false;
3043
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.structureTablesVisible, state.structure.tablesVisible);
2845
3044
  emitChange();
2846
3045
  }
2847
3046
 
@@ -2850,6 +3049,16 @@ export function setTableDesignerSearchQuery(query) {
2850
3049
  emitChange();
2851
3050
  }
2852
3051
 
3052
+ export function setDataTableSearchQuery(query) {
3053
+ state.dataBrowser.tableSearchQuery = String(query ?? '');
3054
+ emitChange();
3055
+ }
3056
+
3057
+ export function setStructureTableSearchQuery(query) {
3058
+ state.structure.tableSearchQuery = String(query ?? '');
3059
+ emitChange();
3060
+ }
3061
+
2853
3062
  export function setTableDesignerSqlPreviewVisibility(visible) {
2854
3063
  const nextValue = typeof visible === 'boolean' ? visible : !Boolean(state.tableDesigner.sqlPreviewVisible);
2855
3064
 
@@ -2858,6 +3067,7 @@ export function setTableDesignerSqlPreviewVisibility(visible) {
2858
3067
  }
2859
3068
 
2860
3069
  state.tableDesigner.sqlPreviewVisible = nextValue;
3070
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.tableDesignerSqlPreviewVisible, nextValue);
2861
3071
  emitChange();
2862
3072
  }
2863
3073
 
@@ -3433,6 +3643,7 @@ export function setDataSearchColumn(columnName) {
3433
3643
 
3434
3644
  export function toggleDataTablesPanel() {
3435
3645
  state.dataBrowser.tablesVisible = state.dataBrowser.tablesVisible === false;
3646
+ storeBoolean(UI_PREFERENCE_STORAGE_KEYS.dataTablesVisible, state.dataBrowser.tablesVisible);
3436
3647
  emitChange();
3437
3648
  }
3438
3649
 
@@ -3499,9 +3710,10 @@ export async function setDataPageSize(pageSize) {
3499
3710
  }
3500
3711
  }
3501
3712
 
3502
- export async function submitDataRowUpdate(rowIndex, values, identity = null) {
3713
+ export async function submitDataRowUpdate(rowIndex, values, identity = null, options = {}) {
3503
3714
  const tableName = state.dataBrowser.selectedTable;
3504
3715
  const selected = resolveDataBrowserRowSelection(rowIndex, identity);
3716
+ const reportErrorToModal = Boolean(options.reportErrorToModal);
3505
3717
 
3506
3718
  if (!tableName || !selected.identity) {
3507
3719
  pushToast('The selected row could not be loaded.', 'alert');
@@ -3523,8 +3735,12 @@ export async function submitDataRowUpdate(rowIndex, values, identity = null) {
3523
3735
  clearDataBrowserRowSelectionState();
3524
3736
  return response.data;
3525
3737
  } catch (error) {
3526
- state.dataBrowser.saveError = normalizeError(error);
3527
- emitChange();
3738
+ if (reportErrorToModal) {
3739
+ withModalError(error);
3740
+ } else {
3741
+ state.dataBrowser.saveError = normalizeError(error);
3742
+ emitChange();
3743
+ }
3528
3744
  return null;
3529
3745
  } finally {
3530
3746
  state.dataBrowser.saving = false;
@@ -3576,11 +3792,12 @@ export async function submitDataRowDelete(rowIndex, options = {}) {
3576
3792
  }
3577
3793
  }
3578
3794
 
3579
- export async function submitEditorRowUpdate(rowIndex, values) {
3795
+ export async function submitEditorRowUpdate(rowIndex, values, options = {}) {
3580
3796
  const numericIndex = Number(rowIndex);
3581
3797
  const result = state.editor.result;
3582
3798
  const row = result?.rows?.[numericIndex];
3583
3799
  const tableName = result?.editing?.tableName ?? null;
3800
+ const reportErrorToModal = Boolean(options.reportErrorToModal);
3584
3801
 
3585
3802
  if (!tableName || !row || !canEditQueryResult()) {
3586
3803
  pushToast('The selected query result row could not be loaded.', 'alert');
@@ -3610,8 +3827,12 @@ export async function submitEditorRowUpdate(rowIndex, values) {
3610
3827
  emitChange();
3611
3828
  return response.data;
3612
3829
  } catch (error) {
3613
- state.editor.saveError = normalizeError(error);
3614
- emitChange();
3830
+ if (reportErrorToModal) {
3831
+ withModalError(error);
3832
+ } else {
3833
+ state.editor.saveError = normalizeError(error);
3834
+ emitChange();
3835
+ }
3615
3836
  return null;
3616
3837
  } finally {
3617
3838
  state.editor.saving = false;
@@ -3689,6 +3910,29 @@ export async function submitDeleteRowConfirmation() {
3689
3910
  return result;
3690
3911
  }
3691
3912
 
3913
+ export async function submitRowUpdatePreviewConfirmation() {
3914
+ const modal = state.modal;
3915
+
3916
+ if (modal?.kind !== 'row-update-preview') {
3917
+ return null;
3918
+ }
3919
+
3920
+ startModalSubmission();
3921
+
3922
+ const result =
3923
+ modal.target === 'editor'
3924
+ ? await submitEditorRowUpdate(modal.rowIndex, modal.values, { reportErrorToModal: true })
3925
+ : await submitDataRowUpdate(modal.rowIndex, modal.values, modal.identity, {
3926
+ reportErrorToModal: true,
3927
+ });
3928
+
3929
+ if (result) {
3930
+ closeModalInternal();
3931
+ }
3932
+
3933
+ return result;
3934
+ }
3935
+
3692
3936
  export async function saveCurrentQueryChartDraft() {
3693
3937
  if (state.modal?.kind !== 'chart-editor' || !state.modal.draft) {
3694
3938
  return null;
@@ -3896,6 +4140,18 @@ export function getCurrentConnection(snapshot = state) {
3896
4140
  }
3897
4141
 
3898
4142
  export function getQueryMessages(snapshot = state) {
4143
+ const queryText = snapshot.editor.result?.sql ?? (snapshot.editor.error ? snapshot.editor.lastExecutedSql : '');
4144
+ const queryMessages = queryText
4145
+ ? [
4146
+ {
4147
+ tone: 'muted',
4148
+ label: 'QUERY',
4149
+ value: queryText,
4150
+ kind: 'query',
4151
+ },
4152
+ ]
4153
+ : [];
4154
+
3899
4155
  if (snapshot.editor.error) {
3900
4156
  return [
3901
4157
  {
@@ -3903,6 +4159,7 @@ export function getQueryMessages(snapshot = state) {
3903
4159
  label: snapshot.editor.error.code,
3904
4160
  value: snapshot.editor.error.message,
3905
4161
  },
4162
+ ...queryMessages,
3906
4163
  ];
3907
4164
  }
3908
4165
 
@@ -3916,14 +4173,17 @@ export function getQueryMessages(snapshot = state) {
3916
4173
  ];
3917
4174
  }
3918
4175
 
3919
- return snapshot.editor.result.statements.map(statement => ({
3920
- tone: statement.kind === 'resultSet' ? 'success' : inferStatusTone(statement.keyword),
3921
- label: `${statement.keyword} #${statement.index + 1}`,
3922
- value:
3923
- statement.kind === 'resultSet'
3924
- ? `${statement.rowCount} row(s) returned.`
3925
- : `${statement.changes} row(s) affected.`,
3926
- }));
4176
+ return [
4177
+ ...snapshot.editor.result.statements.map(statement => ({
4178
+ tone: statement.kind === 'resultSet' ? 'success' : inferStatusTone(statement.keyword),
4179
+ label: `${statement.keyword} #${statement.index + 1}`,
4180
+ value:
4181
+ statement.kind === 'resultSet'
4182
+ ? `${statement.rowCount} row(s) returned.`
4183
+ : `${statement.changes} row(s) affected.`,
4184
+ })),
4185
+ ...queryMessages,
4186
+ ];
3927
4187
  }
3928
4188
 
3929
4189
  export function getQueryPerformance(snapshot = state) {
@@ -402,7 +402,7 @@ function renderChartCard(chart, state, analysis) {
402
402
  export function renderChartsDetail(state) {
403
403
  const detail = state.charts.detail;
404
404
  const selectedHistoryId = state.charts.selectedHistoryId;
405
- const historyVisible = state.editor.historyPanelVisible !== false;
405
+ const historyVisible = state.charts.historyPanelVisible !== false;
406
406
 
407
407
  if (!selectedHistoryId) {
408
408
  return renderEmptyChartDetail();
@@ -514,7 +514,7 @@ export function renderChartsDetail(state) {
514
514
  }
515
515
 
516
516
  export function renderChartsView(state) {
517
- const historyVisible = state.editor.historyPanelVisible !== false || !state.charts.selectedHistoryId;
517
+ const historyVisible = state.charts.historyPanelVisible !== false || !state.charts.selectedHistoryId;
518
518
 
519
519
  if (!state.connections.active && state.charts.error?.code === 'ACTIVE_DATABASE_REQUIRED') {
520
520
  return {