@libredb/studio 0.9.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 (572) hide show
  1. package/.claude/settings.local.json +127 -0
  2. package/.cursorrules +426 -0
  3. package/.devin/wiki.json +143 -0
  4. package/.dockerignore +80 -0
  5. package/.env.example +159 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +49 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
  8. package/.github/PULL_REQUEST_TEMPLATE.md +57 -0
  9. package/.github/workflows/ci.yml +185 -0
  10. package/.github/workflows/codeql.yml +57 -0
  11. package/.github/workflows/docker-build-push.yml +118 -0
  12. package/.github/workflows/helm-release.yml +113 -0
  13. package/CLAUDE.md +265 -0
  14. package/CODE_OF_CONDUCT.md +124 -0
  15. package/CONTRIBUTING.md +154 -0
  16. package/Dockerfile +73 -0
  17. package/LICENSE +21 -0
  18. package/README.md +614 -0
  19. package/SECURITY.md +107 -0
  20. package/artifacthub-repo.yml +4 -0
  21. package/bun.lock +1714 -0
  22. package/bunfig.toml +3 -0
  23. package/charts/libredb-studio/.helmignore +11 -0
  24. package/charts/libredb-studio/Chart.lock +6 -0
  25. package/charts/libredb-studio/Chart.yaml +50 -0
  26. package/charts/libredb-studio/README.md +206 -0
  27. package/charts/libredb-studio/templates/NOTES.txt +59 -0
  28. package/charts/libredb-studio/templates/_helpers.tpl +135 -0
  29. package/charts/libredb-studio/templates/configmap.yaml +37 -0
  30. package/charts/libredb-studio/templates/deployment.yaml +184 -0
  31. package/charts/libredb-studio/templates/hpa.yaml +32 -0
  32. package/charts/libredb-studio/templates/ingress.yaml +41 -0
  33. package/charts/libredb-studio/templates/networkpolicy.yaml +50 -0
  34. package/charts/libredb-studio/templates/pdb.yaml +18 -0
  35. package/charts/libredb-studio/templates/pvc.yaml +23 -0
  36. package/charts/libredb-studio/templates/secret.yaml +30 -0
  37. package/charts/libredb-studio/templates/seed-configmap.yaml +11 -0
  38. package/charts/libredb-studio/templates/service.yaml +22 -0
  39. package/charts/libredb-studio/templates/serviceaccount.yaml +13 -0
  40. package/charts/libredb-studio/values.schema.json +246 -0
  41. package/charts/libredb-studio/values.yaml +286 -0
  42. package/components.json +22 -0
  43. package/conductor/code_styleguides/typescript.md +43 -0
  44. package/conductor/product-guidelines.md +43 -0
  45. package/conductor/product.md +3 -0
  46. package/conductor/setup_state.json +1 -0
  47. package/conductor/tech-stack.md +39 -0
  48. package/conductor/tracks/enhance_postgres_monitoring_20251227/metadata.json +8 -0
  49. package/conductor/tracks/enhance_postgres_monitoring_20251227/plan.md +44 -0
  50. package/conductor/tracks/enhance_postgres_monitoring_20251227/spec.md +31 -0
  51. package/conductor/tracks.md +8 -0
  52. package/conductor/workflow.md +333 -0
  53. package/database-compose.yml +55 -0
  54. package/docker/postgres-init/01-extensions.sql +10 -0
  55. package/docker/postgres-init/02-sample-data.sql +585 -0
  56. package/docker/postgres.yml +68 -0
  57. package/docker-compose.yml +38 -0
  58. package/docs/AI_PLAN.md +74 -0
  59. package/docs/API_DOCS.md +875 -0
  60. package/docs/ARCHITECTURE.md +218 -0
  61. package/docs/DATABASE_PROVIDERS.md +358 -0
  62. package/docs/FEATURES.md +116 -0
  63. package/docs/HELM_CHART.md +252 -0
  64. package/docs/LOGIN_PAGE.md +178 -0
  65. package/docs/MONACO_EDITOR_PERFORMANCE.md +315 -0
  66. package/docs/OIDC_ARCH.md +681 -0
  67. package/docs/OIDC_SETUP.md +322 -0
  68. package/docs/POSTGRES_METRICS.md +516 -0
  69. package/docs/QUERY_OPTIMIZATION.md +370 -0
  70. package/docs/SEED_CONNECTIONS.md +468 -0
  71. package/docs/SQL_ALIAS_COMPLETION.md +190 -0
  72. package/docs/STORAGE_ARCHITECTURE.md +565 -0
  73. package/docs/STORAGE_QUICK_SETUP.md +419 -0
  74. package/docs/TECHNICAL_PLAN.md +36 -0
  75. package/docs/THEMING.md +345 -0
  76. package/docs/adding-a-new-database-provider.md +642 -0
  77. package/docs/backlogs/000-PLATFORM_DATA_SYNC_DATABASE.md +360 -0
  78. package/docs/backlogs/001-INLINE_DATA_EDITING.md +118 -0
  79. package/docs/backlogs/002-DATA_IMPORT.md +215 -0
  80. package/docs/backlogs/003-QUERY_TIME_MACHINE.md +183 -0
  81. package/docs/backlogs/004-AI_DATA_STORYTELLER.md +292 -0
  82. package/docs/backlogs/005-QUERY_PLAYGROUND.md +352 -0
  83. package/docs/backlogs/006-DATA_MASKING.md +418 -0
  84. package/docs/enterprise-features.md +718 -0
  85. package/docs/kubernetes-helm-chart-artifacthub-plan.md +803 -0
  86. package/docs/medium-koyeb-article-en.md +215 -0
  87. package/docs/plans/test-plans.md +445 -0
  88. package/docs/releases/RELEASE.V0.3.0.md +22 -0
  89. package/docs/releases/RELEASE.V0.4.0.md +154 -0
  90. package/docs/releases/RELEASE.V0.5.0.md +252 -0
  91. package/docs/releases/RELEASE_v0.5.6.md +145 -0
  92. package/docs/releases/RELEASE_v0.6.1.md +303 -0
  93. package/docs/releases/RELEASE_v0.6.7.md +292 -0
  94. package/docs/releases/RELEASE_v0.7.0.md +332 -0
  95. package/docs/releases/RELEASE_v0.8.0.md +521 -0
  96. package/docs/sampledb/titanic.sql +1379 -0
  97. package/docs/superpowers/plans/2026-03-25-seed-connections.md +1362 -0
  98. package/docs/superpowers/specs/2026-03-25-seed-connections-design.md +590 -0
  99. package/e2e/admin-dashboard.spec.ts +64 -0
  100. package/e2e/connection-management.spec.ts +58 -0
  101. package/e2e/export.spec.ts +34 -0
  102. package/e2e/login.spec.ts +85 -0
  103. package/e2e/query-execution.spec.ts +35 -0
  104. package/e2e/tab-management.spec.ts +64 -0
  105. package/eslint.config.mjs +28 -0
  106. package/fly.toml +43 -0
  107. package/next.config.ts +32 -0
  108. package/package.json +130 -0
  109. package/playwright.config.ts +34 -0
  110. package/postcss.config.mjs +7 -0
  111. package/public/favicon-32x32.png +0 -0
  112. package/public/favicon.ico +0 -0
  113. package/public/file.svg +1 -0
  114. package/public/globe.svg +1 -0
  115. package/public/logo.svg +32 -0
  116. package/public/next.svg +1 -0
  117. package/public/screenshots/code-generator.png +0 -0
  118. package/public/screenshots/connection-modal.png +0 -0
  119. package/public/screenshots/data-profiler.png +0 -0
  120. package/public/screenshots/erd-diagram.png +0 -0
  121. package/public/screenshots/hero-editor.png +0 -0
  122. package/public/screenshots/nl2sql.png +0 -0
  123. package/public/vercel.svg +1 -0
  124. package/public/window.svg +1 -0
  125. package/render.yaml +58 -0
  126. package/scripts/merge-lcov.mjs +239 -0
  127. package/sonar-project.properties +16 -0
  128. package/src/app/admin/error.tsx +46 -0
  129. package/src/app/admin/page.tsx +10 -0
  130. package/src/app/api/admin/audit/route.ts +52 -0
  131. package/src/app/api/admin/fleet-health/route.ts +81 -0
  132. package/src/app/api/ai/autopilot/route.ts +105 -0
  133. package/src/app/api/ai/chat/route.ts +132 -0
  134. package/src/app/api/ai/describe-schema/route.ts +52 -0
  135. package/src/app/api/ai/explain/route.ts +86 -0
  136. package/src/app/api/ai/impact/route.ts +97 -0
  137. package/src/app/api/ai/index-advisor/route.ts +98 -0
  138. package/src/app/api/ai/nl2sql/route.ts +87 -0
  139. package/src/app/api/ai/query-safety/route.ts +87 -0
  140. package/src/app/api/auth/login/route.ts +62 -0
  141. package/src/app/api/auth/logout/route.ts +25 -0
  142. package/src/app/api/auth/me/route.ts +10 -0
  143. package/src/app/api/auth/oidc/callback/route.ts +82 -0
  144. package/src/app/api/auth/oidc/login/route.ts +43 -0
  145. package/src/app/api/connections/managed/route.ts +35 -0
  146. package/src/app/api/db/cancel/route.ts +42 -0
  147. package/src/app/api/db/disconnect/route.ts +28 -0
  148. package/src/app/api/db/health/route.ts +49 -0
  149. package/src/app/api/db/maintenance/route.ts +72 -0
  150. package/src/app/api/db/monitoring/route.ts +62 -0
  151. package/src/app/api/db/multi-query/route.ts +116 -0
  152. package/src/app/api/db/pool-stats/route.ts +37 -0
  153. package/src/app/api/db/profile/route.ts +144 -0
  154. package/src/app/api/db/provider-meta/route.ts +49 -0
  155. package/src/app/api/db/query/route.ts +50 -0
  156. package/src/app/api/db/schema/route.ts +47 -0
  157. package/src/app/api/db/schema-snapshot/route.ts +42 -0
  158. package/src/app/api/db/test-connection/route.ts +55 -0
  159. package/src/app/api/db/transaction/route.ts +111 -0
  160. package/src/app/api/storage/[collection]/route.ts +67 -0
  161. package/src/app/api/storage/config/route.ts +17 -0
  162. package/src/app/api/storage/migrate/route.ts +45 -0
  163. package/src/app/api/storage/route.ts +32 -0
  164. package/src/app/error.tsx +49 -0
  165. package/src/app/global-error.tsx +55 -0
  166. package/src/app/globals.css +146 -0
  167. package/src/app/icon.svg +42 -0
  168. package/src/app/layout.tsx +34 -0
  169. package/src/app/login/login-form.tsx +301 -0
  170. package/src/app/login/page.tsx +11 -0
  171. package/src/app/monitoring/page.tsx +8 -0
  172. package/src/app/not-found.tsx +29 -0
  173. package/src/app/page.tsx +5 -0
  174. package/src/components/AIAutopilotPanel.tsx +238 -0
  175. package/src/components/CodeGenerator.tsx +271 -0
  176. package/src/components/CommandPalette.tsx +227 -0
  177. package/src/components/ConnectionModal.tsx +759 -0
  178. package/src/components/CreateTableModal.tsx +281 -0
  179. package/src/components/DataCharts.tsx +962 -0
  180. package/src/components/DataImportModal.tsx +582 -0
  181. package/src/components/DataProfiler.tsx +335 -0
  182. package/src/components/DatabaseDocs.tsx +251 -0
  183. package/src/components/MaskingSettings.tsx +414 -0
  184. package/src/components/MobileNav.tsx +50 -0
  185. package/src/components/NL2SQLPanel.tsx +281 -0
  186. package/src/components/PivotTable.tsx +257 -0
  187. package/src/components/QueryEditor.tsx +760 -0
  188. package/src/components/QueryHistory.tsx +344 -0
  189. package/src/components/QuerySafetyDialog.tsx +290 -0
  190. package/src/components/ResultsGrid.tsx +644 -0
  191. package/src/components/SaveQueryModal.tsx +104 -0
  192. package/src/components/SavedQueries.tsx +128 -0
  193. package/src/components/SchemaDiagram.tsx +473 -0
  194. package/src/components/SchemaDiff.tsx +473 -0
  195. package/src/components/SnapshotTimeline.tsx +116 -0
  196. package/src/components/Studio.tsx +639 -0
  197. package/src/components/TestDataGenerator.tsx +261 -0
  198. package/src/components/VisualExplain.tsx +820 -0
  199. package/src/components/admin/AdminDashboard.tsx +163 -0
  200. package/src/components/admin/tabs/AuditTab.tsx +531 -0
  201. package/src/components/admin/tabs/MonitoringEmbed.tsx +11 -0
  202. package/src/components/admin/tabs/OperationsTab.tsx +646 -0
  203. package/src/components/admin/tabs/OverviewTab.tsx +1328 -0
  204. package/src/components/admin/tabs/SecurityTab.tsx +284 -0
  205. package/src/components/community-section.tsx +92 -0
  206. package/src/components/icons/db-icons.tsx +84 -0
  207. package/src/components/libredb-logo.tsx +61 -0
  208. package/src/components/monitoring/MonitoringDashboard.tsx +345 -0
  209. package/src/components/monitoring/tabs/MetricChart.tsx +82 -0
  210. package/src/components/monitoring/tabs/OverviewTab.tsx +263 -0
  211. package/src/components/monitoring/tabs/PerformanceTab.tsx +254 -0
  212. package/src/components/monitoring/tabs/PoolTab.tsx +174 -0
  213. package/src/components/monitoring/tabs/QueriesTab.tsx +287 -0
  214. package/src/components/monitoring/tabs/SessionsTab.tsx +316 -0
  215. package/src/components/monitoring/tabs/StorageTab.tsx +335 -0
  216. package/src/components/monitoring/tabs/TablesTab.tsx +300 -0
  217. package/src/components/results-grid/ResultCard.tsx +111 -0
  218. package/src/components/results-grid/RowDetailSheet.tsx +178 -0
  219. package/src/components/results-grid/StatsBar.tsx +201 -0
  220. package/src/components/results-grid/index.ts +1 -0
  221. package/src/components/results-grid/utils.ts +23 -0
  222. package/src/components/schema-explorer/ColumnList.tsx +53 -0
  223. package/src/components/schema-explorer/SchemaExplorer.tsx +182 -0
  224. package/src/components/schema-explorer/TableItem.tsx +210 -0
  225. package/src/components/schema-explorer/index.ts +1 -0
  226. package/src/components/sidebar/ConnectionItem.tsx +105 -0
  227. package/src/components/sidebar/ConnectionsList.tsx +62 -0
  228. package/src/components/sidebar/Sidebar.tsx +130 -0
  229. package/src/components/sidebar/index.ts +2 -0
  230. package/src/components/studio/BottomPanel.tsx +286 -0
  231. package/src/components/studio/QueryToolbar.tsx +180 -0
  232. package/src/components/studio/StudioDesktopHeader.tsx +114 -0
  233. package/src/components/studio/StudioMobileHeader.tsx +340 -0
  234. package/src/components/studio/StudioTabBar.tsx +82 -0
  235. package/src/components/studio/index.ts +5 -0
  236. package/src/components/ui/accordion.tsx +66 -0
  237. package/src/components/ui/alert-dialog.tsx +157 -0
  238. package/src/components/ui/alert.tsx +66 -0
  239. package/src/components/ui/aspect-ratio.tsx +11 -0
  240. package/src/components/ui/avatar.tsx +53 -0
  241. package/src/components/ui/badge.tsx +46 -0
  242. package/src/components/ui/breadcrumb.tsx +109 -0
  243. package/src/components/ui/button-group.tsx +83 -0
  244. package/src/components/ui/button.tsx +60 -0
  245. package/src/components/ui/calendar.tsx +216 -0
  246. package/src/components/ui/card.tsx +92 -0
  247. package/src/components/ui/carousel.tsx +241 -0
  248. package/src/components/ui/chart.tsx +357 -0
  249. package/src/components/ui/checkbox.tsx +32 -0
  250. package/src/components/ui/collapsible.tsx +33 -0
  251. package/src/components/ui/command.tsx +184 -0
  252. package/src/components/ui/context-menu.tsx +252 -0
  253. package/src/components/ui/dialog.tsx +143 -0
  254. package/src/components/ui/drawer.tsx +135 -0
  255. package/src/components/ui/dropdown-menu.tsx +257 -0
  256. package/src/components/ui/empty.tsx +104 -0
  257. package/src/components/ui/field.tsx +248 -0
  258. package/src/components/ui/form.tsx +167 -0
  259. package/src/components/ui/hover-card.tsx +44 -0
  260. package/src/components/ui/input-group.tsx +170 -0
  261. package/src/components/ui/input-otp.tsx +77 -0
  262. package/src/components/ui/input.tsx +21 -0
  263. package/src/components/ui/item.tsx +193 -0
  264. package/src/components/ui/kbd.tsx +28 -0
  265. package/src/components/ui/label.tsx +24 -0
  266. package/src/components/ui/menubar.tsx +276 -0
  267. package/src/components/ui/navigation-menu.tsx +168 -0
  268. package/src/components/ui/pagination.tsx +127 -0
  269. package/src/components/ui/popover.tsx +48 -0
  270. package/src/components/ui/progress.tsx +31 -0
  271. package/src/components/ui/radio-group.tsx +45 -0
  272. package/src/components/ui/resizable.tsx +56 -0
  273. package/src/components/ui/scroll-area.tsx +58 -0
  274. package/src/components/ui/select.tsx +187 -0
  275. package/src/components/ui/separator.tsx +28 -0
  276. package/src/components/ui/sheet.tsx +139 -0
  277. package/src/components/ui/sidebar.tsx +726 -0
  278. package/src/components/ui/skeleton.tsx +13 -0
  279. package/src/components/ui/slider.tsx +63 -0
  280. package/src/components/ui/sonner.tsx +40 -0
  281. package/src/components/ui/spinner.tsx +16 -0
  282. package/src/components/ui/switch.tsx +31 -0
  283. package/src/components/ui/table.tsx +116 -0
  284. package/src/components/ui/tabs.tsx +66 -0
  285. package/src/components/ui/textarea.tsx +18 -0
  286. package/src/components/ui/toggle-group.tsx +83 -0
  287. package/src/components/ui/toggle.tsx +47 -0
  288. package/src/components/ui/tooltip.tsx +61 -0
  289. package/src/exports/components.ts +15 -0
  290. package/src/exports/index.ts +4 -0
  291. package/src/exports/providers.ts +4 -0
  292. package/src/exports/types.ts +26 -0
  293. package/src/hooks/use-ai-chat.ts +182 -0
  294. package/src/hooks/use-all-connections.ts +66 -0
  295. package/src/hooks/use-api-call.ts +71 -0
  296. package/src/hooks/use-auth.ts +51 -0
  297. package/src/hooks/use-connection-form.ts +349 -0
  298. package/src/hooks/use-connection-manager.ts +169 -0
  299. package/src/hooks/use-connection-payload.ts +15 -0
  300. package/src/hooks/use-inline-editing.ts +109 -0
  301. package/src/hooks/use-mobile.ts +20 -0
  302. package/src/hooks/use-monitoring-data.ts +270 -0
  303. package/src/hooks/use-provider-metadata.ts +62 -0
  304. package/src/hooks/use-query-execution.ts +478 -0
  305. package/src/hooks/use-storage-sync.ts +259 -0
  306. package/src/hooks/use-tab-manager.ts +231 -0
  307. package/src/hooks/use-toast.ts +20 -0
  308. package/src/hooks/use-transaction-control.ts +64 -0
  309. package/src/lib/api/error-codes.ts +30 -0
  310. package/src/lib/api/errors.ts +236 -0
  311. package/src/lib/api/with-error-handler.ts +41 -0
  312. package/src/lib/audit.ts +105 -0
  313. package/src/lib/auth.ts +87 -0
  314. package/src/lib/connection-string-parser.ts +172 -0
  315. package/src/lib/data-masking.ts +385 -0
  316. package/src/lib/db/base-provider.ts +325 -0
  317. package/src/lib/db/errors.ts +317 -0
  318. package/src/lib/db/factory.ts +324 -0
  319. package/src/lib/db/index.ts +123 -0
  320. package/src/lib/db/providers/document/index.ts +6 -0
  321. package/src/lib/db/providers/document/mongodb.ts +992 -0
  322. package/src/lib/db/providers/keyvalue/redis.ts +554 -0
  323. package/src/lib/db/providers/sql/index.ts +11 -0
  324. package/src/lib/db/providers/sql/mssql.ts +1065 -0
  325. package/src/lib/db/providers/sql/mysql.ts +978 -0
  326. package/src/lib/db/providers/sql/oracle.ts +1044 -0
  327. package/src/lib/db/providers/sql/postgres.ts +1179 -0
  328. package/src/lib/db/providers/sql/sql-base.ts +174 -0
  329. package/src/lib/db/providers/sql/sqlite.ts +721 -0
  330. package/src/lib/db/types.ts +437 -0
  331. package/src/lib/db/utils/pool-manager.ts +287 -0
  332. package/src/lib/db/utils/query-limiter.ts +239 -0
  333. package/src/lib/db-ui-config.ts +86 -0
  334. package/src/lib/editor/mongodb-completions.ts +172 -0
  335. package/src/lib/editor/sql-completions.ts +280 -0
  336. package/src/lib/llm/base-provider.ts +117 -0
  337. package/src/lib/llm/factory.ts +102 -0
  338. package/src/lib/llm/index.ts +90 -0
  339. package/src/lib/llm/providers/custom.ts +181 -0
  340. package/src/lib/llm/providers/gemini.ts +126 -0
  341. package/src/lib/llm/providers/ollama.ts +154 -0
  342. package/src/lib/llm/providers/openai.ts +146 -0
  343. package/src/lib/llm/types.ts +173 -0
  344. package/src/lib/llm/utils/config.ts +187 -0
  345. package/src/lib/llm/utils/retry.ts +119 -0
  346. package/src/lib/llm/utils/streaming.ts +202 -0
  347. package/src/lib/logger.ts +127 -0
  348. package/src/lib/monitoring-thresholds.ts +44 -0
  349. package/src/lib/oidc.ts +262 -0
  350. package/src/lib/query-generators.ts +61 -0
  351. package/src/lib/schema-diff/diff-engine.ts +273 -0
  352. package/src/lib/schema-diff/migration-generator.ts +208 -0
  353. package/src/lib/schema-diff/types.ts +55 -0
  354. package/src/lib/seed/config-loader.ts +79 -0
  355. package/src/lib/seed/connection-filter.ts +49 -0
  356. package/src/lib/seed/credential-resolver.ts +62 -0
  357. package/src/lib/seed/index.ts +40 -0
  358. package/src/lib/seed/resolve-connection.ts +57 -0
  359. package/src/lib/seed/types.ts +69 -0
  360. package/src/lib/sql/alias-extractor.ts +267 -0
  361. package/src/lib/sql/index.ts +8 -0
  362. package/src/lib/sql/statement-splitter.ts +167 -0
  363. package/src/lib/sql/types.ts +40 -0
  364. package/src/lib/ssh/tunnel.ts +142 -0
  365. package/src/lib/storage/factory.ts +84 -0
  366. package/src/lib/storage/index.ts +14 -0
  367. package/src/lib/storage/local-storage.ts +99 -0
  368. package/src/lib/storage/providers/postgres.ts +225 -0
  369. package/src/lib/storage/providers/sqlite.ts +153 -0
  370. package/src/lib/storage/storage-facade.ts +272 -0
  371. package/src/lib/storage/types.ts +75 -0
  372. package/src/lib/time-series-buffer.ts +58 -0
  373. package/src/lib/types.ts +173 -0
  374. package/src/lib/utils.ts +6 -0
  375. package/src/proxy.ts +104 -0
  376. package/src/types/db-drivers.d.ts +23 -0
  377. package/src/types/html2canvas.d.ts +9 -0
  378. package/tests/api/admin/audit.test.ts +178 -0
  379. package/tests/api/admin/fleet-health.test.ts +183 -0
  380. package/tests/api/ai/autopilot.test.ts +174 -0
  381. package/tests/api/ai/chat.test.ts +250 -0
  382. package/tests/api/ai/describe-schema.test.ts +266 -0
  383. package/tests/api/ai/explain.test.ts +199 -0
  384. package/tests/api/ai/impact.test.ts +168 -0
  385. package/tests/api/ai/index-advisor.test.ts +171 -0
  386. package/tests/api/ai/nl2sql.test.ts +202 -0
  387. package/tests/api/ai/query-safety.test.ts +196 -0
  388. package/tests/api/auth/login.test.ts +170 -0
  389. package/tests/api/auth/logout.test.ts +140 -0
  390. package/tests/api/auth/me.test.ts +73 -0
  391. package/tests/api/auth/oidc-callback.test.ts +215 -0
  392. package/tests/api/auth/oidc-login.test.ts +127 -0
  393. package/tests/api/db/cancel.test.ts +198 -0
  394. package/tests/api/db/disconnect.test.ts +124 -0
  395. package/tests/api/db/health.test.ts +222 -0
  396. package/tests/api/db/maintenance.test.ts +263 -0
  397. package/tests/api/db/monitoring.test.ts +221 -0
  398. package/tests/api/db/multi-query.test.ts +316 -0
  399. package/tests/api/db/pool-stats.test.ts +135 -0
  400. package/tests/api/db/profile.test.ts +330 -0
  401. package/tests/api/db/provider-meta.test.ts +193 -0
  402. package/tests/api/db/query.test.ts +314 -0
  403. package/tests/api/db/schema-snapshot.test.ts +170 -0
  404. package/tests/api/db/schema.test.ts +191 -0
  405. package/tests/api/db/test-connection.test.ts +185 -0
  406. package/tests/api/db/transaction.test.ts +314 -0
  407. package/tests/api/proxy.test.ts +191 -0
  408. package/tests/api/seed/managed-route.test.ts +113 -0
  409. package/tests/api/storage/config.test.ts +42 -0
  410. package/tests/api/storage/storage-routes.test.ts +309 -0
  411. package/tests/components/AIAutopilotPanel.test.tsx +756 -0
  412. package/tests/components/AdminPage.test.tsx +33 -0
  413. package/tests/components/CodeGenerator.test.tsx +182 -0
  414. package/tests/components/CommandPalette.test.tsx +428 -0
  415. package/tests/components/CommunitySection.test.tsx +91 -0
  416. package/tests/components/ConnectionModal.mobile.test.tsx +284 -0
  417. package/tests/components/ConnectionModal.test.tsx +570 -0
  418. package/tests/components/CreateTableModal.test.tsx +383 -0
  419. package/tests/components/DataCharts.test.tsx +739 -0
  420. package/tests/components/DataImportModal.test.tsx +751 -0
  421. package/tests/components/DataProfiler.test.tsx +589 -0
  422. package/tests/components/DatabaseDocs.test.tsx +353 -0
  423. package/tests/components/LoginPage.test.tsx +163 -0
  424. package/tests/components/LoginPageOIDC.test.tsx +92 -0
  425. package/tests/components/MaskingSettings.test.tsx +498 -0
  426. package/tests/components/MobileNav.test.tsx +30 -0
  427. package/tests/components/MonitoringPage.test.tsx +32 -0
  428. package/tests/components/NL2SQLPanel.test.tsx +621 -0
  429. package/tests/components/Page.test.tsx +33 -0
  430. package/tests/components/PivotTable.test.tsx +350 -0
  431. package/tests/components/QueryEditor.test.tsx +1730 -0
  432. package/tests/components/QueryHistory.test.tsx +572 -0
  433. package/tests/components/QuerySafetyDialog.test.tsx +586 -0
  434. package/tests/components/ResultsGrid.test.tsx +804 -0
  435. package/tests/components/RootLayout.test.tsx +83 -0
  436. package/tests/components/SaveQueryModal.test.tsx +25 -0
  437. package/tests/components/SavedQueries.test.tsx +43 -0
  438. package/tests/components/SchemaDiagram.test.tsx +1034 -0
  439. package/tests/components/SchemaDiff.test.tsx +906 -0
  440. package/tests/components/SnapshotTimeline.test.tsx +174 -0
  441. package/tests/components/Studio.test.tsx +1030 -0
  442. package/tests/components/TestDataGenerator.test.tsx +291 -0
  443. package/tests/components/VisualExplain.test.tsx +704 -0
  444. package/tests/components/admin/AdminDashboard.test.tsx +205 -0
  445. package/tests/components/admin/AuditTab.test.tsx +220 -0
  446. package/tests/components/admin/MonitoringEmbed.test.tsx +58 -0
  447. package/tests/components/admin/OperationsTab.test.tsx +975 -0
  448. package/tests/components/admin/OverviewTab.test.tsx +254 -0
  449. package/tests/components/admin/SecurityTab.test.tsx +467 -0
  450. package/tests/components/monitoring/MetricChart.test.tsx +111 -0
  451. package/tests/components/monitoring/MonitoringDashboard.test.tsx +259 -0
  452. package/tests/components/monitoring/OverviewTab.test.tsx +78 -0
  453. package/tests/components/monitoring/PerformanceTab.test.tsx +87 -0
  454. package/tests/components/monitoring/PoolTab.test.tsx +42 -0
  455. package/tests/components/monitoring/QueriesTab.test.tsx +80 -0
  456. package/tests/components/monitoring/SessionsTab.test.tsx +154 -0
  457. package/tests/components/monitoring/StorageTab.test.tsx +127 -0
  458. package/tests/components/monitoring/TablesTab.test.tsx +153 -0
  459. package/tests/components/results-grid/ResultCard.test.tsx +105 -0
  460. package/tests/components/results-grid/RowDetailSheet.test.tsx +308 -0
  461. package/tests/components/results-grid/StatsBar.test.tsx +162 -0
  462. package/tests/components/schema-explorer/ColumnList.test.tsx +151 -0
  463. package/tests/components/schema-explorer/SchemaExplorer.test.tsx +461 -0
  464. package/tests/components/schema-explorer/TableItem.test.tsx +415 -0
  465. package/tests/components/sidebar/ConnectionItem.test.tsx +201 -0
  466. package/tests/components/sidebar/ConnectionsList.test.tsx +176 -0
  467. package/tests/components/sidebar/Sidebar.test.tsx +187 -0
  468. package/tests/components/studio/BottomPanel.test.tsx +383 -0
  469. package/tests/components/studio/QueryToolbar.test.tsx +321 -0
  470. package/tests/components/studio/StudioDesktopHeader.test.tsx +377 -0
  471. package/tests/components/studio/StudioMobileHeader.test.tsx +198 -0
  472. package/tests/components/studio/StudioTabBar.test.tsx +331 -0
  473. package/tests/fixtures/connections.ts +96 -0
  474. package/tests/fixtures/masking-configs.ts +86 -0
  475. package/tests/fixtures/query-results.ts +71 -0
  476. package/tests/fixtures/schemas.ts +64 -0
  477. package/tests/fixtures/seed-connections/invalid-config.yaml +7 -0
  478. package/tests/fixtures/seed-connections/minimal-config.yaml +8 -0
  479. package/tests/fixtures/seed-connections/mixed-credentials.yaml +23 -0
  480. package/tests/fixtures/seed-connections/multi-role-config.yaml +30 -0
  481. package/tests/fixtures/seed-connections/valid-config.json +15 -0
  482. package/tests/fixtures/seed-connections/valid-config.yaml +51 -0
  483. package/tests/helpers/mock-fetch.ts +59 -0
  484. package/tests/helpers/mock-monaco.ts +112 -0
  485. package/tests/helpers/mock-navigation.ts +28 -0
  486. package/tests/helpers/mock-next.ts +80 -0
  487. package/tests/helpers/mock-provider.ts +133 -0
  488. package/tests/helpers/mock-sonner.ts +29 -0
  489. package/tests/helpers/render-with-providers.tsx +19 -0
  490. package/tests/hooks/use-ai-chat.test.ts +600 -0
  491. package/tests/hooks/use-auth.test.ts +371 -0
  492. package/tests/hooks/use-connection-form.test.ts +743 -0
  493. package/tests/hooks/use-connection-manager.test.ts +466 -0
  494. package/tests/hooks/use-inline-editing.test.ts +321 -0
  495. package/tests/hooks/use-mobile.test.ts +177 -0
  496. package/tests/hooks/use-monitoring-data.test.ts +819 -0
  497. package/tests/hooks/use-provider-metadata.test.ts +228 -0
  498. package/tests/hooks/use-query-execution.test.ts +1212 -0
  499. package/tests/hooks/use-tab-manager.test.ts +756 -0
  500. package/tests/hooks/use-toast.test.ts +74 -0
  501. package/tests/hooks/use-transaction-control.test.ts +211 -0
  502. package/tests/integration/db/mongodb-provider.test.ts +698 -0
  503. package/tests/integration/db/mssql-provider.test.ts +840 -0
  504. package/tests/integration/db/mysql-provider.test.ts +872 -0
  505. package/tests/integration/db/oracle-provider.test.ts +843 -0
  506. package/tests/integration/db/postgres-provider.test.ts +1382 -0
  507. package/tests/integration/db/redis-provider.test.ts +526 -0
  508. package/tests/integration/db/sqlite-provider.test.ts +480 -0
  509. package/tests/integration/seed/seed-pipeline.test.ts +102 -0
  510. package/tests/isolated/factory-singleton.test.ts +150 -0
  511. package/tests/isolated/use-storage-sync.test.ts +389 -0
  512. package/tests/run-components.sh +196 -0
  513. package/tests/setup-dom.ts +58 -0
  514. package/tests/setup.ts +40 -0
  515. package/tests/unit/api-errors.test.ts +210 -0
  516. package/tests/unit/code-generator-functions.test.ts +271 -0
  517. package/tests/unit/components/column-list.test.tsx +190 -0
  518. package/tests/unit/components/data-import-modal.test.tsx +441 -0
  519. package/tests/unit/components/studio-mobile-header.test.tsx +327 -0
  520. package/tests/unit/data-charts-functions.test.ts +496 -0
  521. package/tests/unit/data-import-functions.test.ts +320 -0
  522. package/tests/unit/data-import-utils.test.ts +125 -0
  523. package/tests/unit/db/base-provider.test.ts +517 -0
  524. package/tests/unit/db/errors.test.ts +403 -0
  525. package/tests/unit/db/factory.test.ts +436 -0
  526. package/tests/unit/db/pool-manager.test.ts +440 -0
  527. package/tests/unit/db/query-limiter.test.ts +387 -0
  528. package/tests/unit/db/sql-base.test.ts +438 -0
  529. package/tests/unit/lib/api/error-codes.test.ts +39 -0
  530. package/tests/unit/lib/audit.test.ts +326 -0
  531. package/tests/unit/lib/auth.test.ts +146 -0
  532. package/tests/unit/lib/connection-string-parser.test.ts +424 -0
  533. package/tests/unit/lib/data-masking.test.ts +583 -0
  534. package/tests/unit/lib/db-icons.test.tsx +41 -0
  535. package/tests/unit/lib/monitoring-thresholds.test.ts +133 -0
  536. package/tests/unit/lib/oidc.test.ts +509 -0
  537. package/tests/unit/lib/query-generators.test.ts +127 -0
  538. package/tests/unit/lib/storage/factory.test.ts +71 -0
  539. package/tests/unit/lib/storage/local-storage.test.ts +114 -0
  540. package/tests/unit/lib/storage/providers/postgres.test.ts +312 -0
  541. package/tests/unit/lib/storage/providers/sqlite.test.ts +232 -0
  542. package/tests/unit/lib/storage/storage-facade-extended.test.ts +331 -0
  543. package/tests/unit/lib/storage/storage-facade.test.ts +184 -0
  544. package/tests/unit/lib/storage.test.ts +317 -0
  545. package/tests/unit/lib/time-series-buffer.test.ts +212 -0
  546. package/tests/unit/lib/utils.test.ts +24 -0
  547. package/tests/unit/llm/base-provider.test.ts +238 -0
  548. package/tests/unit/llm/config.test.ts +262 -0
  549. package/tests/unit/llm/custom-provider.test.ts +281 -0
  550. package/tests/unit/llm/gemini-provider.test.ts +248 -0
  551. package/tests/unit/llm/llm-factory.test.ts +155 -0
  552. package/tests/unit/llm/ollama-provider.test.ts +288 -0
  553. package/tests/unit/llm/openai-provider.test.ts +324 -0
  554. package/tests/unit/llm/retry.test.ts +180 -0
  555. package/tests/unit/llm/streaming.test.ts +355 -0
  556. package/tests/unit/logger.test.ts +198 -0
  557. package/tests/unit/mongodb-completions.test.ts +516 -0
  558. package/tests/unit/pivot-table-functions.test.ts +76 -0
  559. package/tests/unit/query-cancelled-error.test.ts +81 -0
  560. package/tests/unit/schema-diff/diff-engine.test.ts +367 -0
  561. package/tests/unit/schema-diff/migration-generator.test.ts +513 -0
  562. package/tests/unit/seed/config-loader.test.ts +73 -0
  563. package/tests/unit/seed/connection-filter.test.ts +91 -0
  564. package/tests/unit/seed/credential-resolver.test.ts +85 -0
  565. package/tests/unit/seed/index.test.ts +72 -0
  566. package/tests/unit/seed/resolve-connection.test.ts +74 -0
  567. package/tests/unit/seed/types.test.ts +129 -0
  568. package/tests/unit/sql/alias-extractor.test.ts +444 -0
  569. package/tests/unit/sql/statement-splitter.test.ts +348 -0
  570. package/tests/unit/sql-completions.test.ts +463 -0
  571. package/tests/unit/ssh-tunnel.test.ts +465 -0
  572. package/tsconfig.json +42 -0
