@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.
- package/README.md +395 -8
- package/dist/EveryskApp.d.ts +34 -2
- package/dist/EveryskApp.d.ts.map +1 -1
- package/dist/EveryskApp.js +35 -2
- package/dist/EveryskApp.js.map +1 -1
- package/dist/agGrid/handleRowsScrollEnd.d.ts +53 -0
- package/dist/agGrid/handleRowsScrollEnd.d.ts.map +1 -0
- package/dist/agGrid/handleRowsScrollEnd.js +47 -0
- package/dist/agGrid/handleRowsScrollEnd.js.map +1 -0
- package/dist/agGrid/index.d.ts +2 -0
- package/dist/agGrid/index.d.ts.map +1 -1
- package/dist/agGrid/index.js +2 -1
- package/dist/api/datastore.d.ts +10 -8
- package/dist/api/datastore.d.ts.map +1 -1
- package/dist/api/datastore.js +24 -55
- package/dist/api/datastore.js.map +1 -1
- package/dist/api/entityQuery.d.ts +46 -41
- package/dist/api/entityQuery.d.ts.map +1 -1
- package/dist/api/entityQuery.js +55 -14
- package/dist/api/entityQuery.js.map +1 -1
- package/dist/api/file.d.ts +26 -9
- package/dist/api/file.d.ts.map +1 -1
- package/dist/api/file.js +45 -55
- package/dist/api/file.js.map +1 -1
- package/dist/api/portfolio.d.ts +11 -8
- package/dist/api/portfolio.d.ts.map +1 -1
- package/dist/api/portfolio.js +24 -55
- package/dist/api/portfolio.js.map +1 -1
- package/dist/api/profile.d.ts +3 -2
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +4 -9
- package/dist/api/profile.js.map +1 -1
- package/dist/api/request.d.ts +106 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +132 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/websocketsConfig.d.ts +7 -2
- package/dist/api/websocketsConfig.d.ts.map +1 -1
- package/dist/api/websocketsConfig.js +2 -10
- package/dist/api/websocketsConfig.js.map +1 -1
- package/dist/api/workflow.d.ts +84 -89
- package/dist/api/workflow.d.ts.map +1 -1
- package/dist/api/workflow.js +121 -208
- package/dist/api/workflow.js.map +1 -1
- package/dist/api/workspace.d.ts +18 -8
- package/dist/api/workspace.d.ts.map +1 -1
- package/dist/api/workspace.js +21 -26
- package/dist/api/workspace.js.map +1 -1
- package/dist/components/ui/Footer/index.d.ts.map +1 -1
- package/dist/components/ui/Footer/index.js.map +1 -1
- package/dist/components/ui/GlobalLoading/index.d.ts.map +1 -1
- package/dist/components/ui/GlobalLoading/index.js.map +1 -1
- package/dist/components/ui/PageContainer/index.d.ts +1 -1
- package/dist/components/ui/PageContainer/index.d.ts.map +1 -1
- package/dist/components/ui/PageContainer/index.js.map +1 -1
- package/dist/components/ui/Toolbar/index.d.ts +40 -3
- package/dist/components/ui/Toolbar/index.d.ts.map +1 -1
- package/dist/components/ui/Toolbar/index.js +42 -15
- package/dist/components/ui/Toolbar/index.js.map +1 -1
- package/dist/contexts/appAlertContext/provider.js.map +1 -1
- package/dist/contexts/appAlertContext/types.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/index.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/index.js.map +1 -1
- package/dist/contexts/appConfigContext/provider.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/provider.js.map +1 -1
- package/dist/contexts/webSocketContext/handler.d.ts +3 -2
- package/dist/contexts/webSocketContext/handler.d.ts.map +1 -1
- package/dist/contexts/webSocketContext/handler.js.map +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.d.ts +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js.map +1 -1
- package/dist/contexts/webSocketContext/provider.d.ts +6 -3
- package/dist/contexts/webSocketContext/provider.d.ts.map +1 -1
- package/dist/contexts/webSocketContext/provider.js +42 -7
- package/dist/contexts/webSocketContext/provider.js.map +1 -1
- package/dist/contexts/webSocketContext/types.d.ts +7 -5
- package/dist/contexts/webSocketContext/types.d.ts.map +1 -1
- package/dist/file/index.d.ts +2 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/hooks/datastore/useDatastoreMutations.d.ts +4 -4
- package/dist/hooks/datastore/useDatastoreMutations.d.ts.map +1 -1
- package/dist/hooks/datastore/useDatastoreMutations.js +17 -55
- package/dist/hooks/datastore/useDatastoreMutations.js.map +1 -1
- package/dist/hooks/datastore/useFetchDatastore.d.ts +30 -41
- package/dist/hooks/datastore/useFetchDatastore.d.ts.map +1 -1
- package/dist/hooks/datastore/useFetchDatastore.js +25 -59
- package/dist/hooks/datastore/useFetchDatastore.js.map +1 -1
- package/dist/hooks/datastore/useFetchDatastores.d.ts +47 -52
- package/dist/hooks/datastore/useFetchDatastores.d.ts.map +1 -1
- package/dist/hooks/datastore/useFetchDatastores.js +55 -70
- package/dist/hooks/datastore/useFetchDatastores.js.map +1 -1
- package/dist/hooks/file/fileData.d.ts +17 -0
- package/dist/hooks/file/fileData.d.ts.map +1 -0
- package/dist/hooks/file/fileData.js +10 -0
- package/dist/hooks/file/fileData.js.map +1 -0
- package/dist/hooks/file/useFetchFile.d.ts +38 -58
- package/dist/hooks/file/useFetchFile.d.ts.map +1 -1
- package/dist/hooks/file/useFetchFile.js +26 -66
- package/dist/hooks/file/useFetchFile.js.map +1 -1
- package/dist/hooks/file/useFetchFiles.d.ts +18 -52
- package/dist/hooks/file/useFetchFiles.d.ts.map +1 -1
- package/dist/hooks/file/useFetchFiles.js +53 -69
- package/dist/hooks/file/useFetchFiles.js.map +1 -1
- package/dist/hooks/file/useFileMutations.d.ts +9 -8
- package/dist/hooks/file/useFileMutations.d.ts.map +1 -1
- package/dist/hooks/file/useFileMutations.js +23 -60
- package/dist/hooks/file/useFileMutations.js.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolio.d.ts +16 -50
- package/dist/hooks/portfolio/useFetchPortfolio.d.ts.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolio.js +15 -63
- package/dist/hooks/portfolio/useFetchPortfolio.js.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolios.d.ts +13 -52
- package/dist/hooks/portfolio/useFetchPortfolios.d.ts.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolios.js +29 -71
- package/dist/hooks/portfolio/useFetchPortfolios.js.map +1 -1
- package/dist/hooks/portfolio/usePortfolioMutations.d.ts +8 -8
- package/dist/hooks/portfolio/usePortfolioMutations.d.ts.map +1 -1
- package/dist/hooks/portfolio/usePortfolioMutations.js +20 -58
- package/dist/hooks/portfolio/usePortfolioMutations.js.map +1 -1
- package/dist/hooks/profile/useFetchProfile.d.ts +18 -44
- package/dist/hooks/profile/useFetchProfile.d.ts.map +1 -1
- package/dist/hooks/profile/useFetchProfile.js +16 -48
- package/dist/hooks/profile/useFetchProfile.js.map +1 -1
- package/dist/hooks/useAxios.js.map +1 -1
- package/dist/hooks/useEntityInfiniteQuery.d.ts +88 -0
- package/dist/hooks/useEntityInfiniteQuery.d.ts.map +1 -0
- package/dist/hooks/useEntityInfiniteQuery.js +111 -0
- package/dist/hooks/useEntityInfiniteQuery.js.map +1 -0
- package/dist/hooks/useEntityMutation.d.ts +47 -0
- package/dist/hooks/useEntityMutation.d.ts.map +1 -0
- package/dist/hooks/useEntityMutation.js +58 -0
- package/dist/hooks/useEntityMutation.js.map +1 -0
- package/dist/hooks/useEntityQuery.d.ts +68 -0
- package/dist/hooks/useEntityQuery.d.ts.map +1 -0
- package/dist/hooks/useEntityQuery.js +75 -0
- package/dist/hooks/useEntityQuery.js.map +1 -0
- package/dist/hooks/workflow/useFetchWorkerExecution.d.ts +17 -34
- package/dist/hooks/workflow/useFetchWorkerExecution.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecution.js +16 -46
- package/dist/hooks/workflow/useFetchWorkerExecution.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts +179 -41
- package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecutions.js +29 -62
- package/dist/hooks/workflow/useFetchWorkerExecutions.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflow.d.ts +16 -35
- package/dist/hooks/workflow/useFetchWorkflow.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflow.js +15 -48
- package/dist/hooks/workflow/useFetchWorkflow.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts +17 -34
- package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecution.js +16 -46
- package/dist/hooks/workflow/useFetchWorkflowExecution.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts +22 -36
- package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecutions.js +43 -56
- package/dist/hooks/workflow/useFetchWorkflowExecutions.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflows.d.ts +20 -37
- package/dist/hooks/workflow/useFetchWorkflows.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflows.js +32 -47
- package/dist/hooks/workflow/useFetchWorkflows.js.map +1 -1
- package/dist/hooks/workflow/useRunWorkflow.d.ts +21 -16
- package/dist/hooks/workflow/useRunWorkflow.d.ts.map +1 -1
- package/dist/hooks/workflow/useRunWorkflow.js +66 -29
- package/dist/hooks/workflow/useRunWorkflow.js.map +1 -1
- package/dist/hooks/workflow/useTriggerWorkflow.d.ts +20 -0
- package/dist/hooks/workflow/useTriggerWorkflow.d.ts.map +1 -0
- package/dist/hooks/workflow/useTriggerWorkflow.js +32 -0
- package/dist/hooks/workflow/useTriggerWorkflow.js.map +1 -0
- package/dist/hooks/workspace/useFetchWorkspace.d.ts +19 -34
- package/dist/hooks/workspace/useFetchWorkspace.d.ts.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspace.js +16 -46
- package/dist/hooks/workspace/useFetchWorkspace.js.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspaces.d.ts +17 -37
- package/dist/hooks/workspace/useFetchWorkspaces.d.ts.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspaces.js +25 -47
- package/dist/hooks/workspace/useFetchWorkspaces.js.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -11
- package/dist/lib/abort.d.ts +58 -0
- package/dist/lib/abort.d.ts.map +1 -0
- package/dist/lib/abort.js +112 -0
- package/dist/lib/abort.js.map +1 -0
- package/dist/lib/datastoreTable.d.ts +59 -54
- package/dist/lib/datastoreTable.d.ts.map +1 -1
- package/dist/lib/datastoreTable.js +58 -62
- package/dist/lib/datastoreTable.js.map +1 -1
- package/dist/lib/file.d.ts +34 -0
- package/dist/lib/file.d.ts.map +1 -0
- package/dist/lib/file.js +63 -0
- package/dist/lib/file.js.map +1 -0
- package/dist/lib/queryClient.d.ts.map +1 -1
- package/dist/lib/queryClient.js.map +1 -1
- package/dist/lib/workflowRun.d.ts +91 -0
- package/dist/lib/workflowRun.d.ts.map +1 -0
- package/dist/lib/workflowRun.js +224 -0
- package/dist/lib/workflowRun.js.map +1 -0
- package/dist/socket/index.d.ts +1 -3
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +3 -5
- package/dist/test/mocks/index.d.ts +1 -1
- package/dist/test/mocks/index.d.ts.map +1 -1
- package/dist/test/renderWithProviders.d.ts +2 -2
- package/dist/test/renderWithProviders.d.ts.map +1 -1
- package/dist/test/renderWithProviders.js.map +1 -1
- package/dist/test/setup.js.map +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/overrides/index.d.ts +4 -2
- package/dist/theme/overrides/index.d.ts.map +1 -1
- package/dist/theme/overrides/index.js +5 -3
- package/dist/theme/overrides/index.js.map +1 -1
- package/dist/theme/overrides/muiButton.d.ts +2 -2
- package/dist/theme/overrides/muiButton.js.map +1 -1
- package/dist/theme/overrides/muiCssBaseline.d.ts.map +1 -1
- package/dist/theme/overrides/muiCssBaseline.js.map +1 -1
- package/dist/theme/overrides/muiDatePicker.js.map +1 -1
- package/dist/theme/overrides/muiFormControl.js.map +1 -1
- package/dist/theme/overrides/muiIconButton.d.ts +2 -2
- package/dist/theme/overrides/muiIconButton.js.map +1 -1
- package/dist/theme/overrides/muiSelect.d.ts.map +1 -1
- package/dist/theme/overrides/muiSelect.js.map +1 -1
- package/dist/theme/overrides/muiSvgIcon.d.ts.map +1 -1
- package/dist/theme/overrides/muiSvgIcon.js.map +1 -1
- package/dist/theme/overrides/muiTextField.js.map +1 -1
- package/dist/theme/overrides/muiToggleButton.d.ts +2 -2
- package/dist/theme/overrides/muiToggleButton.js.map +1 -1
- package/dist/theme/overrides/muiToggleButtonGroup.d.ts +2 -2
- package/dist/theme/overrides/muiToggleButtonGroup.js.map +1 -1
- package/dist/theme/themes/DefaultDark.js +2 -2
- package/dist/theme/themes/DefaultDark.js.map +1 -1
- package/dist/theme/themes/DefaultLight.js +2 -2
- package/dist/theme/themes/DefaultLight.js.map +1 -1
- package/dist/theme/themes/EveryskDark.js +2 -2
- package/dist/theme/themes/EveryskDark.js.map +1 -1
- package/dist/theme/themes/EveryskLight.js +2 -2
- package/dist/theme/themes/EveryskLight.js.map +1 -1
- package/dist/theme/themes/MidnightEmber.js +2 -2
- package/dist/theme/themes/MidnightEmber.js.map +1 -1
- package/dist/types/anyRecord.d.ts.map +1 -1
- package/dist/types/datastore.d.ts +35 -5
- package/dist/types/datastore.d.ts.map +1 -1
- package/dist/types/datastoreDataFormat.d.ts +13 -0
- package/dist/types/datastoreDataFormat.d.ts.map +1 -0
- package/dist/types/entityQuery.d.ts +86 -16
- package/dist/types/entityQuery.d.ts.map +1 -1
- package/dist/types/file.d.ts +7 -3
- package/dist/types/file.d.ts.map +1 -1
- package/dist/types/portfolio.d.ts +1 -3
- package/dist/types/portfolio.d.ts.map +1 -1
- package/dist/types/profile.d.ts +0 -10
- package/dist/types/profile.d.ts.map +1 -1
- package/dist/types/workflow.d.ts +35 -6
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workspace.d.ts +1 -2
- package/dist/types/workspace.d.ts.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/EveryskApp.tsx +53 -2
- package/src/agGrid/handleRowsScrollEnd.ts +71 -0
- package/src/agGrid/index.ts +5 -1
- package/src/api/datastore.ts +79 -107
- package/src/api/entityQuery.ts +86 -17
- package/src/api/file.ts +110 -103
- package/src/api/portfolio.ts +82 -125
- package/src/api/profile.ts +25 -18
- package/src/api/request.ts +168 -0
- package/src/api/websocketsConfig.ts +11 -19
- package/src/api/workflow.ts +232 -334
- package/src/api/workspace.ts +43 -43
- package/src/components/ui/Footer/index.tsx +8 -7
- package/src/components/ui/GlobalLoading/index.tsx +13 -3
- package/src/components/ui/PageContainer/index.tsx +9 -2
- package/src/components/ui/Toolbar/index.tsx +105 -30
- package/src/contexts/appAlertContext/provider.tsx +1 -1
- package/src/contexts/appAlertContext/types.ts +3 -3
- package/src/contexts/appConfigContext/index.tsx +1 -1
- package/src/contexts/appConfigContext/provider.tsx +1 -5
- package/src/contexts/webSocketContext/handler.ts +8 -2
- package/src/contexts/webSocketContext/hooks/useWebSocket/index.ts +1 -1
- package/src/contexts/webSocketContext/provider.tsx +64 -14
- package/src/contexts/webSocketContext/types.ts +7 -6
- package/src/file/index.ts +2 -0
- package/src/hooks/datastore/useDatastoreMutations.ts +19 -60
- package/src/hooks/datastore/useFetchDatastore.ts +45 -73
- package/src/hooks/datastore/useFetchDatastores.ts +106 -131
- package/src/hooks/file/fileData.ts +19 -0
- package/src/hooks/file/useFetchFile.ts +41 -76
- package/src/hooks/file/useFetchFiles.ts +92 -87
- package/src/hooks/file/useFileMutations.ts +23 -73
- package/src/hooks/portfolio/useFetchPortfolio.ts +26 -78
- package/src/hooks/portfolio/useFetchPortfolios.ts +50 -93
- package/src/hooks/portfolio/usePortfolioMutations.ts +22 -72
- package/src/hooks/profile/useFetchProfile.ts +24 -65
- package/src/hooks/useAxios.ts +5 -5
- package/src/hooks/useEntityInfiniteQuery.ts +193 -0
- package/src/hooks/useEntityMutation.ts +70 -0
- package/src/hooks/useEntityQuery.ts +117 -0
- package/src/hooks/workflow/useFetchWorkerExecution.ts +27 -56
- package/src/hooks/workflow/useFetchWorkerExecutions.ts +54 -79
- package/src/hooks/workflow/useFetchWorkflow.ts +24 -58
- package/src/hooks/workflow/useFetchWorkflowExecution.ts +27 -57
- package/src/hooks/workflow/useFetchWorkflowExecutions.ts +64 -73
- package/src/hooks/workflow/useFetchWorkflows.ts +48 -64
- package/src/hooks/workflow/useRunWorkflow.ts +82 -36
- package/src/hooks/workflow/useTriggerWorkflow.ts +36 -0
- package/src/hooks/workspace/useFetchWorkspace.ts +25 -58
- package/src/hooks/workspace/useFetchWorkspaces.ts +38 -69
- package/src/index.ts +34 -19
- package/src/lib/abort.ts +131 -0
- package/src/lib/datastoreTable.ts +127 -74
- package/src/lib/file.ts +67 -0
- package/src/lib/queryClient.ts +11 -13
- package/src/lib/workflowRun.ts +329 -0
- package/src/socket/index.ts +1 -3
- package/src/test/mocks/index.ts +1 -5
- package/src/test/renderWithProviders.tsx +8 -3
- package/src/test/setup.ts +16 -16
- package/src/theme/index.ts +1 -1
- package/src/theme/overrides/index.ts +5 -3
- package/src/theme/overrides/muiButton.ts +3 -3
- package/src/theme/overrides/muiCssBaseline.ts +11 -12
- package/src/theme/overrides/muiDatePicker.ts +2 -2
- package/src/theme/overrides/muiFormControl.ts +2 -2
- package/src/theme/overrides/muiIconButton.ts +3 -3
- package/src/theme/overrides/muiSelect.ts +2 -2
- package/src/theme/overrides/muiSvgIcon.ts +2 -2
- package/src/theme/overrides/muiTextField.ts +1 -1
- package/src/theme/overrides/muiToggleButton.ts +4 -4
- package/src/theme/overrides/muiToggleButtonGroup.ts +4 -4
- package/src/theme/themes/DefaultDark.ts +2 -2
- package/src/theme/themes/DefaultLight.ts +2 -2
- package/src/theme/themes/EveryskDark.ts +2 -2
- package/src/theme/themes/EveryskLight.ts +2 -2
- package/src/theme/themes/MidnightEmber.ts +15 -15
- package/src/types/anyRecord.ts +2 -2
- package/src/types/datastore.ts +56 -22
- package/src/types/datastoreDataFormat.ts +12 -0
- package/src/types/entityQuery.ts +122 -38
- package/src/types/file.ts +8 -6
- package/src/types/portfolio.ts +70 -74
- package/src/types/profile.ts +0 -11
- package/src/types/workflow.ts +38 -9
- package/src/types/workspace.ts +2 -4
- package/src/ui/index.ts +1 -1
- 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
|
-
|
|
9
|
-
[`@everysk/apps-
|
|
10
|
-
|
|
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
|
-
```
|
|
79
|
-
// src/
|
|
80
|
-
import {
|
|
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
|
-
|
|
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
|
package/dist/EveryskApp.d.ts
CHANGED
|
@@ -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?:
|
|
64
|
+
providers?: ProviderEntry[];
|
|
33
65
|
}>;
|
|
34
66
|
/**
|
|
35
67
|
* EveryskApp
|
package/dist/EveryskApp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EveryskApp.d.ts","sourceRoot":"","sources":["../src/EveryskApp.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,iBAAiB,
|
|
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"}
|
package/dist/EveryskApp.js
CHANGED
|
@@ -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,
|
|
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
|
package/dist/EveryskApp.js.map
CHANGED
|
@@ -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?:
|
|
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"}
|