sqlite-hub 0.9.13 → 0.11.1

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.
@@ -366,6 +366,15 @@ export function getDataTable(tableName, options = {}) {
366
366
  params.set("sortDirection", String(options.sortDirection));
367
367
  }
368
368
 
369
+ const filterColumn = String(options.filterColumn ?? "").trim();
370
+ const filterValue = String(options.filterValue ?? "");
371
+
372
+ if (filterColumn && filterValue.trim()) {
373
+ params.set("filterColumn", filterColumn);
374
+ params.set("filterOperator", String(options.filterOperator ?? "="));
375
+ params.set("filterValue", filterValue);
376
+ }
377
+
369
378
  const query = params.toString();
370
379
 
371
380
  return request(`/api/data/${encodeURIComponent(tableName)}${query ? `?${query}` : ""}`);
@@ -385,6 +394,13 @@ export function updateDataTableRow(tableName, payload) {
385
394
  });
386
395
  }
387
396
 
397
+ export function previewDataTableRowUpdate(tableName, payload) {
398
+ return request(`/api/data/${encodeURIComponent(tableName)}/rows/preview-update`, {
399
+ method: "POST",
400
+ body: payload,
401
+ });
402
+ }
403
+
388
404
  export function deleteDataTableRow(tableName, payload) {
389
405
  return request(`/api/data/${encodeURIComponent(tableName)}/rows`, {
390
406
  method: "DELETE",
@@ -49,6 +49,8 @@ import {
49
49
  openEditConnectionModal,
50
50
  openCreateQueryChartModal,
51
51
  openEditQueryChartModal,
52
+ openDataRowUpdatePreview,
53
+ openEditorRowUpdatePreview,
52
54
  refreshCurrentRoute,
53
55
  refreshMediaTaggingPreview,
54
56
  removeConnection,
@@ -66,9 +68,12 @@ import {
66
68
  selectStructureEntry,
67
69
  setTableDesignerSearchQuery,
68
70
  setTableDesignerSqlPreviewVisibility,
71
+ setDataTableSearchQuery,
72
+ setStructureTableSearchQuery,
69
73
  toggleStructureTablesPanel,
70
74
  setDataPage,
71
75
  setDataPageSize,
76
+ setDataFilterOperator,
72
77
  setDataSearchColumn,
73
78
  setDataSearchQuery,
74
79
  toggleDataTablesPanel,
@@ -82,6 +87,7 @@ import {
82
87
  submitCreateMediaTaggingTagTable,
83
88
  submitCreateMediaTaggingMappingTable,
84
89
  submitDeleteQueryHistoryConfirmation,
90
+ submitRowUpdatePreviewConfirmation,
85
91
  setQueryHistoryPanelVisibility,
86
92
  sortDataTableByColumn,
87
93
  sortEditorResultsByColumn,
@@ -100,8 +106,6 @@ import {
100
106
  submitCreateConnection,
101
107
  createCurrentMediaTag,
102
108
  submitDeleteRowConfirmation,
103
- submitDataRowUpdate,
104
- submitEditorRowUpdate,
105
109
  submitEditConnection,
106
110
  submitImportSql,
107
111
  submitOpenConnection,
@@ -1771,7 +1775,17 @@ document.addEventListener('input', event => {
1771
1775
  }
1772
1776
 
1773
1777
  if (bindNode.dataset.bind === 'data-search-query') {
1774
- setDataSearchQuery(bindNode.value);
1778
+ void setDataSearchQuery(bindNode.value);
1779
+ return;
1780
+ }
1781
+
1782
+ if (bindNode.dataset.bind === 'data-table-search') {
1783
+ setDataTableSearchQuery(bindNode.value);
1784
+ return;
1785
+ }
1786
+
1787
+ if (bindNode.dataset.bind === 'structure-table-search') {
1788
+ setStructureTableSearchQuery(bindNode.value);
1775
1789
  return;
1776
1790
  }
1777
1791
 
@@ -1870,7 +1884,12 @@ document.addEventListener('change', event => {
1870
1884
  }
1871
1885
 
1872
1886
  if (bindNode.dataset.bind === 'data-search-column') {
1873
- setDataSearchColumn(bindNode.value);
1887
+ void setDataSearchColumn(bindNode.value);
1888
+ return;
1889
+ }
1890
+
1891
+ if (bindNode.dataset.bind === 'data-filter-operator') {
1892
+ void setDataFilterOperator(bindNode.value);
1874
1893
  return;
1875
1894
  }
1876
1895
 
@@ -2055,6 +2074,9 @@ document.addEventListener('submit', async event => {
2055
2074
  case 'delete-query-history-confirm':
2056
2075
  await submitDeleteQueryHistoryConfirmation();
2057
2076
  return;
2077
+ case 'apply-row-update-preview':
2078
+ await submitRowUpdatePreviewConfirmation();
2079
+ return;
2058
2080
  case 'create-media-tagging-tag-table':
2059
2081
  await submitCreateMediaTaggingTagTable();
2060
2082
  return;
@@ -2083,7 +2105,7 @@ document.addEventListener('submit', async event => {
2083
2105
  }
2084
2106
  }
2085
2107
 
2086
- await submitDataRowUpdate(String(formData.get('rowIndex') ?? ''), values, rowIdentity);
2108
+ await openDataRowUpdatePreview(String(formData.get('rowIndex') ?? ''), values, rowIdentity);
2087
2109
  return;
2088
2110
  }
2089
2111
  case 'save-editor-row': {
@@ -2097,7 +2119,7 @@ document.addEventListener('submit', async event => {
2097
2119
  values[key.slice('field:'.length)] = String(value ?? '');
2098
2120
  }
2099
2121
 
2100
- await submitEditorRowUpdate(String(formData.get('rowIndex') ?? ''), values);
2122
+ await openEditorRowUpdatePreview(String(formData.get('rowIndex') ?? ''), values);
2101
2123
  return;
2102
2124
  }
2103
2125
  case 'save-query-history-title': {
@@ -425,6 +425,98 @@ function renderDeleteRowConfirmForm(modal) {
425
425
  ].join("");
426
426
  }
427
427
 
428
+ function renderRowUpdatePreviewForm(modal) {
429
+ const preview = modal.preview ?? {};
430
+ const changes = preview.changes ?? [];
431
+ const params = preview.params ?? [];
432
+ const warnings = preview.warnings ?? [];
433
+ const changesMarkup = changes.length
434
+ ? [
435
+ '<div class="overflow-hidden border border-outline-variant/10">',
436
+ '<table class="w-full text-left text-sm">',
437
+ '<thead class="bg-surface-container-highest text-[10px] font-mono uppercase tracking-[0.16em] text-on-surface-variant/55">',
438
+ '<tr><th class="px-3 py-2">Column</th><th class="px-3 py-2">Old</th><th class="px-3 py-2">New</th></tr>',
439
+ '</thead><tbody class="divide-y divide-outline-variant/10">',
440
+ changes
441
+ .map(
442
+ change => `
443
+ <tr>
444
+ <td class="px-3 py-2 font-mono text-xs text-primary-container">${escapeHtml(change.column)}</td>
445
+ <td class="px-3 py-2 text-on-surface-variant/70">${escapeHtml(change.oldValue)}</td>
446
+ <td class="px-3 py-2 text-on-surface">${escapeHtml(change.newValue)}</td>
447
+ </tr>
448
+ `,
449
+ )
450
+ .join(''),
451
+ '</tbody></table></div>',
452
+ ].join('')
453
+ : '<div class="border border-outline-variant/10 bg-surface-container-low px-4 py-3 text-sm text-on-surface-variant/65">No changed values were detected.</div>';
454
+ const paramsMarkup = params.length
455
+ ? `
456
+ <div class="space-y-2">
457
+ <div class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">Parameters</div>
458
+ <div class="space-y-2">
459
+ ${params
460
+ .map(
461
+ param => `
462
+ <div class="flex gap-3 border border-outline-variant/10 bg-surface-container-low px-3 py-2 text-xs">
463
+ <span class="font-mono text-primary-container">$${escapeHtml(param.index)}</span>
464
+ <span class="min-w-0 break-words text-on-surface">${escapeHtml(param.value)}</span>
465
+ </div>
466
+ `,
467
+ )
468
+ .join('')}
469
+ </div>
470
+ </div>
471
+ `
472
+ : '';
473
+ const warningsMarkup = warnings.length
474
+ ? `
475
+ <div class="space-y-2">
476
+ ${warnings
477
+ .map(
478
+ warning => `
479
+ <div class="border border-primary-container/20 bg-primary-container/10 px-4 py-3 text-sm text-on-surface">
480
+ ${escapeHtml(warning)}
481
+ </div>
482
+ `,
483
+ )
484
+ .join('')}
485
+ </div>
486
+ `
487
+ : '';
488
+
489
+ return `
490
+ <form class="space-y-5" data-form="apply-row-update-preview">
491
+ <div class="space-y-2">
492
+ <div class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">
493
+ ${escapeHtml(modal.tableName ?? 'Table Row')}
494
+ </div>
495
+ <p class="text-sm leading-7 text-on-surface-variant/70">
496
+ Review the SQL and changed values before applying this row update.
497
+ </p>
498
+ </div>
499
+ ${warningsMarkup}
500
+ <div class="space-y-2">
501
+ <div class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">SQL Preview</div>
502
+ ${renderSqlPreviewField(preview.sql ?? '', 'sql-highlight-shell--compact')}
503
+ </div>
504
+ <div class="space-y-2">
505
+ <div class="text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">Changed Values</div>
506
+ ${changesMarkup}
507
+ </div>
508
+ ${paramsMarkup}
509
+ ${renderError(modal.error)}
510
+ <div class="flex items-center justify-end gap-3 pt-2">
511
+ <button class="standard-button" data-action="close-modal" type="button">Cancel</button>
512
+ <button class="signature-button" type="submit">
513
+ ${modal.submitting ? 'Applying...' : 'Apply Changes'}
514
+ </button>
515
+ </div>
516
+ </form>
517
+ `;
518
+ }
519
+
428
520
  function renderChartColumnOptions(analysis, { allowEmpty = false, includeNumericHint = false } = {}) {
429
521
  const options = allowEmpty ? [{ value: "", label: "None" }] : [];
430
522
 
@@ -869,6 +961,11 @@ export function renderModal(state) {
869
961
  title: "Delete Row",
870
962
  body: renderDeleteRowConfirmForm(modal),
871
963
  },
964
+ "row-update-preview": {
965
+ eyebrow: "Mutation // Review row update",
966
+ title: "Review Update",
967
+ body: renderRowUpdatePreviewForm(modal),
968
+ },
872
969
  "chart-editor": {
873
970
  eyebrow: "Charts // Configure query-based ECharts panel",
874
971
  title: modal.draft?.mode === "edit" ? "Edit Chart" : "New Chart",
@@ -904,7 +1001,7 @@ export function renderModal(state) {
904
1001
 
905
1002
  return `
906
1003
  <div class="fixed inset-0 z-50 flex items-center justify-center bg-background/85 px-4 backdrop-blur-sm">
907
- <div class="w-full ${modal.kind === "chart-editor" ? "max-w-3xl" : "max-w-xl"} border border-outline-variant/20 bg-surface-container shadow-[0_24px_80px_rgba(0,0,0,0.45)]">
1004
+ <div class="w-full ${modal.kind === "chart-editor" || modal.kind === "row-update-preview" ? "max-w-3xl" : "max-w-xl"} border border-outline-variant/20 bg-surface-container shadow-[0_24px_80px_rgba(0,0,0,0.45)]">
908
1005
  <div class="flex items-start justify-between gap-4 border-b border-outline-variant/10 bg-surface-container-low px-6 py-5">
909
1006
  <div>
910
1007
  <div class="text-[10px] font-mono uppercase tracking-[0.26em] text-primary-container/70">
@@ -38,7 +38,6 @@ function renderEditorSurface({ query }) {
38
38
 
39
39
  export function renderQueryEditor({
40
40
  query,
41
- title,
42
41
  executing = false,
43
42
  exporting = false,
44
43
  historyLoading = false,
@@ -48,13 +47,7 @@ export function renderQueryEditor({
48
47
  }) {
49
48
  const secondaryButtonClass = "standard-button";
50
49
  const left = `
51
- <div class="flex items-center gap-2 bg-surface-container-lowest px-3 py-1">
52
- <span class="material-symbols-outlined text-xs text-[#FCE300]">database</span>
53
- <span class="text-[10px] font-mono uppercase tracking-widest text-on-surface-variant">${escapeHtml(
54
- title
55
- )}</span>
56
- </div>
57
- <div class="hidden items-center gap-2 text-[10px] font-mono uppercase tracking-widest text-on-surface-variant/40 md:flex">
50
+ <div class="flex items-center gap-2 text-[10px] font-mono uppercase tracking-widest text-on-surface-variant/40">
58
51
  <span class="material-symbols-outlined text-xs">history</span>
59
52
  ${historyLoading ? "Loading history..." : `${historyTotal} queries tracked`}
60
53
  </div>