sqlite-hub 1.1.0 → 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.
Files changed (58) hide show
  1. package/README.md +17 -196
  2. package/bin/sqlite-hub.js +7 -2
  3. package/frontend/js/api.js +60 -0
  4. package/frontend/js/app.js +140 -10
  5. package/frontend/js/components/dropdownButton.js +92 -0
  6. package/frontend/js/components/modal.js +991 -876
  7. package/frontend/js/components/queryEditor.js +29 -18
  8. package/frontend/js/components/queryHistoryDetail.js +20 -1
  9. package/frontend/js/components/queryHistoryHeader.js +3 -2
  10. package/frontend/js/components/rowEditorPanel.js +1 -0
  11. package/frontend/js/components/sidebar.js +1 -0
  12. package/frontend/js/components/structureGraph.js +1 -0
  13. package/frontend/js/components/tableDesignerEditor.js +23 -42
  14. package/frontend/js/components/tableDesignerSidebar.js +7 -31
  15. package/frontend/js/components/tableDesignerSqlPreview.js +2 -1
  16. package/frontend/js/router.js +2 -0
  17. package/frontend/js/store.js +407 -38
  18. package/frontend/js/utils/riskySql.js +165 -0
  19. package/frontend/js/views/backups.js +176 -0
  20. package/frontend/js/views/charts.js +12 -11
  21. package/frontend/js/views/data.js +37 -35
  22. package/frontend/js/views/documents.js +231 -162
  23. package/frontend/js/views/mediaTagging.js +6 -5
  24. package/frontend/js/views/structure.js +47 -43
  25. package/frontend/js/views/tableDesigner.js +45 -1
  26. package/frontend/styles/components.css +237 -59
  27. package/frontend/styles/structure-graph.css +10 -2
  28. package/frontend/styles/tailwind.generated.css +1 -1
  29. package/frontend/styles/tokens.css +2 -0
  30. package/frontend/styles/views.css +84 -41
  31. package/package.json +2 -1
  32. package/server/routes/backups.js +120 -0
  33. package/server/routes/connections.js +26 -3
  34. package/server/routes/externalApi.js +6 -2
  35. package/server/server.js +3 -1
  36. package/server/services/databaseCommandService.js +4 -3
  37. package/server/services/sqlite/backupService.js +497 -66
  38. package/server/services/sqlite/connectionManager.js +2 -2
  39. package/server/services/sqlite/dataBrowserService.js +11 -3
  40. package/server/services/sqlite/importService.js +25 -0
  41. package/server/services/sqlite/sqlExecutor.js +2 -0
  42. package/server/services/storage/appStateStore.js +379 -88
  43. package/tests/api-token-auth.test.js +45 -2
  44. package/tests/backup-manager.test.js +140 -0
  45. package/tests/backups-view.test.js +64 -0
  46. package/tests/charts-height-preset-storage.test.js +60 -0
  47. package/tests/charts-route-state.test.js +144 -0
  48. package/tests/cli-service-delegation.test.js +97 -0
  49. package/tests/connection-removal.test.js +52 -0
  50. package/tests/database-command-service.test.js +38 -3
  51. package/tests/documents-view.test.js +132 -0
  52. package/tests/dropdown-button.test.js +75 -0
  53. package/tests/query-editor.test.js +28 -0
  54. package/tests/query-history-detail.test.js +37 -0
  55. package/tests/query-history-header.test.js +30 -0
  56. package/tests/risky-sql.test.js +30 -0
  57. package/tests/row-editor-null-values.test.js +24 -0
  58. package/tests/structure-view.test.js +56 -0
