@everysk/apps-sdk 0.1.0 → 0.3.0-beta-20261016180126

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 (349) hide show
  1. package/README.md +395 -8
  2. package/dist/EveryskApp.d.ts +34 -2
  3. package/dist/EveryskApp.d.ts.map +1 -1
  4. package/dist/EveryskApp.js +35 -2
  5. package/dist/EveryskApp.js.map +1 -1
  6. package/dist/agGrid/handleRowsScrollEnd.d.ts +53 -0
  7. package/dist/agGrid/handleRowsScrollEnd.d.ts.map +1 -0
  8. package/dist/agGrid/handleRowsScrollEnd.js +47 -0
  9. package/dist/agGrid/handleRowsScrollEnd.js.map +1 -0
  10. package/dist/agGrid/index.d.ts +2 -0
  11. package/dist/agGrid/index.d.ts.map +1 -1
  12. package/dist/agGrid/index.js +2 -1
  13. package/dist/api/datastore.d.ts +10 -8
  14. package/dist/api/datastore.d.ts.map +1 -1
  15. package/dist/api/datastore.js +24 -55
  16. package/dist/api/datastore.js.map +1 -1
  17. package/dist/api/entityQuery.d.ts +46 -41
  18. package/dist/api/entityQuery.d.ts.map +1 -1
  19. package/dist/api/entityQuery.js +55 -14
  20. package/dist/api/entityQuery.js.map +1 -1
  21. package/dist/api/file.d.ts +26 -9
  22. package/dist/api/file.d.ts.map +1 -1
  23. package/dist/api/file.js +45 -55
  24. package/dist/api/file.js.map +1 -1
  25. package/dist/api/portfolio.d.ts +11 -8
  26. package/dist/api/portfolio.d.ts.map +1 -1
  27. package/dist/api/portfolio.js +24 -55
  28. package/dist/api/portfolio.js.map +1 -1
  29. package/dist/api/profile.d.ts +3 -2
  30. package/dist/api/profile.d.ts.map +1 -1
  31. package/dist/api/profile.js +4 -9
  32. package/dist/api/profile.js.map +1 -1
  33. package/dist/api/request.d.ts +106 -0
  34. package/dist/api/request.d.ts.map +1 -0
  35. package/dist/api/request.js +132 -0
  36. package/dist/api/request.js.map +1 -0
  37. package/dist/api/websocketsConfig.d.ts +7 -2
  38. package/dist/api/websocketsConfig.d.ts.map +1 -1
  39. package/dist/api/websocketsConfig.js +2 -10
  40. package/dist/api/websocketsConfig.js.map +1 -1
  41. package/dist/api/workflow.d.ts +84 -89
  42. package/dist/api/workflow.d.ts.map +1 -1
  43. package/dist/api/workflow.js +121 -208
  44. package/dist/api/workflow.js.map +1 -1
  45. package/dist/api/workspace.d.ts +18 -8
  46. package/dist/api/workspace.d.ts.map +1 -1
  47. package/dist/api/workspace.js +21 -26
  48. package/dist/api/workspace.js.map +1 -1
  49. package/dist/components/ui/Footer/index.d.ts.map +1 -1
  50. package/dist/components/ui/Footer/index.js.map +1 -1
  51. package/dist/components/ui/GlobalLoading/index.d.ts.map +1 -1
  52. package/dist/components/ui/GlobalLoading/index.js.map +1 -1
  53. package/dist/components/ui/PageContainer/index.d.ts +1 -1
  54. package/dist/components/ui/PageContainer/index.d.ts.map +1 -1
  55. package/dist/components/ui/PageContainer/index.js.map +1 -1
  56. package/dist/components/ui/Toolbar/index.d.ts +40 -3
  57. package/dist/components/ui/Toolbar/index.d.ts.map +1 -1
  58. package/dist/components/ui/Toolbar/index.js +42 -15
  59. package/dist/components/ui/Toolbar/index.js.map +1 -1
  60. package/dist/contexts/appAlertContext/provider.js.map +1 -1
  61. package/dist/contexts/appAlertContext/types.d.ts.map +1 -1
  62. package/dist/contexts/appConfigContext/index.d.ts.map +1 -1
  63. package/dist/contexts/appConfigContext/index.js.map +1 -1
  64. package/dist/contexts/appConfigContext/provider.d.ts.map +1 -1
  65. package/dist/contexts/appConfigContext/provider.js.map +1 -1
  66. package/dist/contexts/webSocketContext/handler.d.ts +3 -2
  67. package/dist/contexts/webSocketContext/handler.d.ts.map +1 -1
  68. package/dist/contexts/webSocketContext/handler.js.map +1 -1
  69. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.d.ts +1 -1
  70. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js +1 -1
  71. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js.map +1 -1
  72. package/dist/contexts/webSocketContext/provider.d.ts +6 -3
  73. package/dist/contexts/webSocketContext/provider.d.ts.map +1 -1
  74. package/dist/contexts/webSocketContext/provider.js +42 -7
  75. package/dist/contexts/webSocketContext/provider.js.map +1 -1
  76. package/dist/contexts/webSocketContext/types.d.ts +7 -5
  77. package/dist/contexts/webSocketContext/types.d.ts.map +1 -1
  78. package/dist/file/index.d.ts +2 -0
  79. package/dist/file/index.d.ts.map +1 -1
  80. package/dist/hooks/datastore/useDatastoreMutations.d.ts +4 -4
  81. package/dist/hooks/datastore/useDatastoreMutations.d.ts.map +1 -1
  82. package/dist/hooks/datastore/useDatastoreMutations.js +17 -55
  83. package/dist/hooks/datastore/useDatastoreMutations.js.map +1 -1
  84. package/dist/hooks/datastore/useFetchDatastore.d.ts +30 -41
  85. package/dist/hooks/datastore/useFetchDatastore.d.ts.map +1 -1
  86. package/dist/hooks/datastore/useFetchDatastore.js +25 -59
  87. package/dist/hooks/datastore/useFetchDatastore.js.map +1 -1
  88. package/dist/hooks/datastore/useFetchDatastores.d.ts +47 -52
  89. package/dist/hooks/datastore/useFetchDatastores.d.ts.map +1 -1
  90. package/dist/hooks/datastore/useFetchDatastores.js +55 -70
  91. package/dist/hooks/datastore/useFetchDatastores.js.map +1 -1
  92. package/dist/hooks/file/fileData.d.ts +17 -0
  93. package/dist/hooks/file/fileData.d.ts.map +1 -0
  94. package/dist/hooks/file/fileData.js +10 -0
  95. package/dist/hooks/file/fileData.js.map +1 -0
  96. package/dist/hooks/file/useFetchFile.d.ts +38 -58
  97. package/dist/hooks/file/useFetchFile.d.ts.map +1 -1
  98. package/dist/hooks/file/useFetchFile.js +26 -66
  99. package/dist/hooks/file/useFetchFile.js.map +1 -1
  100. package/dist/hooks/file/useFetchFiles.d.ts +18 -52
  101. package/dist/hooks/file/useFetchFiles.d.ts.map +1 -1
  102. package/dist/hooks/file/useFetchFiles.js +53 -69
  103. package/dist/hooks/file/useFetchFiles.js.map +1 -1
  104. package/dist/hooks/file/useFileMutations.d.ts +9 -8
  105. package/dist/hooks/file/useFileMutations.d.ts.map +1 -1
  106. package/dist/hooks/file/useFileMutations.js +23 -60
  107. package/dist/hooks/file/useFileMutations.js.map +1 -1
  108. package/dist/hooks/portfolio/useFetchPortfolio.d.ts +16 -50
  109. package/dist/hooks/portfolio/useFetchPortfolio.d.ts.map +1 -1
  110. package/dist/hooks/portfolio/useFetchPortfolio.js +15 -63
  111. package/dist/hooks/portfolio/useFetchPortfolio.js.map +1 -1
  112. package/dist/hooks/portfolio/useFetchPortfolios.d.ts +13 -52
  113. package/dist/hooks/portfolio/useFetchPortfolios.d.ts.map +1 -1
  114. package/dist/hooks/portfolio/useFetchPortfolios.js +29 -71
  115. package/dist/hooks/portfolio/useFetchPortfolios.js.map +1 -1
  116. package/dist/hooks/portfolio/usePortfolioMutations.d.ts +8 -8
  117. package/dist/hooks/portfolio/usePortfolioMutations.d.ts.map +1 -1
  118. package/dist/hooks/portfolio/usePortfolioMutations.js +20 -58
  119. package/dist/hooks/portfolio/usePortfolioMutations.js.map +1 -1
  120. package/dist/hooks/profile/useFetchProfile.d.ts +18 -44
  121. package/dist/hooks/profile/useFetchProfile.d.ts.map +1 -1
  122. package/dist/hooks/profile/useFetchProfile.js +16 -48
  123. package/dist/hooks/profile/useFetchProfile.js.map +1 -1
  124. package/dist/hooks/useAxios.js.map +1 -1
  125. package/dist/hooks/useEntityInfiniteQuery.d.ts +88 -0
  126. package/dist/hooks/useEntityInfiniteQuery.d.ts.map +1 -0
  127. package/dist/hooks/useEntityInfiniteQuery.js +111 -0
  128. package/dist/hooks/useEntityInfiniteQuery.js.map +1 -0
  129. package/dist/hooks/useEntityMutation.d.ts +47 -0
  130. package/dist/hooks/useEntityMutation.d.ts.map +1 -0
  131. package/dist/hooks/useEntityMutation.js +58 -0
  132. package/dist/hooks/useEntityMutation.js.map +1 -0
  133. package/dist/hooks/useEntityQuery.d.ts +68 -0
  134. package/dist/hooks/useEntityQuery.d.ts.map +1 -0
  135. package/dist/hooks/useEntityQuery.js +75 -0
  136. package/dist/hooks/useEntityQuery.js.map +1 -0
  137. package/dist/hooks/workflow/useFetchWorkerExecution.d.ts +17 -34
  138. package/dist/hooks/workflow/useFetchWorkerExecution.d.ts.map +1 -1
  139. package/dist/hooks/workflow/useFetchWorkerExecution.js +16 -46
  140. package/dist/hooks/workflow/useFetchWorkerExecution.js.map +1 -1
  141. package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts +179 -41
  142. package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts.map +1 -1
  143. package/dist/hooks/workflow/useFetchWorkerExecutions.js +29 -62
  144. package/dist/hooks/workflow/useFetchWorkerExecutions.js.map +1 -1
  145. package/dist/hooks/workflow/useFetchWorkflow.d.ts +16 -35
  146. package/dist/hooks/workflow/useFetchWorkflow.d.ts.map +1 -1
  147. package/dist/hooks/workflow/useFetchWorkflow.js +15 -48
  148. package/dist/hooks/workflow/useFetchWorkflow.js.map +1 -1
  149. package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts +17 -34
  150. package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts.map +1 -1
  151. package/dist/hooks/workflow/useFetchWorkflowExecution.js +16 -46
  152. package/dist/hooks/workflow/useFetchWorkflowExecution.js.map +1 -1
  153. package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts +22 -36
  154. package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts.map +1 -1
  155. package/dist/hooks/workflow/useFetchWorkflowExecutions.js +43 -56
  156. package/dist/hooks/workflow/useFetchWorkflowExecutions.js.map +1 -1
  157. package/dist/hooks/workflow/useFetchWorkflows.d.ts +20 -37
  158. package/dist/hooks/workflow/useFetchWorkflows.d.ts.map +1 -1
  159. package/dist/hooks/workflow/useFetchWorkflows.js +32 -47
  160. package/dist/hooks/workflow/useFetchWorkflows.js.map +1 -1
  161. package/dist/hooks/workflow/useRunWorkflow.d.ts +21 -16
  162. package/dist/hooks/workflow/useRunWorkflow.d.ts.map +1 -1
  163. package/dist/hooks/workflow/useRunWorkflow.js +66 -29
  164. package/dist/hooks/workflow/useRunWorkflow.js.map +1 -1
  165. package/dist/hooks/workflow/useTriggerWorkflow.d.ts +20 -0
  166. package/dist/hooks/workflow/useTriggerWorkflow.d.ts.map +1 -0
  167. package/dist/hooks/workflow/useTriggerWorkflow.js +32 -0
  168. package/dist/hooks/workflow/useTriggerWorkflow.js.map +1 -0
  169. package/dist/hooks/workspace/useFetchWorkspace.d.ts +19 -34
  170. package/dist/hooks/workspace/useFetchWorkspace.d.ts.map +1 -1
  171. package/dist/hooks/workspace/useFetchWorkspace.js +16 -46
  172. package/dist/hooks/workspace/useFetchWorkspace.js.map +1 -1
  173. package/dist/hooks/workspace/useFetchWorkspaces.d.ts +17 -37
  174. package/dist/hooks/workspace/useFetchWorkspaces.d.ts.map +1 -1
  175. package/dist/hooks/workspace/useFetchWorkspaces.js +25 -47
  176. package/dist/hooks/workspace/useFetchWorkspaces.js.map +1 -1
  177. package/dist/index.d.ts +13 -10
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +13 -11
  180. package/dist/lib/abort.d.ts +58 -0
  181. package/dist/lib/abort.d.ts.map +1 -0
  182. package/dist/lib/abort.js +112 -0
  183. package/dist/lib/abort.js.map +1 -0
  184. package/dist/lib/datastoreTable.d.ts +59 -54
  185. package/dist/lib/datastoreTable.d.ts.map +1 -1
  186. package/dist/lib/datastoreTable.js +58 -62
  187. package/dist/lib/datastoreTable.js.map +1 -1
  188. package/dist/lib/file.d.ts +34 -0
  189. package/dist/lib/file.d.ts.map +1 -0
  190. package/dist/lib/file.js +63 -0
  191. package/dist/lib/file.js.map +1 -0
  192. package/dist/lib/queryClient.d.ts.map +1 -1
  193. package/dist/lib/queryClient.js.map +1 -1
  194. package/dist/lib/workflowRun.d.ts +91 -0
  195. package/dist/lib/workflowRun.d.ts.map +1 -0
  196. package/dist/lib/workflowRun.js +224 -0
  197. package/dist/lib/workflowRun.js.map +1 -0
  198. package/dist/socket/index.d.ts +1 -3
  199. package/dist/socket/index.d.ts.map +1 -1
  200. package/dist/socket/index.js +3 -5
  201. package/dist/test/mocks/index.d.ts +1 -1
  202. package/dist/test/mocks/index.d.ts.map +1 -1
  203. package/dist/test/renderWithProviders.d.ts +2 -2
  204. package/dist/test/renderWithProviders.d.ts.map +1 -1
  205. package/dist/test/renderWithProviders.js.map +1 -1
  206. package/dist/test/setup.js.map +1 -1
  207. package/dist/theme/index.d.ts +1 -1
  208. package/dist/theme/index.d.ts.map +1 -1
  209. package/dist/theme/overrides/index.d.ts +4 -2
  210. package/dist/theme/overrides/index.d.ts.map +1 -1
  211. package/dist/theme/overrides/index.js +5 -3
  212. package/dist/theme/overrides/index.js.map +1 -1
  213. package/dist/theme/overrides/muiButton.d.ts +2 -2
  214. package/dist/theme/overrides/muiButton.js.map +1 -1
  215. package/dist/theme/overrides/muiCssBaseline.d.ts.map +1 -1
  216. package/dist/theme/overrides/muiCssBaseline.js.map +1 -1
  217. package/dist/theme/overrides/muiDatePicker.js.map +1 -1
  218. package/dist/theme/overrides/muiFormControl.js.map +1 -1
  219. package/dist/theme/overrides/muiIconButton.d.ts +2 -2
  220. package/dist/theme/overrides/muiIconButton.js.map +1 -1
  221. package/dist/theme/overrides/muiSelect.d.ts.map +1 -1
  222. package/dist/theme/overrides/muiSelect.js.map +1 -1
  223. package/dist/theme/overrides/muiSvgIcon.d.ts.map +1 -1
  224. package/dist/theme/overrides/muiSvgIcon.js.map +1 -1
  225. package/dist/theme/overrides/muiTextField.js.map +1 -1
  226. package/dist/theme/overrides/muiToggleButton.d.ts +2 -2
  227. package/dist/theme/overrides/muiToggleButton.js.map +1 -1
  228. package/dist/theme/overrides/muiToggleButtonGroup.d.ts +2 -2
  229. package/dist/theme/overrides/muiToggleButtonGroup.js.map +1 -1
  230. package/dist/theme/themes/DefaultDark.js +2 -2
  231. package/dist/theme/themes/DefaultDark.js.map +1 -1
  232. package/dist/theme/themes/DefaultLight.js +2 -2
  233. package/dist/theme/themes/DefaultLight.js.map +1 -1
  234. package/dist/theme/themes/EveryskDark.js +2 -2
  235. package/dist/theme/themes/EveryskDark.js.map +1 -1
  236. package/dist/theme/themes/EveryskLight.js +2 -2
  237. package/dist/theme/themes/EveryskLight.js.map +1 -1
  238. package/dist/theme/themes/MidnightEmber.js +2 -2
  239. package/dist/theme/themes/MidnightEmber.js.map +1 -1
  240. package/dist/types/anyRecord.d.ts.map +1 -1
  241. package/dist/types/datastore.d.ts +35 -5
  242. package/dist/types/datastore.d.ts.map +1 -1
  243. package/dist/types/datastoreDataFormat.d.ts +13 -0
  244. package/dist/types/datastoreDataFormat.d.ts.map +1 -0
  245. package/dist/types/entityQuery.d.ts +86 -16
  246. package/dist/types/entityQuery.d.ts.map +1 -1
  247. package/dist/types/file.d.ts +7 -3
  248. package/dist/types/file.d.ts.map +1 -1
  249. package/dist/types/portfolio.d.ts +1 -3
  250. package/dist/types/portfolio.d.ts.map +1 -1
  251. package/dist/types/profile.d.ts +0 -10
  252. package/dist/types/profile.d.ts.map +1 -1
  253. package/dist/types/workflow.d.ts +35 -6
  254. package/dist/types/workflow.d.ts.map +1 -1
  255. package/dist/types/workspace.d.ts +1 -2
  256. package/dist/types/workspace.d.ts.map +1 -1
  257. package/dist/ui/index.d.ts +1 -1
  258. package/dist/ui/index.d.ts.map +1 -1
  259. package/dist/workflow/index.d.ts +2 -0
  260. package/dist/workflow/index.d.ts.map +1 -1
  261. package/package.json +6 -6
  262. package/src/EveryskApp.tsx +53 -2
  263. package/src/agGrid/handleRowsScrollEnd.ts +71 -0
  264. package/src/agGrid/index.ts +5 -1
  265. package/src/api/datastore.ts +79 -107
  266. package/src/api/entityQuery.ts +86 -17
  267. package/src/api/file.ts +110 -103
  268. package/src/api/portfolio.ts +82 -125
  269. package/src/api/profile.ts +25 -18
  270. package/src/api/request.ts +168 -0
  271. package/src/api/websocketsConfig.ts +11 -19
  272. package/src/api/workflow.ts +232 -334
  273. package/src/api/workspace.ts +43 -43
  274. package/src/components/ui/Footer/index.tsx +8 -7
  275. package/src/components/ui/GlobalLoading/index.tsx +13 -3
  276. package/src/components/ui/PageContainer/index.tsx +9 -2
  277. package/src/components/ui/Toolbar/index.tsx +105 -30
  278. package/src/contexts/appAlertContext/provider.tsx +1 -1
  279. package/src/contexts/appAlertContext/types.ts +3 -3
  280. package/src/contexts/appConfigContext/index.tsx +1 -1
  281. package/src/contexts/appConfigContext/provider.tsx +1 -5
  282. package/src/contexts/webSocketContext/handler.ts +8 -2
  283. package/src/contexts/webSocketContext/hooks/useWebSocket/index.ts +1 -1
  284. package/src/contexts/webSocketContext/provider.tsx +64 -14
  285. package/src/contexts/webSocketContext/types.ts +7 -6
  286. package/src/file/index.ts +2 -0
  287. package/src/hooks/datastore/useDatastoreMutations.ts +19 -60
  288. package/src/hooks/datastore/useFetchDatastore.ts +45 -73
  289. package/src/hooks/datastore/useFetchDatastores.ts +106 -131
  290. package/src/hooks/file/fileData.ts +19 -0
  291. package/src/hooks/file/useFetchFile.ts +41 -76
  292. package/src/hooks/file/useFetchFiles.ts +92 -87
  293. package/src/hooks/file/useFileMutations.ts +23 -73
  294. package/src/hooks/portfolio/useFetchPortfolio.ts +26 -78
  295. package/src/hooks/portfolio/useFetchPortfolios.ts +50 -93
  296. package/src/hooks/portfolio/usePortfolioMutations.ts +22 -72
  297. package/src/hooks/profile/useFetchProfile.ts +24 -65
  298. package/src/hooks/useAxios.ts +5 -5
  299. package/src/hooks/useEntityInfiniteQuery.ts +193 -0
  300. package/src/hooks/useEntityMutation.ts +70 -0
  301. package/src/hooks/useEntityQuery.ts +117 -0
  302. package/src/hooks/workflow/useFetchWorkerExecution.ts +27 -56
  303. package/src/hooks/workflow/useFetchWorkerExecutions.ts +54 -79
  304. package/src/hooks/workflow/useFetchWorkflow.ts +24 -58
  305. package/src/hooks/workflow/useFetchWorkflowExecution.ts +27 -57
  306. package/src/hooks/workflow/useFetchWorkflowExecutions.ts +64 -73
  307. package/src/hooks/workflow/useFetchWorkflows.ts +48 -64
  308. package/src/hooks/workflow/useRunWorkflow.ts +82 -36
  309. package/src/hooks/workflow/useTriggerWorkflow.ts +36 -0
  310. package/src/hooks/workspace/useFetchWorkspace.ts +25 -58
  311. package/src/hooks/workspace/useFetchWorkspaces.ts +38 -69
  312. package/src/index.ts +34 -19
  313. package/src/lib/abort.ts +131 -0
  314. package/src/lib/datastoreTable.ts +127 -74
  315. package/src/lib/file.ts +67 -0
  316. package/src/lib/queryClient.ts +11 -13
  317. package/src/lib/workflowRun.ts +329 -0
  318. package/src/socket/index.ts +1 -3
  319. package/src/test/mocks/index.ts +1 -5
  320. package/src/test/renderWithProviders.tsx +8 -3
  321. package/src/test/setup.ts +16 -16
  322. package/src/theme/index.ts +1 -1
  323. package/src/theme/overrides/index.ts +5 -3
  324. package/src/theme/overrides/muiButton.ts +3 -3
  325. package/src/theme/overrides/muiCssBaseline.ts +11 -12
  326. package/src/theme/overrides/muiDatePicker.ts +2 -2
  327. package/src/theme/overrides/muiFormControl.ts +2 -2
  328. package/src/theme/overrides/muiIconButton.ts +3 -3
  329. package/src/theme/overrides/muiSelect.ts +2 -2
  330. package/src/theme/overrides/muiSvgIcon.ts +2 -2
  331. package/src/theme/overrides/muiTextField.ts +1 -1
  332. package/src/theme/overrides/muiToggleButton.ts +4 -4
  333. package/src/theme/overrides/muiToggleButtonGroup.ts +4 -4
  334. package/src/theme/themes/DefaultDark.ts +2 -2
  335. package/src/theme/themes/DefaultLight.ts +2 -2
  336. package/src/theme/themes/EveryskDark.ts +2 -2
  337. package/src/theme/themes/EveryskLight.ts +2 -2
  338. package/src/theme/themes/MidnightEmber.ts +15 -15
  339. package/src/types/anyRecord.ts +2 -2
  340. package/src/types/datastore.ts +56 -22
  341. package/src/types/datastoreDataFormat.ts +12 -0
  342. package/src/types/entityQuery.ts +122 -38
  343. package/src/types/file.ts +8 -6
  344. package/src/types/portfolio.ts +70 -74
  345. package/src/types/profile.ts +0 -11
  346. package/src/types/workflow.ts +38 -9
  347. package/src/types/workspace.ts +2 -4
  348. package/src/ui/index.ts +1 -1
  349. package/src/workflow/index.ts +5 -0
