dbviewer 0.7.10 → 0.7.11

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/assets/images/dbviewer/emoji-favicon.txt +1 -0
  4. data/app/assets/images/dbviewer/favicon.ico +4 -0
  5. data/app/assets/images/dbviewer/favicon.png +4 -0
  6. data/app/assets/images/dbviewer/favicon.svg +10 -0
  7. data/app/assets/javascripts/dbviewer/entity_relationship_diagram.js +38 -42
  8. data/app/assets/javascripts/dbviewer/error_handler.js +58 -0
  9. data/app/assets/javascripts/dbviewer/home.js +25 -34
  10. data/app/assets/javascripts/dbviewer/layout.js +100 -129
  11. data/app/assets/javascripts/dbviewer/query.js +309 -246
  12. data/app/assets/javascripts/dbviewer/sidebar.js +170 -183
  13. data/app/assets/javascripts/dbviewer/utility.js +124 -0
  14. data/app/assets/stylesheets/dbviewer/application.css +8 -146
  15. data/app/assets/stylesheets/dbviewer/entity_relationship_diagram.css +0 -34
  16. data/app/assets/stylesheets/dbviewer/logs.css +0 -11
  17. data/app/assets/stylesheets/dbviewer/query.css +21 -9
  18. data/app/assets/stylesheets/dbviewer/table.css +49 -131
  19. data/app/controllers/concerns/dbviewer/database_operations/connection_management.rb +90 -0
  20. data/app/controllers/concerns/dbviewer/database_operations/data_export.rb +31 -0
  21. data/app/controllers/concerns/dbviewer/database_operations/database_information.rb +54 -0
  22. data/app/controllers/concerns/dbviewer/database_operations/datatable_operations.rb +37 -0
  23. data/app/controllers/concerns/dbviewer/database_operations/query_operations.rb +37 -0
  24. data/app/controllers/concerns/dbviewer/database_operations/relationship_management.rb +175 -0
  25. data/app/controllers/concerns/dbviewer/database_operations/table_operations.rb +46 -0
  26. data/app/controllers/concerns/dbviewer/database_operations.rb +4 -9
  27. data/app/controllers/dbviewer/api/tables_controller.rb +12 -0
  28. data/app/controllers/dbviewer/entity_relationship_diagrams_controller.rb +0 -15
  29. data/app/controllers/dbviewer/tables_controller.rb +4 -33
  30. data/app/views/dbviewer/entity_relationship_diagrams/index.html.erb +1 -1
  31. data/app/views/dbviewer/tables/query.html.erb +21 -6
  32. data/app/views/dbviewer/tables/show.html.erb +2 -2
  33. data/app/views/layouts/dbviewer/application.html.erb +12 -3
  34. data/config/routes.rb +2 -2
  35. data/lib/dbviewer/database/manager.rb +2 -2
  36. data/lib/dbviewer/datatable/query_operations.rb +1 -17
  37. data/lib/dbviewer/engine.rb +29 -0
  38. data/lib/dbviewer/version.rb +1 -1
  39. metadata +15 -10
  40. data/app/controllers/concerns/dbviewer/connection_management.rb +0 -88
  41. data/app/controllers/concerns/dbviewer/data_export.rb +0 -32
  42. data/app/controllers/concerns/dbviewer/database_information.rb +0 -62
  43. data/app/controllers/concerns/dbviewer/datatable_support.rb +0 -47
  44. data/app/controllers/concerns/dbviewer/pagination_concern.rb +0 -34
  45. data/app/controllers/concerns/dbviewer/query_operations.rb +0 -28
  46. data/app/controllers/concerns/dbviewer/relationship_management.rb +0 -173
  47. data/app/controllers/concerns/dbviewer/table_operations.rb +0 -56
@@ -54,15 +54,6 @@ body {
54
54
  transition: color 0.2s ease, background-color 0.2s ease;
55
55
  }
56
56
 
57
- /* Smooth theme transitions */
58
- html {
59
- transition: background-color 0.2s ease;
60
- }
61
-
62
- body {
63
- transition: color 0.2s ease, background-color 0.2s ease;
64
- }
65
-
66
57
  /* Sidebar styles - enhanced for elegance with Grafana-like compact design */