@@ -0,0 +1,180 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import type { DatabaseConnection } from '@/lib/types';
5
+ import type { ProviderMetadata } from '@/hooks/use-provider-metadata';
6
+ import { cn } from '@/lib/utils';
7
+ import { FlaskConical, Pencil, Play, Save, Square, Terminal, Upload } from 'lucide-react';
8
+ import { Button } from '@/components/ui/button';
9
+
10
+ interface QueryToolbarProps {
11
+ activeConnection: DatabaseConnection | null;
12
+ metadata: ProviderMetadata | null;
13
+ isExecuting: boolean;
14
+ playgroundMode: boolean;
15
+ transactionActive: boolean;
16
+ editingEnabled: boolean;
17
+ onSaveQuery: () => void;
18
+ onExecuteQuery: () => void;
19
+ onCancelQuery: () => void;
20
+ onBeginTransaction: () => void;
21
+ onCommitTransaction: () => void;
22
+ onRollbackTransaction: () => void;
23
+ onTogglePlayground: () => void;
24
+ onToggleEditing: () => void;
25
+ onImport: () => void;
26
+ }
27
+
28
+ export function QueryToolbar({
29
+ activeConnection,
30
+ metadata,
31
+ isExecuting,
32
+ playgroundMode,
33
+ transactionActive,
34
+ editingEnabled,
35
+ onSaveQuery,
36
+ onExecuteQuery,
37
+ onCancelQuery,
38
+ onBeginTransaction,
39
+ onCommitTransaction,
40
+ onRollbackTransaction,
41
+ onTogglePlayground,
42
+ onToggleEditing,
43
+ onImport,
44
+ }: QueryToolbarProps) {
45
+ return (
46
+ <>
47
+ {/* Playground Mode Banner */}
48
+ {playgroundMode && (
49
+ <div className="hidden md:flex items-center justify-center gap-2 px-4 py-1 bg-emerald-500/10 border-b border-emerald-500/20 text-emerald-400">
50
+ <FlaskConical className="w-3 h-3" />
51
+ <span className="text-[10px] font-bold uppercase tracking-widest">
52
+ Sandbox Mode — All changes will be auto-rolled back
53
+ </span>
54
+ </div>
55
+ )}
56
+
57
+ {/* Desktop Query Toolbar */}
58
+ <div className="hidden md:flex items-center justify-between px-4 py-1.5 bg-[#0a0a0a] border-b border-white/5">
59
+ <div className="flex items-center gap-4">
60
+ <div className="flex items-center gap-2 px-2 py-0.5 rounded bg-blue-500/5 border border-blue-500/10">
61
+ <Terminal className="w-3 h-3 text-blue-400" />
62
+ <span className="text-[10px] font-bold text-blue-400 uppercase tracking-widest">Query</span>
63
+ </div>
64
+ <div className="h-4 w-px bg-white/5" />
65
+ <Button
66
+ variant="ghost"
67
+ size="sm"
68
+ className="h-7 text-[10px] font-bold uppercase tracking-widest text-zinc-500 hover:text-white gap-2"
69
+ onClick={onSaveQuery}
70
+ >
71
+ <Save className="w-3 h-3" /> Save
72
+ </Button>
73
+ </div>
74
+ {isExecuting ? (
75
+ <Button
76
+ size="sm"
77
+ className="bg-red-600 hover:bg-red-500 text-white font-bold text-[11px] h-7 px-4 gap-2"
78
+ onClick={onCancelQuery}
79
+ >
80
+ <Square className="w-3 h-3 fill-current" />
81
+ CANCEL
82
+ </Button>
83
+ ) : (
84
+ <Button
85
+ size="sm"
86
+ className="bg-blue-600 hover:bg-blue-500 text-white font-bold text-[11px] h-7 px-4 gap-2"
87
+ onClick={onExecuteQuery}
88
+ disabled={!activeConnection}
89
+ >
90
+ <Play className="w-3 h-3 fill-current" />
91
+ RUN
92
+ </Button>
93
+ )}
94
+
95
+ {/* Transaction Controls + Playground + Import + Edit */}
96
+ {activeConnection && metadata?.capabilities.queryLanguage === 'sql' && (
97
+ <div className="flex items-center gap-1 ml-2 pl-2 border-l border-white/10">
98
+ {transactionActive ? (
99
+ <>
100
+ <span className="text-[9px] font-bold text-amber-400 uppercase tracking-wider px-1.5 py-0.5 bg-amber-500/10 rounded border border-amber-500/20 mr-1">
101
+ TXN
102
+ </span>
103
+ <Button
104
+ size="sm"
105
+ variant="ghost"
106
+ className="h-7 text-[10px] font-bold text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 gap-1"
107
+ onClick={onCommitTransaction}
108
+ >
109
+ COMMIT
110
+ </Button>
111
+ <Button
112
+ size="sm"
113
+ variant="ghost"
114
+ className="h-7 text-[10px] font-bold text-red-400 hover:text-red-300 hover:bg-red-500/10 gap-1"
115
+ onClick={onRollbackTransaction}
116
+ >
117
+ ROLLBACK
118
+ </Button>
119
+ </>
120
+ ) : (
121
+ <Button
122
+ size="sm"
123
+ variant="ghost"
124
+ className="h-7 text-[10px] font-bold uppercase tracking-widest text-zinc-500 hover:text-white gap-1"
125
+ onClick={onBeginTransaction}
126
+ disabled={playgroundMode}
127
+ >
128
+ BEGIN
129
+ </Button>
130
+ )}
131
+
132
+ <Button
133
+ size="sm"
134
+ variant="ghost"
135
+ className={cn(
136
+ "h-7 text-[10px] font-bold uppercase tracking-widest gap-1",
137
+ playgroundMode
138
+ ? "text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20"
139
+ : "text-zinc-500 hover:text-white"
140
+ )}
141
+ onClick={onTogglePlayground}
142
+ disabled={transactionActive}
143
+ title="Playground mode: queries are auto-rolled back"
144
+ >
145
+ <FlaskConical className="w-3 h-3" />
146
+ SANDBOX
147
+ </Button>
148
+
149
+ <Button
150
+ size="sm"
151
+ variant="ghost"
152
+ className={cn(
153
+ "h-7 text-[10px] font-bold uppercase tracking-widest gap-1",
154
+ editingEnabled
155
+ ? "text-amber-400 bg-amber-500/10 hover:bg-amber-500/20"
156
+ : "text-zinc-500 hover:text-white"
157
+ )}
158
+ onClick={onToggleEditing}
159
+ title="Enable inline data editing"
160
+ >
161
+ <Pencil className="w-3 h-3" />
162
+ EDIT
163
+ </Button>
164
+
165
+ <Button
166
+ size="sm"
167
+ variant="ghost"
168
+ className="h-7 text-[10px] font-bold uppercase tracking-widest text-zinc-500 hover:text-white gap-1"
169
+ onClick={onImport}
170
+ title="Import data from CSV/JSON"
171
+ >
172
+ <Upload className="w-3 h-3" />
173
+ IMPORT
174
+ </Button>
175
+ </div>
176
+ )}
177
+ </div>
178
+ </>
179
+ );
180
+ }
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import type { DatabaseConnection } from '@/lib/types';
5
+ import { useRouter } from 'next/navigation';
6
+ import { cn } from '@/lib/utils';
7
+ import { Database, Gauge, LogOut, Settings, User } from 'lucide-react';
8
+ import {
9
+ DropdownMenu, DropdownMenuContent,
10
+ DropdownMenuItem, DropdownMenuTrigger,
11
+ } from '@/components/ui/dropdown-menu';
12
+ import { Button } from '@/components/ui/button';
13
+
14
+ interface StudioDesktopHeaderProps {
15
+ activeConnection: DatabaseConnection | null;
16
+ connectionPulse: 'healthy' | 'degraded' | 'error' | null;
17
+ user: { role?: string } | null;
18
+ isAdmin: boolean;
19
+ onLogout: () => void;
20
+ }
21
+
22
+ export function StudioDesktopHeader({
23
+ activeConnection,
24
+ connectionPulse,
25
+ user,
26
+ isAdmin,
27
+ onLogout,
28
+ }: StudioDesktopHeaderProps) {
29
+ const router = useRouter();
30
+
31
+ return (
32
+ <header className="hidden md:flex h-14 border-b border-white/5 items-center justify-between px-4 bg-[#0a0a0a]/80 backdrop-blur-xl sticky top-0 z-30">
33
+ <div className="flex items-center gap-3">
34
+ <div className="p-1.5 rounded-lg bg-blue-500/10 border border-blue-500/20">
35
+ <Database className="w-4 h-4 text-blue-400" />
36
+ </div>
37
+ <div>
38
+ <h1 className="text-sm font-semibold tracking-tight text-zinc-200 truncate max-w-[120px]">
39
+ {activeConnection ? activeConnection.name : 'Quick Access'}
40
+ </h1>
41
+ {activeConnection && (
42
+ <p className="text-[10px] text-zinc-500 font-mono uppercase tracking-widest leading-none mt-0.5">
43
+ {activeConnection.type}
44
+ {activeConnection.environment && activeConnection.environment !== 'other' && (
45
+ <span
46
+ className="ml-1 font-bold"
47
+ style={{ color: activeConnection.color || '#22c55e' }}
48
+ >
49
+ • {activeConnection.environment}
50
+ </span>
51
+ )}
52
+ {!activeConnection.environment && (
53
+ <span> • <span className="text-emerald-500/80">Online</span></span>
54
+ )}
55
+ </p>
56
+ )}
57
+ </div>
58
+ </div>
59
+
60
+ <div className="flex items-center gap-2">
61
+ {connectionPulse && (
62
+ <div className="flex items-center gap-1.5 px-2 py-1 rounded-lg bg-white/5 mr-2" title={`Connection: ${connectionPulse}`}>
63
+ <div className={cn(
64
+ "w-2 h-2 rounded-full",
65
+ connectionPulse === 'healthy' && "bg-emerald-500 animate-pulse",
66
+ connectionPulse === 'degraded' && "bg-amber-500",
67
+ connectionPulse === 'error' && "bg-red-500",
68
+ )} />
69
+ <span className="text-[10px] font-bold uppercase tracking-widest text-zinc-500">
70
+ {connectionPulse === 'healthy' ? 'Online' : connectionPulse === 'degraded' ? 'Slow' : 'Error'}
71
+ </span>
72
+ </div>
73
+ )}
74
+
75
+ <Button
76
+ variant="ghost"
77
+ size="sm"
78
+ className="h-7 px-3 text-[10px] font-bold uppercase tracking-widest gap-2 text-zinc-500 hover:text-purple-400 hover:bg-purple-500/10"
79
+ onClick={() => router.push('/monitoring')}
80
+ >
81
+ <Gauge className="w-3 h-3" /> Monitoring
82
+ </Button>
83
+
84
+ {user && (
85
+ <DropdownMenu>
86
+ <DropdownMenuTrigger asChild>
87
+ <Button variant="ghost" size="sm" className="h-8 gap-2 hover:bg-white/5 px-2">
88
+ <User className="w-3.5 h-3.5 text-blue-400" />
89
+ </Button>
90
+ </DropdownMenuTrigger>
91
+ <DropdownMenuContent align="end" className="w-56 bg-[#0d0d0d] border-white/10 text-zinc-300">
92
+ {isAdmin && (
93
+ <DropdownMenuItem onClick={() => router.push('/admin')} className="cursor-pointer">
94
+ <Settings className="w-4 h-4 mr-2" /> Admin Dashboard
95
+ </DropdownMenuItem>
96
+ )}
97
+ <DropdownMenuItem onClick={() => router.push('/monitoring')} className="cursor-pointer">
98
+ <Gauge className="w-4 h-4 mr-2" /> Monitoring
99
+ </DropdownMenuItem>
100
+ <div className="border-t border-white/5 my-1" />
101
+ <DropdownMenuItem onClick={onLogout} className="text-red-400 cursor-pointer">
102
+ <LogOut className="w-4 h-4 mr-2" /> Logout
103
+ </DropdownMenuItem>
104
+ </DropdownMenuContent>
105
+ </DropdownMenu>
106
+ )}
107
+ <Settings className="w-4 h-4 text-zinc-400 cursor-pointer hover:text-white transition-colors mx-2" />
108
+ <span className="text-[10px] text-zinc-500 font-mono">
109
+ v{process.env.NEXT_PUBLIC_APP_VERSION}
110
+ </span>
111
+ </div>
112
+ </header>
113
+ );
114
+ }
@@ -0,0 +1,340 @@
1
+ 'use client';
2
+
3
+ import React, { type RefObject } from 'react';
4
+ import type { DatabaseConnection } from '@/lib/types';
5
+ import type { QueryEditorRef } from '@/components/QueryEditor';
6
+ import { useRouter } from 'next/navigation';
7
+ import { cn } from '@/lib/utils';
8
+ import {
9
+ AlignLeft, ChevronDown, Copy, Database, Edit3, Gauge,
10
+ LogOut, MoreVertical, Pencil, Play, PlayCircle, Plus,
11
+ Save, Settings, Sparkles, Square, Trash2, Upload, User, Zap,
12
+ } from 'lucide-react';
13
+ import {
14
+ DropdownMenu, DropdownMenuContent,
15
+ DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger,
16
+ } from '@/components/ui/dropdown-menu';
17
+ import { Button } from '@/components/ui/button';
18
+
19
+ interface StudioMobileHeaderProps {
20
+ connections: DatabaseConnection[];
21
+ activeConnection: DatabaseConnection | null;
22
+ connectionPulse: 'healthy' | 'degraded' | 'error' | null;
23
+ user: { role?: string } | null;
24
+ isAdmin: boolean;
25
+ activeMobileTab: 'database' | 'schema' | 'editor';
26
+ isExecuting: boolean;
27
+ currentQuery: string;
28
+ queryEditorRef: RefObject<QueryEditorRef | null>;
29
+ transactionActive: boolean;
30
+ playgroundMode: boolean;
31
+ editingEnabled: boolean;
32
+ onSelectConnection: (conn: DatabaseConnection) => void;
33
+ onAddConnection: () => void;
34
+ onLogout: () => void;
35
+ onSaveQuery: () => void;
36
+ onClearQuery: () => void;
37
+ onExecuteQuery: () => void;
38
+ onCancelQuery: () => void;
39
+ onBeginTransaction: () => void;
40
+ onCommitTransaction: () => void;
41
+ onRollbackTransaction: () => void;
42
+ onTogglePlayground: () => void;
43
+ onToggleEditing: () => void;
44
+ onImport: () => void;
45
+ onExplain?: () => void;
46
+ }
47
+
48
+ export function StudioMobileHeader({
49
+ connections,
50
+ activeConnection,
51
+ connectionPulse,
52
+ user,
53
+ isAdmin,
54
+ activeMobileTab,
55
+ isExecuting,
56
+ currentQuery,
57
+ queryEditorRef,
58
+ transactionActive,
59
+ playgroundMode,
60
+ editingEnabled,
61
+ onSelectConnection,
62
+ onAddConnection,
63
+ onLogout,
64
+ onSaveQuery,
65
+ onClearQuery,
66
+ onExecuteQuery,
67
+ onCancelQuery,
68
+ onBeginTransaction,
69
+ onCommitTransaction,
70
+ onRollbackTransaction,
71
+ onTogglePlayground,
72
+ onToggleEditing,
73
+ onImport,
74
+ onExplain,
75
+ }: StudioMobileHeaderProps) {
76
+ const router = useRouter();
77
+
78
+ return (
79
+ <header className="md:hidden border-b border-white/5 bg-[#0a0a0a]/95 backdrop-blur-xl sticky top-0 z-30">
80
+ {/* Row 1: DB Selector + Connection Info + User */}
81
+ <div className="h-12 flex items-center justify-between px-3">
82
+ <div className="flex items-center gap-2 flex-1 min-w-0">
83
+ <DropdownMenu>
84
+ <DropdownMenuTrigger asChild>
85
+ <Button
86
+ variant="outline"
87
+ size="sm"
88
+ className="h-8 px-2 gap-1 bg-[#111] border-white/10 hover:bg-white/5 text-zinc-300 max-w-[160px]"
89
+ >
90
+ <Database className="w-3.5 h-3.5 text-blue-400 shrink-0" />
91
+ <span className="truncate text-xs font-medium">
92
+ {activeConnection ? activeConnection.name : 'Select DB'}
93
+ </span>
94
+ <ChevronDown className="w-3 h-3 text-zinc-500 shrink-0" />
95
+ </Button>
96
+ </DropdownMenuTrigger>
97
+ <DropdownMenuContent align="start" className="w-64 bg-[#0d0d0d] border-white/10">
98
+ {connections.length === 0 ? (
99
+ <DropdownMenuItem onClick={onAddConnection} className="text-zinc-400 cursor-pointer">
100
+ <Plus className="w-4 h-4 mr-2" /> Add Connection
101
+ </DropdownMenuItem>
102
+ ) : (
103
+ <>
104
+ {connections.map((c) => (
105
+ <DropdownMenuItem
106
+ key={c.id}
107
+ onClick={() => onSelectConnection(c)}
108
+ className={cn(
109
+ "cursor-pointer",
110
+ activeConnection?.id === c.id && "bg-blue-600/20 text-blue-400"
111
+ )}
112
+ >
113
+ <Database className="w-4 h-4 mr-2" />
114
+ <span className="truncate">{c.name}</span>
115
+ {activeConnection?.id === c.id && (
116
+ <div className="ml-auto w-1.5 h-1.5 rounded-full bg-blue-500" />
117
+ )}
118
+ </DropdownMenuItem>
119
+ ))}
120
+ <DropdownMenuItem
121
+ onClick={onAddConnection}
122
+ className="text-zinc-500 cursor-pointer border-t border-white/5 mt-1"
123
+ >
124
+ <Plus className="w-4 h-4 mr-2" /> Add New
125
+ </DropdownMenuItem>
126
+ </>
127
+ )}
128
+ </DropdownMenuContent>
129
+ </DropdownMenu>
130
+
131
+ {activeConnection && (
132
+ <span className="text-[10px] text-emerald-500 font-medium px-1.5 py-0.5 rounded bg-emerald-500/10">
133
+ Online
134
+ </span>
135
+ )}
136
+ </div>
137
+
138
+ <div className="flex items-center gap-1">
139
+ <Button
140
+ variant="ghost"
141
+ size="sm"
142
+ className="h-8 w-8 p-0 text-zinc-500 hover:text-purple-400"
143
+ onClick={() => router.push('/monitoring')}
144
+ >
145
+ <Gauge className="w-4 h-4" />
146
+ </Button>
147
+ {connectionPulse && (
148
+ <div className="flex items-center gap-1 px-1.5 py-0.5 rounded bg-white/5" title={`Connection: ${connectionPulse}`}>
149
+ <div className={cn(
150
+ "w-1.5 h-1.5 rounded-full",
151
+ connectionPulse === 'healthy' && "bg-emerald-500 animate-pulse",
152
+ connectionPulse === 'degraded' && "bg-amber-500",
153
+ connectionPulse === 'error' && "bg-red-500",
154
+ )} />
155
+ </div>
156
+ )}
157
+ {user && (
158
+ <DropdownMenu>
159
+ <DropdownMenuTrigger asChild>
160
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0">
161
+ <User className="w-4 h-4 text-zinc-400" />
162
+ </Button>
163
+ </DropdownMenuTrigger>
164
+ <DropdownMenuContent align="end" className="bg-[#0d0d0d] border-white/10">
165
+ {isAdmin && (
166
+ <DropdownMenuItem onClick={() => router.push('/admin')} className="cursor-pointer">
167
+ <Settings className="w-4 h-4 mr-2" /> Admin Dashboard
168
+ </DropdownMenuItem>
169
+ )}
170
+ <DropdownMenuItem onClick={() => router.push('/monitoring')} className="cursor-pointer">
171
+ <Gauge className="w-4 h-4 mr-2" /> Monitoring
172
+ </DropdownMenuItem>
173
+ <div className="border-t border-white/5 my-1" />
174
+ <DropdownMenuItem onClick={onLogout} className="text-red-400 cursor-pointer">
175
+ <LogOut className="w-4 h-4 mr-2" /> Logout
176
+ </DropdownMenuItem>
177
+ <div className="border-t border-white/5 mt-1 pt-1 px-2 pb-1">
178
+ <span className="text-[10px] text-zinc-500 font-mono">v{process.env.NEXT_PUBLIC_APP_VERSION}</span>
179
+ </div>
180
+ </DropdownMenuContent>
181
+ </DropdownMenu>
182
+ )}
183
+ </div>
184
+ </div>
185
+
186
+ {/* Row 2: Actions + RUN (only show when on editor tab) */}
187
+ {activeMobileTab === 'editor' && (
188
+ <div className="h-10 flex items-center justify-between px-3 border-t border-white/5 bg-[#080808]">
189
+ <div className="flex items-center gap-1">
190
+ <Button
191
+ variant="ghost"
192
+ size="sm"
193
+ className="h-7 px-2 gap-1 text-[10px] font-bold text-zinc-500 hover:text-blue-400"
194
+ onClick={() => queryEditorRef.current?.toggleAi()}
195
+ >
196
+ <Sparkles className="w-3.5 h-3.5" />
197
+ AI
198
+ </Button>
199
+
200
+ <DropdownMenu>
201
+ <DropdownMenuTrigger asChild>
202
+ <Button variant="ghost" size="sm" className="h-7 px-2 gap-1 text-[10px] text-zinc-500">
203
+ <MoreVertical className="w-3.5 h-3.5" />
204
+ </Button>
205
+ </DropdownMenuTrigger>
206
+ <DropdownMenuContent align="start" className="bg-[#0d0d0d] border-white/10 w-48">
207
+ <DropdownMenuItem
208
+ onClick={() => queryEditorRef.current?.format()}
209
+ className="cursor-pointer text-xs"
210
+ >
211
+ <AlignLeft className="w-4 h-4 mr-2" /> Format SQL
212
+ </DropdownMenuItem>
213
+ <DropdownMenuItem
214
+ onClick={() => {
215
+ const query = queryEditorRef.current?.getValue() || currentQuery;
216
+ navigator.clipboard.writeText(query);
217
+ }}
218
+ className="cursor-pointer text-xs"
219
+ >
220
+ <Copy className="w-4 h-4 mr-2" /> Copy Query
221
+ </DropdownMenuItem>
222
+ <DropdownMenuItem
223
+ onClick={onClearQuery}
224
+ className="cursor-pointer text-xs text-red-400"
225
+ >
226
+ <Trash2 className="w-4 h-4 mr-2" /> Clear
227
+ </DropdownMenuItem>
228
+ <DropdownMenuItem
229
+ onClick={onSaveQuery}
230
+ className="cursor-pointer text-xs"
231
+ >
232
+ <Save className="w-4 h-4 mr-2" /> Save Query
233
+ </DropdownMenuItem>
234
+
235
+ {onExplain && (
236
+ <>
237
+ <DropdownMenuSeparator className="bg-white/5" />
238
+ <DropdownMenuItem
239
+ onClick={onExplain}
240
+ className="cursor-pointer text-xs text-amber-400"
241
+ >
242
+ <Zap className="w-4 h-4 mr-2" /> Explain Plan
243
+ </DropdownMenuItem>
244
+ </>
245
+ )}
246
+
247
+ <DropdownMenuSeparator className="bg-white/5" />
248
+ <div className="px-2 py-1">
249
+ <span className="text-[9px] font-bold text-zinc-600 uppercase tracking-widest">Advanced</span>
250
+ </div>
251
+
252
+ {!transactionActive ? (
253
+ <DropdownMenuItem
254
+ onClick={onBeginTransaction}
255
+ className="cursor-pointer text-xs"
256
+ disabled={!activeConnection}
257
+ >
258
+ <PlayCircle className="w-4 h-4 mr-2" /> BEGIN Transaction
259
+ </DropdownMenuItem>
260
+ ) : (
261
+ <>
262
+ <DropdownMenuItem
263
+ onClick={onCommitTransaction}
264
+ className="cursor-pointer text-xs text-emerald-400"
265
+ >
266
+ <PlayCircle className="w-4 h-4 mr-2" /> COMMIT
267
+ </DropdownMenuItem>
268
+ <DropdownMenuItem
269
+ onClick={onRollbackTransaction}
270
+ className="cursor-pointer text-xs text-red-400"
271
+ >
272
+ <PlayCircle className="w-4 h-4 mr-2" /> ROLLBACK
273
+ </DropdownMenuItem>
274
+ </>
275
+ )}
276
+
277
+ <DropdownMenuItem
278
+ onClick={onTogglePlayground}
279
+ className="cursor-pointer text-xs"
280
+ >
281
+ <Pencil className="w-4 h-4 mr-2" />
282
+ {playgroundMode ? 'Disable Sandbox' : 'Enable Sandbox'}
283
+ </DropdownMenuItem>
284
+
285
+ <DropdownMenuItem
286
+ onClick={onToggleEditing}
287
+ className="cursor-pointer text-xs"
288
+ >
289
+ <Edit3 className="w-4 h-4 mr-2" />
290
+ {editingEnabled ? 'Disable Editing' : 'Enable Editing'}
291
+ </DropdownMenuItem>
292
+
293
+ <DropdownMenuItem
294
+ onClick={onImport}
295
+ className="cursor-pointer text-xs"
296
+ disabled={!activeConnection}
297
+ >
298
+ <Upload className="w-4 h-4 mr-2" /> Import Data
299
+ </DropdownMenuItem>
300
+ </DropdownMenuContent>
301
+ </DropdownMenu>
302
+
303
+ {/* Status badges */}
304
+ {transactionActive && (
305
+ <span className="text-[9px] font-black text-amber-400 px-1.5 py-0.5 rounded bg-amber-500/10 border border-amber-500/20">
306
+ TXN
307
+ </span>
308
+ )}
309
+ {playgroundMode && (
310
+ <span className="text-[9px] font-black text-purple-400 px-1.5 py-0.5 rounded bg-purple-500/10 border border-purple-500/20">
311
+ SANDBOX
312
+ </span>
313
+ )}
314
+ </div>
315
+
316
+ {isExecuting ? (
317
+ <Button
318
+ size="sm"
319
+ className="bg-red-600 hover:bg-red-500 text-white font-bold text-[11px] h-7 px-4 gap-1.5"
320
+ onClick={onCancelQuery}
321
+ >
322
+ <Square className="w-3 h-3 fill-current" />
323
+ CANCEL
324
+ </Button>
325
+ ) : (
326
+ <Button
327
+ size="sm"
328
+ className="bg-blue-600 hover:bg-blue-500 text-white font-bold text-[11px] h-7 px-4 gap-1.5"
329
+ onClick={onExecuteQuery}
330
+ disabled={!activeConnection}
331
+ >
332
+ <Play className="w-3 h-3 fill-current" />
333
+ RUN
334
+ </Button>
335
+ )}
336
+ </div>
337
+ )}
338
+ </header>
339
+ );
340
+ }