db-model-router 1.0.6 → 1.0.7

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 (137) hide show
  1. package/README.md +150 -11
  2. package/TODO.md +0 -15
  3. package/db-manager/.dbmanager.sqlite +0 -0
  4. package/db-manager/README.md +223 -0
  5. package/db-manager/adapter-proxy.js +361 -0
  6. package/db-manager/demo/cockroachdb.env +6 -0
  7. package/db-manager/demo/demo.sqlite +0 -0
  8. package/db-manager/demo/dynamodb.env +7 -0
  9. package/db-manager/demo/mongodb.env +4 -0
  10. package/db-manager/demo/mssql.env +6 -0
  11. package/db-manager/demo/mysql.env +6 -0
  12. package/db-manager/demo/oracle.env +6 -0
  13. package/db-manager/demo/postgres.env +6 -0
  14. package/db-manager/demo/redis.env +4 -0
  15. package/db-manager/demo/seeds/cockroachdb.sql +32 -0
  16. package/db-manager/demo/seeds/mssql.sql +32 -0
  17. package/db-manager/demo/seeds/mysql.sql +32 -0
  18. package/db-manager/demo/seeds/oracle.sql +43 -0
  19. package/db-manager/demo/seeds/postgres.sql +32 -0
  20. package/db-manager/demo/seeds/sqlite3.sql +32 -0
  21. package/db-manager/demo/sqlite3.env +2 -0
  22. package/db-manager/metadata-db.js +170 -0
  23. package/db-manager/public/.gitkeep +1 -0
  24. package/db-manager/public/css/style.css +1413 -0
  25. package/db-manager/public/js/app.js +1370 -0
  26. package/db-manager/routes/api.js +388 -0
  27. package/db-manager/routes/views.js +61 -0
  28. package/db-manager/server.js +39 -0
  29. package/db-manager/utils/build-filter-config.js +18 -0
  30. package/db-manager/utils/csv-export.js +59 -0
  31. package/db-manager/utils/export-filename.js +39 -0
  32. package/db-manager/utils/filter-tables.js +20 -0
  33. package/db-manager/utils/parse-filters.js +93 -0
  34. package/db-manager/utils/sort-state.js +35 -0
  35. package/db-manager/views/.gitkeep +1 -0
  36. package/db-manager/views/dashboard.ejs +53 -0
  37. package/db-manager/views/history.ejs +52 -0
  38. package/db-manager/views/index.ejs +35 -0
  39. package/db-manager/views/layout.ejs +31 -0
  40. package/db-manager/views/partials/data-panel.ejs +74 -0
  41. package/db-manager/views/partials/header.ejs +36 -0
  42. package/db-manager/views/partials/sidebar.ejs +30 -0
  43. package/db-manager/views/query.ejs +58 -0
  44. package/dbmr.schema.json +22 -44
  45. package/demo/.dockerignore +7 -0
  46. package/demo/.env.example +14 -0
  47. package/demo/Dockerfile +20 -0
  48. package/demo/app.js +39 -0
  49. package/demo/commons/add_migration.js +43 -0
  50. package/demo/commons/db.js +28 -0
  51. package/demo/commons/migrate.js +68 -0
  52. package/demo/commons/modules.js +18 -0
  53. package/demo/commons/password.js +36 -0
  54. package/demo/commons/security.js +30 -0
  55. package/demo/commons/session.js +13 -0
  56. package/demo/commons/webhook.js +81 -0
  57. package/demo/dbmr.schema.json +338 -0
  58. package/demo/middleware/authenticate.js +14 -0
  59. package/demo/middleware/hasPermission.js +30 -0
  60. package/demo/middleware/logger.js +67 -0
  61. package/demo/middleware/tenantIsolation.js +17 -0
  62. package/demo/migrations/20260509170349_create_migrations_table.sql +6 -0
  63. package/demo/migrations/20260509170349_create_saas_tables.sql +69 -0
  64. package/demo/migrations/20260509170349_create_tables.sql +193 -0
  65. package/demo/models/addresses.js +24 -0
  66. package/demo/models/cart_items.js +20 -0
  67. package/demo/models/carts.js +18 -0
  68. package/demo/models/categories.js +22 -0
  69. package/demo/models/coupons.js +25 -0
  70. package/demo/models/index.js +43 -0
  71. package/demo/models/order_items.js +23 -0
  72. package/demo/models/orders.js +27 -0
  73. package/demo/models/payments.js +23 -0
  74. package/demo/models/product_images.js +20 -0
  75. package/demo/models/product_reviews.js +22 -0
  76. package/demo/models/product_variants.js +22 -0
  77. package/demo/models/products.js +32 -0
  78. package/demo/models/role_permissions.js +17 -0
  79. package/demo/models/roles.js +17 -0
  80. package/demo/models/shipments.js +21 -0
  81. package/demo/models/tenants.js +18 -0
  82. package/demo/models/users.js +23 -0
  83. package/demo/models/webhook_logs.js +22 -0
  84. package/demo/models/webhooks.js +19 -0
  85. package/demo/models/wishlists.js +17 -0
  86. package/demo/openapi.json +7000 -0
  87. package/demo/package-lock.json +2810 -0
  88. package/demo/package.json +43 -0
  89. package/demo/routes/addresses/index.js +6 -0
  90. package/demo/routes/auth/index.js +55 -0
  91. package/demo/routes/carts/cart_items/index.js +7 -0
  92. package/demo/routes/carts/index.js +6 -0
  93. package/demo/routes/categories/index.js +6 -0
  94. package/demo/routes/coupons/index.js +6 -0
  95. package/demo/routes/docs.js +18 -0
  96. package/demo/routes/health.js +35 -0
  97. package/demo/routes/index.js +54 -0
  98. package/demo/routes/orders/index.js +6 -0
  99. package/demo/routes/orders/order_items/index.js +7 -0
  100. package/demo/routes/orders/payments/index.js +7 -0
  101. package/demo/routes/orders/shipments/index.js +7 -0
  102. package/demo/routes/products/index.js +6 -0
  103. package/demo/routes/products/product_images/index.js +7 -0
  104. package/demo/routes/products/product_reviews/index.js +7 -0
  105. package/demo/routes/products/product_variants/index.js +7 -0
  106. package/demo/routes/roles/index.js +75 -0
  107. package/demo/routes/roles/permissions/index.js +47 -0
  108. package/demo/routes/tenants/index.js +45 -0
  109. package/demo/routes/users/index.js +45 -0
  110. package/demo/routes/wishlists/index.js +6 -0
  111. package/demo/seeds/saas-seed.js +329 -0
  112. package/docker-compose.yml +61 -0
  113. package/package.json +120 -113
  114. package/scripts/demo-create.js +1 -1
  115. package/skill/SKILL.md +119 -3
  116. package/src/cli/commands/db-manager.js +134 -0
  117. package/src/cli/commands/generate.js +106 -60
  118. package/src/cli/commands/help.js +0 -1
  119. package/src/cli/generate-route.js +60 -21
  120. package/src/cli/generate-saas-structure.js +122 -0
  121. package/src/cli/init/generators.js +6 -0
  122. package/src/cli/init.js +8 -0
  123. package/src/cli/main.js +8 -1
  124. package/src/cli/saas/generate-saas-middleware.js +108 -0
  125. package/src/cli/saas/generate-saas-migrations.js +480 -0
  126. package/src/cli/saas/generate-saas-models.js +211 -0
  127. package/src/cli/saas/generate-saas-openapi.js +419 -0
  128. package/src/cli/saas/generate-saas-routes.js +435 -0
  129. package/src/cli/saas/generate-saas-seeds.js +243 -0
  130. package/src/cli/saas/generate-saas-utils.js +176 -0
  131. package/src/commons/kafka.js +139 -0
  132. package/src/commons/model.js +29 -9
  133. package/src/index.js +2 -0
  134. package/src/mssql/db.js +41 -3
  135. package/src/mysql/db.js +3 -0
  136. package/src/postgres/db.js +6 -0
  137. package/src/cli/generate-db-manager.js +0 -1573
