@everysk/apps-sdk 0.2.0 → 0.3.0-beta-20261019175049
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 +342 -12
- 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/msw/fakeApi.d.ts +43 -0
- package/dist/test/msw/fakeApi.d.ts.map +1 -0
- package/dist/test/msw/fakeApi.js +74 -0
- package/dist/test/msw/fakeApi.js.map +1 -0
- package/dist/test/msw/handlers.d.ts +20 -0
- package/dist/test/msw/handlers.d.ts.map +1 -0
- package/dist/test/msw/handlers.js +279 -0
- package/dist/test/msw/handlers.js.map +1 -0
- package/dist/test/msw/index.d.ts +5 -0
- package/dist/test/msw/index.d.ts.map +1 -0
- package/dist/test/msw/index.js +2 -0
- package/dist/test/msw/query.d.ts +34 -0
- package/dist/test/msw/query.d.ts.map +1 -0
- package/dist/test/msw/query.js +96 -0
- package/dist/test/msw/query.js.map +1 -0
- package/dist/test/msw/recorder.d.ts +30 -0
- package/dist/test/msw/recorder.d.ts.map +1 -0
- package/dist/test/msw/recorder.js +65 -0
- package/dist/test/msw/recorder.js.map +1 -0
- package/dist/test/msw/store.d.ts +57 -0
- package/dist/test/msw/store.d.ts.map +1 -0
- package/dist/test/msw/store.js +145 -0
- package/dist/test/msw/store.js.map +1 -0
- 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 +10 -1
- 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/msw/fakeApi.ts +83 -0
- package/src/test/msw/handlers.ts +350 -0
- package/src/test/msw/index.ts +9 -0
- package/src/test/msw/query.ts +134 -0
- package/src/test/msw/recorder.ts +88 -0
- package/src/test/msw/store.ts +182 -0
- 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
|
@@ -63,7 +63,7 @@ to nested JSX in the right slot.
|
|
|
63
63
|
| `theme` | A MUI theme. Omitted, the app mounts the Everysk dark theme |
|
|
64
64
|
| `queryClient` | Defaults to a fresh `createQueryClient()`, created once per mount |
|
|
65
65
|
| `appId`, `appEnvironmentVar` | Override `window.APP_ID` / `window.APP_CONFIG`, for tests and hosts that resolve configuration themselves |
|
|
66
|
-
| `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
67
|
|
|
68
68
|
## What it exports
|
|
69
69
|
|
|
@@ -83,10 +83,57 @@ a list rendered.
|
|
|
83
83
|
| File | `useFetchFile` | `useFetchFiles` | `useFileMutations` |
|
|
84
84
|
| Workspace | `useFetchWorkspace` | `useFetchWorkspaces` | — |
|
|
85
85
|
| Profile | `useFetchProfile` | — | — |
|
|
86
|
-
| Workflow | `useFetchWorkflow` | `useFetchWorkflows` | `useRunWorkflow` |
|
|
86
|
+
| Workflow | `useFetchWorkflow` | `useFetchWorkflows` | `useTriggerWorkflow`, `useRunWorkflow` |
|
|
87
87
|
|
|
88
88
|
Workflow carries four more for the run side: `useFetchWorkflowExecution(s)` and
|
|
89
|
-
`useFetchWorkerExecution(s)`.
|
|
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.
|
|
90
137
|
|
|
91
138
|
```tsx
|
|
92
139
|
const { query, queryKey } = useFetchPortfolios({
|
|
@@ -103,6 +150,197 @@ directly, so `const { data, isLoading, queryKey } = useFetchPortfolio({ id, work
|
|
|
103
150
|
Mutations return `{ create, update, remove }`, each a React Query mutation that shows an alert on
|
|
104
151
|
success and failure through `useAppAlert`.
|
|
105
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
|
+
|
|
106
344
|
### Components
|
|
107
345
|
|
|
108
346
|
Five, all MUI underneath.
|
|
@@ -110,7 +348,7 @@ Five, all MUI underneath.
|
|
|
110
348
|
| Component | Props | |
|
|
111
349
|
|---|---|---|
|
|
112
350
|
| `PageContainer` | `header?`, `footer?`, `contentClassName?` | The page frame: chrome around a scrolling content area |
|
|
113
|
-
| `Toolbar` | `className?` | Top bar
|
|
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` |
|
|
114
352
|
| `Footer` | `className?` | Bottom bar |
|
|
115
353
|
| `GlobalLoading` | `isLoading`, `backdrop?`, `message?` | Full-page spinner. `backdrop` defaults to `true` |
|
|
116
354
|
| `EveryskIcon` | every `SvgIconProps` except `color` | The brand mark |
|
|
@@ -119,8 +357,15 @@ Five, all MUI underneath.
|
|
|
119
357
|
but a utility loses to MUI's own styles in the cascade, so reach for `sx` when one is dropped.
|
|
120
358
|
`GlobalLoading` takes no `className`, and `EveryskIcon` gets one through `SvgIconProps`.
|
|
121
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
|
+
|
|
122
364
|
```tsx
|
|
123
|
-
<PageContainer
|
|
365
|
+
<PageContainer
|
|
366
|
+
header={<Toolbar title="Trade Allocation" action={<DateFilter />} />}
|
|
367
|
+
footer={<Footer />}
|
|
368
|
+
>
|
|
124
369
|
<GlobalLoading isLoading={query.isLoading} message="Loading portfolios…" />
|
|
125
370
|
{/* the page */}
|
|
126
371
|
</PageContainer>
|
|
@@ -139,14 +384,19 @@ but a utility loses to MUI's own styles in the cascade, so reach for `sx` when o
|
|
|
139
384
|
`EveryskDarkTheme`, `EveryskLightTheme`, `DefaultDarkTheme`, `DefaultLightTheme` and
|
|
140
385
|
`MidnightEmberTheme`, plus `getTheme(name)` to resolve one by the name the CLI writes, and
|
|
141
386
|
`getBrandTheme(mode)` / `getDefaultTheme(mode)` for the pair. `EveryskApp` mounts the brand dark
|
|
142
|
-
theme unless given a `theme` prop.
|
|
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.
|
|
143
389
|
|
|
144
390
|
### Query client and helpers
|
|
145
391
|
|
|
146
392
|
`createQueryClient(config?)` builds the QueryClient `EveryskApp` mounts — a factory rather than a
|
|
147
393
|
shared instance, because two apps or two tests sharing one client share its cache.
|
|
148
|
-
`
|
|
149
|
-
|
|
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.
|
|
150
400
|
|
|
151
401
|
`useAxios`'s interceptor is worth knowing about if you write one of those: on `GET` and `DELETE`
|
|
152
402
|
it parses the request's query object into the shape the platform API expects. It is attached in
|
|
@@ -167,6 +417,7 @@ which npm does not install for you:
|
|
|
167
417
|
| `/ag-grid` | `ag-grid-community`, `ag-grid-enterprise` |
|
|
168
418
|
| `/socket` | `socket.io-client` |
|
|
169
419
|
| `/test` | `@testing-library/*` |
|
|
420
|
+
| `/test/msw` | `msw` |
|
|
170
421
|
| `/test/mocks` | doubles for the optional peers above |
|
|
171
422
|
| `/test/setup` | the vitest setup file to point `setupFiles` at |
|
|
172
423
|
|
|
@@ -176,13 +427,25 @@ nothing but `createQueryClient`. The subpath is what makes the peer genuinely op
|
|
|
176
427
|
|
|
177
428
|
## The AG Grid licence is a parameter
|
|
178
429
|
|
|
179
|
-
```
|
|
180
|
-
// src/
|
|
181
|
-
import {
|
|
430
|
+
```tsx
|
|
431
|
+
// src/App.tsx
|
|
432
|
+
import { EveryskApp, withProps } from "@everysk/apps-sdk";
|
|
433
|
+
import { AgGridLicenseProvider } from "@everysk/apps-sdk/ag-grid";
|
|
434
|
+
|
|
435
|
+
const agGridLicense = withProps(AgGridLicenseProvider, {
|
|
436
|
+
licenseKey: import.meta.env.VITE_AG_GRID_LICENSE_KEY,
|
|
437
|
+
});
|
|
182
438
|
|
|
183
|
-
|
|
439
|
+
export function App() {
|
|
440
|
+
return <EveryskApp providers={[agGridLicense]}>…</EveryskApp>;
|
|
441
|
+
}
|
|
184
442
|
```
|
|
185
443
|
|
|
444
|
+
`providers` mounts a bare component with no props, so a bare `AgGridLicenseProvider` there
|
|
445
|
+
registers nothing; `withProps` is what carries the key, checked against the provider's props. It describes
|
|
446
|
+
the provider rather than wrapping it, so calling it inside a render does not remount the app.
|
|
447
|
+
`setAgGridLicense(key)`, called once in `main.tsx`, does the same without a provider.
|
|
448
|
+
|
|
186
449
|
This package never reads your environment. Vite replaces `import.meta.env.VITE_*` with a literal
|
|
187
450
|
at the build of whoever compiles the file — for a published package that is this package's own
|
|
188
451
|
CI, where the variable does not exist, so the value would freeze as `undefined` and your
|
|
@@ -193,6 +456,30 @@ is the AG Grid watermark.
|
|
|
193
456
|
any theme — including one the app creates — gets a matching grid without a second table of
|
|
194
457
|
colours.
|
|
195
458
|
|
|
459
|
+
## Paging an AG Grid on scroll
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
import { handleRowsScrollEnd } from "@everysk/apps-sdk/ag-grid";
|
|
463
|
+
|
|
464
|
+
const { query } = useFetchDatastores({ filters, select: toRows });
|
|
465
|
+
|
|
466
|
+
<AgGridReact
|
|
467
|
+
rowData={query.data}
|
|
468
|
+
onBodyScrollEnd={(event) => handleRowsScrollEnd(event.api, query)}
|
|
469
|
+
onModelUpdated={(event) => handleRowsScrollEnd(event.api, query)}
|
|
470
|
+
/>
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
It requests the next page when the grid is scrolled within `scrollEndThreshold` pixels of its
|
|
474
|
+
last row, or shows no rows — the second event is what keeps a grid whose rows a filter hid
|
|
475
|
+
entirely loading. The names are MUI X DataGrid's (`onRowsScrollEnd`, `scrollEndThreshold`, default
|
|
476
|
+
`80`), and so is the unit: pixels, which hold when rows differ in height.
|
|
477
|
+
|
|
478
|
+
A function rather than part of a hook: it takes any infinite query's `hasNextPage`,
|
|
479
|
+
`isFetchingNextPage` and `fetchNextPage`, so it pages any list hook or a `useInfiniteQuery` of the
|
|
480
|
+
app's own. Grid events arrive in bursts, so it asks with `cancelRefetch: false` and a repeat
|
|
481
|
+
while the first request is in flight does nothing.
|
|
482
|
+
|
|
196
483
|
## Testing an app against it
|
|
197
484
|
|
|
198
485
|
```ts
|
|
@@ -210,6 +497,49 @@ renderWithProviders(<Home />, { appId: "app_42" });
|
|
|
210
497
|
test and the real app cannot see different contexts. Each render gets a fresh QueryClient with
|
|
211
498
|
retries and caching off.
|
|
212
499
|
|
|
500
|
+
`@everysk/apps-sdk/test/msw` fakes the API behind `/api` with [MSW](https://mswjs.io), so a
|
|
501
|
+
page renders with the SDK's real hooks, axios instance and query cache, and only the API is
|
|
502
|
+
pretend. It needs `msw` installed (`^2.15` or `^3`) as a devDependency.
|
|
503
|
+
|
|
504
|
+
```tsx
|
|
505
|
+
import { setupFakeApi } from "@everysk/apps-sdk/test/msw";
|
|
506
|
+
|
|
507
|
+
const api = setupFakeApi(); // once per file: listens, and resets after every test
|
|
508
|
+
|
|
509
|
+
it("lists the alert datastores", async () => {
|
|
510
|
+
api.seed({ datastores: [{ name: "Alertas de hoje", link_uid: "ALERTAS" }] });
|
|
511
|
+
|
|
512
|
+
renderWithProviders(<Panel />, { appEnvironmentVar: { workspace: "main" } });
|
|
513
|
+
|
|
514
|
+
expect(await screen.findByText("Alertas de hoje")).toBeInTheDocument();
|
|
515
|
+
expect(api.requests[0]?.query).toMatchObject({ filters: [["workspace", "main"], ["link_uid", "ALERTAS"]] });
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
it("shows the error", async () => {
|
|
519
|
+
api.fail("GET", "/datastores", 500); // the next matching request gets the API's error body
|
|
520
|
+
// ...
|
|
521
|
+
});
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
Every request an SDK hook sends is answered, the way the API answers it:
|
|
525
|
+
|
|
526
|
+
| Seed key | Routes | As the API does |
|
|
527
|
+
|---|---|---|
|
|
528
|
+
| `datastores`, `files`, `portfolios` | list, read, create, update, delete | a JSON query's filters (`=`, `!=`, `<`, `<=`, `>`, `>=`, `IN`, `NOT_IN`), `order`, `projection` (a comma-joined string or mixed inclusions and exclusions is a 500) and pages of 20, the URL's `page_size` and `page_token` winning; a file read without data unless `with_data`, a created file given its `/file/<hash>` url |
|
|
529
|
+
| `workflows` | list, read, `POST …/run` | a text search (id, `#tag`, `&link_uid`, name prefix, 10 a page) in the `workspace` given; a run answers 202 with a `RUNNING` execution, added to `workflowExecutions` |
|
|
530
|
+
| `workflowExecutions`, `workerExecutions` | `…/workflow_executions`, `…/worker_executions` | the URL's parameters only; worker executions grouped by worker, unpaginated |
|
|
531
|
+
| `workspaces` | list, read by name | a text search |
|
|
532
|
+
| `profile`, `websocketsConfig` | `GET /profile`, `GET /websockets_config` | the SDK's `DEV_PROFILE` and a blank config unless seeded |
|
|
533
|
+
|
|
534
|
+
A create defaults the workspace to `main`, a delete answers with one `{ id, name, deleted }`, and
|
|
535
|
+
errors come as `{ code, message }`. A seeded record needs only the fields the test cares about.
|
|
536
|
+
A request it has no handler for fails the test; add one of the app's own with
|
|
537
|
+
`api.server.use(...)`. `useRunWorkflow` waits for a run's end over the websocket, which this does
|
|
538
|
+
not fake: pair it with the socket double in `@everysk/apps-sdk/test/mocks`.
|
|
539
|
+
|
|
540
|
+
It replaces mocking the SDK's modules: `vi.mock("@everysk/apps-sdk")` replaces only what the app's
|
|
541
|
+
own code imports, never the api modules the hooks reach through the SDK's internal imports.
|
|
542
|
+
|
|
213
543
|
`@everysk/apps-sdk/test/mocks` carries opt-in doubles for the optional peers: `ag-grid-react`
|
|
214
544
|
(renders rows and cells as plain DOM, so assertions about the data still hold),
|
|
215
545
|
`ag-grid-enterprise` (captures the registered licence, readable with `getAgGridLicenseKey()`)
|
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"}
|