67
58
  .dbviewer-sidebar {
68
59
  width: 240px; /* More compact sidebar width */
@@ -90,51 +81,7 @@ body {
90
81
  border-right: 1px solid rgba(73, 80, 87, 0.3);
91
82
  }
92
83
 
93
- .dbviewer-sidebar-header {
94
- padding: 0.8rem 1rem; /* Reduced padding for more compact header */
95
- font-weight: 600;
96
- align-items: center;
97
- justify-content: space-between;
98
- flex-shrink: 0;
99
- display: flex;
100
- }
101
-
102
- [data-bs-theme="light"] .dbviewer-sidebar-header {
103
- border-bottom: 1px solid rgba(222, 226, 230, 0.6);
104
- background: linear-gradient(to right, #f8f9fa, #f1f3f5);
105
- }
106
-
107
- [data-bs-theme="dark"] .dbviewer-sidebar-header {
108
- border-bottom: 1px solid rgba(73, 80, 87, 0.3);
109
- background: linear-gradient(to right, #343a40, #2c3034);
110
- }
111
-
112
- .dbviewer-sidebar-header h5 {
113
- overflow: hidden;
114
- text-overflow: ellipsis;
115
- white-space: nowrap;
116
- max-width: 80%;
117
- cursor: default;
118
- position: relative;
119
- }
120
-
121
- /* Tooltip for database name */
122
- .dbviewer-sidebar-header h5[title]:hover::after {
123
- content: attr(title);
124
- position: absolute;
125
- left: 0;
126
- top: 100%;
127
- z-index: 1000;
128
- background-color: #343a40;
129
- color: white;
130
- padding: 0.375rem 0.75rem;
131
- border-radius: 0.25rem;
132
- font-size: 0.875rem;
133
- white-space: normal;
134
- max-width: 250px;
135
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
136
- margin-top: 6px;
137
- }
84
+ /* Sidebar top section styles */
138
85
 
139
86
  .dbviewer-sidebar-top {
140
87
  flex-shrink: 0;
@@ -273,10 +220,7 @@ body {
273
220
  .dbviewer-main {
274
221
  padding: 1rem;
275
222
  }
276
- .dbviewer-sidebar-header h5 {
277
- max-width: 70%;
278
- font-size: 1rem;
279
- }
223
+ /* Removed unused .dbviewer-sidebar-header h5 */
280
224
 
281
225
  /* Make tables more responsive */
282
226
  .table-responsive {
@@ -284,9 +228,7 @@ body {
284
228
  -webkit-overflow-scrolling: touch;
285
229
  }
286
230
 
287
- .stat-card-bg {
288
- margin-bottom: 1rem;
289
- }
231
+ /* Removed unused .stat-card-bg */
290
232
  }
291
233
 
292
234
  /* Extra small screens - more compact for small devices */
@@ -325,23 +267,11 @@ body {
325
267
  transition: background-color 0.2s ease;
326
268
  }
327
269
 
328
- .dbviewer-table-filter-icon {
329
- position: absolute;
330
- left: 1.5rem;
331
- top: 50%;
332
- transform: translateY(-50%);
333
- color: #6c757d;
334
- font-size: 0.85rem;
335
- padding: 0.25rem;
336
- width: 1.5rem;
337
- text-align: center;
338
- z-index: 2;
339
- transition: color 0.2s ease;
340
- }
270
+ /* Filter styles */
341
271
 
342
272
  .dbviewer-table-filter {
343
273
  border-radius: 8px;
344
- padding: 0.65rem 0.85rem 0.65rem 2.5rem;
274
+ padding: 0.65rem 0.85rem;
345
275
  margin-bottom: 1rem;
346
276
  transition: all 0.2s ease;
347
277
  border: 1px solid rgba(0, 0, 0, 0.1);
@@ -455,7 +385,7 @@ body {
455
385
  z-index: 40;
456
386
  }
457
387
 
458
- /* Additional specificity for table headers in dark mode */
388
+ /* Additional specificity for table headers in different themes */
459
389
  [data-bs-theme="light"] .table-responsive .table thead th,
460
390
  [data-bs-theme="light"] .dbviewer-scrollable .table thead th {
461
391
  background-color: #f1f3f5;
@@ -515,50 +445,7 @@ body {
515
445
  z-index: 1;
516
446
  }
517
447
 
518
- /* Equal height for timeline and structure cards - Grafana-inspired compact layout */
519
- .two-column-layout .card {
520
- height: 100%;
521
- display: flex;
522
- flex-direction: column;
523
- }
524
- .two-column-layout .card-body {
525
- flex: 1;
526
- display: flex;
527
- flex-direction: column;
528
- padding: 0.75rem;
529
- } /* Reduced padding */
530
- .two-column-layout .chart-container {
531
- flex: 1;
532
- min-height: 220px;
533
- } /* Reduced min-height */
534
- .two-column-layout .structure-container {
535
- padding: 0;
536
- }
537
- .two-column-layout .tab-content {
538
- flex: 1;
539
- overflow: hidden;
540
- display: flex;
541
- flex-direction: column;
542
- }
543
- .two-column-layout .tab-pane {
544
- flex: 1;
545
- overflow: hidden;
546
- }
547
- .two-column-layout .table-responsive {
548
- overflow-x: auto;
549
- }
550
-
551
- [data-bs-theme="light"] .two-column-layout .sticky-top {
552
- top: 0;
553
- z-index: 999;
554
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
555
- }
556
-
557
- [data-bs-theme="dark"] .two-column-layout .sticky-top {
558
- top: 0;
559
- z-index: 999;
560
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
561
- }
448
+ /* Theme specific styles */
562
449
 
563
450
  /* Enhanced dark mode toggle */
564
451
  .theme-toggle {
@@ -1146,32 +1033,7 @@ code.sql-query-code {
1146
1033
  color: #adb5bd;
1147
1034
  }
1148
1035
 
1149
- [data-bs-theme="dark"] .stat-card-bg {
1150
- background-color: #2c3034;
1151
- }
1152
-
1153
- .stat-card-bg {
1154
- background-color: var(--bs-light);
1155
- }
1156
-
1157
- /* Enhanced stat cards and metric icons - Grafana-inspired */
1158
- .stat-card-bg {
1159
- background: #ffffff;
1160
- border-radius: 3px; /* Smaller radius for Grafana look */
1161
- box-shadow: 0 1px 5px rgba(0, 0, 0, 0.03);
1162
- transition: all 0.3s ease;
1163
- border: none;
1164
- }
1165
-
1166
- .stat-card-bg:hover {
1167
- transform: translateY(-1px); /* Subtler hover */
1168
- box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
1169
- }
1170
-
1171
- [data-bs-theme="dark"] .stat-card-bg {
1172
- background-color: #212529;
1173
- box-shadow: 0 1px 5px rgba(0, 0, 0, 0.08);
1174
- }
1036
+ /* Enhanced metric icon styling - Grafana-inspired */
1175
1037
 
1176
1038
  /* Enhanced metric icon styling - Grafana-inspired */
1177
1039
  .metric-icon {
@@ -137,27 +137,6 @@
137
137
  }
138
138
 
139
139
  /* Data loading badge styling */
140
- #data-loading-badge {
141
- animation: pulse 2s infinite;
142
- }
143
-
144
- @keyframes pulse {
145
- 0% {
146
- opacity: 1;
147
- }
148
- 50% {
149
- opacity: 0.7;
150
- }
151
- 100% {
152
- opacity: 1;
153
- }
154
- }
155
-
156
- #data-loading-badge .badge {
157
- font-size: 0.75rem;
158
- padding: 0.4rem 0.6rem;
159
- }
160
-
161
140
  /* Mermaid override for text size */
162
141
  .mermaid .entityLabel div {
163
142
  font-size: 20px !important;
@@ -166,16 +145,3 @@
166
145
  .mermaid .er.relationshipLabel {
167
146
  font-size: 20px !important;
168
147
  }
169
-
170
- /* Enhanced table highlighting for current table */
171
- .current-table-highlight rect {
172
- fill: var(--bs-primary-bg-subtle) !important;
173
- stroke: var(--bs-primary) !important;
174
- stroke-width: 2px !important;
175
- }
176
-
177
- [data-bs-theme="dark"] .current-table-highlight rect {
178
- fill: #2c3034 !important;
179
- stroke: #6ea8fe !important;
180
- stroke-width: 2px !important;
181
- }
@@ -40,17 +40,6 @@ details summary {
40
40
  cursor: pointer;
41
41
  }
42
42
 
43
- /* Rotate icon when expanded */
44
- .collapsed-section[aria-expanded="true"] .bi-chevron-down {
45
- transform: rotate(180deg);
46
- transition: transform 0.3s ease;
47
- }
48
-
49
- .collapsed-section[aria-expanded="false"] .bi-chevron-down {
50
- transform: rotate(0deg);
51
- transition: transform 0.3s ease;
52
- }
53
-
54
43
  /* Code styling */
55
44
  .pattern-code,
56
45
  .query-binds {
@@ -44,15 +44,7 @@
44
44
  color: #f8f9fa;
45
45
  }
46
46
 
47
- /* Result table styling */
48
- .results-table {
49
- border-collapse: collapse;
50
- }
51
-
52
- [data-bs-theme="dark"] .results-table {
53
- border-color: #495057;
54
- }
55
-
47
+ /* Button styling */
56
48
  .example-query:hover {
57
49
  background-color: #0d6efd;
58
50
  color: white;
@@ -74,6 +66,26 @@
74
66
  color: #adb5bd;
75
67
  }
76
68
 
69
+ /* Error containers */
70
+ .editor-error-container {
71
+ margin: 10px 0;
72
+ display: none; /* Hidden by default */
73
+ }
74
+
75
+ .editor-error-container:not(:empty) {
76
+ display: block;
77
+ padding: 15px;
78
+ border-radius: 4px;
79
+ background-color: #f8d7da;
80
+ border: 1px solid #f5c2c7;
81
+ }
82
+
83
+ [data-bs-theme="dark"] .editor-error-container:not(:empty) {
84
+ background-color: #2d1a1d;
85
+ border: 1px solid #842029;
86
+ color: #ea868f;
87
+ }
88
+
77
89
  /* Monaco status bar */
78
90
  .monaco-status-bar {
79
91
  display: flex;
@@ -1,3 +1,4 @@
1
+ /* ========== TABLE HEADER AND COLUMN SORTING STYLES ========== */
1
2
  /* Column sorting styles */
2
3
  .sortable-column {
3
4
  cursor: pointer;
@@ -104,6 +105,7 @@ tbody tr td.action-column {
104
105
  background-color: rgba(255, 255, 255, 0.1);
105
106
  }
106
107
 
108
+ /* ========== FILTER STYLING ========== */
107
109
  /* Column filter styling */
108
110
  .column-filters td {
109
111
  padding: 0.5rem;
@@ -120,6 +122,7 @@ tbody tr td.action-column {
120
122
  cursor: not-allowed;
121
123
  }
122
124
 
125
+ /* ========== ACTION COLUMN STYLING ========== */
123
126
  /* Action column styling */
124
127
  .action-column {
125
128
  width: 100px; /* Increased from 60px to accommodate two buttons */
@@ -127,29 +130,38 @@ tbody tr td.action-column {
127
130
  white-space: nowrap;
128
131
  position: sticky;
129
132
  left: 0;
130
- z-index: 15;
131
- background-color: var(--bs-table-striped-bg, #f2f2f2);
132
- box-shadow: 2px 0 4px rgba(0, 0, 0, 0.05);
133
+ z-index: 30; /* Higher z-index to ensure it stays on top */
134
+ background-color: var(--bs-body-bg, #fff); /* Use body background color */
135
+ box-shadow: 2px 0 6px rgba(0, 0, 0, 0.04);
133
136
  }
134
137
 
135
- .copy-factory-btn {
138
+ .copy-factory-btn,
139
+ .view-record-btn {
136
140
  padding: 0.1rem 0.4rem;
137
141
  width: 32px;
138
142
  }
139
143
 
140
- .copy-factory-btn:hover {
144
+ .copy-factory-btn:hover,
145
+ .view-record-btn:hover {
141
146
  opacity: 0.85;
142
147
  transform: translateY(-1px);
143
148
  }
144
149
 
145
150
  /* Ensure proper background color for actions column in dark mode */
146
151
  [data-bs-theme="dark"] .action-column {
147
- background-color: var(--bs-dark-bg-subtle, #343a40);
152
+ background-color: var(
153
+ --bs-body-bg,
154
+ #212529
155
+ ); /* Use body background in dark mode */
148
156
  }
149
157
 
150
158
  /* Maintain zebra striping with sticky action column */
151
159
  .table-striped > tbody > tr:nth-of-type(odd) > .action-column {
152
- background-color: var(--bs-table-striped-bg, #f8f9fa);
160
+ background-color: var(--bs-tertiary-bg, #f8f9fa);
161
+ }
162
+
163
+ .table-striped > tbody > tr:nth-of-type(even) > .action-column {
164
+ background-color: var(--bs-body-bg, #fff);
153
165
  }
154
166
 
155
167
  [data-bs-theme="dark"]
@@ -157,17 +169,15 @@ tbody tr td.action-column {
157
169
  > tbody
158
170
  > tr:nth-of-type(odd)
159
171
  > .action-column {
160
- background-color: var(--bs-dark-bg-subtle, #343a40);
161
- }
162
-
163
- .view-record-btn {
164
- padding: 0.1rem 0.4rem;
165
- width: 32px;
172
+ background-color: var(--bs-tertiary-bg, #2b3035);
166
173
  }
167
174
 
168
- .view-record-btn:hover {
169
- opacity: 0.85;
170
- transform: translateY(-1px);
175
+ [data-bs-theme="dark"]
176
+ .table-striped
177
+ > tbody
178
+ > tr:nth-of-type(even)
179
+ > .action-column {
180
+ background-color: var(--bs-body-bg, #212529);
171
181
  }
172
182
 
173
183
  /* Make action column header sticky as well */
@@ -183,10 +193,6 @@ tbody tr td.action-column {
183
193
  background-color: var(--bs-dark-bg-subtle, #343a40) !important;
184
194
  }
185
195
 
186
- [data-bs-theme="dark"] .action-column-header {
187
- background-color: var(--bs-dark-bg-subtle, #343a40) !important;
188
- }
189
-
190
196
  /* Make action column filter cell sticky as well */
191
197
  .action-column-filter {
192
198
  position: sticky;
@@ -199,11 +205,6 @@ tbody tr td.action-column {
199
205
  background-color: var(--bs-tertiary-bg, #2b3035) !important;
200
206
  }
201
207
 
202
- /* Fix action column for entire table */
203
- .action-column {
204
- box-shadow: 2px 0 6px rgba(0, 0, 0, 0.04);
205
- }
206
-
207
208
  /* Ensure equal padding for all cells */
208
209
  .action-column-header,
209
210
  .action-column-filter {
@@ -211,6 +212,7 @@ tbody tr td.action-column {
211
212
  padding-right: 8px !important;
212
213
  }
213
214
 
215
+ /* ========== RELATIONSHIP AND RECORD DETAIL STYLING ========== */
214
216
  /* Relationship section styles */
215
217
  #relationshipsSection {
216
218
  border-top: 1px solid var(--bs-border-color, #dee2e6);
@@ -261,14 +263,23 @@ tbody tr td.action-column {
261
263
  padding: 0.375rem 0.75rem;
262
264
  }
263
265
 
264
- .relationship-section .btn-outline-primary:hover {
266
+ .relationship-section .btn-outline-primary:hover,
267
+ .relationship-section .btn-outline-success:hover {
265
268
  transform: translateX(2px);
266
269
  transition: transform 0.2s ease;
267
270
  }
268
271
 
269
- .relationship-section .btn-outline-success:hover {
270
- transform: translateX(2px);
271
- transition: transform 0.2s ease;
272
+ /* Relationships table specific styles */
273
+ .relationships-table .btn-outline-primary {
274
+ font-size: 0.75rem;
275
+ padding: 0.25rem 0.5rem;
276
+ }
277
+
278
+ .relationships-table code {
279
+ background-color: var(--bs-gray-100);
280
+ padding: 0.125rem 0.25rem;
281
+ border-radius: 0.125rem;
282
+ font-size: 0.875rem;
272
283
  }
273
284
 
274
285
  /* Dark mode relationship styles */
@@ -293,6 +304,11 @@ tbody tr td.action-column {
293
304
  border-color: var(--bs-border-color, #495057);
294
305
  }
295
306
 
307
+ [data-bs-theme="dark"] .relationships-table code {
308
+ background-color: var(--bs-gray-800);
309
+ color: var(--bs-gray-100);
310
+ }
311
+
296
312
  /* Responsive relationship tables */
297
313
  @media (max-width: 767.98px) {
298
314
  .relationship-section .table th,
@@ -307,6 +323,7 @@ tbody tr td.action-column {
307
323
  }
308
324
  }
309
325
 
326
+ /* ========== GENERAL TABLE STYLING ========== */
310
327
  /* Borderless table styling */
311
328
  .table {
312
329
  border-collapse: separate;
@@ -343,77 +360,6 @@ tbody tr td.action-column {
343
360
  background-color: var(--bs-tertiary-bg, rgba(255, 255, 255, 0.03));
344
361
  }
345
362
 
346
- /* Column filter styling */
347
- .column-filters td {
348
- padding: 0.5rem;
349
- background-color: var(--bs-tertiary-bg, #f8f9fa);
350
- }
351
-
352
- /* Action column styling */
353
- .action-column {
354
- width: 100px; /* Increased from 60px to accommodate two buttons */
355
- min-width: 100px; /* Ensure minimum width */
356
- white-space: nowrap;
357
- position: sticky;
358
- left: 0;
359
- z-index: 30; /* Increased z-index to ensure it stays on top */
360
- background-color: var(--bs-body-bg, #fff); /* Use body background color */
361
- box-shadow: 2px 0 6px rgba(0, 0, 0, 0.04);
362
- }
363
-
364
- .copy-factory-btn {
365
- padding: 0.1rem 0.4rem;
366
- width: 32px;
367
- }
368
-
369
- .copy-factory-btn:hover {
370
- opacity: 0.85;
371
- transform: translateY(-1px);
372
- }
373
-
374
- /* Ensure proper background color for actions column in dark mode */
375
- [data-bs-theme="dark"] .action-column {
376
- background-color: var(
377
- --bs-body-bg,
378
- #212529
379
- ); /* Use body background in dark mode */
380
- }
381
-
382
- /* Maintain zebra striping with sticky action column */
383
- .table-striped > tbody > tr:nth-of-type(odd) > .action-column {
384
- background-color: var(--bs-tertiary-bg, #f8f9fa);
385
- }
386
-
387
- .table-striped > tbody > tr:nth-of-type(even) > .action-column {
388
- background-color: var(--bs-body-bg, #fff);
389
- }
390
-
391
- [data-bs-theme="dark"]
392
- .table-striped
393
- > tbody
394
- > tr:nth-of-type(odd)
395
- > .action-column {
396
- background-color: var(--bs-tertiary-bg, #2b3035);
397
- }
398
-
399
- [data-bs-theme="dark"]
400
- .table-striped
401
- > tbody
402
- > tr:nth-of-type(even)
403
- > .action-column {
404
- background-color: var(--bs-body-bg, #212529);
405
- }
406
-
407
- .view-record-btn {
408
- padding: 0.1rem 0.4rem;
409
- width: 32px;
410
- }
411
-
412
- .view-record-btn:hover {
413
- opacity: 0.85;
414
- transform: translateY(-1px);
415
- }
416
-
417
363
  /* Record detail modal styling */
418
364
  .record-detail-table tr:first-child th,
419
365
  .record-detail-table tr:first-child td {
@@ -429,41 +375,11 @@ tbody tr td.action-column {
429
375
  }
430
376
 
431
377
  /* Relationships section styling */
432
- #relationshipsSection {
433
- border-top: 1px solid var(--bs-border-color);
434
- padding-top: 1rem;
435
- }
436
-
437
- #relationshipsSection h6 {
438
- color: var(--bs-emphasis-color);
439
- margin-bottom: 1rem;
440
- }
441
-
442
- [data-bs-theme="dark"] #relationshipsSection {
443
- border-top-color: #495057;
444
- }
445
-
446
- .relationships-table .btn-outline-primary {
447
- font-size: 0.75rem;
448
- padding: 0.25rem 0.5rem;
449
- }
450
-
451
- .relationships-table code {
452
- background-color: var(--bs-gray-100);
453
- padding: 0.125rem 0.25rem;
454
- border-radius: 0.125rem;
455
- font-size: 0.875rem;
456
- }
457
-
458
- [data-bs-theme="dark"] .relationships-table code {
459
- background-color: var(--bs-gray-800);
460
- color: var(--bs-gray-100);
461
- }
462
-
463
378
  [data-bs-theme="dark"] .record-detail-table .code-block {
464
379
  background-color: var(--bs-dark);
465
380
  }
466
381
 
382
+ /* ========== FULLSCREEN TABLE STYLES ========== */
467
383
  /* Fullscreen table styles */
468
384
  .table-fullscreen {
469
385
  position: fixed !important;
@@ -529,6 +445,7 @@ body.table-fullscreen-active {
529
445
  transition: all 0.3s ease-in-out;
530
446
  }
531
447
 
448
+ /* ========== FLOATING FILTER STYLES ========== */
532
449
  /* Floating creation filter button */
533
450
  .floating-creation-filter {
534
451
  position: fixed;
@@ -764,6 +681,7 @@ body.table-fullscreen-active {
764
681
  box-shadow: 0 2px 8px rgba(var(--bs-primary-rgb), 0.3);
765
682
  }
766
683
 
684
+ /* ========== FLATPICKR DATE PICKER STYLING ========== */
767
685
  /* Flatpickr theme adjustments */
768
686
  .flatpickr-calendar {
769
687
  border-radius: 8px;
@@ -0,0 +1,90 @@
1
+ module Dbviewer
2
+ module DatabaseOperations
3
+ module ConnectionManagement
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :current_connection_key, :available_connections if respond_to?(:helper_method)
8
+ end
9
+
10
+ # Get the current active connection key
11
+ def current_connection_key
12
+ key = session[:dbviewer_connection] || Dbviewer.configuration.current_connection
13
+ return key.to_sym if key && Dbviewer.configuration.database_connections.key?(key.to_sym)
14
+
15
+ first_key = Dbviewer.configuration.database_connections.keys.first
16
+ if first_key
17
+ session[:dbviewer_connection] = first_key
18
+ return first_key
19
+ end
20
+
21
+ :default
22
+ end
23
+
24
+ # Set the current connection to use
25
+ def switch_connection(connection_key)
26
+ connection_key = connection_key.to_sym if connection_key.respond_to?(:to_sym)
27
+
28
+ if connection_key && Dbviewer.configuration.database_connections.key?(connection_key)
29
+ session[:dbviewer_connection] = connection_key
30
+ # Clear the database manager to force it to be recreated with the new connection
31
+ @database_manager = nil
32
+ return true
33
+ else
34
+ # If the connection key doesn't exist, reset to default connection
35
+ if Dbviewer.configuration.database_connections.key?(Dbviewer.configuration.current_connection)
36
+ session[:dbviewer_connection] = Dbviewer.configuration.current_connection
37
+ @database_manager = nil
38
+ return true
39
+ else
40
+ # If even the default connection isn't valid, try the first available connection
41
+ first_key = Dbviewer.configuration.database_connections.keys.first
42
+ if first_key
43
+ session[:dbviewer_connection] = first_key
44
+ @database_manager = nil
45
+ return true
46
+ end
47
+ end
48
+ end
49
+
50
+ false # Return false if we couldn't set a valid connection
51
+ end
52
+
53
+ # Get list of available connections
54
+ def available_connections
55
+ connections = Dbviewer.configuration.database_connections.map do |key, config|
56
+ # Try to determine the adapter name if it's not already stored
57
+ adapter_name = nil
58
+ if config[:adapter_name].present?
59
+ adapter_name = config[:adapter_name]
60
+ elsif config[:connection].present?
61
+ begin
62
+ adapter_name = config[:connection].connection.adapter_name
63
+ rescue => e
64
+ Rails.logger.error("Error getting adapter name: #{e.message}")
65
+ end
66
+ end
67
+
68
+ {
69
+ key: key,
70
+ name: config[:name] || key.to_s.humanize,
71
+ adapter_name: adapter_name,
72
+ current: key.to_sym == current_connection_key.to_sym
73
+ }
74
+ end
75
+
76
+ # Ensure at least one connection is marked as current
77
+ unless connections.any? { |c| c[:current] }
78
+ # If no connection is current, mark the first one as current
79
+ if connections.any?
80
+ connections.first[:current] = true
81
+ # Also update the session
82
+ session[:dbviewer_connection] = connections.first[:key]
83
+ end
84
+ end
85
+
86
+ connections
87
+ end
88
+ end
89
+ end
90
+ end