package/README.md CHANGED
@@ -5,16 +5,30 @@
5
5
  The runtime an Everysk app bundles: the provider tree, the API layer, the entity hooks, the
6
6
  shared components and the MUI theme. Declared as a `dependency`.
7
7
 
8
- Part of [everysk/apps-sdk](https://github.com/everysk/apps-sdk), alongside
9
- [`@everysk/apps-devkit`](../apps-devkit) (build presets) and
10
- [`@everysk/apps-cli`](../apps-cli) (the `everysk-apps` bin).
8
+ One of three: [`@everysk/apps-devkit`](https://www.npmjs.com/package/@everysk/apps-devkit) holds
9
+ the build presets and [`@everysk/apps-cli`](https://www.npmjs.com/package/@everysk/apps-cli) the
10
+ `everysk-apps` bin.
11
+
12
+ ## Start with the CLI
13
+
14
+ ```bash
15
+ npx @everysk/apps-cli init
16
+ ```
17
+
18
+ For a new app, do this instead of installing by hand: it writes an app already wired for the
19
+ modules and theme you pick, including four decisions that fail *quietly* when made by hand.
20
+ [`@everysk/apps-cli`](https://www.npmjs.com/package/@everysk/apps-cli) lists them.
11
21
 
12
22
  ## Install
13
23
 
24
+ For adding the SDK to an app that already exists:
25
+
14
26
  ```bash
15
27
  npm install @everysk/apps-sdk
16
28
  ```
17
29
 
30
+ Then `npx @everysk/apps-cli doctor` will tell you what the wiring is still missing.
31
+
18
32
  `react`, `react-dom`, `@mui/material`, `@mui/x-date-pickers`, `@emotion/*`,
19
33
  `@tanstack/react-query` and `axios` are **required** peers — npm installs them with the package,
20
34
  and a version outside its range fails the install rather than giving the app a second copy. Two
@@ -49,7 +63,344 @@ to nested JSX in the right slot.
49
63
  | `theme` | A MUI theme. Omitted, the app mounts the Everysk dark theme |
50
64
  | `queryClient` | Defaults to a fresh `createQueryClient()`, created once per mount |
51
65
  | `appId`, `appEnvironmentVar` | Override `window.APP_ID` / `window.APP_CONFIG`, for tests and hosts that resolve configuration themselves |
52
- | `providers` | Optional providers, mounted inside the core tree |
66
+ | `providers` | Optional providers, mounted inside the core tree. One configured by props goes in through `withProps(Provider, props)` |
67
+
68
+ ## What it exports
69
+
70
+ Everything below comes from the package root — `import { … } from "@everysk/apps-sdk"`. A bundler
71
+ drops what you do not use, so there is nothing to be careful about here.
72
+
73
+ ### Entity slices
74
+
75
+ Each entity is an API module, its types, and React Query hooks over them. The hooks take an
76
+ object and return the query result plus its `queryKey`, so a mutation can invalidate exactly what
77
+ a list rendered.
78
+
79
+ | Entity | One | Many | Write |
80
+ |---|---|---|---|
81
+ | Portfolio | `useFetchPortfolio` | `useFetchPortfolios` | `usePortfolioMutations` |
82
+ | Datastore | `useFetchDatastore` | `useFetchDatastores` | `useDatastoreMutations` |
83
+ | File | `useFetchFile` | `useFetchFiles` | `useFileMutations` |
84
+ | Workspace | `useFetchWorkspace` | `useFetchWorkspaces` | — |
85
+ | Profile | `useFetchProfile` | — | — |
86
+ | Workflow | `useFetchWorkflow` | `useFetchWorkflows` | `useTriggerWorkflow`, `useRunWorkflow` |
87
+
88
+ Workflow carries four more for the run side: `useFetchWorkflowExecution(s)` and
89
+ `useFetchWorkerExecution(s)`. `useFetchWorkflowExecutions` pages by cursor and takes the
90
+ endpoint's own filters, `workerId` and `withResume`, not a `filters` list.
91
+ `useFetchWorkerExecutions` is not paginated: the API returns every worker of one execution at
92
+ once, grouped by worker, so it returns `{ data, …, queryKey }` like a single-entity hook. Narrow
93
+ each group on `is_parallel_execution`: a worker that ran in parallel carries `executions`, any
94
+ other one `execution`.
95
+
96
+ `useFetchWorkflows` and `useFetchWorkspaces` take a text `search` rather than filters: their
97
+ endpoints search by name prefix (and, for workflows, by `#tag` or id). `useFetchWorkflows`
98
+ requires a `workspace`, like every other hook — without one the API would read `main`.
99
+ `useFetchWorkspaces` takes none: it lists the account's workspaces.
100
+
101
+ A file's content comes as base64 in `data`, a third larger than the file, so `useFetchFile` and
102
+ `useFetchFiles` leave it out unless `withData: true` asks for it (the list through the projection
103
+ `-data`, added to a `projection` of the app's own that only excludes fields; one that includes
104
+ fields is sent as given, and the content is still removed). To
105
+ show or download a file, use its `url` (`/file/<hash>`) in an `<iframe>`, an `<img>` or an
106
+ `<a href download>`: the platform serves it inline with the user's permissions, and the
107
+ `@everysk/apps-devkit` dev server and `vite preview` serve it too. Do not build a `blob:` URL
108
+ from the content: the app page's CSP blocks `blob:` frames, images and media. To upload,
109
+ `fileToBase64(file)` turns a `File` from an `<input type="file">` into the raw base64
110
+ `createFile` and `updateFile` take, and which they insist on: a data URL is refused, since the
111
+ API would store its prefix as part of the file. `base64ToBlob(data, contentType)` decodes one, to
112
+ work on the bytes in code (a CSV, a zip); given a file read without its content, it warns and
113
+ gives an empty blob. An app uploads
114
+ in one JSON request: the app's `/api` reads no multipart body.
115
+
116
+ ```tsx
117
+ const { data: file } = useFetchFile({ id, workspace });
118
+
119
+ return file ? <iframe src={file.url} title={file.name} /> : null;
120
+ ```
121
+
122
+ `useTriggerWorkflow` starts a run and resolves with the started `WorkflowExecution`; it needs no
123
+ websocket. `useRunWorkflow` starts one and waits for it to end **over the websocket**,
124
+ resolving with `{ execution, workerExecution, result }`, so it needs `WebSocketProvider` (from
125
+ `@everysk/apps-sdk/socket`) in `EveryskApp`'s `providers`, and throws on render without it.
126
+
127
+ The backend announces each worker and the run's end on the app's channel; the end itself is
128
+ then read from the API, and the Ender's output with it. Because those events are not replayed,
129
+ it also reads the execution after a minute without any event of the run
130
+ (`waitOptions.silenceMs`) and whenever the socket reconnects, and gives up after five minutes
131
+ (`waitOptions.timeoutMs`). It fails when the socket stays unavailable for 30 seconds
132
+ (`waitOptions.unavailableAfterMs`), since the end cannot be followed without it, and does not
133
+ start the run before the socket is connected. Leaving the
134
+ screen, or aborting `waitOptions.signal`, stops it without an error alert; the mutation then fails
135
+ with a `WorkflowRunAbortedError`, so `error instanceof WorkflowRunAbortedError` tells a stop from
136
+ a failure.
137
+
138
+ ```tsx
139
+ const { query, queryKey } = useFetchPortfolios({
140
+ filters: [{ field: "workspace", value: "ws-1" }],
141
+ pageSize: 20,
142
+ });
143
+
144
+ const { remove } = usePortfolioMutations({ queryKey });
145
+ ```
146
+
147
+ `useFetchPortfolios` is paginated — `query` is the whole `useInfiniteQuery` result, so
148
+ `hasNextPage` and `fetchNextPage` are there. The single-entity hooks spread the query result
149
+ directly, so `const { data, isLoading, queryKey } = useFetchPortfolio({ id, workspace })`.
150
+ Mutations return `{ create, update, remove }`, each a React Query mutation that shows an alert on
151
+ success and failure through `useAppAlert`.
152
+
153
+ #### Using a list hook without wrapping it
154
+
155
+ The six list hooks (`useFetchDatastores`, `useFetchFiles`, `useFetchPortfolios`,
156
+ `useFetchWorkflows`, `useFetchWorkflowExecutions`, `useFetchWorkspaces`) share one set of props, meant to cover what apps used to write a hook of
157
+ their own for:
158
+
159
+ | Prop | Default | |
160
+ |---|---|---|
161
+ | `select` | — | Shapes the merged list: `query.data` is what it returns. Applied after the pages are merged |
162
+ | `fetchAllPages` | `false` | Reads to the last page before reporting success |
163
+ | `pageSize` | `10` | Items per request |
164
+ | `queryOptions` | — | Passed through to `useInfiniteQuery`, except `select`, which is the prop above |
165
+
166
+ ```tsx
167
+ // Module scope, so the reference is stable: TanStack reruns a select whose reference changes.
168
+ const toRows = (datastores: ParsedDatastore[]) =>
169
+ datastores.filter(isTableDatastore).flatMap((datastore) => datastore.data);
170
+
171
+ const { query, queryKey } = useFetchDatastores({
172
+ filters: [{ field: "workspace", value: workspace }],
173
+ select: toRows, // query.data: AnyRecord[]
174
+ });
175
+ ```
176
+
177
+ - **`select` shapes what one caller sees; the cache keeps the pages.** Write to it with the
178
+ returned `queryKey` and the hook's cache type (`DatastoresCache`, `FilesCache`, …), and every
179
+ `select` reruns on the new data:
180
+
181
+ ```ts
182
+ queryClient.setQueryData<DatastoresCache>(queryKey, (cache) => cache && {
183
+ ...cache,
184
+ pages: cache.pages.map((page) => ({
185
+ ...page,
186
+ datastores: page.datastores.map((datastore) =>
187
+ isTableDatastore(datastore)
188
+ ? { ...datastore, data: datastore.data.map((row) => (row.UID === uid ? { ...row, ...patch } : row)) }
189
+ : datastore,
190
+ ),
191
+ })),
192
+ });
193
+ ```
194
+
195
+ - **`fetchAllPages` is for a view that consolidates the whole set**, where a partial read is a
196
+ wrong answer rather than a shorter one. Without it the hook reads one page and stops, which a
197
+ screen that never asks for more shows as silently missing data. It fails rather than stop short
198
+ after 100 pages, so raise `pageSize` with it — the limit counts requests, not items — and it
199
+ stops requesting the moment the screen that asked unmounts, so a user leaving mid-read does not
200
+ keep the backend walking the cursor.
201
+ - **Leaving a screen aborts its request.** Every list hook hands the query's `AbortSignal` to its
202
+ `api/` function, which passes it to axios: the HTTP request in flight is cancelled, not only the
203
+ query state. The `api/` list functions take it as an optional last argument.
204
+ - **The key holds everything that changes the response** — filters (field, operator and value),
205
+ `order`, `projection`, `pageSize` and `fetchAllPages` — after the base keys, so a metadata read
206
+ (`projection: "-data"`) and a full read of the same workspace never share an entry, and prefix
207
+ invalidation (`["workflow_executions", workflowId]`) still reaches every page size and filter.
208
+ - **`projection` takes one field or a list.** `["name", "date"]` returns only those; `["-data"]`
209
+ everything but `data`. Don't mix the two, and name only fields the entity has: the API answers
210
+ either with a 500. That is also why `"name,date"` fails — it reads as one field of that name. Filters take
211
+ `IN` and `NOT_IN` with a list as the value.
212
+ - **A missing workspace fails loudly.** Without a `workspace` filter, or with an empty one, the
213
+ hooks that take filters fail at once with an error naming the hook, log it with
214
+ `console.error` (once, in every environment), and send no request. The app config is in
215
+ `window.APP_CONFIG` before the app renders, so an empty workspace is a wrong or misspelled
216
+ config key — never a state to wait out, and not one to hide behind an empty screen.
217
+ - **A datastore is tabular or JSON, and a list can mix them.** The API does not say which, so the
218
+ shape of `data` decides: an array of rows is a table; an object or an array of objects is JSON.
219
+ They come back told apart by `format`:
220
+
221
+ | `format` | `data` | Also |
222
+ |---|---|---|
223
+ | `"table"` | row objects, one per matrix row — or, with `dataFormat: "matrix"`, the matrix unconverted | `fields`: the header row, in the datastore's order |
224
+ | `"json"` | the object or array of objects, untouched | — |
225
+
226
+ Narrow before reading rows — `isTableDatastore(datastore)` or `datastore.format === "table"`.
227
+ A table keeps its column order in `fields`, so saving back is `toDatastoreMatrix(datastore)`,
228
+ which returns a new matrix the caller owns, however the datastore was read — rebuilt from the
229
+ rows, patches included, or copied after a `dataFormat: "matrix"` read. `query.data` itself is
230
+ the query cache: do not edit it in place. A read that projects `data` away has nothing to tell
231
+ the kinds apart and comes back as an empty table, so do not save its result.
232
+ - **`dataFormat: "matrix"` skips the conversion** in `useFetchDatastores` and `useFetchDatastore`:
233
+ a tabular datastore's `data` stays the matrix, header row included, typed as such in
234
+ `query.data` and in `select`. Use it for a grid that takes arrays, an export, or a datastore too
235
+ large to convert one object per row. The default, `"object"`, is what lets an app patch a row
236
+ as `{ ...row, ...patch }`. The option is part of the cache key, so the two reads never share an
237
+ entry.
238
+ - **Paging on grid scroll** is `handleRowsScrollEnd`, in [`/ag-grid`](#paging-an-ag-grid-on-scroll),
239
+ kept out of the hooks so that it works with any of them.
240
+
241
+ #### A list hook for an endpoint the SDK does not cover
242
+
243
+ Compose `useEntityInfiniteQuery`, the hook the seven are built on, rather than copying one of
244
+ them. You say how to request a page and where its items are; it brings the rest — pages merged,
245
+ `select`, `fetchAllPages` (up to `FETCH_ALL_PAGES_LIMIT` pages), and a `query` that
246
+ `handleRowsScrollEnd` pages. Two ways to hold a request back: `configError` for what must always
247
+ be there (it fails loudly), `enabled` for what legitimately is not there yet, like a selection
248
+ (it stays idle).
249
+
250
+ ```ts
251
+ export const useFetchReports = <TData = Report[]>({ workspace, select, fetchAllPages = false }: Props<TData>) => {
252
+ const { api } = useAxios();
253
+ const filters = [{ field: "workspace", value: workspace }];
254
+ // Everything that changes the response goes in the key, fetchAllPages included.
255
+ const queryKey = buildQueryKey(["reports"], filters, { fetchAllPages });
256
+
257
+ const query = useEntityInfiniteQuery<ReportListResponse, "reports", TData>({
258
+ queryKey,
259
+ itemsKey: "reports", // ReportListResponse = { next_page_token: string | null; reports: Report[] }
260
+ fetchPage: (pageToken) => listReports(api, workspace, pageToken),
261
+ select,
262
+ fetchAllPages,
263
+ configError: hasWorkspaceFilter(filters) ? undefined : missingWorkspaceError("useFetchReports"),
264
+ });
265
+
266
+ return { query, queryKey };
267
+ };
268
+ ```
269
+
270
+ The key is the one thing it cannot check for you: two reads under the same key share one cache
271
+ entry, whatever each asked for. `buildQueryKey` builds it from the same parts as the request.
272
+
273
+ `fetchPage` also receives an `AbortSignal`, aborted when no screen reads the query any more.
274
+ Pass it on (`api.get(url, { signal })`) and a request in flight is cancelled too; ignore it and
275
+ the hook still stops `fetchAllPages` between pages.
276
+
277
+ #### Single-entity hooks
278
+
279
+ The eight (`useFetchDatastore`, `useFetchFile`, `useFetchPortfolio`, `useFetchWorkflow`,
280
+ `useFetchWorkflowExecution`, `useFetchWorkerExecution`, `useFetchWorkspace`, `useFetchProfile`),
281
+ and `useFetchWorkerExecutions`, which has the same shape,
282
+ share one set of doors with the lists:
283
+
284
+ | Prop | |
285
+ |---|---|
286
+ | `select` | Shapes the entity: `data` is what it returns, and is typed so |
287
+ | `queryOptions` | Passed through to `useQuery`, **merged over** the hook's defaults, except `select` |
288
+
289
+ - **Options are merged, not swapped.** Passing `queryOptions: { enabled }` keeps the defaults
290
+ (`refetchOnMount: "always"`, `staleTime: 0`, `gcTime: 0`; for the profile, fetched once per
291
+ session). The hooks used to replace them with whatever was passed, which fell back to
292
+ TanStack's own and cached for five minutes.
293
+ - **An empty id waits; an empty workspace fails.** An id usually comes from a selection the user
294
+ has not made yet, so while it is empty the hook stays idle — the guard apps wrote as
295
+ `queryOptions: { enabled: Boolean(id && workspace) }`, no longer needed. The workspace comes from
296
+ the app config, in place before the app renders, so an empty one is a misconfigured app: the
297
+ hook fails at once, without a request, with an error naming it, logged once with
298
+ `console.error` and shown as the alert — even when the id is empty too. `useFetchWorkspace` is
299
+ the exception that follows from the API: a workspace is identified by its name, so its `name`
300
+ is the id, and an empty one waits.
301
+ - **A failure shows an error alert**, through `useAppAlert`, as it always has.
302
+
303
+ For an endpoint the SDK does not cover, compose `useEntityQuery`, the hook the eight are built
304
+ on:
305
+
306
+ ```ts
307
+ export const useFetchReport = <TData = Report>({ id, workspace, select, queryOptions }: Props<TData>) => {
308
+ const { api } = useAxios();
309
+ const queryKey = ["report", id, workspace];
310
+
311
+ const query = useEntityQuery<Report, TData>({
312
+ queryKey,
313
+ fetchEntity: (signal) => getReport(api, id, workspace, signal),
314
+ select,
315
+ enabled: Boolean(id), // a selection not made yet: wait
316
+ configError: workspace ? undefined : missingWorkspaceError("useFetchReport"), // misconfigured: fail
317
+ queryOptions,
318
+ });
319
+
320
+ return { ...query, queryKey };
321
+ };
322
+ ```
323
+
324
+ `defaultQueryOptions` replaces the SDK's defaults for a hook whose data does not change, as the
325
+ profile's does. `fetchEntity` receives the query's `AbortSignal`: the SDK's hooks hand it to
326
+ their `api/` get function, which passes it to axios, so leaving a screen aborts the request.
327
+
328
+ #### Mutation hooks
329
+
330
+ `useDatastoreMutations`, `useFileMutations` and `usePortfolioMutations` are built on
331
+ `useEntityMutation`. For a write the SDK does not cover, compose it too: it invalidates
332
+ `queryKey` after a success (awaited, so code after `mutateAsync` sees fresh data) and shows the
333
+ success alert, or the failure's own message as an error alert, falling back to `errorMessage`.
334
+
335
+ ```ts
336
+ const share = useEntityMutation({
337
+ mutationFn: ({ id, workspace }: ShareReportProps) => shareReport(api, id, workspace),
338
+ queryKey, // optional: invalidated after a success
339
+ successMessage: "Report shared successfully.",
340
+ errorMessage: "Unable to share the report. Please try again.",
341
+ });
342
+ ```
343
+
344
+ ### Components
345
+
346
+ Five, all MUI underneath.
347
+
348
+ | Component | Props | |
349
+ |---|---|---|
350
+ | `PageContainer` | `header?`, `footer?`, `contentClassName?` | The page frame: chrome around a scrolling content area |
351
+ | `Toolbar` | `title?`, `subheader?`, `action?`, `startAction?`, `logo?`, `hideLogo?`, `position?`, `className?` | Top bar: `startAction`, logo (`EveryskIcon` unless replaced or hidden), title, children, then `action` at the far end. `position` defaults to `relative` |
352
+ | `Footer` | `className?` | Bottom bar |
353
+ | `GlobalLoading` | `isLoading`, `backdrop?`, `message?` | Full-page spinner. `backdrop` defaults to `true` |
354
+ | `EveryskIcon` | every `SvgIconProps` except `color` | The brand mark |
355
+
356
+ `Toolbar`, `Footer` and `PageContainer` take a `className`, so a Tailwind utility reaches them —
357
+ but a utility loses to MUI's own styles in the cascade, so reach for `sx` when one is dropped.
358
+ `GlobalLoading` takes no `className`, and `EveryskIcon` gets one through `SvgIconProps`.
359
+
360
+ A shell that renders the `Toolbar` for its pages holds a `ToolbarContent` — `title`, `subheader`,
361
+ `action` and `children`, the part a page supplies — and adds `startAction`, the logo and
362
+ `position` itself.
363
+
364
+ ```tsx
365
+ <PageContainer
366
+ header={<Toolbar title="Trade Allocation" action={<DateFilter />} />}
367
+ footer={<Footer />}
368
+ >
369
+ <GlobalLoading isLoading={query.isLoading} message="Loading portfolios…" />
370
+ {/* the page */}
371
+ </PageContainer>
372
+ ```
373
+
374
+ ### Contexts
375
+
376
+ | Hook | |
377
+ |---|---|
378
+ | `useAppConfig()` | `{ appId, appEnvironmentVar }`, resolved from the page or from `EveryskApp`'s props |
379
+ | `useAppAlert()` | `showAlert({ message, severity, …SnackbarProps })`. The entity mutations already use it |
380
+ | `useAxios()` | `{ api }` — a memoised axios instance on the app's `baseURL`, defaulting to `/api` |
381
+
382
+ ### Theme
383
+
384
+ `EveryskDarkTheme`, `EveryskLightTheme`, `DefaultDarkTheme`, `DefaultLightTheme` and
385
+ `MidnightEmberTheme`, plus `getTheme(name)` to resolve one by the name the CLI writes, and
386
+ `getBrandTheme(mode)` / `getDefaultTheme(mode)` for the pair. `EveryskApp` mounts the brand dark
387
+ theme unless given a `theme` prop. `componentOverrides` is the MUI component overrides every one
388
+ of them applies, for an app that builds its own theme.
389
+
390
+ ### Query client and helpers
391
+
392
+ `createQueryClient(config?)` builds the QueryClient `EveryskApp` mounts — a factory rather than a
393
+ shared instance, because two apps or two tests sharing one client share its cache.
394
+ `buildQueryObject`, `buildQueryKey`, `hasWorkspaceFilter`, `missingWorkspaceError`,
395
+ `useEntityQuery`, `useEntityInfiniteQuery` and `useEntityMutation` are the pieces the entity hooks are built from,
396
+ exported for a query the slices do not cover. `parseDatastore` is the
397
+ conversion the datastore hooks apply to each datastore, for an app that seeds their cache, and
398
+ `isTableDatastore` narrows its result to a tabular one. `toDatastoreMatrix` gives a tabular
399
+ datastore's matrix back, and `matrixToObjects` / `objectsToMatrix` convert a matrix either way. They were `tableToObjects` / `objectsToTable` in 0.2.0.
400
+
401
+ `useAxios`'s interceptor is worth knowing about if you write one of those: on `GET` and `DELETE`
402
+ it parses the request's query object into the shape the platform API expects. It is attached in
403
+ an effect and ejected on cleanup, so interceptors do not stack across renders.
53
404
 
54
405
  ## Entry points
55
406
 
@@ -75,13 +426,25 @@ nothing but `createQueryClient`. The subpath is what makes the peer genuinely op
75
426
 
76
427
  ## The AG Grid licence is a parameter
77
428
 
78
- ```ts
79
- // src/main.tsx
80
- import { setAgGridLicense } from "@everysk/apps-sdk/ag-grid";
429
+ ```tsx
430
+ // src/App.tsx
431
+ import { EveryskApp, withProps } from "@everysk/apps-sdk";
432
+ import { AgGridLicenseProvider } from "@everysk/apps-sdk/ag-grid";
433
+
434
+ const agGridLicense = withProps(AgGridLicenseProvider, {
435
+ licenseKey: import.meta.env.VITE_AG_GRID_LICENSE_KEY,
436
+ });
81
437
 
82
- setAgGridLicense(import.meta.env.VITE_AG_GRID_LICENSE_KEY);
438
+ export function App() {
439
+ return <EveryskApp providers={[agGridLicense]}>…</EveryskApp>;
440
+ }
83
441
  ```
84
442
 
443
+ `providers` mounts a bare component with no props, so a bare `AgGridLicenseProvider` there
444
+ registers nothing; `withProps` is what carries the key, checked against the provider's props. It describes
445
+ the provider rather than wrapping it, so calling it inside a render does not remount the app.
446
+ `setAgGridLicense(key)`, called once in `main.tsx`, does the same without a provider.
447
+
85
448
  This package never reads your environment. Vite replaces `import.meta.env.VITE_*` with a literal
86
449
  at the build of whoever compiles the file — for a published package that is this package's own
87
450
  CI, where the variable does not exist, so the value would freeze as `undefined` and your
@@ -92,6 +455,30 @@ is the AG Grid watermark.
92
455
  any theme — including one the app creates — gets a matching grid without a second table of
93
456
  colours.
94
457
 
458
+ ## Paging an AG Grid on scroll
459
+
460
+ ```tsx
461
+ import { handleRowsScrollEnd } from "@everysk/apps-sdk/ag-grid";
462
+
463
+ const { query } = useFetchDatastores({ filters, select: toRows });
464
+
465
+ <AgGridReact
466
+ rowData={query.data}
467
+ onBodyScrollEnd={(event) => handleRowsScrollEnd(event.api, query)}
468
+ onModelUpdated={(event) => handleRowsScrollEnd(event.api, query)}
469
+ />
470
+ ```
471
+
472
+ It requests the next page when the grid is scrolled within `scrollEndThreshold` pixels of its
473
+ last row, or shows no rows — the second event is what keeps a grid whose rows a filter hid
474
+ entirely loading. The names are MUI X DataGrid's (`onRowsScrollEnd`, `scrollEndThreshold`, default
475
+ `80`), and so is the unit: pixels, which hold when rows differ in height.
476
+
477
+ A function rather than part of a hook: it takes any infinite query's `hasNextPage`,
478
+ `isFetchingNextPage` and `fetchNextPage`, so it pages any list hook or a `useInfiniteQuery` of the
479
+ app's own. Grid events arrive in bursts, so it asks with `cancelRefetch: false` and a repeat
480
+ while the first request is in flight does nothing.
481
+
95
482
  ## Testing an app against it
96
483
 
97
484
  ```ts
@@ -1,9 +1,39 @@
1
- import { type ComponentType, type PropsWithChildren } from "react";
1
+ import { type ComponentType, type PropsWithChildren, type ReactNode } from "react";
2
2
  import { type QueryClient } from "@tanstack/react-query";
3
3
  import type { AnyRecord } from "./types/anyRecord.d.ts";
4
4
  import type { Theme } from "@mui/material/styles";
5
5
  /** A provider is any component that renders its children. */
6
6
  export type ProviderComponent = ComponentType<PropsWithChildren>;
7
+ /** A provider with the props it is mounted with, as `withProps` describes it. */
8
+ export type ConfiguredProvider = {
9
+ readonly component: ComponentType<PropsWithChildren<AnyRecord>>;
10
+ readonly props: AnyRecord;
11
+ };
12
+ /** What `providers` takes: a provider, or one with its props. */
13
+ export type ProviderEntry = ProviderComponent | ConfiguredProvider;
14
+ /**
15
+ * withProps
16
+ *
17
+ * A provider for `EveryskApp`'s `providers`, mounted with these props. `providers` mounts a bare
18
+ * component as `<Provider>{children}</Provider>`, so a provider configured by a prop — AG Grid's
19
+ * license key — needs its props said here:
20
+ *
21
+ * ```tsx
22
+ * <EveryskApp
23
+ * providers={[
24
+ * withProps(AgGridLicenseProvider, { licenseKey: import.meta.env.VITE_AG_GRID_LICENSE_KEY }),
25
+ * WebSocketProvider,
26
+ * ]}
27
+ * >
28
+ * ```
29
+ *
30
+ * It describes the provider rather than returning a wrapper component: a wrapper made in `App`'s
31
+ * render is a new component type each time, and React would remount the whole app under it on
32
+ * every render. The props are checked against the component's own.
33
+ */
34
+ export declare const withProps: <P extends {
35
+ children?: ReactNode;
36
+ }>(component: ComponentType<P>, props: NoInfer<Omit<P, "children">>) => ConfiguredProvider;
7
37
  export type EveryskAppProps = PropsWithChildren<{
8
38
  /**
9
39
  * The client every `useQuery` in the tree talks to. Defaults to a fresh
@@ -28,8 +58,10 @@ export type EveryskAppProps = PropsWithChildren<{
28
58
  * `modules.json` kept an explicit `providerOrder` only because the app owned the tree and
29
59
  * each module had to be hand-wired into the right slot; owning the tree here is what
30
60
  * retires that contract.
61
+ *
62
+ * A provider configured by props goes in through `withProps`.
31
63
  */
32
- providers?: ProviderComponent[];
64
+ providers?: ProviderEntry[];
33
65
  }>;
34
66
  /**
35
67
  * EveryskApp
@@ -1 +1 @@
1
- {"version":3,"file":"EveryskApp.d.ts","sourceRoot":"","sources":["../src/EveryskApp.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAkB,MAAM,OAAO,CAAC;AAE5F,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAM9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;AAEjE,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC;IAC5C;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACnC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,UAAU,GAAI,wEAOxB,eAAe,gCAoBjB,CAAC"}
1
+ {"version":3,"file":"EveryskApp.d.ts","sourceRoot":"","sources":["../src/EveryskApp.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5F,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAM9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;AAEjE,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC;IAChE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC7B,CAAC;AAEF,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,EACxD,WAAW,aAAa,CAAC,CAAC,CAAC,EAC3B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,KACpC,kBAGD,CAAC;AAcH,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC;IAC5C;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;CAC/B,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,UAAU,GAAI,wEAOxB,eAAe,gCAoBjB,CAAC"}
@@ -7,6 +7,39 @@ import { QueryClientProvider } from "@tanstack/react-query";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  //#region src/EveryskApp.tsx
9
9
  /**
10
+ * withProps
11
+ *
12
+ * A provider for `EveryskApp`'s `providers`, mounted with these props. `providers` mounts a bare
13
+ * component as `<Provider>{children}</Provider>`, so a provider configured by a prop — AG Grid's
14
+ * license key — needs its props said here:
15
+ *
16
+ * ```tsx
17
+ * <EveryskApp
18
+ * providers={[
19
+ * withProps(AgGridLicenseProvider, { licenseKey: import.meta.env.VITE_AG_GRID_LICENSE_KEY }),
20
+ * WebSocketProvider,
21
+ * ]}
22
+ * >
23
+ * ```
24
+ *
25
+ * It describes the provider rather than returning a wrapper component: a wrapper made in `App`'s
26
+ * render is a new component type each time, and React would remount the whole app under it on
27
+ * every render. The props are checked against the component's own.
28
+ */
29
+ var withProps = (component, props) => ({
30
+ component,
31
+ props
32
+ });
33
+ var isConfigured = (entry) => typeof entry === "object" && entry !== null && "component" in entry && "props" in entry;
34
+ var mount = (entry, children) => {
35
+ if (!isConfigured(entry)) return /* @__PURE__ */ jsx(entry, { children });
36
+ const { component: Provider, props } = entry;
37
+ return /* @__PURE__ */ jsx(Provider, {
38
+ ...props,
39
+ children
40
+ });
41
+ };
42
+ /**
10
43
  * EveryskApp
11
44
  *
12
45
  * The provider tree every Everysk app mounts, composed in one fixed order:
@@ -47,7 +80,7 @@ import { jsx } from "react/jsx-runtime";
47
80
  var EveryskApp = ({ children, queryClient, theme, appId, appEnvironmentVar, providers }) => {
48
81
  const fallbackQueryClient = useMemo(() => createQueryClient(), []);
49
82
  const client = queryClient ?? fallbackQueryClient;
50
- const wrapped = (providers ?? []).reduceRight((inner, Provider) => /* @__PURE__ */ jsx(Provider, { children: inner }), children);
83
+ const wrapped = (providers ?? []).reduceRight((inner, entry) => mount(entry, inner), children);
51
84
  return /* @__PURE__ */ jsx(ThemeProvider, {
52
85
  theme,
53
86
  children: /* @__PURE__ */ jsx(AppConfigProvider, {
@@ -61,6 +94,6 @@ var EveryskApp = ({ children, queryClient, theme, appId, appEnvironmentVar, prov
61
94
  });
62
95
  };
63
96
  //#endregion
64
- export { EveryskApp };
97
+ export { EveryskApp, withProps };
65
98
 
66
99
  //# sourceMappingURL=EveryskApp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EveryskApp.js","names":[],"sources":["../src/EveryskApp.tsx"],"sourcesContent":["import { useMemo, type ComponentType, type PropsWithChildren, type ReactNode } from \"react\";\n\nimport { QueryClientProvider, type QueryClient } from \"@tanstack/react-query\";\n\nimport { ThemeProvider } from \"@/theme/ThemeProvider\";\nimport { AppConfigProvider } from \"@/contexts/appConfigContext/provider\";\nimport { AppAlertProvider } from \"@/contexts/appAlertContext/provider\";\nimport { createQueryClient } from \"@/lib/queryClient\";\nimport type { AnyRecord } from \"@/types/anyRecord\";\nimport type { Theme } from \"@mui/material/styles\";\n\n/** A provider is any component that renders its children. */\nexport type ProviderComponent = ComponentType<PropsWithChildren>;\n\nexport type EveryskAppProps = PropsWithChildren<{\n /**\n * The client every `useQuery` in the tree talks to. Defaults to a fresh\n * `createQueryClient()` created once per mount. Pass one to seed the cache, to share it\n * with code outside the tree, or to assert on it from a test.\n */\n queryClient?: QueryClient;\n /** Overrides `window.APP_ID`. */\n appId?: string | null;\n /**\n * The MUI theme. Omitted, the app gets the Everysk dark theme — see `ThemeProvider`.\n */\n theme?: Theme;\n /** Overrides `window.APP_CONFIG` wholesale. */\n appEnvironmentVar?: AnyRecord;\n /**\n * Optional providers, applied innermost — inside every core provider and directly around\n * `children`, in array order, so the first entry is outermost of the group.\n *\n * They go innermost rather than into named slots because that is the only position from\n * which a provider can read every core context (theme, app config, query client, alerts).\n * `modules.json` kept an explicit `providerOrder` only because the app owned the tree and\n * each module had to be hand-wired into the right slot; owning the tree here is what\n * retires that contract.\n */\n providers?: ProviderComponent[];\n}>;\n\n/**\n * EveryskApp\n *\n * The provider tree every Everysk app mounts, composed in one fixed order:\n *\n * ```\n * ThemeProvider\n * AppConfigProvider\n * QueryClientProvider\n * AppAlertProvider\n * …providers\n * children\n * ```\n *\n * The order is not arbitrary. `AppAlertProvider` renders MUI's `Snackbar`, so it must sit\n * inside `ThemeProvider`; and `QueryClientProvider` sits inside `AppConfigProvider` because\n * entity hooks build their Axios instance from `useAppConfig()`.\n *\n * `BroadcastChannelProvider` used to sit between theme and app configuration. It is gone: the\n * optional socket layer supersedes it for cross-tab and server-push messaging (as\n * `modules.json` already stated), and the one production path that still used it — app\n * configuration arriving over the channel — was replaced by `window.APP_CONFIG`.\n *\n * `src/test/renderWithProviders` renders through this same component, so a test and the real\n * app can never see different trees.\n *\n * @example\n * ```tsx\n * // src/App.tsx — the entire file\n * export function App() {\n * return (\n * <EveryskApp>\n * <Routes />\n * </EveryskApp>\n * );\n * }\n * ```\n */\nexport const EveryskApp = ({\n children,\n queryClient,\n theme,\n appId,\n appEnvironmentVar,\n providers,\n}: EveryskAppProps) => {\n // Only used when the caller passes no client. Created once per mount so a re-render\n // never swaps the cache out from under the tree.\n const fallbackQueryClient = useMemo(() => createQueryClient(), []);\n const client = queryClient ?? fallbackQueryClient;\n\n const wrapped = (providers ?? []).reduceRight<ReactNode>(\n (inner, Provider) => <Provider>{inner}</Provider>,\n children,\n );\n\n return (\n <ThemeProvider theme={theme}>\n <AppConfigProvider appId={appId} appEnvironmentVar={appEnvironmentVar}>\n <QueryClientProvider client={client}>\n <AppAlertProvider>{wrapped}</AppAlertProvider>\n </QueryClientProvider>\n </AppConfigProvider>\n </ThemeProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgFA,IAAa,cAAc,EACvB,UACA,aACA,OACA,OACA,mBACA,gBACmB;CAGnB,MAAM,sBAAsB,cAAc,kBAAkB,GAAG,CAAC,CAAC;CACjE,MAAM,SAAS,eAAe;CAE9B,MAAM,WAAW,aAAa,CAAC,EAAA,CAAG,aAC7B,OAAO,aAAa,oBAAC,UAAD,EAAA,UAAW,MAAgB,CAAA,GAChD,QACJ;CAEA,OACI,oBAAC,eAAD;EAAsB;EAClB,UAAA,oBAAC,mBAAD;GAA0B;GAA0B;GAChD,UAAA,oBAAC,qBAAD;IAA6B;IACzB,UAAA,oBAAC,kBAAD,EAAA,UAAmB,QAA0B,CAAA;GAC5B,CAAA;EACN,CAAA;CACR,CAAA;AAEvB"}
1
+ {"version":3,"file":"EveryskApp.js","names":[],"sources":["../src/EveryskApp.tsx"],"sourcesContent":["import { useMemo, type ComponentType, type PropsWithChildren, type ReactNode } from \"react\";\n\nimport { QueryClientProvider, type QueryClient } from \"@tanstack/react-query\";\n\nimport { ThemeProvider } from \"@/theme/ThemeProvider\";\nimport { AppConfigProvider } from \"@/contexts/appConfigContext/provider\";\nimport { AppAlertProvider } from \"@/contexts/appAlertContext/provider\";\nimport { createQueryClient } from \"@/lib/queryClient\";\nimport type { AnyRecord } from \"@/types/anyRecord\";\nimport type { Theme } from \"@mui/material/styles\";\n\n/** A provider is any component that renders its children. */\nexport type ProviderComponent = ComponentType<PropsWithChildren>;\n\n/** A provider with the props it is mounted with, as `withProps` describes it. */\nexport type ConfiguredProvider = {\n readonly component: ComponentType<PropsWithChildren<AnyRecord>>;\n readonly props: AnyRecord;\n};\n\n/** What `providers` takes: a provider, or one with its props. */\nexport type ProviderEntry = ProviderComponent | ConfiguredProvider;\n\n/**\n * withProps\n *\n * A provider for `EveryskApp`'s `providers`, mounted with these props. `providers` mounts a bare\n * component as `<Provider>{children}</Provider>`, so a provider configured by a prop — AG Grid's\n * license key — needs its props said here:\n *\n * ```tsx\n * <EveryskApp\n * providers={[\n * withProps(AgGridLicenseProvider, { licenseKey: import.meta.env.VITE_AG_GRID_LICENSE_KEY }),\n * WebSocketProvider,\n * ]}\n * >\n * ```\n *\n * It describes the provider rather than returning a wrapper component: a wrapper made in `App`'s\n * render is a new component type each time, and React would remount the whole app under it on\n * every render. The props are checked against the component's own.\n */\nexport const withProps = <P extends { children?: ReactNode }>(\n component: ComponentType<P>,\n props: NoInfer<Omit<P, \"children\">>,\n): ConfiguredProvider => ({\n component: component as ComponentType<PropsWithChildren<AnyRecord>>,\n props: props as AnyRecord,\n});\n\nconst isConfigured = (entry: ProviderEntry): entry is ConfiguredProvider =>\n typeof entry === \"object\" && entry !== null && \"component\" in entry && \"props\" in entry;\n\nconst mount = (entry: ProviderEntry, children: ReactNode): ReactNode => {\n if (!isConfigured(entry)) {\n const Provider = entry;\n return <Provider>{children}</Provider>;\n }\n const { component: Provider, props } = entry;\n return <Provider {...props}>{children}</Provider>;\n};\n\nexport type EveryskAppProps = PropsWithChildren<{\n /**\n * The client every `useQuery` in the tree talks to. Defaults to a fresh\n * `createQueryClient()` created once per mount. Pass one to seed the cache, to share it\n * with code outside the tree, or to assert on it from a test.\n */\n queryClient?: QueryClient;\n /** Overrides `window.APP_ID`. */\n appId?: string | null;\n /**\n * The MUI theme. Omitted, the app gets the Everysk dark theme — see `ThemeProvider`.\n */\n theme?: Theme;\n /** Overrides `window.APP_CONFIG` wholesale. */\n appEnvironmentVar?: AnyRecord;\n /**\n * Optional providers, applied innermost — inside every core provider and directly around\n * `children`, in array order, so the first entry is outermost of the group.\n *\n * They go innermost rather than into named slots because that is the only position from\n * which a provider can read every core context (theme, app config, query client, alerts).\n * `modules.json` kept an explicit `providerOrder` only because the app owned the tree and\n * each module had to be hand-wired into the right slot; owning the tree here is what\n * retires that contract.\n *\n * A provider configured by props goes in through `withProps`.\n */\n providers?: ProviderEntry[];\n}>;\n\n/**\n * EveryskApp\n *\n * The provider tree every Everysk app mounts, composed in one fixed order:\n *\n * ```\n * ThemeProvider\n * AppConfigProvider\n * QueryClientProvider\n * AppAlertProvider\n * …providers\n * children\n * ```\n *\n * The order is not arbitrary. `AppAlertProvider` renders MUI's `Snackbar`, so it must sit\n * inside `ThemeProvider`; and `QueryClientProvider` sits inside `AppConfigProvider` because\n * entity hooks build their Axios instance from `useAppConfig()`.\n *\n * `BroadcastChannelProvider` used to sit between theme and app configuration. It is gone: the\n * optional socket layer supersedes it for cross-tab and server-push messaging (as\n * `modules.json` already stated), and the one production path that still used it — app\n * configuration arriving over the channel — was replaced by `window.APP_CONFIG`.\n *\n * `src/test/renderWithProviders` renders through this same component, so a test and the real\n * app can never see different trees.\n *\n * @example\n * ```tsx\n * // src/App.tsx — the entire file\n * export function App() {\n * return (\n * <EveryskApp>\n * <Routes />\n * </EveryskApp>\n * );\n * }\n * ```\n */\nexport const EveryskApp = ({\n children,\n queryClient,\n theme,\n appId,\n appEnvironmentVar,\n providers,\n}: EveryskAppProps) => {\n // Only used when the caller passes no client. Created once per mount so a re-render\n // never swaps the cache out from under the tree.\n const fallbackQueryClient = useMemo(() => createQueryClient(), []);\n const client = queryClient ?? fallbackQueryClient;\n\n const wrapped = (providers ?? []).reduceRight<ReactNode>(\n (inner, entry) => mount(entry, inner),\n children,\n );\n\n return (\n <ThemeProvider theme={theme}>\n <AppConfigProvider appId={appId} appEnvironmentVar={appEnvironmentVar}>\n <QueryClientProvider client={client}>\n <AppAlertProvider>{wrapped}</AppAlertProvider>\n </QueryClientProvider>\n </AppConfigProvider>\n </ThemeProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,IAAa,aACT,WACA,WACsB;CACX;CACJ;AACX;AAEA,IAAM,gBAAgB,UAClB,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe,SAAS,WAAW;AAEtF,IAAM,SAAS,OAAsB,aAAmC;CACpE,IAAI,CAAC,aAAa,KAAK,GAEnB,OAAO,oBAAC,OAAD,EAAW,SAAmB,CAAA;CAEzC,MAAM,EAAE,WAAW,UAAU,UAAU;CACvC,OAAO,oBAAC,UAAD;EAAU,GAAI;EAAQ;CAAmB,CAAA;AACpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsEA,IAAa,cAAc,EACvB,UACA,aACA,OACA,OACA,mBACA,gBACmB;CAGnB,MAAM,sBAAsB,cAAc,kBAAkB,GAAG,CAAC,CAAC;CACjE,MAAM,SAAS,eAAe;CAE9B,MAAM,WAAW,aAAa,CAAC,EAAA,CAAG,aAC7B,OAAO,UAAU,MAAM,OAAO,KAAK,GACpC,QACJ;CAEA,OACI,oBAAC,eAAD;EAAsB;EAClB,UAAA,oBAAC,mBAAD;GAA0B;GAA0B;GAChD,UAAA,oBAAC,qBAAD;IAA6B;IACzB,UAAA,oBAAC,kBAAD,EAAA,UAAmB,QAA0B,CAAA;GAC5B,CAAA;EACN,CAAA;CACR,CAAA;AAEvB"}
@@ -0,0 +1,53 @@
1
+ import type { GridApi } from "ag-grid-community";
2
+ /**
3
+ * The part of an infinite query this needs. Structural, so it takes any list hook's `query`,
4
+ * or a `useInfiniteQuery` an app writes itself.
5
+ */
6
+ export type InfiniteQueryPaging = {
7
+ hasNextPage: boolean;
8
+ isFetchingNextPage: boolean;
9
+ fetchNextPage: (options?: {
10
+ cancelRefetch?: boolean;
11
+ }) => Promise<unknown>;
12
+ };
13
+ export type HandleRowsScrollEndOptions = {
14
+ /**
15
+ * Distance in pixels from the end of the rows at which the next page is requested. Named and
16
+ * measured as MUI X DataGrid's `scrollEndThreshold`, whose default it shares. Pixels rather
17
+ * than rows, so it holds with rows of different heights.
18
+ */
19
+ scrollEndThreshold?: number;
20
+ };
21
+ /**
22
+ * handleRowsScrollEnd
23
+ *
24
+ * Requests the next page when an AG Grid is scrolled near its last row, or shows none — the
25
+ * grid paging on demand. The handler for what MUI X DataGrid calls `onRowsScrollEnd`; wire it
26
+ * to AG Grid's `onBodyScrollEnd` and `onModelUpdated`, the second so that a grid whose rows a
27
+ * client-side filter hid entirely keeps loading.
28
+ *
29
+ * A function, not part of any hook: the data hook does not know a grid exists, and the grid
30
+ * does not know where its rows come from. It lives in this subpath because it needs `GridApi`,
31
+ * and AG Grid is an optional peer.
32
+ *
33
+ * Events fire in bursts, before `isFetchingNextPage` has flipped, so the request is made with
34
+ * `cancelRefetch: false`: TanStack then ignores a repeat while the first one is in flight,
35
+ * instead of cancelling it and asking for the same page again.
36
+ *
37
+ * @param {GridApi} gridApi - The grid, from the event (`event.api`).
38
+ * @param {InfiniteQueryPaging} query - The infinite query feeding the grid.
39
+ * @param {HandleRowsScrollEndOptions} [options] - `scrollEndThreshold`, in pixels (default 80).
40
+ *
41
+ * Example:
42
+ * ```tsx
43
+ * const { query } = useFetchDatastores({ filters, select: toRows });
44
+ *
45
+ * <AgGridReact
46
+ * rowData={query.data}
47
+ * onBodyScrollEnd={(event) => handleRowsScrollEnd(event.api, query)}
48
+ * onModelUpdated={(event) => handleRowsScrollEnd(event.api, query)}
49
+ * />
50
+ * ```
51
+ */
52
+ export declare const handleRowsScrollEnd: (gridApi: GridApi, query: InfiniteQueryPaging, { scrollEndThreshold }?: HandleRowsScrollEndOptions) => void;
53
+ //# sourceMappingURL=handleRowsScrollEnd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleRowsScrollEnd.d.ts","sourceRoot":"","sources":["../../src/agGrid/handleRowsScrollEnd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9E,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACrC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,mBAAmB,GAC5B,SAAS,OAAO,EAChB,OAAO,mBAAmB,EAC1B,yBAA6B,0BAA+B,KAC7D,IAcF,CAAC"}