@@ -16,12 +16,56 @@ function renderRouteError(error) {
16
16
  `;
17
17
  }
18
18
 
19
+ function renderWorkspaceToolbar(state) {
20
+ const tablesVisible = state.tableDesigner.tablesVisible !== false;
21
+
22
+ return `
23
+ <div class="table-designer-workspace__toolbar workspace-header">
24
+ <div class="table-designer-workspace__toolbar-left">
25
+ <button
26
+ class="standard-button panel-toggle-button ${tablesVisible ? "" : "is-active"}"
27
+ aria-pressed="${tablesVisible ? "false" : "true"}"
28
+ data-action="toggle-table-designer-tables"
29
+ type="button"
30
+ >
31
+ <span class="material-symbols-outlined">${tablesVisible ? "visibility_off" : "visibility"}</span>
32
+ ${tablesVisible ? "Hide Tables" : "Show Tables"}
33
+ </button>
34
+ </div>
35
+ <div class="table-designer-workspace__toolbar-right">
36
+ <button
37
+ class="standard-button"
38
+ data-action="import-table-designer-csv"
39
+ type="button"
40
+ >
41
+ Import CSV
42
+ </button>
43
+ <input
44
+ accept=".csv,text/csv"
45
+ class="table-designer-workspace__file-input"
46
+ data-bind="table-designer-import-file"
47
+ type="file"
48
+ />
49
+ <button
50
+ class="signature-button"
51
+ data-action="navigate"
52
+ data-to="/table-designer/new"
53
+ type="button"
54
+ >
55
+ + New Table
56
+ </button>
57
+ </div>
58
+ </div>
59
+ `;
60
+ }
61
+
19
62
  export function renderTableDesignerView(state) {
20
63
  return {
21
64
  main: `
22
65
  <section class="view-surface table-designer-view">
23
- ${renderTableDesignerSidebar(state)}
66
+ ${state.tableDesigner.tablesVisible !== false ? renderTableDesignerSidebar(state) : ""}
24
67
  <div class="table-designer-workspace">
68
+ ${renderWorkspaceToolbar(state)}
25
69
  ${renderRouteError(state.tableDesigner.error)}
26
70
  <div class="table-designer-workspace__top">
27
71
  ${renderTableDesignerEditor(state)}
@@ -153,6 +153,92 @@
153
153
  color: var(--color-primary-container);
154
154
  }
155
155
 
156
+ .subnavi-panel {
157
+ display: flex;
158
+ flex: 0 0 var(--subnavi-width);
159
+ flex-direction: column;
160
+ min-height: 0;
161
+ min-width: min(var(--subnavi-width), 100%);
162
+ width: var(--subnavi-width);
163
+ }
164
+
165
+ .subnavi-list {
166
+ align-items: center;
167
+ display: flex;
168
+ flex: 1;
169
+ flex-direction: column;
170
+ gap: var(--spacing-2);
171
+ min-height: 0;
172
+ overflow: auto;
173
+ padding: var(--spacing-3);
174
+ }
175
+
176
+ .subnavi-item {
177
+ max-width: 100%;
178
+ width: min(var(--subnavi-item-width), 100%);
179
+ }
180
+
181
+ .subnavi-header {
182
+ align-items: center;
183
+ border-bottom: 1px solid var(--border-medium);
184
+ display: flex;
185
+ flex-wrap: wrap;
186
+ gap: var(--spacing-4);
187
+ justify-content: space-between;
188
+ padding: var(--spacing-5);
189
+ }
190
+
191
+ .subnavi-header > :first-child {
192
+ align-items: baseline;
193
+ display: flex;
194
+ flex-wrap: wrap;
195
+ gap: var(--spacing-3);
196
+ justify-content: space-between;
197
+ min-width: 0;
198
+ width: 100%;
199
+ }
200
+
201
+ .subnavi-header-title {
202
+ color: var(--color-primary-container);
203
+ flex: 1 1 auto;
204
+ font-family: var(--font-family-mono);
205
+ font-size: var(--font-size-status);
206
+ font-weight: 700;
207
+ letter-spacing: 0.2em;
208
+ min-width: 0;
209
+ text-transform: uppercase;
210
+ }
211
+
212
+ .subnavi-header-details {
213
+ color: rgb(var(--rgb-on-surface-variant) / 0.55);
214
+ flex: 0 0 auto;
215
+ font-family: var(--font-family-mono);
216
+ font-size: var(--font-size-status);
217
+ letter-spacing: 0.16em;
218
+ margin-left: auto;
219
+ text-align: right;
220
+ text-transform: uppercase;
221
+ }
222
+
223
+ .workspace-header {
224
+ align-items: center;
225
+ background: var(--color-surface-container);
226
+ border-bottom: 1px solid rgb(var(--rgb-outline) / 0.1);
227
+ display: flex;
228
+ flex-wrap: wrap;
229
+ gap: var(--spacing-4);
230
+ min-height: calc(var(--button-height) + (var(--spacing-3) * 2));
231
+ padding: var(--spacing-3) var(--spacing-6);
232
+ }
233
+
234
+ .workspace-header--low {
235
+ background: var(--color-surface-container-low);
236
+ }
237
+
238
+ .workspace-header > :only-child {
239
+ width: 100%;
240
+ }
241
+
156
242
  .sidebar-footer {
157
243
  margin-top: auto;
158
244
  padding: 0 var(--spacing-6);
@@ -391,6 +477,7 @@
391
477
  .signature-button,
392
478
  .delete-button,
393
479
  .toolbar-button,
480
+ .dropdown-button__toggle,
394
481
  .query-history-icon-button,
395
482
  .top-nav-icon {
396
483
  align-items: center;
@@ -409,6 +496,21 @@
409
496
  text-transform: uppercase;
410
497
  }
411
498
 
499
+ .panel-toggle-button.is-active,
500
+ .panel-toggle-button[aria-pressed='true'] {
501
+ background: var(--primary-alpha-12);
502
+ border-color: rgb(var(--rgb-primary) / 0.38);
503
+ box-shadow: inset 0 0 0 1px var(--primary-alpha-12);
504
+ color: var(--color-primary-container);
505
+ }
506
+
507
+ .panel-toggle-button.is-active:hover,
508
+ .panel-toggle-button[aria-pressed='true']:hover {
509
+ background: var(--primary-alpha-18);
510
+ border-color: rgb(var(--rgb-primary) / 0.5);
511
+ color: var(--color-primary-container);
512
+ }
513
+
412
514
  .signature-button {
413
515
  color: #000;
414
516
  font-family: var(--font-family-headline);
@@ -431,10 +533,29 @@
431
533
  text-transform: uppercase;
432
534
  }
433
535
 
536
+ .backup-safety-actions {
537
+ align-items: center;
538
+ display: flex;
539
+ flex-wrap: nowrap;
540
+ gap: var(--spacing-3);
541
+ overflow-x: auto;
542
+ }
543
+
544
+ .backup-safety-actions > button {
545
+ flex: 0 0 auto;
546
+ white-space: nowrap;
547
+ }
548
+
549
+ .backup-safety-actions > .standard-button {
550
+ margin-right: auto;
551
+ }
552
+
434
553
  .standard-button:focus-visible,
435
554
  .signature-button:focus-visible,
436
555
  .delete-button:focus-visible,
437
556
  .toolbar-button:focus-visible,
557
+ .dropdown-button__toggle:focus-visible,
558
+ .dropdown-button__item:focus-visible,
438
559
  .query-result-column-menu__toggle:focus-visible,
439
560
  .query-result-column-menu__item:focus-visible,
440
561
  .query-history-icon-button:focus-visible,
@@ -465,6 +586,94 @@
465
586
  color var(--transition-fast);
466
587
  }
