@libredb/studio 0.9.7 → 0.9.13

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 (688) hide show
  1. package/dist/chunk-34YQUUCM.mjs +319 -0
  2. package/dist/chunk-34YQUUCM.mjs.map +1 -0
  3. package/dist/chunk-4LVB3K53.mjs +37 -0
  4. package/dist/chunk-4LVB3K53.mjs.map +1 -0
  5. package/dist/chunk-6DRZXXNT.mjs +100 -0
  6. package/dist/chunk-6DRZXXNT.mjs.map +1 -0
  7. package/dist/chunk-CPF7XWV5.mjs +1289 -0
  8. package/dist/chunk-CPF7XWV5.mjs.map +1 -0
  9. package/dist/chunk-CZVV3JJB.mjs +160 -0
  10. package/dist/chunk-CZVV3JJB.mjs.map +1 -0
  11. package/dist/chunk-D4WVWWWF.js +332 -0
  12. package/dist/chunk-D4WVWWWF.js.map +1 -0
  13. package/dist/chunk-DY3KXE44.mjs +3 -0
  14. package/dist/chunk-DY3KXE44.mjs.map +1 -0
  15. package/dist/chunk-FYSE52VB.js +242 -0
  16. package/dist/chunk-FYSE52VB.js.map +1 -0
  17. package/dist/chunk-G3S66G64.mjs +6673 -0
  18. package/dist/chunk-G3S66G64.mjs.map +1 -0
  19. package/dist/chunk-G4WYE6TI.js +4 -0
  20. package/dist/chunk-G4WYE6TI.js.map +1 -0
  21. package/dist/chunk-HGPD6PWV.js +1310 -0
  22. package/dist/chunk-HGPD6PWV.js.map +1 -0
  23. package/dist/chunk-JZO5KRZN.js +165 -0
  24. package/dist/chunk-JZO5KRZN.js.map +1 -0
  25. package/dist/chunk-KV356UXJ.js +253 -0
  26. package/dist/chunk-KV356UXJ.js.map +1 -0
  27. package/dist/chunk-PPODO6HX.mjs +237 -0
  28. package/dist/chunk-PPODO6HX.mjs.map +1 -0
  29. package/dist/chunk-PTIRB2JO.js +258 -0
  30. package/dist/chunk-PTIRB2JO.js.map +1 -0
  31. package/dist/chunk-Q6LRDBK7.js +42 -0
  32. package/dist/chunk-Q6LRDBK7.js.map +1 -0
  33. package/dist/chunk-QJP5FZRY.mjs +255 -0
  34. package/dist/chunk-QJP5FZRY.mjs.map +1 -0
  35. package/dist/chunk-R3POCJK6.mjs +248 -0
  36. package/dist/chunk-R3POCJK6.mjs.map +1 -0
  37. package/dist/chunk-RCQB4FCE.js +186 -0
  38. package/dist/chunk-RCQB4FCE.js.map +1 -0
  39. package/dist/chunk-SR5DRGBX.mjs +174 -0
  40. package/dist/chunk-SR5DRGBX.mjs.map +1 -0
  41. package/dist/chunk-VLCRUZX7.js +102 -0
  42. package/dist/chunk-VLCRUZX7.js.map +1 -0
  43. package/dist/chunk-Y52UIFEX.js +6741 -0
  44. package/dist/chunk-Y52UIFEX.js.map +1 -0
  45. package/dist/components.d.mts +273 -0
  46. package/dist/components.d.ts +273 -0
  47. package/dist/components.js +59 -0
  48. package/dist/components.js.map +1 -0
  49. package/dist/components.mjs +6 -0
  50. package/dist/components.mjs.map +1 -0
  51. package/dist/custom-BNDOYC5P.js +134 -0
  52. package/dist/custom-BNDOYC5P.js.map +1 -0
  53. package/dist/custom-S2EKFMP3.mjs +132 -0
  54. package/dist/custom-S2EKFMP3.mjs.map +1 -0
  55. package/dist/gemini-4ASHNK4H.js +81 -0
  56. package/dist/gemini-4ASHNK4H.js.map +1 -0
  57. package/dist/gemini-C5RBLQEJ.mjs +79 -0
  58. package/dist/gemini-C5RBLQEJ.mjs.map +1 -0
  59. package/dist/index.d.mts +6 -0
  60. package/dist/index.d.ts +6 -0
  61. package/dist/index.js +95 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/index.mjs +10 -0
  64. package/dist/index.mjs.map +1 -0
  65. package/dist/mongodb-XMZEZA4A.mjs +748 -0
  66. package/dist/mongodb-XMZEZA4A.mjs.map +1 -0
  67. package/dist/mongodb-YQJJTLX3.js +750 -0
  68. package/dist/mongodb-YQJJTLX3.js.map +1 -0
  69. package/dist/mssql-PMOU4D36.js +916 -0
  70. package/dist/mssql-PMOU4D36.js.map +1 -0
  71. package/{src/lib/db/providers/sql/mssql.ts → dist/mssql-ZH5VP2C5.mjs} +268 -423
  72. package/dist/mssql-ZH5VP2C5.mjs.map +1 -0
  73. package/{src/lib/db/providers/sql/mysql.ts → dist/mysql-I3WJQXN2.mjs} +277 -428
  74. package/dist/mysql-I3WJQXN2.mjs.map +1 -0
  75. package/dist/mysql-Y3MSA5QY.js +833 -0
  76. package/dist/mysql-Y3MSA5QY.js.map +1 -0
  77. package/dist/ollama-26BYLVEV.mjs +115 -0
  78. package/dist/ollama-26BYLVEV.mjs.map +1 -0
  79. package/dist/ollama-HVWAGKQC.js +117 -0
  80. package/dist/ollama-HVWAGKQC.js.map +1 -0
  81. package/dist/openai-4U56KPG7.mjs +111 -0
  82. package/dist/openai-4U56KPG7.mjs.map +1 -0
  83. package/dist/openai-AK3R37BS.js +113 -0
  84. package/dist/openai-AK3R37BS.js.map +1 -0
  85. package/dist/oracle-L6VEAVXO.js +917 -0
  86. package/dist/oracle-L6VEAVXO.js.map +1 -0
  87. package/{src/lib/db/providers/sql/oracle.ts → dist/oracle-P2G7T4P4.mjs} +321 -454
  88. package/dist/oracle-P2G7T4P4.mjs.map +1 -0
  89. package/{src/lib/db/providers/sql/postgres.ts → dist/postgres-O5KOQUVP.mjs} +261 -471
  90. package/dist/postgres-O5KOQUVP.mjs.map +1 -0
  91. package/dist/postgres-RLCWNFFX.js +971 -0
  92. package/dist/postgres-RLCWNFFX.js.map +1 -0
  93. package/dist/providers.d.mts +149 -0
  94. package/dist/providers.d.ts +149 -0
  95. package/dist/providers.js +44 -0
  96. package/dist/providers.js.map +1 -0
  97. package/dist/providers.mjs +7 -0
  98. package/dist/providers.mjs.map +1 -0
  99. package/dist/redis-4WMQOVLX.mjs +435 -0
  100. package/dist/redis-4WMQOVLX.mjs.map +1 -0
  101. package/dist/redis-QVQ6YU62.js +441 -0
  102. package/dist/redis-QVQ6YU62.js.map +1 -0
  103. package/dist/sqlite-4I2P2OGQ.js +554 -0
  104. package/dist/sqlite-4I2P2OGQ.js.map +1 -0
  105. package/dist/sqlite-OA4YJX5S.mjs +531 -0
  106. package/dist/sqlite-OA4YJX5S.mjs.map +1 -0
  107. package/dist/types-BJvJfxSY.d.mts +141 -0
  108. package/dist/types-BJvJfxSY.d.ts +141 -0
  109. package/dist/types-ClAg_v5k.d.mts +343 -0
  110. package/dist/types-Der_X8E8.d.ts +343 -0
  111. package/dist/types.d.mts +2 -0
  112. package/dist/types.d.ts +2 -0
  113. package/dist/types.js +6 -0
  114. package/dist/types.js.map +1 -0
  115. package/dist/types.mjs +3 -0
  116. package/dist/types.mjs.map +1 -0
  117. package/dist/workspace.d.mts +80 -0
  118. package/dist/workspace.d.ts +80 -0
  119. package/dist/workspace.js +4174 -0
  120. package/dist/workspace.js.map +1 -0
  121. package/dist/workspace.mjs +4147 -0
  122. package/dist/workspace.mjs.map +1 -0
  123. package/package.json +60 -5
  124. package/.claude/settings.local.json +0 -127
  125. package/.cursorrules +0 -426
  126. package/.devin/wiki.json +0 -143
  127. package/.dockerignore +0 -80
  128. package/.env.example +0 -159
  129. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -49
  130. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -29
  131. package/.github/PULL_REQUEST_TEMPLATE.md +0 -57
  132. package/.github/workflows/ci.yml +0 -185
  133. package/.github/workflows/codeql.yml +0 -57
  134. package/.github/workflows/docker-build-push.yml +0 -118
  135. package/.github/workflows/helm-release.yml +0 -113
  136. package/CLAUDE.md +0 -265
  137. package/CODE_OF_CONDUCT.md +0 -124
  138. package/CONTRIBUTING.md +0 -154
  139. package/Dockerfile +0 -73
  140. package/SECURITY.md +0 -107
  141. package/artifacthub-repo.yml +0 -4
  142. package/bun.lock +0 -1714
  143. package/bunfig.toml +0 -3
  144. package/charts/libredb-studio/.helmignore +0 -11
  145. package/charts/libredb-studio/Chart.lock +0 -6
  146. package/charts/libredb-studio/Chart.yaml +0 -50
  147. package/charts/libredb-studio/README.md +0 -206
  148. package/charts/libredb-studio/templates/NOTES.txt +0 -59
  149. package/charts/libredb-studio/templates/_helpers.tpl +0 -135
  150. package/charts/libredb-studio/templates/configmap.yaml +0 -37
  151. package/charts/libredb-studio/templates/deployment.yaml +0 -184
  152. package/charts/libredb-studio/templates/hpa.yaml +0 -32
  153. package/charts/libredb-studio/templates/ingress.yaml +0 -41
  154. package/charts/libredb-studio/templates/networkpolicy.yaml +0 -50
  155. package/charts/libredb-studio/templates/pdb.yaml +0 -18
  156. package/charts/libredb-studio/templates/pvc.yaml +0 -23
  157. package/charts/libredb-studio/templates/secret.yaml +0 -30
  158. package/charts/libredb-studio/templates/seed-configmap.yaml +0 -11
  159. package/charts/libredb-studio/templates/service.yaml +0 -22
  160. package/charts/libredb-studio/templates/serviceaccount.yaml +0 -13
  161. package/charts/libredb-studio/values.schema.json +0 -246
  162. package/charts/libredb-studio/values.yaml +0 -286
  163. package/components.json +0 -22
  164. package/conductor/code_styleguides/typescript.md +0 -43
  165. package/conductor/product-guidelines.md +0 -43
  166. package/conductor/product.md +0 -3
  167. package/conductor/setup_state.json +0 -1
  168. package/conductor/tech-stack.md +0 -39
  169. package/conductor/tracks/enhance_postgres_monitoring_20251227/metadata.json +0 -8
  170. package/conductor/tracks/enhance_postgres_monitoring_20251227/plan.md +0 -44
  171. package/conductor/tracks/enhance_postgres_monitoring_20251227/spec.md +0 -31
  172. package/conductor/tracks.md +0 -8
  173. package/conductor/workflow.md +0 -333
  174. package/database-compose.yml +0 -55
  175. package/docker/postgres-init/01-extensions.sql +0 -10
  176. package/docker/postgres-init/02-sample-data.sql +0 -585
  177. package/docker/postgres.yml +0 -68
  178. package/docker-compose.yml +0 -38
  179. package/docs/AI_PLAN.md +0 -74
  180. package/docs/API_DOCS.md +0 -875
  181. package/docs/ARCHITECTURE.md +0 -218
  182. package/docs/DATABASE_PROVIDERS.md +0 -358
  183. package/docs/FEATURES.md +0 -116
  184. package/docs/HELM_CHART.md +0 -252
  185. package/docs/LOGIN_PAGE.md +0 -178
  186. package/docs/MONACO_EDITOR_PERFORMANCE.md +0 -315
  187. package/docs/OIDC_ARCH.md +0 -681
  188. package/docs/OIDC_SETUP.md +0 -322
  189. package/docs/POSTGRES_METRICS.md +0 -516
  190. package/docs/QUERY_OPTIMIZATION.md +0 -370
  191. package/docs/SEED_CONNECTIONS.md +0 -468
  192. package/docs/SQL_ALIAS_COMPLETION.md +0 -190
  193. package/docs/STORAGE_ARCHITECTURE.md +0 -565
  194. package/docs/STORAGE_QUICK_SETUP.md +0 -419
  195. package/docs/TECHNICAL_PLAN.md +0 -36
  196. package/docs/THEMING.md +0 -345
  197. package/docs/adding-a-new-database-provider.md +0 -642
  198. package/docs/backlogs/000-PLATFORM_DATA_SYNC_DATABASE.md +0 -360
  199. package/docs/backlogs/001-INLINE_DATA_EDITING.md +0 -118
  200. package/docs/backlogs/002-DATA_IMPORT.md +0 -215
  201. package/docs/backlogs/003-QUERY_TIME_MACHINE.md +0 -183
  202. package/docs/backlogs/004-AI_DATA_STORYTELLER.md +0 -292
  203. package/docs/backlogs/005-QUERY_PLAYGROUND.md +0 -352
  204. package/docs/backlogs/006-DATA_MASKING.md +0 -418
  205. package/docs/enterprise-features.md +0 -718
  206. package/docs/kubernetes-helm-chart-artifacthub-plan.md +0 -803
  207. package/docs/medium-koyeb-article-en.md +0 -215
  208. package/docs/plans/test-plans.md +0 -445
  209. package/docs/releases/RELEASE.V0.3.0.md +0 -22
  210. package/docs/releases/RELEASE.V0.4.0.md +0 -154
  211. package/docs/releases/RELEASE.V0.5.0.md +0 -252
  212. package/docs/releases/RELEASE_v0.5.6.md +0 -145
  213. package/docs/releases/RELEASE_v0.6.1.md +0 -303
  214. package/docs/releases/RELEASE_v0.6.7.md +0 -292
  215. package/docs/releases/RELEASE_v0.7.0.md +0 -332
  216. package/docs/releases/RELEASE_v0.8.0.md +0 -521
  217. package/docs/sampledb/titanic.sql +0 -1379
  218. package/docs/superpowers/plans/2026-03-25-seed-connections.md +0 -1362
  219. package/docs/superpowers/specs/2026-03-25-seed-connections-design.md +0 -590
  220. package/e2e/admin-dashboard.spec.ts +0 -64
  221. package/e2e/connection-management.spec.ts +0 -58
  222. package/e2e/export.spec.ts +0 -34
  223. package/e2e/login.spec.ts +0 -85
  224. package/e2e/query-execution.spec.ts +0 -35
  225. package/e2e/tab-management.spec.ts +0 -64
  226. package/eslint.config.mjs +0 -28
  227. package/fly.toml +0 -43
  228. package/next.config.ts +0 -32
  229. package/playwright.config.ts +0 -34
  230. package/postcss.config.mjs +0 -7
  231. package/public/favicon-32x32.png +0 -0
  232. package/public/favicon.ico +0 -0
  233. package/public/file.svg +0 -1
  234. package/public/globe.svg +0 -1
  235. package/public/logo.svg +0 -32
  236. package/public/next.svg +0 -1
  237. package/public/screenshots/code-generator.png +0 -0
  238. package/public/screenshots/connection-modal.png +0 -0
  239. package/public/screenshots/data-profiler.png +0 -0
  240. package/public/screenshots/erd-diagram.png +0 -0
  241. package/public/screenshots/hero-editor.png +0 -0
  242. package/public/screenshots/nl2sql.png +0 -0
  243. package/public/vercel.svg +0 -1
  244. package/public/window.svg +0 -1
  245. package/render.yaml +0 -58
  246. package/scripts/merge-lcov.mjs +0 -239
  247. package/sonar-project.properties +0 -16
  248. package/src/app/admin/error.tsx +0 -46
  249. package/src/app/admin/page.tsx +0 -10
  250. package/src/app/api/admin/audit/route.ts +0 -52
  251. package/src/app/api/admin/fleet-health/route.ts +0 -81
  252. package/src/app/api/ai/autopilot/route.ts +0 -105
  253. package/src/app/api/ai/chat/route.ts +0 -132
  254. package/src/app/api/ai/describe-schema/route.ts +0 -52
  255. package/src/app/api/ai/explain/route.ts +0 -86
  256. package/src/app/api/ai/impact/route.ts +0 -97
  257. package/src/app/api/ai/index-advisor/route.ts +0 -98
  258. package/src/app/api/ai/nl2sql/route.ts +0 -87
  259. package/src/app/api/ai/query-safety/route.ts +0 -87
  260. package/src/app/api/auth/login/route.ts +0 -62
  261. package/src/app/api/auth/logout/route.ts +0 -25
  262. package/src/app/api/auth/me/route.ts +0 -10
  263. package/src/app/api/auth/oidc/callback/route.ts +0 -82
  264. package/src/app/api/auth/oidc/login/route.ts +0 -43
  265. package/src/app/api/connections/managed/route.ts +0 -35
  266. package/src/app/api/db/cancel/route.ts +0 -42
  267. package/src/app/api/db/disconnect/route.ts +0 -28
  268. package/src/app/api/db/health/route.ts +0 -49
  269. package/src/app/api/db/maintenance/route.ts +0 -72
  270. package/src/app/api/db/monitoring/route.ts +0 -62
  271. package/src/app/api/db/multi-query/route.ts +0 -116
  272. package/src/app/api/db/pool-stats/route.ts +0 -37
  273. package/src/app/api/db/profile/route.ts +0 -144
  274. package/src/app/api/db/provider-meta/route.ts +0 -49
  275. package/src/app/api/db/query/route.ts +0 -50
  276. package/src/app/api/db/schema/route.ts +0 -47
  277. package/src/app/api/db/schema-snapshot/route.ts +0 -42
  278. package/src/app/api/db/test-connection/route.ts +0 -55
  279. package/src/app/api/db/transaction/route.ts +0 -111
  280. package/src/app/api/storage/[collection]/route.ts +0 -67
  281. package/src/app/api/storage/config/route.ts +0 -17
  282. package/src/app/api/storage/migrate/route.ts +0 -45
  283. package/src/app/api/storage/route.ts +0 -32
  284. package/src/app/error.tsx +0 -49
  285. package/src/app/global-error.tsx +0 -55
  286. package/src/app/globals.css +0 -146
  287. package/src/app/icon.svg +0 -42
  288. package/src/app/layout.tsx +0 -34
  289. package/src/app/login/login-form.tsx +0 -301
  290. package/src/app/login/page.tsx +0 -11
  291. package/src/app/monitoring/page.tsx +0 -8
  292. package/src/app/not-found.tsx +0 -29
  293. package/src/app/page.tsx +0 -5
  294. package/src/components/AIAutopilotPanel.tsx +0 -238
  295. package/src/components/CodeGenerator.tsx +0 -271
  296. package/src/components/CommandPalette.tsx +0 -227
  297. package/src/components/ConnectionModal.tsx +0 -759
  298. package/src/components/CreateTableModal.tsx +0 -281
  299. package/src/components/DataCharts.tsx +0 -962
  300. package/src/components/DataImportModal.tsx +0 -582
  301. package/src/components/DataProfiler.tsx +0 -335
  302. package/src/components/DatabaseDocs.tsx +0 -251
  303. package/src/components/MaskingSettings.tsx +0 -414
  304. package/src/components/MobileNav.tsx +0 -50
  305. package/src/components/NL2SQLPanel.tsx +0 -281
  306. package/src/components/PivotTable.tsx +0 -257
  307. package/src/components/QueryEditor.tsx +0 -760
  308. package/src/components/QueryHistory.tsx +0 -344
  309. package/src/components/QuerySafetyDialog.tsx +0 -290
  310. package/src/components/ResultsGrid.tsx +0 -644
  311. package/src/components/SaveQueryModal.tsx +0 -104
  312. package/src/components/SavedQueries.tsx +0 -128
  313. package/src/components/SchemaDiagram.tsx +0 -473
  314. package/src/components/SchemaDiff.tsx +0 -473
  315. package/src/components/SnapshotTimeline.tsx +0 -116
  316. package/src/components/Studio.tsx +0 -639
  317. package/src/components/TestDataGenerator.tsx +0 -261
  318. package/src/components/VisualExplain.tsx +0 -820
  319. package/src/components/admin/AdminDashboard.tsx +0 -163
  320. package/src/components/admin/tabs/AuditTab.tsx +0 -531
  321. package/src/components/admin/tabs/MonitoringEmbed.tsx +0 -11
  322. package/src/components/admin/tabs/OperationsTab.tsx +0 -646
  323. package/src/components/admin/tabs/OverviewTab.tsx +0 -1328
  324. package/src/components/admin/tabs/SecurityTab.tsx +0 -284
  325. package/src/components/community-section.tsx +0 -92
  326. package/src/components/icons/db-icons.tsx +0 -84
  327. package/src/components/libredb-logo.tsx +0 -61
  328. package/src/components/monitoring/MonitoringDashboard.tsx +0 -345
  329. package/src/components/monitoring/tabs/MetricChart.tsx +0 -82
  330. package/src/components/monitoring/tabs/OverviewTab.tsx +0 -263
  331. package/src/components/monitoring/tabs/PerformanceTab.tsx +0 -254
  332. package/src/components/monitoring/tabs/PoolTab.tsx +0 -174
  333. package/src/components/monitoring/tabs/QueriesTab.tsx +0 -287
  334. package/src/components/monitoring/tabs/SessionsTab.tsx +0 -316
  335. package/src/components/monitoring/tabs/StorageTab.tsx +0 -335
  336. package/src/components/monitoring/tabs/TablesTab.tsx +0 -300
  337. package/src/components/results-grid/ResultCard.tsx +0 -111
  338. package/src/components/results-grid/RowDetailSheet.tsx +0 -178
  339. package/src/components/results-grid/StatsBar.tsx +0 -201
  340. package/src/components/results-grid/index.ts +0 -1
  341. package/src/components/results-grid/utils.ts +0 -23
  342. package/src/components/schema-explorer/ColumnList.tsx +0 -53
  343. package/src/components/schema-explorer/SchemaExplorer.tsx +0 -182
  344. package/src/components/schema-explorer/TableItem.tsx +0 -210
  345. package/src/components/schema-explorer/index.ts +0 -1
  346. package/src/components/sidebar/ConnectionItem.tsx +0 -105
  347. package/src/components/sidebar/ConnectionsList.tsx +0 -62
  348. package/src/components/sidebar/Sidebar.tsx +0 -130
  349. package/src/components/sidebar/index.ts +0 -2
  350. package/src/components/studio/BottomPanel.tsx +0 -286
  351. package/src/components/studio/QueryToolbar.tsx +0 -180
  352. package/src/components/studio/StudioDesktopHeader.tsx +0 -114
  353. package/src/components/studio/StudioMobileHeader.tsx +0 -340
  354. package/src/components/studio/StudioTabBar.tsx +0 -82
  355. package/src/components/studio/index.ts +0 -5
  356. package/src/components/ui/accordion.tsx +0 -66
  357. package/src/components/ui/alert-dialog.tsx +0 -157
  358. package/src/components/ui/alert.tsx +0 -66
  359. package/src/components/ui/aspect-ratio.tsx +0 -11
  360. package/src/components/ui/avatar.tsx +0 -53
  361. package/src/components/ui/badge.tsx +0 -46
  362. package/src/components/ui/breadcrumb.tsx +0 -109
  363. package/src/components/ui/button-group.tsx +0 -83
  364. package/src/components/ui/button.tsx +0 -60
  365. package/src/components/ui/calendar.tsx +0 -216
  366. package/src/components/ui/card.tsx +0 -92
  367. package/src/components/ui/carousel.tsx +0 -241
  368. package/src/components/ui/chart.tsx +0 -357
  369. package/src/components/ui/checkbox.tsx +0 -32
  370. package/src/components/ui/collapsible.tsx +0 -33
  371. package/src/components/ui/command.tsx +0 -184
  372. package/src/components/ui/context-menu.tsx +0 -252
  373. package/src/components/ui/dialog.tsx +0 -143
  374. package/src/components/ui/drawer.tsx +0 -135
  375. package/src/components/ui/dropdown-menu.tsx +0 -257
  376. package/src/components/ui/empty.tsx +0 -104
  377. package/src/components/ui/field.tsx +0 -248
  378. package/src/components/ui/form.tsx +0 -167
  379. package/src/components/ui/hover-card.tsx +0 -44
  380. package/src/components/ui/input-group.tsx +0 -170
  381. package/src/components/ui/input-otp.tsx +0 -77
  382. package/src/components/ui/input.tsx +0 -21
  383. package/src/components/ui/item.tsx +0 -193
  384. package/src/components/ui/kbd.tsx +0 -28
  385. package/src/components/ui/label.tsx +0 -24
  386. package/src/components/ui/menubar.tsx +0 -276
  387. package/src/components/ui/navigation-menu.tsx +0 -168
  388. package/src/components/ui/pagination.tsx +0 -127
  389. package/src/components/ui/popover.tsx +0 -48
  390. package/src/components/ui/progress.tsx +0 -31
  391. package/src/components/ui/radio-group.tsx +0 -45
  392. package/src/components/ui/resizable.tsx +0 -56
  393. package/src/components/ui/scroll-area.tsx +0 -58
  394. package/src/components/ui/select.tsx +0 -187
  395. package/src/components/ui/separator.tsx +0 -28
  396. package/src/components/ui/sheet.tsx +0 -139
  397. package/src/components/ui/sidebar.tsx +0 -726
  398. package/src/components/ui/skeleton.tsx +0 -13
  399. package/src/components/ui/slider.tsx +0 -63
  400. package/src/components/ui/sonner.tsx +0 -40
  401. package/src/components/ui/spinner.tsx +0 -16
  402. package/src/components/ui/switch.tsx +0 -31
  403. package/src/components/ui/table.tsx +0 -116
  404. package/src/components/ui/tabs.tsx +0 -66
  405. package/src/components/ui/textarea.tsx +0 -18
  406. package/src/components/ui/toggle-group.tsx +0 -83
  407. package/src/components/ui/toggle.tsx +0 -47
  408. package/src/components/ui/tooltip.tsx +0 -61
  409. package/src/exports/components.ts +0 -15
  410. package/src/exports/index.ts +0 -4
  411. package/src/exports/providers.ts +0 -4
  412. package/src/exports/types.ts +0 -26
  413. package/src/hooks/use-ai-chat.ts +0 -182
  414. package/src/hooks/use-all-connections.ts +0 -66
  415. package/src/hooks/use-api-call.ts +0 -71
  416. package/src/hooks/use-auth.ts +0 -51
  417. package/src/hooks/use-connection-form.ts +0 -349
  418. package/src/hooks/use-connection-manager.ts +0 -169
  419. package/src/hooks/use-connection-payload.ts +0 -15
  420. package/src/hooks/use-inline-editing.ts +0 -109
  421. package/src/hooks/use-mobile.ts +0 -20
  422. package/src/hooks/use-monitoring-data.ts +0 -270
  423. package/src/hooks/use-provider-metadata.ts +0 -62
  424. package/src/hooks/use-query-execution.ts +0 -478
  425. package/src/hooks/use-storage-sync.ts +0 -259
  426. package/src/hooks/use-tab-manager.ts +0 -231
  427. package/src/hooks/use-toast.ts +0 -20
  428. package/src/hooks/use-transaction-control.ts +0 -64
  429. package/src/lib/api/error-codes.ts +0 -30
  430. package/src/lib/api/errors.ts +0 -236
  431. package/src/lib/api/with-error-handler.ts +0 -41
  432. package/src/lib/audit.ts +0 -105
  433. package/src/lib/auth.ts +0 -87
  434. package/src/lib/connection-string-parser.ts +0 -172
  435. package/src/lib/data-masking.ts +0 -385
  436. package/src/lib/db/base-provider.ts +0 -325
  437. package/src/lib/db/errors.ts +0 -317
  438. package/src/lib/db/factory.ts +0 -324
  439. package/src/lib/db/index.ts +0 -123
  440. package/src/lib/db/providers/document/index.ts +0 -6
  441. package/src/lib/db/providers/document/mongodb.ts +0 -992
  442. package/src/lib/db/providers/keyvalue/redis.ts +0 -554
  443. package/src/lib/db/providers/sql/index.ts +0 -11
  444. package/src/lib/db/providers/sql/sql-base.ts +0 -174
  445. package/src/lib/db/providers/sql/sqlite.ts +0 -721
  446. package/src/lib/db/types.ts +0 -437
  447. package/src/lib/db/utils/pool-manager.ts +0 -287
  448. package/src/lib/db/utils/query-limiter.ts +0 -239
  449. package/src/lib/db-ui-config.ts +0 -86
  450. package/src/lib/editor/mongodb-completions.ts +0 -172
  451. package/src/lib/editor/sql-completions.ts +0 -280
  452. package/src/lib/llm/base-provider.ts +0 -117
  453. package/src/lib/llm/factory.ts +0 -102
  454. package/src/lib/llm/index.ts +0 -90
  455. package/src/lib/llm/providers/custom.ts +0 -181
  456. package/src/lib/llm/providers/gemini.ts +0 -126
  457. package/src/lib/llm/providers/ollama.ts +0 -154
  458. package/src/lib/llm/providers/openai.ts +0 -146
  459. package/src/lib/llm/types.ts +0 -173
  460. package/src/lib/llm/utils/config.ts +0 -187
  461. package/src/lib/llm/utils/retry.ts +0 -119
  462. package/src/lib/llm/utils/streaming.ts +0 -202
  463. package/src/lib/logger.ts +0 -127
  464. package/src/lib/monitoring-thresholds.ts +0 -44
  465. package/src/lib/oidc.ts +0 -262
  466. package/src/lib/query-generators.ts +0 -61
  467. package/src/lib/schema-diff/diff-engine.ts +0 -273
  468. package/src/lib/schema-diff/migration-generator.ts +0 -208
  469. package/src/lib/schema-diff/types.ts +0 -55
  470. package/src/lib/seed/config-loader.ts +0 -79
  471. package/src/lib/seed/connection-filter.ts +0 -49
  472. package/src/lib/seed/credential-resolver.ts +0 -62
  473. package/src/lib/seed/index.ts +0 -40
  474. package/src/lib/seed/resolve-connection.ts +0 -57
  475. package/src/lib/seed/types.ts +0 -69
  476. package/src/lib/sql/alias-extractor.ts +0 -267
  477. package/src/lib/sql/index.ts +0 -8
  478. package/src/lib/sql/statement-splitter.ts +0 -167
  479. package/src/lib/sql/types.ts +0 -40
  480. package/src/lib/ssh/tunnel.ts +0 -142
  481. package/src/lib/storage/factory.ts +0 -84
  482. package/src/lib/storage/index.ts +0 -14
  483. package/src/lib/storage/local-storage.ts +0 -99
  484. package/src/lib/storage/providers/postgres.ts +0 -225
  485. package/src/lib/storage/providers/sqlite.ts +0 -153
  486. package/src/lib/storage/storage-facade.ts +0 -272
  487. package/src/lib/storage/types.ts +0 -75
  488. package/src/lib/time-series-buffer.ts +0 -58
  489. package/src/lib/types.ts +0 -173
  490. package/src/lib/utils.ts +0 -6
  491. package/src/proxy.ts +0 -104
  492. package/src/types/db-drivers.d.ts +0 -23
  493. package/src/types/html2canvas.d.ts +0 -9
  494. package/tests/api/admin/audit.test.ts +0 -178
  495. package/tests/api/admin/fleet-health.test.ts +0 -183
  496. package/tests/api/ai/autopilot.test.ts +0 -174
  497. package/tests/api/ai/chat.test.ts +0 -250
  498. package/tests/api/ai/describe-schema.test.ts +0 -266
  499. package/tests/api/ai/explain.test.ts +0 -199
  500. package/tests/api/ai/impact.test.ts +0 -168
  501. package/tests/api/ai/index-advisor.test.ts +0 -171
  502. package/tests/api/ai/nl2sql.test.ts +0 -202
  503. package/tests/api/ai/query-safety.test.ts +0 -196
  504. package/tests/api/auth/login.test.ts +0 -170
  505. package/tests/api/auth/logout.test.ts +0 -140
  506. package/tests/api/auth/me.test.ts +0 -73
  507. package/tests/api/auth/oidc-callback.test.ts +0 -215
  508. package/tests/api/auth/oidc-login.test.ts +0 -127
  509. package/tests/api/db/cancel.test.ts +0 -198
  510. package/tests/api/db/disconnect.test.ts +0 -124
  511. package/tests/api/db/health.test.ts +0 -222
  512. package/tests/api/db/maintenance.test.ts +0 -263
  513. package/tests/api/db/monitoring.test.ts +0 -221
  514. package/tests/api/db/multi-query.test.ts +0 -316
  515. package/tests/api/db/pool-stats.test.ts +0 -135
  516. package/tests/api/db/profile.test.ts +0 -330
  517. package/tests/api/db/provider-meta.test.ts +0 -193
  518. package/tests/api/db/query.test.ts +0 -314
  519. package/tests/api/db/schema-snapshot.test.ts +0 -170
  520. package/tests/api/db/schema.test.ts +0 -191
  521. package/tests/api/db/test-connection.test.ts +0 -185
  522. package/tests/api/db/transaction.test.ts +0 -314
  523. package/tests/api/proxy.test.ts +0 -191
  524. package/tests/api/seed/managed-route.test.ts +0 -113
  525. package/tests/api/storage/config.test.ts +0 -42
  526. package/tests/api/storage/storage-routes.test.ts +0 -309
  527. package/tests/components/AIAutopilotPanel.test.tsx +0 -756
  528. package/tests/components/AdminPage.test.tsx +0 -33
  529. package/tests/components/CodeGenerator.test.tsx +0 -182
  530. package/tests/components/CommandPalette.test.tsx +0 -428
  531. package/tests/components/CommunitySection.test.tsx +0 -91
  532. package/tests/components/ConnectionModal.mobile.test.tsx +0 -284
  533. package/tests/components/ConnectionModal.test.tsx +0 -570
  534. package/tests/components/CreateTableModal.test.tsx +0 -383
  535. package/tests/components/DataCharts.test.tsx +0 -739
  536. package/tests/components/DataImportModal.test.tsx +0 -751
  537. package/tests/components/DataProfiler.test.tsx +0 -589
  538. package/tests/components/DatabaseDocs.test.tsx +0 -353
  539. package/tests/components/LoginPage.test.tsx +0 -163
  540. package/tests/components/LoginPageOIDC.test.tsx +0 -92
  541. package/tests/components/MaskingSettings.test.tsx +0 -498
  542. package/tests/components/MobileNav.test.tsx +0 -30
  543. package/tests/components/MonitoringPage.test.tsx +0 -32
  544. package/tests/components/NL2SQLPanel.test.tsx +0 -621
  545. package/tests/components/Page.test.tsx +0 -33
  546. package/tests/components/PivotTable.test.tsx +0 -350
  547. package/tests/components/QueryEditor.test.tsx +0 -1730
  548. package/tests/components/QueryHistory.test.tsx +0 -572
  549. package/tests/components/QuerySafetyDialog.test.tsx +0 -586
  550. package/tests/components/ResultsGrid.test.tsx +0 -804
  551. package/tests/components/RootLayout.test.tsx +0 -83
  552. package/tests/components/SaveQueryModal.test.tsx +0 -25
  553. package/tests/components/SavedQueries.test.tsx +0 -43
  554. package/tests/components/SchemaDiagram.test.tsx +0 -1034
  555. package/tests/components/SchemaDiff.test.tsx +0 -906
  556. package/tests/components/SnapshotTimeline.test.tsx +0 -174
  557. package/tests/components/Studio.test.tsx +0 -1030
  558. package/tests/components/TestDataGenerator.test.tsx +0 -291
  559. package/tests/components/VisualExplain.test.tsx +0 -704
  560. package/tests/components/admin/AdminDashboard.test.tsx +0 -205
  561. package/tests/components/admin/AuditTab.test.tsx +0 -220
  562. package/tests/components/admin/MonitoringEmbed.test.tsx +0 -58
  563. package/tests/components/admin/OperationsTab.test.tsx +0 -975
  564. package/tests/components/admin/OverviewTab.test.tsx +0 -254
  565. package/tests/components/admin/SecurityTab.test.tsx +0 -467
  566. package/tests/components/monitoring/MetricChart.test.tsx +0 -111
  567. package/tests/components/monitoring/MonitoringDashboard.test.tsx +0 -259
  568. package/tests/components/monitoring/OverviewTab.test.tsx +0 -78
  569. package/tests/components/monitoring/PerformanceTab.test.tsx +0 -87
  570. package/tests/components/monitoring/PoolTab.test.tsx +0 -42
  571. package/tests/components/monitoring/QueriesTab.test.tsx +0 -80
  572. package/tests/components/monitoring/SessionsTab.test.tsx +0 -154
  573. package/tests/components/monitoring/StorageTab.test.tsx +0 -127
  574. package/tests/components/monitoring/TablesTab.test.tsx +0 -153
  575. package/tests/components/results-grid/ResultCard.test.tsx +0 -105
  576. package/tests/components/results-grid/RowDetailSheet.test.tsx +0 -308
  577. package/tests/components/results-grid/StatsBar.test.tsx +0 -162
  578. package/tests/components/schema-explorer/ColumnList.test.tsx +0 -151
  579. package/tests/components/schema-explorer/SchemaExplorer.test.tsx +0 -461
  580. package/tests/components/schema-explorer/TableItem.test.tsx +0 -415
  581. package/tests/components/sidebar/ConnectionItem.test.tsx +0 -201
  582. package/tests/components/sidebar/ConnectionsList.test.tsx +0 -176
  583. package/tests/components/sidebar/Sidebar.test.tsx +0 -187
  584. package/tests/components/studio/BottomPanel.test.tsx +0 -383
  585. package/tests/components/studio/QueryToolbar.test.tsx +0 -321
  586. package/tests/components/studio/StudioDesktopHeader.test.tsx +0 -377
  587. package/tests/components/studio/StudioMobileHeader.test.tsx +0 -198
  588. package/tests/components/studio/StudioTabBar.test.tsx +0 -331
  589. package/tests/fixtures/connections.ts +0 -96
  590. package/tests/fixtures/masking-configs.ts +0 -86
  591. package/tests/fixtures/query-results.ts +0 -71
  592. package/tests/fixtures/schemas.ts +0 -64
  593. package/tests/fixtures/seed-connections/invalid-config.yaml +0 -7
  594. package/tests/fixtures/seed-connections/minimal-config.yaml +0 -8
  595. package/tests/fixtures/seed-connections/mixed-credentials.yaml +0 -23
  596. package/tests/fixtures/seed-connections/multi-role-config.yaml +0 -30
  597. package/tests/fixtures/seed-connections/valid-config.json +0 -15
  598. package/tests/fixtures/seed-connections/valid-config.yaml +0 -51
  599. package/tests/helpers/mock-fetch.ts +0 -59
  600. package/tests/helpers/mock-monaco.ts +0 -112
  601. package/tests/helpers/mock-navigation.ts +0 -28
  602. package/tests/helpers/mock-next.ts +0 -80
  603. package/tests/helpers/mock-provider.ts +0 -133
  604. package/tests/helpers/mock-sonner.ts +0 -29
  605. package/tests/helpers/render-with-providers.tsx +0 -19
  606. package/tests/hooks/use-ai-chat.test.ts +0 -600
  607. package/tests/hooks/use-auth.test.ts +0 -371
  608. package/tests/hooks/use-connection-form.test.ts +0 -743
  609. package/tests/hooks/use-connection-manager.test.ts +0 -466
  610. package/tests/hooks/use-inline-editing.test.ts +0 -321
  611. package/tests/hooks/use-mobile.test.ts +0 -177
  612. package/tests/hooks/use-monitoring-data.test.ts +0 -819
  613. package/tests/hooks/use-provider-metadata.test.ts +0 -228
  614. package/tests/hooks/use-query-execution.test.ts +0 -1212
  615. package/tests/hooks/use-tab-manager.test.ts +0 -756
  616. package/tests/hooks/use-toast.test.ts +0 -74
  617. package/tests/hooks/use-transaction-control.test.ts +0 -211
  618. package/tests/integration/db/mongodb-provider.test.ts +0 -698
  619. package/tests/integration/db/mssql-provider.test.ts +0 -840
  620. package/tests/integration/db/mysql-provider.test.ts +0 -872
  621. package/tests/integration/db/oracle-provider.test.ts +0 -843
  622. package/tests/integration/db/postgres-provider.test.ts +0 -1382
  623. package/tests/integration/db/redis-provider.test.ts +0 -526
  624. package/tests/integration/db/sqlite-provider.test.ts +0 -480
  625. package/tests/integration/seed/seed-pipeline.test.ts +0 -102
  626. package/tests/isolated/factory-singleton.test.ts +0 -150
  627. package/tests/isolated/use-storage-sync.test.ts +0 -389
  628. package/tests/run-components.sh +0 -196
  629. package/tests/setup-dom.ts +0 -58
  630. package/tests/setup.ts +0 -40
  631. package/tests/unit/api-errors.test.ts +0 -210
  632. package/tests/unit/code-generator-functions.test.ts +0 -271
  633. package/tests/unit/components/column-list.test.tsx +0 -190
  634. package/tests/unit/components/data-import-modal.test.tsx +0 -441
  635. package/tests/unit/components/studio-mobile-header.test.tsx +0 -327
  636. package/tests/unit/data-charts-functions.test.ts +0 -496
  637. package/tests/unit/data-import-functions.test.ts +0 -320
  638. package/tests/unit/data-import-utils.test.ts +0 -125
  639. package/tests/unit/db/base-provider.test.ts +0 -517
  640. package/tests/unit/db/errors.test.ts +0 -403
  641. package/tests/unit/db/factory.test.ts +0 -436
  642. package/tests/unit/db/pool-manager.test.ts +0 -440
  643. package/tests/unit/db/query-limiter.test.ts +0 -387
  644. package/tests/unit/db/sql-base.test.ts +0 -438
  645. package/tests/unit/lib/api/error-codes.test.ts +0 -39
  646. package/tests/unit/lib/audit.test.ts +0 -326
  647. package/tests/unit/lib/auth.test.ts +0 -146
  648. package/tests/unit/lib/connection-string-parser.test.ts +0 -424
  649. package/tests/unit/lib/data-masking.test.ts +0 -583
  650. package/tests/unit/lib/db-icons.test.tsx +0 -41
  651. package/tests/unit/lib/monitoring-thresholds.test.ts +0 -133
  652. package/tests/unit/lib/oidc.test.ts +0 -509
  653. package/tests/unit/lib/query-generators.test.ts +0 -127
  654. package/tests/unit/lib/storage/factory.test.ts +0 -71
  655. package/tests/unit/lib/storage/local-storage.test.ts +0 -114
  656. package/tests/unit/lib/storage/providers/postgres.test.ts +0 -312
  657. package/tests/unit/lib/storage/providers/sqlite.test.ts +0 -232
  658. package/tests/unit/lib/storage/storage-facade-extended.test.ts +0 -331
  659. package/tests/unit/lib/storage/storage-facade.test.ts +0 -184
  660. package/tests/unit/lib/storage.test.ts +0 -317
  661. package/tests/unit/lib/time-series-buffer.test.ts +0 -212
  662. package/tests/unit/lib/utils.test.ts +0 -24
  663. package/tests/unit/llm/base-provider.test.ts +0 -238
  664. package/tests/unit/llm/config.test.ts +0 -262
  665. package/tests/unit/llm/custom-provider.test.ts +0 -281
  666. package/tests/unit/llm/gemini-provider.test.ts +0 -248
  667. package/tests/unit/llm/llm-factory.test.ts +0 -155
  668. package/tests/unit/llm/ollama-provider.test.ts +0 -288
  669. package/tests/unit/llm/openai-provider.test.ts +0 -324
  670. package/tests/unit/llm/retry.test.ts +0 -180
  671. package/tests/unit/llm/streaming.test.ts +0 -355
  672. package/tests/unit/logger.test.ts +0 -198
  673. package/tests/unit/mongodb-completions.test.ts +0 -516
  674. package/tests/unit/pivot-table-functions.test.ts +0 -76
  675. package/tests/unit/query-cancelled-error.test.ts +0 -81
  676. package/tests/unit/schema-diff/diff-engine.test.ts +0 -367
  677. package/tests/unit/schema-diff/migration-generator.test.ts +0 -513
  678. package/tests/unit/seed/config-loader.test.ts +0 -73
  679. package/tests/unit/seed/connection-filter.test.ts +0 -91
  680. package/tests/unit/seed/credential-resolver.test.ts +0 -85
  681. package/tests/unit/seed/index.test.ts +0 -72
  682. package/tests/unit/seed/resolve-connection.test.ts +0 -74
  683. package/tests/unit/seed/types.test.ts +0 -129
  684. package/tests/unit/sql/alias-extractor.test.ts +0 -444
  685. package/tests/unit/sql/statement-splitter.test.ts +0 -348
  686. package/tests/unit/sql-completions.test.ts +0 -463
  687. package/tests/unit/ssh-tunnel.test.ts +0 -465
  688. package/tsconfig.json +0 -42
