@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
package/src/api/workspace.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AxiosInstance } from "axios";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
4
|
-
import type { Workspace, WorkspaceListResponse
|
|
3
|
+
import type { EntitySingleResponse } from "@/types/entityQuery";
|
|
4
|
+
import type { Workspace, WorkspaceListResponse } from "@/types/workspace";
|
|
5
|
+
import { pageParams, request } from "./request";
|
|
5
6
|
|
|
6
7
|
const baseUrl = "workspaces";
|
|
7
8
|
|
|
9
|
+
/** The endpoint's envelope, private: `getWorkspace` returns the workspace itself. */
|
|
10
|
+
type WorkspaceSingleResponse = EntitySingleResponse<"workspace", Workspace>;
|
|
11
|
+
|
|
8
12
|
/**
|
|
9
13
|
* getWorkspace
|
|
10
14
|
*
|
|
@@ -12,61 +16,57 @@ const baseUrl = "workspaces";
|
|
|
12
16
|
*
|
|
13
17
|
* @param {AxiosInstance} api - Axios instance.
|
|
14
18
|
* @param {string} name - Workspace name.
|
|
19
|
+
* @param {AbortSignal} [signal] - Aborts the request itself; the entity hooks pass the query's own.
|
|
15
20
|
* @returns {Promise<Workspace>} The fetched workspace.
|
|
16
21
|
*
|
|
17
22
|
* @throws {Error} If the request fails.
|
|
18
23
|
*/
|
|
19
|
-
export const getWorkspace = async (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} catch (error: unknown) {
|
|
26
|
-
if (isAxiosError<AnyRecord>(error)) {
|
|
27
|
-
throw new Error(error.message || "Error while fetching workspace", { cause: error });
|
|
28
|
-
}
|
|
24
|
+
export const getWorkspace = async (
|
|
25
|
+
api: AxiosInstance,
|
|
26
|
+
name: string,
|
|
27
|
+
signal?: AbortSignal,
|
|
28
|
+
): Promise<Workspace> => {
|
|
29
|
+
if (!name) throw new Error("Workspace name is required to fetch a workspace");
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const body = await request(
|
|
32
|
+
() => api.get<WorkspaceSingleResponse>(`${baseUrl}/${name}`, { signal }),
|
|
33
|
+
"Error fetching workspace",
|
|
34
|
+
);
|
|
35
|
+
return body.workspace;
|
|
36
|
+
};
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
/** What `listWorkspaces` sends. */
|
|
39
|
+
export type WorkspaceListParams = {
|
|
40
|
+
/** A name prefix. Sent as `query`. */
|
|
41
|
+
search?: string;
|
|
42
|
+
pageSize?: number;
|
|
43
|
+
pageToken?: string;
|
|
36
44
|
};
|
|
37
45
|
|
|
38
46
|
/**
|
|
39
47
|
* listWorkspaces
|
|
40
48
|
*
|
|
41
|
-
*
|
|
49
|
+
* Lists the account's workspaces, a page at a time.
|
|
50
|
+
*
|
|
51
|
+
* The one list that takes no workspace: the docs exempt it, and the endpoint ignores one. This
|
|
52
|
+
* function used to send it anyway, documented as "required by some API configurations".
|
|
42
53
|
*
|
|
43
54
|
* @param {AxiosInstance} api - Axios instance.
|
|
44
|
-
* @param {
|
|
45
|
-
* @param {
|
|
46
|
-
* @
|
|
47
|
-
* @returns {Promise<WorkspaceListResponse>} List of workspaces.
|
|
55
|
+
* @param {WorkspaceListParams} [params] - Search and paging.
|
|
56
|
+
* @param {AbortSignal} [signal] - Aborts the request itself; the list hooks pass the query's own.
|
|
57
|
+
* @returns {Promise<WorkspaceListResponse>} A page of workspaces, with the cursor to the next one.
|
|
48
58
|
*
|
|
49
59
|
* @throws {Error} If the request fails.
|
|
50
60
|
*/
|
|
51
|
-
export const listWorkspaces = async (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const response: AxiosResponse<WorkspaceListResponse> = await api.get(baseUrl, { params });
|
|
60
|
-
return response.data;
|
|
61
|
-
} catch (error: unknown) {
|
|
62
|
-
if (isAxiosError<AnyRecord>(error)) {
|
|
63
|
-
throw new Error(error.message || "Error while fetching workspaces", { cause: error });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (error instanceof Error) {
|
|
67
|
-
throw error;
|
|
68
|
-
}
|
|
61
|
+
export const listWorkspaces = async (
|
|
62
|
+
api: AxiosInstance,
|
|
63
|
+
{ search, pageSize, pageToken }: WorkspaceListParams = {},
|
|
64
|
+
signal?: AbortSignal,
|
|
65
|
+
): Promise<WorkspaceListResponse> => {
|
|
66
|
+
const params = pageParams({ search, pageSize, pageToken });
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
return request(
|
|
69
|
+
() => api.get<WorkspaceListResponse>(baseUrl, { params, signal }),
|
|
70
|
+
"Error listing workspaces",
|
|
71
|
+
);
|
|
72
72
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { PropsWithChildren } from "react"
|
|
1
|
+
import type { PropsWithChildren } from "react";
|
|
2
2
|
|
|
3
|
-
import { clsx } from
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
4
|
import Paper from "@mui/material/Paper";
|
|
5
5
|
import { useTheme, type Theme } from "@mui/material/styles";
|
|
6
6
|
|
|
@@ -10,11 +10,11 @@ export const Footer = ({ className, children }: PropsWithChildren<{ className?:
|
|
|
10
10
|
const theme: Theme = useTheme();
|
|
11
11
|
const paperProps: AnyRecord = {
|
|
12
12
|
light: {
|
|
13
|
-
variant:
|
|
13
|
+
variant: "outlined",
|
|
14
14
|
},
|
|
15
15
|
dark: {
|
|
16
|
-
variant:
|
|
17
|
-
}
|
|
16
|
+
variant: "elevation",
|
|
17
|
+
},
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
return (
|
|
@@ -23,8 +23,9 @@ export const Footer = ({ className, children }: PropsWithChildren<{ className?:
|
|
|
23
23
|
elevation={1}
|
|
24
24
|
component="footer"
|
|
25
25
|
className={clsx("flex shrink-0 grow-0 basis-auto h-16 pl-6 pr-6", className)}
|
|
26
|
-
{...paperProps?.[theme.palette.mode]}
|
|
26
|
+
{...paperProps?.[theme.palette.mode]}
|
|
27
|
+
>
|
|
27
28
|
{children}
|
|
28
29
|
</Paper>
|
|
29
30
|
);
|
|
30
|
-
}
|
|
31
|
+
};
|
|
@@ -21,7 +21,14 @@ export const GlobalLoading = ({ isLoading, backdrop = true, message }: GlobalLoa
|
|
|
21
21
|
|
|
22
22
|
if (!backdrop) {
|
|
23
23
|
return (
|
|
24
|
-
<Box
|
|
24
|
+
<Box
|
|
25
|
+
sx={{
|
|
26
|
+
display: "flex",
|
|
27
|
+
justifyContent: "center",
|
|
28
|
+
alignItems: "center",
|
|
29
|
+
height: "100%",
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
25
32
|
{content}
|
|
26
33
|
</Box>
|
|
27
34
|
);
|
|
@@ -30,9 +37,12 @@ export const GlobalLoading = ({ isLoading, backdrop = true, message }: GlobalLoa
|
|
|
30
37
|
return (
|
|
31
38
|
<Backdrop
|
|
32
39
|
open
|
|
33
|
-
sx={{
|
|
40
|
+
sx={{
|
|
41
|
+
zIndex: (theme) => theme.zIndex.modal + 1,
|
|
42
|
+
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
|
43
|
+
}}
|
|
34
44
|
>
|
|
35
45
|
{content}
|
|
36
46
|
</Backdrop>
|
|
37
47
|
);
|
|
38
|
-
}
|
|
48
|
+
};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import clsx from "clsx";
|
|
2
2
|
import type { PropsWithChildren, ReactNode } from "react";
|
|
3
3
|
|
|
4
|
-
export const PageContainer = ({
|
|
4
|
+
export const PageContainer = ({
|
|
5
|
+
header,
|
|
6
|
+
footer,
|
|
7
|
+
contentClassName,
|
|
8
|
+
children,
|
|
9
|
+
}: PropsWithChildren<{ header?: ReactNode; footer?: ReactNode; contentClassName?: string }>) => {
|
|
5
10
|
return (
|
|
6
11
|
<div className="flex flex-col w-full h-full overflow-hidden">
|
|
7
12
|
{header}
|
|
8
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
className={clsx("flex shrink-1 grow-1 basis-auto overflow-auto", contentClassName)}
|
|
15
|
+
>
|
|
9
16
|
{children}
|
|
10
17
|
</div>
|
|
11
18
|
{footer}
|
|
@@ -1,44 +1,119 @@
|
|
|
1
|
-
import type { PropsWithChildren } from
|
|
1
|
+
import type { PropsWithChildren, ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
import AppBar from
|
|
4
|
-
import { useTheme, type Theme } from
|
|
5
|
-
import MuiToolbar from
|
|
3
|
+
import AppBar, { type AppBarProps } from "@mui/material/AppBar";
|
|
4
|
+
import { useTheme, type PaletteMode, type Theme } from "@mui/material/styles";
|
|
5
|
+
import MuiToolbar from "@mui/material/Toolbar";
|
|
6
|
+
import Typography from "@mui/material/Typography";
|
|
6
7
|
|
|
7
|
-
import clsx from
|
|
8
|
+
import clsx from "clsx";
|
|
8
9
|
|
|
9
|
-
import { EveryskIcon } from
|
|
10
|
+
import { EveryskIcon } from "@/components/ui/EveryskIcon";
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The names follow MUI's own header components: `title`, `subheader` and `action` are
|
|
14
|
+
* `CardHeader`'s, `logo` is Toolpad's `branding.logo`, and the boolean reads as what turning
|
|
15
|
+
* it *on* does (`hideLogo`), because an MUI boolean defaults to `false`.
|
|
16
|
+
*/
|
|
17
|
+
export type ToolbarProps = PropsWithChildren<{
|
|
18
|
+
/**
|
|
19
|
+
* Rendered before the logo. It is a slot rather than `onToggleMenu`/`onBack` props because
|
|
20
|
+
* the buttons that go here belong to whatever shell hosts the bar (a drawer toggle, a back
|
|
21
|
+
* button), and a prop per button would make the bar grow with every shell.
|
|
22
|
+
*/
|
|
23
|
+
startAction?: ReactNode;
|
|
24
|
+
/** Replaces the Everysk mark, for an app that carries its client's. */
|
|
25
|
+
logo?: ReactNode;
|
|
26
|
+
/**
|
|
27
|
+
* A flag rather than `logo={null}` or `logo={false}` (MUI's `Alert.icon` spelling), so
|
|
28
|
+
* that no single prop means default, replace and remove at once. It wins over `logo`.
|
|
29
|
+
*/
|
|
30
|
+
hideLogo?: boolean;
|
|
31
|
+
/** The page heading. An `h1`: the bar is where the page says what it is. */
|
|
32
|
+
title?: ReactNode;
|
|
33
|
+
subheader?: ReactNode;
|
|
34
|
+
/** Pushed to the far end of the bar, so no page has to align it with `justify-between`. */
|
|
35
|
+
action?: ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* `relative` by default: in `PageContainer` only the content scrolls, so the bar stays put
|
|
38
|
+
* by layout. `sticky` is for a page that scrolls as a whole.
|
|
39
|
+
*/
|
|
40
|
+
position?: AppBarProps["position"];
|
|
41
|
+
/** Applied to the content row. */
|
|
42
|
+
className?: string;
|
|
43
|
+
}>;
|
|
12
44
|
|
|
13
|
-
|
|
14
|
-
|
|
45
|
+
/**
|
|
46
|
+
* What a page supplies, as opposed to what the chrome around it decides (`startAction`, the
|
|
47
|
+
* logo, `position`). A shell that renders the bar for its pages holds this, and a page
|
|
48
|
+
* publishes it without ever rendering the bar itself.
|
|
49
|
+
*/
|
|
50
|
+
export type ToolbarContent = Pick<ToolbarProps, "title" | "subheader" | "action" | "children">;
|
|
15
51
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
52
|
+
// Typed as AppBar props, not `AnyRecord`: a loose map here is what let an invalid `color: ''`
|
|
53
|
+
// through for as long as it did.
|
|
54
|
+
const MODE_PROPS: Record<PaletteMode, AppBarProps> = {
|
|
55
|
+
light: {
|
|
56
|
+
color: "transparent",
|
|
57
|
+
elevation: 0,
|
|
58
|
+
sx: {
|
|
59
|
+
border: "1px solid rgba(0, 0, 0, 0.12)",
|
|
23
60
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
61
|
+
},
|
|
62
|
+
dark: {
|
|
63
|
+
// 'default', not ''. An empty string is not a value the AppBar API takes — it
|
|
64
|
+
// produced the class `MuiAppBar-color` with no variant suffix, which rendered the
|
|
65
|
+
// same only because the brand theme overrides AppBar anyway. This is the explicit
|
|
66
|
+
// spelling of what already happens, and it survives a theme that does not.
|
|
67
|
+
color: "default",
|
|
68
|
+
elevation: 1,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const Toolbar = ({
|
|
73
|
+
startAction,
|
|
74
|
+
logo,
|
|
75
|
+
hideLogo = false,
|
|
76
|
+
title,
|
|
77
|
+
subheader,
|
|
78
|
+
action,
|
|
79
|
+
position = "relative",
|
|
80
|
+
className,
|
|
81
|
+
children,
|
|
82
|
+
}: ToolbarProps) => {
|
|
83
|
+
const theme: Theme = useTheme();
|
|
33
84
|
|
|
34
85
|
return (
|
|
35
|
-
<AppBar position=
|
|
36
|
-
<MuiToolbar
|
|
37
|
-
<div className={clsx("flex items-center gap-4", className)}>
|
|
38
|
-
<
|
|
86
|
+
<AppBar position={position} {...MODE_PROPS[theme.palette.mode]}>
|
|
87
|
+
<MuiToolbar>
|
|
88
|
+
<div className={clsx("flex items-center gap-4 w-full min-w-0", className)}>
|
|
89
|
+
{startAction && <div className="flex items-center shrink-0">{startAction}</div>}
|
|
90
|
+
|
|
91
|
+
{!hideLogo && (logo ?? <EveryskIcon titleAccess="Everysk" />)}
|
|
92
|
+
|
|
93
|
+
{(title || subheader) && (
|
|
94
|
+
// `min-w-0` is what lets the title truncate instead of pushing the
|
|
95
|
+
// action out of the bar.
|
|
96
|
+
<div className="flex flex-col min-w-0">
|
|
97
|
+
{title && (
|
|
98
|
+
<Typography variant="h6" component="h1" noWrap>
|
|
99
|
+
{title}
|
|
100
|
+
</Typography>
|
|
101
|
+
)}
|
|
102
|
+
{subheader && (
|
|
103
|
+
<Typography variant="body2" color="text.secondary" noWrap>
|
|
104
|
+
{subheader}
|
|
105
|
+
</Typography>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
)}
|
|
109
|
+
|
|
39
110
|
{children}
|
|
111
|
+
|
|
112
|
+
{action && (
|
|
113
|
+
<div className="flex items-center gap-3 ml-auto shrink-0">{action}</div>
|
|
114
|
+
)}
|
|
40
115
|
</div>
|
|
41
116
|
</MuiToolbar>
|
|
42
117
|
</AppBar>
|
|
43
118
|
);
|
|
44
|
-
}
|
|
119
|
+
};
|
|
@@ -12,6 +12,6 @@ export type ShowAlertOptions = Partial<Omit<AppAlertState, "open">> & {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export type AppAlertContextType = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
15
|
+
showAlert: (options: ShowAlertOptions) => void;
|
|
16
|
+
hideAlert: () => void;
|
|
17
|
+
};
|
|
@@ -59,9 +59,5 @@ export const AppConfigProvider = ({
|
|
|
59
59
|
};
|
|
60
60
|
}, [appId, appEnvironmentVar]);
|
|
61
61
|
|
|
62
|
-
return
|
|
63
|
-
<AppConfigContext.Provider value={value}>
|
|
64
|
-
{children}
|
|
65
|
-
</AppConfigContext.Provider>
|
|
66
|
-
);
|
|
62
|
+
return <AppConfigContext.Provider value={value}>{children}</AppConfigContext.Provider>;
|
|
67
63
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { io, type Socket } from "socket.io-client";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { WebsocketsConfig } from "@/api/websocketsConfig";
|
|
4
|
+
import type { WebSocketNotification, WebSocketStatus } from "./types";
|
|
4
5
|
|
|
5
6
|
function isWebSocketNotification(value: unknown): value is WebSocketNotification {
|
|
6
7
|
return (
|
|
@@ -35,7 +36,12 @@ export class WebSocketHandler {
|
|
|
35
36
|
private _everyskUID: string;
|
|
36
37
|
private _listeners: Set<(msg: WebSocketNotification) => void> = new Set();
|
|
37
38
|
|
|
38
|
-
constructor({
|
|
39
|
+
constructor({
|
|
40
|
+
appConnectionURL,
|
|
41
|
+
appChannelID,
|
|
42
|
+
everyskUID,
|
|
43
|
+
onStatusChange,
|
|
44
|
+
}: WebSocketHandlerConfig) {
|
|
39
45
|
this._everyskUID = everyskUID;
|
|
40
46
|
|
|
41
47
|
this._socket = io(appConnectionURL, {
|
|
@@ -7,7 +7,7 @@ import { WebSocketContext } from "../..";
|
|
|
7
7
|
*
|
|
8
8
|
* Convenience hook that reads the WebSocket API from `WebSocketContext`.
|
|
9
9
|
*
|
|
10
|
-
* Returns: `{ subscribe, lastMessage, status }` (see `WebSocketContextType`).
|
|
10
|
+
* Returns: `{ subscribe, subscribeStatus, lastMessage, status }` (see `WebSocketContextType`).
|
|
11
11
|
*
|
|
12
12
|
* @throws {Error} If used outside of `<WebSocketProvider>`.
|
|
13
13
|
*/
|
|
@@ -5,7 +5,24 @@ import { useAxios } from "@/hooks/useAxios";
|
|
|
5
5
|
import { useAppAlert } from "@/contexts/appAlertContext/useAppAlert";
|
|
6
6
|
import { WebSocketContext } from ".";
|
|
7
7
|
import { WebSocketHandler } from "./handler";
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
WebSocketContextType,
|
|
10
|
+
WebSocketNotification,
|
|
11
|
+
WebSocketProviderProps,
|
|
12
|
+
WebSocketStatus,
|
|
13
|
+
} from "./types";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Calls a status listener, logging and skipping one that throws, as notification listeners are,
|
|
17
|
+
* so it cannot keep the others from hearing the change.
|
|
18
|
+
*/
|
|
19
|
+
const tellStatus = (listener: (status: WebSocketStatus) => void, status: WebSocketStatus) => {
|
|
20
|
+
try {
|
|
21
|
+
listener(status);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error("WebSocket status listener threw:", error);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
9
26
|
|
|
10
27
|
/**
|
|
11
28
|
* WebSocketProvider
|
|
@@ -14,9 +31,10 @@ import type { WebSocketContextType, WebSocketNotification, WebSocketProviderProp
|
|
|
14
31
|
*
|
|
15
32
|
* What this provider does:
|
|
16
33
|
* - Fetches `/api/websockets_config` once on mount to get the connection URL, channel id,
|
|
17
|
-
* and session uid. Socket.IO handles reconnection internally — the config is not re-fetched
|
|
34
|
+
* and session uid. Socket.IO handles reconnection internally — the config is not re-fetched,
|
|
35
|
+
* and the effect that does it runs once (`changeStatus`, its only dependency, is stable).
|
|
18
36
|
* - Opens a `WebSocketHandler` instance that connects and joins the per-user channel.
|
|
19
|
-
* - Exposes `subscribe`, `lastMessage`, and `status` via `WebSocketContext`.
|
|
37
|
+
* - Exposes `subscribe`, `subscribeStatus`, `lastMessage`, and `status` via `WebSocketContext`.
|
|
20
38
|
*
|
|
21
39
|
* Why the pending buffer exists (`pendingRef`):
|
|
22
40
|
* - The handler is created asynchronously (after the config fetch resolves).
|
|
@@ -40,8 +58,10 @@ import type { WebSocketContextType, WebSocketNotification, WebSocketProviderProp
|
|
|
40
58
|
* Context value (WebSocketContextType):
|
|
41
59
|
* @returns {object}
|
|
42
60
|
* - `subscribe(fn)`: register a listener; returns an unsubscribe function.
|
|
61
|
+
* - `subscribeStatus(fn)`: hear the current status at once, then every status the socket
|
|
62
|
+
* reports, repeats included; returns an unsubscribe function.
|
|
43
63
|
* - `lastMessage`: the most recently received notification (or null).
|
|
44
|
-
* - `status`: current connection status ("connecting" | "connected" | "error").
|
|
64
|
+
* - `status`: current connection status ("idle" | "connecting" | "connected" | "error").
|
|
45
65
|
*/
|
|
46
66
|
export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
47
67
|
const { api } = useAxios();
|
|
@@ -51,13 +71,30 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
|
51
71
|
// making it re-run when api or showAlert change.
|
|
52
72
|
const apiRef = useRef(api);
|
|
53
73
|
const showAlertRef = useRef(showAlert);
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
apiRef.current = api;
|
|
76
|
+
});
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
showAlertRef.current = showAlert;
|
|
79
|
+
});
|
|
56
80
|
|
|
57
81
|
const handlerRef = useRef<WebSocketHandler | null>(null);
|
|
58
82
|
const unsubscribeProviderRef = useRef<(() => void) | null>(null);
|
|
59
83
|
const [lastMessage, setLastMessage] = useState<WebSocketNotification | null>(null);
|
|
60
84
|
const [status, setStatus] = useState<WebSocketStatus>("idle");
|
|
85
|
+
const statusListenersRef = useRef(new Set<(status: WebSocketStatus) => void>());
|
|
86
|
+
const currentStatusRef = useRef<WebSocketStatus>("idle");
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Sets `status` and tells the status listeners, so both see the same sequence. The current
|
|
90
|
+
* status is also kept in a ref, so a new listener is told it at once rather than from React
|
|
91
|
+
* state, which lags a change until the next render.
|
|
92
|
+
*/
|
|
93
|
+
const changeStatus = useCallback((next: WebSocketStatus) => {
|
|
94
|
+
currentStatusRef.current = next;
|
|
95
|
+
setStatus(next);
|
|
96
|
+
statusListenersRef.current.forEach((listener) => tellStatus(listener, next));
|
|
97
|
+
}, []);
|
|
61
98
|
|
|
62
99
|
const pendingRef = useRef(new Map<(m: WebSocketNotification) => void, (() => void) | null>());
|
|
63
100
|
|
|
@@ -69,14 +106,16 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
|
69
106
|
.then((config) => {
|
|
70
107
|
if (cancelled) return;
|
|
71
108
|
|
|
72
|
-
|
|
109
|
+
changeStatus("connecting");
|
|
73
110
|
const handler = new WebSocketHandler({
|
|
74
111
|
...config,
|
|
75
|
-
onStatusChange:
|
|
112
|
+
onStatusChange: changeStatus,
|
|
76
113
|
});
|
|
77
114
|
handlerRef.current = handler;
|
|
78
115
|
|
|
79
|
-
unsubscribeProviderRef.current = handler.listen((message) =>
|
|
116
|
+
unsubscribeProviderRef.current = handler.listen((message) =>
|
|
117
|
+
setLastMessage(message),
|
|
118
|
+
);
|
|
80
119
|
|
|
81
120
|
for (const [fn, unsub] of pending.entries()) {
|
|
82
121
|
if (!unsub) {
|
|
@@ -88,8 +127,11 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
|
88
127
|
.catch((error) => {
|
|
89
128
|
if (cancelled) return;
|
|
90
129
|
console.error("Failed to initialize WebSocket connection:", error);
|
|
91
|
-
|
|
92
|
-
showAlertRef.current({
|
|
130
|
+
changeStatus("error");
|
|
131
|
+
showAlertRef.current({
|
|
132
|
+
message: "Real-time notifications are unavailable. Please refresh the page.",
|
|
133
|
+
severity: "error",
|
|
134
|
+
});
|
|
93
135
|
});
|
|
94
136
|
|
|
95
137
|
return () => {
|
|
@@ -100,7 +142,7 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
|
100
142
|
handlerRef.current = null;
|
|
101
143
|
pending.clear();
|
|
102
144
|
};
|
|
103
|
-
}, []);
|
|
145
|
+
}, [changeStatus]);
|
|
104
146
|
|
|
105
147
|
const subscribe = useCallback((fn: (m: WebSocketNotification) => void) => {
|
|
106
148
|
if (handlerRef.current) {
|
|
@@ -116,9 +158,17 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
|
|
116
158
|
};
|
|
117
159
|
}, []);
|
|
118
160
|
|
|
161
|
+
const subscribeStatus = useCallback((listener: (status: WebSocketStatus) => void) => {
|
|
162
|
+
statusListenersRef.current.add(listener);
|
|
163
|
+
tellStatus(listener, currentStatusRef.current);
|
|
164
|
+
return () => {
|
|
165
|
+
statusListenersRef.current.delete(listener);
|
|
166
|
+
};
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
119
169
|
const value: WebSocketContextType = useMemo(
|
|
120
|
-
() => ({ subscribe, lastMessage, status }),
|
|
121
|
-
[subscribe, lastMessage, status]
|
|
170
|
+
() => ({ subscribe, subscribeStatus, lastMessage, status }),
|
|
171
|
+
[subscribe, subscribeStatus, lastMessage, status],
|
|
122
172
|
);
|
|
123
173
|
|
|
124
174
|
return <WebSocketContext.Provider value={value}>{children}</WebSocketContext.Provider>;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
|
|
3
|
-
export type WebsocketsConfig = {
|
|
4
|
-
appConnectionURL: string;
|
|
5
|
-
appChannelID: string;
|
|
6
|
-
everyskUID: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
3
|
export type WebSocketStatus = "idle" | "connecting" | "connected" | "error";
|
|
10
4
|
|
|
11
5
|
export type AppNotificationPayload = {
|
|
@@ -38,6 +32,13 @@ export type AppNotification = WebSocketNotification & {
|
|
|
38
32
|
|
|
39
33
|
export type WebSocketContextType = {
|
|
40
34
|
subscribe: (listener: (msg: WebSocketNotification) => void) => () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Calls `listener` with the current status at once, then on every status the socket reports,
|
|
37
|
+
* repeats included; returns the unsubscribe. For code that waits on the socket outside React,
|
|
38
|
+
* where `status` cannot be watched: a reconnect is when it must catch up on what was
|
|
39
|
+
* published in between, which the server does not replay.
|
|
40
|
+
*/
|
|
41
|
+
subscribeStatus: (listener: (status: WebSocketStatus) => void) => () => void;
|
|
41
42
|
lastMessage: WebSocketNotification | null;
|
|
42
43
|
status: WebSocketStatus;
|
|
43
44
|
};
|
package/src/file/index.ts
CHANGED