467
588
 
589
+ .dropdown-button {
590
+ display: inline-flex;
591
+ position: relative;
592
+ }
593
+
594
+ .dropdown-button__toggle {
595
+ cursor: pointer;
596
+ gap: var(--spacing-2);
597
+ list-style: none;
598
+ }
599
+
600
+ .dropdown-button__toggle::-webkit-details-marker {
601
+ display: none;
602
+ }
603
+
604
+ .dropdown-button[open] .dropdown-button__toggle {
605
+ background: var(--primary-alpha-12);
606
+ border-color: rgb(var(--rgb-primary) / 0.38);
607
+ color: var(--color-primary-container);
608
+ }
609
+
610
+ .dropdown-button__chevron {
611
+ font-size: 18px;
612
+ line-height: 1;
613
+ transition: transform var(--transition-fast);
614
+ }
615
+
616
+ .dropdown-button[open] .dropdown-button__chevron {
617
+ transform: rotate(180deg);
618
+ }
619
+
620
+ .dropdown-button__panel {
621
+ background: var(--color-surface-container);
622
+ border: 1px solid rgb(var(--rgb-outline) / 0.22);
623
+ box-shadow: 0 18px 40px rgb(0 0 0 / 0.35);
624
+ min-width: 13rem;
625
+ padding: var(--spacing-1);
626
+ position: absolute;
627
+ top: calc(100% + var(--spacing-2));
628
+ z-index: 35;
629
+ }
630
+
631
+ .dropdown-button--align-right .dropdown-button__panel {
632
+ right: 0;
633
+ }
634
+
635
+ .dropdown-button--align-left .dropdown-button__panel {
636
+ left: 0;
637
+ }
638
+
639
+ .dropdown-button__item {
640
+ align-items: center;
641
+ color: var(--color-on-surface);
642
+ cursor: pointer;
643
+ display: flex;
644
+ font-family: var(--font-family-body);
645
+ font-size: 0.75rem;
646
+ gap: var(--spacing-2);
647
+ justify-content: flex-start;
648
+ line-height: 1.3;
649
+ padding: 0.6rem 0.75rem;
650
+ text-align: left;
651
+ transition:
652
+ background-color var(--transition-fast),
653
+ color var(--transition-fast);
654
+ width: 100%;
655
+ }
656
+
657
+ .dropdown-button__item:hover {
658
+ background: var(--color-surface-highest);
659
+ color: var(--color-primary-container);
660
+ }
661
+
662
+ .dropdown-button__item:disabled,
663
+ .dropdown-button__item[aria-disabled='true'] {
664
+ color: rgb(var(--rgb-on-surface-variant) / 0.32);
665
+ cursor: not-allowed;
666
+ }
667
+
668
+ .dropdown-button__item--danger {
669
+ color: var(--color-error);
670
+ }
671
+
672
+ .dropdown-button__item .material-symbols-outlined {
673
+ font-size: 18px;
674
+ line-height: 1;
675
+ }
676
+
468
677
  .query-result-header-cell {
469
678
  min-width: 10rem;
470
679
  position: relative;
@@ -789,6 +998,26 @@
789
998
  text-transform: uppercase;
790
999
  }
