@adecore/database 0.0.1 → 0.16.0-beta.0

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 (400) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -1
  3. package/dist/DatabaseProvider.d.ts +13 -0
  4. package/dist/DatabaseProvider.js +17 -0
  5. package/dist/actions.d.ts +40 -0
  6. package/dist/actions.js +1 -0
  7. package/dist/client/client.d.ts +5 -0
  8. package/dist/client/client.js +245 -0
  9. package/dist/client/index.d.ts +2 -0
  10. package/dist/client/index.js +2 -0
  11. package/dist/client/types.d.ts +97 -0
  12. package/dist/client/types.js +13 -0
  13. package/dist/client-context.d.ts +16 -0
  14. package/dist/client-context.js +17 -0
  15. package/dist/connections/ConnectionForm.d.ts +10 -0
  16. package/dist/connections/ConnectionForm.js +145 -0
  17. package/dist/connections/ConnectionManager.d.ts +12 -0
  18. package/dist/connections/ConnectionManager.js +93 -0
  19. package/dist/connections/EngineIcon.d.ts +9 -0
  20. package/dist/connections/EngineIcon.js +7 -0
  21. package/dist/connections/connection-config.d.ts +16 -0
  22. package/dist/connections/connection-config.js +107 -0
  23. package/dist/connections/docker.d.ts +9 -0
  24. package/dist/connections/docker.js +38 -0
  25. package/dist/connections/engine-icons.d.ts +3 -0
  26. package/dist/connections/engine-icons.js +3 -0
  27. package/dist/connections/use-docker-containers.d.ts +17 -0
  28. package/dist/connections/use-docker-containers.js +26 -0
  29. package/dist/console/DestructiveDialog.d.ts +9 -0
  30. package/dist/console/DestructiveDialog.js +9 -0
  31. package/dist/console/HistoryPanel.d.ts +10 -0
  32. package/dist/console/HistoryPanel.js +15 -0
  33. package/dist/console/QueryConsole.d.ts +14 -0
  34. package/dist/console/QueryConsole.js +261 -0
  35. package/dist/console/SchemaPicker.d.ts +11 -0
  36. package/dist/console/SchemaPicker.js +8 -0
  37. package/dist/console/SqlEditor.d.ts +12 -0
  38. package/dist/console/SqlEditor.js +61 -0
  39. package/dist/console/StatementResultView.d.ts +18 -0
  40. package/dist/console/StatementResultView.js +32 -0
  41. package/dist/console/TransactionControls.d.ts +13 -0
  42. package/dist/console/TransactionControls.js +12 -0
  43. package/dist/console/destructive.d.ts +7 -0
  44. package/dist/console/destructive.js +43 -0
  45. package/dist/console/editing.d.ts +12 -0
  46. package/dist/console/editing.js +60 -0
  47. package/dist/console/history.d.ts +13 -0
  48. package/dist/console/history.js +43 -0
  49. package/dist/console/labels.d.ts +1 -0
  50. package/dist/console/labels.js +6 -0
  51. package/dist/console/outcome.d.ts +6 -0
  52. package/dist/console/outcome.js +11 -0
  53. package/dist/console/schemas.d.ts +2 -0
  54. package/dist/console/schemas.js +5 -0
  55. package/dist/console/shortcuts.d.ts +2 -0
  56. package/dist/console/shortcuts.js +3 -0
  57. package/dist/console/useConsoleHistory.d.ts +7 -0
  58. package/dist/console/useConsoleHistory.js +22 -0
  59. package/dist/ddl/alter-mysql.d.ts +4 -0
  60. package/dist/ddl/alter-mysql.js +79 -0
  61. package/dist/ddl/alter-sqlite.d.ts +4 -0
  62. package/dist/ddl/alter-sqlite.js +80 -0
  63. package/dist/ddl/alter.d.ts +4 -0
  64. package/dist/ddl/alter.js +24 -0
  65. package/dist/ddl/column.d.ts +9 -0
  66. package/dist/ddl/column.js +62 -0
  67. package/dist/ddl/create.d.ts +12 -0
  68. package/dist/ddl/create.js +74 -0
  69. package/dist/ddl/dialect.d.ts +12 -0
  70. package/dist/ddl/dialect.js +34 -0
  71. package/dist/ddl/diff.d.ts +34 -0
  72. package/dist/ddl/diff.js +111 -0
  73. package/dist/ddl/draft.d.ts +46 -0
  74. package/dist/ddl/draft.js +70 -0
  75. package/dist/ddl/index.d.ts +10 -0
  76. package/dist/ddl/index.js +10 -0
  77. package/dist/ddl/parse.d.ts +17 -0
  78. package/dist/ddl/parse.js +131 -0
  79. package/dist/ddl/statements.d.ts +6 -0
  80. package/dist/ddl/statements.js +12 -0
  81. package/dist/ddl/types.d.ts +6 -0
  82. package/dist/ddl/types.js +52 -0
  83. package/dist/ddl/validate.d.ts +7 -0
  84. package/dist/ddl/validate.js +38 -0
  85. package/dist/designer/ColumnsEditor.d.ts +2 -0
  86. package/dist/designer/ColumnsEditor.js +24 -0
  87. package/dist/designer/DesignerView.d.ts +25 -0
  88. package/dist/designer/DesignerView.js +33 -0
  89. package/dist/designer/ForeignKeysEditor.d.ts +7 -0
  90. package/dist/designer/ForeignKeysEditor.js +24 -0
  91. package/dist/designer/IndexesEditor.d.ts +2 -0
  92. package/dist/designer/IndexesEditor.js +13 -0
  93. package/dist/designer/NamePicker.d.ts +11 -0
  94. package/dist/designer/NamePicker.js +13 -0
  95. package/dist/designer/OptionsEditor.d.ts +2 -0
  96. package/dist/designer/OptionsEditor.js +17 -0
  97. package/dist/designer/SqlPreview.d.ts +12 -0
  98. package/dist/designer/SqlPreview.js +17 -0
  99. package/dist/designer/TableDesigner.d.ts +10 -0
  100. package/dist/designer/TableDesigner.js +103 -0
  101. package/dist/designer/edit.d.ts +17 -0
  102. package/dist/designer/edit.js +115 -0
  103. package/dist/designer/editor-props.d.ts +10 -0
  104. package/dist/designer/editor-props.js +1 -0
  105. package/dist/designer/plan.d.ts +9 -0
  106. package/dist/designer/plan.js +13 -0
  107. package/dist/designer/recover.d.ts +2 -0
  108. package/dist/designer/recover.js +18 -0
  109. package/dist/designer/useReferenceColumns.d.ts +3 -0
  110. package/dist/designer/useReferenceColumns.js +36 -0
  111. package/dist/explorer/DatabaseExplorer.d.ts +13 -0
  112. package/dist/explorer/DatabaseExplorer.js +264 -0
  113. package/dist/explorer/RowMenu.d.ts +11 -0
  114. package/dist/explorer/RowMenu.js +89 -0
  115. package/dist/explorer/TableDialog.d.ts +15 -0
  116. package/dist/explorer/TableDialog.js +50 -0
  117. package/dist/explorer/expansion.d.ts +7 -0
  118. package/dist/explorer/expansion.js +31 -0
  119. package/dist/explorer/table-statements.d.ts +5 -0
  120. package/dist/explorer/table-statements.js +12 -0
  121. package/dist/explorer/tree.d.ts +125 -0
  122. package/dist/explorer/tree.js +295 -0
  123. package/dist/explorer/use-explorer-loads.d.ts +12 -0
  124. package/dist/explorer/use-explorer-loads.js +109 -0
  125. package/dist/explorer/use-stored-expansion.d.ts +9 -0
  126. package/dist/explorer/use-stored-expansion.js +47 -0
  127. package/dist/grid/CellEditor.d.ts +9 -0
  128. package/dist/grid/CellEditor.js +29 -0
  129. package/dist/grid/CopyAsMenu.d.ts +7 -0
  130. package/dist/grid/CopyAsMenu.js +10 -0
  131. package/dist/grid/DataGrid.d.ts +36 -0
  132. package/dist/grid/DataGrid.js +512 -0
  133. package/dist/grid/EnumPicker.d.ts +17 -0
  134. package/dist/grid/EnumPicker.js +53 -0
  135. package/dist/grid/GridHeaderCell.d.ts +36 -0
  136. package/dist/grid/GridHeaderCell.js +69 -0
  137. package/dist/grid/RecordView.d.ts +20 -0
  138. package/dist/grid/RecordView.js +126 -0
  139. package/dist/grid/ValueDock.d.ts +11 -0
  140. package/dist/grid/ValueDock.js +28 -0
  141. package/dist/grid/aggregates.d.ts +22 -0
  142. package/dist/grid/aggregates.js +62 -0
  143. package/dist/grid/cell-range.d.ts +14 -0
  144. package/dist/grid/cell-range.js +11 -0
  145. package/dist/grid/column-layout.d.ts +18 -0
  146. package/dist/grid/column-layout.js +49 -0
  147. package/dist/grid/column-selection.d.ts +11 -0
  148. package/dist/grid/column-selection.js +28 -0
  149. package/dist/grid/column-view.d.ts +10 -0
  150. package/dist/grid/column-view.js +23 -0
  151. package/dist/grid/copy-formats.d.ts +15 -0
  152. package/dist/grid/copy-formats.js +80 -0
  153. package/dist/grid/display.d.ts +20 -0
  154. package/dist/grid/display.js +81 -0
  155. package/dist/grid/edit-value.d.ts +5 -0
  156. package/dist/grid/edit-value.js +55 -0
  157. package/dist/grid/enum-type.d.ts +7 -0
  158. package/dist/grid/enum-type.js +52 -0
  159. package/dist/grid/focused-value.d.ts +4 -0
  160. package/dist/grid/focused-value.js +19 -0
  161. package/dist/grid/layout.d.ts +22 -0
  162. package/dist/grid/layout.js +74 -0
  163. package/dist/grid/navigation.d.ts +15 -0
  164. package/dist/grid/navigation.js +52 -0
  165. package/dist/grid/row-selection.d.ts +9 -0
  166. package/dist/grid/row-selection.js +24 -0
  167. package/dist/grid/sort.d.ts +7 -0
  168. package/dist/grid/sort.js +7 -0
  169. package/dist/grid/types.d.ts +30 -0
  170. package/dist/grid/types.js +9 -0
  171. package/dist/host/helper-path.d.ts +7 -0
  172. package/dist/host/helper-path.js +15 -0
  173. package/dist/host/host.d.ts +2 -0
  174. package/dist/host/host.js +343 -0
  175. package/dist/host/index.d.ts +5 -0
  176. package/dist/host/index.js +4 -0
  177. package/dist/host/spawn.d.ts +7 -0
  178. package/dist/host/spawn.js +98 -0
  179. package/dist/host/types.d.ts +19 -0
  180. package/dist/host/types.js +1 -0
  181. package/dist/host/validate.d.ts +10 -0
  182. package/dist/host/validate.js +339 -0
  183. package/dist/index.d.ts +14 -0
  184. package/dist/index.js +13 -0
  185. package/dist/locales/en.json +577 -0
  186. package/dist/locales/nl.json +577 -0
  187. package/dist/locales.d.ts +4 -0
  188. package/dist/locales.js +14 -0
  189. package/dist/protocol/connection.d.ts +56 -0
  190. package/dist/protocol/connection.js +1 -0
  191. package/dist/protocol/errors.d.ts +7 -0
  192. package/dist/protocol/errors.js +1 -0
  193. package/dist/protocol/index.d.ts +5 -0
  194. package/dist/protocol/index.js +3 -0
  195. package/dist/protocol/messages.d.ts +250 -0
  196. package/dist/protocol/messages.js +2 -0
  197. package/dist/protocol/schema.d.ts +53 -0
  198. package/dist/protocol/schema.js +1 -0
  199. package/dist/protocol/values.d.ts +21 -0
  200. package/dist/protocol/values.js +15 -0
  201. package/dist/sql-split.d.ts +15 -0
  202. package/dist/sql-split.js +201 -0
  203. package/dist/sql.d.ts +29 -0
  204. package/dist/sql.js +104 -0
  205. package/dist/structure/StructureView.d.ts +14 -0
  206. package/dist/structure/StructureView.js +99 -0
  207. package/dist/structure/structure-text.d.ts +2 -0
  208. package/dist/structure/structure-text.js +2 -0
  209. package/dist/table/CommandField.d.ts +14 -0
  210. package/dist/table/CommandField.js +157 -0
  211. package/dist/table/ImportDialog.d.ts +27 -0
  212. package/dist/table/ImportDialog.js +28 -0
  213. package/dist/table/TableStatusBar.d.ts +19 -0
  214. package/dist/table/TableStatusBar.js +22 -0
  215. package/dist/table/TableToolbar.d.ts +43 -0
  216. package/dist/table/TableToolbar.js +16 -0
  217. package/dist/table/TableView.d.ts +13 -0
  218. package/dist/table/TableView.js +508 -0
  219. package/dist/table/command-field.d.ts +57 -0
  220. package/dist/table/command-field.js +203 -0
  221. package/dist/table/grid-rows.d.ts +23 -0
  222. package/dist/table/grid-rows.js +55 -0
  223. package/dist/table/import-mapping.d.ts +7 -0
  224. package/dist/table/import-mapping.js +28 -0
  225. package/dist/table/layout-store.d.ts +13 -0
  226. package/dist/table/layout-store.js +43 -0
  227. package/dist/table/paging.d.ts +12 -0
  228. package/dist/table/paging.js +20 -0
  229. package/dist/table/pending.d.ts +32 -0
  230. package/dist/table/pending.js +94 -0
  231. package/dist/table/references.d.ts +12 -0
  232. package/dist/table/references.js +21 -0
  233. package/dist/table/useLoaded.d.ts +7 -0
  234. package/dist/table/useLoaded.js +36 -0
  235. package/dist/table/useStoredLayout.d.ts +8 -0
  236. package/dist/table/useStoredLayout.js +39 -0
  237. package/dist/table/useTableTransfer.d.ts +51 -0
  238. package/dist/table/useTableTransfer.js +125 -0
  239. package/dist/testing/fake.d.ts +21 -0
  240. package/dist/testing/fake.js +372 -0
  241. package/dist/testing/index.d.ts +1 -0
  242. package/dist/testing/index.js +1 -0
  243. package/dist/use-popup-press.d.ts +1 -0
  244. package/dist/use-popup-press.js +24 -0
  245. package/dist/use-schema-change.d.ts +1 -0
  246. package/dist/use-schema-change.js +13 -0
  247. package/dist/use-stable-callback.d.ts +1 -0
  248. package/dist/use-stable-callback.js +9 -0
  249. package/dist/value/ValuePanel.d.ts +14 -0
  250. package/dist/value/ValuePanel.js +103 -0
  251. package/dist/value/draft.d.ts +33 -0
  252. package/dist/value/draft.js +44 -0
  253. package/dist/value/hex.d.ts +14 -0
  254. package/dist/value/hex.js +46 -0
  255. package/dist/value/json.d.ts +9 -0
  256. package/dist/value/json.js +71 -0
  257. package/dist/value/views.d.ts +22 -0
  258. package/dist/value/views.js +54 -0
  259. package/dist/workbench/DatabaseWorkbench.d.ts +9 -0
  260. package/dist/workbench/DatabaseWorkbench.js +179 -0
  261. package/dist/workbench/DesignerTab.d.ts +10 -0
  262. package/dist/workbench/DesignerTab.js +22 -0
  263. package/dist/workbench/TableTab.d.ts +10 -0
  264. package/dist/workbench/TableTab.js +8 -0
  265. package/dist/workbench/tabs.d.ts +42 -0
  266. package/dist/workbench/tabs.js +139 -0
  267. package/package.json +79 -3
  268. package/src/DatabaseProvider.tsx +37 -0
  269. package/src/actions.ts +34 -0
  270. package/src/client/client.ts +324 -0
  271. package/src/client/index.ts +18 -0
  272. package/src/client/types.ts +161 -0
  273. package/src/client-context.ts +35 -0
  274. package/src/connections/ConnectionForm.tsx +474 -0
  275. package/src/connections/ConnectionManager.tsx +224 -0
  276. package/src/connections/EngineIcon.tsx +18 -0
  277. package/src/connections/connection-config.ts +143 -0
  278. package/src/connections/docker.ts +50 -0
  279. package/src/connections/engine-icons.ts +5 -0
  280. package/src/connections/use-docker-containers.ts +41 -0
  281. package/src/console/DestructiveDialog.tsx +40 -0
  282. package/src/console/HistoryPanel.tsx +67 -0
  283. package/src/console/QueryConsole.tsx +439 -0
  284. package/src/console/SchemaPicker.tsx +32 -0
  285. package/src/console/SqlEditor.tsx +95 -0
  286. package/src/console/StatementResultView.tsx +176 -0
  287. package/src/console/TransactionControls.tsx +53 -0
  288. package/src/console/destructive.ts +60 -0
  289. package/src/console/editing.ts +77 -0
  290. package/src/console/history.ts +62 -0
  291. package/src/console/labels.ts +7 -0
  292. package/src/console/outcome.ts +14 -0
  293. package/src/console/schemas.ts +7 -0
  294. package/src/console/shortcuts.ts +4 -0
  295. package/src/console/useConsoleHistory.ts +39 -0
  296. package/src/ddl/alter-mysql.ts +90 -0
  297. package/src/ddl/alter-sqlite.ts +93 -0
  298. package/src/ddl/alter.ts +29 -0
  299. package/src/ddl/column.ts +74 -0
  300. package/src/ddl/create.ts +92 -0
  301. package/src/ddl/dialect.ts +53 -0
  302. package/src/ddl/diff.ts +164 -0
  303. package/src/ddl/draft.ts +136 -0
  304. package/src/ddl/index.ts +10 -0
  305. package/src/ddl/parse.ts +161 -0
  306. package/src/ddl/statements.ts +20 -0
  307. package/src/ddl/types.ts +60 -0
  308. package/src/ddl/validate.ts +47 -0
  309. package/src/designer/ColumnsEditor.tsx +204 -0
  310. package/src/designer/DesignerView.tsx +184 -0
  311. package/src/designer/ForeignKeysEditor.tsx +132 -0
  312. package/src/designer/IndexesEditor.tsx +63 -0
  313. package/src/designer/NamePicker.tsx +44 -0
  314. package/src/designer/OptionsEditor.tsx +101 -0
  315. package/src/designer/SqlPreview.tsx +56 -0
  316. package/src/designer/TableDesigner.tsx +186 -0
  317. package/src/designer/edit.ts +137 -0
  318. package/src/designer/editor-props.ts +13 -0
  319. package/src/designer/plan.ts +25 -0
  320. package/src/designer/recover.ts +20 -0
  321. package/src/designer/useReferenceColumns.ts +54 -0
  322. package/src/explorer/DatabaseExplorer.tsx +450 -0
  323. package/src/explorer/RowMenu.tsx +134 -0
  324. package/src/explorer/TableDialog.tsx +80 -0
  325. package/src/explorer/expansion.ts +47 -0
  326. package/src/explorer/table-statements.ts +18 -0
  327. package/src/explorer/tree.ts +453 -0
  328. package/src/explorer/use-explorer-loads.ts +157 -0
  329. package/src/explorer/use-stored-expansion.ts +66 -0
  330. package/src/grid/CellEditor.tsx +53 -0
  331. package/src/grid/CopyAsMenu.tsx +33 -0
  332. package/src/grid/DataGrid.tsx +871 -0
  333. package/src/grid/EnumPicker.tsx +108 -0
  334. package/src/grid/GridHeaderCell.tsx +243 -0
  335. package/src/grid/RecordView.tsx +293 -0
  336. package/src/grid/ValueDock.tsx +52 -0
  337. package/src/grid/aggregates.ts +94 -0
  338. package/src/grid/cell-range.ts +26 -0
  339. package/src/grid/column-layout.ts +71 -0
  340. package/src/grid/column-selection.ts +42 -0
  341. package/src/grid/column-view.ts +35 -0
  342. package/src/grid/copy-formats.ts +108 -0
  343. package/src/grid/display.ts +109 -0
  344. package/src/grid/edit-value.ts +60 -0
  345. package/src/grid/enum-type.ts +62 -0
  346. package/src/grid/focused-value.ts +23 -0
  347. package/src/grid/layout.ts +91 -0
  348. package/src/grid/navigation.ts +74 -0
  349. package/src/grid/row-selection.ts +35 -0
  350. package/src/grid/sort.ts +12 -0
  351. package/src/grid/types.ts +59 -0
  352. package/src/host/helper-path.ts +41 -0
  353. package/src/host/host.ts +456 -0
  354. package/src/host/index.ts +5 -0
  355. package/src/host/spawn.ts +124 -0
  356. package/src/host/types.ts +46 -0
  357. package/src/host/validate.ts +402 -0
  358. package/src/index.ts +37 -0
  359. package/src/locales/en.json +577 -0
  360. package/src/locales/nl.json +577 -0
  361. package/src/locales.ts +18 -0
  362. package/src/protocol/connection.ts +86 -0
  363. package/src/protocol/errors.ts +38 -0
  364. package/src/protocol/index.ts +33 -0
  365. package/src/protocol/messages.ts +168 -0
  366. package/src/protocol/schema.ts +76 -0
  367. package/src/protocol/values.ts +52 -0
  368. package/src/sql-split.ts +220 -0
  369. package/src/sql.ts +152 -0
  370. package/src/structure/StructureView.tsx +269 -0
  371. package/src/structure/structure-text.ts +4 -0
  372. package/src/table/CommandField.tsx +318 -0
  373. package/src/table/ImportDialog.tsx +168 -0
  374. package/src/table/TableStatusBar.tsx +91 -0
  375. package/src/table/TableToolbar.tsx +217 -0
  376. package/src/table/TableView.tsx +880 -0
  377. package/src/table/command-field.ts +285 -0
  378. package/src/table/grid-rows.ts +80 -0
  379. package/src/table/import-mapping.ts +37 -0
  380. package/src/table/layout-store.ts +62 -0
  381. package/src/table/paging.ts +33 -0
  382. package/src/table/pending.ts +143 -0
  383. package/src/table/references.ts +38 -0
  384. package/src/table/useLoaded.ts +58 -0
  385. package/src/table/useStoredLayout.ts +53 -0
  386. package/src/table/useTableTransfer.ts +187 -0
  387. package/src/testing/fake.ts +533 -0
  388. package/src/testing/index.ts +1 -0
  389. package/src/use-popup-press.ts +27 -0
  390. package/src/use-schema-change.ts +19 -0
  391. package/src/use-stable-callback.ts +12 -0
  392. package/src/value/ValuePanel.tsx +254 -0
  393. package/src/value/draft.ts +72 -0
  394. package/src/value/hex.ts +62 -0
  395. package/src/value/json.ts +74 -0
  396. package/src/value/views.ts +68 -0
  397. package/src/workbench/DatabaseWorkbench.tsx +348 -0
  398. package/src/workbench/DesignerTab.tsx +37 -0
  399. package/src/workbench/TableTab.tsx +27 -0
  400. package/src/workbench/tabs.ts +184 -0