@@ -0,0 +1,1413 @@
1
+ /* DB Manager - Modern Dashboard Theme */
2
+ /* Supports: Light, Dark, System mode */
3
+ /* Typography: Fira Sans (UI) + Fira Code (data/code) */
4
+ /* Design System: Dark Mode OLED + Professional Dashboard */
5
+
6
+ /* === Reset & Base === */
7
+ *,
8
+ *::before,
9
+ *::after {
10
+ box-sizing: border-box;
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+
15
+ /* === Theme Variables === */
16
+ :root {
17
+ /* Light theme (default for system-light) */
18
+ --bg-primary: #F8FAFC;
19
+ --bg-secondary: #FFFFFF;
20
+ --bg-tertiary: #F1F5F9;
21
+ --bg-surface: #F8FAFC;
22
+ --bg-hover: #E2E8F0;
23
+ --bg-input: #FFFFFF;
24
+ --bg-sidebar: #FFFFFF;
25
+ --bg-header: #FFFFFF;
26
+ --text-primary: #0F172A;
27
+ --text-secondary: #475569;
28
+ --text-muted: #94A3B8;
29
+ --border-color: #E2E8F0;
30
+ --border-light: #F1F5F9;
31
+ --accent-green: #22C55E;
32
+ --accent-green-hover: #16A34A;
33
+ --accent-red: #EF4444;
34
+ --accent-red-hover: #DC2626;
35
+ --accent-blue: #3B82F6;
36
+ --accent-blue-hover: #2563EB;
37
+ --accent-purple: #8B5CF6;
38
+ --accent-purple-hover: #7C3AED;
39
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
40
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
41
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
42
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
43
+ --radius: 6px;
44
+ --radius-lg: 10px;
45
+ --radius-xl: 14px;
46
+ --transition: 0.2s ease;
47
+ --font-sans: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
48
+ --font-mono: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace;
49
+ }
50
+
51
+ /* Dark theme */
52
+ [data-theme="dark"] {
53
+ --bg-primary: #020617;
54
+ --bg-secondary: #0F172A;
55
+ --bg-tertiary: #1E293B;
56
+ --bg-surface: #0F172A;
57
+ --bg-hover: #1E293B;
58
+ --bg-input: #0F172A;
59
+ --bg-sidebar: #0F172A;
60
+ --bg-header: #0F172A;
61
+ --text-primary: #F8FAFC;
62
+ --text-secondary: #94A3B8;
63
+ --text-muted: #64748B;
64
+ --border-color: #1E293B;
65
+ --border-light: #334155;
66
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
67
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);
68
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
69
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
70
+ }
71
+
72
+ /* System preference: dark */
73
+ @media (prefers-color-scheme: dark) {
74
+ [data-theme="system"] {
75
+ --bg-primary: #020617;
76
+ --bg-secondary: #0F172A;
77
+ --bg-tertiary: #1E293B;
78
+ --bg-surface: #0F172A;
79
+ --bg-hover: #1E293B;
80
+ --bg-input: #0F172A;
81
+ --bg-sidebar: #0F172A;
82
+ --bg-header: #0F172A;
83
+ --text-primary: #F8FAFC;
84
+ --text-secondary: #94A3B8;
85
+ --text-muted: #64748B;
86
+ --border-color: #1E293B;
87
+ --border-light: #334155;
88
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
89
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);
90
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
91
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
92
+ }
93
+ }
94
+
95
+ html,
96
+ body {
97
+ height: 100%;
98
+ font-family: var(--font-sans);
99
+ font-size: 14px;
100
+ line-height: 1.6;
101
+ background-color: var(--bg-primary);
102
+ color: var(--text-primary);
103
+ -webkit-font-smoothing: antialiased;
104
+ -moz-osx-font-smoothing: grayscale;
105
+ }
106
+
107
+ body {
108
+ display: flex;
109
+ flex-direction: column;
110
+ }
111
+
112
+ @media (prefers-reduced-motion: reduce) {
113
+ * {
114
+ transition-duration: 0.01ms !important;
115
+ animation-duration: 0.01ms !important;
116
+ }
117
+ }
118
+
119
+ /* === Header === */
120
+ .app-header {
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: space-between;
124
+ padding: 0 24px;
125
+ height: 56px;
126
+ background-color: var(--bg-header);
127
+ border-bottom: 1px solid var(--border-color);
128
+ flex-shrink: 0;
129
+ box-shadow: var(--shadow-sm);
130
+ position: sticky;
131
+ top: 0;
132
+ z-index: 50;
133
+ }
134
+
135
+ .app-header h1 {
136
+ font-size: 16px;
137
+ font-weight: 700;
138
+ color: var(--text-primary);
139
+ letter-spacing: -0.02em;
140
+ display: flex;
141
+ align-items: center;
142
+ gap: 8px;
143
+ }
144
+
145
+ .app-header h1::before {
146
+ content: '';
147
+ display: inline-block;
148
+ width: 8px;
149
+ height: 8px;
150
+ border-radius: 50%;
151
+ background-color: var(--accent-green);
152
+ box-shadow: 0 0 6px var(--accent-green);
153
+ }
154
+
155
+ .header-right {
156
+ display: flex;
157
+ align-items: center;
158
+ gap: 16px;
159
+ }
160
+
161
+ .connection-info {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 8px;
165
+ }
166
+
167
+ .connection-info span {
168
+ padding: 4px 10px;
169
+ border-radius: 20px;
170
+ font-size: 11px;
171
+ font-weight: 600;
172
+ letter-spacing: 0.02em;
173
+ text-transform: uppercase;
174
+ }
175
+
176
+ .db-type {
177
+ background-color: var(--accent-purple);
178
+ color: #fff;
179
+ }
180
+
181
+ .db-name {
182
+ background-color: var(--bg-tertiary);
183
+ color: var(--text-primary);
184
+ border: 1px solid var(--border-color);
185
+ }
186
+
187
+ .db-host {
188
+ background-color: var(--bg-tertiary);
189
+ color: var(--text-secondary);
190
+ border: 1px solid var(--border-color);
191
+ }
192
+
193
+ /* === Theme Switcher === */
194
+ .theme-switcher {
195
+ display: flex;
196
+ align-items: center;
197
+ gap: 2px;
198
+ padding: 3px;
199
+ background-color: var(--bg-tertiary);
200
+ border-radius: 8px;
201
+ border: 1px solid var(--border-color);
202
+ }
203
+
204
+ .theme-btn {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ width: 30px;
209
+ height: 28px;
210
+ border: none;
211
+ border-radius: 6px;
212
+ background: transparent;
213
+ color: var(--text-muted);
214
+ cursor: pointer;
215
+ transition: all var(--transition);
216
+ }
217
+
218
+ .theme-btn:hover {
219
+ color: var(--text-primary);
220
+ background-color: var(--bg-hover);
221
+ }
222
+
223
+ .theme-btn.active {
224
+ background-color: var(--bg-secondary);
225
+ color: var(--text-primary);
226
+ box-shadow: var(--shadow-sm);
227
+ }
228
+
229
+ .theme-btn .material-icons {
230
+ font-size: 16px;
231
+ }
232
+
233
+ /* === Main Layout === */
234
+ .app-container {
235
+ display: flex;
236
+ flex: 1;
237
+ overflow: hidden;
238
+ }
239
+
240
+ /* === Sidebar === */
241
+ .sidebar {
242
+ width: 260px;
243
+ min-width: 260px;
244
+ background-color: var(--bg-sidebar);
245
+ border-right: 1px solid var(--border-color);
246
+ overflow-y: auto;
247
+ display: flex;
248
+ flex-direction: column;
249
+ }
250
+
251
+ /* === Sidebar Nav Links === */
252
+ .nav-links {
253
+ display: flex;
254
+ flex-direction: column;
255
+ padding: 12px 8px;
256
+ gap: 2px;
257
+ border-bottom: 1px solid var(--border-color);
258
+ }
259
+
260
+ .nav-link {
261
+ display: flex;
262
+ align-items: center;
263
+ gap: 10px;
264
+ padding: 10px 12px;
265
+ color: var(--text-secondary);
266
+ text-decoration: none;
267
+ font-size: 13px;
268
+ font-weight: 500;
269
+ border-radius: var(--radius);
270
+ transition: background-color var(--transition), color var(--transition);
271
+ cursor: pointer;
272
+ }
273
+
274
+ .nav-link:hover {
275
+ background-color: var(--bg-hover);
276
+ color: var(--text-primary);
277
+ }
278
+
279
+ .nav-link.active {
280
+ background-color: var(--bg-hover);
281
+ color: var(--accent-blue);
282
+ font-weight: 600;
283
+ }
284
+
285
+ .nav-link .material-icons {
286
+ font-size: 18px;
287
+ color: var(--text-muted);
288
+ transition: color var(--transition);
289
+ }
290
+
291
+ .nav-link:hover .material-icons {
292
+ color: var(--text-secondary);
293
+ }
294
+
295
+ .nav-link.active .material-icons {
296
+ color: var(--accent-blue);
297
+ }
298
+
299
+ /* === Sidebar Tables Section === */
300
+ .sidebar-tables {
301
+ flex: 1;
302
+ overflow-y: auto;
303
+ display: flex;
304
+ flex-direction: column;
305
+ }
306
+
307
+ .sidebar-tables-toggle {
308
+ display: flex;
309
+ align-items: center;
310
+ gap: 10px;
311
+ width: 100%;
312
+ padding: 12px 16px;
313
+ background: none;
314
+ border: none;
315
+ color: var(--text-secondary);
316
+ font-size: 11px;
317
+ font-weight: 700;
318
+ text-transform: uppercase;
319
+ letter-spacing: 0.06em;
320
+ cursor: pointer;
321
+ transition: background-color var(--transition), color var(--transition);
322
+ }
323
+
324
+ .sidebar-tables-toggle:hover {
325
+ background-color: var(--bg-hover);
326
+ color: var(--text-primary);
327
+ }
328
+
329
+ .sidebar-tables-toggle .material-icons {
330
+ font-size: 16px;
331
+ }
332
+
333
+ .sidebar-tables-toggle .toggle-arrow {
334
+ margin-left: auto;
335
+ font-size: 18px;
336
+ transition: transform var(--transition);
337
+ }
338
+
339
+ .sidebar-tables-toggle[aria-expanded="false"] .toggle-arrow {
340
+ transform: rotate(-90deg);
341
+ }
342
+
343
+ .sidebar-tables-content {
344
+ padding: 0 8px 12px;
345
+ flex: 1;
346
+ overflow-y: auto;
347
+ }
348
+
349
+ .sidebar-tables-toggle[aria-expanded="false"] + .sidebar-tables-content {
350
+ display: none;
351
+ }
352
+
353
+ /* === Table Search === */
354
+ .table-search {
355
+ width: 100%;
356
+ padding: 8px 12px;
357
+ margin-bottom: 8px;
358
+ background-color: var(--bg-input);
359
+ border: 1px solid var(--border-color);
360
+ border-radius: var(--radius);
361
+ color: var(--text-primary);
362
+ font-family: var(--font-sans);
363
+ font-size: 13px;
364
+ outline: none;
365
+ transition: border-color var(--transition), box-shadow var(--transition);
366
+ }
367
+
368
+ .table-search:focus {
369
+ border-color: var(--accent-blue);
370
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
371
+ }
372
+
373
+ .table-search::placeholder {
374
+ color: var(--text-muted);
375
+ }
376
+
377
+ /* === Table List === */
378
+ .table-list,
379
+ .history-list {
380
+ list-style: none;
381
+ max-height: 400px;
382
+ overflow-y: auto;
383
+ }
384
+
385
+ .table-list li,
386
+ .history-list li {
387
+ padding: 7px 12px;
388
+ border-radius: var(--radius);
389
+ cursor: pointer;
390
+ font-size: 13px;
391
+ font-family: var(--font-mono);
392
+ color: var(--text-secondary);
393
+ transition: background-color var(--transition), color var(--transition);
394
+ }
395
+
396
+ .table-list li:hover,
397
+ .history-list li:hover {
398
+ background-color: var(--bg-hover);
399
+ color: var(--text-primary);
400
+ }
401
+
402
+ .table-list li.active {
403
+ background-color: var(--bg-hover);
404
+ color: var(--accent-blue);
405
+ font-weight: 500;
406
+ }
407
+
408
+ /* === Data Panel === */
409
+ .data-panel {
410
+ flex: 1;
411
+ display: flex;
412
+ flex-direction: column;
413
+ overflow: hidden;
414
+ background-color: var(--bg-primary);
415
+ }
416
+
417
+ .data-panel-content {
418
+ display: flex;
419
+ flex-direction: column;
420
+ flex: 1;
421
+ padding: 20px 24px;
422
+ overflow: hidden;
423
+ }
424
+
425
+ /* === Data Toolbar === */
426
+ .data-toolbar {
427
+ display: flex;
428
+ align-items: center;
429
+ gap: 8px;
430
+ margin-bottom: 16px;
431
+ flex-shrink: 0;
432
+ justify-content: flex-end;
433
+ }
434
+
435
+ /* === Buttons === */
436
+ .btn {
437
+ display: inline-flex;
438
+ align-items: center;
439
+ gap: 6px;
440
+ padding: 8px 14px;
441
+ border: none;
442
+ border-radius: var(--radius);
443
+ font-family: var(--font-sans);
444
+ font-size: 13px;
445
+ font-weight: 500;
446
+ cursor: pointer;
447
+ transition: all var(--transition);
448
+ color: #fff;
449
+ white-space: nowrap;
450
+ }
451
+
452
+ .btn:disabled {
453
+ opacity: 0.4;
454
+ cursor: not-allowed;
455
+ }
456
+
457
+ .btn .material-icons {
458
+ font-size: 16px;
459
+ }
460
+
461
+ .btn-add {
462
+ background-color: var(--accent-green);
463
+ }
464
+
465
+ .btn-add:hover:not(:disabled) {
466
+ background-color: var(--accent-green-hover);
467
+ box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
468
+ }
469
+
470
+ .btn-delete {
471
+ background-color: var(--accent-red);
472
+ }
473
+
474
+ .btn-delete:hover:not(:disabled) {
475
+ background-color: var(--accent-red-hover);
476
+ box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
477
+ }
478
+
479
+ .btn-export {
480
+ background-color: var(--accent-blue);
481
+ }
482
+
483
+ .btn-export:hover:not(:disabled) {
484
+ background-color: var(--accent-blue-hover);
485
+ box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
486
+ }
487
+
488
+ .btn-filter {
489
+ background-color: var(--bg-tertiary);
490
+ color: var(--text-primary);
491
+ border: 1px solid var(--border-color);
492
+ }
493
+
494
+ .btn-filter:hover:not(:disabled) {
495
+ background-color: var(--bg-hover);
496
+ border-color: var(--accent-blue);
497
+ color: var(--accent-blue);
498
+ }
499
+
500
+ .btn-prev,
501
+ .btn-next {
502
+ background-color: var(--bg-tertiary);
503
+ color: var(--text-primary);
504
+ border: 1px solid var(--border-color);
505
+ padding: 6px 12px;
506
+ }
507
+
508
+ .btn-prev:hover:not(:disabled),
509
+ .btn-next:hover:not(:disabled) {
510
+ background-color: var(--accent-blue);
511
+ border-color: var(--accent-blue);
512
+ color: #fff;
513
+ }
514
+
515
+ /* === Data Table === */
516
+ .data-table-wrapper {
517
+ flex: 1;
518
+ overflow: auto;
519
+ border: 1px solid var(--border-color);
520
+ border-radius: var(--radius-lg);
521
+ box-shadow: var(--shadow-sm);
522
+ }
523
+
524
+ .data-table {
525
+ width: 100%;
526
+ border-collapse: collapse;
527
+ font-size: 13px;
528
+ }
529
+
530
+ .data-table thead {
531
+ position: sticky;
532
+ top: 0;
533
+ z-index: 1;
534
+ }
535
+
536
+ .data-table th {
537
+ padding: 11px 14px;
538
+ background-color: var(--bg-tertiary);
539
+ color: var(--text-secondary);
540
+ font-weight: 600;
541
+ font-size: 11px;
542
+ text-align: left;
543
+ text-transform: uppercase;
544
+ letter-spacing: 0.04em;
545
+ border-bottom: 1px solid var(--border-color);
546
+ white-space: nowrap;
547
+ user-select: none;
548
+ }
549
+
550
+ .data-table td {
551
+ padding: 10px 14px;
552
+ border-bottom: 1px solid var(--border-color);
553
+ color: var(--text-primary);
554
+ font-family: var(--font-mono);
555
+ font-size: 12px;
556
+ white-space: nowrap;
557
+ max-width: 300px;
558
+ overflow: hidden;
559
+ text-overflow: ellipsis;
560
+ }
561
+
562
+ .data-table tbody tr {
563
+ transition: background-color var(--transition);
564
+ }
565
+
566
+ .data-table tbody tr:nth-child(even) {
567
+ background-color: var(--bg-surface);
568
+ }
569
+
570
+ .data-table tbody tr:nth-child(odd) {
571
+ background-color: transparent;
572
+ }
573
+
574
+ .data-table tbody tr:hover {
575
+ background-color: var(--bg-hover);
576
+ }
577
+
578
+ .data-table tbody tr.selected {
579
+ background-color: rgba(59, 130, 246, 0.08);
580
+ }
581
+
582
+ /* Checkbox column */
583
+ .data-table th:first-child,
584
+ .data-table td:first-child {
585
+ width: 40px;
586
+ text-align: center;
587
+ }
588
+
589
+ .data-table input[type="checkbox"] {
590
+ accent-color: var(--accent-blue);
591
+ cursor: pointer;
592
+ width: 15px;
593
+ height: 15px;
594
+ }
595
+
596
+ /* === Pagination === */
597
+ .pagination-controls {
598
+ display: flex;
599
+ align-items: center;
600
+ gap: 12px;
601
+ margin-top: 16px;
602
+ flex-shrink: 0;
603
+ }
604
+
605
+ .page-info {
606
+ font-size: 13px;
607
+ color: var(--text-secondary);
608
+ font-weight: 500;
609
+ }
610
+
611
+ .page-size {
612
+ margin-left: auto;
613
+ padding: 6px 10px;
614
+ background-color: var(--bg-input);
615
+ border: 1px solid var(--border-color);
616
+ border-radius: var(--radius);
617
+ color: var(--text-primary);
618
+ font-family: var(--font-sans);
619
+ font-size: 13px;
620
+ cursor: pointer;
621
+ outline: none;
622
+ transition: border-color var(--transition);
623
+ }
624
+
625
+ .page-size:focus {
626
+ border-color: var(--accent-blue);
627
+ }
628
+
629
+ /* === Forms (Add/Edit Row) === */
630
+ .row-form {
631
+ padding: 20px;
632
+ background-color: var(--bg-secondary);
633
+ border: 1px solid var(--border-color);
634
+ border-radius: var(--radius-lg);
635
+ margin-bottom: 16px;
636
+ box-shadow: var(--shadow);
637
+ }
638
+
639
+ .row-form h3 {
640
+ margin-bottom: 16px;
641
+ font-size: 14px;
642
+ font-weight: 600;
643
+ color: var(--text-primary);
644
+ }
645
+
646
+ .form-grid {
647
+ display: grid;
648
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
649
+ gap: 14px;
650
+ }
651
+
652
+ .form-field {
653
+ display: flex;
654
+ flex-direction: column;
655
+ gap: 4px;
656
+ }
657
+
658
+ .form-field label {
659
+ font-size: 11px;
660
+ font-weight: 600;
661
+ color: var(--text-secondary);
662
+ text-transform: uppercase;
663
+ letter-spacing: 0.04em;
664
+ }
665
+
666
+ .form-field input,
667
+ .form-field select,
668
+ .form-field textarea {
669
+ padding: 8px 12px;
670
+ background-color: var(--bg-input);
671
+ border: 1px solid var(--border-color);
672
+ border-radius: var(--radius);
673
+ color: var(--text-primary);
674
+ font-family: var(--font-mono);
675
+ font-size: 13px;
676
+ outline: none;
677
+ transition: border-color var(--transition), box-shadow var(--transition);
678
+ }
679
+
680
+ .form-field input:focus,
681
+ .form-field select:focus,
682
+ .form-field textarea:focus {
683
+ border-color: var(--accent-blue);
684
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
685
+ }
686
+
687
+ .form-actions {
688
+ display: flex;
689
+ gap: 8px;
690
+ margin-top: 16px;
691
+ }
692
+
693
+ .btn-save {
694
+ background-color: var(--accent-green);
695
+ }
696
+
697
+ .btn-save:hover:not(:disabled) {
698
+ background-color: var(--accent-green-hover);
699
+ }
700
+
701
+ .btn-cancel {
702
+ background-color: var(--bg-tertiary);
703
+ color: var(--text-primary);
704
+ border: 1px solid var(--border-color);
705
+ }
706
+
707
+ .btn-cancel:hover:not(:disabled) {
708
+ background-color: var(--bg-hover);
709
+ }
710
+
711
+ /* Inline edit inputs in table cells */
712
+ .data-table td input {
713
+ width: 100%;
714
+ padding: 4px 8px;
715
+ background-color: var(--bg-input);
716
+ border: 1px solid var(--accent-blue);
717
+ border-radius: var(--radius);
718
+ color: var(--text-primary);
719
+ font-family: var(--font-mono);
720
+ font-size: 12px;
721
+ outline: none;
722
+ }
723
+
724
+ .data-table .row-actions {
725
+ display: flex;
726
+ gap: 4px;
727
+ }
728
+
729
+ .btn-edit,
730
+ .btn-row-save,
731
+ .btn-row-cancel,
732
+ .btn-row-delete {
733
+ display: inline-flex;
734
+ align-items: center;
735
+ justify-content: center;
736
+ padding: 5px 8px;
737
+ font-size: 12px;
738
+ border: none;
739
+ border-radius: var(--radius);
740
+ cursor: pointer;
741
+ color: #fff;
742
+ transition: all var(--transition);
743
+ }
744
+
745
+ .btn-edit {
746
+ background-color: var(--bg-tertiary);
747
+ color: var(--text-secondary);
748
+ border: 1px solid var(--border-color);
749
+ }
750
+
751
+ .btn-edit:hover {
752
+ background-color: var(--accent-blue);
753
+ border-color: var(--accent-blue);
754
+ color: #fff;
755
+ }
756
+
757
+ .btn-row-save {
758
+ background-color: var(--accent-green);
759
+ }
760
+
761
+ .btn-row-save:hover {
762
+ background-color: var(--accent-green-hover);
763
+ }
764
+
765
+ .btn-row-cancel {
766
+ background-color: var(--bg-tertiary);
767
+ color: var(--text-secondary);
768
+ border: 1px solid var(--border-color);
769
+ }
770
+
771
+ .btn-row-cancel:hover {
772
+ background-color: var(--accent-red);
773
+ border-color: var(--accent-red);
774
+ color: #fff;
775
+ }
776
+
777
+ .btn-row-delete {
778
+ background-color: transparent;
779
+ color: var(--text-muted);
780
+ border: 1px solid transparent;
781
+ }
782
+
783
+ .btn-row-delete:hover {
784
+ background-color: var(--accent-red);
785
+ color: #fff;
786
+ }
787
+
788
+ .btn-edit .material-icons,
789
+ .btn-row-delete .material-icons {
790
+ font-size: 15px;
791
+ }
792
+
793
+ /* === Toast Messages === */
794
+ .toast-container {
795
+ position: fixed;
796
+ top: 16px;
797
+ right: 16px;
798
+ z-index: 1000;
799
+ display: flex;
800
+ flex-direction: column;
801
+ gap: 8px;
802
+ }
803
+
804
+ .toast {
805
+ padding: 12px 20px;
806
+ border-radius: var(--radius-lg);
807
+ font-size: 13px;
808
+ font-weight: 500;
809
+ color: #fff;
810
+ box-shadow: var(--shadow-lg);
811
+ animation: toast-in 0.3s ease;
812
+ backdrop-filter: blur(8px);
813
+ }
814
+
815
+ .toast-success {
816
+ background-color: var(--accent-green);
817
+ }
818
+
819
+ .toast-error {
820
+ background-color: var(--accent-red);
821
+ }
822
+
823
+ @keyframes toast-in {
824
+ from {
825
+ opacity: 0;
826
+ transform: translateY(-8px) scale(0.96);
827
+ }
828
+ to {
829
+ opacity: 1;
830
+ transform: translateY(0) scale(1);
831
+ }
832
+ }
833
+
834
+ /* === Scrollbar Styling === */
835
+ ::-webkit-scrollbar {
836
+ width: 6px;
837
+ height: 6px;
838
+ }
839
+
840
+ ::-webkit-scrollbar-track {
841
+ background: transparent;
842
+ }
843
+
844
+ ::-webkit-scrollbar-thumb {
845
+ background: var(--border-light);
846
+ border-radius: 3px;
847
+ }
848
+
849
+ ::-webkit-scrollbar-thumb:hover {
850
+ background: var(--text-muted);
851
+ }
852
+
853
+ /* === Empty State === */
854
+ .empty-state {
855
+ display: flex;
856
+ align-items: center;
857
+ justify-content: center;
858
+ flex: 1;
859
+ color: var(--text-muted);
860
+ font-size: 15px;
861
+ flex-direction: column;
862
+ gap: 8px;
863
+ }
864
+
865
+ /* === Sort Indicators === */
866
+ .sortable {
867
+ cursor: pointer;
868
+ }
869
+
870
+ .sortable:hover {
871
+ color: var(--text-primary);
872
+ }
873
+
874
+ .sort-icon {
875
+ font-size: 13px;
876
+ vertical-align: middle;
877
+ color: var(--accent-blue);
878
+ margin-left: 2px;
879
+ }
880
+
881
+ /* === Filter Tags === */
882
+ .filter-tags {
883
+ display: flex;
884
+ flex-wrap: wrap;
885
+ gap: 6px;
886
+ margin-bottom: 10px;
887
+ min-height: 0;
888
+ }
889
+
890
+ .filter-tag {
891
+ display: inline-flex;
892
+ align-items: center;
893
+ gap: 6px;
894
+ padding: 4px 10px;
895
+ background-color: var(--bg-tertiary);
896
+ border: 1px solid var(--border-color);
897
+ border-radius: 20px;
898
+ font-size: 12px;
899
+ font-family: var(--font-mono);
900
+ color: var(--text-primary);
901
+ }
902
+
903
+ .filter-tag-text {
904
+ max-width: 200px;
905
+ overflow: hidden;
906
+ text-overflow: ellipsis;
907
+ white-space: nowrap;
908
+ }
909
+
910
+ .filter-tag-remove {
911
+ display: flex;
912
+ align-items: center;
913
+ justify-content: center;
914
+ width: 16px;
915
+ height: 16px;
916
+ border: none;
917
+ background: none;
918
+ color: var(--text-muted);
919
+ cursor: pointer;
920
+ border-radius: 50%;
921
+ font-size: 14px;
922
+ line-height: 1;
923
+ padding: 0;
924
+ transition: all var(--transition);
925
+ }
926
+
927
+ .filter-tag-remove:hover {
928
+ color: var(--accent-red);
929
+ background-color: rgba(239, 68, 68, 0.1);
930
+ }
931
+
932
+ /* === Filter Modal === */
933
+ .filter-modal-overlay {
934
+ position: fixed;
935
+ top: 0;
936
+ left: 0;
937
+ right: 0;
938
+ bottom: 0;
939
+ background-color: rgba(0, 0, 0, 0.5);
940
+ backdrop-filter: blur(4px);
941
+ z-index: 1000;
942
+ display: flex;
943
+ align-items: center;
944
+ justify-content: center;
945
+ animation: fade-in 0.15s ease;
946
+ }
947
+
948
+ @keyframes fade-in {
949
+ from { opacity: 0; }
950
+ to { opacity: 1; }
951
+ }
952
+
953
+ .filter-modal {
954
+ background-color: var(--bg-secondary);
955
+ border: 1px solid var(--border-color);
956
+ border-radius: var(--radius-xl);
957
+ width: 500px;
958
+ max-width: 90vw;
959
+ box-shadow: var(--shadow-lg);
960
+ animation: modal-in 0.2s ease;
961
+ }
962
+
963
+ @keyframes modal-in {
964
+ from {
965
+ opacity: 0;
966
+ transform: scale(0.96) translateY(8px);
967
+ }
968
+ to {
969
+ opacity: 1;
970
+ transform: scale(1) translateY(0);
971
+ }
972
+ }
973
+
974
+ .filter-modal-header {
975
+ display: flex;
976
+ align-items: center;
977
+ justify-content: space-between;
978
+ padding: 16px 20px;
979
+ border-bottom: 1px solid var(--border-color);
980
+ }
981
+
982
+ .filter-modal-header h3 {
983
+ font-size: 15px;
984
+ font-weight: 600;
985
+ color: var(--text-primary);
986
+ margin: 0;
987
+ }
988
+
989
+ .filter-modal-close {
990
+ background: none;
991
+ border: none;
992
+ color: var(--text-muted);
993
+ cursor: pointer;
994
+ padding: 4px;
995
+ border-radius: var(--radius);
996
+ transition: all var(--transition);
997
+ }
998
+
999
+ .filter-modal-close:hover {
1000
+ color: var(--text-primary);
1001
+ background-color: var(--bg-hover);
1002
+ }
1003
+
1004
+ .filter-modal-body {
1005
+ padding: 20px;
1006
+ }
1007
+
1008
+ .filter-modal-row {
1009
+ display: flex;
1010
+ gap: 8px;
1011
+ align-items: center;
1012
+ }
1013
+
1014
+ .filter-col-select,
1015
+ .filter-op-select {
1016
+ padding: 8px 12px;
1017
+ background-color: var(--bg-input);
1018
+ border: 1px solid var(--border-color);
1019
+ border-radius: var(--radius);
1020
+ color: var(--text-primary);
1021
+ font-family: var(--font-sans);
1022
+ font-size: 13px;
1023
+ outline: none;
1024
+ transition: border-color var(--transition);
1025
+ }
1026
+
1027
+ .filter-col-select:focus,
1028
+ .filter-op-select:focus {
1029
+ border-color: var(--accent-blue);
1030
+ }
1031
+
1032
+ .filter-col-select {
1033
+ flex: 1.5;
1034
+ }
1035
+
1036
+ .filter-op-select {
1037
+ flex: 1;
1038
+ }
1039
+
1040
+ .filter-val-input {
1041
+ flex: 2;
1042
+ padding: 8px 12px;
1043
+ background-color: var(--bg-input);
1044
+ border: 1px solid var(--border-color);
1045
+ border-radius: var(--radius);
1046
+ color: var(--text-primary);
1047
+ font-family: var(--font-mono);
1048
+ font-size: 13px;
1049
+ outline: none;
1050
+ transition: border-color var(--transition);
1051
+ }
1052
+
1053
+ .filter-val-input:focus {
1054
+ border-color: var(--accent-blue);
1055
+ }
1056
+
1057
+ .btn-filter-add {
1058
+ padding: 8px;
1059
+ background-color: var(--accent-green);
1060
+ border: none;
1061
+ border-radius: var(--radius);
1062
+ color: #fff;
1063
+ cursor: pointer;
1064
+ display: flex;
1065
+ align-items: center;
1066
+ transition: all var(--transition);
1067
+ }
1068
+
1069
+ .btn-filter-add:hover {
1070
+ background-color: var(--accent-green-hover);
1071
+ box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
1072
+ }
1073
+
1074
+ .btn-filter-add .material-icons {
1075
+ font-size: 18px;
1076
+ margin: 0;
1077
+ }
1078
+
1079
+ /* === Query Page === */
1080
+ .query-content {
1081
+ display: flex;
1082
+ flex-direction: column;
1083
+ flex: 1;
1084
+ padding: 20px 24px;
1085
+ gap: 14px;
1086
+ overflow: hidden;
1087
+ }
1088
+
1089
+ .query-editor {
1090
+ width: 100%;
1091
+ min-height: 140px;
1092
+ max-height: 220px;
1093
+ padding: 16px;
1094
+ background-color: var(--bg-secondary);
1095
+ border: 1px solid var(--border-color);
1096
+ border-radius: var(--radius-lg);
1097
+ color: var(--text-primary);
1098
+ font-family: var(--font-mono);
1099
+ font-size: 13px;
1100
+ line-height: 1.6;
1101
+ resize: vertical;
1102
+ outline: none;
1103
+ transition: border-color var(--transition), box-shadow var(--transition);
1104
+ }
1105
+
1106
+ .query-editor:focus {
1107
+ border-color: var(--accent-blue);
1108
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
1109
+ }
1110
+
1111
+ .query-editor::placeholder {
1112
+ color: var(--text-muted);
1113
+ }
1114
+
1115
+ .query-actions {
1116
+ display: flex;
1117
+ gap: 8px;
1118
+ flex-shrink: 0;
1119
+ }
1120
+
1121
+ .btn-run {
1122
+ background-color: var(--accent-green);
1123
+ }
1124
+
1125
+ .btn-run:hover:not(:disabled) {
1126
+ background-color: var(--accent-green-hover);
1127
+ box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
1128
+ }
1129
+
1130
+ .btn-export-query {
1131
+ background-color: var(--accent-blue);
1132
+ }
1133
+
1134
+ .btn-export-query:hover:not(:disabled) {
1135
+ background-color: var(--accent-blue-hover);
1136
+ }
1137
+
1138
+ .query-error {
1139
+ padding: 12px 16px;
1140
+ background-color: rgba(239, 68, 68, 0.08);
1141
+ border: 1px solid rgba(239, 68, 68, 0.3);
1142
+ border-radius: var(--radius);
1143
+ color: var(--accent-red);
1144
+ font-family: var(--font-mono);
1145
+ font-size: 13px;
1146
+ }
1147
+
1148
+ .query-results-wrapper {
1149
+ flex: 1;
1150
+ overflow: auto;
1151
+ border: 1px solid var(--border-color);
1152
+ border-radius: var(--radius-lg);
1153
+ box-shadow: var(--shadow-sm);
1154
+ }
1155
+
1156
+ .query-results-table {
1157
+ width: 100%;
1158
+ border-collapse: collapse;
1159
+ font-size: 13px;
1160
+ }
1161
+
1162
+ .query-results-table th {
1163
+ padding: 11px 14px;
1164
+ background-color: var(--bg-tertiary);
1165
+ color: var(--text-secondary);
1166
+ font-weight: 600;
1167
+ font-size: 11px;
1168
+ text-align: left;
1169
+ text-transform: uppercase;
1170
+ letter-spacing: 0.04em;
1171
+ border-bottom: 1px solid var(--border-color);
1172
+ white-space: nowrap;
1173
+ }
1174
+
1175
+ .query-results-table td {
1176
+ padding: 10px 14px;
1177
+ border-bottom: 1px solid var(--border-color);
1178
+ color: var(--text-primary);
1179
+ font-family: var(--font-mono);
1180
+ font-size: 12px;
1181
+ white-space: nowrap;
1182
+ max-width: 300px;
1183
+ overflow: hidden;
1184
+ text-overflow: ellipsis;
1185
+ }
1186
+
1187
+ .query-results-table tbody tr:nth-child(even) {
1188
+ background-color: var(--bg-surface);
1189
+ }
1190
+
1191
+ .query-results-table tbody tr:hover {
1192
+ background-color: var(--bg-hover);
1193
+ }
1194
+
1195
+ /* === Dashboard Page === */
1196
+ .dashboard-content {
1197
+ display: flex;
1198
+ flex-direction: column;
1199
+ flex: 1;
1200
+ padding: 20px 24px;
1201
+ overflow-y: auto;
1202
+ }
1203
+
1204
+ .dashboard-title {
1205
+ font-size: 18px;
1206
+ font-weight: 700;
1207
+ color: var(--text-primary);
1208
+ margin-bottom: 20px;
1209
+ letter-spacing: -0.02em;
1210
+ }
1211
+
1212
+ .dashboard-table-wrapper {
1213
+ flex: 1;
1214
+ overflow: auto;
1215
+ border: 1px solid var(--border-color);
1216
+ border-radius: var(--radius-lg);
1217
+ box-shadow: var(--shadow-sm);
1218
+ }
1219
+
1220
+ .dashboard-table {
1221
+ width: 100%;
1222
+ border-collapse: collapse;
1223
+ font-size: 13px;
1224
+ }
1225
+
1226
+ .dashboard-table th {
1227
+ padding: 12px 16px;
1228
+ background-color: var(--bg-tertiary);
1229
+ color: var(--text-secondary);
1230
+ font-weight: 600;
1231
+ font-size: 11px;
1232
+ text-align: left;
1233
+ text-transform: uppercase;
1234
+ letter-spacing: 0.04em;
1235
+ border-bottom: 1px solid var(--border-color);
1236
+ white-space: nowrap;
1237
+ }
1238
+
1239
+ .dashboard-table td {
1240
+ padding: 12px 16px;
1241
+ border-bottom: 1px solid var(--border-color);
1242
+ color: var(--text-primary);
1243
+ font-family: var(--font-mono);
1244
+ font-size: 12px;
1245
+ white-space: nowrap;
1246
+ }
1247
+
1248
+ .dashboard-table tbody tr:nth-child(even) {
1249
+ background-color: var(--bg-surface);
1250
+ }
1251
+
1252
+ .dashboard-row {
1253
+ cursor: pointer;
1254
+ transition: background-color var(--transition);
1255
+ }
1256
+
1257
+ .dashboard-row:hover {
1258
+ background-color: var(--bg-hover) !important;
1259
+ }
1260
+
1261
+ .dashboard-table-name {
1262
+ font-weight: 600;
1263
+ color: var(--accent-blue);
1264
+ }
1265
+
1266
+ /* === History Page === */
1267
+ .history-content {
1268
+ display: flex;
1269
+ flex-direction: column;
1270
+ flex: 1;
1271
+ padding: 20px 24px;
1272
+ overflow-y: auto;
1273
+ }
1274
+
1275
+ .history-title {
1276
+ font-size: 18px;
1277
+ font-weight: 700;
1278
+ color: var(--text-primary);
1279
+ margin-bottom: 20px;
1280
+ letter-spacing: -0.02em;
1281
+ }
1282
+
1283
+ .history-table-wrapper {
1284
+ flex: 1;
1285
+ overflow: auto;
1286
+ border: 1px solid var(--border-color);
1287
+ border-radius: var(--radius-lg);
1288
+ box-shadow: var(--shadow-sm);
1289
+ }
1290
+
1291
+ .history-table {
1292
+ width: 100%;
1293
+ border-collapse: collapse;
1294
+ font-size: 13px;
1295
+ }
1296
+
1297
+ .history-table th {
1298
+ padding: 12px 16px;
1299
+ background-color: var(--bg-tertiary);
1300
+ color: var(--text-secondary);
1301
+ font-weight: 600;
1302
+ font-size: 11px;
1303
+ text-align: left;
1304
+ text-transform: uppercase;
1305
+ letter-spacing: 0.04em;
1306
+ border-bottom: 1px solid var(--border-color);
1307
+ white-space: nowrap;
1308
+ }
1309
+
1310
+ .history-table td {
1311
+ padding: 12px 16px;
1312
+ border-bottom: 1px solid var(--border-color);
1313
+ color: var(--text-primary);
1314
+ }
1315
+
1316
+ .history-table tbody tr:nth-child(even) {
1317
+ background-color: var(--bg-surface);
1318
+ }
1319
+
1320
+ .history-table tbody tr:hover {
1321
+ background-color: var(--bg-hover);
1322
+ }
1323
+
1324
+ .history-query-text {
1325
+ max-width: 500px;
1326
+ overflow: hidden;
1327
+ text-overflow: ellipsis;
1328
+ white-space: nowrap;
1329
+ font-family: var(--font-mono);
1330
+ font-size: 12px;
1331
+ }
1332
+
1333
+ /* === Accordion (legacy support) === */
1334
+ .accordion {
1335
+ display: flex;
1336
+ flex-direction: column;
1337
+ flex: 1;
1338
+ }
1339
+
1340
+ .accordion-section {
1341
+ border-bottom: 1px solid var(--border-color);
1342
+ }
1343
+
1344
+ .accordion-toggle {
1345
+ display: flex;
1346
+ align-items: center;
1347
+ width: 100%;
1348
+ padding: 12px 16px;
1349
+ background: none;
1350
+ border: none;
1351
+ color: var(--text-primary);
1352
+ font-size: 13px;
1353
+ font-weight: 600;
1354
+ text-transform: uppercase;
1355
+ letter-spacing: 0.5px;
1356
+ cursor: pointer;
1357
+ transition: background-color var(--transition);
1358
+ }
1359
+
1360
+ .accordion-toggle:hover {
1361
+ background-color: var(--bg-hover);
1362
+ }
1363
+
1364
+ .accordion-toggle::before {
1365
+ content: "\25B6";
1366
+ display: inline-block;
1367
+ margin-right: 8px;
1368
+ font-size: 10px;
1369
+ transition: transform var(--transition);
1370
+ }
1371
+
1372
+ .accordion-toggle[aria-expanded="true"]::before {
1373
+ transform: rotate(90deg);
1374
+ }
1375
+
1376
+ .accordion-content {
1377
+ display: none;
1378
+ padding: 0 12px 12px;
1379
+ }
1380
+
1381
+ .accordion-toggle[aria-expanded="true"] + .accordion-content {
1382
+ display: block;
1383
+ }
1384
+
1385
+ /* === Filter Bar (legacy) === */
1386
+ .filter-bar {
1387
+ display: flex;
1388
+ gap: 4px;
1389
+ margin-bottom: 8px;
1390
+ flex-shrink: 0;
1391
+ overflow-x: auto;
1392
+ }
1393
+
1394
+ .filter-input {
1395
+ flex: 1;
1396
+ min-width: 80px;
1397
+ padding: 6px 10px;
1398
+ background-color: var(--bg-input);
1399
+ border: 1px solid var(--border-color);
1400
+ border-radius: var(--radius);
1401
+ color: var(--text-primary);
1402
+ font-size: 12px;
1403
+ outline: none;
1404
+ transition: border-color var(--transition);
1405
+ }
1406
+
1407
+ .filter-input:focus {
1408
+ border-color: var(--accent-blue);
1409
+ }
1410
+
1411
+ .filter-input::placeholder {
1412
+ color: var(--text-muted);
1413
+ }