791
1000
 
1001
+ .query-history-search {
1002
+ display: block;
1003
+ margin-top: var(--spacing-4);
1004
+ position: relative;
1005
+ }
1006
+
1007
+ .query-history-search__icon {
1008
+ color: rgb(var(--rgb-on-surface-variant) / 0.55);
1009
+ font-size: 1rem;
1010
+ left: var(--spacing-3);
1011
+ pointer-events: none;
1012
+ position: absolute;
1013
+ top: 50%;
1014
+ transform: translateY(-50%);
1015
+ }
1016
+
1017
+ .query-history-search__input {
1018
+ padding-left: calc(var(--spacing-3) + 1rem + var(--spacing-2));
1019
+ }
1020
+
792
1021
  .query-history-list-scroll {
793
1022
  flex: 1;
794
1023
  min-height: 0;
@@ -841,35 +1070,14 @@
841
1070
  .table-designer-sidebar {
842
1071
  background: var(--color-surface-low);
843
1072
  border-right: 1px solid var(--border-medium);
844
- display: flex;
845
- flex: 0 0 clamp(16rem, 20vw, 18.2rem);
846
- flex-direction: column;
847
- max-width: 18.2rem;
848
- min-height: 0;
849
- min-width: min(18.2rem, 100%);
850
- width: clamp(16rem, 20vw, 18.2rem);
1073
+ max-width: var(--subnavi-width);
851
1074
  }
852
1075
 
853
1076
  .table-designer-sidebar__header {
854
- border-bottom: 1px solid var(--border-medium);
855
- display: flex;
856
- flex-wrap: wrap;
857
- gap: var(--spacing-4);
858
- justify-content: space-between;
859
- padding: var(--spacing-5);
860
- }
861
-
862
- .table-designer-sidebar__header-actions {
863
- align-items: center;
864
- display: flex;
865
- flex-direction: row;
866
- gap: var(--spacing-2);
867
- flex-wrap: wrap;
1077
+ align-items: flex-start;
868
1078
  }
869
1079
 
870
- .table-designer-sidebar__eyebrow,
871
- .table-designer-preview__eyebrow,
872
- .table-designer-main__eyebrow {
1080
+ .table-designer-preview__eyebrow {
873
1081
  color: var(--color-primary-container);
874
1082
  font-family: var(--font-family-mono);
875
1083
  font-size: var(--font-size-status);
@@ -877,8 +1085,7 @@
877
1085
  text-transform: uppercase;
878
1086
  }
879
1087
 
880
- .table-designer-preview__title,
881
- .table-designer-main__section-title {
1088
+ .table-designer-preview__title {
882
1089
  color: var(--color-on-surface);
883
1090
  font-family: var(--font-family-headline);
884
1091
  font-size: 1rem;
@@ -887,21 +1094,6 @@
887
1094
  margin-top: var(--spacing-2);
888
1095
  }
889
1096
 
890
- .table-designer-sidebar__meta,
891
- .table-designer-main__subtitle,
892
- .table-designer-main__section-text {
893
- color: rgb(var(--rgb-on-surface) / 0.52);
894
- font-family: var(--font-family-mono);
895
- font-size: var(--font-size-status);
896
- letter-spacing: 0.14em;
897
- margin-top: var(--spacing-2);
898
- text-transform: uppercase;
899
- }
900
-
901
- .table-designer-sidebar__file-input {
902
- display: none;
903
- }
904
-
905
1097
  .table-designer-sidebar__search {
906
1098
  align-items: center;
907
1099
  background: var(--color-surface-container-lowest);
@@ -984,16 +1176,8 @@ input.table-designer-sidebar__search-input[type='search'] {
984
1176
  color: rgb(var(--rgb-on-surface-variant) / 0.65);
985
1177
  }
986
1178
 
987
- .table-designer-sidebar__list {
988
- flex: 1;
989
- min-height: 0;
990
- overflow: auto;
991
- padding: var(--spacing-3);
992
- }
993
-
994
1179
  .table-designer-sidebar__item {
995
1180
  display: block;
996
- margin-bottom: var(--spacing-2);
997
1181
  transition:
998
1182
  background-color var(--transition-fast),
999
1183
  border-color var(--transition-fast);
@@ -1067,7 +1251,6 @@ input.table-designer-sidebar__search-input[type='search'] {
1067
1251
  min-height: 0;
1068
1252
  }
1069
1253
 
1070
- .table-designer-main__header,
1071
1254
  .table-designer-preview__header {
1072
1255
  align-items: center;
1073
1256
  border-bottom: 1px solid rgb(var(--rgb-outline) / 0.16);
@@ -1091,7 +1274,7 @@ input.table-designer-sidebar__search-input[type='search'] {
1091
1274
  display: flex;
1092
1275
  flex-wrap: wrap;
1093
1276
  gap: var(--spacing-3);
1094
- margin-top: var(--spacing-2);
1277
+ margin-top: 0;
1095
1278
  }
1096
1279
 
1097
1280
  .table-designer-main__name {
@@ -1125,13 +1308,6 @@ input.table-designer-main__name[type='text'] {
1125
1308
  padding: 0;
1126
1309
  }
1127
1310
 
1128
- .table-designer-main__actions {
1129
- align-items: center;
1130
- display: flex;
1131
- flex-wrap: wrap;
1132
- gap: var(--spacing-3);
1133
- }
1134
-
1135
1311
  .table-designer-preview__actions {
1136
1312
  align-items: center;
1137
1313
  display: flex;
@@ -1245,7 +1421,7 @@ input.table-designer-main__name[type='text'] {
1245
1421
  }
1246
1422
 
1247
1423
  .table-designer-main__section-header {
1248
- align-items: flex-start;
1424
+ align-items: center;
1249
1425
  display: flex;
1250
1426
  flex-wrap: wrap;
1251
1427
  gap: var(--spacing-4);
@@ -1524,6 +1700,8 @@ input.table-designer-main__name[type='text'] {
1524
1700
  border-bottom: 1px solid var(--border-medium);
1525
1701
  border-right: none;
1526
1702
  flex-basis: auto;
1703
+ max-width: none;
1704
+ width: 100%;
1527
1705
  }
1528
1706
  }
1529
1707
 
@@ -12,7 +12,6 @@
12
12
  display: flex;
13
13
  flex-wrap: wrap;
14
14
  gap: 1rem;
15
- padding: 1rem 1.25rem;
16
15
  }
17
16
 
18
17
  .structure-graph__toolbar-main {
@@ -57,9 +56,18 @@
57
56
  background: var(--color-surface-container-highest);
58
57
  }
59
58
 
60
- .structure-graph__toolbar .standard-button.is-active {
59
+ .structure-graph__toolbar .panel-toggle-button.is-active,
60
+ .structure-graph__toolbar .panel-toggle-button[aria-pressed='true'] {
61
61
  background: var(--primary-alpha-12);
62
62
  border-color: rgb(var(--rgb-primary) / 0.38);
63
+ box-shadow: inset 0 0 0 1px var(--primary-alpha-12);
64
+ color: var(--color-primary-container);
65
+ }
66
+
67
+ .structure-graph__toolbar .panel-toggle-button.is-active:hover,
68
+ .structure-graph__toolbar .panel-toggle-button[aria-pressed='true']:hover {
69
+ background: var(--primary-alpha-18);
70
+ border-color: rgb(var(--rgb-primary) / 0.5);
63
71
  color: var(--color-primary-container);
64
72
  }
65
73