@@ -0,0 +1,508 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from 'react';
3
+ import clsx from 'clsx';
4
+ import { ArrowDownWideNarrow, ArrowUpRight, Check, CircleAlert, CopyPlus, Download, Filter, FilterX, RefreshCw, Trash2, Undo2 } from 'lucide-react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Banner, Button, ContextMenu, Icon, isApplePlatform, Kbd, KEY_SHORTCUTS, matchesShortcut, messageOf, PanelEmpty, PromptDialog, shortcut, Spinner } from '@adecore/ui';
7
+ import { formatNumber } from '@adecore/ui/format';
8
+ import { DatabaseRequestError } from '../client/types.js';
9
+ import { useDatabaseAction, useDatabaseClient, useDatabaseFiles, useDatabaseStorage } from '../client-context.js';
10
+ import { aggregateBlock, blockSize } from '../grid/aggregates.js';
11
+ import { DataGrid } from '../grid/DataGrid.js';
12
+ import { wholeValueOf } from '../grid/focused-value.js';
13
+ import { RecordView } from '../grid/RecordView.js';
14
+ import { ValueDock } from '../grid/ValueDock.js';
15
+ import { valueOfCell } from '../protocol/index.js';
16
+ import { useSchemaChange } from '../use-schema-change.js';
17
+ import { ValuePanel } from '../value/ValuePanel.js';
18
+ import { addChip, cellChip, chipsFromQuery, chipsToOrderBy, chipsToWhere, shorten, sortsOf, toggleSort, withSorts } from './command-field.js';
19
+ import { buildGridColumns, buildGridRows, cloneValues, parseRowKey } from './grid-rows.js';
20
+ import { importableColumns } from './import-mapping.js';
21
+ import { ImportDialog } from './ImportDialog.js';
22
+ import { layoutStorageKey } from './layout-store.js';
23
+ import { DEFAULT_PAGE_SIZE, lastPageOffset, pageBounds } from './paging.js';
24
+ import { addInsertWith, describeKey, emptyPending, hasRowChanges, isPendingEmpty, markDeleted, pendingCount, removeInsert, revertRows, rowKeyOf, setEdit, setInsertValue, toRowChanges } from './pending.js';
25
+ import { foreignKeyOf, referenceOf } from './references.js';
26
+ import { TableStatusBar } from './TableStatusBar.js';
27
+ import { TableToolbar } from './TableToolbar.js';
28
+ import { useLoaded } from './useLoaded.js';
29
+ import { useStoredLayout } from './useStoredLayout.js';
30
+ import { useTableTransfer } from './useTableTransfer.js';
31
+ const NO_KEYS = new Set();
32
+ /* How much of a value a menu item spells out before it cuts it. */
33
+ const MENU_VALUE_LENGTH = 40;
34
+ const FOCUS_COMMAND = shortcut('Mod+F');
35
+ const DUPLICATE_ROWS = shortcut('Mod+D');
36
+ /*
37
+ * The rows of one table: read a page at a time, filtered and sorted with SQL a person types, and
38
+ * editable in place. Changes pile up as pending and go to the server together on Submit.
39
+ */
40
+ export function TableView({ connection, schema, table, defaultWhere, defaultOrderBy, onDirtyChange, className, ref }) {
41
+ // A new table, or the same one asked for with other filters, starts from nothing: no page, no pending change.
42
+ return (_jsx(TableBody, { connection: connection, schema: schema, table: table, defaultWhere: defaultWhere, defaultOrderBy: defaultOrderBy, onDirtyChange: onDirtyChange, className: className, ref: ref }, [connection.id, schema, table, defaultWhere ?? '', defaultOrderBy ?? ''].join('\u0000')));
43
+ }
44
+ function TableBody({ connection, schema, table, defaultWhere, defaultOrderBy, onDirtyChange, className, ref }) {
45
+ const { t } = useTranslation('database');
46
+ const client = useDatabaseClient();
47
+ const onAction = useDatabaseAction();
48
+ const files = useDatabaseFiles();
49
+ const { stored, remember } = useStoredLayout(useDatabaseStorage(), layoutStorageKey(connection.id, schema, table));
50
+ const session = useMemo(() => client.session(connection), [client, connection]);
51
+ const grid = useRef(null);
52
+ const command = useRef(null);
53
+ const lifetime = useRef(null);
54
+ const counter = useRef(null);
55
+ const insertedBefore = useRef(0);
56
+ const engine = connection.config.engine;
57
+ const [chips, setChips] = useState(() => chipsFromQuery(engine, {
58
+ where: defaultWhere ?? stored?.where ?? '',
59
+ orderBy: defaultOrderBy ?? stored?.orderBy ?? '',
60
+ remembered: defaultWhere === undefined ? stored?.filters : undefined
61
+ }));
62
+ const [offset, setOffset] = useState(0);
63
+ const [pageSize, setPageSize] = useState(stored?.pageSize ?? DEFAULT_PAGE_SIZE);
64
+ const [pending, setPending] = useState(emptyPending);
65
+ const [selected, setSelected] = useState(NO_KEYS);
66
+ const [counted, setCounted] = useState(null);
67
+ const [counting, setCounting] = useState(false);
68
+ const [submitting, setSubmitting] = useState(false);
69
+ const [failure, setFailure] = useState(null);
70
+ const [shapeChanged, setShapeChanged] = useState(false);
71
+ const [discard, setDiscard] = useState(null);
72
+ const [panelOpen, setPanelOpen] = useState(false);
73
+ const [focus, setFocus] = useState(null);
74
+ const [recordOpen, setRecordOpen] = useState(false);
75
+ const [recordKey, setRecordKey] = useState(null);
76
+ const [focusRequest, setFocusRequest] = useState(null);
77
+ const [columnRequest, setColumnRequest] = useState(null);
78
+ const [range, setRange] = useState(null);
79
+ const [fetched, setFetched] = useState(null);
80
+ const applied = useMemo(() => ({ where: chipsToWhere(chips), orderBy: chipsToOrderBy(engine, chips) }), [chips, engine]);
81
+ const target = `${connection.id}|${schema}|${table}`;
82
+ const structureLoad = useLoaded((signal) => session.structure(schema, table, { signal }), target);
83
+ // The offset travels with the page it belongs to, since the page on screen lags behind the one asked for.
84
+ const rowsLoad = useLoaded(async (signal) => ({
85
+ result: await session.rows(schema, table, { where: applied.where || undefined, orderBy: applied.orderBy || undefined, offset, limit: pageSize }, { signal }),
86
+ offset
87
+ }), JSON.stringify([target, applied, offset, pageSize]));
88
+ const structure = structureLoad.value;
89
+ const loaded = rowsLoad.value?.result ?? null;
90
+ const loadedOffset = rowsLoad.value?.offset ?? 0;
91
+ const readOnlyReason = connection.config.readOnly === true
92
+ ? t('table.readOnly.connection')
93
+ : structure === null
94
+ ? null
95
+ : structure.kind === 'view'
96
+ ? t('table.readOnly.view')
97
+ : structure.rowKey === null
98
+ ? t('table.readOnly.noKey')
99
+ : null;
100
+ const editable = readOnlyReason === null && structure !== null && loaded !== null && !rowsLoad.loading;
101
+ const columns = useMemo(() => (loaded === null ? [] : buildGridColumns(loaded, structure)), [loaded, structure]);
102
+ const rows = useMemo(() => (loaded === null ? [] : buildGridRows({ structure, loaded, pending, offset: loadedOffset })), [loaded, structure, pending, loadedOffset]);
103
+ const transfer = useTableTransfer({
104
+ client,
105
+ session,
106
+ files,
107
+ schema,
108
+ table,
109
+ structure,
110
+ where: applied.where,
111
+ orderBy: applied.orderBy,
112
+ onImported: () => {
113
+ setCounted(null);
114
+ rowsLoad.reload();
115
+ }
116
+ });
117
+ const changeCount = pendingCount(pending);
118
+ const dirty = changeCount > 0;
119
+ const reportDirty = useRef(onDirtyChange);
120
+ const reportedDirty = useRef(false);
121
+ const sorts = useMemo(() => sortsOf(chips), [chips]);
122
+ const commandColumns = useMemo(() => columns.map((column) => ({ name: column.name, type: column.type })), [columns]);
123
+ const rowByKey = useMemo(() => new Map(rows.map((row) => [row.key, row])), [rows]);
124
+ const recordIndex = Math.max(0, rows.findIndex((row) => row.key === recordKey));
125
+ const selectionFigures = useMemo(() => recordOpen || range === null || blockSize(range) < 2
126
+ ? null
127
+ : {
128
+ columns: range.columns.map((index) => columns[index]?.name ?? ''),
129
+ aggregates: aggregateBlock(rows.map((row) => row.cells), columns.map((column) => column.kind), range)
130
+ }, [recordOpen, range, rows, columns]);
131
+ const sqlTarget = useMemo(() => ({ engine, schema, table }), [engine, schema, table]);
132
+ const focusedRow = panelOpen && focus !== null ? rows.find((row) => row.key === focus.rowKey) : undefined;
133
+ const focusedCell = focus === null ? undefined : focusedRow?.cells[focus.column];
134
+ const needsFetch = focusedCell !== undefined &&
135
+ focus !== null &&
136
+ wholeValueOf(focusedCell) === undefined &&
137
+ !(focusedCell !== null && typeof focusedCell === 'object' && focusedCell.kind === 'default');
138
+ const focusedRef = focus === null ? null : parseRowKey(focus.rowKey);
139
+ const canFetch = focusedRef?.kind === 'loaded' && structure !== null && loaded !== null && rowKeyOf(structure, loaded, focusedRef.index) !== null;
140
+ const fetchId = needsFetch && canFetch ? `${focus.rowKey}:${focus.column}` : null;
141
+ useSchemaChange(connection.id, schema, () => {
142
+ if (isPendingEmpty(pending)) {
143
+ setCounted(null);
144
+ structureLoad.reload();
145
+ rowsLoad.reload();
146
+ }
147
+ else {
148
+ setShapeChanged(true);
149
+ }
150
+ });
151
+ useEffect(() => {
152
+ reportDirty.current = onDirtyChange;
153
+ });
154
+ useEffect(() => {
155
+ if (dirty !== reportedDirty.current) {
156
+ reportedDirty.current = dirty;
157
+ reportDirty.current?.(dirty);
158
+ }
159
+ }, [dirty]);
160
+ useEffect(() => {
161
+ const controller = new AbortController();
162
+ lifetime.current = controller;
163
+ return () => {
164
+ controller.abort();
165
+ counter.current?.abort();
166
+ };
167
+ }, []);
168
+ useEffect(() => {
169
+ if (pending.inserts.length > insertedBefore.current && grid.current !== null) {
170
+ grid.current.scrollTop = grid.current.scrollHeight;
171
+ }
172
+ insertedBefore.current = pending.inserts.length;
173
+ }, [pending.inserts.length]);
174
+ useEffect(() => {
175
+ if (fetchId === null || focus === null || structure === null || loaded === null) {
176
+ return;
177
+ }
178
+ const row = parseRowKey(focus.rowKey);
179
+ const key = row.kind === 'loaded' ? rowKeyOf(structure, loaded, row.index) : null;
180
+ const name = loaded.columns[focus.column]?.name;
181
+ if (key === null || name === undefined) {
182
+ return;
183
+ }
184
+ const controller = new AbortController();
185
+ session.cell(schema, table, key, name, { signal: controller.signal }).then((value) => {
186
+ if (!controller.signal.aborted) {
187
+ setFetched({ id: fetchId, rows: loaded, value });
188
+ }
189
+ }, (error) => {
190
+ if (!controller.signal.aborted) {
191
+ setFetched({ id: fetchId, rows: loaded, value: undefined });
192
+ setFailure(messageOf(error));
193
+ }
194
+ });
195
+ return () => controller.abort();
196
+ }, [fetchId, focus, structure, loaded, session, schema, table]);
197
+ const discardPending = () => {
198
+ setPending(emptyPending);
199
+ setSelected(NO_KEYS);
200
+ };
201
+ /* Anything that replaces the page asks first when it would throw pending changes away. */
202
+ const guard = (action) => {
203
+ if (isPendingEmpty(pending)) {
204
+ action();
205
+ }
206
+ else {
207
+ setDiscard({
208
+ run: () => {
209
+ discardPending();
210
+ action();
211
+ }
212
+ });
213
+ }
214
+ };
215
+ /* Every change of the chips applies at once; one that changes the page asks first when it would throw pending changes away. */
216
+ const applyChips = (next) => {
217
+ const where = chipsToWhere(next);
218
+ const orderBy = chipsToOrderBy(engine, next);
219
+ const filters = next.filter((chip) => chip.kind === 'filter').map(({ text, sql }) => ({ text, sql }));
220
+ if (where === applied.where && orderBy === applied.orderBy) {
221
+ remember({ filters });
222
+ setChips([...next]);
223
+ return;
224
+ }
225
+ guard(() => {
226
+ remember({ where, orderBy, filters });
227
+ counter.current?.abort();
228
+ setCounting(false);
229
+ setCounted(null);
230
+ setOffset(0);
231
+ setSelected(NO_KEYS);
232
+ setFailure(null);
233
+ setChips([...next]);
234
+ });
235
+ };
236
+ const changeSorts = (next) => {
237
+ applyChips(withSorts(chips, next));
238
+ };
239
+ const cellChipAt = (cell, exclude) => {
240
+ const row = parseRowKey(cell.rowKey);
241
+ const column = loaded?.columns[cell.column];
242
+ const value = loaded === null || row.kind !== 'loaded' ? undefined : valueOfCell(loaded.rows[row.index]?.[cell.column] ?? null);
243
+ return column === undefined || value === undefined ? null : cellChip(engine, column.name, value, column.kind, exclude);
244
+ };
245
+ const sortByColumn = (cell) => {
246
+ const name = columns[cell.column]?.name;
247
+ if (name !== undefined) {
248
+ applyChips(toggleSort(chips, name));
249
+ }
250
+ };
251
+ const jumpToColumn = (name) => {
252
+ const index = columns.findIndex((column) => column.name === name);
253
+ if (index >= 0) {
254
+ setRecordOpen(false);
255
+ setColumnRequest({ column: index });
256
+ }
257
+ };
258
+ const refresh = () => {
259
+ guard(() => {
260
+ setCounted(null);
261
+ setFailure(null);
262
+ setShapeChanged(false);
263
+ structureLoad.reload();
264
+ rowsLoad.reload();
265
+ });
266
+ };
267
+ const goToPage = (nextOffset) => {
268
+ guard(() => {
269
+ setOffset(Math.max(0, nextOffset));
270
+ setSelected(NO_KEYS);
271
+ });
272
+ };
273
+ const changePageSize = (size) => {
274
+ guard(() => {
275
+ remember({ pageSize: size });
276
+ setPageSize(size);
277
+ setOffset(0);
278
+ });
279
+ };
280
+ const countRows = async () => {
281
+ const controller = new AbortController();
282
+ counter.current?.abort();
283
+ counter.current = controller;
284
+ setCounting(true);
285
+ try {
286
+ const total = await session.count(schema, table, applied.where || undefined, { signal: controller.signal });
287
+ if (!controller.signal.aborted) {
288
+ setCounted(total);
289
+ return total;
290
+ }
291
+ }
292
+ catch (error) {
293
+ if (!controller.signal.aborted) {
294
+ setFailure(messageOf(error));
295
+ }
296
+ }
297
+ finally {
298
+ if (!controller.signal.aborted) {
299
+ setCounting(false);
300
+ }
301
+ }
302
+ return null;
303
+ };
304
+ const goToLast = async () => {
305
+ const total = counted ?? (await countRows());
306
+ if (total !== null) {
307
+ goToPage(lastPageOffset(total, pageSize));
308
+ }
309
+ };
310
+ const commit = (rowKey, column, value) => {
311
+ const name = loaded?.columns[column]?.name;
312
+ const row = parseRowKey(rowKey);
313
+ if (loaded === null || name === undefined) {
314
+ return;
315
+ }
316
+ if (row.kind === 'inserted') {
317
+ setPending((now) => setInsertValue(now, row.id, name, value));
318
+ }
319
+ else {
320
+ setPending((now) => setEdit(now, row.index, name, value, loaded.rows[row.index][column] ?? null));
321
+ }
322
+ };
323
+ const loadValue = async (rowKey, column) => {
324
+ const row = parseRowKey(rowKey);
325
+ const name = loaded?.columns[column]?.name;
326
+ const key = row.kind === 'loaded' && structure !== null && loaded !== null ? rowKeyOf(structure, loaded, row.index) : null;
327
+ if (key === null || name === undefined) {
328
+ return undefined;
329
+ }
330
+ try {
331
+ return await session.cell(schema, table, key, name, { signal: lifetime.current?.signal });
332
+ }
333
+ catch (error) {
334
+ setFailure(messageOf(error));
335
+ return undefined;
336
+ }
337
+ };
338
+ const refsOf = (keys) => {
339
+ const loadedRows = [];
340
+ const inserted = [];
341
+ for (const key of keys) {
342
+ const row = parseRowKey(key);
343
+ if (row.kind === 'inserted') {
344
+ inserted.push(row.id);
345
+ }
346
+ else {
347
+ loadedRows.push(row.index);
348
+ }
349
+ }
350
+ return { loaded: loadedRows, inserted };
351
+ };
352
+ const deleteRows = (keys) => {
353
+ setPending((now) => {
354
+ const refs = refsOf(keys);
355
+ const next = refs.inserted.reduce(removeInsert, now);
356
+ return markDeleted(next, refs.loaded.filter((index) => loaded !== null && structure !== null && rowKeyOf(structure, loaded, index) !== null));
357
+ });
358
+ setSelected(NO_KEYS);
359
+ };
360
+ const deleteSelected = () => deleteRows(selected);
361
+ const cloneRows = (keys) => {
362
+ const wanted = new Set(keys);
363
+ const copies = rows.filter((row) => wanted.has(row.key)).map((row) => cloneValues(columns, row.cells));
364
+ setPending((now) => copies.reduce(addInsertWith, now));
365
+ };
366
+ const revertRowKeys = (keys) => {
367
+ setPending((now) => revertRows(now, refsOf(keys)));
368
+ };
369
+ const canRevert = (keys) => hasRowChanges(pending, refsOf(keys));
370
+ const referenceAt = (cell) => {
371
+ const column = columns[cell.column];
372
+ const key = column === undefined || structure === null ? undefined : foreignKeyOf(structure.foreignKeys, column.name);
373
+ const row = rowByKey.get(cell.rowKey);
374
+ return key === undefined || row === undefined ? null : referenceOf(engine, key, columns, row.cells);
375
+ };
376
+ const isReferenceColumn = (column) => {
377
+ const name = columns[column]?.name;
378
+ return name !== undefined && structure !== null && foreignKeyOf(structure.foreignKeys, name) !== undefined;
379
+ };
380
+ const follow = (cell) => {
381
+ const reference = referenceAt(cell);
382
+ if (reference !== null) {
383
+ onAction?.({
384
+ kind: 'open-table',
385
+ ref: { connectionId: connection.id, schema: reference.schema, table: reference.table },
386
+ view: 'data',
387
+ where: reference.where
388
+ });
389
+ }
390
+ };
391
+ const toggleRecordView = () => {
392
+ if (recordOpen) {
393
+ const row = rows[recordIndex];
394
+ setRecordOpen(false);
395
+ if (row !== undefined) {
396
+ setFocusRequest({ rowKey: row.key, column: focus?.column ?? 0 });
397
+ }
398
+ return;
399
+ }
400
+ const focused = focus === null ? undefined : rows.find((row) => row.key === focus.rowKey);
401
+ setRecordKey((focused ?? rows[0])?.key ?? null);
402
+ setRecordOpen(true);
403
+ };
404
+ const changeRecordIndex = (index) => {
405
+ const row = rows[index];
406
+ if (row !== undefined) {
407
+ setRecordKey(row.key);
408
+ setFocus((now) => (now === null ? now : { rowKey: row.key, column: now.column }));
409
+ }
410
+ };
411
+ const queryMenu = (context) => {
412
+ const cell = context.cell;
413
+ const name = cell === null ? undefined : columns[cell.column]?.name;
414
+ if (cell === null || name === undefined) {
415
+ return null;
416
+ }
417
+ const include = cellChipAt(cell, false);
418
+ const exclude = cellChipAt(cell, true);
419
+ return (_jsxs(_Fragment, { children: [_jsxs(ContextMenu.Item, { disabled: include === null, onClick: () => include !== null && applyChips(addChip(chips, include)), children: [_jsx(Icon, { icon: Filter, size: 14 }), t('table.menu.filterOn'), " ", _jsx("span", { className: "font-mono", children: shorten(include?.text ?? name, MENU_VALUE_LENGTH) })] }), _jsxs(ContextMenu.Item, { disabled: exclude === null, onClick: () => exclude !== null && applyChips(addChip(chips, exclude)), children: [_jsx(Icon, { icon: FilterX, size: 14 }), t('table.menu.exclude'), " ", _jsx("span", { className: "font-mono", children: shorten(exclude?.text ?? name, MENU_VALUE_LENGTH) })] }), _jsxs(ContextMenu.Item, { onClick: () => sortByColumn(cell), children: [_jsx(Icon, { icon: ArrowDownWideNarrow, size: 14 }), t('table.menu.sortBy'), " ", _jsx("span", { className: "font-mono", children: name })] }), onAction !== undefined && isReferenceColumn(cell.column) && (_jsxs(ContextMenu.Item, { disabled: referenceAt(cell) === null, onClick: () => follow(cell), children: [_jsx(Icon, { icon: ArrowUpRight, size: 14 }), t('table.goToReferenced')] }))] }));
420
+ };
421
+ const gridMenu = (context) => {
422
+ const count = context.rowKeys.length;
423
+ return (_jsxs(_Fragment, { children: [_jsxs(ContextMenu.Item, { disabled: !editable, onClick: () => cloneRows(context.rowKeys), children: [_jsx(Icon, { icon: CopyPlus, size: 14 }), t('table.menu.duplicateRows', { count, formatted: formatNumber(count) }), _jsx(Kbd, { shortcut: DUPLICATE_ROWS })] }), canRevert(context.rowKeys) && (_jsxs(ContextMenu.Item, { onClick: () => revertRowKeys(context.rowKeys), children: [_jsx(Icon, { icon: Undo2, size: 14 }), t('table.menu.revertRows', { count, formatted: formatNumber(count) })] })), _jsxs(ContextMenu.Item, { className: "text-status-error", disabled: !editable, onClick: () => deleteRows(context.rowKeys), children: [_jsx(Icon, { icon: Trash2, size: 14 }), t('table.menu.deleteRows', { count, formatted: formatNumber(count) }), _jsx(Kbd, { shortcut: KEY_SHORTCUTS.backspace })] })] }));
424
+ };
425
+ const conflictMessage = (error, changes) => {
426
+ const change = error.change === undefined ? undefined : changes[error.change];
427
+ if (error.change === undefined || change === undefined || change.kind === 'insert') {
428
+ return error.message;
429
+ }
430
+ return t('table.conflict', { number: formatNumber(error.change + 1), row: describeKey(change.key) });
431
+ };
432
+ const submit = async () => {
433
+ if (structure === null || loaded === null) {
434
+ return;
435
+ }
436
+ const changes = toRowChanges(structure, loaded, pending);
437
+ setSubmitting(true);
438
+ setFailure(null);
439
+ try {
440
+ await session.apply(schema, table, changes);
441
+ discardPending();
442
+ setCounted(null);
443
+ rowsLoad.reload();
444
+ }
445
+ catch (error) {
446
+ setFailure(error instanceof DatabaseRequestError && error.code === 'conflict' ? conflictMessage(error, changes) : messageOf(error));
447
+ }
448
+ finally {
449
+ setSubmitting(false);
450
+ }
451
+ };
452
+ const handleKeyDown = (event) => {
453
+ // A dialog opened from here is a portal: its events reach this handler through React, not through the DOM.
454
+ if (!event.nativeEvent.isComposing &&
455
+ event.currentTarget.contains(event.target) &&
456
+ matchesShortcut(FOCUS_COMMAND, event.nativeEvent, isApplePlatform())) {
457
+ event.preventDefault();
458
+ command.current?.focus();
459
+ command.current?.select();
460
+ }
461
+ };
462
+ const bounds = pageBounds(loadedOffset, loaded?.rows.length ?? 0, loaded?.hasMore ?? false, counted);
463
+ const focusedColumn = focus === null ? null : (columns[focus.column] ?? null);
464
+ const panelEditable = editable && focusedRow !== undefined && focusedRow.locked !== true && focusedRow.state !== 'deleted' && focusedColumn?.readOnly !== true;
465
+ const fetchedNow = fetched !== null && fetched.id === fetchId && fetched.rows === loaded;
466
+ const panelValue = (() => {
467
+ if (focusedCell === undefined || focusedRow === undefined || focus === null) {
468
+ return undefined;
469
+ }
470
+ const whole = wholeValueOf(focusedCell);
471
+ if (whole !== undefined) {
472
+ return whole;
473
+ }
474
+ if (focusedCell !== null && typeof focusedCell === 'object' && focusedCell.kind === 'default') {
475
+ // A pending DEFAULT holds no value of its own, so the panel keeps showing what the row had.
476
+ const row = parseRowKey(focusedRow.key);
477
+ return row.kind === 'loaded' && loaded !== null ? wholeValueOf(loaded.rows[row.index]?.[focus.column] ?? null) : null;
478
+ }
479
+ return fetchedNow ? fetched.value : undefined;
480
+ })();
481
+ const notice = failure ?? rowsLoad.error ?? structureLoad.error;
482
+ const noticeText = (found) => {
483
+ switch (found.kind) {
484
+ case 'exporting':
485
+ return t('table.export.running', { format: found.format.toUpperCase() });
486
+ case 'exported':
487
+ return t('table.export.done', { count: found.rows, rows: formatNumber(found.rows) });
488
+ case 'imported':
489
+ return t('table.import.done', { count: found.rows, rows: formatNumber(found.rows) });
490
+ case 'failed':
491
+ return found.message;
492
+ }
493
+ };
494
+ return (_jsxs("div", { ref: ref, className: clsx('flex min-h-0 flex-col bg-surface text-text', className), onKeyDown: handleKeyDown, children: [_jsx(TableToolbar, { refreshing: rowsLoad.loading, readOnlyReason: readOnlyReason, hasSelection: selected.size > 0, canRevertSelection: selected.size > 0 && canRevert(selected), valuePanelOpen: panelOpen, recordViewOpen: recordOpen, transfer: files === undefined
495
+ ? undefined
496
+ : {
497
+ busy: transfer.notice?.kind === 'exporting',
498
+ onExport: transfer.exportAs,
499
+ onImport: readOnlyReason === null && structure !== null ? () => guard(transfer.chooseImportFile) : undefined
500
+ }, pendingCount: changeCount, submitting: submitting, engine: engine, chips: chips, columns: commandColumns, pageSize: pageSize, bounds: bounds, commandRef: command, onChipsChange: applyChips, onJumpToColumn: jumpToColumn, onRefresh: refresh, onAddRow: () => setPending((now) => addInsertWith(now, {})), onDeleteRows: deleteSelected, onCloneRows: () => cloneRows([...selected]), onRevertRows: () => revertRowKeys(selected), onToggleValuePanel: () => setPanelOpen((now) => !now), onToggleRecordView: toggleRecordView, onPageSizeChange: changePageSize, onFirstPage: () => goToPage(0), onLastPage: () => void goToLast(), onSubmit: () => void submit(), onRevert: discardPending }), notice !== null && (_jsx(Banner, { icon: CircleAlert, tone: "error", message: notice, className: "shrink-0 pt-2", children: failure === null ? (_jsx(Button, { size: "xs", onClick: refresh, children: t('table.retry') })) : (_jsx(Button, { size: "xs", onClick: () => setFailure(null), children: t('table.dismiss') })) })), shapeChanged && (_jsx(Banner, { icon: RefreshCw, tone: "neutral", message: t('table.changed'), className: "shrink-0 pt-2", children: _jsx(Button, { size: "xs", onClick: refresh, children: t('table.reload') }) })), transfer.notice !== null && (_jsx(Banner, { icon: transfer.notice.kind === 'failed' ? CircleAlert : transfer.notice.kind === 'exporting' ? Download : Check, tone: transfer.notice.kind === 'failed' ? 'error' : 'neutral', message: noticeText(transfer.notice), className: "shrink-0 pt-2", children: transfer.notice.kind === 'exporting' ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { size: 12, label: t('table.export.running', { format: transfer.notice.format.toUpperCase() }) }), _jsx(Button, { size: "xs", onClick: transfer.cancelExport, children: t('table.export.cancel') })] })) : (_jsx(Button, { size: "xs", onClick: transfer.dismiss, children: t('table.dismiss') })) })), loaded === null ? (_jsx(PanelEmpty, { busy: notice === null, children: notice === null ? t('table.loading') : t('table.notLoaded') })) : (_jsxs(_Fragment, { children: [_jsxs(ValueDock, { open: panelOpen, panel: _jsx(ValuePanel, { column: focusedColumn, value: panelValue, loading: fetchId !== null && !fetchedNow, editable: panelEditable, onCommit: (value) => focus !== null && commit(focus.rowKey, focus.column, value), onClose: () => setPanelOpen(false), className: "min-w-0 flex-1" }), children: [_jsx("div", { "aria-busy": rowsLoad.loading, className: clsx('relative min-h-0 flex-1 flex-col', recordOpen ? 'hidden' : 'flex', rowsLoad.loading && 'pointer-events-none opacity-60'), children: _jsx(DataGrid, { ref: grid, label: t('table.grid', { table }), columns: columns, rows: rows, editable: editable, empty: t('table.empty'), selectedKeys: selected, onSelectedKeysChange: setSelected, onCommit: commit, loadValue: loadValue, sorts: sorts, onSortsChange: changeSorts, onFocusedCellChange: setFocus, onDeleteSelected: editable ? deleteSelected : undefined, sqlTarget: sqlTarget, queryMenu: queryMenu, menu: gridMenu, onDuplicateRows: editable ? cloneRows : undefined, onFollow: onAction === undefined ? undefined : follow, canFollow: (cell) => referenceAt(cell) !== null, onRangeChange: setRange, initialLayout: stored ?? undefined, onLayoutChange: remember, focusRequest: focusRequest, columnRequest: columnRequest }) }), recordOpen && (_jsx(RecordView, { label: t('table.recordFields', { table }), columns: columns, rows: rows, index: recordIndex, onIndexChange: changeRecordIndex, editable: editable, onCommit: commit, loadValue: loadValue, onFocusedCellChange: setFocus, onFollow: onAction === undefined ? undefined : follow, canFollow: (cell) => referenceAt(cell) !== null, empty: t('table.empty') }))] }), _jsx(TableStatusBar, { elapsedMs: loaded.elapsedMs, bounds: bounds, counting: counting, selection: selectionFigures, onCount: () => void countRows(), onPrevious: () => goToPage(offset - pageSize), onNext: () => goToPage(offset + pageSize) })] })), transfer.importDraft !== null && structure !== null && (_jsx(ImportDialog, { open: true, path: transfer.importDraft.path, tableColumns: importableColumns(structure.columns), sample: transfer.importDraft.sample, header: transfer.importDraft.header, mapping: transfer.importDraft.mapping, busy: transfer.importDraft.busy, error: transfer.importDraft.error, onHeaderChange: transfer.changeHeader, onMappingChange: transfer.changeMapping, onImport: transfer.runImport, onCancel: transfer.closeImport, onOpenChange: (open) => !open && transfer.closeImport() })), _jsx(PromptDialog, { open: discard !== null, danger: true, title: t('table.discard.title'), description: t('table.discard.description'), confirmLabel: t('table.discard.confirm'), onConfirm: () => {
501
+ discard?.run();
502
+ setDiscard(null);
503
+ }, onOpenChange: (open) => {
504
+ if (!open) {
505
+ setDiscard(null);
506
+ }
507
+ } })] }));
508
+ }
@@ -0,0 +1,57 @@
1
+ import type { Engine, ValueKind } from '../protocol/index.ts';
2
+ import { type ColumnSort, type LiteralValue, type SortDirection } from '../sql.ts';
3
+ export interface FilterChip {
4
+ readonly kind: 'filter';
5
+ readonly text: string;
6
+ readonly sql: string;
7
+ }
8
+ export interface SortChip {
9
+ readonly kind: 'sort';
10
+ readonly column: string;
11
+ readonly direction: SortDirection;
12
+ }
13
+ export interface OrderChip {
14
+ readonly kind: 'order';
15
+ readonly text: string;
16
+ }
17
+ export type Chip = FilterChip | SortChip | OrderChip;
18
+ export type StoredFilter = Pick<FilterChip, 'text' | 'sql'>;
19
+ export interface CommandColumn {
20
+ readonly name: string;
21
+ readonly type: string;
22
+ }
23
+ export type Suggestion = {
24
+ readonly kind: 'condition';
25
+ readonly chip: FilterChip;
26
+ } | {
27
+ readonly kind: 'filter' | 'sort' | 'jump';
28
+ readonly column: CommandColumn;
29
+ } | {
30
+ readonly kind: 'sql';
31
+ readonly chip: FilterChip;
32
+ };
33
+ export declare const SUGGESTED_COLUMNS = 4;
34
+ export declare const chipKey: (chip: Chip) => string;
35
+ export declare const identifierText: (name: string) => string;
36
+ export declare const chipsToWhere: (chips: readonly Chip[]) => string;
37
+ export declare const chipsToOrderBy: (engine: Engine, chips: readonly Chip[]) => string;
38
+ export declare const sortsOf: (chips: readonly Chip[]) => ColumnSort[];
39
+ export declare const withSorts: (chips: readonly Chip[], sorts: readonly ColumnSort[]) => Chip[];
40
+ export declare const toggleSort: (chips: readonly Chip[], column: string) => Chip[];
41
+ export declare const addChip: (chips: readonly Chip[], chip: Chip) => Chip[];
42
+ export declare const removeChipAt: (chips: readonly Chip[], index: number) => Chip[];
43
+ export declare const replaceChipAt: (chips: readonly Chip[], index: number, chip: Chip) => Chip[];
44
+ export declare const filterChipsOf: (where: string, remembered?: readonly StoredFilter[]) => Chip[];
45
+ export declare const sortChipsOf: (engine: Engine, orderBy: string) => Chip[];
46
+ export interface ChipSource {
47
+ readonly where: string;
48
+ readonly orderBy: string;
49
+ readonly remembered?: readonly StoredFilter[];
50
+ }
51
+ export declare const chipsFromQuery: (engine: Engine, { where, orderBy, remembered }: ChipSource) => Chip[];
52
+ export declare const parseCondition: (engine: Engine, text: string, columns: readonly string[]) => FilterChip | null;
53
+ export declare const cellChip: (engine: Engine, column: string, value: LiteralValue, kind: ValueKind | undefined, exclude: boolean) => FilterChip;
54
+ export declare const shorten: (text: string, limit: number) => string;
55
+ export declare const matchColumns: (columns: readonly CommandColumn[], typed: string, limit?: number) => CommandColumn[];
56
+ export declare const suggest: (engine: Engine, text: string, columns: readonly CommandColumn[], limit?: number) => Suggestion[];
57
+ export declare const filterStartText: (column: CommandColumn) => string;