@everysk/apps-sdk 0.1.0 → 0.3.0-beta-20261016180126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +395 -8
- package/dist/EveryskApp.d.ts +34 -2
- package/dist/EveryskApp.d.ts.map +1 -1
- package/dist/EveryskApp.js +35 -2
- package/dist/EveryskApp.js.map +1 -1
- package/dist/agGrid/handleRowsScrollEnd.d.ts +53 -0
- package/dist/agGrid/handleRowsScrollEnd.d.ts.map +1 -0
- package/dist/agGrid/handleRowsScrollEnd.js +47 -0
- package/dist/agGrid/handleRowsScrollEnd.js.map +1 -0
- package/dist/agGrid/index.d.ts +2 -0
- package/dist/agGrid/index.d.ts.map +1 -1
- package/dist/agGrid/index.js +2 -1
- package/dist/api/datastore.d.ts +10 -8
- package/dist/api/datastore.d.ts.map +1 -1
- package/dist/api/datastore.js +24 -55
- package/dist/api/datastore.js.map +1 -1
- package/dist/api/entityQuery.d.ts +46 -41
- package/dist/api/entityQuery.d.ts.map +1 -1
- package/dist/api/entityQuery.js +55 -14
- package/dist/api/entityQuery.js.map +1 -1
- package/dist/api/file.d.ts +26 -9
- package/dist/api/file.d.ts.map +1 -1
- package/dist/api/file.js +45 -55
- package/dist/api/file.js.map +1 -1
- package/dist/api/portfolio.d.ts +11 -8
- package/dist/api/portfolio.d.ts.map +1 -1
- package/dist/api/portfolio.js +24 -55
- package/dist/api/portfolio.js.map +1 -1
- package/dist/api/profile.d.ts +3 -2
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +4 -9
- package/dist/api/profile.js.map +1 -1
- package/dist/api/request.d.ts +106 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +132 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/websocketsConfig.d.ts +7 -2
- package/dist/api/websocketsConfig.d.ts.map +1 -1
- package/dist/api/websocketsConfig.js +2 -10
- package/dist/api/websocketsConfig.js.map +1 -1
- package/dist/api/workflow.d.ts +84 -89
- package/dist/api/workflow.d.ts.map +1 -1
- package/dist/api/workflow.js +121 -208
- package/dist/api/workflow.js.map +1 -1
- package/dist/api/workspace.d.ts +18 -8
- package/dist/api/workspace.d.ts.map +1 -1
- package/dist/api/workspace.js +21 -26
- package/dist/api/workspace.js.map +1 -1
- package/dist/components/ui/Footer/index.d.ts.map +1 -1
- package/dist/components/ui/Footer/index.js.map +1 -1
- package/dist/components/ui/GlobalLoading/index.d.ts.map +1 -1
- package/dist/components/ui/GlobalLoading/index.js.map +1 -1
- package/dist/components/ui/PageContainer/index.d.ts +1 -1
- package/dist/components/ui/PageContainer/index.d.ts.map +1 -1
- package/dist/components/ui/PageContainer/index.js.map +1 -1
- package/dist/components/ui/Toolbar/index.d.ts +40 -3
- package/dist/components/ui/Toolbar/index.d.ts.map +1 -1
- package/dist/components/ui/Toolbar/index.js +42 -15
- package/dist/components/ui/Toolbar/index.js.map +1 -1
- package/dist/contexts/appAlertContext/provider.js.map +1 -1
- package/dist/contexts/appAlertContext/types.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/index.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/index.js.map +1 -1
- package/dist/contexts/appConfigContext/provider.d.ts.map +1 -1
- package/dist/contexts/appConfigContext/provider.js.map +1 -1
- package/dist/contexts/webSocketContext/handler.d.ts +3 -2
- package/dist/contexts/webSocketContext/handler.d.ts.map +1 -1
- package/dist/contexts/webSocketContext/handler.js.map +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.d.ts +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js +1 -1
- package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js.map +1 -1
- package/dist/contexts/webSocketContext/provider.d.ts +6 -3
- package/dist/contexts/webSocketContext/provider.d.ts.map +1 -1
- package/dist/contexts/webSocketContext/provider.js +42 -7
- package/dist/contexts/webSocketContext/provider.js.map +1 -1
- package/dist/contexts/webSocketContext/types.d.ts +7 -5
- package/dist/contexts/webSocketContext/types.d.ts.map +1 -1
- package/dist/file/index.d.ts +2 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/hooks/datastore/useDatastoreMutations.d.ts +4 -4
- package/dist/hooks/datastore/useDatastoreMutations.d.ts.map +1 -1
- package/dist/hooks/datastore/useDatastoreMutations.js +17 -55
- package/dist/hooks/datastore/useDatastoreMutations.js.map +1 -1
- package/dist/hooks/datastore/useFetchDatastore.d.ts +30 -41
- package/dist/hooks/datastore/useFetchDatastore.d.ts.map +1 -1
- package/dist/hooks/datastore/useFetchDatastore.js +25 -59
- package/dist/hooks/datastore/useFetchDatastore.js.map +1 -1
- package/dist/hooks/datastore/useFetchDatastores.d.ts +47 -52
- package/dist/hooks/datastore/useFetchDatastores.d.ts.map +1 -1
- package/dist/hooks/datastore/useFetchDatastores.js +55 -70
- package/dist/hooks/datastore/useFetchDatastores.js.map +1 -1
- package/dist/hooks/file/fileData.d.ts +17 -0
- package/dist/hooks/file/fileData.d.ts.map +1 -0
- package/dist/hooks/file/fileData.js +10 -0
- package/dist/hooks/file/fileData.js.map +1 -0
- package/dist/hooks/file/useFetchFile.d.ts +38 -58
- package/dist/hooks/file/useFetchFile.d.ts.map +1 -1
- package/dist/hooks/file/useFetchFile.js +26 -66
- package/dist/hooks/file/useFetchFile.js.map +1 -1
- package/dist/hooks/file/useFetchFiles.d.ts +18 -52
- package/dist/hooks/file/useFetchFiles.d.ts.map +1 -1
- package/dist/hooks/file/useFetchFiles.js +53 -69
- package/dist/hooks/file/useFetchFiles.js.map +1 -1
- package/dist/hooks/file/useFileMutations.d.ts +9 -8
- package/dist/hooks/file/useFileMutations.d.ts.map +1 -1
- package/dist/hooks/file/useFileMutations.js +23 -60
- package/dist/hooks/file/useFileMutations.js.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolio.d.ts +16 -50
- package/dist/hooks/portfolio/useFetchPortfolio.d.ts.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolio.js +15 -63
- package/dist/hooks/portfolio/useFetchPortfolio.js.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolios.d.ts +13 -52
- package/dist/hooks/portfolio/useFetchPortfolios.d.ts.map +1 -1
- package/dist/hooks/portfolio/useFetchPortfolios.js +29 -71
- package/dist/hooks/portfolio/useFetchPortfolios.js.map +1 -1
- package/dist/hooks/portfolio/usePortfolioMutations.d.ts +8 -8
- package/dist/hooks/portfolio/usePortfolioMutations.d.ts.map +1 -1
- package/dist/hooks/portfolio/usePortfolioMutations.js +20 -58
- package/dist/hooks/portfolio/usePortfolioMutations.js.map +1 -1
- package/dist/hooks/profile/useFetchProfile.d.ts +18 -44
- package/dist/hooks/profile/useFetchProfile.d.ts.map +1 -1
- package/dist/hooks/profile/useFetchProfile.js +16 -48
- package/dist/hooks/profile/useFetchProfile.js.map +1 -1
- package/dist/hooks/useAxios.js.map +1 -1
- package/dist/hooks/useEntityInfiniteQuery.d.ts +88 -0
- package/dist/hooks/useEntityInfiniteQuery.d.ts.map +1 -0
- package/dist/hooks/useEntityInfiniteQuery.js +111 -0
- package/dist/hooks/useEntityInfiniteQuery.js.map +1 -0
- package/dist/hooks/useEntityMutation.d.ts +47 -0
- package/dist/hooks/useEntityMutation.d.ts.map +1 -0
- package/dist/hooks/useEntityMutation.js +58 -0
- package/dist/hooks/useEntityMutation.js.map +1 -0
- package/dist/hooks/useEntityQuery.d.ts +68 -0
- package/dist/hooks/useEntityQuery.d.ts.map +1 -0
- package/dist/hooks/useEntityQuery.js +75 -0
- package/dist/hooks/useEntityQuery.js.map +1 -0
- package/dist/hooks/workflow/useFetchWorkerExecution.d.ts +17 -34
- package/dist/hooks/workflow/useFetchWorkerExecution.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecution.js +16 -46
- package/dist/hooks/workflow/useFetchWorkerExecution.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts +179 -41
- package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkerExecutions.js +29 -62
- package/dist/hooks/workflow/useFetchWorkerExecutions.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflow.d.ts +16 -35
- package/dist/hooks/workflow/useFetchWorkflow.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflow.js +15 -48
- package/dist/hooks/workflow/useFetchWorkflow.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts +17 -34
- package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecution.js +16 -46
- package/dist/hooks/workflow/useFetchWorkflowExecution.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts +22 -36
- package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflowExecutions.js +43 -56
- package/dist/hooks/workflow/useFetchWorkflowExecutions.js.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflows.d.ts +20 -37
- package/dist/hooks/workflow/useFetchWorkflows.d.ts.map +1 -1
- package/dist/hooks/workflow/useFetchWorkflows.js +32 -47
- package/dist/hooks/workflow/useFetchWorkflows.js.map +1 -1
- package/dist/hooks/workflow/useRunWorkflow.d.ts +21 -16
- package/dist/hooks/workflow/useRunWorkflow.d.ts.map +1 -1
- package/dist/hooks/workflow/useRunWorkflow.js +66 -29
- package/dist/hooks/workflow/useRunWorkflow.js.map +1 -1
- package/dist/hooks/workflow/useTriggerWorkflow.d.ts +20 -0
- package/dist/hooks/workflow/useTriggerWorkflow.d.ts.map +1 -0
- package/dist/hooks/workflow/useTriggerWorkflow.js +32 -0
- package/dist/hooks/workflow/useTriggerWorkflow.js.map +1 -0
- package/dist/hooks/workspace/useFetchWorkspace.d.ts +19 -34
- package/dist/hooks/workspace/useFetchWorkspace.d.ts.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspace.js +16 -46
- package/dist/hooks/workspace/useFetchWorkspace.js.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspaces.d.ts +17 -37
- package/dist/hooks/workspace/useFetchWorkspaces.d.ts.map +1 -1
- package/dist/hooks/workspace/useFetchWorkspaces.js +25 -47
- package/dist/hooks/workspace/useFetchWorkspaces.js.map +1 -1
- package/dist/index.d.ts +13 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -11
- package/dist/lib/abort.d.ts +58 -0
- package/dist/lib/abort.d.ts.map +1 -0
- package/dist/lib/abort.js +112 -0
- package/dist/lib/abort.js.map +1 -0
- package/dist/lib/datastoreTable.d.ts +59 -54
- package/dist/lib/datastoreTable.d.ts.map +1 -1
- package/dist/lib/datastoreTable.js +58 -62
- package/dist/lib/datastoreTable.js.map +1 -1
- package/dist/lib/file.d.ts +34 -0
- package/dist/lib/file.d.ts.map +1 -0
- package/dist/lib/file.js +63 -0
- package/dist/lib/file.js.map +1 -0
- package/dist/lib/queryClient.d.ts.map +1 -1
- package/dist/lib/queryClient.js.map +1 -1
- package/dist/lib/workflowRun.d.ts +91 -0
- package/dist/lib/workflowRun.d.ts.map +1 -0
- package/dist/lib/workflowRun.js +224 -0
- package/dist/lib/workflowRun.js.map +1 -0
- package/dist/socket/index.d.ts +1 -3
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +3 -5
- package/dist/test/mocks/index.d.ts +1 -1
- package/dist/test/mocks/index.d.ts.map +1 -1
- package/dist/test/renderWithProviders.d.ts +2 -2
- package/dist/test/renderWithProviders.d.ts.map +1 -1
- package/dist/test/renderWithProviders.js.map +1 -1
- package/dist/test/setup.js.map +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/overrides/index.d.ts +4 -2
- package/dist/theme/overrides/index.d.ts.map +1 -1
- package/dist/theme/overrides/index.js +5 -3
- package/dist/theme/overrides/index.js.map +1 -1
- package/dist/theme/overrides/muiButton.d.ts +2 -2
- package/dist/theme/overrides/muiButton.js.map +1 -1
- package/dist/theme/overrides/muiCssBaseline.d.ts.map +1 -1
- package/dist/theme/overrides/muiCssBaseline.js.map +1 -1
- package/dist/theme/overrides/muiDatePicker.js.map +1 -1
- package/dist/theme/overrides/muiFormControl.js.map +1 -1
- package/dist/theme/overrides/muiIconButton.d.ts +2 -2
- package/dist/theme/overrides/muiIconButton.js.map +1 -1
- package/dist/theme/overrides/muiSelect.d.ts.map +1 -1
- package/dist/theme/overrides/muiSelect.js.map +1 -1
- package/dist/theme/overrides/muiSvgIcon.d.ts.map +1 -1
- package/dist/theme/overrides/muiSvgIcon.js.map +1 -1
- package/dist/theme/overrides/muiTextField.js.map +1 -1
- package/dist/theme/overrides/muiToggleButton.d.ts +2 -2
- package/dist/theme/overrides/muiToggleButton.js.map +1 -1
- package/dist/theme/overrides/muiToggleButtonGroup.d.ts +2 -2
- package/dist/theme/overrides/muiToggleButtonGroup.js.map +1 -1
- package/dist/theme/themes/DefaultDark.js +2 -2
- package/dist/theme/themes/DefaultDark.js.map +1 -1
- package/dist/theme/themes/DefaultLight.js +2 -2
- package/dist/theme/themes/DefaultLight.js.map +1 -1
- package/dist/theme/themes/EveryskDark.js +2 -2
- package/dist/theme/themes/EveryskDark.js.map +1 -1
- package/dist/theme/themes/EveryskLight.js +2 -2
- package/dist/theme/themes/EveryskLight.js.map +1 -1
- package/dist/theme/themes/MidnightEmber.js +2 -2
- package/dist/theme/themes/MidnightEmber.js.map +1 -1
- package/dist/types/anyRecord.d.ts.map +1 -1
- package/dist/types/datastore.d.ts +35 -5
- package/dist/types/datastore.d.ts.map +1 -1
- package/dist/types/datastoreDataFormat.d.ts +13 -0
- package/dist/types/datastoreDataFormat.d.ts.map +1 -0
- package/dist/types/entityQuery.d.ts +86 -16
- package/dist/types/entityQuery.d.ts.map +1 -1
- package/dist/types/file.d.ts +7 -3
- package/dist/types/file.d.ts.map +1 -1
- package/dist/types/portfolio.d.ts +1 -3
- package/dist/types/portfolio.d.ts.map +1 -1
- package/dist/types/profile.d.ts +0 -10
- package/dist/types/profile.d.ts.map +1 -1
- package/dist/types/workflow.d.ts +35 -6
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workspace.d.ts +1 -2
- package/dist/types/workspace.d.ts.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/EveryskApp.tsx +53 -2
- package/src/agGrid/handleRowsScrollEnd.ts +71 -0
- package/src/agGrid/index.ts +5 -1
- package/src/api/datastore.ts +79 -107
- package/src/api/entityQuery.ts +86 -17
- package/src/api/file.ts +110 -103
- package/src/api/portfolio.ts +82 -125
- package/src/api/profile.ts +25 -18
- package/src/api/request.ts +168 -0
- package/src/api/websocketsConfig.ts +11 -19
- package/src/api/workflow.ts +232 -334
- package/src/api/workspace.ts +43 -43
- package/src/components/ui/Footer/index.tsx +8 -7
- package/src/components/ui/GlobalLoading/index.tsx +13 -3
- package/src/components/ui/PageContainer/index.tsx +9 -2
- package/src/components/ui/Toolbar/index.tsx +105 -30
- package/src/contexts/appAlertContext/provider.tsx +1 -1
- package/src/contexts/appAlertContext/types.ts +3 -3
- package/src/contexts/appConfigContext/index.tsx +1 -1
- package/src/contexts/appConfigContext/provider.tsx +1 -5
- package/src/contexts/webSocketContext/handler.ts +8 -2
- package/src/contexts/webSocketContext/hooks/useWebSocket/index.ts +1 -1
- package/src/contexts/webSocketContext/provider.tsx +64 -14
- package/src/contexts/webSocketContext/types.ts +7 -6
- package/src/file/index.ts +2 -0
- package/src/hooks/datastore/useDatastoreMutations.ts +19 -60
- package/src/hooks/datastore/useFetchDatastore.ts +45 -73
- package/src/hooks/datastore/useFetchDatastores.ts +106 -131
- package/src/hooks/file/fileData.ts +19 -0
- package/src/hooks/file/useFetchFile.ts +41 -76
- package/src/hooks/file/useFetchFiles.ts +92 -87
- package/src/hooks/file/useFileMutations.ts +23 -73
- package/src/hooks/portfolio/useFetchPortfolio.ts +26 -78
- package/src/hooks/portfolio/useFetchPortfolios.ts +50 -93
- package/src/hooks/portfolio/usePortfolioMutations.ts +22 -72
- package/src/hooks/profile/useFetchProfile.ts +24 -65
- package/src/hooks/useAxios.ts +5 -5
- package/src/hooks/useEntityInfiniteQuery.ts +193 -0
- package/src/hooks/useEntityMutation.ts +70 -0
- package/src/hooks/useEntityQuery.ts +117 -0
- package/src/hooks/workflow/useFetchWorkerExecution.ts +27 -56
- package/src/hooks/workflow/useFetchWorkerExecutions.ts +54 -79
- package/src/hooks/workflow/useFetchWorkflow.ts +24 -58
- package/src/hooks/workflow/useFetchWorkflowExecution.ts +27 -57
- package/src/hooks/workflow/useFetchWorkflowExecutions.ts +64 -73
- package/src/hooks/workflow/useFetchWorkflows.ts +48 -64
- package/src/hooks/workflow/useRunWorkflow.ts +82 -36
- package/src/hooks/workflow/useTriggerWorkflow.ts +36 -0
- package/src/hooks/workspace/useFetchWorkspace.ts +25 -58
- package/src/hooks/workspace/useFetchWorkspaces.ts +38 -69
- package/src/index.ts +34 -19
- package/src/lib/abort.ts +131 -0
- package/src/lib/datastoreTable.ts +127 -74
- package/src/lib/file.ts +67 -0
- package/src/lib/queryClient.ts +11 -13
- package/src/lib/workflowRun.ts +329 -0
- package/src/socket/index.ts +1 -3
- package/src/test/mocks/index.ts +1 -5
- package/src/test/renderWithProviders.tsx +8 -3
- package/src/test/setup.ts +16 -16
- package/src/theme/index.ts +1 -1
- package/src/theme/overrides/index.ts +5 -3
- package/src/theme/overrides/muiButton.ts +3 -3
- package/src/theme/overrides/muiCssBaseline.ts +11 -12
- package/src/theme/overrides/muiDatePicker.ts +2 -2
- package/src/theme/overrides/muiFormControl.ts +2 -2
- package/src/theme/overrides/muiIconButton.ts +3 -3
- package/src/theme/overrides/muiSelect.ts +2 -2
- package/src/theme/overrides/muiSvgIcon.ts +2 -2
- package/src/theme/overrides/muiTextField.ts +1 -1
- package/src/theme/overrides/muiToggleButton.ts +4 -4
- package/src/theme/overrides/muiToggleButtonGroup.ts +4 -4
- package/src/theme/themes/DefaultDark.ts +2 -2
- package/src/theme/themes/DefaultLight.ts +2 -2
- package/src/theme/themes/EveryskDark.ts +2 -2
- package/src/theme/themes/EveryskLight.ts +2 -2
- package/src/theme/themes/MidnightEmber.ts +15 -15
- package/src/types/anyRecord.ts +2 -2
- package/src/types/datastore.ts +56 -22
- package/src/types/datastoreDataFormat.ts +12 -0
- package/src/types/entityQuery.ts +122 -38
- package/src/types/file.ts +8 -6
- package/src/types/portfolio.ts +70 -74
- package/src/types/profile.ts +0 -11
- package/src/types/workflow.ts +38 -9
- package/src/types/workspace.ts +2 -4
- package/src/ui/index.ts +1 -1
- package/src/workflow/index.ts +5 -0
|
@@ -1,86 +1,55 @@
|
|
|
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 { listWorkspaces } from "@/api/workspace";
|
|
4
|
+
import { buildQueryKey } from "@/api/entityQuery";
|
|
6
5
|
import type { Workspace, WorkspaceListResponse } from "@/types/workspace";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const defaultQueryOptions: InfiniteOptions<Workspace[]> = {
|
|
22
|
-
refetchOnMount: "always",
|
|
23
|
-
staleTime: 0,
|
|
24
|
-
gcTime: 0,
|
|
6
|
+
import type { FetchEntitiesProps, ListCache } from "@/types/entityQuery";
|
|
7
|
+
|
|
8
|
+
/** The query cache of `useFetchWorkspaces`, for typing `setQueryData`. */
|
|
9
|
+
export type WorkspacesCache = ListCache<WorkspaceListResponse>;
|
|
10
|
+
|
|
11
|
+
export type FetchWorkspacesProps<TData = Workspace[]> = FetchEntitiesProps<
|
|
12
|
+
Workspace,
|
|
13
|
+
TData,
|
|
14
|
+
WorkspaceListResponse
|
|
15
|
+
> & {
|
|
16
|
+
/** A name prefix. */
|
|
17
|
+
search?: string;
|
|
25
18
|
};
|
|
26
19
|
|
|
27
20
|
/**
|
|
28
21
|
* useFetchWorkspaces
|
|
29
22
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* Important notes:
|
|
37
|
-
* - `query.data` returns a flat `Workspace[]` (all pages merged).
|
|
38
|
-
* - `workspace` is required by some API configurations to avoid being blocked.
|
|
23
|
+
* Lists workspaces with cursor pagination; `query.data` is every loaded page merged, or
|
|
24
|
+
* whatever `select` makes of it. `select` and `fetchAllPages` behave as in
|
|
25
|
+
* `useFetchDatastores`. This endpoint lists the account's workspaces: it takes a name `search`,
|
|
26
|
+
* and no workspace — the docs exempt it, and the endpoint ignores one, which this hook used to
|
|
27
|
+
* send.
|
|
39
28
|
*
|
|
40
|
-
* @param props -
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* - `queryOptions`: TanStack Query options passed through to `useInfiniteQuery`.
|
|
44
|
-
*
|
|
45
|
-
* Returns:
|
|
46
|
-
* @returns {object}
|
|
47
|
-
* - `query`: the full `useInfiniteQuery` result (data, isLoading, hasNextPage, fetchNextPage, etc.)
|
|
48
|
-
* - `queryKey`: the cache key used by React Query
|
|
49
|
-
*
|
|
50
|
-
* Example:
|
|
51
|
-
* ```ts
|
|
52
|
-
* const { query } = useFetchWorkspaces({ workspace: "main", pageSize: 20 });
|
|
53
|
-
*
|
|
54
|
-
* // Flat list of all fetched workspaces
|
|
55
|
-
* const workspaces = query.data ?? [];
|
|
56
|
-
* ```
|
|
29
|
+
* @param {FetchWorkspacesProps} props - Search, page size, `select`, `fetchAllPages` and
|
|
30
|
+
* TanStack `queryOptions`.
|
|
31
|
+
* @returns {object} `query` (the `useInfiniteQuery` result) and `queryKey`.
|
|
57
32
|
*/
|
|
58
|
-
export function useFetchWorkspaces
|
|
33
|
+
export function useFetchWorkspaces<TData = Workspace[]>({
|
|
34
|
+
search,
|
|
35
|
+
pageSize = 10,
|
|
36
|
+
select,
|
|
37
|
+
fetchAllPages = false,
|
|
38
|
+
queryOptions,
|
|
39
|
+
}: FetchWorkspacesProps<TData>) {
|
|
59
40
|
const { api } = useAxios();
|
|
60
41
|
|
|
61
|
-
const queryKey
|
|
62
|
-
|
|
63
|
-
const mergedQueryOptions = useMemo<InfiniteOptions<Workspace[]>>(() => ({
|
|
64
|
-
...defaultQueryOptions,
|
|
65
|
-
...(queryOptions ?? {}),
|
|
66
|
-
}), [queryOptions]);
|
|
42
|
+
const queryKey = buildQueryKey(["workspaces", search ?? null], [], { pageSize, fetchAllPages });
|
|
67
43
|
|
|
68
|
-
const query =
|
|
44
|
+
const query = useEntityInfiniteQuery<WorkspaceListResponse, "workspaces", TData>({
|
|
69
45
|
queryKey,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
select: (data) => data.pages.flatMap((p) => p.workspaces),
|
|
78
|
-
|
|
79
|
-
...mergedQueryOptions,
|
|
46
|
+
itemsKey: "workspaces",
|
|
47
|
+
fetchPage: (pageToken, signal) =>
|
|
48
|
+
listWorkspaces(api, { search, pageSize, pageToken: pageToken ?? undefined }, signal),
|
|
49
|
+
select,
|
|
50
|
+
fetchAllPages,
|
|
51
|
+
queryOptions,
|
|
80
52
|
});
|
|
81
53
|
|
|
82
|
-
return {
|
|
83
|
-
query,
|
|
84
|
-
queryKey,
|
|
85
|
-
};
|
|
54
|
+
return { query, queryKey };
|
|
86
55
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,21 +10,19 @@
|
|
|
10
10
|
// before it can tree-shake it, so re-exporting the AG Grid layer from here would fail to build
|
|
11
11
|
// in an app that never installed ag-grid — even one importing nothing but createQueryClient.
|
|
12
12
|
|
|
13
|
-
export { EveryskApp } from "./EveryskApp";
|
|
14
|
-
export type {
|
|
13
|
+
export { EveryskApp, withProps } from "./EveryskApp";
|
|
14
|
+
export type {
|
|
15
|
+
ConfiguredProvider,
|
|
16
|
+
EveryskAppProps,
|
|
17
|
+
ProviderComponent,
|
|
18
|
+
ProviderEntry,
|
|
19
|
+
} from "./EveryskApp";
|
|
15
20
|
|
|
16
|
-
// Contexts
|
|
17
|
-
|
|
18
|
-
export { AppConfigProvider } from "./contexts/appConfigContext/provider";
|
|
21
|
+
// Contexts. `EveryskApp` mounts both providers, so only the hooks and the types are public: a
|
|
22
|
+
// second provider would give part of the tree a context of its own.
|
|
19
23
|
export { useAppConfig } from "./contexts/appConfigContext/useAppConfig";
|
|
20
|
-
export type {
|
|
21
|
-
AppConfigContextType,
|
|
22
|
-
AppConfigProviderProps,
|
|
23
|
-
} from "./contexts/appConfigContext/types";
|
|
24
|
+
export type { AppConfigContextType } from "./contexts/appConfigContext/types";
|
|
24
25
|
|
|
25
|
-
// Contexts — alerts
|
|
26
|
-
export { AppAlertContext } from "./contexts/appAlertContext";
|
|
27
|
-
export { AppAlertProvider } from "./contexts/appAlertContext/provider";
|
|
28
26
|
export { useAppAlert } from "./contexts/appAlertContext/useAppAlert";
|
|
29
27
|
export type {
|
|
30
28
|
AppAlertContextType,
|
|
@@ -34,29 +32,46 @@ export type {
|
|
|
34
32
|
|
|
35
33
|
// Hooks
|
|
36
34
|
export { useAxios } from "./hooks/useAxios";
|
|
35
|
+
// The hooks the entity slices are built on, public for an endpoint the SDK does not cover.
|
|
36
|
+
export { useEntityQuery } from "./hooks/useEntityQuery";
|
|
37
|
+
export type { EntityQueryProps } from "./hooks/useEntityQuery";
|
|
38
|
+
export { useEntityMutation } from "./hooks/useEntityMutation";
|
|
39
|
+
export type { EntityMutationProps } from "./hooks/useEntityMutation";
|
|
40
|
+
export { useEntityInfiniteQuery, FETCH_ALL_PAGES_LIMIT } from "./hooks/useEntityInfiniteQuery";
|
|
41
|
+
export type { EntityInfiniteQueryProps, ItemOf } from "./hooks/useEntityInfiniteQuery";
|
|
37
42
|
|
|
38
43
|
// API helpers
|
|
39
|
-
export {
|
|
44
|
+
export {
|
|
45
|
+
buildQueryObject,
|
|
46
|
+
buildQueryKey,
|
|
47
|
+
hasWorkspaceFilter,
|
|
48
|
+
missingWorkspaceError,
|
|
49
|
+
} from "./api/entityQuery";
|
|
50
|
+
export type { QueryKeyParams } from "./api/entityQuery";
|
|
40
51
|
|
|
41
52
|
// Query client
|
|
42
|
-
export { createQueryClient
|
|
53
|
+
export { createQueryClient } from "./lib/queryClient";
|
|
43
54
|
|
|
44
55
|
// Types
|
|
45
56
|
export type { AnyRecord } from "./types/anyRecord";
|
|
46
57
|
export type {
|
|
47
|
-
|
|
48
|
-
DeleteEntityDefaultResponse,
|
|
58
|
+
DeletedEntity,
|
|
49
59
|
DeleteEntityResponse,
|
|
50
|
-
|
|
60
|
+
EntityInfiniteQueryOptions,
|
|
51
61
|
EntityListResponse,
|
|
52
62
|
EntityQueryOptions,
|
|
53
63
|
EntityQueryParams,
|
|
54
64
|
EntitySingleResponse,
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
FetchEntitiesProps,
|
|
66
|
+
FetchEntityByIdProps,
|
|
67
|
+
FetchEntityProps,
|
|
57
68
|
FilterClause,
|
|
58
69
|
FilterExpression,
|
|
59
70
|
FilterOperator,
|
|
71
|
+
ListCache,
|
|
72
|
+
ListQueryProps,
|
|
73
|
+
PagedResponse,
|
|
74
|
+
PageToken,
|
|
60
75
|
QueryObject,
|
|
61
76
|
} from "./types/entityQuery";
|
|
62
77
|
|
package/src/lib/abort.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* abortable
|
|
3
|
+
*
|
|
4
|
+
* The one shape every abortable wait here takes: a promise that `start` settles, or that rejects
|
|
5
|
+
* with the signal's reason as soon as it aborts. `start` returns its cleanup, which runs either
|
|
6
|
+
* way, so a timer or a listener never outlives the promise.
|
|
7
|
+
*
|
|
8
|
+
* @param signal - Aborts the wait.
|
|
9
|
+
* @param start - Begins the work and returns what undoes it.
|
|
10
|
+
* @returns The work's result, unless the signal aborts first.
|
|
11
|
+
*/
|
|
12
|
+
export const abortable = <T>(
|
|
13
|
+
signal: AbortSignal,
|
|
14
|
+
start: (resolve: (value: T) => void, reject: (error: unknown) => void) => () => void,
|
|
15
|
+
): Promise<T> =>
|
|
16
|
+
new Promise<T>((resolve, reject) => {
|
|
17
|
+
if (signal.aborted) return reject(signal.reason);
|
|
18
|
+
|
|
19
|
+
let cleanup = () => {};
|
|
20
|
+
const finish = () => {
|
|
21
|
+
cleanup();
|
|
22
|
+
signal.removeEventListener("abort", onAbort);
|
|
23
|
+
};
|
|
24
|
+
const onAbort = () => {
|
|
25
|
+
finish();
|
|
26
|
+
reject(signal.reason);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
30
|
+
cleanup = start(
|
|
31
|
+
(value) => {
|
|
32
|
+
finish();
|
|
33
|
+
resolve(value);
|
|
34
|
+
},
|
|
35
|
+
(error) => {
|
|
36
|
+
finish();
|
|
37
|
+
reject(error);
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Settles as `promise` does, or rejects with the signal's reason once it aborts first — for work
|
|
44
|
+
* that may not honour the signal itself.
|
|
45
|
+
*/
|
|
46
|
+
export const unlessAborted = <T>(promise: Promise<T>, signal: AbortSignal): Promise<T> =>
|
|
47
|
+
abortable(signal, (resolve, reject) => {
|
|
48
|
+
promise.then(resolve, reject);
|
|
49
|
+
return () => {};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* createDeadline
|
|
54
|
+
*
|
|
55
|
+
* A signal that aborts after `timeoutMs`, or as soon as `signal` does, each with its own error.
|
|
56
|
+
* `dispose` stops the timer and the listener once the work is done.
|
|
57
|
+
*
|
|
58
|
+
* @param options - The timeout, the outer signal, and the error each abort carries. The errors
|
|
59
|
+
* are built when the abort happens, so they can describe the state at that moment.
|
|
60
|
+
* @returns The signal, and `dispose`.
|
|
61
|
+
*/
|
|
62
|
+
export const createDeadline = ({
|
|
63
|
+
timeoutMs,
|
|
64
|
+
signal,
|
|
65
|
+
timeoutError,
|
|
66
|
+
abortError,
|
|
67
|
+
}: {
|
|
68
|
+
timeoutMs: number;
|
|
69
|
+
signal?: AbortSignal;
|
|
70
|
+
timeoutError: () => Error;
|
|
71
|
+
abortError: () => Error;
|
|
72
|
+
}) => {
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timer = setTimeout(() => controller.abort(timeoutError()), timeoutMs);
|
|
75
|
+
const abort = () => controller.abort(abortError());
|
|
76
|
+
|
|
77
|
+
if (signal?.aborted) abort();
|
|
78
|
+
else signal?.addEventListener("abort", abort, { once: true });
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
signal: controller.signal,
|
|
82
|
+
dispose() {
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
signal?.removeEventListener("abort", abort);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* anySignal
|
|
91
|
+
*
|
|
92
|
+
* A signal that aborts as soon as any of `signals` does, with that one's reason. It is
|
|
93
|
+
* `AbortSignal.any`, written out because that arrived in Chrome 116, Firefox 124 and Safari 17.4,
|
|
94
|
+
* after the browsers a Vite 8 app targets by default (Chrome 111, Firefox 114, Safari 16.4).
|
|
95
|
+
* What it uses instead — `abort(reason)`, `signal.reason` and `addEventListener`'s `once` —
|
|
96
|
+
* predates them all. Source: MDN browser-compat-data, `api/AbortSignal.json` and
|
|
97
|
+
* `api/AbortController.json` (2026-10-14).
|
|
98
|
+
*
|
|
99
|
+
* Missing signals are skipped, so an optional one can be passed as is. It stops listening to the
|
|
100
|
+
* others once one aborts, or when `dispose` is called: a run that ends normally aborts nothing,
|
|
101
|
+
* and a long-lived signal would otherwise keep one listener per run.
|
|
102
|
+
*
|
|
103
|
+
* @param signals - The signals to follow; `undefined` entries are ignored.
|
|
104
|
+
* @returns The signal that aborts with the first of them, and `dispose`.
|
|
105
|
+
*/
|
|
106
|
+
export const anySignal = (
|
|
107
|
+
signals: (AbortSignal | undefined)[],
|
|
108
|
+
): { signal: AbortSignal; dispose: () => void } => {
|
|
109
|
+
const controller = new AbortController();
|
|
110
|
+
const present = signals.filter((signal): signal is AbortSignal => signal !== undefined);
|
|
111
|
+
|
|
112
|
+
const already = present.find((signal) => signal.aborted);
|
|
113
|
+
if (already) {
|
|
114
|
+
controller.abort(already.reason);
|
|
115
|
+
return { signal: controller.signal, dispose: () => {} };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const dispose = () => {
|
|
119
|
+
for (const [signal, listener] of listeners) signal.removeEventListener("abort", listener);
|
|
120
|
+
};
|
|
121
|
+
const listeners = present.map((signal) => {
|
|
122
|
+
const listener = () => {
|
|
123
|
+
dispose();
|
|
124
|
+
controller.abort(signal.reason);
|
|
125
|
+
};
|
|
126
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
127
|
+
return [signal, listener] as const;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return { signal: controller.signal, dispose };
|
|
131
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Datastore } from "@/types/datastore";
|
|
1
|
+
import type { Datastore, ParsedDatastore, JsonDatastore } from "@/types/datastore";
|
|
2
|
+
import type { DatastoreDataFormat } from "@/types/datastoreDataFormat";
|
|
2
3
|
import type { AnyRecord } from "@/types/anyRecord";
|
|
3
4
|
|
|
4
5
|
type Cell = string | number | null;
|
|
@@ -34,30 +35,103 @@ type DatastoreData = Cell[][];
|
|
|
34
35
|
* ["Alice", 30],
|
|
35
36
|
* ["Bob", null],
|
|
36
37
|
* ];
|
|
37
|
-
* const rows =
|
|
38
|
+
* const rows = matrixToObjects("ds_123", headers, data);
|
|
38
39
|
* // [
|
|
39
40
|
* // { datastoreId: "ds_123", name: "Alice", age: 30 },
|
|
40
41
|
* // { datastoreId: "ds_123", name: "Bob", age: null }
|
|
41
42
|
* // ]
|
|
42
43
|
*/
|
|
43
|
-
export const
|
|
44
|
-
|
|
44
|
+
export const matrixToObjects = <T extends Record<string, Cell>>(
|
|
45
|
+
datastoreId: string,
|
|
46
|
+
headers: string[],
|
|
47
|
+
data: DatastoreData,
|
|
48
|
+
): T[] => {
|
|
49
|
+
const result: T[] = [];
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
for (let i = 1; i < data?.length; i++) {
|
|
52
|
+
const item: Record<string, Cell> = {};
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
item.datastoreId = datastoreId;
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
headers.forEach((header: string, index: number) => {
|
|
57
|
+
item[header] = data[i][index];
|
|
58
|
+
});
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
result.push(item as T);
|
|
61
|
+
}
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
return result;
|
|
59
64
|
};
|
|
60
65
|
|
|
66
|
+
/** A tabular datastore's `data`: an array of rows. An empty array counts, as an empty table. */
|
|
67
|
+
const isMatrix = (data: unknown): data is DatastoreData =>
|
|
68
|
+
Array.isArray(data) && data.every(Array.isArray);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Converts a datastore as the API returns it into the shape the datastore hooks return.
|
|
72
|
+
*
|
|
73
|
+
* A datastore is tabular or JSON, and the API does not say which. `data` is a matrix, an object,
|
|
74
|
+
* or an array of objects, so only an array whose every element is an array is read as a table.
|
|
75
|
+
* "Any array" is not enough: the API has returned `[{ … }]` for a JSON datastore, which read as a
|
|
76
|
+
* matrix lost its content with one element and threw with two. A table's matrix becomes row
|
|
77
|
+
* objects, with the header row kept as `fields` so that saving back can restore the column
|
|
78
|
+
* order. JSON passes through untouched.
|
|
79
|
+
*
|
|
80
|
+
* A read without its data (`projection: "-data"`) carries nothing to tell the kinds apart and
|
|
81
|
+
* comes back as an empty table.
|
|
82
|
+
*
|
|
83
|
+
* The hooks convert in the request rather than in `select`, so the cache holds objects and an
|
|
84
|
+
* app patches a row as `{ ...row, ...patch }` rather than by column index. It is exported for an
|
|
85
|
+
* app that seeds that cache itself.
|
|
86
|
+
*
|
|
87
|
+
* With `dataFormat: "matrix"` a table keeps its matrix unconverted, header row included, and still
|
|
88
|
+
* gets `fields`. JSON is untouched either way.
|
|
89
|
+
*
|
|
90
|
+
* @param datastore The datastore as the API returned it.
|
|
91
|
+
* @param dataFormat `"object"` (default) or `"matrix"`.
|
|
92
|
+
* @returns A tabular or a `JsonDatastore`, told apart by `format`.
|
|
93
|
+
*/
|
|
94
|
+
export function parseDatastore(datastore: Datastore): ParsedDatastore;
|
|
95
|
+
export function parseDatastore<F extends DatastoreDataFormat>(
|
|
96
|
+
datastore: Datastore,
|
|
97
|
+
dataFormat: F,
|
|
98
|
+
): ParsedDatastore<F>;
|
|
99
|
+
export function parseDatastore(
|
|
100
|
+
datastore: Datastore,
|
|
101
|
+
dataFormat: DatastoreDataFormat = "object",
|
|
102
|
+
): ParsedDatastore<DatastoreDataFormat> {
|
|
103
|
+
const { data } = datastore;
|
|
104
|
+
|
|
105
|
+
if (data && !isMatrix(data)) {
|
|
106
|
+
return { ...datastore, format: "json", data: data as JsonDatastore["data"] };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const matrix = (data ?? []) as DatastoreData;
|
|
110
|
+
const fields = (matrix[0] ?? []) as string[];
|
|
111
|
+
|
|
112
|
+
if (dataFormat === "matrix") {
|
|
113
|
+
return { ...datastore, format: "table", fields, data: matrix };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
...datastore,
|
|
118
|
+
format: "table",
|
|
119
|
+
fields,
|
|
120
|
+
data: matrixToObjects(datastore.id, fields, matrix),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Narrows a datastore to a tabular one, whose `data` is rows. For a `select` over a list that
|
|
126
|
+
* may mix kinds: `datastores.filter(isTableDatastore).flatMap((d) => d.data)`.
|
|
127
|
+
*
|
|
128
|
+
* @param datastore A datastore as the hooks return it.
|
|
129
|
+
* @returns True for a tabular datastore.
|
|
130
|
+
*/
|
|
131
|
+
export const isTableDatastore = <D extends ParsedDatastore<DatastoreDataFormat>>(
|
|
132
|
+
datastore: D,
|
|
133
|
+
): datastore is Extract<D, { format: "table" }> => datastore.format === "table";
|
|
134
|
+
|
|
61
135
|
/**
|
|
62
136
|
* Converts an array of objects into a datastore table (2D array).
|
|
63
137
|
*
|
|
@@ -66,7 +140,8 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
|
|
|
66
140
|
* - For each object in `data`, creates a row by mapping `headers` to values in the object.
|
|
67
141
|
* - If a header is missing in an object, the corresponding cell is set to `null`.
|
|
68
142
|
*
|
|
69
|
-
*
|
|
143
|
+
* Takes rows as the datastore hooks hand them over (`AnyRecord`): a value that is not a cell is
|
|
144
|
+
* written as it is, since the row came from a matrix in the first place.
|
|
70
145
|
*
|
|
71
146
|
* @param headers Column names (and output table header row).
|
|
72
147
|
* @param data Array of objects to convert into rows.
|
|
@@ -77,7 +152,7 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
|
|
|
77
152
|
*
|
|
78
153
|
* @example
|
|
79
154
|
* const headers = ["name", "age"];
|
|
80
|
-
* const rows =
|
|
155
|
+
* const rows = objectsToMatrix(headers, [
|
|
81
156
|
* { name: "Alice", age: 30 },
|
|
82
157
|
* { name: "Bob" }, // age missing -> null
|
|
83
158
|
* ]);
|
|
@@ -87,73 +162,51 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
|
|
|
87
162
|
* // ["Bob", null]
|
|
88
163
|
* // ]
|
|
89
164
|
*/
|
|
90
|
-
export const
|
|
91
|
-
|
|
165
|
+
export const objectsToMatrix = <T extends AnyRecord = AnyRecord>(
|
|
166
|
+
headers: string[],
|
|
167
|
+
data: T[],
|
|
168
|
+
): DatastoreData => {
|
|
169
|
+
// Built into one array: mapping the rows and then spreading them after the header copied the
|
|
170
|
+
// whole list a second time. The header is copied: a caller's `headers` is often a datastore's
|
|
171
|
+
// `fields`, held in the query cache, and renaming a column in the matrix renamed it there too.
|
|
172
|
+
const matrix: DatastoreData = [headers.slice()];
|
|
92
173
|
|
|
93
|
-
|
|
174
|
+
for (const row of data)
|
|
175
|
+
matrix.push(headers.map<Cell>((header) => (row[header] ?? null) as Cell));
|
|
176
|
+
|
|
177
|
+
return matrix;
|
|
94
178
|
};
|
|
95
179
|
|
|
96
180
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
181
|
+
* The matrix of a tabular datastore, however the hook read it. Code that saves or exports a
|
|
182
|
+
* datastore calls this without knowing the `dataFormat` it was read with: a matrix read is
|
|
183
|
+
* copied, an object read is rebuilt in the datastore's own column order (`fields`), without the
|
|
184
|
+
* `datastoreId` the SDK adds to each row, and with any patch applied to the rows.
|
|
101
185
|
*
|
|
102
|
-
*
|
|
186
|
+
* Either way the result is a new matrix the caller owns and may edit before saving. A matrix
|
|
187
|
+
* read's `data` is the matrix in the query cache, and handing that back made an edit change what
|
|
188
|
+
* every screen reading the entry sees.
|
|
103
189
|
*
|
|
104
|
-
*
|
|
190
|
+
* Do not save the result of a read that projected `data` away (`projection: "-data"`): it comes
|
|
191
|
+
* back as an empty table, indistinguishable from a real one, and saving it would empty the
|
|
192
|
+
* datastore.
|
|
105
193
|
*
|
|
106
|
-
* @
|
|
107
|
-
*
|
|
108
|
-
* [{ datastoreId: "a", x: 1 }],
|
|
109
|
-
* [{ datastoreId: "b", x: 2 }, { datastoreId: "b", x: 3 }],
|
|
110
|
-
* ]);
|
|
111
|
-
* // [{...}, {...}, {...}]
|
|
194
|
+
* @param datastore A tabular datastore as the hooks return it (narrow with `isTableDatastore`).
|
|
195
|
+
* @returns The matrix, header row first.
|
|
112
196
|
*/
|
|
113
|
-
export const
|
|
114
|
-
|
|
197
|
+
export const toDatastoreMatrix = (
|
|
198
|
+
datastore: Extract<ParsedDatastore<DatastoreDataFormat>, { format: "table" }>,
|
|
199
|
+
): DatastoreData => {
|
|
200
|
+
const { data, fields } = datastore;
|
|
115
201
|
|
|
116
|
-
|
|
117
|
-
result.push(...datastore);
|
|
118
|
-
});
|
|
202
|
+
if (data.length === 0) return fields.length > 0 ? [fields.slice()] : [];
|
|
119
203
|
|
|
120
|
-
|
|
204
|
+
// The first row is enough: the SDK built this `data`, so it is all rows or all objects. The
|
|
205
|
+
// full `isMatrix` scan guards the API's data, and here it would only walk every row for nothing.
|
|
206
|
+
// A row-by-row copy is a full copy: a matrix is two levels deep and its cells are primitives.
|
|
207
|
+
// `structuredClone` would do the same about 8 times slower (147 ms against 18 ms for 100,000
|
|
208
|
+
// rows of 10 cells), paying for cycles and special types a datastore matrix never holds.
|
|
209
|
+
return Array.isArray(data[0])
|
|
210
|
+
? (data as DatastoreData).map((row) => row.slice())
|
|
211
|
+
: objectsToMatrix(fields, data as AnyRecord[]);
|
|
121
212
|
};
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* buildDatastoreProps
|
|
125
|
-
*
|
|
126
|
-
* Extracts and maps the metadata properties of a `Datastore` into a plain object
|
|
127
|
-
* for UI usage, discarding raw data rows.
|
|
128
|
-
*
|
|
129
|
-
* - `header` is derived from `datastore.data?.[0]` (the first row of the data matrix),
|
|
130
|
-
* which is expected to contain the column names. Falls back to `[]` if not present.
|
|
131
|
-
*
|
|
132
|
-
* @param {Datastore} datastore - The source datastore object.
|
|
133
|
-
* @returns Metadata object with the datastore's descriptive properties and header.
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
* const meta = buildDatastoreProps(datastore);
|
|
137
|
-
* // {
|
|
138
|
-
* // name: "my-datastore",
|
|
139
|
-
* // workspace: "ws-1",
|
|
140
|
-
* // header: ["col1", "col2"],
|
|
141
|
-
* // ...
|
|
142
|
-
* // }
|
|
143
|
-
*/
|
|
144
|
-
export const buildDatastoreProps = (datastore: Datastore) => {
|
|
145
|
-
return {
|
|
146
|
-
name: datastore.name,
|
|
147
|
-
date: datastore.date,
|
|
148
|
-
version: datastore.version,
|
|
149
|
-
description: datastore.description,
|
|
150
|
-
tags: datastore.tags,
|
|
151
|
-
link_uid: datastore.link_uid,
|
|
152
|
-
workspace: datastore.workspace,
|
|
153
|
-
date_time: datastore.date_time,
|
|
154
|
-
created: datastore.created,
|
|
155
|
-
updated: datastore.updated,
|
|
156
|
-
level: datastore.level,
|
|
157
|
-
header: datastore.data?.[0] || [],
|
|
158
|
-
};
|
|
159
|
-
};
|
package/src/lib/file.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fileToBase64
|
|
3
|
+
*
|
|
4
|
+
* The raw base64 `createFile` and `updateFile` take as `data`, from a `File` an `<input
|
|
5
|
+
* type="file">` gives or any `Blob`. The API stores `data` as given, so the `data:<type>;base64,`
|
|
6
|
+
* prefix `FileReader` puts in front would be stored as part of the content.
|
|
7
|
+
*
|
|
8
|
+
* Read through `FileReader` rather than by encoding the bytes in a loop: the browser encodes
|
|
9
|
+
* natively, with no binary string built byte by byte for `btoa`. An empty file reads as `data:`
|
|
10
|
+
* with no comma in Chromium, so a missing comma is empty content — for an empty file only, as
|
|
11
|
+
* a file with content read that way would otherwise be uploaded empty.
|
|
12
|
+
*
|
|
13
|
+
* @param blob - The file.
|
|
14
|
+
* @returns The content as base64, without a prefix.
|
|
15
|
+
*/
|
|
16
|
+
export const fileToBase64 = (blob: Blob): Promise<string> =>
|
|
17
|
+
new Promise((resolve, reject) => {
|
|
18
|
+
const reader = new FileReader();
|
|
19
|
+
reader.onload = () => {
|
|
20
|
+
const dataUrl = String(reader.result);
|
|
21
|
+
const comma = dataUrl.indexOf(",");
|
|
22
|
+
if (comma !== -1) {
|
|
23
|
+
resolve(dataUrl.slice(comma + 1));
|
|
24
|
+
} else if (blob.size === 0) {
|
|
25
|
+
resolve("");
|
|
26
|
+
} else {
|
|
27
|
+
reject(new Error("Unable to read the file: it read as a data URL with no content"));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
reader.onerror = () => reject(reader.error ?? new Error("Unable to read the file"));
|
|
31
|
+
reader.readAsDataURL(blob);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* base64ToBlob
|
|
36
|
+
*
|
|
37
|
+
* A file's content, as the API returns it in `data`, decoded into a `Blob` byte for byte: to work
|
|
38
|
+
* on the bytes in code, such as parsing a CSV or unzipping. Not to show the file — the app page's
|
|
39
|
+
* CSP blocks a `blob:` frame, image or media; use the file's own `url` — and it decodes
|
|
40
|
+
* synchronously, a byte at a time, so a file of several megabytes is better read through it.
|
|
41
|
+
*
|
|
42
|
+
* Without content — a file read without `withData: true` — it warns and gives an empty blob:
|
|
43
|
+
* `atob(null)` decodes the text "null", three bytes of garbage that would pass for the file.
|
|
44
|
+
*
|
|
45
|
+
* @param data - The content as base64, as the hooks return it with `withData: true`.
|
|
46
|
+
* @param contentType - The file's `content_type`, which becomes the blob's `type`.
|
|
47
|
+
* @returns The content.
|
|
48
|
+
* @throws {Error} If `data` is not raw base64.
|
|
49
|
+
*/
|
|
50
|
+
export const base64ToBlob = (data: string | null | undefined, contentType: string): Blob => {
|
|
51
|
+
if (data == null) {
|
|
52
|
+
console.warn(
|
|
53
|
+
"[apps-sdk] base64ToBlob: the file came without its content; read it with withData: true.",
|
|
54
|
+
);
|
|
55
|
+
return new Blob([], { type: contentType });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let binary: string;
|
|
59
|
+
try {
|
|
60
|
+
binary = atob(data);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error("The file's data is not raw base64", { cause: error });
|
|
63
|
+
}
|
|
64
|
+
const bytes = new Uint8Array(binary.length);
|
|
65
|
+
for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
|
|
66
|
+
return new Blob([bytes], { type: contentType });
|
|
67
|
+
};
|