@everysk/apps-sdk 0.2.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 +298 -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/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 +1 -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/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
|
@@ -1,109 +1,66 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
import { useInfiniteQuery, type UseInfiniteQueryOptions, type QueryKey } from "@tanstack/react-query";
|
|
3
|
-
|
|
4
1
|
import { useAxios } from "@/hooks/useAxios";
|
|
2
|
+
import { useEntityInfiniteQuery } from "@/hooks/useEntityInfiniteQuery";
|
|
5
3
|
import { listPortfolios } from "@/api/portfolio";
|
|
6
|
-
import type { FetchEntitiesParams } from "@/types/entityQuery";
|
|
7
4
|
import type { Portfolio, PortfolioListResponse } from "@/types/portfolio";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
>;
|
|
5
|
+
import type { FetchEntitiesProps, ListQueryProps, ListCache } from "@/types/entityQuery";
|
|
6
|
+
import {
|
|
7
|
+
buildQueryKey,
|
|
8
|
+
buildQueryObject,
|
|
9
|
+
hasWorkspaceFilter,
|
|
10
|
+
missingWorkspaceError,
|
|
11
|
+
} from "@/api/entityQuery";
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
13
|
+
/** The query cache of `useFetchPortfolios`, for typing `setQueryData`. */
|
|
14
|
+
export type PortfoliosCache = ListCache<PortfolioListResponse>;
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
staleTime: 0,
|
|
24
|
-
gcTime: 0,
|
|
25
|
-
};
|
|
16
|
+
export type FetchPortfoliosProps<TData = Portfolio[]> = ListQueryProps &
|
|
17
|
+
FetchEntitiesProps<Portfolio, TData, PortfolioListResponse>;
|
|
26
18
|
|
|
27
19
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* Data-fetching hook built on TanStack Query's `useInfiniteQuery` to retrieve
|
|
31
|
-
* portfolios with cursor-based pagination.
|
|
32
|
-
*
|
|
33
|
-
* It also:
|
|
34
|
-
* - flattens all pages into a single `Portfolio[]` via `select`
|
|
35
|
-
*
|
|
36
|
-
* Important notes:
|
|
37
|
-
* - `query.data` returns a flat `Portfolio[]` (all pages merged).
|
|
38
|
-
*
|
|
39
|
-
* Parameters (FetchInfinitePortfolioProps):
|
|
40
|
-
* @param {FilterClause[]} [filters=[]]
|
|
41
|
-
* Filters applied to every page request. Must include a `workspace` filter.
|
|
42
|
-
*
|
|
43
|
-
* @param {string[]} [order=[]]
|
|
44
|
-
* Sorting applied to every page request.
|
|
45
|
-
*
|
|
46
|
-
* @param {string} [projection=""]
|
|
47
|
-
* Single field to project: `"field"` returns only that field (others come back null),
|
|
48
|
-
* `"-field"` returns every field except that one. One field only — lists 500. Omitted when empty.
|
|
49
|
-
*
|
|
50
|
-
* @param {number} [pageSize=10]
|
|
51
|
-
* Number of portfolios to fetch per page.
|
|
20
|
+
* useFetchPortfolios
|
|
52
21
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
22
|
+
* Lists portfolios with cursor pagination; `query.data` is every loaded page merged, or
|
|
23
|
+
* whatever `select` makes of it. Paging, `select`, `fetchAllPages` and the
|
|
24
|
+
* missing-workspace error behave as in `useFetchDatastores`.
|
|
56
25
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* - `queryKey`: the cache key used by React Query
|
|
61
|
-
*
|
|
62
|
-
* Example:
|
|
63
|
-
* ```ts
|
|
64
|
-
* const { query } = useFetchInfinitePortfolios({
|
|
65
|
-
* filters: [{ field: "workspace", value: "ws-1" }],
|
|
66
|
-
* pageSize: 20,
|
|
67
|
-
* });
|
|
68
|
-
*
|
|
69
|
-
* // Flat list of all fetched portfolios
|
|
70
|
-
* const portfolios = query.data ?? [];
|
|
71
|
-
* ```
|
|
26
|
+
* @param {FetchPortfoliosProps} props - Filters (one must be `workspace`), order,
|
|
27
|
+
* projection, page size, `select`, `fetchAllPages` and TanStack `queryOptions`.
|
|
28
|
+
* @returns {object} `query` (the `useInfiniteQuery` result) and `queryKey`.
|
|
72
29
|
*/
|
|
73
|
-
export function useFetchPortfolios
|
|
30
|
+
export function useFetchPortfolios<TData = Portfolio[]>({
|
|
31
|
+
filters = [],
|
|
32
|
+
order = [],
|
|
33
|
+
projection = "",
|
|
34
|
+
pageSize = 10,
|
|
35
|
+
select,
|
|
36
|
+
fetchAllPages = false,
|
|
37
|
+
queryOptions,
|
|
38
|
+
}: FetchPortfoliosProps<TData>) {
|
|
74
39
|
const { api } = useAxios();
|
|
75
40
|
|
|
76
|
-
const queryKey = buildQueryKey(["portfolios"], filters
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
})
|
|
41
|
+
const queryKey = buildQueryKey(["portfolios"], filters, {
|
|
42
|
+
order,
|
|
43
|
+
projection,
|
|
44
|
+
pageSize,
|
|
45
|
+
fetchAllPages,
|
|
46
|
+
});
|
|
82
47
|
|
|
83
|
-
const query =
|
|
48
|
+
const query = useEntityInfiniteQuery<PortfolioListResponse, "portfolios", TData>({
|
|
84
49
|
queryKey,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
select: (data) => data.pages.flatMap((p) => p.portfolios),
|
|
101
|
-
|
|
102
|
-
...mergedQueryOptions,
|
|
50
|
+
itemsKey: "portfolios",
|
|
51
|
+
fetchPage: (pageToken, signal) =>
|
|
52
|
+
listPortfolios(
|
|
53
|
+
api,
|
|
54
|
+
buildQueryObject({ filters, order, projection, pageSize, pageToken }),
|
|
55
|
+
signal,
|
|
56
|
+
),
|
|
57
|
+
select,
|
|
58
|
+
fetchAllPages,
|
|
59
|
+
configError: hasWorkspaceFilter(filters)
|
|
60
|
+
? undefined
|
|
61
|
+
: missingWorkspaceError("useFetchPortfolios"),
|
|
62
|
+
queryOptions,
|
|
103
63
|
});
|
|
104
64
|
|
|
105
|
-
return {
|
|
106
|
-
|
|
107
|
-
queryKey,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
65
|
+
return { query, queryKey };
|
|
66
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
|
|
3
1
|
import { useAxios } from "@/hooks/useAxios";
|
|
4
|
-
import {
|
|
2
|
+
import { useEntityMutation } from "@/hooks/useEntityMutation";
|
|
5
3
|
import type { Portfolio } from "@/types/portfolio";
|
|
6
4
|
import { deletePortfolio, createPortfolio, updatePortfolio } from "@/api/portfolio";
|
|
7
5
|
|
|
@@ -23,9 +21,6 @@ type UsePortfolioMutationsProps = {
|
|
|
23
21
|
queryKey?: unknown[];
|
|
24
22
|
};
|
|
25
23
|
|
|
26
|
-
const getErrorMessage = (err: unknown, fallback: string) =>
|
|
27
|
-
err instanceof Error && err.message ? err.message : fallback;
|
|
28
|
-
|
|
29
24
|
/**
|
|
30
25
|
* usePortfolioMutations
|
|
31
26
|
*
|
|
@@ -60,26 +55,26 @@ const getErrorMessage = (err: unknown, fallback: string) =>
|
|
|
60
55
|
* - mutationFn: `createPortfolio(api, data)`
|
|
61
56
|
* - variables: `{ data: Partial<Portfolio> }`
|
|
62
57
|
* - success message: "Portfolio created successfully."
|
|
63
|
-
* - error message: "
|
|
58
|
+
* - error message: "Unable to create the portfolio. Please try again." (fallback)
|
|
64
59
|
*
|
|
65
60
|
* - `update`:
|
|
66
61
|
* - mutationFn: `updatePortfolio(api, id, data)`
|
|
67
62
|
* - variables: `{ id: string; data: Partial<Portfolio> }`
|
|
68
63
|
* - success message: "Portfolio updated successfully."
|
|
69
|
-
* - error message: "
|
|
64
|
+
* - error message: "Unable to update the portfolio. Please try again." (fallback)
|
|
70
65
|
*
|
|
71
66
|
* - `remove`:
|
|
72
67
|
* - mutationFn: `deletePortfolio(api, id, workspace)`
|
|
73
68
|
* - variables: `{ id: string; workspace: string }`
|
|
74
69
|
* - success message: "Portfolio deleted successfully."
|
|
75
|
-
* - error message: "
|
|
70
|
+
* - error message: "Unable to delete the portfolio. Please try again." (fallback)
|
|
76
71
|
*
|
|
77
72
|
* Return value:
|
|
78
73
|
* @returns {object}
|
|
79
74
|
* Returns an object with the three TanStack Query mutation results:
|
|
80
75
|
* - `create`: UseMutationResult<Portfolio, Error, CreatePortfolioProps, unknown>
|
|
81
76
|
* - `update`: UseMutationResult<Portfolio, Error, UpdatePortfolioProps, unknown>
|
|
82
|
-
* - `remove`: UseMutationResult<
|
|
77
|
+
* - `remove`: UseMutationResult<DeletedEntity, Error, DeletePortfolioProps, unknown>
|
|
83
78
|
*
|
|
84
79
|
* Each mutation includes standard TanStack Query helpers:
|
|
85
80
|
* - `mutate(variables, options?)`
|
|
@@ -92,7 +87,7 @@ const getErrorMessage = (err: unknown, fallback: string) =>
|
|
|
92
87
|
* ```ts
|
|
93
88
|
* const { create, update, remove } = usePortfolioMutations({ queryKey: ["portfolio"] });
|
|
94
89
|
*
|
|
95
|
-
|
|
90
|
+
* // Create (minimal example - other Security fields omitted for brevity)
|
|
96
91
|
* create.mutate({
|
|
97
92
|
* data: {
|
|
98
93
|
* name: "My Portfolio",
|
|
@@ -178,72 +173,27 @@ const getErrorMessage = (err: unknown, fallback: string) =>
|
|
|
178
173
|
|
|
179
174
|
export const usePortfolioMutations = ({ queryKey }: UsePortfolioMutationsProps) => {
|
|
180
175
|
const { api } = useAxios();
|
|
181
|
-
const { showAlert } = useAppAlert();
|
|
182
|
-
const queryClient = useQueryClient();
|
|
183
|
-
|
|
184
|
-
const invalidate = async () => {
|
|
185
|
-
if (!queryKey?.length) return;
|
|
186
|
-
await queryClient.invalidateQueries({ queryKey });
|
|
187
|
-
};
|
|
188
176
|
|
|
189
|
-
const create =
|
|
190
|
-
mutationFn:
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
severity: "success",
|
|
195
|
-
message: "Portfolio created successfully.",
|
|
196
|
-
});
|
|
197
|
-
},
|
|
198
|
-
onError: (err: unknown) => {
|
|
199
|
-
showAlert({
|
|
200
|
-
severity: "error",
|
|
201
|
-
message: getErrorMessage(
|
|
202
|
-
err,
|
|
203
|
-
"We couldn't create the portfolio. Please review your inputs and try again."
|
|
204
|
-
),
|
|
205
|
-
});
|
|
206
|
-
},
|
|
177
|
+
const create = useEntityMutation({
|
|
178
|
+
mutationFn: ({ data }: CreatePortfolioProps) => createPortfolio(api, data),
|
|
179
|
+
queryKey,
|
|
180
|
+
successMessage: "Portfolio created successfully.",
|
|
181
|
+
errorMessage: "Unable to create the portfolio. Please try again.",
|
|
207
182
|
});
|
|
208
183
|
|
|
209
|
-
const update =
|
|
210
|
-
mutationFn:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
severity: "success",
|
|
215
|
-
message: "Portfolio updated successfully.",
|
|
216
|
-
});
|
|
217
|
-
},
|
|
218
|
-
onError: (err: unknown) => {
|
|
219
|
-
showAlert({
|
|
220
|
-
severity: "error",
|
|
221
|
-
message: getErrorMessage(
|
|
222
|
-
err,
|
|
223
|
-
"We couldn't update the portfolio. Please try again."
|
|
224
|
-
),
|
|
225
|
-
});
|
|
226
|
-
},
|
|
184
|
+
const update = useEntityMutation({
|
|
185
|
+
mutationFn: ({ id, data }: UpdatePortfolioProps) => updatePortfolio(api, id, data),
|
|
186
|
+
queryKey,
|
|
187
|
+
successMessage: "Portfolio updated successfully.",
|
|
188
|
+
errorMessage: "Unable to update the portfolio. Please try again.",
|
|
227
189
|
});
|
|
228
190
|
|
|
229
|
-
const remove =
|
|
230
|
-
mutationFn:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
message: "Portfolio deleted successfully.",
|
|
236
|
-
});
|
|
237
|
-
},
|
|
238
|
-
onError: (err: unknown) => {
|
|
239
|
-
showAlert({
|
|
240
|
-
severity: "error",
|
|
241
|
-
message: getErrorMessage(
|
|
242
|
-
err,
|
|
243
|
-
"We couldn't delete the portfolio. Please try again."
|
|
244
|
-
),
|
|
245
|
-
});
|
|
246
|
-
},
|
|
191
|
+
const remove = useEntityMutation({
|
|
192
|
+
mutationFn: ({ id, workspace }: DeletePortfolioProps) =>
|
|
193
|
+
deletePortfolio(api, id, workspace),
|
|
194
|
+
queryKey,
|
|
195
|
+
successMessage: "Portfolio deleted successfully.",
|
|
196
|
+
errorMessage: "Unable to delete the portfolio. Please try again.",
|
|
247
197
|
});
|
|
248
198
|
|
|
249
199
|
return { create, update, remove };
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
|
|
3
|
-
import { useQuery } from "@tanstack/react-query";
|
|
4
|
-
|
|
5
1
|
import { useAxios } from "@/hooks/useAxios";
|
|
6
|
-
import {
|
|
7
|
-
import type { Profile } from "@/types/profile";
|
|
2
|
+
import { useEntityQuery } from "@/hooks/useEntityQuery";
|
|
8
3
|
import { getProfile } from "@/api/profile";
|
|
9
|
-
import type {
|
|
4
|
+
import type { Profile } from "@/types/profile";
|
|
5
|
+
import type { FetchEntityProps, EntityQueryOptions } from "@/types/entityQuery";
|
|
10
6
|
|
|
11
|
-
export type FetchProfileProps<TData = Profile, TSelected = TData> =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* where `/api/profile` has no session to resolve.
|
|
16
|
-
*/
|
|
7
|
+
export type FetchProfileProps<TData = Profile, TSelected = TData> = FetchEntityProps<
|
|
8
|
+
TData,
|
|
9
|
+
TSelected
|
|
10
|
+
> & {
|
|
17
11
|
fallback?: Profile;
|
|
18
12
|
};
|
|
19
13
|
|
|
20
14
|
// The logged user's profile does not change during a session, so it is fetched once and kept —
|
|
21
15
|
// unlike the entity hooks (staleTime/gcTime 0, refetch on every mount), which read data the
|
|
22
16
|
// platform keeps changing.
|
|
23
|
-
const
|
|
17
|
+
const profileQueryOptions: EntityQueryOptions<Profile> = {
|
|
24
18
|
staleTime: Infinity,
|
|
25
19
|
refetchOnMount: false,
|
|
26
20
|
refetchOnWindowFocus: false,
|
|
@@ -29,65 +23,30 @@ const defaultQueryOptions: EntityQueryOptions<Profile> = {
|
|
|
29
23
|
/**
|
|
30
24
|
* useFetchProfile
|
|
31
25
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* It also:
|
|
36
|
-
* - builds a stable React Query `queryKey`, shared by every consumer, so the profile is fetched
|
|
37
|
-
* once per session and read from cache afterwards
|
|
38
|
-
* - triggers an error alert via `useAppAlert` whenever `query.error` is present
|
|
39
|
-
*
|
|
40
|
-
* Parameters (FetchProfileProps):
|
|
41
|
-
* @param queryOptions
|
|
42
|
-
* TanStack Query options passed through to `useQuery` (e.g., enabled, staleTime, gcTime, etc.).
|
|
43
|
-
* Defaults keep the profile cached for the whole session.
|
|
44
|
-
* @param fallback
|
|
45
|
-
* Served instead of calling the API. `/api/profile` only resolves in production, so an app
|
|
46
|
-
* running the dev server passes `DEV_PROFILE` here:
|
|
47
|
-
* `useFetchProfile({ fallback: import.meta.env.DEV ? DEV_PROFILE : undefined })`.
|
|
48
|
-
* The SDK cannot make that choice itself — see `getProfile`.
|
|
26
|
+
* Fetches the logged user's profile, once per session; `data` is the profile, or whatever
|
|
27
|
+
* `select` makes of it. `fallback` is what `getProfile` returns when the platform has none to
|
|
28
|
+
* give — see `getProfile` for why it is a parameter. A failure is shown as an error alert.
|
|
49
29
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* - `queryKey`: the cache key used by React Query
|
|
54
|
-
*
|
|
55
|
-
* Example:
|
|
56
|
-
* ```ts
|
|
57
|
-
* const { data, isPending } = useFetchProfile();
|
|
58
|
-
* // data -> Profile
|
|
59
|
-
* ```
|
|
30
|
+
* @param {FetchProfileProps} [props] - `fallback`, `select` and TanStack `queryOptions`, merged
|
|
31
|
+
* over the fetched-once defaults.
|
|
32
|
+
* @returns {object} The `useQuery` result, plus `queryKey`.
|
|
60
33
|
*/
|
|
61
|
-
export const useFetchProfile = ({
|
|
62
|
-
queryOptions = defaultQueryOptions,
|
|
34
|
+
export const useFetchProfile = <TSelected = Profile>({
|
|
63
35
|
fallback,
|
|
64
|
-
|
|
65
|
-
|
|
36
|
+
select,
|
|
37
|
+
queryOptions,
|
|
38
|
+
}: FetchProfileProps<Profile, TSelected> = {}) => {
|
|
66
39
|
const { api } = useAxios();
|
|
67
|
-
const { showAlert } = useAppAlert();
|
|
68
40
|
|
|
69
41
|
const queryKey = ["profile"];
|
|
70
42
|
|
|
71
|
-
const query =
|
|
43
|
+
const query = useEntityQuery<Profile, TSelected>({
|
|
72
44
|
queryKey,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
...queryOptions ?? {}
|
|
45
|
+
fetchEntity: (signal) => getProfile(api, fallback, signal),
|
|
46
|
+
select,
|
|
47
|
+
defaultQueryOptions: profileQueryOptions as EntityQueryOptions<Profile, TSelected>,
|
|
48
|
+
queryOptions,
|
|
78
49
|
});
|
|
79
50
|
|
|
80
|
-
|
|
81
|
-
if (!query.error) return;
|
|
82
|
-
|
|
83
|
-
showAlert({
|
|
84
|
-
severity: "error",
|
|
85
|
-
message: query.error.message,
|
|
86
|
-
});
|
|
87
|
-
}, [query.error, showAlert]);
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
...query,
|
|
91
|
-
queryKey,
|
|
92
|
-
};
|
|
51
|
+
return { ...query, queryKey };
|
|
93
52
|
};
|
package/src/hooks/useAxios.ts
CHANGED
|
@@ -43,7 +43,6 @@ import { useAppConfig } from "@/contexts/appConfigContext/useAppConfig";
|
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
45
|
export const useAxios = (url: string | null = null) => {
|
|
46
|
-
|
|
47
46
|
const reqInterceptorId = useRef<number | null>(null);
|
|
48
47
|
const { appId } = useAppConfig();
|
|
49
48
|
|
|
@@ -68,11 +67,12 @@ export const useAxios = (url: string | null = null) => {
|
|
|
68
67
|
const queryObj = typeof rawQuery === "string" ? JSON.parse(rawQuery) : null;
|
|
69
68
|
|
|
70
69
|
const workspaceFilter = queryObj?.filters?.find(
|
|
71
|
-
(filter: FilterExpression) => filter?.[0] === "workspace"
|
|
70
|
+
(filter: FilterExpression) => filter?.[0] === "workspace",
|
|
72
71
|
);
|
|
73
72
|
|
|
74
|
-
const workspace =
|
|
75
|
-
|
|
73
|
+
const workspace = Array.isArray(workspaceFilter)
|
|
74
|
+
? workspaceFilter[workspaceFilter.length - 1]
|
|
75
|
+
: null;
|
|
76
76
|
|
|
77
77
|
if (workspace) {
|
|
78
78
|
config.params = { ...params, workspace };
|
|
@@ -83,7 +83,7 @@ export const useAxios = (url: string | null = null) => {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return config;
|
|
86
|
-
}
|
|
86
|
+
},
|
|
87
87
|
);
|
|
88
88
|
|
|
89
89
|
return () => {
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useInfiniteQuery, type QueryKey } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
PagedResponse,
|
|
6
|
+
EntityInfiniteQueryOptions,
|
|
7
|
+
ListCache,
|
|
8
|
+
PageToken,
|
|
9
|
+
} from "@/types/entityQuery";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ceiling on `fetchAllPages`. Reaching it fails the read instead of returning what was read so
|
|
13
|
+
* far: a cursor that never ends is a bug, and a consolidated view shown from a partial read is
|
|
14
|
+
* a wrong answer that looks right. A set legitimately this long wants a larger `pageSize`.
|
|
15
|
+
*/
|
|
16
|
+
export const FETCH_ALL_PAGES_LIMIT = 100;
|
|
17
|
+
|
|
18
|
+
/** The element type of a page's item array. */
|
|
19
|
+
export type ItemOf<TPage, K extends keyof TPage> = TPage[K] extends (infer TItem)[] ? TItem : never;
|
|
20
|
+
|
|
21
|
+
export type EntityInfiniteQueryProps<TPage extends PagedResponse, K extends keyof TPage, TData> = {
|
|
22
|
+
/**
|
|
23
|
+
* Must describe everything that changes the response, `fetchAllPages` included, or two reads
|
|
24
|
+
* share one cache entry. Build it with `buildQueryKey(keys, filters, { order, projection,
|
|
25
|
+
* pageSize, fetchAllPages })`, and return it from your hook so callers can write to the cache.
|
|
26
|
+
*/
|
|
27
|
+
queryKey: QueryKey;
|
|
28
|
+
/** Where a page keeps its items (`"datastores"`, `"files"`, …). */
|
|
29
|
+
itemsKey: K;
|
|
30
|
+
/**
|
|
31
|
+
* Requests one page; `undefined` asks for the first. `signal` aborts when no screen wants the
|
|
32
|
+
* read any more — pass it to the request (`api.get(url, { signal })`) to cancel it in flight.
|
|
33
|
+
*/
|
|
34
|
+
fetchPage: (pageToken: string | undefined, signal?: AbortSignal) => Promise<TPage>;
|
|
35
|
+
select?: (items: ItemOf<TPage, K>[]) => TData;
|
|
36
|
+
fetchAllPages?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Your hook's own precondition for something legitimately not there yet (a selection the
|
|
39
|
+
* user has not made), ANDed with the caller's `queryOptions.enabled`. Unmet, the query stays
|
|
40
|
+
* idle. For something that should always be there, use `configError`: idle hides it.
|
|
41
|
+
*/
|
|
42
|
+
enabled?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Why the request cannot be right, when it cannot — `missingWorkspaceError(hookName)` in the
|
|
45
|
+
* SDK's hooks. Set, the query fails at once with it as the error, without a request or a
|
|
46
|
+
* retry, and logs it with `console.error` once per message, in every environment: a
|
|
47
|
+
* misconfigured app shows up in the browser console and in test output, not as an empty
|
|
48
|
+
* screen.
|
|
49
|
+
* It is reported even while `enabled` is unmet, so an empty id cannot hide a misconfigured
|
|
50
|
+
* workspace; only the caller's `queryOptions.enabled: false` holds it back.
|
|
51
|
+
*/
|
|
52
|
+
configError?: string;
|
|
53
|
+
queryOptions?: EntityInfiniteQueryOptions<TPage, TData>;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** The `configError` messages already logged, so a render loop does not flood the console. */
|
|
57
|
+
const loggedConfigErrors = new Set<string>();
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fails a query with its `configError`, logging it the first time. Shared by the SDK's query
|
|
61
|
+
* hooks.
|
|
62
|
+
*/
|
|
63
|
+
export const failWithConfigError = (configError: string): never => {
|
|
64
|
+
if (!loggedConfigErrors.has(configError)) {
|
|
65
|
+
loggedConfigErrors.add(configError);
|
|
66
|
+
console.error(configError);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw new Error(configError);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const defaultQueryOptions = {
|
|
73
|
+
refetchOnMount: "always",
|
|
74
|
+
staleTime: 0,
|
|
75
|
+
gcTime: 0,
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Reads every page into one page, so the cache holds a single entry for the whole set and a
|
|
80
|
+
* refetch rereads all of it.
|
|
81
|
+
*
|
|
82
|
+
* Stops as soon as `signal` aborts. TanStack aborts it when the last screen reading the query
|
|
83
|
+
* unmounts — only because the query function takes it — and without this check the loop would
|
|
84
|
+
* go on requesting every remaining page for nobody.
|
|
85
|
+
*/
|
|
86
|
+
const fetchEveryPage = async <TPage extends PagedResponse, K extends keyof TPage>(
|
|
87
|
+
fetchPage: (pageToken: string | undefined, signal?: AbortSignal) => Promise<TPage>,
|
|
88
|
+
itemsKey: K,
|
|
89
|
+
signal: AbortSignal,
|
|
90
|
+
): Promise<TPage> => {
|
|
91
|
+
let page = await fetchPage(undefined, signal);
|
|
92
|
+
const items = [...(page[itemsKey] as unknown[])];
|
|
93
|
+
|
|
94
|
+
for (let count = 1; page.next_page_token; count++) {
|
|
95
|
+
signal.throwIfAborted();
|
|
96
|
+
|
|
97
|
+
if (count >= FETCH_ALL_PAGES_LIMIT) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`fetchAllPages stopped after ${FETCH_ALL_PAGES_LIMIT} pages without reaching the end. ` +
|
|
100
|
+
"Raise pageSize, or page on demand instead.",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
page = await fetchPage(page.next_page_token, signal);
|
|
105
|
+
items.push(...(page[itemsKey] as unknown[]));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { ...page, [itemsKey]: items, next_page_token: null };
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* useEntityInfiniteQuery
|
|
113
|
+
*
|
|
114
|
+
* The list hook every SDK list hook is built on, and the one to build on for an endpoint the
|
|
115
|
+
* SDK does not cover. A hook says how to request a page and where its items are; this merges
|
|
116
|
+
* the pages, applies the caller's `select`, and owns the paging modes (`fetchAllPages`, and
|
|
117
|
+
* `fetchNextPage` for `handleRowsScrollEnd`). It replaced seven copies of the same
|
|
118
|
+
* `useInfiniteQuery` call, which is how one `select` defect had reached all seven — an app
|
|
119
|
+
* copying a list hook instead of composing this would copy the next one too.
|
|
120
|
+
*
|
|
121
|
+
* `select` is composed with the merging after the caller's options are spread, so nothing in
|
|
122
|
+
* `queryOptions` can replace it. The composed function is memoised on the caller's `select`:
|
|
123
|
+
* TanStack skips a select whose data and reference are both unchanged.
|
|
124
|
+
*
|
|
125
|
+
* @returns {UseInfiniteQueryResult} The `useInfiniteQuery` result; `data` is the merged items,
|
|
126
|
+
* or what `select` makes of them.
|
|
127
|
+
*
|
|
128
|
+
* Example:
|
|
129
|
+
* ```ts
|
|
130
|
+
* export const useFetchReports = <TData = Report[]>({ workspace, select, fetchAllPages = false }: Props<TData>) => {
|
|
131
|
+
* const { api } = useAxios();
|
|
132
|
+
* const filters = [{ field: "workspace", value: workspace }];
|
|
133
|
+
* const queryKey = buildQueryKey(["reports"], filters, { fetchAllPages });
|
|
134
|
+
*
|
|
135
|
+
* const query = useEntityInfiniteQuery<ReportListResponse, "reports", TData>({
|
|
136
|
+
* queryKey,
|
|
137
|
+
* itemsKey: "reports",
|
|
138
|
+
* fetchPage: (pageToken) => listReports(api, workspace, pageToken),
|
|
139
|
+
* select,
|
|
140
|
+
* fetchAllPages,
|
|
141
|
+
* configError: hasWorkspaceFilter(filters) ? undefined : missingWorkspaceError("useFetchReports"),
|
|
142
|
+
* });
|
|
143
|
+
*
|
|
144
|
+
* return { query, queryKey };
|
|
145
|
+
* };
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function useEntityInfiniteQuery<
|
|
149
|
+
TPage extends PagedResponse,
|
|
150
|
+
K extends keyof TPage,
|
|
151
|
+
TData = ItemOf<TPage, K>[],
|
|
152
|
+
>({
|
|
153
|
+
queryKey,
|
|
154
|
+
itemsKey,
|
|
155
|
+
fetchPage,
|
|
156
|
+
select,
|
|
157
|
+
fetchAllPages = false,
|
|
158
|
+
enabled = true,
|
|
159
|
+
configError,
|
|
160
|
+
queryOptions,
|
|
161
|
+
}: EntityInfiniteQueryProps<TPage, K, TData>) {
|
|
162
|
+
const selectMerged = useCallback(
|
|
163
|
+
(data: ListCache<TPage>): TData => {
|
|
164
|
+
const items = data.pages.flatMap((page) => page[itemsKey] as ItemOf<TPage, K>[]);
|
|
165
|
+
return select ? select(items) : (items as unknown as TData);
|
|
166
|
+
},
|
|
167
|
+
[itemsKey, select],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return useInfiniteQuery<TPage, Error, TData, QueryKey, PageToken>({
|
|
171
|
+
...defaultQueryOptions,
|
|
172
|
+
...queryOptions,
|
|
173
|
+
|
|
174
|
+
queryKey,
|
|
175
|
+
initialPageParam: null,
|
|
176
|
+
getNextPageParam: (lastPage) => lastPage.next_page_token ?? undefined,
|
|
177
|
+
queryFn: async ({ pageParam, signal }) => {
|
|
178
|
+
if (configError) return failWithConfigError(configError);
|
|
179
|
+
|
|
180
|
+
return fetchAllPages
|
|
181
|
+
? fetchEveryPage(fetchPage, itemsKey, signal)
|
|
182
|
+
: fetchPage(pageParam ?? undefined, signal);
|
|
183
|
+
},
|
|
184
|
+
// A retry would rerun the same check and delay an error that cannot resolve itself.
|
|
185
|
+
...(configError ? { retry: false } : {}),
|
|
186
|
+
|
|
187
|
+
select: selectMerged,
|
|
188
|
+
// A config error runs past the hook's own precondition, so that an empty id cannot hide a
|
|
189
|
+
// misconfigured workspace; the caller's `enabled` still wins. Kept as the caller wrote it,
|
|
190
|
+
// so a function still works.
|
|
191
|
+
enabled: configError || enabled ? (queryOptions?.enabled ?? true) : false,
|
|
192
|
+
});
|
|
193
|
+
}
|