@@ -0,0 +1,4174 @@
1
+ 'use strict';
2
+
3
+ var chunkY52UIFEX_js = require('./chunk-Y52UIFEX.js');
4
+ require('./chunk-VLCRUZX7.js');
5
+ var chunkQ6LRDBK7_js = require('./chunk-Q6LRDBK7.js');
6
+ var React = require('react');
7
+ var lucideReact = require('lucide-react');
8
+ var framerMotion = require('framer-motion');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+ require('next/navigation');
11
+ var dateFns = require('date-fns');
12
+ var reactSlot = require('@radix-ui/react-slot');
13
+ var classVarianceAuthority = require('class-variance-authority');
14
+ var sonner = require('sonner');
15
+ var ResizablePrimitive = require('react-resizable-panels');
16
+ var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
17
+
18
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
19
+
20
+ function _interopNamespace(e) {
21
+ if (e && e.__esModule) return e;
22
+ var n = Object.create(null);
23
+ if (e) {
24
+ Object.keys(e).forEach(function (k) {
25
+ if (k !== 'default') {
26
+ var d = Object.getOwnPropertyDescriptor(e, k);
27
+ Object.defineProperty(n, k, d.get ? d : {
28
+ enumerable: true,
29
+ get: function () { return e[k]; }
30
+ });
31
+ }
32
+ });
33
+ }
34
+ n.default = e;
35
+ return Object.freeze(n);
36
+ }
37
+
38
+ var React__default = /*#__PURE__*/_interopDefault(React);
39
+ var ResizablePrimitive__namespace = /*#__PURE__*/_interopNamespace(ResizablePrimitive);
40
+ var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
41
+
42
+ var ConnectionItem = React__default.default.memo(function ConnectionItem2({
43
+ connection: conn,
44
+ isActive,
45
+ onSelect,
46
+ onDelete,
47
+ onEdit
48
+ }) {
49
+ return /* @__PURE__ */ jsxRuntime.jsxs(
50
+ framerMotion.motion.div,
51
+ {
52
+ initial: false,
53
+ className: chunkY52UIFEX_js.cn(
54
+ "group flex items-center gap-2.5 px-3 py-2 rounded-lg cursor-pointer transition-all duration-200 text-xs relative overflow-hidden",
55
+ isActive ? "bg-blue-600/10 text-blue-400" : "hover:bg-accent/50 text-muted-foreground hover:text-foreground"
56
+ ),
57
+ onClick: () => onSelect(conn),
58
+ children: [
59
+ isActive && /* @__PURE__ */ jsxRuntime.jsx(
60
+ framerMotion.motion.div,
61
+ {
62
+ layoutId: "active-indicator",
63
+ className: "absolute left-0 w-1 h-4 rounded-r-full",
64
+ style: { backgroundColor: conn.color || "#3b82f6" }
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsxRuntime.jsx(
68
+ "div",
69
+ {
70
+ className: chunkY52UIFEX_js.cn(
71
+ "p-1 rounded transition-colors",
72
+ isActive ? "bg-blue-500/20" : "bg-muted group-hover:bg-accent"
73
+ ),
74
+ children: React__default.default.createElement(chunkY52UIFEX_js.getDBIcon(conn.type), { className: "w-3 h-3" })
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
78
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate block font-medium text-xs", children: conn.name }),
79
+ conn.environment && conn.environment !== "other" && /* @__PURE__ */ jsxRuntime.jsx(
80
+ "span",
81
+ {
82
+ className: "text-[0.5rem] font-medium px-1.5 py-0.5 rounded-sm shrink-0",
83
+ style: {
84
+ color: conn.color || "#6b7280",
85
+ backgroundColor: `${conn.color || "#6b7280"}15`
86
+ },
87
+ children: chunkY52UIFEX_js.ENVIRONMENT_LABELS[conn.environment]
88
+ }
89
+ )
90
+ ] }) }),
91
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5", children: [
92
+ conn.managed && /* @__PURE__ */ jsxRuntime.jsx(
93
+ "div",
94
+ {
95
+ "data-testid": `managed-lock-${conn.seedId || conn.id}`,
96
+ className: "flex items-center justify-center text-amber-500/60",
97
+ title: "Managed by administrator",
98
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { strokeWidth: 1.5, className: "w-3 h-3" })
99
+ }
100
+ ),
101
+ !conn.managed && onEdit && /* @__PURE__ */ jsxRuntime.jsx(
102
+ "button",
103
+ {
104
+ className: "p-1 rounded opacity-0 group-hover:opacity-100 transition-opacity hover:bg-blue-500/20 hover:text-blue-400",
105
+ onClick: (e) => {
106
+ e.stopPropagation();
107
+ onEdit(conn);
108
+ },
109
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { strokeWidth: 1.5, className: "w-3 h-3" })
110
+ }
111
+ ),
112
+ !conn.managed && /* @__PURE__ */ jsxRuntime.jsx(
113
+ "button",
114
+ {
115
+ className: "p-1 rounded opacity-0 group-hover:opacity-100 transition-opacity hover:bg-red-500/20 hover:text-red-400",
116
+ onClick: (e) => {
117
+ e.stopPropagation();
118
+ onDelete(conn.id);
119
+ },
120
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { strokeWidth: 1.5, className: "w-3 h-3" })
121
+ }
122
+ )
123
+ ] })
124
+ ]
125
+ }
126
+ );
127
+ });
128
+ function ConnectionsList({
129
+ connections,
130
+ activeConnection,
131
+ onSelectConnection,
132
+ onDeleteConnection,
133
+ onEditConnection,
134
+ onAddConnection
135
+ }) {
136
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 mb-2 flex items-center justify-between", children: [
138
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Connections" }),
139
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[1px] flex-1 bg-border/30 ml-3" })
140
+ ] }),
141
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: connections.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-6 text-center border border-dashed border-border/50 rounded-lg mx-2", children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-3 leading-relaxed", children: "No database connections established yet." }),
143
+ /* @__PURE__ */ jsxRuntime.jsx(
144
+ chunkY52UIFEX_js.Button,
145
+ {
146
+ variant: "outline",
147
+ size: "sm",
148
+ className: "h-7 text-xs",
149
+ onClick: onAddConnection,
150
+ children: "Add Connection"
151
+ }
152
+ )
153
+ ] }) : connections.map((conn) => /* @__PURE__ */ jsxRuntime.jsx(
154
+ ConnectionItem,
155
+ {
156
+ connection: conn,
157
+ isActive: (activeConnection == null ? void 0 : activeConnection.id) === conn.id,
158
+ onSelect: onSelectConnection,
159
+ onDelete: onDeleteConnection,
160
+ onEdit: onEditConnection
161
+ },
162
+ conn.id
163
+ )) })
164
+ ] });
165
+ }
166
+ function Sidebar({
167
+ connections,
168
+ activeConnection,
169
+ schema,
170
+ isLoadingSchema,
171
+ onSelectConnection,
172
+ onDeleteConnection,
173
+ onEditConnection,
174
+ onAddConnection,
175
+ onTableClick,
176
+ onGenerateSelect,
177
+ onCreateTableClick,
178
+ onShowDiagram,
179
+ isAdmin = false,
180
+ onOpenMaintenance,
181
+ databaseType,
182
+ metadata,
183
+ onProfileTable,
184
+ onGenerateCode,
185
+ onGenerateTestData
186
+ }) {
187
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full h-full border-r border-border flex-col bg-background select-none", children: [
188
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-14 px-4 flex items-center justify-between border-b border-border", children: [
189
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
190
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 bg-blue-600 rounded flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { strokeWidth: 1.5, className: "w-3 h-3 text-white fill-current" }) }),
191
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-xs tracking-tight bg-gradient-to-r from-foreground to-muted-foreground bg-clip-text text-transparent", children: "LibreDB Studio" })
192
+ ] }),
193
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
194
+ activeConnection && /* @__PURE__ */ jsxRuntime.jsx(
195
+ "button",
196
+ {
197
+ className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
198
+ onClick: onShowDiagram,
199
+ title: "Show ERD Diagram",
200
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Layers, { strokeWidth: 1.5, className: "w-3.5 h-3.5" })
201
+ }
202
+ ),
203
+ /* @__PURE__ */ jsxRuntime.jsx(
204
+ "button",
205
+ {
206
+ className: "p-1 rounded hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
207
+ onClick: onAddConnection,
208
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { strokeWidth: 1.5, className: "w-3.5 h-3.5" })
209
+ }
210
+ )
211
+ ] })
212
+ ] }),
213
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.ScrollArea, { className: "flex-1 min-h-0 px-2 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
214
+ /* @__PURE__ */ jsxRuntime.jsx(
215
+ ConnectionsList,
216
+ {
217
+ connections,
218
+ activeConnection,
219
+ onSelectConnection,
220
+ onDeleteConnection,
221
+ onEditConnection,
222
+ onAddConnection
223
+ }
224
+ ),
225
+ activeConnection && /* @__PURE__ */ jsxRuntime.jsx(
226
+ chunkY52UIFEX_js.SchemaExplorer,
227
+ {
228
+ schema,
229
+ isLoadingSchema,
230
+ onTableClick,
231
+ onGenerateSelect,
232
+ onCreateTableClick,
233
+ isAdmin,
234
+ onOpenMaintenance,
235
+ databaseType,
236
+ metadata,
237
+ onProfileTable,
238
+ onGenerateCode,
239
+ onGenerateTestData
240
+ }
241
+ )
242
+ ] }) }),
243
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 border-t border-border bg-card/50 backdrop-blur-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 rounded-lg bg-muted/30 border border-border/50", children: [
244
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
245
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" }),
246
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Connected" })
247
+ ] }),
248
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-muted-foreground/70", children: "v1.2.5" })
249
+ ] }) })
250
+ ] });
251
+ }
252
+ function parseCSV(text) {
253
+ const lines = text.split(/\r?\n/).filter((line) => line.trim());
254
+ if (lines.length === 0) return { headers: [], rows: [], totalRows: 0 };
255
+ const parseLine = (line) => {
256
+ const result = [];
257
+ let current = "";
258
+ let inQuotes = false;
259
+ for (let i = 0; i < line.length; i++) {
260
+ const ch = line[i];
261
+ if (ch === '"' && !inQuotes) {
262
+ inQuotes = true;
263
+ } else if (ch === '"' && inQuotes) {
264
+ if (i + 1 < line.length && line[i + 1] === '"') {
265
+ current += '"';
266
+ i++;
267
+ } else {
268
+ inQuotes = false;
269
+ }
270
+ } else if (ch === "," && !inQuotes) {
271
+ result.push(current.trim());
272
+ current = "";
273
+ } else {
274
+ current += ch;
275
+ }
276
+ }
277
+ result.push(current.trim());
278
+ return result;
279
+ };
280
+ const headers = parseLine(lines[0]);
281
+ const rows = lines.slice(1).map((line) => parseLine(line));
282
+ return { headers, rows, totalRows: rows.length };
283
+ }
284
+ function parseJSON(text) {
285
+ const data = JSON.parse(text);
286
+ const arr = Array.isArray(data) ? data : [data];
287
+ if (arr.length === 0) return { headers: [], rows: [], totalRows: 0 };
288
+ const headers = [...new Set(arr.flatMap((obj) => Object.keys(obj)))];
289
+ const rows = arr.map((obj) => headers.map((h) => {
290
+ const val = obj[h];
291
+ if (val === null || val === void 0) return "";
292
+ if (typeof val === "object") return JSON.stringify(val);
293
+ return String(val);
294
+ }));
295
+ return { headers, rows, totalRows: rows.length };
296
+ }
297
+ function inferSqlType(values) {
298
+ const nonEmpty = values.filter((v) => v !== "" && v !== null);
299
+ if (nonEmpty.length === 0) return "TEXT";
300
+ const allIntegers = nonEmpty.every((v) => /^-?\d+$/.test(v));
301
+ if (allIntegers) return "INTEGER";
302
+ const allNumbers = nonEmpty.every((v) => /^-?\d+(\.\d+)?$/.test(v));
303
+ if (allNumbers) return "NUMERIC";
304
+ const allBooleans = nonEmpty.every((v) => /^(true|false|0|1)$/i.test(v));
305
+ if (allBooleans) return "BOOLEAN";
306
+ return "TEXT";
307
+ }
308
+ function escapeSQL(value) {
309
+ if (value === "" || value === "null" || value === "NULL") return "NULL";
310
+ return `'${value.replace(/'/g, "''")}'`;
311
+ }
312
+ function generateImportSQL(parsedData, targetTable, createNewTable, newTableName, columnMapping) {
313
+ if (!parsedData) return "";
314
+ const tableName = createNewTable ? newTableName || "imported_data" : targetTable;
315
+ if (!tableName) return "";
316
+ const statements = [];
317
+ if (createNewTable) {
318
+ const colDefs = parsedData.headers.map((h) => {
319
+ const colValues = parsedData.rows.slice(0, 100).map((r) => r[parsedData.headers.indexOf(h)]);
320
+ const sqlType = inferSqlType(colValues);
321
+ const colName = columnMapping[h] || h;
322
+ return ` ${colName} ${sqlType}`;
323
+ });
324
+ statements.push(`CREATE TABLE ${tableName} (
325
+ ${colDefs.join(",\n")}
326
+ );`);
327
+ }
328
+ const mappedHeaders = parsedData.headers.map((h) => columnMapping[h] || h);
329
+ const batchSize = 100;
330
+ for (let i = 0; i < parsedData.rows.length; i += batchSize) {
331
+ const batch = parsedData.rows.slice(i, i + batchSize);
332
+ const valueRows = batch.map((row) => {
333
+ const values = row.map((val, idx) => {
334
+ const sqlType = inferSqlType(parsedData.rows.slice(0, 100).map((r) => r[idx]));
335
+ if (val === "" || val === "NULL" || val === "null") return "NULL";
336
+ if (sqlType === "INTEGER" || sqlType === "NUMERIC" || sqlType === "BOOLEAN") {
337
+ if (sqlType === "BOOLEAN") return val.toLowerCase() === "true" || val === "1" ? "TRUE" : "FALSE";
338
+ return val;
339
+ }
340
+ return escapeSQL(val);
341
+ });
342
+ return ` (${values.join(", ")})`;
343
+ });
344
+ statements.push(
345
+ `INSERT INTO ${tableName} (${mappedHeaders.join(", ")})
346
+ VALUES
347
+ ${valueRows.join(",\n")};`
348
+ );
349
+ }
350
+ return statements.join("\n\n");
351
+ }
352
+ function DataImportModal({ isOpen, onClose, onImport, tables, databaseType }) {
353
+ const [step, setStep] = React.useState("upload");
354
+ const [parsedData, setParsedData] = React.useState(null);
355
+ const [fileName, setFileName] = React.useState("");
356
+ const [fileType, setFileType] = React.useState("csv");
357
+ const [targetTable, setTargetTable] = React.useState("");
358
+ const [createNewTable, setCreateNewTable] = React.useState(false);
359
+ const [newTableName, setNewTableName] = React.useState("");
360
+ const [columnMapping, setColumnMapping] = React.useState({});
361
+ const [error, setError] = React.useState(null);
362
+ const [isImporting, setIsImporting] = React.useState(false);
363
+ const fileInputRef = React.useRef(null);
364
+ const resetState = React.useCallback(() => {
365
+ setStep("upload");
366
+ setParsedData(null);
367
+ setFileName("");
368
+ setTargetTable("");
369
+ setCreateNewTable(false);
370
+ setNewTableName("");
371
+ setColumnMapping({});
372
+ setError(null);
373
+ setIsImporting(false);
374
+ }, []);
375
+ const handleClose = () => {
376
+ resetState();
377
+ onClose();
378
+ };
379
+ const handleFileSelect = React.useCallback((file) => {
380
+ var _a;
381
+ setError(null);
382
+ setFileName(file.name);
383
+ const ext = (_a = file.name.split(".").pop()) == null ? void 0 : _a.toLowerCase();
384
+ const isJSON = ext === "json";
385
+ setFileType(isJSON ? "json" : "csv");
386
+ const reader = new FileReader();
387
+ reader.onload = (e) => {
388
+ var _a2;
389
+ try {
390
+ const text = (_a2 = e.target) == null ? void 0 : _a2.result;
391
+ const data = isJSON ? parseJSON(text) : parseCSV(text);
392
+ if (data.headers.length === 0) {
393
+ setError("No data found in file");
394
+ return;
395
+ }
396
+ setParsedData(data);
397
+ const mapping = {};
398
+ data.headers.forEach((h) => {
399
+ mapping[h] = h;
400
+ });
401
+ setColumnMapping(mapping);
402
+ setStep("preview");
403
+ } catch (err) {
404
+ setError(`Failed to parse file: ${err instanceof Error ? err.message : "Unknown error"}`);
405
+ }
406
+ };
407
+ reader.readAsText(file);
408
+ }, []);
409
+ const handleDrop = React.useCallback((e) => {
410
+ e.preventDefault();
411
+ const file = e.dataTransfer.files[0];
412
+ if (file) handleFileSelect(file);
413
+ }, [handleFileSelect]);
414
+ const handleDragOver = React.useCallback((e) => {
415
+ e.preventDefault();
416
+ }, []);
417
+ const generatedSQL = React.useMemo(
418
+ () => generateImportSQL(parsedData, targetTable, createNewTable, newTableName, columnMapping),
419
+ [parsedData, targetTable, createNewTable, newTableName, columnMapping]
420
+ );
421
+ const handleImport = () => {
422
+ if (!generatedSQL) return;
423
+ setIsImporting(true);
424
+ onImport(generatedSQL);
425
+ setTimeout(() => {
426
+ handleClose();
427
+ }, 200);
428
+ };
429
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogContent, { className: "bg-[#0a0a0a] border-white/10 text-zinc-100 max-w-2xl max-h-[85vh] overflow-hidden flex flex-col", children: [
430
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogTitle, { className: "flex items-center gap-2", children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { strokeWidth: 1.5, className: "w-5 h-5 text-blue-400" }),
432
+ "Import Data",
433
+ fileName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-normal ml-2", children: fileName })
434
+ ] }) }),
435
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 px-1 py-2", children: ["upload", "preview", "configure", "ready"].map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
436
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkY52UIFEX_js.cn(
437
+ "flex items-center gap-1.5 text-xs font-mediumr",
438
+ step === s ? "text-blue-400" : idx < ["upload", "preview", "configure", "ready"].indexOf(step) ? "text-emerald-400" : "text-zinc-600"
439
+ ), children: [
440
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkY52UIFEX_js.cn(
441
+ "w-5 h-5 rounded-full flex items-center justify-center text-[0.625rem]",
442
+ step === s ? "bg-blue-500/20 border border-blue-500/40" : idx < ["upload", "preview", "configure", "ready"].indexOf(step) ? "bg-emerald-500/20 border border-emerald-500/40" : "bg-white/5 border border-white/10"
443
+ ), children: idx < ["upload", "preview", "configure", "ready"].indexOf(step) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { strokeWidth: 1.5, className: "w-3 h-3" }) : idx + 1 }),
444
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: s === "upload" ? "Upload" : s === "preview" ? "Preview" : s === "configure" ? "Configure" : "Import" })
445
+ ] }),
446
+ idx < 3 && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { strokeWidth: 1.5, className: "w-3 h-3 text-zinc-700" })
447
+ ] }, s)) }),
448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto min-h-0", children: [
449
+ step === "upload" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
450
+ /* @__PURE__ */ jsxRuntime.jsxs(
451
+ "div",
452
+ {
453
+ onDrop: handleDrop,
454
+ onDragOver: handleDragOver,
455
+ onClick: () => {
456
+ var _a;
457
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
458
+ },
459
+ className: "border-2 border-dashed border-white/10 rounded-xl p-12 text-center cursor-pointer hover:border-blue-500/30 hover:bg-blue-500/5 transition-all",
460
+ children: [
461
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { strokeWidth: 1.5, className: "w-10 h-10 text-zinc-600 mx-auto mb-4" }),
462
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-400 mb-1", children: "Drop a file here or click to browse" }),
463
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-600", children: "Supports CSV and JSON files" }),
464
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-4 mt-4", children: [
465
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-zinc-500", children: [
466
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSpreadsheet, { strokeWidth: 1.5, className: "w-3.5 h-3.5" }),
467
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "CSV" })
468
+ ] }),
469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-zinc-500", children: [
470
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileJson, { strokeWidth: 1.5, className: "w-3.5 h-3.5" }),
471
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "JSON" })
472
+ ] })
473
+ ] })
474
+ ]
475
+ }
476
+ ),
477
+ /* @__PURE__ */ jsxRuntime.jsx(
478
+ "input",
479
+ {
480
+ ref: fileInputRef,
481
+ type: "file",
482
+ accept: ".csv,.json,.tsv",
483
+ className: "hidden",
484
+ onChange: (e) => {
485
+ var _a;
486
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
487
+ if (file) handleFileSelect(file);
488
+ }
489
+ }
490
+ ),
491
+ error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 p-3 rounded-lg bg-red-500/10 border border-red-500/20 flex items-center gap-2", children: [
492
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { strokeWidth: 1.5, className: "w-3.5 h-3.5 text-red-400 shrink-0" }),
493
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-red-400", children: error })
494
+ ] })
495
+ ] }),
496
+ step === "preview" && parsedData && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-4", children: [
497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
498
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
499
+ fileType === "json" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileJson, { strokeWidth: 1.5, className: "w-5 h-5 text-amber-400" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { strokeWidth: 1.5, className: "w-5 h-5 text-emerald-400" }),
500
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
501
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: fileName }),
502
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-zinc-500", children: [
503
+ parsedData.totalRows,
504
+ " rows, ",
505
+ parsedData.headers.length,
506
+ " columns"
507
+ ] })
508
+ ] })
509
+ ] }),
510
+ /* @__PURE__ */ jsxRuntime.jsxs(
511
+ chunkY52UIFEX_js.Button,
512
+ {
513
+ variant: "ghost",
514
+ size: "sm",
515
+ className: "h-7 text-xs text-zinc-500",
516
+ onClick: () => {
517
+ resetState();
518
+ },
519
+ children: [
520
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { strokeWidth: 1.5, className: "w-3 h-3 mr-1" }),
521
+ " Reset"
522
+ ]
523
+ }
524
+ )
525
+ ] }),
526
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-white/5 rounded-lg overflow-auto max-h-60", children: [
527
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-xs", children: [
528
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "bg-[#0d0d0d]", children: parsedData.headers.map((h) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left text-xs uppercase text-zinc-500 font-mono border-b border-white/5 whitespace-nowrap", children: h }, h)) }) }),
529
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: parsedData.rows.slice(0, 10).map((row, idx) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-white/5 hover:bg-white/[0.02]", children: row.map((cell, cidx) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1.5 text-zinc-300 font-mono whitespace-nowrap max-w-[200px] truncate", children: cell || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-600 italic", children: "NULL" }) }, cidx)) }, idx)) })
530
+ ] }),
531
+ parsedData.totalRows > 10 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-2 text-xs text-zinc-600 bg-[#0d0d0d]", children: [
532
+ "... and ",
533
+ parsedData.totalRows - 10,
534
+ " more rows"
535
+ ] })
536
+ ] }),
537
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
538
+ chunkY52UIFEX_js.Button,
539
+ {
540
+ size: "sm",
541
+ className: "bg-blue-600 hover:bg-blue-500 h-8 text-xs gap-1",
542
+ onClick: () => setStep("configure"),
543
+ children: [
544
+ "Configure Import ",
545
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { strokeWidth: 1.5, className: "w-3 h-3" })
546
+ ]
547
+ }
548
+ ) })
549
+ ] }),
550
+ step === "configure" && parsedData && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-4", children: [
551
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
552
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-zinc-400 font-medium", children: "Target Table" }),
553
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
554
+ /* @__PURE__ */ jsxRuntime.jsxs(
555
+ "button",
556
+ {
557
+ className: chunkY52UIFEX_js.cn(
558
+ "flex-1 px-3 py-2 rounded-lg border text-xs text-left transition-all",
559
+ !createNewTable ? "border-blue-500/40 bg-blue-500/10 text-blue-400" : "border-white/10 text-zinc-500 hover:bg-white/5"
560
+ ),
561
+ onClick: () => setCreateNewTable(false),
562
+ children: [
563
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Table2, { strokeWidth: 1.5, className: "w-3.5 h-3.5 mb-1" }),
564
+ "Existing Table"
565
+ ]
566
+ }
567
+ ),
568
+ /* @__PURE__ */ jsxRuntime.jsxs(
569
+ "button",
570
+ {
571
+ className: chunkY52UIFEX_js.cn(
572
+ "flex-1 px-3 py-2 rounded-lg border text-xs text-left transition-all",
573
+ createNewTable ? "border-emerald-500/40 bg-emerald-500/10 text-emerald-400" : "border-white/10 text-zinc-500 hover:bg-white/5"
574
+ ),
575
+ onClick: () => setCreateNewTable(true),
576
+ children: [
577
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSpreadsheet, { strokeWidth: 1.5, className: "w-3.5 h-3.5 mb-1" }),
578
+ "New Table"
579
+ ]
580
+ }
581
+ )
582
+ ] })
583
+ ] }),
584
+ createNewTable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
585
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-zinc-400", children: "New Table Name" }),
586
+ /* @__PURE__ */ jsxRuntime.jsx(
587
+ chunkY52UIFEX_js.Input,
588
+ {
589
+ value: newTableName,
590
+ onChange: (e) => setNewTableName(e.target.value),
591
+ placeholder: "imported_data",
592
+ className: "mt-1 bg-[#111] border-white/10 text-xs h-9"
593
+ }
594
+ )
595
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
596
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-zinc-400", children: "Select Table" }),
597
+ /* @__PURE__ */ jsxRuntime.jsxs(
598
+ "select",
599
+ {
600
+ value: targetTable,
601
+ onChange: (e) => setTargetTable(e.target.value),
602
+ className: "w-full mt-1 bg-[#111] border border-white/10 rounded-md px-3 py-2 text-xs text-zinc-300 outline-none focus:border-blue-500/40",
603
+ children: [
604
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "-- Select a table --" }),
605
+ tables.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.name, children: t.name }, t.name))
606
+ ]
607
+ }
608
+ )
609
+ ] }),
610
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-zinc-400 font-medium", children: "Column Mapping" }),
612
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-white/5 rounded-lg overflow-hidden", children: [
613
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[#0d0d0d] grid grid-cols-[1fr,auto,1fr] gap-2 px-3 py-1.5 text-xs text-zinc-500 border-b border-white/5", children: [
614
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Source Column" }),
615
+ /* @__PURE__ */ jsxRuntime.jsx("span", {}),
616
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Target Column" })
617
+ ] }),
618
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-40 overflow-auto", children: parsedData.headers.map((header) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr,auto,1fr] gap-2 items-center px-3 py-1.5 border-b border-white/5", children: [
619
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-300 font-mono truncate", children: header }),
620
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { strokeWidth: 1.5, className: "w-3 h-3 text-zinc-600" }),
621
+ /* @__PURE__ */ jsxRuntime.jsx(
622
+ chunkY52UIFEX_js.Input,
623
+ {
624
+ value: columnMapping[header] || "",
625
+ onChange: (e) => setColumnMapping((prev) => chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, prev), { [header]: e.target.value })),
626
+ className: "h-7 text-xs bg-[#111] border-white/10",
627
+ placeholder: header
628
+ }
629
+ )
630
+ ] }, header)) })
631
+ ] })
632
+ ] }),
633
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
634
+ /* @__PURE__ */ jsxRuntime.jsx(
635
+ chunkY52UIFEX_js.Button,
636
+ {
637
+ variant: "ghost",
638
+ size: "sm",
639
+ className: "h-8 text-xs text-zinc-500",
640
+ onClick: () => setStep("preview"),
641
+ children: "Back"
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsxRuntime.jsxs(
645
+ chunkY52UIFEX_js.Button,
646
+ {
647
+ size: "sm",
648
+ className: "bg-blue-600 hover:bg-blue-500 h-8 text-xs gap-1",
649
+ onClick: () => setStep("ready"),
650
+ disabled: !createNewTable && !targetTable,
651
+ children: [
652
+ "Review SQL ",
653
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { strokeWidth: 1.5, className: "w-3 h-3" })
654
+ ]
655
+ }
656
+ )
657
+ ] })
658
+ ] }),
659
+ step === "ready" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-4", children: [
660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
661
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
662
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: "Ready to Import" }),
663
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-zinc-500 mt-0.5", children: [
664
+ parsedData == null ? void 0 : parsedData.totalRows,
665
+ " rows into ",
666
+ createNewTable ? newTableName || "imported_data" : targetTable
667
+ ] })
668
+ ] }),
669
+ databaseType && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 bg-white/5 px-2 py-1 rounded", children: databaseType })
670
+ ] }),
671
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-white/5 rounded-lg bg-[#0d0d0d] overflow-auto max-h-60", children: /* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "p-3 text-xs text-zinc-400 font-mono whitespace-pre-wrap", children: [
672
+ generatedSQL.substring(0, 3e3),
673
+ generatedSQL.length > 3e3 && "\n\n... (truncated for preview)"
674
+ ] }) }),
675
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
676
+ /* @__PURE__ */ jsxRuntime.jsx(
677
+ chunkY52UIFEX_js.Button,
678
+ {
679
+ variant: "ghost",
680
+ size: "sm",
681
+ className: "h-8 text-xs text-zinc-500",
682
+ onClick: () => setStep("configure"),
683
+ children: "Back"
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
687
+ /* @__PURE__ */ jsxRuntime.jsx(
688
+ chunkY52UIFEX_js.Button,
689
+ {
690
+ variant: "outline",
691
+ size: "sm",
692
+ className: "h-8 text-xs border-white/10",
693
+ onClick: () => {
694
+ navigator.clipboard.writeText(generatedSQL);
695
+ },
696
+ children: "Copy SQL"
697
+ }
698
+ ),
699
+ /* @__PURE__ */ jsxRuntime.jsx(
700
+ chunkY52UIFEX_js.Button,
701
+ {
702
+ size: "sm",
703
+ className: "bg-emerald-600 hover:bg-emerald-500 h-8 text-xs gap-1",
704
+ onClick: handleImport,
705
+ disabled: isImporting,
706
+ children: isImporting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
707
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { strokeWidth: 1.5, className: "w-3 h-3 animate-spin" }),
708
+ " Importing..."
709
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { strokeWidth: 1.5, className: "w-3 h-3" }),
711
+ " Execute Import"
712
+ ] })
713
+ }
714
+ )
715
+ ] })
716
+ ] })
717
+ ] })
718
+ ] })
719
+ ] }) });
720
+ }
721
+ function Textarea(_a) {
722
+ var _b = _a, { className } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, ["className"]);
723
+ return /* @__PURE__ */ jsxRuntime.jsx(
724
+ "textarea",
725
+ chunkQ6LRDBK7_js.__spreadValues({
726
+ "data-slot": "textarea",
727
+ className: chunkY52UIFEX_js.cn(
728
+ "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
729
+ className
730
+ )
731
+ }, props)
732
+ );
733
+ }
734
+ function SaveQueryModal({ isOpen, onClose, onSave, defaultQuery }) {
735
+ const [name, setName] = React.useState("");
736
+ const [description, setDescription] = React.useState("");
737
+ const [tagsInput, setTagsInput] = React.useState("");
738
+ const handleSave = () => {
739
+ if (!name) return;
740
+ const tags = tagsInput.split(",").map((t) => t.trim()).filter((t) => t);
741
+ onSave(name, description, tags);
742
+ setName("");
743
+ setDescription("");
744
+ setTagsInput("");
745
+ onClose();
746
+ };
747
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Dialog, { open: isOpen, onOpenChange: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogContent, { className: "bg-[#0d0d0d] border-white/10 text-zinc-300 sm:max-w-[425px]", children: [
748
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogHeader, { children: [
749
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogTitle, { className: "text-white flex items-center gap-2", children: [
750
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bookmark, { strokeWidth: 1.5, className: "w-5 h-5 text-blue-500" }),
751
+ " Save Query"
752
+ ] }),
753
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DialogDescription, { className: "text-zinc-500", children: "Give your query a name and description to find it easily later." })
754
+ ] }),
755
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 py-4", children: [
756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
757
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Label, { htmlFor: "name", className: "text-xs font-medium text-zinc-500", children: "Name" }),
758
+ /* @__PURE__ */ jsxRuntime.jsx(
759
+ chunkY52UIFEX_js.Input,
760
+ {
761
+ id: "name",
762
+ value: name,
763
+ onChange: (e) => setName(e.target.value),
764
+ placeholder: "e.g. Monthly Active Users",
765
+ className: "bg-white/5 border-white/10 focus:ring-blue-500/20"
766
+ }
767
+ )
768
+ ] }),
769
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
770
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Label, { htmlFor: "description", className: "text-xs font-medium text-zinc-500", children: "Description" }),
771
+ /* @__PURE__ */ jsxRuntime.jsx(
772
+ Textarea,
773
+ {
774
+ id: "description",
775
+ value: description,
776
+ onChange: (e) => setDescription(e.target.value),
777
+ placeholder: "What does this query do?",
778
+ className: "bg-white/5 border-white/10 focus:ring-blue-500/20 min-h-[80px]"
779
+ }
780
+ )
781
+ ] }),
782
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
783
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.Label, { htmlFor: "tags", className: "text-xs font-medium text-zinc-500 flex items-center gap-2", children: [
784
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { strokeWidth: 1.5, className: "w-3 h-3" }),
785
+ " Tags (comma separated)"
786
+ ] }),
787
+ /* @__PURE__ */ jsxRuntime.jsx(
788
+ chunkY52UIFEX_js.Input,
789
+ {
790
+ id: "tags",
791
+ value: tagsInput,
792
+ onChange: (e) => setTagsInput(e.target.value),
793
+ placeholder: "reports, analytics, users",
794
+ className: "bg-white/5 border-white/10 focus:ring-blue-500/20"
795
+ }
796
+ )
797
+ ] }),
798
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2", children: [
799
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Label, { className: "text-xs font-medium text-zinc-500 mb-2 block", children: "Preview" }),
800
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-[#050505] p-3 rounded-md border border-white/5 max-h-[100px] overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs font-mono text-zinc-500 italic whitespace-pre-wrap break-words", children: defaultQuery }) })
801
+ ] })
802
+ ] }),
803
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DialogFooter, { children: [
804
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Button, { variant: "ghost", onClick: onClose, className: "text-zinc-400", children: "Cancel" }),
805
+ /* @__PURE__ */ jsxRuntime.jsx(
806
+ chunkY52UIFEX_js.Button,
807
+ {
808
+ onClick: handleSave,
809
+ disabled: !name,
810
+ className: "bg-blue-600 hover:bg-blue-500 text-white font-medium",
811
+ children: "Save Query"
812
+ }
813
+ )
814
+ ] })
815
+ ] }) });
816
+ }
817
+ function StudioTabBar({
818
+ tabs,
819
+ activeTabId,
820
+ editingTabId,
821
+ editingTabName,
822
+ onSetActiveTabId,
823
+ onSetEditingTabId,
824
+ onSetEditingTabName,
825
+ onSetTabs,
826
+ onCloseTab,
827
+ onAddTab
828
+ }) {
829
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex h-10 bg-[#0d0d0d] border-b border-white/5 items-center px-2 gap-1 overflow-x-auto no-scrollbar", children: [
830
+ tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
831
+ "div",
832
+ {
833
+ onClick: () => onSetActiveTabId(tab.id),
834
+ onDoubleClick: () => {
835
+ onSetEditingTabId(tab.id);
836
+ onSetEditingTabName(tab.name);
837
+ },
838
+ className: chunkY52UIFEX_js.cn(
839
+ "h-8 flex items-center px-3 gap-2 rounded-t-md transition-all cursor-pointer min-w-[120px] max-w-[200px] group relative border-t-2",
840
+ activeTabId === tab.id ? "bg-[#141414] text-zinc-100 border-blue-500" : "text-zinc-500 hover:bg-white/5 border-transparent"
841
+ ),
842
+ children: [
843
+ tab.type === "sql" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hash, { strokeWidth: 1.5, className: "w-3 h-3" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileJson, { strokeWidth: 1.5, className: "w-3 h-3" }),
844
+ editingTabId === tab.id ? /* @__PURE__ */ jsxRuntime.jsx(
845
+ "input",
846
+ {
847
+ autoFocus: true,
848
+ value: editingTabName,
849
+ onChange: (e) => onSetEditingTabName(e.target.value),
850
+ onBlur: () => {
851
+ if (editingTabName.trim()) {
852
+ onSetTabs((prev) => prev.map((t) => t.id === tab.id ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), { name: editingTabName.trim() }) : t));
853
+ }
854
+ onSetEditingTabId(null);
855
+ },
856
+ onKeyDown: (e) => {
857
+ if (e.key === "Enter") {
858
+ if (editingTabName.trim()) {
859
+ onSetTabs((prev) => prev.map((t) => t.id === tab.id ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), { name: editingTabName.trim() }) : t));
860
+ }
861
+ onSetEditingTabId(null);
862
+ } else if (e.key === "Escape") {
863
+ onSetEditingTabId(null);
864
+ }
865
+ },
866
+ onClick: (e) => e.stopPropagation(),
867
+ className: "text-xs font-medium bg-transparent border-b border-blue-500 outline-none w-full text-zinc-100"
868
+ }
869
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs truncate font-medium", children: tab.name }),
870
+ tabs.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { strokeWidth: 1.5, className: "w-3 h-3 ml-auto opacity-0 group-hover:opacity-100 hover:text-white shrink-0", onClick: (e) => onCloseTab(tab.id, e) })
871
+ ]
872
+ },
873
+ tab.id
874
+ )),
875
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { strokeWidth: 1.5, className: "w-3.5 h-3.5 text-zinc-500 cursor-pointer hover:text-white mx-2", onClick: onAddTab })
876
+ ] });
877
+ }
878
+ function QueryToolbar({
879
+ activeConnection,
880
+ metadata,
881
+ isExecuting,
882
+ playgroundMode,
883
+ transactionActive,
884
+ editingEnabled,
885
+ onSaveQuery,
886
+ onExecuteQuery,
887
+ onCancelQuery,
888
+ onBeginTransaction,
889
+ onCommitTransaction,
890
+ onRollbackTransaction,
891
+ onTogglePlayground,
892
+ onToggleEditing,
893
+ onImport
894
+ }) {
895
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
896
+ playgroundMode && /* @__PURE__ */ jsxRuntime.jsxs("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", children: [
897
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlaskConical, { strokeWidth: 1.5, className: "w-3 h-3" }),
898
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mediumr", children: "Sandbox Mode \u2014 All changes will be auto-rolled back" })
899
+ ] }),
900
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex items-center justify-between px-4 py-1.5 bg-[#0a0a0a] border-b border-white/5", children: [
901
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
902
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-2 py-0.5 rounded bg-blue-500/5 border border-blue-500/10", children: [
903
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Terminal, { strokeWidth: 1.5, className: "w-3 h-3 text-blue-400" }),
904
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-blue-400", children: "Query" })
905
+ ] }),
906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-white/5" }),
907
+ /* @__PURE__ */ jsxRuntime.jsxs(
908
+ chunkY52UIFEX_js.Button,
909
+ {
910
+ variant: "ghost",
911
+ size: "sm",
912
+ className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-2",
913
+ onClick: onSaveQuery,
914
+ children: [
915
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { strokeWidth: 1.5, className: "w-3 h-3" }),
916
+ " Save"
917
+ ]
918
+ }
919
+ )
920
+ ] }),
921
+ isExecuting ? /* @__PURE__ */ jsxRuntime.jsxs(
922
+ chunkY52UIFEX_js.Button,
923
+ {
924
+ size: "sm",
925
+ className: "bg-red-600 hover:bg-red-500 text-white font-medium text-xs h-7 px-4 gap-2",
926
+ onClick: onCancelQuery,
927
+ children: [
928
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { strokeWidth: 1.5, className: "w-3 h-3 fill-current" }),
929
+ "CANCEL"
930
+ ]
931
+ }
932
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
933
+ chunkY52UIFEX_js.Button,
934
+ {
935
+ size: "sm",
936
+ className: "bg-blue-600 hover:bg-blue-500 text-white font-medium text-xs h-7 px-4 gap-2",
937
+ onClick: onExecuteQuery,
938
+ disabled: !activeConnection,
939
+ children: [
940
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { strokeWidth: 1.5, className: "w-3 h-3 fill-current" }),
941
+ "RUN"
942
+ ]
943
+ }
944
+ ),
945
+ activeConnection && (metadata == null ? void 0 : metadata.capabilities.queryLanguage) === "sql" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-2 pl-2 border-l border-white/10", children: [
946
+ transactionActive ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
947
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.625rem] font-medium text-amber-400 px-1.5 py-0.5 bg-amber-500/10 rounded border border-amber-500/20 mr-1", children: "TXN" }),
948
+ /* @__PURE__ */ jsxRuntime.jsx(
949
+ chunkY52UIFEX_js.Button,
950
+ {
951
+ size: "sm",
952
+ variant: "ghost",
953
+ className: "h-7 text-xs font-medium text-emerald-400 hover:text-emerald-300 hover:bg-emerald-500/10 gap-1",
954
+ onClick: onCommitTransaction,
955
+ children: "COMMIT"
956
+ }
957
+ ),
958
+ /* @__PURE__ */ jsxRuntime.jsx(
959
+ chunkY52UIFEX_js.Button,
960
+ {
961
+ size: "sm",
962
+ variant: "ghost",
963
+ className: "h-7 text-xs font-medium text-red-400 hover:text-red-300 hover:bg-red-500/10 gap-1",
964
+ onClick: onRollbackTransaction,
965
+ children: "ROLLBACK"
966
+ }
967
+ )
968
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
969
+ chunkY52UIFEX_js.Button,
970
+ {
971
+ size: "sm",
972
+ variant: "ghost",
973
+ className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-1",
974
+ onClick: onBeginTransaction,
975
+ disabled: playgroundMode,
976
+ children: "BEGIN"
977
+ }
978
+ ),
979
+ /* @__PURE__ */ jsxRuntime.jsxs(
980
+ chunkY52UIFEX_js.Button,
981
+ {
982
+ size: "sm",
983
+ variant: "ghost",
984
+ className: chunkY52UIFEX_js.cn(
985
+ "h-7 text-xs font-medium gap-1",
986
+ playgroundMode ? "text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20" : "text-zinc-500 hover:text-white"
987
+ ),
988
+ onClick: onTogglePlayground,
989
+ disabled: transactionActive,
990
+ title: "Playground mode: queries are auto-rolled back",
991
+ children: [
992
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlaskConical, { strokeWidth: 1.5, className: "w-3 h-3" }),
993
+ "SANDBOX"
994
+ ]
995
+ }
996
+ ),
997
+ /* @__PURE__ */ jsxRuntime.jsxs(
998
+ chunkY52UIFEX_js.Button,
999
+ {
1000
+ size: "sm",
1001
+ variant: "ghost",
1002
+ className: chunkY52UIFEX_js.cn(
1003
+ "h-7 text-xs font-medium gap-1",
1004
+ editingEnabled ? "text-amber-400 bg-amber-500/10 hover:bg-amber-500/20" : "text-zinc-500 hover:text-white"
1005
+ ),
1006
+ onClick: onToggleEditing,
1007
+ title: "Enable inline data editing",
1008
+ children: [
1009
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { strokeWidth: 1.5, className: "w-3 h-3" }),
1010
+ "EDIT"
1011
+ ]
1012
+ }
1013
+ ),
1014
+ /* @__PURE__ */ jsxRuntime.jsxs(
1015
+ chunkY52UIFEX_js.Button,
1016
+ {
1017
+ size: "sm",
1018
+ variant: "ghost",
1019
+ className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-1",
1020
+ onClick: onImport,
1021
+ title: "Import data from CSV/JSON",
1022
+ children: [
1023
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { strokeWidth: 1.5, className: "w-3 h-3" }),
1024
+ "IMPORT"
1025
+ ]
1026
+ }
1027
+ )
1028
+ ] })
1029
+ ] })
1030
+ ] });
1031
+ }
1032
+ function AIAutopilotPanel({ connection, schemaContext, onExecuteQuery }) {
1033
+ const [isLoading, setIsLoading] = React.useState(false);
1034
+ const [report, setReport] = React.useState("");
1035
+ const [error, setError] = React.useState(null);
1036
+ const [copiedIndex, setCopiedIndex] = React.useState(null);
1037
+ const reportRef = React.useRef(null);
1038
+ const runAutopilot = async () => {
1039
+ var _a;
1040
+ if (!connection) return;
1041
+ setIsLoading(true);
1042
+ setError(null);
1043
+ setReport("");
1044
+ try {
1045
+ const [monitoringRes] = await Promise.all([
1046
+ fetch("/api/db/monitoring", {
1047
+ method: "POST",
1048
+ headers: { "Content-Type": "application/json" },
1049
+ body: JSON.stringify({
1050
+ connection,
1051
+ options: {
1052
+ includeTables: true,
1053
+ includeIndexes: true,
1054
+ slowQueryLimit: 20
1055
+ }
1056
+ })
1057
+ })
1058
+ ]);
1059
+ let monitoringData = null;
1060
+ if (monitoringRes.ok) {
1061
+ monitoringData = await monitoringRes.json();
1062
+ }
1063
+ let filteredSchema = "";
1064
+ if (schemaContext) {
1065
+ try {
1066
+ const tables = JSON.parse(schemaContext);
1067
+ filteredSchema = tables.slice(0, 30).map((t) => {
1068
+ var _a2;
1069
+ const cols = ((_a2 = t.columns) == null ? void 0 : _a2.slice(0, 6).map((c) => `${c.name} (${c.type})`).join(", ")) || "";
1070
+ return `${t.name} (${t.rowCount || 0} rows): ${cols}`;
1071
+ }).join("\n");
1072
+ } catch (e) {
1073
+ filteredSchema = schemaContext.substring(0, 2e3);
1074
+ }
1075
+ }
1076
+ const response = await fetch("/api/ai/autopilot", {
1077
+ method: "POST",
1078
+ headers: { "Content-Type": "application/json" },
1079
+ body: JSON.stringify({
1080
+ slowQueries: monitoringData == null ? void 0 : monitoringData.slowQueries,
1081
+ indexStats: monitoringData == null ? void 0 : monitoringData.indexes,
1082
+ tableStats: monitoringData == null ? void 0 : monitoringData.tables,
1083
+ performanceMetrics: monitoringData == null ? void 0 : monitoringData.performance,
1084
+ overview: monitoringData == null ? void 0 : monitoringData.overview,
1085
+ schemaContext: filteredSchema,
1086
+ databaseType: connection.type
1087
+ })
1088
+ });
1089
+ if (!response.ok) {
1090
+ const errData = await response.json();
1091
+ throw new Error(errData.error || "Autopilot analysis failed");
1092
+ }
1093
+ const reader = (_a = response.body) == null ? void 0 : _a.getReader();
1094
+ if (!reader) throw new Error("No reader");
1095
+ let fullResponse = "";
1096
+ while (true) {
1097
+ const { done, value } = await reader.read();
1098
+ if (done) break;
1099
+ fullResponse += new TextDecoder().decode(value);
1100
+ setReport(fullResponse);
1101
+ }
1102
+ } catch (err) {
1103
+ setError(err instanceof Error ? err.message : "Unknown error");
1104
+ } finally {
1105
+ setIsLoading(false);
1106
+ }
1107
+ };
1108
+ const copyToClipboard = (text, index) => {
1109
+ navigator.clipboard.writeText(text);
1110
+ setCopiedIndex(index);
1111
+ setTimeout(() => setCopiedIndex(null), 2e3);
1112
+ };
1113
+ const renderMarkdown = (text) => {
1114
+ const lines = text.split("\n");
1115
+ const elements = [];
1116
+ let inCodeBlock = false;
1117
+ let codeContent = "";
1118
+ let codeBlockIdx = 0;
1119
+ for (let i = 0; i < lines.length; i++) {
1120
+ const line = lines[i];
1121
+ if (line.startsWith("```")) {
1122
+ if (inCodeBlock) {
1123
+ const blockIndex = codeBlockIdx++;
1124
+ const sql = codeContent.trim();
1125
+ elements.push(
1126
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group my-2", children: [
1127
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "bg-[#050505] rounded-lg p-3 text-xs font-mono text-blue-300 overflow-x-auto whitespace-pre-wrap border border-white/5", children: sql }),
1128
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-1.5 right-1.5 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
1129
+ /* @__PURE__ */ jsxRuntime.jsx(
1130
+ "button",
1131
+ {
1132
+ onClick: () => copyToClipboard(sql, blockIndex),
1133
+ className: "p-1 rounded bg-white/10 hover:bg-white/20 text-zinc-400",
1134
+ title: "Copy",
1135
+ children: copiedIndex === blockIndex ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { strokeWidth: 1.5, className: "w-3 h-3 text-emerald-400" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { strokeWidth: 1.5, className: "w-3 h-3" })
1136
+ }
1137
+ ),
1138
+ onExecuteQuery && /* @__PURE__ */ jsxRuntime.jsx(
1139
+ "button",
1140
+ {
1141
+ onClick: () => onExecuteQuery(sql),
1142
+ className: "p-1 rounded bg-blue-600/20 hover:bg-blue-600/30 text-blue-400",
1143
+ title: "Execute",
1144
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { strokeWidth: 1.5, className: "w-3 h-3 fill-current" })
1145
+ }
1146
+ )
1147
+ ] })
1148
+ ] }, `code-${i}`)
1149
+ );
1150
+ codeContent = "";
1151
+ inCodeBlock = false;
1152
+ } else {
1153
+ inCodeBlock = true;
1154
+ }
1155
+ continue;
1156
+ }
1157
+ if (inCodeBlock) {
1158
+ codeContent += line + "\n";
1159
+ continue;
1160
+ }
1161
+ if (line.startsWith("## ")) {
1162
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xs font-medium text-zinc-200 mt-4 mb-2", children: line.slice(3) }, i));
1163
+ } else if (line.startsWith("### ")) {
1164
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-medium text-zinc-300 mt-3 mb-1", children: line.slice(4) }, i));
1165
+ } else if (line.startsWith("- ")) {
1166
+ const content = line.slice(2).replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1167
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-xs text-zinc-400 ml-4 leading-relaxed", dangerouslySetInnerHTML: { __html: content } }, i));
1168
+ } else if (line.match(/^\d+\.\s/)) {
1169
+ const content = line.replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1170
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-xs text-zinc-400 ml-4 leading-relaxed list-decimal", dangerouslySetInnerHTML: { __html: content } }, i));
1171
+ } else if (line.trim()) {
1172
+ const content = line.replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1173
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-400 leading-relaxed", dangerouslySetInnerHTML: { __html: content } }, i));
1174
+ } else {
1175
+ elements.push(/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2" }, i));
1176
+ }
1177
+ }
1178
+ return elements;
1179
+ };
1180
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
1181
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-b border-white/5 bg-[#0a0a0a]", children: [
1182
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1183
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1 rounded bg-cyan-500/10", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { strokeWidth: 1.5, className: "w-3 h-3 text-cyan-400" }) }),
1184
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-cyan-400", children: "AI Performance Autopilot" })
1185
+ ] }),
1186
+ /* @__PURE__ */ jsxRuntime.jsx(
1187
+ "button",
1188
+ {
1189
+ onClick: runAutopilot,
1190
+ disabled: isLoading || !connection,
1191
+ className: chunkY52UIFEX_js.cn(
1192
+ "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors",
1193
+ isLoading ? "bg-cyan-600/20 text-cyan-400 cursor-wait" : "bg-cyan-600 hover:bg-cyan-500 text-white"
1194
+ ),
1195
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1196
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { strokeWidth: 1.5, className: "w-3 h-3 animate-spin" }),
1197
+ " Analyzing..."
1198
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1199
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { strokeWidth: 1.5, className: "w-3 h-3" }),
1200
+ " ",
1201
+ report ? "Re-analyze" : "Run Analysis"
1202
+ ] })
1203
+ }
1204
+ )
1205
+ ] }),
1206
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: reportRef, className: "flex-1 overflow-auto p-4", children: [
1207
+ !report && !isLoading && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full opacity-40", children: [
1208
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { strokeWidth: 1.5, className: "w-8 h-8 mb-3" }),
1209
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: "AI Performance Autopilot" }),
1210
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-500 mt-1", children: 'Click "Run Analysis" to get AI-powered optimization recommendations' })
1211
+ ] }),
1212
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3 text-xs text-red-400", children: error }),
1213
+ report && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-invert prose-xs max-w-none", children: renderMarkdown(report) })
1214
+ ] })
1215
+ ] });
1216
+ }
1217
+ var AGG_LABELS = {
1218
+ count: "COUNT",
1219
+ sum: "SUM",
1220
+ avg: "AVG",
1221
+ min: "MIN",
1222
+ max: "MAX"
1223
+ };
1224
+ function aggregate(values, fn) {
1225
+ const nums = values.map((v) => Number(v)).filter((n) => !isNaN(n));
1226
+ switch (fn) {
1227
+ case "count":
1228
+ return String(values.length);
1229
+ case "sum":
1230
+ return nums.length ? nums.reduce((a, b) => a + b, 0).toFixed(2) : "0";
1231
+ case "avg":
1232
+ return nums.length ? (nums.reduce((a, b) => a + b, 0) / nums.length).toFixed(2) : "0";
1233
+ case "min":
1234
+ return nums.length ? String(Math.min(...nums)) : "-";
1235
+ case "max":
1236
+ return nums.length ? String(Math.max(...nums)) : "-";
1237
+ }
1238
+ }
1239
+ function PivotTable({ result, onLoadQuery }) {
1240
+ const [rowField, setRowField] = React.useState(null);
1241
+ const [colField, setColField] = React.useState(null);
1242
+ const [valueField, setValueField] = React.useState(null);
1243
+ const [aggFunction, setAggFunction] = React.useState("count");
1244
+ const fields = (result == null ? void 0 : result.fields) || [];
1245
+ const rows = React.useMemo(() => (result == null ? void 0 : result.rows) || [], [result == null ? void 0 : result.rows]);
1246
+ React.useEffect(() => {
1247
+ if (fields.length >= 2 && !rowField) {
1248
+ const strCol = fields.find((f) => {
1249
+ var _a;
1250
+ const sample = (_a = rows[0]) == null ? void 0 : _a[f];
1251
+ return typeof sample === "string";
1252
+ });
1253
+ if (strCol) setRowField(strCol);
1254
+ const numCol = fields.find((f) => {
1255
+ var _a;
1256
+ const sample = (_a = rows[0]) == null ? void 0 : _a[f];
1257
+ return typeof sample === "number";
1258
+ });
1259
+ if (numCol) setValueField(numCol);
1260
+ }
1261
+ }, [fields.length]);
1262
+ const pivotData = React.useMemo(() => {
1263
+ var _a, _b;
1264
+ if (!rowField || !rows.length) return null;
1265
+ const groups = /* @__PURE__ */ new Map();
1266
+ const colValues = /* @__PURE__ */ new Set();
1267
+ for (const row of rows) {
1268
+ const rowKey = String((_a = row[rowField]) != null ? _a : "NULL");
1269
+ const colKey = colField ? String((_b = row[colField]) != null ? _b : "NULL") : "__all__";
1270
+ const value = valueField ? row[valueField] : 1;
1271
+ if (colField) colValues.add(colKey);
1272
+ if (!groups.has(rowKey)) groups.set(rowKey, /* @__PURE__ */ new Map());
1273
+ const colMap = groups.get(rowKey);
1274
+ if (!colMap.has(colKey)) colMap.set(colKey, []);
1275
+ colMap.get(colKey).push(value);
1276
+ }
1277
+ const colKeys = colField ? Array.from(colValues).sort() : ["__all__"];
1278
+ const pivotRows = [];
1279
+ for (const [rowKey, colMap] of groups) {
1280
+ const values = /* @__PURE__ */ new Map();
1281
+ for (const ck of colKeys) {
1282
+ const vals = colMap.get(ck) || [];
1283
+ values.set(ck, aggregate(vals, aggFunction));
1284
+ }
1285
+ pivotRows.push({ rowKey, values });
1286
+ }
1287
+ pivotRows.sort((a, b) => a.rowKey.localeCompare(b.rowKey));
1288
+ return { colKeys, pivotRows };
1289
+ }, [rows, rowField, colField, valueField, aggFunction]);
1290
+ const generateSQL = React.useCallback(() => {
1291
+ if (!rowField) return "";
1292
+ const select = [`"${rowField}"`];
1293
+ const groupBy = [`"${rowField}"`];
1294
+ if (colField) {
1295
+ const colKeys = (pivotData == null ? void 0 : pivotData.colKeys) || [];
1296
+ for (const ck of colKeys) {
1297
+ if (ck === "__all__") continue;
1298
+ const valExpr = valueField ? `"${valueField}"` : "1";
1299
+ select.push(
1300
+ `${AGG_LABELS[aggFunction]}(CASE WHEN "${colField}" = '${ck.replace(/'/g, "''")}' THEN ${valExpr} END) AS "${ck}"`
1301
+ );
1302
+ }
1303
+ } else {
1304
+ const valExpr = valueField ? `"${valueField}"` : "*";
1305
+ select.push(`${AGG_LABELS[aggFunction]}(${valExpr}) AS "${aggFunction}_value"`);
1306
+ }
1307
+ return `SELECT
1308
+ ${select.join(",\n ")}
1309
+ FROM your_table
1310
+ GROUP BY ${groupBy.join(", ")}
1311
+ ORDER BY ${groupBy.join(", ")};`;
1312
+ }, [rowField, colField, valueField, aggFunction, pivotData]);
1313
+ if (!result || rows.length === 0) {
1314
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center opacity-30", children: [
1315
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Columns3, { strokeWidth: 1.5, className: "w-8 h-8 mb-3" }),
1316
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: "Pivot Table" }),
1317
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-500 mt-1", children: "Execute a query to create pivot tables" })
1318
+ ] });
1319
+ }
1320
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
1321
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 border-b border-white/5 bg-[#0a0a0a] flex-wrap", children: [
1322
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1323
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-medium", children: "Rows:" }),
1324
+ /* @__PURE__ */ jsxRuntime.jsxs(
1325
+ "select",
1326
+ {
1327
+ value: rowField || "",
1328
+ onChange: (e) => setRowField(e.target.value || null),
1329
+ className: "bg-[#111] border border-white/10 rounded px-2 py-1 text-xs text-zinc-300 outline-none",
1330
+ children: [
1331
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select..." }),
1332
+ fields.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f, children: f }, f))
1333
+ ]
1334
+ }
1335
+ )
1336
+ ] }),
1337
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1338
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-medium", children: "Columns:" }),
1339
+ /* @__PURE__ */ jsxRuntime.jsxs(
1340
+ "select",
1341
+ {
1342
+ value: colField || "",
1343
+ onChange: (e) => setColField(e.target.value || null),
1344
+ className: "bg-[#111] border border-white/10 rounded px-2 py-1 text-xs text-zinc-300 outline-none",
1345
+ children: [
1346
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "None" }),
1347
+ fields.filter((f) => f !== rowField).map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f, children: f }, f))
1348
+ ]
1349
+ }
1350
+ )
1351
+ ] }),
1352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-medium", children: "Values:" }),
1354
+ /* @__PURE__ */ jsxRuntime.jsxs(
1355
+ "select",
1356
+ {
1357
+ value: valueField || "",
1358
+ onChange: (e) => setValueField(e.target.value || null),
1359
+ className: "bg-[#111] border border-white/10 rounded px-2 py-1 text-xs text-zinc-300 outline-none",
1360
+ children: [
1361
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Count" }),
1362
+ fields.filter((f) => f !== rowField && f !== colField).map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f, children: f }, f))
1363
+ ]
1364
+ }
1365
+ )
1366
+ ] }),
1367
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: Object.keys(AGG_LABELS).map((fn) => /* @__PURE__ */ jsxRuntime.jsx(
1368
+ "button",
1369
+ {
1370
+ onClick: () => setAggFunction(fn),
1371
+ className: chunkY52UIFEX_js.cn(
1372
+ "px-1.5 py-0.5 rounded text-xs font-medium transition-colors",
1373
+ aggFunction === fn ? "bg-blue-500/20 text-blue-400 border border-blue-500/20" : "text-zinc-600 hover:text-zinc-400"
1374
+ ),
1375
+ children: AGG_LABELS[fn]
1376
+ },
1377
+ fn
1378
+ )) }),
1379
+ onLoadQuery && rowField && /* @__PURE__ */ jsxRuntime.jsxs(
1380
+ "button",
1381
+ {
1382
+ onClick: () => {
1383
+ const sql = generateSQL();
1384
+ if (sql) onLoadQuery(sql);
1385
+ },
1386
+ className: "ml-auto flex items-center gap-1 px-2 py-1 rounded text-xs font-medium text-zinc-500 hover:text-blue-400 hover:bg-blue-500/10 transition-colors",
1387
+ children: [
1388
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { strokeWidth: 1.5, className: "w-3 h-3" }),
1389
+ " Generate SQL"
1390
+ ]
1391
+ }
1392
+ )
1393
+ ] }),
1394
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto", children: pivotData && pivotData.pivotRows.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-xs font-mono", children: [
1395
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "sticky top-0 z-10 bg-[#0d0d0d]", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1396
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-3 py-2 text-zinc-500 border-b border-r border-white/5 font-mediumr", children: rowField }),
1397
+ pivotData.colKeys.map((ck) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-right px-3 py-2 text-zinc-500 border-b border-r border-white/5 font-medium", children: ck === "__all__" ? `${AGG_LABELS[aggFunction]}(${valueField || "*"})` : ck }, ck))
1398
+ ] }) }),
1399
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: pivotData.pivotRows.map((row, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-blue-500/[0.03] border-b border-white/5", children: [
1400
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1.5 text-zinc-300 border-r border-white/5 font-medium", children: row.rowKey }),
1401
+ pivotData.colKeys.map((ck) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1.5 text-right text-amber-500/90 border-r border-white/5", children: row.values.get(ck) || "0" }, ck))
1402
+ ] }, i)) })
1403
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full opacity-30", children: [
1404
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVertical, { strokeWidth: 1.5, className: "w-6 h-6 mb-2" }),
1405
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "Select row and value fields to build pivot" })
1406
+ ] }) }),
1407
+ pivotData && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-1.5 border-t border-white/5 bg-[#0a0a0a] text-xs text-zinc-500 font-mono", children: [
1408
+ pivotData.pivotRows.length,
1409
+ " groups \u2022 ",
1410
+ pivotData.colKeys.length,
1411
+ " columns \u2022 ",
1412
+ AGG_LABELS[aggFunction],
1413
+ " aggregation"
1414
+ ] })
1415
+ ] });
1416
+ }
1417
+ function DatabaseDocs({ schema, schemaContext, databaseType }) {
1418
+ const [search, setSearch] = React.useState("");
1419
+ const [aiDocs, setAiDocs] = React.useState("");
1420
+ const [isAiLoading, setIsAiLoading] = React.useState(false);
1421
+ const [error, setError] = React.useState(null);
1422
+ const filteredSchema = schema.filter(
1423
+ (t) => {
1424
+ var _a;
1425
+ return t.name.toLowerCase().includes(search.toLowerCase()) || ((_a = t.columns) == null ? void 0 : _a.some((c) => c.name.toLowerCase().includes(search.toLowerCase())));
1426
+ }
1427
+ );
1428
+ const generateAiDocs = async () => {
1429
+ var _a;
1430
+ setIsAiLoading(true);
1431
+ setError(null);
1432
+ setAiDocs("");
1433
+ try {
1434
+ let filteredSchemaStr = "";
1435
+ if (schemaContext) {
1436
+ try {
1437
+ const tables = JSON.parse(schemaContext);
1438
+ filteredSchemaStr = tables.slice(0, 50).map((t) => {
1439
+ var _a2;
1440
+ const cols = ((_a2 = t.columns) == null ? void 0 : _a2.map(
1441
+ (c) => `${c.name} (${c.type}${c.isPrimary ? ", PK" : ""}${c.isNullable === false ? ", NOT NULL" : ""})`
1442
+ ).join(", ")) || "";
1443
+ return `Table: ${t.name} (${t.rowCount || 0} rows)
1444
+ Columns: ${cols}`;
1445
+ }).join("\n\n");
1446
+ } catch (e) {
1447
+ filteredSchemaStr = schemaContext.substring(0, 5e3);
1448
+ }
1449
+ }
1450
+ const response = await fetch("/api/ai/describe-schema", {
1451
+ method: "POST",
1452
+ headers: { "Content-Type": "application/json" },
1453
+ body: JSON.stringify({
1454
+ schemaContext: filteredSchemaStr,
1455
+ databaseType,
1456
+ mode: "full"
1457
+ })
1458
+ });
1459
+ if (!response.ok) {
1460
+ const err = await response.json();
1461
+ throw new Error(err.error || "Documentation generation failed");
1462
+ }
1463
+ const reader = (_a = response.body) == null ? void 0 : _a.getReader();
1464
+ if (!reader) throw new Error("No reader");
1465
+ let full = "";
1466
+ while (true) {
1467
+ const { done, value } = await reader.read();
1468
+ if (done) break;
1469
+ full += new TextDecoder().decode(value);
1470
+ setAiDocs(full);
1471
+ }
1472
+ } catch (err) {
1473
+ setError(err instanceof Error ? err.message : "Unknown error");
1474
+ } finally {
1475
+ setIsAiLoading(false);
1476
+ }
1477
+ };
1478
+ const exportMarkdown = () => {
1479
+ let md = `# Database Documentation
1480
+
1481
+ `;
1482
+ md += `**Type:** ${databaseType || "Unknown"}
1483
+ `;
1484
+ md += `**Tables:** ${schema.length}
1485
+
1486
+ `;
1487
+ if (aiDocs) {
1488
+ md += `## AI Analysis
1489
+
1490
+ ${aiDocs}
1491
+
1492
+ ---
1493
+
1494
+ `;
1495
+ }
1496
+ md += `## Table Reference
1497
+
1498
+ `;
1499
+ for (const table of schema) {
1500
+ md += `### ${table.name}
1501
+
1502
+ `;
1503
+ if (table.rowCount !== void 0) md += `Rows: ${table.rowCount.toLocaleString()}
1504
+
1505
+ `;
1506
+ if (table.columns && table.columns.length > 0) {
1507
+ md += `| Column | Type | Primary | Nullable |
1508
+ |--------|------|---------|----------|
1509
+ `;
1510
+ for (const col of table.columns) {
1511
+ md += `| ${col.name} | ${col.type} | ${col.isPrimary ? "Yes" : ""} | ${col.nullable !== false ? "Yes" : "No"} |
1512
+ `;
1513
+ }
1514
+ md += "\n";
1515
+ }
1516
+ }
1517
+ const blob = new Blob([md], { type: "text/markdown" });
1518
+ const url = URL.createObjectURL(blob);
1519
+ const a = document.createElement("a");
1520
+ a.href = url;
1521
+ a.download = "database-docs.md";
1522
+ a.click();
1523
+ URL.revokeObjectURL(url);
1524
+ };
1525
+ const renderMarkdown = (text) => {
1526
+ return text.split("\n").map((line, i) => {
1527
+ if (line.startsWith("## ")) return /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xs font-medium text-zinc-200 mt-4 mb-2", children: line.slice(3) }, i);
1528
+ if (line.startsWith("### ")) return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-medium text-zinc-300 mt-3 mb-1", children: line.slice(4) }, i);
1529
+ if (line.startsWith("- ")) {
1530
+ const content = line.slice(2).replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1531
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-xs text-zinc-400 ml-4 leading-relaxed", dangerouslySetInnerHTML: { __html: content } }, i);
1532
+ }
1533
+ if (line.match(/^\d+\.\s/)) {
1534
+ const content = line.replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1535
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-xs text-zinc-400 ml-4 leading-relaxed list-decimal", dangerouslySetInnerHTML: { __html: content } }, i);
1536
+ }
1537
+ if (line.trim()) {
1538
+ const content = line.replace(/\*\*(.*?)\*\*/g, '<strong class="text-zinc-200">$1</strong>');
1539
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-400 leading-relaxed", dangerouslySetInnerHTML: { __html: content } }, i);
1540
+ }
1541
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5" }, i);
1542
+ });
1543
+ };
1544
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
1545
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-b border-white/5 bg-[#0a0a0a]", children: [
1546
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1547
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1 rounded bg-teal-500/10", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { strokeWidth: 1.5, className: "w-3 h-3 text-teal-400" }) }),
1548
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-teal-400", children: "Database Docs" }),
1549
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.625rem] text-zinc-500 font-mono", children: [
1550
+ schema.length,
1551
+ " tables"
1552
+ ] })
1553
+ ] }),
1554
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
1555
+ /* @__PURE__ */ jsxRuntime.jsxs(
1556
+ "button",
1557
+ {
1558
+ onClick: generateAiDocs,
1559
+ disabled: isAiLoading,
1560
+ className: chunkY52UIFEX_js.cn(
1561
+ "flex items-center gap-1 px-2.5 py-1 rounded-lg text-xs font-medium transition-colors",
1562
+ isAiLoading ? "bg-teal-600/20 text-teal-400 cursor-wait" : "bg-teal-600 hover:bg-teal-500 text-white"
1563
+ ),
1564
+ children: [
1565
+ isAiLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { strokeWidth: 1.5, className: "w-3 h-3 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { strokeWidth: 1.5, className: "w-3 h-3" }),
1566
+ aiDocs ? "Regenerate" : "AI Describe"
1567
+ ]
1568
+ }
1569
+ ),
1570
+ /* @__PURE__ */ jsxRuntime.jsxs(
1571
+ "button",
1572
+ {
1573
+ onClick: exportMarkdown,
1574
+ className: "flex items-center gap-1 px-2.5 py-1 rounded-lg bg-white/5 text-zinc-400 text-xs font-medium hover:bg-white/10 transition-colors",
1575
+ children: [
1576
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { strokeWidth: 1.5, className: "w-3 h-3" }),
1577
+ " Export MD"
1578
+ ]
1579
+ }
1580
+ )
1581
+ ] })
1582
+ ] }),
1583
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-2 border-b border-white/5 bg-[#0a0a0a]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1584
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { strokeWidth: 1.5, className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-zinc-500" }),
1585
+ /* @__PURE__ */ jsxRuntime.jsx(
1586
+ "input",
1587
+ {
1588
+ value: search,
1589
+ onChange: (e) => setSearch(e.target.value),
1590
+ placeholder: "Search tables or columns...",
1591
+ className: "w-full bg-[#111] border border-white/10 rounded-lg pl-7 pr-3 py-1.5 text-xs text-zinc-200 placeholder:text-zinc-600 outline-none focus:border-teal-500/30"
1592
+ }
1593
+ )
1594
+ ] }) }),
1595
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-auto p-4 space-y-3", children: [
1596
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3 text-xs text-red-400", children: error }),
1597
+ (aiDocs || isAiLoading) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-teal-500/5 border border-teal-500/10 rounded-lg p-4 mb-4", children: [
1598
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
1599
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { strokeWidth: 1.5, className: "w-3 h-3 text-teal-400" }),
1600
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-teal-400", children: "AI-Generated Documentation" }),
1601
+ isAiLoading && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { strokeWidth: 1.5, className: "w-3 h-3 animate-spin text-teal-400" })
1602
+ ] }),
1603
+ aiDocs && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-invert prose-xs max-w-none", children: renderMarkdown(aiDocs) })
1604
+ ] }),
1605
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-medium text-zinc-400", children: "Table Reference" }),
1606
+ filteredSchema.map((table) => {
1607
+ var _a;
1608
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[#0a0a0a] border border-white/5 rounded-lg overflow-hidden", children: [
1609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [
1610
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1611
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-zinc-200", children: table.name }),
1612
+ table.rowCount !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-zinc-500 font-mono", children: [
1613
+ table.rowCount.toLocaleString(),
1614
+ " rows"
1615
+ ] })
1616
+ ] }),
1617
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-zinc-600", children: [
1618
+ ((_a = table.columns) == null ? void 0 : _a.length) || 0,
1619
+ " columns"
1620
+ ] })
1621
+ ] }),
1622
+ table.columns && table.columns.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-white/5", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-xs", children: [
1623
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-zinc-500", children: [
1624
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-3 py-1 font-normal", children: "Column" }),
1625
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-3 py-1 font-normal", children: "Type" }),
1626
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-3 py-1 font-normal", children: "PK" }),
1627
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "text-left px-3 py-1 font-normal", children: "Nullable" })
1628
+ ] }) }),
1629
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: table.columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-white/[0.03] hover:bg-white/[0.02]", children: [
1630
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1 text-zinc-300 font-mono", children: col.name }),
1631
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1 text-zinc-500 font-mono", children: col.type }),
1632
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1", children: col.isPrimary && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-400 text-[0.625rem] font-medium", children: "PK" }) }),
1633
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-1 text-zinc-600", children: col.nullable !== false ? "Yes" : "No" })
1634
+ ] }, col.name)) })
1635
+ ] }) })
1636
+ ] }, table.name);
1637
+ })
1638
+ ] })
1639
+ ] });
1640
+ }
1641
+ function QueryHistory({ onSelectQuery, activeConnectionId, refreshTrigger }) {
1642
+ const [history, setHistory] = React.useState([]);
1643
+ const [search, setSearch] = React.useState("");
1644
+ const [filterStatus, setFilterStatus] = React.useState("all");
1645
+ const [isGlobal, setIsGlobal] = React.useState(false);
1646
+ const [sortField, setSortField] = React.useState("executedAt");
1647
+ const [sortOrder, setSortOrder] = React.useState("desc");
1648
+ React.useEffect(() => {
1649
+ setHistory(chunkY52UIFEX_js.storage.getHistory());
1650
+ }, [refreshTrigger]);
1651
+ const filteredHistory = React.useMemo(() => {
1652
+ return history.filter((item) => {
1653
+ var _a, _b;
1654
+ const matchesSearch = item.query.toLowerCase().includes(search.toLowerCase()) || ((_a = item.connectionName) == null ? void 0 : _a.toLowerCase().includes(search.toLowerCase())) || ((_b = item.tabName) == null ? void 0 : _b.toLowerCase().includes(search.toLowerCase()));
1655
+ const matchesStatus = filterStatus === "all" || item.status === filterStatus;
1656
+ const matchesConnection = isGlobal || !activeConnectionId || item.connectionId === activeConnectionId;
1657
+ return matchesSearch && matchesStatus && matchesConnection;
1658
+ }).sort((a, b) => {
1659
+ let valA = 0;
1660
+ let valB = 0;
1661
+ if (sortField === "executedAt") {
1662
+ valA = a.executedAt ? new Date(a.executedAt).getTime() : 0;
1663
+ valB = b.executedAt ? new Date(b.executedAt).getTime() : 0;
1664
+ } else {
1665
+ valA = a[sortField] || 0;
1666
+ valB = b[sortField] || 0;
1667
+ }
1668
+ if (sortOrder === "asc") return valA > valB ? 1 : -1;
1669
+ return valA < valB ? 1 : -1;
1670
+ });
1671
+ }, [history, search, filterStatus, isGlobal, activeConnectionId, sortField, sortOrder]);
1672
+ const handleClearHistory = () => {
1673
+ if (confirm("Are you sure you want to clear all history?")) {
1674
+ chunkY52UIFEX_js.storage.clearHistory();
1675
+ setHistory([]);
1676
+ }
1677
+ };
1678
+ const handleSort = (field) => {
1679
+ if (sortField === field) {
1680
+ setSortOrder(sortOrder === "asc" ? "desc" : "asc");
1681
+ } else {
1682
+ setSortField(field);
1683
+ setSortOrder("desc");
1684
+ }
1685
+ };
1686
+ const exportHistory = (format3) => {
1687
+ let content = "";
1688
+ let mimeType = "";
1689
+ const fileName = `query_history_${(/* @__PURE__ */ new Date()).getTime()}.${format3}`;
1690
+ if (format3 === "csv") {
1691
+ const headers = ["Executed At", "Status", "Connection", "Tab", "Execution Time (ms)", "Rows", "Query", "Error"];
1692
+ const rows = filteredHistory.map((item) => [
1693
+ item.executedAt,
1694
+ item.status,
1695
+ item.connectionName || item.connectionId,
1696
+ item.tabName || "",
1697
+ item.executionTime,
1698
+ item.rowCount || 0,
1699
+ `"${item.query.replace(/"/g, '""')}"`,
1700
+ `"${(item.errorMessage || "").replace(/"/g, '""')}"`
1701
+ ].join(","));
1702
+ content = [headers.join(","), ...rows].join("\n");
1703
+ mimeType = "text/csv";
1704
+ } else {
1705
+ content = JSON.stringify(filteredHistory, null, 2);
1706
+ mimeType = "application/json";
1707
+ }
1708
+ const blob = new Blob([content], { type: mimeType });
1709
+ const url = URL.createObjectURL(blob);
1710
+ const link = document.createElement("a");
1711
+ link.href = url;
1712
+ link.download = fileName;
1713
+ link.click();
1714
+ URL.revokeObjectURL(url);
1715
+ };
1716
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
1717
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-white/5 bg-[#0a0a0a]/50 backdrop-blur-sm sticky top-0 z-10 space-y-4", children: [
1718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1719
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1720
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 rounded-lg bg-emerald-500/10 border border-emerald-500/20", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { strokeWidth: 1.5, className: "w-3.5 h-3.5 text-emerald-400" }) }),
1721
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1722
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-medium text-zinc-100 flex items-center gap-2", children: "Query History" }),
1723
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-zinc-500 font-medium", children: [
1724
+ "Showing ",
1725
+ filteredHistory.length,
1726
+ " executions"
1727
+ ] })
1728
+ ] })
1729
+ ] }),
1730
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1731
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DropdownMenu, { children: [
1732
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.Button, { variant: "ghost", size: "sm", className: "h-8 text-xs font-medium text-zinc-400 hover:text-white gap-2", children: [
1733
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { strokeWidth: 1.5, className: "w-3 h-3" }),
1734
+ " Export"
1735
+ ] }) }),
1736
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DropdownMenuContent, { align: "end", className: "bg-[#0d0d0d] border-white/10 text-zinc-300", children: [
1737
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => exportHistory("csv"), className: "text-xs cursor-pointer", children: "Export as CSV" }),
1738
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => exportHistory("json"), className: "text-xs cursor-pointer", children: "Export as JSON" })
1739
+ ] })
1740
+ ] }),
1741
+ /* @__PURE__ */ jsxRuntime.jsxs(
1742
+ chunkY52UIFEX_js.Button,
1743
+ {
1744
+ variant: "ghost",
1745
+ size: "sm",
1746
+ onClick: handleClearHistory,
1747
+ className: "h-8 text-xs font-medium text-red-400/70 hover:text-red-400 hover:bg-red-400/10",
1748
+ children: [
1749
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { strokeWidth: 1.5, className: "w-3 h-3 mr-2" }),
1750
+ " Clear"
1751
+ ]
1752
+ }
1753
+ )
1754
+ ] })
1755
+ ] }),
1756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
1757
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 min-w-[240px]", children: [
1758
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { strokeWidth: 1.5, className: "absolute left-3 top-1/2 -translate-y-1/2 w-3 h-3 text-zinc-500" }),
1759
+ /* @__PURE__ */ jsxRuntime.jsx(
1760
+ chunkY52UIFEX_js.Input,
1761
+ {
1762
+ placeholder: "Search by query, connection or tab...",
1763
+ value: search,
1764
+ onChange: (e) => setSearch(e.target.value),
1765
+ className: "pl-9 h-9 bg-white/5 border-white/10 text-xs focus:ring-emerald-500/20 rounded-lg"
1766
+ }
1767
+ ),
1768
+ search && /* @__PURE__ */ jsxRuntime.jsx(
1769
+ "button",
1770
+ {
1771
+ onClick: () => setSearch(""),
1772
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500 hover:text-white",
1773
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { strokeWidth: 1.5, className: "w-3 h-3" })
1774
+ }
1775
+ )
1776
+ ] }),
1777
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 bg-white/5 rounded-lg p-1 border border-white/10", children: [
1778
+ /* @__PURE__ */ jsxRuntime.jsx(
1779
+ "button",
1780
+ {
1781
+ onClick: () => setIsGlobal(false),
1782
+ className: chunkY52UIFEX_js.cn(
1783
+ "px-3 py-1.5 text-xs font-medium rounded-md transition-all",
1784
+ !isGlobal ? "bg-emerald-600 text-white shadow-lg shadow-emerald-600/20" : "text-zinc-500 hover:text-zinc-300"
1785
+ ),
1786
+ children: "Active Conn"
1787
+ }
1788
+ ),
1789
+ /* @__PURE__ */ jsxRuntime.jsx(
1790
+ "button",
1791
+ {
1792
+ onClick: () => setIsGlobal(true),
1793
+ className: chunkY52UIFEX_js.cn(
1794
+ "px-3 py-1.5 text-xs font-medium rounded-md transition-all",
1795
+ isGlobal ? "bg-emerald-600 text-white shadow-lg shadow-emerald-600/20" : "text-zinc-500 hover:text-zinc-300"
1796
+ ),
1797
+ children: "All Connections"
1798
+ }
1799
+ )
1800
+ ] }),
1801
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex bg-white/5 rounded-lg p-1 border border-white/10", children: ["all", "success", "error"].map((status) => /* @__PURE__ */ jsxRuntime.jsx(
1802
+ "button",
1803
+ {
1804
+ onClick: () => setFilterStatus(status),
1805
+ className: chunkY52UIFEX_js.cn(
1806
+ "px-3 py-1.5 text-xs font-medium rounded-md transition-all",
1807
+ filterStatus === status ? "bg-white/10 text-white" : "text-zinc-500 hover:text-zinc-300"
1808
+ ),
1809
+ children: status
1810
+ },
1811
+ status
1812
+ )) })
1813
+ ] })
1814
+ ] }),
1815
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto custom-scrollbar", children: filteredHistory.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center opacity-20 p-8 text-center", children: [
1816
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { strokeWidth: 1.5, className: "w-16 h-16 mb-4 text-zinc-600" }),
1817
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: "No history items found" }),
1818
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-500 mt-1r", children: "Run some queries to see them here" })
1819
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-[800px]", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full text-left border-collapse", children: [
1820
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-white/[0.02] border-b border-white/5 text-xs font-medium text-zinc-500", children: [
1821
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 w-10 text-center", children: "Status" }),
1822
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 cursor-pointer hover:text-zinc-300 transition-colors group", onClick: () => handleSort("executedAt"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1823
+ "Executed At",
1824
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: chunkY52UIFEX_js.cn("w-3 h-3 transition-opacity", sortField === "executedAt" ? "opacity-100 text-emerald-500" : "opacity-0 group-hover:opacity-100") })
1825
+ ] }) }),
1826
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3", children: "Source" }),
1827
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3", children: "SQL Query" }),
1828
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 cursor-pointer hover:text-zinc-300 transition-colors group", onClick: () => handleSort("executionTime"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1829
+ "Duration",
1830
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: chunkY52UIFEX_js.cn("w-3 h-3 transition-opacity", sortField === "executionTime" ? "opacity-100 text-emerald-500" : "opacity-0 group-hover:opacity-100") })
1831
+ ] }) }),
1832
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 cursor-pointer hover:text-zinc-300 transition-colors group", onClick: () => handleSort("rowCount"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1833
+ "Rows",
1834
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: chunkY52UIFEX_js.cn("w-3 h-3 transition-opacity", sortField === "rowCount" ? "opacity-100 text-emerald-500" : "opacity-0 group-hover:opacity-100") })
1835
+ ] }) }),
1836
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 w-20" })
1837
+ ] }) }),
1838
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-white/5", children: filteredHistory.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
1839
+ "tr",
1840
+ {
1841
+ className: "hover:bg-white/[0.03] transition-colors group text-xs border-b border-white/5",
1842
+ children: [
1843
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: item.status === "success" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 rounded-full bg-emerald-500/10 flex items-center justify-center border border-emerald-500/20", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { strokeWidth: 1.5, className: "w-3 h-3 text-emerald-500" }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 rounded-full bg-red-500/10 flex items-center justify-center border border-red-500/20", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { strokeWidth: 1.5, className: "w-3 h-3 text-red-500" }) }) }) }),
1844
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
1845
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-200 font-medium", children: item.executedAt ? dateFns.format(new Date(item.executedAt), "MMM d, HH:mm:ss") : "-" }),
1846
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-mono mt-0.5", children: item.executedAt ? dateFns.format(new Date(item.executedAt), "yyyy") : "" })
1847
+ ] }) }),
1848
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1849
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-zinc-300", children: [
1850
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-3 h-3 text-blue-400" }),
1851
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: item.connectionName || "Unknown" })
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-zinc-500 text-xs", children: [
1854
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hash, { strokeWidth: 1.5, className: "w-2.5 h-2.5" }),
1855
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: item.tabName || "Default Tab" })
1856
+ ] })
1857
+ ] }) }),
1858
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 max-w-md", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[#050505] border border-white/5 rounded-md p-2 relative group-hover:border-white/10 transition-colors", children: [
1859
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs font-mono text-zinc-400 line-clamp-2 break-all whitespace-pre-wrap leading-relaxed", children: item.query }),
1860
+ item.errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 pt-2 border-t border-red-500/10 text-xs text-red-400/80 font-mono italic", children: item.errorMessage })
1861
+ ] }) }),
1862
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: chunkY52UIFEX_js.cn(
1863
+ "px-2 py-0.5 rounded text-xs font-mono font-medium",
1864
+ item.executionTime > 500 ? "text-amber-400 bg-amber-400/10" : "text-zinc-400 bg-white/5"
1865
+ ), children: [
1866
+ item.executionTime,
1867
+ "ms"
1868
+ ] }) }),
1869
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 whitespace-nowrap", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 font-mono text-xs", children: item.rowCount != null ? item.rowCount.toLocaleString() : "-" }) }),
1870
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-4 text-right", children: /* @__PURE__ */ jsxRuntime.jsx(
1871
+ chunkY52UIFEX_js.Button,
1872
+ {
1873
+ variant: "ghost",
1874
+ size: "sm",
1875
+ className: "h-8 w-8 p-0 hover:bg-emerald-500/10 hover:text-emerald-400",
1876
+ onClick: () => onSelectQuery(item.query),
1877
+ title: "Restore Query",
1878
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "w-3 h-3" })
1879
+ }
1880
+ ) })
1881
+ ]
1882
+ },
1883
+ item.id
1884
+ )) })
1885
+ ] }) }) })
1886
+ ] });
1887
+ }
1888
+ function SavedQueries({ onSelectQuery, connectionType, refreshTrigger }) {
1889
+ const [queries, setQueries] = React.useState([]);
1890
+ const [search, setSearch] = React.useState("");
1891
+ React.useEffect(() => {
1892
+ setQueries(chunkY52UIFEX_js.storage.getSavedQueries());
1893
+ }, [refreshTrigger]);
1894
+ const filteredQueries = queries.filter((q) => {
1895
+ const matchesSearch = q.name.toLowerCase().includes(search.toLowerCase()) || q.query.toLowerCase().includes(search.toLowerCase());
1896
+ const matchesType = !connectionType || q.connectionType === connectionType;
1897
+ return matchesSearch && matchesType;
1898
+ });
1899
+ const handleDelete = (id, e) => {
1900
+ e.stopPropagation();
1901
+ if (confirm("Are you sure you want to delete this saved query?")) {
1902
+ chunkY52UIFEX_js.storage.deleteSavedQuery(id);
1903
+ setQueries(chunkY52UIFEX_js.storage.getSavedQueries());
1904
+ }
1905
+ };
1906
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#0a0a0a]", children: [
1907
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-white/5 flex flex-col gap-4", children: [
1908
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-xs font-medium text-zinc-400 flex items-center gap-2", children: [
1909
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bookmark, { strokeWidth: 1.5, className: "w-3.5 h-3.5" }),
1910
+ " Saved Queries"
1911
+ ] }),
1912
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1913
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { strokeWidth: 1.5, className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3 h-3 text-zinc-500" }),
1914
+ /* @__PURE__ */ jsxRuntime.jsx(
1915
+ chunkY52UIFEX_js.Input,
1916
+ {
1917
+ placeholder: "Search saved queries...",
1918
+ value: search,
1919
+ onChange: (e) => setSearch(e.target.value),
1920
+ className: "pl-8 h-8 bg-white/5 border-white/10 text-xs focus:ring-blue-500/20"
1921
+ }
1922
+ )
1923
+ ] })
1924
+ ] }),
1925
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto custom-scrollbar", children: filteredQueries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center opacity-20 p-8 text-center", children: [
1926
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bookmark, { strokeWidth: 1.5, className: "w-12 h-12 mb-4" }),
1927
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs italic", children: "No saved queries found" })
1928
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-px bg-white/5", children: filteredQueries.map((q) => {
1929
+ var _a;
1930
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1931
+ "div",
1932
+ {
1933
+ className: "bg-[#0a0a0a] p-4 hover:bg-white/[0.02] transition-colors group cursor-pointer",
1934
+ onClick: () => onSelectQuery(q.query),
1935
+ children: [
1936
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between mb-2", children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1938
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs font-medium text-blue-400 mb-1 group-hover:text-blue-300 transition-colors", children: q.name }),
1939
+ q.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-500 line-clamp-1", children: q.description })
1940
+ ] }),
1941
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
1942
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Button, { variant: "ghost", size: "icon", className: "h-6 w-6 text-zinc-500 hover:text-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit3, { strokeWidth: 1.5, className: "w-3 h-3" }) }),
1943
+ /* @__PURE__ */ jsxRuntime.jsx(
1944
+ chunkY52UIFEX_js.Button,
1945
+ {
1946
+ variant: "ghost",
1947
+ size: "icon",
1948
+ className: "h-6 w-6 text-zinc-500 hover:text-red-400",
1949
+ onClick: (e) => handleDelete(q.id, e),
1950
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { strokeWidth: 1.5, className: "w-3 h-3" })
1951
+ }
1952
+ )
1953
+ ] })
1954
+ ] }),
1955
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-[#050505] border border-white/5 rounded-md p-2 mb-3", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs font-mono text-zinc-400 line-clamp-3", children: q.query }) }),
1956
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1957
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1958
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1.5 py-0.5 rounded bg-blue-500/10 border border-blue-500/20 text-[0.625rem] font-medium text-blue-400er", children: q.connectionType }),
1959
+ (_a = q.tags) == null ? void 0 : _a.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-[0.625rem] text-zinc-500", children: [
1960
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tag, { strokeWidth: 1.5, className: "w-2.5 h-2.5" }),
1961
+ " ",
1962
+ tag
1963
+ ] }, tag))
1964
+ ] }),
1965
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.625rem] text-zinc-600 flex items-center gap-1 font-mono", children: [
1966
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "w-2.5 h-2.5" }),
1967
+ " ",
1968
+ dateFns.format(q.updatedAt, "MMM d, yyyy")
1969
+ ] })
1970
+ ] })
1971
+ ]
1972
+ },
1973
+ q.id
1974
+ );
1975
+ }) }) })
1976
+ ] });
1977
+ }
1978
+ var badgeVariants = classVarianceAuthority.cva(
1979
+ "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
1980
+ {
1981
+ variants: {
1982
+ variant: {
1983
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
1984
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
1985
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
1986
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
1987
+ }
1988
+ },
1989
+ defaultVariants: {
1990
+ variant: "default"
1991
+ }
1992
+ }
1993
+ );
1994
+ function Badge(_a) {
1995
+ var _b = _a, {
1996
+ className,
1997
+ variant,
1998
+ asChild = false
1999
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
2000
+ "className",
2001
+ "variant",
2002
+ "asChild"
2003
+ ]);
2004
+ const Comp = asChild ? reactSlot.Slot : "span";
2005
+ return /* @__PURE__ */ jsxRuntime.jsx(
2006
+ Comp,
2007
+ chunkQ6LRDBK7_js.__spreadValues({
2008
+ "data-slot": "badge",
2009
+ className: chunkY52UIFEX_js.cn(badgeVariants({ variant }), className)
2010
+ }, props)
2011
+ );
2012
+ }
2013
+ function useAllConnections() {
2014
+ const [connections, setConnections] = React.useState([]);
2015
+ const [loading, setLoading] = React.useState(true);
2016
+ React.useEffect(() => {
2017
+ let cancelled = false;
2018
+ async function load() {
2019
+ const userConns = chunkY52UIFEX_js.storage.getConnections();
2020
+ try {
2021
+ const res = await fetch("/api/connections/managed");
2022
+ if (res.ok) {
2023
+ const { connections: managedConns } = await res.json();
2024
+ if ((managedConns == null ? void 0 : managedConns.length) > 0 && !cancelled) {
2025
+ const merged = [];
2026
+ const addedIds = /* @__PURE__ */ new Set();
2027
+ for (const mc of managedConns) {
2028
+ merged.push(chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, mc), { createdAt: new Date(mc.createdAt) }));
2029
+ addedIds.add(mc.id);
2030
+ if (mc.seedId) addedIds.add(`seed:${mc.seedId}`);
2031
+ }
2032
+ for (const uc of userConns) {
2033
+ if (addedIds.has(uc.id)) continue;
2034
+ if (uc.seedId && managedConns.some((mc) => mc.seedId === uc.seedId)) continue;
2035
+ merged.push(uc);
2036
+ }
2037
+ setConnections(merged);
2038
+ setLoading(false);
2039
+ return;
2040
+ }
2041
+ }
2042
+ } catch (e) {
2043
+ }
2044
+ if (!cancelled) {
2045
+ setConnections(userConns);
2046
+ setLoading(false);
2047
+ }
2048
+ }
2049
+ load();
2050
+ return () => {
2051
+ cancelled = true;
2052
+ };
2053
+ }, []);
2054
+ return { connections, loading };
2055
+ }
2056
+
2057
+ // src/lib/schema-diff/diff-engine.ts
2058
+ function diffColumns(sourceCols, targetCols) {
2059
+ const diffs = [];
2060
+ const sourceMap = new Map(sourceCols.map((c) => [c.name, c]));
2061
+ const targetMap = new Map(targetCols.map((c) => [c.name, c]));
2062
+ for (const [name, col] of targetMap) {
2063
+ if (!sourceMap.has(name)) {
2064
+ diffs.push({
2065
+ action: "added",
2066
+ columnName: name,
2067
+ targetType: col.type,
2068
+ targetNullable: col.nullable,
2069
+ targetDefault: col.defaultValue,
2070
+ targetIsPrimary: col.isPrimary,
2071
+ changes: [`Added column "${name}" (${col.type})`]
2072
+ });
2073
+ }
2074
+ }
2075
+ for (const [name, col] of sourceMap) {
2076
+ if (!targetMap.has(name)) {
2077
+ diffs.push({
2078
+ action: "removed",
2079
+ columnName: name,
2080
+ sourceType: col.type,
2081
+ sourceNullable: col.nullable,
2082
+ sourceDefault: col.defaultValue,
2083
+ sourceIsPrimary: col.isPrimary,
2084
+ changes: [`Removed column "${name}" (${col.type})`]
2085
+ });
2086
+ }
2087
+ }
2088
+ for (const [name, sourceCol] of sourceMap) {
2089
+ const targetCol = targetMap.get(name);
2090
+ if (!targetCol) continue;
2091
+ const changes = [];
2092
+ if (sourceCol.type.toLowerCase() !== targetCol.type.toLowerCase()) {
2093
+ changes.push(`Type changed: ${sourceCol.type} \u2192 ${targetCol.type}`);
2094
+ }
2095
+ if (sourceCol.nullable !== targetCol.nullable) {
2096
+ changes.push(`Nullable changed: ${sourceCol.nullable} \u2192 ${targetCol.nullable}`);
2097
+ }
2098
+ if ((sourceCol.defaultValue || "") !== (targetCol.defaultValue || "")) {
2099
+ changes.push(`Default changed: ${sourceCol.defaultValue || "none"} \u2192 ${targetCol.defaultValue || "none"}`);
2100
+ }
2101
+ if (sourceCol.isPrimary !== targetCol.isPrimary) {
2102
+ changes.push(`Primary key changed: ${sourceCol.isPrimary} \u2192 ${targetCol.isPrimary}`);
2103
+ }
2104
+ if (changes.length > 0) {
2105
+ diffs.push({
2106
+ action: "modified",
2107
+ columnName: name,
2108
+ sourceType: sourceCol.type,
2109
+ targetType: targetCol.type,
2110
+ sourceNullable: sourceCol.nullable,
2111
+ targetNullable: targetCol.nullable,
2112
+ sourceDefault: sourceCol.defaultValue,
2113
+ targetDefault: targetCol.defaultValue,
2114
+ sourceIsPrimary: sourceCol.isPrimary,
2115
+ targetIsPrimary: targetCol.isPrimary,
2116
+ changes
2117
+ });
2118
+ }
2119
+ }
2120
+ return diffs;
2121
+ }
2122
+ function diffIndexes(sourceIndexes, targetIndexes) {
2123
+ const diffs = [];
2124
+ const sourceMap = /* @__PURE__ */ new Map();
2125
+ sourceIndexes.forEach((idx) => {
2126
+ const key = idx.name || idx.columns.sort().join(",");
2127
+ sourceMap.set(key, idx);
2128
+ });
2129
+ const targetMap = /* @__PURE__ */ new Map();
2130
+ targetIndexes.forEach((idx) => {
2131
+ const key = idx.name || idx.columns.sort().join(",");
2132
+ targetMap.set(key, idx);
2133
+ });
2134
+ for (const [key, idx] of targetMap) {
2135
+ if (!sourceMap.has(key)) {
2136
+ diffs.push({
2137
+ action: "added",
2138
+ indexName: idx.name || key,
2139
+ targetColumns: idx.columns,
2140
+ targetUnique: idx.unique,
2141
+ changes: [`Added index "${idx.name || key}" on (${idx.columns.join(", ")})`]
2142
+ });
2143
+ }
2144
+ }
2145
+ for (const [key, idx] of sourceMap) {
2146
+ if (!targetMap.has(key)) {
2147
+ diffs.push({
2148
+ action: "removed",
2149
+ indexName: idx.name || key,
2150
+ sourceColumns: idx.columns,
2151
+ sourceUnique: idx.unique,
2152
+ changes: [`Removed index "${idx.name || key}"`]
2153
+ });
2154
+ }
2155
+ }
2156
+ for (const [key, sourceIdx] of sourceMap) {
2157
+ const targetIdx = targetMap.get(key);
2158
+ if (!targetIdx) continue;
2159
+ const changes = [];
2160
+ const sourceColStr = sourceIdx.columns.sort().join(",");
2161
+ const targetColStr = targetIdx.columns.sort().join(",");
2162
+ if (sourceColStr !== targetColStr) {
2163
+ changes.push(`Columns changed: (${sourceIdx.columns.join(", ")}) \u2192 (${targetIdx.columns.join(", ")})`);
2164
+ }
2165
+ if (sourceIdx.unique !== targetIdx.unique) {
2166
+ changes.push(`Unique changed: ${sourceIdx.unique} \u2192 ${targetIdx.unique}`);
2167
+ }
2168
+ if (changes.length > 0) {
2169
+ diffs.push({
2170
+ action: "modified",
2171
+ indexName: sourceIdx.name || key,
2172
+ sourceColumns: sourceIdx.columns,
2173
+ targetColumns: targetIdx.columns,
2174
+ sourceUnique: sourceIdx.unique,
2175
+ targetUnique: targetIdx.unique,
2176
+ changes
2177
+ });
2178
+ }
2179
+ }
2180
+ return diffs;
2181
+ }
2182
+ function diffForeignKeys(sourceFKs, targetFKs) {
2183
+ const diffs = [];
2184
+ const makeKey = (fk) => `${fk.columnName}\u2192${fk.referencedTable}.${fk.referencedColumn}`;
2185
+ const sourceMap = new Map(sourceFKs.map((fk) => [makeKey(fk), fk]));
2186
+ const targetMap = new Map(targetFKs.map((fk) => [makeKey(fk), fk]));
2187
+ for (const [key, fk] of targetMap) {
2188
+ if (!sourceMap.has(key)) {
2189
+ diffs.push({
2190
+ action: "added",
2191
+ columnName: fk.columnName,
2192
+ targetReferencedTable: fk.referencedTable,
2193
+ targetReferencedColumn: fk.referencedColumn,
2194
+ changes: [`Added FK: ${fk.columnName} \u2192 ${fk.referencedTable}(${fk.referencedColumn})`]
2195
+ });
2196
+ }
2197
+ }
2198
+ for (const [key, fk] of sourceMap) {
2199
+ if (!targetMap.has(key)) {
2200
+ diffs.push({
2201
+ action: "removed",
2202
+ columnName: fk.columnName,
2203
+ sourceReferencedTable: fk.referencedTable,
2204
+ sourceReferencedColumn: fk.referencedColumn,
2205
+ changes: [`Removed FK: ${fk.columnName} \u2192 ${fk.referencedTable}(${fk.referencedColumn})`]
2206
+ });
2207
+ }
2208
+ }
2209
+ return diffs;
2210
+ }
2211
+ function diffSchemas(source, target) {
2212
+ const sourceMap = new Map(source.map((t) => [t.name, t]));
2213
+ const targetMap = new Map(target.map((t) => [t.name, t]));
2214
+ const tables = [];
2215
+ let added = 0, removed = 0, modified = 0;
2216
+ for (const [name, table] of targetMap) {
2217
+ if (!sourceMap.has(name)) {
2218
+ tables.push({
2219
+ action: "added",
2220
+ tableName: name,
2221
+ columns: table.columns.map((c) => ({
2222
+ action: "added",
2223
+ columnName: c.name,
2224
+ targetType: c.type,
2225
+ targetNullable: c.nullable,
2226
+ targetDefault: c.defaultValue,
2227
+ targetIsPrimary: c.isPrimary,
2228
+ changes: [`Added column "${c.name}" (${c.type})`]
2229
+ })),
2230
+ indexes: table.indexes.map((idx) => ({
2231
+ action: "added",
2232
+ indexName: idx.name,
2233
+ targetColumns: idx.columns,
2234
+ targetUnique: idx.unique,
2235
+ changes: [`Added index "${idx.name}"`]
2236
+ })),
2237
+ foreignKeys: (table.foreignKeys || []).map((fk) => ({
2238
+ action: "added",
2239
+ columnName: fk.columnName,
2240
+ targetReferencedTable: fk.referencedTable,
2241
+ targetReferencedColumn: fk.referencedColumn,
2242
+ changes: [`Added FK: ${fk.columnName} \u2192 ${fk.referencedTable}(${fk.referencedColumn})`]
2243
+ }))
2244
+ });
2245
+ added++;
2246
+ }
2247
+ }
2248
+ for (const [name, table] of sourceMap) {
2249
+ if (!targetMap.has(name)) {
2250
+ tables.push({
2251
+ action: "removed",
2252
+ tableName: name,
2253
+ columns: table.columns.map((c) => ({
2254
+ action: "removed",
2255
+ columnName: c.name,
2256
+ sourceType: c.type,
2257
+ sourceNullable: c.nullable,
2258
+ sourceDefault: c.defaultValue,
2259
+ sourceIsPrimary: c.isPrimary,
2260
+ changes: [`Removed column "${c.name}"`]
2261
+ })),
2262
+ indexes: [],
2263
+ foreignKeys: []
2264
+ });
2265
+ removed++;
2266
+ }
2267
+ }
2268
+ for (const [name, sourceTable] of sourceMap) {
2269
+ const targetTable = targetMap.get(name);
2270
+ if (!targetTable) continue;
2271
+ const columns = diffColumns(sourceTable.columns, targetTable.columns);
2272
+ const indexes = diffIndexes(sourceTable.indexes, targetTable.indexes);
2273
+ const foreignKeys = diffForeignKeys(sourceTable.foreignKeys || [], targetTable.foreignKeys || []);
2274
+ if (columns.length > 0 || indexes.length > 0 || foreignKeys.length > 0) {
2275
+ tables.push({
2276
+ action: "modified",
2277
+ tableName: name,
2278
+ columns,
2279
+ indexes,
2280
+ foreignKeys
2281
+ });
2282
+ modified++;
2283
+ }
2284
+ }
2285
+ return {
2286
+ tables,
2287
+ summary: { added, removed, modified },
2288
+ hasChanges: tables.length > 0
2289
+ };
2290
+ }
2291
+
2292
+ // src/lib/schema-diff/migration-generator.ts
2293
+ function escapeIdentifier(name, dialect) {
2294
+ switch (dialect) {
2295
+ case "mysql":
2296
+ return `\`${name}\``;
2297
+ case "mssql":
2298
+ return `[${name.replace(/\]/g, "]]")}]`;
2299
+ case "oracle":
2300
+ case "postgres":
2301
+ case "sqlite":
2302
+ default:
2303
+ return `"${name}"`;
2304
+ }
2305
+ }
2306
+ function generateColumnDef(col, dialect) {
2307
+ const type = col.targetType || col.sourceType || "TEXT";
2308
+ const nullable = col.targetNullable === false ? " NOT NULL" : "";
2309
+ const defaultVal = col.targetDefault ? ` DEFAULT ${col.targetDefault}` : "";
2310
+ return `${escapeIdentifier(col.columnName, dialect)} ${type}${nullable}${defaultVal}`;
2311
+ }
2312
+ function generateCreateTable(table, dialect) {
2313
+ const lines = [];
2314
+ const id = escapeIdentifier(table.tableName, dialect);
2315
+ const colDefs = table.columns.filter((c) => c.action === "added").map((c) => ` ${generateColumnDef(c, dialect)}`);
2316
+ const pkCols = table.columns.filter((c) => c.targetIsPrimary).map((c) => escapeIdentifier(c.columnName, dialect));
2317
+ lines.push(`CREATE TABLE ${id} (`);
2318
+ lines.push(colDefs.join(",\n"));
2319
+ if (pkCols.length > 0) {
2320
+ lines.push(`, PRIMARY KEY (${pkCols.join(", ")})`);
2321
+ }
2322
+ lines.push(");");
2323
+ table.indexes.filter((i) => i.action === "added").forEach((idx) => {
2324
+ const unique = idx.targetUnique ? "UNIQUE " : "";
2325
+ const cols = (idx.targetColumns || []).map((c) => escapeIdentifier(c, dialect)).join(", ");
2326
+ lines.push(`CREATE ${unique}INDEX ${escapeIdentifier(idx.indexName, dialect)} ON ${id} (${cols});`);
2327
+ });
2328
+ table.foreignKeys.filter((fk) => fk.action === "added").forEach((fk) => {
2329
+ lines.push(`ALTER TABLE ${id} ADD CONSTRAINT ${escapeIdentifier(`fk_${table.tableName}_${fk.columnName}`, dialect)} FOREIGN KEY (${escapeIdentifier(fk.columnName, dialect)}) REFERENCES ${escapeIdentifier(fk.targetReferencedTable || "", dialect)}(${escapeIdentifier(fk.targetReferencedColumn || "", dialect)});`);
2330
+ });
2331
+ return lines.join("\n");
2332
+ }
2333
+ function generateDropTable(table, dialect) {
2334
+ return `DROP TABLE IF EXISTS ${escapeIdentifier(table.tableName, dialect)};`;
2335
+ }
2336
+ function generateAlterTable(table, dialect) {
2337
+ const lines = [];
2338
+ const id = escapeIdentifier(table.tableName, dialect);
2339
+ lines.push(`-- Alter table: ${table.tableName}`);
2340
+ table.columns.filter((c) => c.action === "added").forEach((col) => {
2341
+ lines.push(`ALTER TABLE ${id} ADD COLUMN ${generateColumnDef(col, dialect)};`);
2342
+ });
2343
+ table.columns.filter((c) => c.action === "removed").forEach((col) => {
2344
+ if (dialect === "sqlite") {
2345
+ lines.push(`-- SQLite: Cannot drop column "${col.columnName}" directly. Requires table recreation.`);
2346
+ } else {
2347
+ lines.push(`ALTER TABLE ${id} DROP COLUMN ${escapeIdentifier(col.columnName, dialect)};`);
2348
+ }
2349
+ });
2350
+ table.columns.filter((c) => c.action === "modified").forEach((col) => {
2351
+ if (dialect === "sqlite") {
2352
+ lines.push(`-- SQLite: Cannot alter column "${col.columnName}" type directly. Requires table recreation.`);
2353
+ } else if (dialect === "mysql") {
2354
+ const type = col.targetType || col.sourceType || "TEXT";
2355
+ const nullable = col.targetNullable === false ? " NOT NULL" : " NULL";
2356
+ const defaultVal = col.targetDefault ? ` DEFAULT ${col.targetDefault}` : "";
2357
+ lines.push(`ALTER TABLE ${id} MODIFY COLUMN ${escapeIdentifier(col.columnName, dialect)} ${type}${nullable}${defaultVal};`);
2358
+ } else if (dialect === "oracle") {
2359
+ const type = col.targetType || col.sourceType || "VARCHAR2(255)";
2360
+ const nullable = col.targetNullable === false ? " NOT NULL" : " NULL";
2361
+ const defaultVal = col.targetDefault ? ` DEFAULT ${col.targetDefault}` : "";
2362
+ lines.push(`ALTER TABLE ${id} MODIFY (${escapeIdentifier(col.columnName, dialect)} ${type}${defaultVal}${nullable});`);
2363
+ } else if (dialect === "mssql") {
2364
+ const type = col.targetType || col.sourceType || "NVARCHAR(MAX)";
2365
+ const nullable = col.targetNullable === false ? " NOT NULL" : " NULL";
2366
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} ${type}${nullable};`);
2367
+ if (col.sourceDefault !== col.targetDefault && col.targetDefault) {
2368
+ lines.push(`ALTER TABLE ${id} ADD DEFAULT ${col.targetDefault} FOR ${escapeIdentifier(col.columnName, dialect)};`);
2369
+ }
2370
+ } else {
2371
+ if (col.sourceType !== col.targetType) {
2372
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} TYPE ${col.targetType};`);
2373
+ }
2374
+ if (col.sourceNullable !== col.targetNullable) {
2375
+ if (col.targetNullable) {
2376
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} DROP NOT NULL;`);
2377
+ } else {
2378
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} SET NOT NULL;`);
2379
+ }
2380
+ }
2381
+ if (col.sourceDefault !== col.targetDefault) {
2382
+ if (col.targetDefault) {
2383
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} SET DEFAULT ${col.targetDefault};`);
2384
+ } else {
2385
+ lines.push(`ALTER TABLE ${id} ALTER COLUMN ${escapeIdentifier(col.columnName, dialect)} DROP DEFAULT;`);
2386
+ }
2387
+ }
2388
+ }
2389
+ });
2390
+ table.indexes.filter((i) => i.action === "added").forEach((idx) => {
2391
+ const unique = idx.targetUnique ? "UNIQUE " : "";
2392
+ const cols = (idx.targetColumns || []).map((c) => escapeIdentifier(c, dialect)).join(", ");
2393
+ lines.push(`CREATE ${unique}INDEX ${escapeIdentifier(idx.indexName, dialect)} ON ${id} (${cols});`);
2394
+ });
2395
+ table.indexes.filter((i) => i.action === "removed").forEach((idx) => {
2396
+ if (dialect === "mysql") {
2397
+ lines.push(`DROP INDEX ${escapeIdentifier(idx.indexName, dialect)} ON ${id};`);
2398
+ } else {
2399
+ lines.push(`DROP INDEX IF EXISTS ${escapeIdentifier(idx.indexName, dialect)};`);
2400
+ }
2401
+ });
2402
+ table.foreignKeys.filter((fk) => fk.action === "added").forEach((fk) => {
2403
+ const constraintName = escapeIdentifier(`fk_${table.tableName}_${fk.columnName}`, dialect);
2404
+ lines.push(`ALTER TABLE ${id} ADD CONSTRAINT ${constraintName} FOREIGN KEY (${escapeIdentifier(fk.columnName, dialect)}) REFERENCES ${escapeIdentifier(fk.targetReferencedTable || "", dialect)}(${escapeIdentifier(fk.targetReferencedColumn || "", dialect)});`);
2405
+ });
2406
+ table.foreignKeys.filter((fk) => fk.action === "removed").forEach((fk) => {
2407
+ const constraintName = escapeIdentifier(`fk_${table.tableName}_${fk.columnName}`, dialect);
2408
+ if (dialect === "mysql") {
2409
+ lines.push(`ALTER TABLE ${id} DROP FOREIGN KEY ${constraintName};`);
2410
+ } else if (dialect === "sqlite") {
2411
+ lines.push(`-- SQLite: Cannot drop foreign key directly. Requires table recreation.`);
2412
+ } else {
2413
+ lines.push(`ALTER TABLE ${id} DROP CONSTRAINT IF EXISTS ${constraintName};`);
2414
+ }
2415
+ });
2416
+ return lines.join("\n");
2417
+ }
2418
+ function generateMigrationSQL(diff, dialect) {
2419
+ if (!diff.hasChanges) {
2420
+ return "-- No schema changes detected.";
2421
+ }
2422
+ const sections = [];
2423
+ sections.push(`-- Migration generated at ${(/* @__PURE__ */ new Date()).toISOString()}`);
2424
+ sections.push(`-- Dialect: ${dialect}`);
2425
+ sections.push(`-- Changes: ${diff.summary.added} added, ${diff.summary.removed} removed, ${diff.summary.modified} modified`);
2426
+ sections.push("");
2427
+ if (dialect !== "sqlite") {
2428
+ sections.push("BEGIN;");
2429
+ sections.push("");
2430
+ }
2431
+ const droppedTables = diff.tables.filter((t) => t.action === "removed");
2432
+ if (droppedTables.length > 0) {
2433
+ sections.push("-- Drop removed tables");
2434
+ droppedTables.forEach((t) => sections.push(generateDropTable(t, dialect)));
2435
+ sections.push("");
2436
+ }
2437
+ const addedTables = diff.tables.filter((t) => t.action === "added");
2438
+ if (addedTables.length > 0) {
2439
+ sections.push("-- Create new tables");
2440
+ addedTables.forEach((t) => {
2441
+ sections.push(generateCreateTable(t, dialect));
2442
+ sections.push("");
2443
+ });
2444
+ }
2445
+ const modifiedTables = diff.tables.filter((t) => t.action === "modified");
2446
+ if (modifiedTables.length > 0) {
2447
+ sections.push("-- Modify existing tables");
2448
+ modifiedTables.forEach((t) => {
2449
+ sections.push(generateAlterTable(t, dialect));
2450
+ sections.push("");
2451
+ });
2452
+ }
2453
+ if (dialect !== "sqlite") {
2454
+ sections.push("COMMIT;");
2455
+ }
2456
+ return sections.join("\n");
2457
+ }
2458
+ function SnapshotTimeline({ snapshots, onCompare, onDelete }) {
2459
+ const [selected, setSelected] = React.useState([]);
2460
+ const handleClick = (id) => {
2461
+ setSelected((prev) => {
2462
+ if (prev.includes(id)) {
2463
+ return prev.filter((s) => s !== id);
2464
+ }
2465
+ if (prev.length >= 2) {
2466
+ return [prev[1], id];
2467
+ }
2468
+ return [...prev, id];
2469
+ });
2470
+ };
2471
+ const canCompare = selected.length === 2;
2472
+ React.useEffect(() => {
2473
+ if (canCompare) {
2474
+ onCompare(selected[0], selected[1]);
2475
+ }
2476
+ }, [selected, canCompare, onCompare]);
2477
+ if (snapshots.length === 0) {
2478
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-4 text-zinc-600 text-xs", children: "No snapshots taken yet. Take a snapshot to start tracking schema changes." });
2479
+ }
2480
+ const sorted = [...snapshots].sort(
2481
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
2482
+ );
2483
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2484
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-2", children: [
2485
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 font-medium", children: "Timeline" }),
2486
+ canCompare && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-blue-400", children: "Comparing 2 snapshots" })
2487
+ ] }),
2488
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center overflow-x-auto pb-2 px-2 gap-0", children: [
2489
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-[18px] left-4 right-4 h-[2px] bg-white/10" }),
2490
+ sorted.map((snapshot, idx) => {
2491
+ const isSelected = selected.includes(snapshot.id);
2492
+ const date = new Date(snapshot.createdAt);
2493
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2494
+ "div",
2495
+ {
2496
+ className: "relative flex flex-col items-center min-w-[100px] cursor-pointer group",
2497
+ onClick: () => handleClick(snapshot.id),
2498
+ children: [
2499
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkY52UIFEX_js.cn(
2500
+ "w-3.5 h-3.5 rounded-full border-2 z-10 transition-all",
2501
+ isSelected ? "bg-blue-500 border-blue-400 scale-125" : "bg-[#0d0d0d] border-white/20 hover:border-white/40"
2502
+ ) }),
2503
+ idx < sorted.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-[7px] left-[50%] w-full h-[2px] bg-white/10" }),
2504
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkY52UIFEX_js.cn(
2505
+ "mt-2 text-center transition-colors",
2506
+ isSelected ? "text-blue-400" : "text-zinc-500 group-hover:text-zinc-300"
2507
+ ), children: [
2508
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium truncate max-w-[90px]", children: snapshot.label || snapshot.connectionName }),
2509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[0.625rem] text-zinc-600", children: [
2510
+ date.toLocaleDateString(),
2511
+ " ",
2512
+ date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
2513
+ ] }),
2514
+ /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "secondary", className: "text-[0.625rem] mt-1", children: [
2515
+ snapshot.schema.length,
2516
+ " tables"
2517
+ ] })
2518
+ ] }),
2519
+ /* @__PURE__ */ jsxRuntime.jsx(
2520
+ "button",
2521
+ {
2522
+ onClick: (e) => {
2523
+ e.stopPropagation();
2524
+ onDelete(snapshot.id);
2525
+ },
2526
+ className: "absolute -top-2 -right-1 p-0.5 text-zinc-600 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-opacity",
2527
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { strokeWidth: 1.5, className: "w-2.5 h-2.5" })
2528
+ }
2529
+ )
2530
+ ]
2531
+ },
2532
+ snapshot.id
2533
+ );
2534
+ })
2535
+ ] })
2536
+ ] });
2537
+ }
2538
+ function SchemaDiff({ schema, connection }) {
2539
+ const [snapshots, setSnapshots] = React.useState(
2540
+ () => chunkY52UIFEX_js.storage.getSchemaSnapshots()
2541
+ );
2542
+ const [sourceId, setSourceId] = React.useState("current");
2543
+ const [targetId, setTargetId] = React.useState("");
2544
+ const [selectedTable, setSelectedTable] = React.useState(null);
2545
+ const [showMigration, setShowMigration] = React.useState(false);
2546
+ const [snapshotLabel, setSnapshotLabel] = React.useState("");
2547
+ const [showLabelInput, setShowLabelInput] = React.useState(false);
2548
+ const takeSnapshot = React.useCallback(() => {
2549
+ if (!connection) return;
2550
+ const snapshot = {
2551
+ id: Date.now().toString(),
2552
+ connectionId: connection.id,
2553
+ connectionName: connection.name,
2554
+ databaseType: connection.type,
2555
+ schema: JSON.parse(JSON.stringify(schema)),
2556
+ createdAt: /* @__PURE__ */ new Date(),
2557
+ label: snapshotLabel.trim() || void 0
2558
+ };
2559
+ chunkY52UIFEX_js.storage.saveSchemaSnapshot(snapshot);
2560
+ setSnapshots(chunkY52UIFEX_js.storage.getSchemaSnapshots());
2561
+ setSnapshotLabel("");
2562
+ setShowLabelInput(false);
2563
+ }, [schema, connection, snapshotLabel]);
2564
+ const deleteSnapshot = React.useCallback((id) => {
2565
+ chunkY52UIFEX_js.storage.deleteSchemaSnapshot(id);
2566
+ setSnapshots(chunkY52UIFEX_js.storage.getSchemaSnapshots());
2567
+ if (sourceId === id) setSourceId("current");
2568
+ if (targetId === id) setTargetId("");
2569
+ }, [sourceId, targetId]);
2570
+ const diff = React.useMemo(() => {
2571
+ var _a, _b;
2572
+ if (!targetId) return null;
2573
+ const sourceSchema = sourceId === "current" ? schema : ((_a = snapshots.find((s) => s.id === sourceId)) == null ? void 0 : _a.schema) || [];
2574
+ const targetSchema = targetId === "current" ? schema : ((_b = snapshots.find((s) => s.id === targetId)) == null ? void 0 : _b.schema) || [];
2575
+ if (sourceId === targetId) return null;
2576
+ return diffSchemas(sourceSchema, targetSchema);
2577
+ }, [sourceId, targetId, schema, snapshots]);
2578
+ const migrationSQL = React.useMemo(() => {
2579
+ if (!diff || !diff.hasChanges) return "";
2580
+ const dialect = (connection == null ? void 0 : connection.type) || "postgres";
2581
+ return generateMigrationSQL(diff, dialect);
2582
+ }, [diff, connection]);
2583
+ const { connections: allConnections } = useAllConnections();
2584
+ const [fetchingRemote, setFetchingRemote] = React.useState(false);
2585
+ const fetchRemoteSchema = React.useCallback(async (connId) => {
2586
+ const conn = allConnections.find((c) => c.id === connId);
2587
+ if (!conn) return;
2588
+ setFetchingRemote(true);
2589
+ try {
2590
+ const res = await fetch("/api/db/schema-snapshot", {
2591
+ method: "POST",
2592
+ headers: { "Content-Type": "application/json" },
2593
+ body: JSON.stringify(
2594
+ conn.managed && conn.seedId ? { connectionId: `seed:${conn.seedId}` } : { connection: conn }
2595
+ )
2596
+ });
2597
+ const data = await res.json();
2598
+ if (!res.ok) throw new Error(data.error);
2599
+ const snapshot = {
2600
+ id: `remote-${Date.now()}`,
2601
+ connectionId: conn.id,
2602
+ connectionName: conn.name,
2603
+ databaseType: conn.type,
2604
+ schema: data.schema,
2605
+ createdAt: /* @__PURE__ */ new Date(),
2606
+ label: `Live: ${conn.name}`
2607
+ };
2608
+ chunkY52UIFEX_js.storage.saveSchemaSnapshot(snapshot);
2609
+ setSnapshots(chunkY52UIFEX_js.storage.getSchemaSnapshots());
2610
+ setTargetId(snapshot.id);
2611
+ } catch (err) {
2612
+ console.error("Failed to fetch remote schema:", err);
2613
+ } finally {
2614
+ setFetchingRemote(false);
2615
+ }
2616
+ }, [allConnections]);
2617
+ const getActionBadge = (action) => {
2618
+ switch (action) {
2619
+ case "added":
2620
+ return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { className: "bg-green-500/20 text-green-400 border-green-500/30 text-xs", children: [
2621
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { strokeWidth: 1.5, className: "w-2.5 h-2.5 mr-0.5" }),
2622
+ "Added"
2623
+ ] });
2624
+ case "removed":
2625
+ return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { className: "bg-red-500/20 text-red-400 border-red-500/30 text-xs", children: [
2626
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "w-2.5 h-2.5 mr-0.5" }),
2627
+ "Removed"
2628
+ ] });
2629
+ case "modified":
2630
+ return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { className: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30 text-xs", children: [
2631
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit3, { strokeWidth: 1.5, className: "w-2.5 h-2.5 mr-0.5" }),
2632
+ "Modified"
2633
+ ] });
2634
+ default:
2635
+ return null;
2636
+ }
2637
+ };
2638
+ const formatSnapshotLabel = (s) => {
2639
+ const date = new Date(s.createdAt).toLocaleString();
2640
+ return `${s.label || s.connectionName} (${date})`;
2641
+ };
2642
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
2643
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-white/5 bg-[#0a0a0a] flex-wrap", children: [
2644
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { strokeWidth: 1.5, className: "w-3.5 h-3.5 text-rose-400" }),
2645
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-zinc-400r", children: "Schema Diff" }),
2646
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-px bg-white/10" }),
2647
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2648
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-600", children: "Source" }),
2649
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.Select, { value: sourceId, onValueChange: setSourceId, children: [
2650
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectTrigger, { className: "h-7 w-[180px] text-xs bg-white/5 border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectValue, { placeholder: "Select source" }) }),
2651
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.SelectContent, { className: "bg-[#111] border-white/10", children: [
2652
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectItem, { value: "current", className: "text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2653
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-3 h-3" }),
2654
+ " Current Schema"
2655
+ ] }) }),
2656
+ snapshots.map((s) => /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectItem, { value: s.id, className: "text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2657
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { strokeWidth: 1.5, className: "w-3 h-3" }),
2658
+ " ",
2659
+ formatSnapshotLabel(s)
2660
+ ] }) }, s.id))
2661
+ ] })
2662
+ ] })
2663
+ ] }),
2664
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-600 text-xs", children: "vs" }),
2665
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2666
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-600", children: "Target" }),
2667
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.Select, { value: targetId, onValueChange: (v) => {
2668
+ if (v.startsWith("conn:")) {
2669
+ fetchRemoteSchema(v.replace("conn:", ""));
2670
+ } else {
2671
+ setTargetId(v);
2672
+ }
2673
+ }, children: [
2674
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectTrigger, { className: "h-7 w-[180px] text-xs bg-white/5 border-white/10", children: /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectValue, { placeholder: "Select target" }) }),
2675
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.SelectContent, { className: "bg-[#111] border-white/10", children: [
2676
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectItem, { value: "current", className: "text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2677
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-3 h-3" }),
2678
+ " Current Schema"
2679
+ ] }) }),
2680
+ snapshots.map((s) => /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectItem, { value: s.id, className: "text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2681
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { strokeWidth: 1.5, className: "w-3 h-3" }),
2682
+ " ",
2683
+ formatSnapshotLabel(s)
2684
+ ] }) }, s.id)),
2685
+ allConnections.filter((c) => c.id !== (connection == null ? void 0 : connection.id)).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2686
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1 text-[0.625rem] text-zinc-600 border-t border-white/5 mt-1", children: "Fetch from connection" }),
2687
+ allConnections.filter((c) => c.id !== (connection == null ? void 0 : connection.id)).map((c) => /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SelectItem, { value: `conn:${c.id}`, className: "text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2688
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-3 h-3 text-blue-400" }),
2689
+ " ",
2690
+ c.name,
2691
+ c.environment === "production" && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { strokeWidth: 1.5, className: "w-3 h-3 text-red-400" })
2692
+ ] }) }, `conn:${c.id}`))
2693
+ ] })
2694
+ ] })
2695
+ ] }),
2696
+ fetchingRemote && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500 animate-pulse", children: "Fetching..." })
2697
+ ] }),
2698
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
2699
+ showLabelInput ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2700
+ /* @__PURE__ */ jsxRuntime.jsx(
2701
+ "input",
2702
+ {
2703
+ type: "text",
2704
+ placeholder: "Label (optional)...",
2705
+ value: snapshotLabel,
2706
+ onChange: (e) => setSnapshotLabel(e.target.value),
2707
+ onKeyDown: (e) => e.key === "Enter" && takeSnapshot(),
2708
+ className: "h-7 px-2 text-xs bg-white/5 border border-white/10 rounded text-zinc-300 focus:outline-none focus:border-blue-500 w-32",
2709
+ autoFocus: true
2710
+ }
2711
+ ),
2712
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Button, { variant: "ghost", size: "sm", className: "h-7 text-xs text-blue-400", onClick: takeSnapshot, children: "Save" }),
2713
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.Button, { variant: "ghost", size: "sm", className: "h-7 text-xs text-zinc-500", onClick: () => setShowLabelInput(false), children: "Cancel" })
2714
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(
2715
+ chunkY52UIFEX_js.Button,
2716
+ {
2717
+ variant: "ghost",
2718
+ size: "sm",
2719
+ className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-1",
2720
+ onClick: () => setShowLabelInput(true),
2721
+ disabled: !connection,
2722
+ children: [
2723
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: "w-3 h-3" }),
2724
+ " Snapshot"
2725
+ ]
2726
+ }
2727
+ ),
2728
+ (diff == null ? void 0 : diff.hasChanges) && /* @__PURE__ */ jsxRuntime.jsxs(
2729
+ chunkY52UIFEX_js.Button,
2730
+ {
2731
+ variant: "ghost",
2732
+ size: "sm",
2733
+ className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-1",
2734
+ onClick: () => setShowMigration(!showMigration),
2735
+ children: [
2736
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileCode, { className: "w-3 h-3" }),
2737
+ " ",
2738
+ showMigration ? "Diff View" : "SQL Migration"
2739
+ ]
2740
+ }
2741
+ )
2742
+ ] }),
2743
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden flex", children: !targetId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-zinc-600 gap-3", children: [
2744
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { strokeWidth: 1.5, className: "w-10 h-10 opacity-30" }),
2745
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "Select source and target to compare schemas" }),
2746
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-700", children: "Take a snapshot first, then compare with the current schema" }),
2747
+ snapshots.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 w-full max-w-2xl px-4", children: /* @__PURE__ */ jsxRuntime.jsx(
2748
+ SnapshotTimeline,
2749
+ {
2750
+ snapshots,
2751
+ onCompare: (sourceId2, targetId2) => {
2752
+ setSourceId(sourceId2);
2753
+ setTargetId(targetId2);
2754
+ },
2755
+ onDelete: deleteSnapshot
2756
+ }
2757
+ ) })
2758
+ ] }) : showMigration && migrationSQL ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs font-mono text-zinc-300 bg-[#0d0d0d] border border-white/10 rounded-lg p-4 overflow-auto whitespace-pre-wrap", children: migrationSQL }) }) : diff && diff.hasChanges ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2759
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-64 border-r border-white/5 overflow-auto", children: [
2760
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b border-white/5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-zinc-500 px-2 mb-1", children: [
2761
+ diff.summary.added,
2762
+ " added, ",
2763
+ diff.summary.removed,
2764
+ " removed, ",
2765
+ diff.summary.modified,
2766
+ " modified"
2767
+ ] }) }),
2768
+ diff.tables.map((table) => /* @__PURE__ */ jsxRuntime.jsxs(
2769
+ "button",
2770
+ {
2771
+ onClick: () => setSelectedTable(table.tableName),
2772
+ className: chunkY52UIFEX_js.cn(
2773
+ "w-full text-left px-3 py-2 text-xs flex items-center gap-2 hover:bg-white/5 transition-colors",
2774
+ selectedTable === table.tableName && "bg-white/10"
2775
+ ),
2776
+ children: [
2777
+ selectedTable === table.tableName ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { strokeWidth: 1.5, className: "w-3 h-3 text-zinc-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { strokeWidth: 1.5, className: "w-3 h-3 text-zinc-500" }),
2778
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-300", children: table.tableName }),
2779
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto", children: getActionBadge(table.action) })
2780
+ ]
2781
+ },
2782
+ table.tableName
2783
+ ))
2784
+ ] }),
2785
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto p-4", children: selectedTable ? /* @__PURE__ */ jsxRuntime.jsx(TableDiffDetail, { diff: diff.tables.find((t) => t.tableName === selectedTable) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full flex items-center justify-center text-zinc-600 text-xs", children: "Select a table to view diff details" }) })
2786
+ ] }) : diff && !diff.hasChanges ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-zinc-600 gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "No differences found between source and target" }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex items-center justify-center text-zinc-600 gap-2", children: [
2787
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { strokeWidth: 1.5, className: "w-3.5 h-3.5" }),
2788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "Cannot compare same schema with itself" })
2789
+ ] }) })
2790
+ ] });
2791
+ }
2792
+ function TableDiffDetail({ diff }) {
2793
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2794
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2795
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-3.5 h-3.5 text-zinc-400" }),
2796
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-medium text-zinc-200", children: diff.tableName }),
2797
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: chunkY52UIFEX_js.cn(
2798
+ "text-xs",
2799
+ diff.action === "added" && "bg-green-500/20 text-green-400",
2800
+ diff.action === "removed" && "bg-red-500/20 text-red-400",
2801
+ diff.action === "modified" && "bg-yellow-500/20 text-yellow-400"
2802
+ ), children: diff.action })
2803
+ ] }),
2804
+ diff.columns.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2805
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs text-zinc-500 mb-2 font-medium", children: "Columns" }),
2806
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: diff.columns.map((col, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkY52UIFEX_js.cn(
2807
+ "px-3 py-2 rounded text-xs flex items-center gap-2",
2808
+ col.action === "added" && "bg-green-500/5 border border-green-500/10",
2809
+ col.action === "removed" && "bg-red-500/5 border border-red-500/10",
2810
+ col.action === "modified" && "bg-yellow-500/5 border border-yellow-500/10"
2811
+ ), children: [
2812
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-zinc-300 min-w-[120px]", children: col.columnName }),
2813
+ col.action === "modified" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-0.5", children: col.changes.map((change, j) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500", children: change }, j)) }),
2814
+ col.action === "added" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-green-400 font-mono", children: col.targetType }),
2815
+ col.action === "removed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-red-400 font-mono", children: col.sourceType }),
2816
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto", children: getActionIcon(col.action) })
2817
+ ] }, i)) })
2818
+ ] }),
2819
+ diff.indexes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2820
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs text-zinc-500 mb-2 font-medium", children: "Indexes" }),
2821
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: diff.indexes.map((idx, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkY52UIFEX_js.cn(
2822
+ "px-3 py-2 rounded text-xs flex items-center gap-2",
2823
+ idx.action === "added" && "bg-green-500/5 border border-green-500/10",
2824
+ idx.action === "removed" && "bg-red-500/5 border border-red-500/10",
2825
+ idx.action === "modified" && "bg-yellow-500/5 border border-yellow-500/10"
2826
+ ), children: [
2827
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-zinc-300", children: idx.indexName }),
2828
+ idx.changes.map((change, j) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500", children: change }, j)),
2829
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto", children: getActionIcon(idx.action) })
2830
+ ] }, i)) })
2831
+ ] }),
2832
+ diff.foreignKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2833
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs text-zinc-500 mb-2 font-medium", children: "Foreign Keys" }),
2834
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: diff.foreignKeys.map((fk, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkY52UIFEX_js.cn(
2835
+ "px-3 py-2 rounded text-xs flex items-center gap-2",
2836
+ fk.action === "added" && "bg-green-500/5 border border-green-500/10",
2837
+ fk.action === "removed" && "bg-red-500/5 border border-red-500/10"
2838
+ ), children: [
2839
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-zinc-300", children: fk.columnName }),
2840
+ fk.changes.map((change, j) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-500", children: change }, j)),
2841
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto", children: getActionIcon(fk.action) })
2842
+ ] }, i)) })
2843
+ ] })
2844
+ ] });
2845
+ }
2846
+ function getActionIcon(action) {
2847
+ switch (action) {
2848
+ case "added":
2849
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { strokeWidth: 1.5, className: "w-3 h-3 text-green-400" });
2850
+ case "removed":
2851
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "w-3 h-3 text-red-400" });
2852
+ case "modified":
2853
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit3, { strokeWidth: 1.5, className: "w-3 h-3 text-yellow-400" });
2854
+ default:
2855
+ return null;
2856
+ }
2857
+ }
2858
+ function ChartDashboardLazy({ result }) {
2859
+ const [savedCharts, setSavedCharts] = React__default.default.useState([]);
2860
+ React__default.default.useEffect(() => {
2861
+ const charts = chunkY52UIFEX_js.storage.getSavedCharts();
2862
+ if (charts.length > 0) setSavedCharts(charts);
2863
+ }, []);
2864
+ if (savedCharts.length === 0) {
2865
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center bg-[#080808] text-zinc-500 gap-2", children: [
2866
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutDashboard, { strokeWidth: 1.5, className: "w-10 h-10 opacity-30" }),
2867
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "No saved charts yet" }),
2868
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-600", children: "Save charts from the Charts tab to display them here" })
2869
+ ] });
2870
+ }
2871
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full overflow-auto bg-[#080808] p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: savedCharts.map((chart) => {
2872
+ var _a;
2873
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-[#0d0d0d] border border-white/10 rounded-lg p-3", children: [
2874
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
2875
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-zinc-300", children: chart.name }),
2876
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-zinc-600", children: chart.chartType })
2877
+ ] }),
2878
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-zinc-500", children: [
2879
+ chart.xAxis && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2880
+ "X: ",
2881
+ chart.xAxis
2882
+ ] }),
2883
+ ((_a = chart.yAxis) == null ? void 0 : _a.length) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2", children: [
2884
+ "Y: ",
2885
+ chart.yAxis.join(", ")
2886
+ ] })
2887
+ ] }),
2888
+ result ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DataCharts, { result }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 h-[100px] flex items-center justify-center text-zinc-600 text-xs", children: "Execute a query to see chart" })
2889
+ ] }, chart.id);
2890
+ }) }) });
2891
+ }
2892
+ function BottomPanel({
2893
+ mode,
2894
+ onSetMode,
2895
+ currentTab,
2896
+ schema,
2897
+ schemaContext,
2898
+ activeConnection,
2899
+ metadata,
2900
+ historyKey,
2901
+ savedKey,
2902
+ isNL2SQLOpen,
2903
+ onSetIsNL2SQLOpen,
2904
+ maskingEnabled,
2905
+ onToggleMasking,
2906
+ userRole,
2907
+ maskingConfig,
2908
+ editingEnabled,
2909
+ pendingChanges,
2910
+ onCellChange,
2911
+ onApplyChanges,
2912
+ onDiscardChanges,
2913
+ onExecuteQuery,
2914
+ onLoadQuery,
2915
+ onLoadMore,
2916
+ isLoadingMore,
2917
+ onExportResults
2918
+ }) {
2919
+ const tabs = [
2920
+ { key: "results", label: "Results", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-blue-400 border-blue-500 bg-white/5" },
2921
+ { key: "explain", label: "Explain", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-amber-400 border-amber-500 bg-white/5" },
2922
+ { key: "history", label: "History", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-emerald-400 border-emerald-500 bg-white/5" },
2923
+ { key: "saved", label: "Saved", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bookmark, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-purple-400 border-purple-500 bg-white/5" },
2924
+ { key: "charts", label: "Charts", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BarChart3, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-cyan-400 border-cyan-500 bg-white/5" },
2925
+ { key: "nl2sql", label: "NL2SQL", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-violet-400 border-violet-500 bg-white/5" },
2926
+ { key: "autopilot", label: "Autopilot", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-cyan-400 border-cyan-500 bg-white/5" },
2927
+ { key: "pivot", label: "Pivot", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Columns3, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-orange-400 border-orange-500 bg-white/5" },
2928
+ { key: "docs", label: "Docs", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-teal-400 border-teal-500 bg-white/5" },
2929
+ { key: "schemadiff", label: "Diff", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitCompare, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-rose-400 border-rose-500 bg-white/5" },
2930
+ { key: "dashboard", label: "Dashboard", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutDashboard, { strokeWidth: 1.5, className: "w-3 h-3" }), activeClass: "text-indigo-400 border-indigo-500 bg-white/5" }
2931
+ ];
2932
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col bg-[#080808]", children: [
2933
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-9 bg-[#0a0a0a] border-b border-white/5 flex items-center justify-between px-2", children: [
2934
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center h-full gap-1", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
2935
+ "button",
2936
+ {
2937
+ onClick: () => {
2938
+ onSetMode(tab.key);
2939
+ if (tab.key === "nl2sql") onSetIsNL2SQLOpen(true);
2940
+ },
2941
+ className: chunkY52UIFEX_js.cn(
2942
+ "h-full px-3 text-xs font-medium transition-all border-b-2 flex items-center gap-2",
2943
+ mode === tab.key ? tab.activeClass : "text-zinc-500 border-transparent hover:text-zinc-300"
2944
+ ),
2945
+ children: [
2946
+ tab.icon,
2947
+ " ",
2948
+ tab.label
2949
+ ]
2950
+ },
2951
+ tab.key
2952
+ )) }),
2953
+ currentTab.result && mode === "results" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2954
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-mono text-zinc-500 mr-2", children: [
2955
+ currentTab.result.rowCount,
2956
+ " rows \u2022 ",
2957
+ currentTab.result.executionTime,
2958
+ "ms"
2959
+ ] }),
2960
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DropdownMenu, { children: [
2961
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.Button, { variant: "ghost", size: "sm", className: "h-7 text-xs font-medium text-zinc-500 hover:text-white gap-2", children: [
2962
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { strokeWidth: 1.5, className: "w-3 h-3" }),
2963
+ " Export"
2964
+ ] }) }),
2965
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkY52UIFEX_js.DropdownMenuContent, { align: "end", className: "bg-[#0d0d0d] border-white/10 text-zinc-300", children: [
2966
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => onExportResults("csv"), className: "text-xs cursor-pointer", children: "Export as CSV" }),
2967
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => onExportResults("json"), className: "text-xs cursor-pointer", children: "Export as JSON" }),
2968
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => onExportResults("sql-insert"), className: "text-xs cursor-pointer", children: "Export as SQL INSERT" }),
2969
+ /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DropdownMenuItem, { onClick: () => onExportResults("sql-ddl"), className: "text-xs cursor-pointer", children: "Export as DDL (CREATE TABLE)" })
2970
+ ] })
2971
+ ] })
2972
+ ] })
2973
+ ] }),
2974
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden relative", children: mode === "nl2sql" ? /* @__PURE__ */ jsxRuntime.jsx(
2975
+ chunkY52UIFEX_js.NL2SQLPanel,
2976
+ {
2977
+ isOpen: isNL2SQLOpen,
2978
+ onClose: () => {
2979
+ onSetIsNL2SQLOpen(false);
2980
+ onSetMode("results");
2981
+ },
2982
+ onExecuteQuery,
2983
+ onLoadQuery: (q) => {
2984
+ onLoadQuery(q);
2985
+ onSetMode("results");
2986
+ },
2987
+ schemaContext,
2988
+ databaseType: activeConnection == null ? void 0 : activeConnection.type,
2989
+ queryLanguage: metadata == null ? void 0 : metadata.capabilities.queryLanguage
2990
+ }
2991
+ ) : mode === "autopilot" ? /* @__PURE__ */ jsxRuntime.jsx(
2992
+ AIAutopilotPanel,
2993
+ {
2994
+ connection: activeConnection,
2995
+ schemaContext,
2996
+ onExecuteQuery
2997
+ }
2998
+ ) : mode === "pivot" ? /* @__PURE__ */ jsxRuntime.jsx(
2999
+ PivotTable,
3000
+ {
3001
+ result: currentTab.result,
3002
+ onLoadQuery: (q) => {
3003
+ onLoadQuery(q);
3004
+ onSetMode("results");
3005
+ }
3006
+ }
3007
+ ) : mode === "docs" ? /* @__PURE__ */ jsxRuntime.jsx(
3008
+ DatabaseDocs,
3009
+ {
3010
+ schema,
3011
+ schemaContext,
3012
+ databaseType: activeConnection == null ? void 0 : activeConnection.type
3013
+ }
3014
+ ) : mode === "history" ? /* @__PURE__ */ jsxRuntime.jsx(
3015
+ QueryHistory,
3016
+ {
3017
+ refreshTrigger: historyKey,
3018
+ activeConnectionId: activeConnection == null ? void 0 : activeConnection.id,
3019
+ onSelectQuery: (q) => {
3020
+ onLoadQuery(q);
3021
+ onSetMode("results");
3022
+ }
3023
+ }
3024
+ ) : mode === "saved" ? /* @__PURE__ */ jsxRuntime.jsx(
3025
+ SavedQueries,
3026
+ {
3027
+ refreshTrigger: savedKey,
3028
+ connectionType: activeConnection == null ? void 0 : activeConnection.type,
3029
+ onSelectQuery: (q) => {
3030
+ onLoadQuery(q);
3031
+ onSetMode("results");
3032
+ }
3033
+ }
3034
+ ) : mode === "charts" ? /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.DataCharts, { result: currentTab.result }) : mode === "schemadiff" ? /* @__PURE__ */ jsxRuntime.jsx(SchemaDiff, { schema, connection: activeConnection }) : mode === "dashboard" ? /* @__PURE__ */ jsxRuntime.jsx(ChartDashboardLazy, { result: currentTab.result }) : currentTab.result ? mode === "explain" ? /* @__PURE__ */ jsxRuntime.jsx(
3035
+ chunkY52UIFEX_js.VisualExplain,
3036
+ {
3037
+ plan: currentTab.explainPlan,
3038
+ query: currentTab.query,
3039
+ schemaContext,
3040
+ databaseType: activeConnection == null ? void 0 : activeConnection.type,
3041
+ onLoadQuery: (q) => {
3042
+ onLoadQuery(q);
3043
+ onSetMode("results");
3044
+ }
3045
+ }
3046
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3047
+ chunkY52UIFEX_js.ResultsGrid,
3048
+ {
3049
+ result: currentTab.result,
3050
+ onLoadMore,
3051
+ isLoadingMore,
3052
+ maskingEnabled,
3053
+ onToggleMasking,
3054
+ userRole,
3055
+ maskingConfig,
3056
+ editingEnabled,
3057
+ pendingChanges,
3058
+ onCellChange,
3059
+ onApplyChanges,
3060
+ onDiscardChanges
3061
+ }
3062
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col items-center justify-center opacity-20 bg-[#0a0a0a]", children: [
3063
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Terminal, { strokeWidth: 1.5, className: "w-12 h-12 mb-4" }),
3064
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium", children: "Execute a query or check history" }),
3065
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-2", children: "Ready to query" })
3066
+ ] }) })
3067
+ ] });
3068
+ }
3069
+ function useToast() {
3070
+ const toast = React.useCallback(({ title, description, variant }) => {
3071
+ if (variant === "destructive") {
3072
+ sonner.toast.error(title, { description });
3073
+ } else {
3074
+ sonner.toast.success(title, { description });
3075
+ }
3076
+ }, []);
3077
+ return { toast };
3078
+ }
3079
+
3080
+ // src/hooks/use-tab-manager.ts
3081
+ var DEFAULT_TAB = {
3082
+ id: "default",
3083
+ name: "Query 1",
3084
+ query: "",
3085
+ result: null,
3086
+ isExecuting: false,
3087
+ type: "sql"
3088
+ };
3089
+ var WORKSPACE_STORAGE_PREFIX = "libredb_workspace_tabs_v1";
3090
+ function useTabManager({
3091
+ activeConnection,
3092
+ metadata,
3093
+ schema,
3094
+ persistWorkspace
3095
+ }) {
3096
+ const [tabs, setTabs] = React.useState([DEFAULT_TAB]);
3097
+ const [activeTabId, setActiveTabId] = React.useState("default");
3098
+ const [editingTabId, setEditingTabId] = React.useState(null);
3099
+ const [editingTabName, setEditingTabName] = React.useState("");
3100
+ const [isWorkspaceHydrated, setIsWorkspaceHydrated] = React.useState(false);
3101
+ const workspaceKey = React.useMemo(
3102
+ () => {
3103
+ var _a;
3104
+ return `${WORKSPACE_STORAGE_PREFIX}:${(_a = activeConnection == null ? void 0 : activeConnection.id) != null ? _a : "default"}`;
3105
+ },
3106
+ [activeConnection == null ? void 0 : activeConnection.id]
3107
+ );
3108
+ const shouldPersistWorkspace = persistWorkspace != null ? persistWorkspace : process.env.NODE_ENV !== "test";
3109
+ const currentTab = tabs.find((t) => t.id === activeTabId) || tabs[0];
3110
+ React.useEffect(() => {
3111
+ setIsWorkspaceHydrated(false);
3112
+ if (!shouldPersistWorkspace) return;
3113
+ const storage2 = typeof globalThis !== "undefined" && "localStorage" in globalThis ? globalThis.localStorage : null;
3114
+ if (!storage2) return;
3115
+ try {
3116
+ const raw = storage2.getItem(workspaceKey);
3117
+ if (!raw) {
3118
+ setTabs([DEFAULT_TAB]);
3119
+ setActiveTabId(DEFAULT_TAB.id);
3120
+ return;
3121
+ }
3122
+ const parsed = JSON.parse(raw);
3123
+ if (!parsed || !Array.isArray(parsed.tabs) || parsed.tabs.length === 0) {
3124
+ setTabs([DEFAULT_TAB]);
3125
+ setActiveTabId(DEFAULT_TAB.id);
3126
+ return;
3127
+ }
3128
+ const restoredTabs = parsed.tabs.map((tab) => ({
3129
+ id: tab.id,
3130
+ name: tab.name,
3131
+ query: tab.query,
3132
+ type: tab.type,
3133
+ result: null,
3134
+ isExecuting: false
3135
+ }));
3136
+ const hasActiveTab = restoredTabs.some((tab) => tab.id === parsed.activeTabId);
3137
+ setTabs(restoredTabs);
3138
+ setActiveTabId(hasActiveTab ? parsed.activeTabId : restoredTabs[0].id);
3139
+ } catch (error) {
3140
+ console.error("[useTabManager] Failed to restore workspace tabs:", error);
3141
+ setTabs([DEFAULT_TAB]);
3142
+ setActiveTabId(DEFAULT_TAB.id);
3143
+ }
3144
+ }, [workspaceKey, shouldPersistWorkspace]);
3145
+ React.useEffect(() => {
3146
+ if (!shouldPersistWorkspace || isWorkspaceHydrated) return;
3147
+ setIsWorkspaceHydrated(true);
3148
+ }, [tabs, activeTabId, shouldPersistWorkspace, isWorkspaceHydrated]);
3149
+ React.useEffect(() => {
3150
+ if (!shouldPersistWorkspace) return;
3151
+ const storage2 = typeof globalThis !== "undefined" && "localStorage" in globalThis ? globalThis.localStorage : null;
3152
+ if (!isWorkspaceHydrated || !storage2) return;
3153
+ const timer = setTimeout(() => {
3154
+ const serialized = {
3155
+ activeTabId,
3156
+ tabs: tabs.map((tab) => ({
3157
+ id: tab.id,
3158
+ name: tab.name,
3159
+ query: tab.query,
3160
+ type: tab.type
3161
+ }))
3162
+ };
3163
+ storage2.setItem(workspaceKey, JSON.stringify(serialized));
3164
+ }, 500);
3165
+ return () => clearTimeout(timer);
3166
+ }, [tabs, activeTabId, workspaceKey, shouldPersistWorkspace, isWorkspaceHydrated]);
3167
+ const updateTabById = React.useCallback((tabId, updates) => {
3168
+ setTabs((prev) => prev.map((t) => t.id === tabId ? chunkQ6LRDBK7_js.__spreadValues(chunkQ6LRDBK7_js.__spreadValues({}, t), updates) : t));
3169
+ }, []);
3170
+ const updateCurrentTab = React.useCallback((updates) => {
3171
+ updateTabById(activeTabId, updates);
3172
+ }, [activeTabId, updateTabById]);
3173
+ const addTab = React.useCallback(() => {
3174
+ const newId = Math.random().toString(36).substring(7);
3175
+ setTabs((prev) => [...prev, {
3176
+ id: newId,
3177
+ name: `Query ${prev.length + 1}`,
3178
+ query: "",
3179
+ result: null,
3180
+ isExecuting: false,
3181
+ type: "sql"
3182
+ }]);
3183
+ setActiveTabId(newId);
3184
+ }, [activeConnection, metadata]);
3185
+ const closeTab = React.useCallback((id, e) => {
3186
+ e.stopPropagation();
3187
+ setTabs((prev) => {
3188
+ if (prev.length === 1) return prev;
3189
+ const newTabs = prev.filter((t) => t.id !== id);
3190
+ if (activeTabId === id && newTabs.length > 0) {
3191
+ setActiveTabId(newTabs[newTabs.length - 1].id);
3192
+ }
3193
+ return newTabs;
3194
+ });
3195
+ }, [activeTabId]);
3196
+ const handleTableClick = React.useCallback((tableName, executeQueryFn) => {
3197
+ const newQuery = `SELECT * FROM ${tableName} LIMIT 50;`;
3198
+ const newId = Math.random().toString(36).substring(7);
3199
+ const newTab = {
3200
+ id: newId,
3201
+ name: tableName,
3202
+ query: newQuery,
3203
+ result: null,
3204
+ isExecuting: false,
3205
+ type: "sql"
3206
+ };
3207
+ setTabs((prev) => [...prev, newTab]);
3208
+ setActiveTabId(newId);
3209
+ setTimeout(() => executeQueryFn(newQuery, newId), 100);
3210
+ }, [metadata]);
3211
+ const handleGenerateSelect = React.useCallback((tableName) => {
3212
+ const table = schema.find((t) => t.name === tableName);
3213
+ const columns = (table == null ? void 0 : table.columns) || [];
3214
+ const newQuery = `SELECT
3215
+ ${columns.map((c) => ` ${c.name}`).join(",\n") || " *"}
3216
+ FROM ${tableName}
3217
+ WHERE 1=1
3218
+ LIMIT 100;`;
3219
+ const tabType = "sql";
3220
+ const newId = Math.random().toString(36).substring(7);
3221
+ setTabs((prev) => [...prev, {
3222
+ id: newId,
3223
+ name: `Query: ${tableName}`,
3224
+ query: newQuery,
3225
+ result: null,
3226
+ isExecuting: false,
3227
+ type: tabType
3228
+ }]);
3229
+ setActiveTabId(newId);
3230
+ }, [metadata, schema]);
3231
+ return {
3232
+ tabs,
3233
+ setTabs,
3234
+ activeTabId,
3235
+ setActiveTabId,
3236
+ currentTab,
3237
+ editingTabId,
3238
+ setEditingTabId,
3239
+ editingTabName,
3240
+ setEditingTabName,
3241
+ addTab,
3242
+ closeTab,
3243
+ updateCurrentTab,
3244
+ updateTabById,
3245
+ handleTableClick,
3246
+ handleGenerateSelect
3247
+ };
3248
+ }
3249
+ function useConnectionAdapter({
3250
+ connections: externalConnections,
3251
+ onSchemaFetch
3252
+ }) {
3253
+ var _a;
3254
+ const connections = React.useMemo(
3255
+ () => externalConnections.map((c) => ({
3256
+ id: c.id,
3257
+ name: c.name,
3258
+ type: c.type,
3259
+ createdAt: /* @__PURE__ */ new Date(),
3260
+ managed: true
3261
+ })),
3262
+ [externalConnections]
3263
+ );
3264
+ const [activeConnection, setActiveConnection] = React.useState(
3265
+ (_a = connections[0]) != null ? _a : null
3266
+ );
3267
+ const [schema, setSchema] = React.useState([]);
3268
+ const [isLoadingSchema, setIsLoadingSchema] = React.useState(false);
3269
+ React.useEffect(() => {
3270
+ if (connections.length === 0) {
3271
+ setActiveConnection(null);
3272
+ return;
3273
+ }
3274
+ if (activeConnection && connections.some((c) => c.id === activeConnection.id)) {
3275
+ return;
3276
+ }
3277
+ setActiveConnection(connections[0]);
3278
+ }, [connections]);
3279
+ const fetchSchema = React.useCallback(
3280
+ async (conn) => {
3281
+ setIsLoadingSchema(true);
3282
+ try {
3283
+ const result = await onSchemaFetch(conn.id);
3284
+ setSchema(result);
3285
+ } catch (e) {
3286
+ setSchema([]);
3287
+ } finally {
3288
+ setIsLoadingSchema(false);
3289
+ }
3290
+ },
3291
+ [onSchemaFetch]
3292
+ );
3293
+ const tableNames = React.useMemo(() => schema.map((s) => s.name), [schema]);
3294
+ const schemaContext = React.useMemo(() => JSON.stringify(schema), [schema]);
3295
+ return {
3296
+ connections,
3297
+ setConnections: (() => {
3298
+ }),
3299
+ activeConnection,
3300
+ setActiveConnection,
3301
+ schema,
3302
+ setSchema,
3303
+ isLoadingSchema,
3304
+ connectionPulse: null,
3305
+ fetchSchema,
3306
+ tableNames,
3307
+ schemaContext
3308
+ };
3309
+ }
3310
+ function useQueryAdapter({
3311
+ activeConnection,
3312
+ onQueryExecute,
3313
+ tabs,
3314
+ activeTabId,
3315
+ currentTab,
3316
+ setTabs,
3317
+ fetchSchema: _fetchSchema,
3318
+ features: _features
3319
+ }) {
3320
+ const cancelledRef = React.useRef(false);
3321
+ const [safetyCheckQuery, setSafetyCheckQuery] = React.useState(null);
3322
+ const [unlimitedWarningOpen, setUnlimitedWarningOpen] = React.useState(false);
3323
+ const [pendingUnlimitedQuery, setPendingUnlimitedQuery] = React.useState(null);
3324
+ const [historyKey, setHistoryKey] = React.useState(0);
3325
+ const [bottomPanelMode, setBottomPanelMode] = React.useState("results");
3326
+ const { toast } = useToast();
3327
+ const executeQuery = React.useCallback(async (overrideQuery, tabId, _isExplain = false) => {
3328
+ const targetTabId = tabId || activeTabId;
3329
+ const tabToExec = tabs.find((t) => t.id === targetTabId) || currentTab;
3330
+ const queryToExecute = overrideQuery || tabToExec.query;
3331
+ if (!activeConnection) {
3332
+ toast({ title: "No Connection", description: "Select a connection first.", variant: "destructive" });
3333
+ return;
3334
+ }
3335
+ if (!queryToExecute || queryToExecute.trim() === "") {
3336
+ toast({ title: "Empty Query", description: "Enter a query to execute.", variant: "destructive" });
3337
+ return;
3338
+ }
3339
+ if (chunkY52UIFEX_js.isDangerousQuery(queryToExecute)) {
3340
+ setSafetyCheckQuery(queryToExecute);
3341
+ return;
3342
+ }
3343
+ cancelledRef.current = false;
3344
+ setTabs((prev) => prev.map((t) => t.id === targetTabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3345
+ isExecuting: true
3346
+ }) : t));
3347
+ setBottomPanelMode("results");
3348
+ const startTime = Date.now();
3349
+ try {
3350
+ const result = await onQueryExecute(activeConnection.id, queryToExecute);
3351
+ if (cancelledRef.current) return;
3352
+ const executionTime = result.executionTime || Date.now() - startTime;
3353
+ setTabs((prev) => prev.map((t) => {
3354
+ if (t.id !== targetTabId) return t;
3355
+ return chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3356
+ result: {
3357
+ rows: result.rows,
3358
+ fields: result.fields,
3359
+ rowCount: result.rowCount,
3360
+ executionTime,
3361
+ pagination: result.pagination
3362
+ },
3363
+ allRows: result.rows,
3364
+ currentOffset: result.rows.length,
3365
+ isExecuting: false,
3366
+ isLoadingMore: false
3367
+ });
3368
+ }));
3369
+ setHistoryKey((prev) => prev + 1);
3370
+ } catch (error) {
3371
+ if (cancelledRef.current) return;
3372
+ setTabs((prev) => prev.map((t) => t.id === targetTabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3373
+ isExecuting: false,
3374
+ isLoadingMore: false
3375
+ }) : t));
3376
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3377
+ toast({ title: "Query Error", description: errorMessage, variant: "destructive" });
3378
+ }
3379
+ }, [activeConnection, tabs, currentTab, activeTabId, toast, onQueryExecute, setTabs]);
3380
+ const forceExecuteQuery = React.useCallback((query) => {
3381
+ setSafetyCheckQuery(null);
3382
+ if (!activeConnection) {
3383
+ toast({ title: "No Connection", description: "Select a connection first.", variant: "destructive" });
3384
+ return;
3385
+ }
3386
+ if (!query || query.trim() === "") {
3387
+ toast({ title: "Empty Query", description: "Enter a query to execute.", variant: "destructive" });
3388
+ return;
3389
+ }
3390
+ cancelledRef.current = false;
3391
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3392
+ isExecuting: true
3393
+ }) : t));
3394
+ setBottomPanelMode("results");
3395
+ const startTime = Date.now();
3396
+ onQueryExecute(activeConnection.id, query).then((result) => {
3397
+ if (cancelledRef.current) return;
3398
+ const executionTime = result.executionTime || Date.now() - startTime;
3399
+ setTabs((prev) => prev.map((t) => {
3400
+ if (t.id !== activeTabId) return t;
3401
+ return chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3402
+ result: {
3403
+ rows: result.rows,
3404
+ fields: result.fields,
3405
+ rowCount: result.rowCount,
3406
+ executionTime,
3407
+ pagination: result.pagination
3408
+ },
3409
+ allRows: result.rows,
3410
+ currentOffset: result.rows.length,
3411
+ isExecuting: false,
3412
+ isLoadingMore: false
3413
+ });
3414
+ }));
3415
+ setHistoryKey((prev) => prev + 1);
3416
+ }).catch((error) => {
3417
+ if (cancelledRef.current) return;
3418
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3419
+ isExecuting: false,
3420
+ isLoadingMore: false
3421
+ }) : t));
3422
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3423
+ toast({ title: "Query Error", description: errorMessage, variant: "destructive" });
3424
+ });
3425
+ }, [activeConnection, activeTabId, toast, onQueryExecute, setTabs]);
3426
+ const cancelQuery = React.useCallback(() => {
3427
+ cancelledRef.current = true;
3428
+ setTabs((prev) => prev.map((t) => t.isExecuting ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3429
+ isExecuting: false,
3430
+ isLoadingMore: false
3431
+ }) : t));
3432
+ toast({ title: "Query Cancelled", description: "Query execution was cancelled." });
3433
+ }, [setTabs, toast]);
3434
+ const handleLoadMore = React.useCallback(() => {
3435
+ var _a, _b;
3436
+ if (!((_b = (_a = currentTab.result) == null ? void 0 : _a.pagination) == null ? void 0 : _b.hasMore)) return;
3437
+ if (!activeConnection) return;
3438
+ const currentOffset = currentTab.currentOffset || currentTab.result.rows.length;
3439
+ setTabs((prev) => prev.map((t) => t.id === currentTab.id ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3440
+ isLoadingMore: true
3441
+ }) : t));
3442
+ onQueryExecute(activeConnection.id, currentTab.query, {
3443
+ limit: 500,
3444
+ offset: currentOffset
3445
+ }).then((result) => {
3446
+ if (cancelledRef.current) return;
3447
+ setTabs((prev) => prev.map((t) => {
3448
+ var _a2, _b2;
3449
+ if (t.id !== currentTab.id) return t;
3450
+ const existingRows = t.allRows || ((_a2 = t.result) == null ? void 0 : _a2.rows) || [];
3451
+ const newAllRows = [...existingRows, ...result.rows];
3452
+ return chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3453
+ result: {
3454
+ rows: newAllRows,
3455
+ fields: result.fields,
3456
+ rowCount: newAllRows.length,
3457
+ executionTime: ((_b2 = t.result) == null ? void 0 : _b2.executionTime) || 0,
3458
+ pagination: result.pagination
3459
+ },
3460
+ allRows: newAllRows,
3461
+ currentOffset: currentOffset + result.rows.length,
3462
+ isExecuting: false,
3463
+ isLoadingMore: false
3464
+ });
3465
+ }));
3466
+ }).catch((error) => {
3467
+ if (cancelledRef.current) return;
3468
+ setTabs((prev) => prev.map((t) => t.id === currentTab.id ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3469
+ isExecuting: false,
3470
+ isLoadingMore: false
3471
+ }) : t));
3472
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3473
+ toast({ title: "Load More Error", description: errorMessage, variant: "destructive" });
3474
+ });
3475
+ }, [currentTab, activeConnection, onQueryExecute, setTabs, toast]);
3476
+ const handleUnlimitedQuery = React.useCallback(() => {
3477
+ if (!pendingUnlimitedQuery) return;
3478
+ if (!activeConnection) return;
3479
+ const { query, tabId } = pendingUnlimitedQuery;
3480
+ cancelledRef.current = false;
3481
+ setTabs((prev) => prev.map((t) => t.id === tabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3482
+ isExecuting: true
3483
+ }) : t));
3484
+ onQueryExecute(activeConnection.id, query, { unlimited: true }).then((result) => {
3485
+ if (cancelledRef.current) return;
3486
+ setTabs((prev) => prev.map((t) => {
3487
+ if (t.id !== tabId) return t;
3488
+ return chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3489
+ result: {
3490
+ rows: result.rows,
3491
+ fields: result.fields,
3492
+ rowCount: result.rowCount,
3493
+ executionTime: result.executionTime,
3494
+ pagination: result.pagination
3495
+ },
3496
+ allRows: result.rows,
3497
+ currentOffset: result.rows.length,
3498
+ isExecuting: false,
3499
+ isLoadingMore: false
3500
+ });
3501
+ }));
3502
+ setHistoryKey((prev) => prev + 1);
3503
+ }).catch((error) => {
3504
+ if (cancelledRef.current) return;
3505
+ setTabs((prev) => prev.map((t) => t.id === tabId ? chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({}, t), {
3506
+ isExecuting: false,
3507
+ isLoadingMore: false
3508
+ }) : t));
3509
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3510
+ toast({ title: "Query Error", description: errorMessage, variant: "destructive" });
3511
+ });
3512
+ setUnlimitedWarningOpen(false);
3513
+ setPendingUnlimitedQuery(null);
3514
+ }, [pendingUnlimitedQuery, activeConnection, onQueryExecute, setTabs, toast]);
3515
+ return {
3516
+ executeQuery,
3517
+ forceExecuteQuery,
3518
+ cancelQuery,
3519
+ handleLoadMore,
3520
+ handleUnlimitedQuery,
3521
+ safetyCheckQuery,
3522
+ setSafetyCheckQuery,
3523
+ unlimitedWarningOpen,
3524
+ setUnlimitedWarningOpen,
3525
+ pendingUnlimitedQuery,
3526
+ setPendingUnlimitedQuery,
3527
+ historyKey,
3528
+ bottomPanelMode,
3529
+ setBottomPanelMode
3530
+ };
3531
+ }
3532
+
3533
+ // src/workspace/types.ts
3534
+ var DEFAULT_WORKSPACE_FEATURES = {
3535
+ ai: false,
3536
+ charts: true,
3537
+ codeGenerator: true,
3538
+ testDataGenerator: true,
3539
+ schemaDiagram: true,
3540
+ dataImport: true,
3541
+ inlineEditing: false,
3542
+ transactions: false,
3543
+ connectionManagement: false,
3544
+ dataMasking: false
3545
+ };
3546
+ function ResizablePanelGroup(_a) {
3547
+ var _b = _a, {
3548
+ className
3549
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3550
+ "className"
3551
+ ]);
3552
+ return /* @__PURE__ */ jsxRuntime.jsx(
3553
+ ResizablePrimitive__namespace.PanelGroup,
3554
+ chunkQ6LRDBK7_js.__spreadValues({
3555
+ "data-slot": "resizable-panel-group",
3556
+ className: chunkY52UIFEX_js.cn(
3557
+ "flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
3558
+ className
3559
+ )
3560
+ }, props)
3561
+ );
3562
+ }
3563
+ function ResizablePanel(_a) {
3564
+ var props = chunkQ6LRDBK7_js.__objRest(_a, []);
3565
+ return /* @__PURE__ */ jsxRuntime.jsx(ResizablePrimitive__namespace.Panel, chunkQ6LRDBK7_js.__spreadValues({ "data-slot": "resizable-panel" }, props));
3566
+ }
3567
+ function ResizableHandle(_a) {
3568
+ var _b = _a, {
3569
+ withHandle,
3570
+ className
3571
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3572
+ "withHandle",
3573
+ "className"
3574
+ ]);
3575
+ return /* @__PURE__ */ jsxRuntime.jsx(
3576
+ ResizablePrimitive__namespace.PanelResizeHandle,
3577
+ chunkQ6LRDBK7_js.__spreadProps(chunkQ6LRDBK7_js.__spreadValues({
3578
+ "data-slot": "resizable-handle",
3579
+ className: chunkY52UIFEX_js.cn(
3580
+ "bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
3581
+ className
3582
+ )
3583
+ }, props), {
3584
+ children: withHandle && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GripVerticalIcon, { className: "size-2.5" }) })
3585
+ })
3586
+ );
3587
+ }
3588
+ function AlertDialog(_a) {
3589
+ var props = chunkQ6LRDBK7_js.__objRest(_a, []);
3590
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Root, chunkQ6LRDBK7_js.__spreadValues({ "data-slot": "alert-dialog" }, props));
3591
+ }
3592
+ function AlertDialogPortal(_a) {
3593
+ var props = chunkQ6LRDBK7_js.__objRest(_a, []);
3594
+ return /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Portal, chunkQ6LRDBK7_js.__spreadValues({ "data-slot": "alert-dialog-portal" }, props));
3595
+ }
3596
+ function AlertDialogOverlay(_a) {
3597
+ var _b = _a, {
3598
+ className
3599
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3600
+ "className"
3601
+ ]);
3602
+ return /* @__PURE__ */ jsxRuntime.jsx(
3603
+ AlertDialogPrimitive__namespace.Overlay,
3604
+ chunkQ6LRDBK7_js.__spreadValues({
3605
+ "data-slot": "alert-dialog-overlay",
3606
+ className: chunkY52UIFEX_js.cn(
3607
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
3608
+ className
3609
+ )
3610
+ }, props)
3611
+ );
3612
+ }
3613
+ function AlertDialogContent(_a) {
3614
+ var _b = _a, {
3615
+ className
3616
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3617
+ "className"
3618
+ ]);
3619
+ return /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { children: [
3620
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
3621
+ /* @__PURE__ */ jsxRuntime.jsx(
3622
+ AlertDialogPrimitive__namespace.Content,
3623
+ chunkQ6LRDBK7_js.__spreadValues({
3624
+ "data-slot": "alert-dialog-content",
3625
+ className: chunkY52UIFEX_js.cn(
3626
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
3627
+ className
3628
+ )
3629
+ }, props)
3630
+ )
3631
+ ] });
3632
+ }
3633
+ function AlertDialogTitle(_a) {
3634
+ var _b = _a, {
3635
+ className
3636
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3637
+ "className"
3638
+ ]);
3639
+ return /* @__PURE__ */ jsxRuntime.jsx(
3640
+ AlertDialogPrimitive__namespace.Title,
3641
+ chunkQ6LRDBK7_js.__spreadValues({
3642
+ "data-slot": "alert-dialog-title",
3643
+ className: chunkY52UIFEX_js.cn("text-lg font-semibold", className)
3644
+ }, props)
3645
+ );
3646
+ }
3647
+ function AlertDialogDescription(_a) {
3648
+ var _b = _a, {
3649
+ className
3650
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3651
+ "className"
3652
+ ]);
3653
+ return /* @__PURE__ */ jsxRuntime.jsx(
3654
+ AlertDialogPrimitive__namespace.Description,
3655
+ chunkQ6LRDBK7_js.__spreadValues({
3656
+ "data-slot": "alert-dialog-description",
3657
+ className: chunkY52UIFEX_js.cn("text-muted-foreground text-sm", className)
3658
+ }, props)
3659
+ );
3660
+ }
3661
+ function AlertDialogAction(_a) {
3662
+ var _b = _a, {
3663
+ className
3664
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3665
+ "className"
3666
+ ]);
3667
+ return /* @__PURE__ */ jsxRuntime.jsx(
3668
+ AlertDialogPrimitive__namespace.Action,
3669
+ chunkQ6LRDBK7_js.__spreadValues({
3670
+ className: chunkY52UIFEX_js.cn(chunkY52UIFEX_js.buttonVariants(), className)
3671
+ }, props)
3672
+ );
3673
+ }
3674
+ function AlertDialogCancel(_a) {
3675
+ var _b = _a, {
3676
+ className
3677
+ } = _b, props = chunkQ6LRDBK7_js.__objRest(_b, [
3678
+ "className"
3679
+ ]);
3680
+ return /* @__PURE__ */ jsxRuntime.jsx(
3681
+ AlertDialogPrimitive__namespace.Cancel,
3682
+ chunkQ6LRDBK7_js.__spreadValues({
3683
+ className: chunkY52UIFEX_js.cn(chunkY52UIFEX_js.buttonVariants({ variant: "outline" }), className)
3684
+ }, props)
3685
+ );
3686
+ }
3687
+ var STUDIO_SCOPED_CSS = `
3688
+ [data-studio-workspace] {
3689
+ /* Dark theme \u2014 monochrome (black/white/gray) */
3690
+ --background: #09090b;
3691
+ --foreground: #fafafa;
3692
+ --card: #09090b;
3693
+ --card-foreground: #fafafa;
3694
+ --popover: #09090b;
3695
+ --popover-foreground: #fafafa;
3696
+ --primary: #fafafa;
3697
+ --primary-foreground: #09090b;
3698
+ --secondary: #27272a;
3699
+ --secondary-foreground: #fafafa;
3700
+ --muted: #27272a;
3701
+ --muted-foreground: #a1a1aa;
3702
+ --accent: #27272a;
3703
+ --accent-foreground: #fafafa;
3704
+ --destructive: #dc2626;
3705
+ --destructive-foreground: #fafafa;
3706
+ --border: #27272a;
3707
+ --input: #27272a;
3708
+ --ring: #d4d4d8;
3709
+ --radius: 0.5rem;
3710
+ --chart-1: #e4e4e7;
3711
+ --chart-2: #a1a1aa;
3712
+ --chart-3: #71717a;
3713
+ --chart-4: #52525b;
3714
+ --chart-5: #3f3f46;
3715
+
3716
+ /* Font \u2014 Geist (inherited from host or fallback to system) */
3717
+ font-family: var(--font-geist-sans, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
3718
+ -webkit-font-smoothing: antialiased;
3719
+ -moz-osx-font-smoothing: grayscale;
3720
+ font-feature-settings: "rlig" 1, "calt" 1;
3721
+ letter-spacing: -0.011em;
3722
+ }
3723
+ [data-studio-workspace] *,
3724
+ [data-studio-workspace] *::before,
3725
+ [data-studio-workspace] *::after {
3726
+ font-family: inherit;
3727
+ }
3728
+ [data-studio-workspace] code,
3729
+ [data-studio-workspace] pre,
3730
+ [data-studio-workspace] kbd,
3731
+ [data-studio-workspace] .font-mono {
3732
+ font-family: var(--font-geist-mono, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace);
3733
+ }
3734
+ `;
3735
+ function useStudioTheme() {
3736
+ React.useEffect(() => {
3737
+ const id = "studio-workspace-theme";
3738
+ if (document.getElementById(id)) return;
3739
+ const style = document.createElement("style");
3740
+ style.id = id;
3741
+ style.textContent = STUDIO_SCOPED_CSS;
3742
+ document.head.appendChild(style);
3743
+ return () => {
3744
+ var _a;
3745
+ (_a = document.getElementById(id)) == null ? void 0 : _a.remove();
3746
+ };
3747
+ }, []);
3748
+ }
3749
+ var NOOP_MASKING_CONFIG = {
3750
+ enabled: false,
3751
+ patterns: [],
3752
+ roleSettings: {
3753
+ admin: { canToggle: false, canReveal: false },
3754
+ user: { canToggle: false, canReveal: false }
3755
+ }
3756
+ };
3757
+ function StudioWorkspace({
3758
+ connections: externalConnections,
3759
+ currentUser,
3760
+ onQueryExecute,
3761
+ onSchemaFetch,
3762
+ onSaveQuery: onSaveQueryProp,
3763
+ // onLoadSavedQueries — reserved for future saved-queries panel integration
3764
+ features: featuresProp,
3765
+ className
3766
+ }) {
3767
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3768
+ const queryEditorRef = React.useRef(null);
3769
+ const { toast } = useToast();
3770
+ const features = React.useMemo(
3771
+ () => chunkQ6LRDBK7_js.__spreadValues(chunkQ6LRDBK7_js.__spreadValues({}, DEFAULT_WORKSPACE_FEATURES), featuresProp),
3772
+ [featuresProp]
3773
+ );
3774
+ const conn = useConnectionAdapter({
3775
+ connections: externalConnections,
3776
+ onSchemaFetch
3777
+ });
3778
+ const tabMgr = useTabManager({
3779
+ activeConnection: conn.activeConnection,
3780
+ metadata: null,
3781
+ schema: conn.schema
3782
+ });
3783
+ const queryExec = useQueryAdapter({
3784
+ activeConnection: conn.activeConnection,
3785
+ onQueryExecute,
3786
+ tabs: tabMgr.tabs,
3787
+ activeTabId: tabMgr.activeTabId,
3788
+ currentTab: tabMgr.currentTab,
3789
+ setTabs: tabMgr.setTabs,
3790
+ fetchSchema: conn.fetchSchema,
3791
+ features
3792
+ });
3793
+ useStudioTheme();
3794
+ React.useEffect(() => {
3795
+ if (conn.activeConnection) {
3796
+ conn.fetchSchema(conn.activeConnection);
3797
+ } else {
3798
+ conn.setSchema([]);
3799
+ }
3800
+ }, [conn.activeConnection]);
3801
+ const [showDiagram, setShowDiagram] = React.useState(false);
3802
+ const [isSaveQueryModalOpen, setIsSaveQueryModalOpen] = React.useState(false);
3803
+ const [savedKey, setSavedKey] = React.useState(0);
3804
+ const [activeMobileTab, setActiveMobileTab] = React.useState("editor");
3805
+ const [isImportModalOpen, setIsImportModalOpen] = React.useState(false);
3806
+ const [isNL2SQLOpen, setIsNL2SQLOpen] = React.useState(false);
3807
+ const [profilerTable, setProfilerTable] = React.useState(null);
3808
+ const [codeGenTable, setCodeGenTable] = React.useState(null);
3809
+ const [testDataTable, setTestDataTable] = React.useState(null);
3810
+ const handleSaveQuery = React.useCallback(async (name, description, tags) => {
3811
+ if (!conn.activeConnection) return;
3812
+ if (onSaveQueryProp) {
3813
+ try {
3814
+ await onSaveQueryProp({
3815
+ name,
3816
+ query: tabMgr.currentTab.query,
3817
+ description,
3818
+ connectionType: conn.activeConnection.type,
3819
+ tags
3820
+ });
3821
+ setSavedKey((prev) => prev + 1);
3822
+ toast({ title: "Query Saved", description: `"${name}" has been added to your saved queries.` });
3823
+ } catch (error) {
3824
+ const msg = error instanceof Error ? error.message : "Failed to save query";
3825
+ toast({ title: "Save Failed", description: msg, variant: "destructive" });
3826
+ }
3827
+ }
3828
+ }, [conn.activeConnection, tabMgr.currentTab.query, onSaveQueryProp, toast]);
3829
+ const exportResults = React.useCallback((format3) => {
3830
+ if (!tabMgr.currentTab.result) return;
3831
+ const data = tabMgr.currentTab.result.rows;
3832
+ let content = "";
3833
+ let mimeType = "text/plain";
3834
+ let ext = format3;
3835
+ if (format3 === "csv") {
3836
+ const headers = Object.keys(data[0] || {}).join(",");
3837
+ const rows = data.map((row) => Object.values(row).map((val) => `"${val}"`).join(",")).join("\n");
3838
+ content = `${headers}
3839
+ ${rows}`;
3840
+ mimeType = "text/csv";
3841
+ ext = "csv";
3842
+ } else if (format3 === "json") {
3843
+ content = JSON.stringify(data, null, 2);
3844
+ mimeType = "application/json";
3845
+ ext = "json";
3846
+ } else if (format3 === "sql-insert") {
3847
+ const tableName = tabMgr.currentTab.name.replace(/^Query[: ]*/, "") || "table_name";
3848
+ const columns = Object.keys(data[0] || {});
3849
+ const lines = data.map((row) => {
3850
+ const values = columns.map((col) => {
3851
+ const val = row[col];
3852
+ if (val === null || val === void 0) return "NULL";
3853
+ if (typeof val === "number" || typeof val === "boolean") return String(val);
3854
+ return `'${String(val).replace(/'/g, "''")}'`;
3855
+ });
3856
+ return `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${values.join(", ")});`;
3857
+ });
3858
+ content = lines.join("\n");
3859
+ mimeType = "text/sql";
3860
+ ext = "sql";
3861
+ } else if (format3 === "sql-ddl") {
3862
+ const tableName = tabMgr.currentTab.name.replace(/^Query[: ]*/, "") || "table_name";
3863
+ const columns = Object.keys(data[0] || {});
3864
+ const colDefs = columns.map((col) => {
3865
+ var _a2;
3866
+ const sampleVal = (_a2 = data[0]) == null ? void 0 : _a2[col];
3867
+ let sqlType = "TEXT";
3868
+ if (typeof sampleVal === "number") {
3869
+ sqlType = Number.isInteger(sampleVal) ? "INTEGER" : "NUMERIC";
3870
+ } else if (typeof sampleVal === "boolean") {
3871
+ sqlType = "BOOLEAN";
3872
+ } else if (sampleVal instanceof Date) {
3873
+ sqlType = "TIMESTAMP";
3874
+ }
3875
+ return ` ${col} ${sqlType}`;
3876
+ });
3877
+ content = `CREATE TABLE ${tableName} (
3878
+ ${colDefs.join(",\n")}
3879
+ );`;
3880
+ mimeType = "text/sql";
3881
+ ext = "sql";
3882
+ }
3883
+ const fileName = `query_result_export.${ext}`;
3884
+ const blob = new Blob([content], { type: mimeType });
3885
+ const url = URL.createObjectURL(blob);
3886
+ const link = document.createElement("a");
3887
+ link.href = url;
3888
+ link.download = fileName;
3889
+ link.click();
3890
+ URL.revokeObjectURL(url);
3891
+ }, [tabMgr.currentTab]);
3892
+ const onTableClick = React.useCallback((tableName) => {
3893
+ tabMgr.handleTableClick(tableName, queryExec.executeQuery);
3894
+ }, [tabMgr, queryExec.executeQuery]);
3895
+ const noop = React.useCallback(() => {
3896
+ }, []);
3897
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3898
+ "div",
3899
+ {
3900
+ "data-studio-workspace": "",
3901
+ className: chunkY52UIFEX_js.cn("dark flex h-full w-full bg-[#050505] text-zinc-100 overflow-hidden font-sans select-none", className),
3902
+ children: [
3903
+ /* @__PURE__ */ jsxRuntime.jsxs(ResizablePanelGroup, { id: "workspace-main", direction: "horizontal", className: "h-full", children: [
3904
+ /* @__PURE__ */ jsxRuntime.jsx(ResizablePanel, { defaultSize: 22, minSize: 15, maxSize: 35, className: "hidden md:block", children: /* @__PURE__ */ jsxRuntime.jsx(
3905
+ Sidebar,
3906
+ {
3907
+ connections: conn.connections,
3908
+ activeConnection: conn.activeConnection,
3909
+ schema: conn.schema,
3910
+ isLoadingSchema: conn.isLoadingSchema,
3911
+ onSelectConnection: conn.setActiveConnection,
3912
+ onDeleteConnection: noop,
3913
+ onEditConnection: noop,
3914
+ onAddConnection: noop,
3915
+ onTableClick,
3916
+ onGenerateSelect: tabMgr.handleGenerateSelect,
3917
+ onCreateTableClick: void 0,
3918
+ onShowDiagram: features.schemaDiagram ? () => setShowDiagram(true) : void 0,
3919
+ isAdmin: false,
3920
+ onOpenMaintenance: noop,
3921
+ databaseType: (_a = conn.activeConnection) == null ? void 0 : _a.type,
3922
+ metadata: null,
3923
+ onProfileTable: features.codeGenerator ? (name) => setProfilerTable(name) : void 0,
3924
+ onGenerateCode: features.codeGenerator ? (name) => setCodeGenTable(name) : void 0,
3925
+ onGenerateTestData: features.testDataGenerator ? (name) => setTestDataTable(name) : void 0
3926
+ }
3927
+ ) }),
3928
+ /* @__PURE__ */ jsxRuntime.jsx(ResizableHandle, { className: "hidden md:flex w-1 bg-transparent hover:bg-blue-500/30 transition-colors" }),
3929
+ /* @__PURE__ */ jsxRuntime.jsx(ResizablePanel, { defaultSize: 78, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col min-w-0 h-full bg-[#0a0a0a]", children: [
3930
+ /* @__PURE__ */ jsxRuntime.jsx(
3931
+ StudioTabBar,
3932
+ {
3933
+ tabs: tabMgr.tabs,
3934
+ activeTabId: tabMgr.activeTabId,
3935
+ editingTabId: tabMgr.editingTabId,
3936
+ editingTabName: tabMgr.editingTabName,
3937
+ onSetActiveTabId: tabMgr.setActiveTabId,
3938
+ onSetEditingTabId: tabMgr.setEditingTabId,
3939
+ onSetEditingTabName: tabMgr.setEditingTabName,
3940
+ onSetTabs: tabMgr.setTabs,
3941
+ onCloseTab: tabMgr.closeTab,
3942
+ onAddTab: tabMgr.addTab
3943
+ }
3944
+ ),
3945
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "flex-1 overflow-hidden relative", children: [
3946
+ features.schemaDiagram && /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showDiagram && /* @__PURE__ */ jsxRuntime.jsx(chunkY52UIFEX_js.SchemaDiagram, { schema: conn.schema, onClose: () => setShowDiagram(false) }) }),
3947
+ activeMobileTab === "database" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden h-full bg-[#080808] overflow-auto p-4", children: [
3948
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xs font-medium text-zinc-300", children: "Connections" }) }),
3949
+ /* @__PURE__ */ jsxRuntime.jsx(
3950
+ ConnectionsList,
3951
+ {
3952
+ connections: conn.connections,
3953
+ activeConnection: conn.activeConnection,
3954
+ onSelectConnection: (c) => {
3955
+ conn.setActiveConnection(c);
3956
+ setActiveMobileTab("editor");
3957
+ },
3958
+ onDeleteConnection: noop,
3959
+ onAddConnection: noop
3960
+ }
3961
+ )
3962
+ ] }),
3963
+ activeMobileTab === "schema" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden h-full bg-[#080808] overflow-auto p-4", children: conn.activeConnection ? /* @__PURE__ */ jsxRuntime.jsx(
3964
+ chunkY52UIFEX_js.SchemaExplorer,
3965
+ {
3966
+ schema: conn.schema,
3967
+ isLoadingSchema: conn.isLoadingSchema,
3968
+ onTableClick: (tableName) => {
3969
+ onTableClick(tableName);
3970
+ setActiveMobileTab("editor");
3971
+ },
3972
+ onGenerateSelect: (tableName) => {
3973
+ tabMgr.handleGenerateSelect(tableName);
3974
+ setActiveMobileTab("editor");
3975
+ },
3976
+ onCreateTableClick: void 0,
3977
+ isAdmin: false,
3978
+ onOpenMaintenance: noop,
3979
+ databaseType: (_b = conn.activeConnection) == null ? void 0 : _b.type,
3980
+ metadata: null,
3981
+ onProfileTable: features.codeGenerator ? (name) => setProfilerTable(name) : void 0,
3982
+ onGenerateCode: features.codeGenerator ? (name) => setCodeGenTable(name) : void 0,
3983
+ onGenerateTestData: features.testDataGenerator ? (name) => setTestDataTable(name) : void 0
3984
+ }
3985
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-zinc-500", children: [
3986
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { strokeWidth: 1.5, className: "w-12 h-12 mb-4 opacity-30" }),
3987
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "Select a connection first" })
3988
+ ] }) }),
3989
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkY52UIFEX_js.cn(
3990
+ "h-full",
3991
+ activeMobileTab !== "editor" && "hidden md:block"
3992
+ ), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsxs(ResizablePanelGroup, { id: "workspace-editor", direction: "vertical", children: [
3993
+ /* @__PURE__ */ jsxRuntime.jsx(ResizablePanel, { defaultSize: 40, minSize: 20, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full flex flex-col", children: [
3994
+ /* @__PURE__ */ jsxRuntime.jsx(
3995
+ QueryToolbar,
3996
+ {
3997
+ activeConnection: conn.activeConnection,
3998
+ metadata: null,
3999
+ isExecuting: tabMgr.currentTab.isExecuting,
4000
+ playgroundMode: false,
4001
+ transactionActive: false,
4002
+ editingEnabled: false,
4003
+ onSaveQuery: onSaveQueryProp ? () => setIsSaveQueryModalOpen(true) : noop,
4004
+ onExecuteQuery: () => queryExec.executeQuery(),
4005
+ onCancelQuery: queryExec.cancelQuery,
4006
+ onBeginTransaction: noop,
4007
+ onCommitTransaction: noop,
4008
+ onRollbackTransaction: noop,
4009
+ onTogglePlayground: noop,
4010
+ onToggleEditing: noop,
4011
+ onImport: features.dataImport ? () => setIsImportModalOpen(true) : noop
4012
+ }
4013
+ ),
4014
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 relative", children: /* @__PURE__ */ jsxRuntime.jsx(
4015
+ chunkY52UIFEX_js.QueryEditor,
4016
+ {
4017
+ ref: queryEditorRef,
4018
+ value: tabMgr.currentTab.query,
4019
+ onContentChange: (val) => tabMgr.updateTabById(tabMgr.currentTab.id, { query: val }),
4020
+ language: tabMgr.currentTab.type === "mongodb" ? "json" : "sql",
4021
+ tables: conn.tableNames,
4022
+ databaseType: (_c = conn.activeConnection) == null ? void 0 : _c.type,
4023
+ schemaContext: conn.schemaContext,
4024
+ capabilities: void 0
4025
+ }
4026
+ ) })
4027
+ ] }) }),
4028
+ /* @__PURE__ */ jsxRuntime.jsx(ResizableHandle, { className: "h-1 bg-white/5 hover:bg-blue-500/20" }),
4029
+ /* @__PURE__ */ jsxRuntime.jsx(ResizablePanel, { defaultSize: 60, minSize: 20, children: /* @__PURE__ */ jsxRuntime.jsx(
4030
+ BottomPanel,
4031
+ {
4032
+ mode: queryExec.bottomPanelMode,
4033
+ onSetMode: queryExec.setBottomPanelMode,
4034
+ currentTab: tabMgr.currentTab,
4035
+ schema: conn.schema,
4036
+ schemaContext: conn.schemaContext,
4037
+ activeConnection: conn.activeConnection,
4038
+ metadata: null,
4039
+ historyKey: queryExec.historyKey,
4040
+ savedKey,
4041
+ isNL2SQLOpen: features.ai ? isNL2SQLOpen : false,
4042
+ onSetIsNL2SQLOpen: features.ai ? setIsNL2SQLOpen : noop,
4043
+ maskingEnabled: false,
4044
+ onToggleMasking: void 0,
4045
+ userRole: currentUser == null ? void 0 : currentUser.role,
4046
+ maskingConfig: NOOP_MASKING_CONFIG,
4047
+ editingEnabled: false,
4048
+ pendingChanges: [],
4049
+ onCellChange: noop,
4050
+ onApplyChanges: noop,
4051
+ onDiscardChanges: noop,
4052
+ onExecuteQuery: (q) => queryExec.executeQuery(q),
4053
+ onLoadQuery: (q) => tabMgr.updateCurrentTab({ query: q }),
4054
+ onLoadMore: ((_e = (_d = tabMgr.currentTab.result) == null ? void 0 : _d.pagination) == null ? void 0 : _e.hasMore) ? queryExec.handleLoadMore : void 0,
4055
+ isLoadingMore: tabMgr.currentTab.isLoadingMore,
4056
+ onExportResults: exportResults
4057
+ }
4058
+ ) })
4059
+ ] }) }) })
4060
+ ] })
4061
+ ] }) })
4062
+ ] }),
4063
+ onSaveQueryProp && /* @__PURE__ */ jsxRuntime.jsx(
4064
+ SaveQueryModal,
4065
+ {
4066
+ isOpen: isSaveQueryModalOpen,
4067
+ onClose: () => setIsSaveQueryModalOpen(false),
4068
+ onSave: handleSaveQuery,
4069
+ defaultQuery: tabMgr.currentTab.query
4070
+ }
4071
+ ),
4072
+ features.dataImport && /* @__PURE__ */ jsxRuntime.jsx(
4073
+ DataImportModal,
4074
+ {
4075
+ isOpen: isImportModalOpen,
4076
+ onClose: () => setIsImportModalOpen(false),
4077
+ onImport: (sql) => queryExec.executeQuery(sql),
4078
+ tables: conn.schema,
4079
+ databaseType: (_f = conn.activeConnection) == null ? void 0 : _f.type
4080
+ }
4081
+ ),
4082
+ /* @__PURE__ */ jsxRuntime.jsx(
4083
+ chunkY52UIFEX_js.QuerySafetyDialog,
4084
+ {
4085
+ isOpen: !!queryExec.safetyCheckQuery,
4086
+ query: queryExec.safetyCheckQuery || "",
4087
+ schemaContext: conn.schemaContext,
4088
+ databaseType: (_g = conn.activeConnection) == null ? void 0 : _g.type,
4089
+ onClose: () => queryExec.setSafetyCheckQuery(null),
4090
+ onProceed: () => {
4091
+ if (queryExec.safetyCheckQuery) queryExec.forceExecuteQuery(queryExec.safetyCheckQuery);
4092
+ },
4093
+ onAnalyzeSafety: async () => ({
4094
+ riskLevel: "high",
4095
+ summary: "Potentially dangerous query detected",
4096
+ warnings: [{
4097
+ type: "destructive",
4098
+ severity: "high",
4099
+ message: "This query may modify or delete data",
4100
+ detail: "Review carefully before proceeding."
4101
+ }],
4102
+ affectedRows: "unknown",
4103
+ cascadeEffects: "unknown",
4104
+ recommendation: "Review this query carefully before proceeding."
4105
+ })
4106
+ }
4107
+ ),
4108
+ features.codeGenerator && /* @__PURE__ */ jsxRuntime.jsx(
4109
+ chunkY52UIFEX_js.DataProfiler,
4110
+ {
4111
+ isOpen: !!profilerTable,
4112
+ onClose: () => setProfilerTable(null),
4113
+ tableName: profilerTable || "",
4114
+ tableSchema: conn.schema.find((t) => t.name === profilerTable) || null,
4115
+ connection: conn.activeConnection,
4116
+ schemaContext: conn.schemaContext,
4117
+ databaseType: (_h = conn.activeConnection) == null ? void 0 : _h.type
4118
+ }
4119
+ ),
4120
+ features.codeGenerator && /* @__PURE__ */ jsxRuntime.jsx(
4121
+ chunkY52UIFEX_js.CodeGenerator,
4122
+ {
4123
+ isOpen: !!codeGenTable,
4124
+ onClose: () => setCodeGenTable(null),
4125
+ tableName: codeGenTable || "",
4126
+ tableSchema: conn.schema.find((t) => t.name === codeGenTable) || null,
4127
+ databaseType: (_i = conn.activeConnection) == null ? void 0 : _i.type
4128
+ }
4129
+ ),
4130
+ features.testDataGenerator && /* @__PURE__ */ jsxRuntime.jsx(
4131
+ chunkY52UIFEX_js.TestDataGenerator,
4132
+ {
4133
+ isOpen: !!testDataTable,
4134
+ onClose: () => setTestDataTable(null),
4135
+ tableName: testDataTable || "",
4136
+ tableSchema: conn.schema.find((t) => t.name === testDataTable) || null,
4137
+ databaseType: (_j = conn.activeConnection) == null ? void 0 : _j.type,
4138
+ queryLanguage: void 0,
4139
+ onExecuteQuery: (q) => queryExec.executeQuery(q)
4140
+ }
4141
+ ),
4142
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open: queryExec.unlimitedWarningOpen, onOpenChange: queryExec.setUnlimitedWarningOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "bg-[#111] border-white/5 max-w-sm p-0 gap-0 overflow-hidden", children: [
4143
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
4144
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-xl bg-gradient-to-br from-amber-500/20 to-red-500/10 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { strokeWidth: 1.5, className: "w-5 h-5 text-amber-400" }) }),
4145
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
4146
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { className: "text-xs font-medium text-zinc-100 mb-1", children: "Load all results?" }),
4147
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogDescription, { className: "text-xs text-zinc-500 leading-relaxed", children: [
4148
+ "This may slow down your browser. Max ",
4149
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400", children: "100K" }),
4150
+ " rows will be loaded."
4151
+ ] })
4152
+ ] })
4153
+ ] }) }),
4154
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 pb-6 flex gap-2", children: [
4155
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { className: "flex-1 h-9 bg-white/5 border-0 text-zinc-400 text-xs font-medium hover:bg-white/10 hover:text-zinc-200", children: "Cancel" }),
4156
+ /* @__PURE__ */ jsxRuntime.jsx(
4157
+ AlertDialogAction,
4158
+ {
4159
+ onClick: queryExec.handleUnlimitedQuery,
4160
+ className: "flex-1 h-9 bg-amber-600 border-0 text-white text-xs font-medium hover:bg-amber-500",
4161
+ children: "Load All"
4162
+ }
4163
+ )
4164
+ ] })
4165
+ ] }) })
4166
+ ]
4167
+ }
4168
+ );
4169
+ }
4170
+
4171
+ exports.DEFAULT_WORKSPACE_FEATURES = DEFAULT_WORKSPACE_FEATURES;
4172
+ exports.StudioWorkspace = StudioWorkspace;
4173
+ //# sourceMappingURL=workspace.js.map
4174
+ //# sourceMappingURL=workspace.js.map