@stigmer/react 0.0.101 → 0.1.1
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/agent/AgentPicker.js +1 -1
- package/agent/AgentPicker.js.map +1 -1
- package/agent/__tests__/useDefaultAgent.test.d.ts +2 -0
- package/agent/__tests__/useDefaultAgent.test.d.ts.map +1 -0
- package/agent/__tests__/useDefaultAgent.test.js +252 -0
- package/agent/__tests__/useDefaultAgent.test.js.map +1 -0
- package/agent/useAgent.d.ts +2 -0
- package/agent/useAgent.d.ts.map +1 -1
- package/agent/useAgent.js +14 -37
- package/agent/useAgent.js.map +1 -1
- package/agent/useAgentCount.d.ts +1 -1
- package/agent/useAgentCount.d.ts.map +1 -1
- package/agent/useAgentList.d.ts +2 -2
- package/agent/useAgentList.d.ts.map +1 -1
- package/agent/useDefaultAgent.d.ts +6 -2
- package/agent/useDefaultAgent.d.ts.map +1 -1
- package/agent/useDefaultAgent.js +51 -31
- package/agent/useDefaultAgent.js.map +1 -1
- package/agent-instance/useAgentInstance.d.ts +2 -0
- package/agent-instance/useAgentInstance.d.ts.map +1 -1
- package/agent-instance/useAgentInstance.js +6 -33
- package/agent-instance/useAgentInstance.js.map +1 -1
- package/agent-instance/useAgentInstanceList.d.ts +2 -0
- package/agent-instance/useAgentInstanceList.d.ts.map +1 -1
- package/agent-instance/useAgentInstanceList.js +22 -40
- package/agent-instance/useAgentInstanceList.js.map +1 -1
- package/api-key/useApiKeyList.d.ts +2 -0
- package/api-key/useApiKeyList.d.ts.map +1 -1
- package/api-key/useApiKeyList.js +3 -27
- package/api-key/useApiKeyList.js.map +1 -1
- package/composer/ComposerToolbar.d.ts +1 -5
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +3 -4
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/ContextChip.d.ts +1 -1
- package/composer/ContextChip.d.ts.map +1 -1
- package/composer/ContextChip.js +1 -0
- package/composer/ContextChip.js.map +1 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +77 -4
- package/composer/SessionComposer.js.map +1 -1
- package/composer/icons.d.ts +1 -0
- package/composer/icons.d.ts.map +1 -1
- package/composer/icons.js +3 -0
- package/composer/icons.js.map +1 -1
- package/environment/useEnvironment.d.ts +2 -0
- package/environment/useEnvironment.d.ts.map +1 -1
- package/environment/useEnvironment.js +6 -33
- package/environment/useEnvironment.js.map +1 -1
- package/environment/useEnvironmentList.d.ts +2 -0
- package/environment/useEnvironmentList.d.ts.map +1 -1
- package/environment/useEnvironmentList.js +23 -53
- package/environment/useEnvironmentList.js.map +1 -1
- package/execution/ArtifactPreviewModal.js +1 -1
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/useArtifactContent.d.ts +4 -2
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +23 -45
- package/execution/useArtifactContent.js.map +1 -1
- package/iam-policy/usePrincipalsCount.d.ts +2 -0
- package/iam-policy/usePrincipalsCount.d.ts.map +1 -1
- package/iam-policy/usePrincipalsCount.js +7 -46
- package/iam-policy/usePrincipalsCount.js.map +1 -1
- package/iam-policy/useResourceAccess.d.ts +2 -0
- package/iam-policy/useResourceAccess.d.ts.map +1 -1
- package/iam-policy/useResourceAccess.js +12 -47
- package/iam-policy/useResourceAccess.js.map +1 -1
- package/identity-provider/useIdentityProvider.d.ts +2 -0
- package/identity-provider/useIdentityProvider.d.ts.map +1 -1
- package/identity-provider/useIdentityProvider.js +3 -33
- package/identity-provider/useIdentityProvider.js.map +1 -1
- package/identity-provider/useIdentityProviderList.d.ts +2 -0
- package/identity-provider/useIdentityProviderList.d.ts.map +1 -1
- package/identity-provider/useIdentityProviderList.js +7 -33
- package/identity-provider/useIdentityProviderList.js.map +1 -1
- package/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/internal/__tests__/useFetch.test.d.ts +2 -0
- package/internal/__tests__/useFetch.test.d.ts.map +1 -0
- package/internal/__tests__/useFetch.test.js +95 -0
- package/internal/__tests__/useFetch.test.js.map +1 -0
- package/internal/useFetch.d.ts +51 -0
- package/internal/useFetch.d.ts.map +1 -0
- package/internal/useFetch.js +75 -0
- package/internal/useFetch.js.map +1 -0
- package/invitation/useInvitationPreview.d.ts +2 -0
- package/invitation/useInvitationPreview.d.ts.map +1 -1
- package/invitation/useInvitationPreview.js +5 -35
- package/invitation/useInvitationPreview.js.map +1 -1
- package/invitation/useOrgInvitations.d.ts +2 -0
- package/invitation/useOrgInvitations.d.ts.map +1 -1
- package/invitation/useOrgInvitations.js +6 -34
- package/invitation/useOrgInvitations.js.map +1 -1
- package/library/ResourceListView.d.ts +2 -2
- package/library/ResourceListView.d.ts.map +1 -1
- package/library/ResourceListView.js +1 -1
- package/library/ResourceListView.js.map +1 -1
- package/library/useDetectSkillPackage.d.ts +1 -1
- package/library/useDetectSkillPackage.d.ts.map +1 -1
- package/mcp-server/McpServerPicker.js +1 -1
- package/mcp-server/McpServerPicker.js.map +1 -1
- package/mcp-server/useMcpServer.d.ts +2 -0
- package/mcp-server/useMcpServer.d.ts.map +1 -1
- package/mcp-server/useMcpServer.js +13 -37
- package/mcp-server/useMcpServer.js.map +1 -1
- package/mcp-server/useMcpServerCount.d.ts +1 -1
- package/mcp-server/useMcpServerCount.d.ts.map +1 -1
- package/mcp-server/useMcpServerList.d.ts +2 -2
- package/mcp-server/useMcpServerList.d.ts.map +1 -1
- package/mcp-server/useOAuthGrantStatus.d.ts +2 -0
- package/mcp-server/useOAuthGrantStatus.d.ts.map +1 -1
- package/mcp-server/useOAuthGrantStatus.js +14 -61
- package/mcp-server/useOAuthGrantStatus.js.map +1 -1
- package/mcp-server/useOrgOAuthApp.d.ts +2 -0
- package/mcp-server/useOrgOAuthApp.d.ts.map +1 -1
- package/mcp-server/useOrgOAuthApp.js +19 -43
- package/mcp-server/useOrgOAuthApp.js.map +1 -1
- package/oauth-app/useOAuthAppList.d.ts +2 -0
- package/oauth-app/useOAuthAppList.d.ts.map +1 -1
- package/oauth-app/useOAuthAppList.js +6 -34
- package/oauth-app/useOAuthAppList.js.map +1 -1
- package/organization/useOrganization.d.ts +2 -0
- package/organization/useOrganization.d.ts.map +1 -1
- package/organization/useOrganization.js +3 -33
- package/organization/useOrganization.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/usePlatformClient.d.ts +2 -0
- package/platform-client/usePlatformClient.d.ts.map +1 -1
- package/platform-client/usePlatformClient.js +3 -33
- package/platform-client/usePlatformClient.js.map +1 -1
- package/platform-client/usePlatformClientList.d.ts +2 -0
- package/platform-client/usePlatformClientList.d.ts.map +1 -1
- package/platform-client/usePlatformClientList.js +6 -34
- package/platform-client/usePlatformClientList.js.map +1 -1
- package/runner/RunnerListPanel.d.ts.map +1 -1
- package/runner/RunnerListPanel.js +21 -5
- package/runner/RunnerListPanel.js.map +1 -1
- package/runner/__tests__/phase.test.d.ts +2 -0
- package/runner/__tests__/phase.test.d.ts.map +1 -0
- package/runner/__tests__/phase.test.js +33 -0
- package/runner/__tests__/phase.test.js.map +1 -0
- package/runner/__tests__/useRunnerList.test.d.ts +2 -0
- package/runner/__tests__/useRunnerList.test.d.ts.map +1 -0
- package/runner/__tests__/useRunnerList.test.js +68 -0
- package/runner/__tests__/useRunnerList.test.js.map +1 -0
- package/runner/index.d.ts +3 -1
- package/runner/index.d.ts.map +1 -1
- package/runner/index.js +2 -1
- package/runner/index.js.map +1 -1
- package/runner/phase.d.ts +13 -0
- package/runner/phase.d.ts.map +1 -1
- package/runner/phase.js +15 -0
- package/runner/phase.js.map +1 -1
- package/runner/useRunnerCredential.d.ts +66 -0
- package/runner/useRunnerCredential.d.ts.map +1 -0
- package/runner/useRunnerCredential.js +50 -0
- package/runner/useRunnerCredential.js.map +1 -0
- package/runner/useRunnerList.d.ts +21 -0
- package/runner/useRunnerList.d.ts.map +1 -1
- package/runner/useRunnerList.js +9 -36
- package/runner/useRunnerList.js.map +1 -1
- package/search/useResourceCount.d.ts +2 -1
- package/search/useResourceCount.d.ts.map +1 -1
- package/search/useResourceCount.js +13 -37
- package/search/useResourceCount.js.map +1 -1
- package/search/useResourceList.d.ts +2 -1
- package/search/useResourceList.d.ts.map +1 -1
- package/search/useResourceList.js +26 -46
- package/search/useResourceList.js.map +1 -1
- package/search/useResourceSearch.d.ts +4 -2
- package/search/useResourceSearch.d.ts.map +1 -1
- package/search/useResourceSearch.js +7 -27
- package/search/useResourceSearch.js.map +1 -1
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +26 -1
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSession.d.ts +3 -1
- package/session/useSession.d.ts.map +1 -1
- package/session/useSession.js +3 -33
- package/session/useSession.js.map +1 -1
- package/session/useSessionExecutions.d.ts +3 -1
- package/session/useSessionExecutions.d.ts.map +1 -1
- package/session/useSessionExecutions.js +6 -34
- package/session/useSessionExecutions.js.map +1 -1
- package/session/useSessionList.d.ts +5 -3
- package/session/useSessionList.d.ts.map +1 -1
- package/session/useSessionList.js +9 -31
- package/session/useSessionList.js.map +1 -1
- package/skill/SkillPicker.js +1 -1
- package/skill/SkillPicker.js.map +1 -1
- package/skill/useSkill.d.ts +2 -0
- package/skill/useSkill.d.ts.map +1 -1
- package/skill/useSkill.js +13 -37
- package/skill/useSkill.js.map +1 -1
- package/skill/useSkillCount.d.ts +1 -1
- package/skill/useSkillCount.d.ts.map +1 -1
- package/skill/useSkillList.d.ts +2 -2
- package/skill/useSkillList.d.ts.map +1 -1
- package/src/agent/AgentPicker.tsx +1 -1
- package/src/agent/__tests__/useDefaultAgent.test.tsx +308 -0
- package/src/agent/useAgent.ts +19 -41
- package/src/agent/useAgentCount.ts +1 -1
- package/src/agent/useAgentList.ts +2 -2
- package/src/agent/useDefaultAgent.ts +67 -35
- package/src/agent-instance/useAgentInstance.ts +13 -37
- package/src/agent-instance/useAgentInstanceList.ts +31 -47
- package/src/api-key/useApiKeyList.ts +9 -32
- package/src/composer/ComposerToolbar.tsx +1 -22
- package/src/composer/ContextChip.tsx +2 -1
- package/src/composer/SessionComposer.tsx +206 -5
- package/src/composer/icons.tsx +27 -0
- package/src/environment/useEnvironment.ts +13 -37
- package/src/environment/useEnvironmentList.ts +31 -58
- package/src/execution/ArtifactPreviewModal.tsx +2 -2
- package/src/execution/useArtifactContent.ts +48 -65
- package/src/iam-policy/usePrincipalsCount.ts +17 -53
- package/src/iam-policy/useResourceAccess.ts +18 -55
- package/src/identity-provider/useIdentityProvider.ts +9 -39
- package/src/identity-provider/useIdentityProviderList.ts +14 -40
- package/src/index.ts +4 -0
- package/src/internal/__tests__/useFetch.test.ts +133 -0
- package/src/internal/useFetch.ts +121 -0
- package/src/invitation/useInvitationPreview.ts +14 -40
- package/src/invitation/useOrgInvitations.ts +15 -41
- package/src/library/ResourceListView.tsx +3 -3
- package/src/library/useDetectSkillPackage.ts +1 -1
- package/src/mcp-server/McpServerPicker.tsx +1 -1
- package/src/mcp-server/useMcpServer.ts +17 -42
- package/src/mcp-server/useMcpServerCount.ts +1 -1
- package/src/mcp-server/useMcpServerList.ts +2 -2
- package/src/mcp-server/useOAuthGrantStatus.ts +31 -69
- package/src/mcp-server/useOrgOAuthApp.ts +34 -51
- package/src/oauth-app/useOAuthAppList.ts +15 -41
- package/src/organization/useOrganization.ts +9 -38
- package/src/platform-client/usePlatformClient.ts +9 -39
- package/src/platform-client/usePlatformClientList.ts +14 -42
- package/src/runner/RunnerListPanel.tsx +49 -41
- package/src/runner/__tests__/phase.test.ts +35 -0
- package/src/runner/__tests__/useRunnerList.test.tsx +96 -0
- package/src/runner/index.ts +7 -0
- package/src/runner/phase.ts +16 -0
- package/src/runner/useRunnerCredential.ts +89 -0
- package/src/runner/useRunnerList.ts +36 -44
- package/src/search/useResourceCount.ts +20 -48
- package/src/search/useResourceList.ts +40 -57
- package/src/search/useResourceSearch.ts +22 -43
- package/src/session/useNewSessionFlow.ts +35 -1
- package/src/session/useSession.ts +10 -39
- package/src/session/useSessionExecutions.ts +20 -46
- package/src/session/useSessionList.ts +21 -42
- package/src/skill/SkillPicker.tsx +1 -1
- package/src/skill/useSkill.ts +17 -42
- package/src/skill/useSkillCount.ts +1 -1
- package/src/skill/useSkillList.ts +2 -2
- package/src/usage/useOrgUsageReport.ts +18 -46
- package/styles.css +1 -1
- package/usage/useOrgUsageReport.d.ts +2 -0
- package/usage/useOrgUsageReport.d.ts.map +1 -1
- package/usage/useOrgUsageReport.js +5 -35
- package/usage/useOrgUsageReport.js.map +1 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
3
|
import { create } from "@bufbuild/protobuf";
|
|
5
4
|
import { GetPrincipalsCountInputSchema } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
|
|
6
5
|
import { useStigmer } from "../hooks";
|
|
7
|
-
import {
|
|
6
|
+
import { useFetch } from "../internal/useFetch";
|
|
8
7
|
|
|
9
8
|
/** Return value of {@link usePrincipalsCount}. */
|
|
10
9
|
export interface UsePrincipalsCountReturn {
|
|
@@ -12,6 +11,8 @@ export interface UsePrincipalsCountReturn {
|
|
|
12
11
|
readonly count: number;
|
|
13
12
|
/** `true` while the fetch is in flight. */
|
|
14
13
|
readonly isLoading: boolean;
|
|
14
|
+
/** `true` while a background refetch is in flight and stale data is shown. */
|
|
15
|
+
readonly isRefetching: boolean;
|
|
15
16
|
/** Error from the last failed request, or `null` when healthy. */
|
|
16
17
|
readonly error: Error | null;
|
|
17
18
|
/** Re-fetch the count from the server. */
|
|
@@ -41,56 +42,19 @@ export function usePrincipalsCount(
|
|
|
41
42
|
principalKind: string = "identity_account",
|
|
42
43
|
): UsePrincipalsCountReturn {
|
|
43
44
|
const stigmer = useStigmer();
|
|
44
|
-
const [count, setCount] = useState(0);
|
|
45
|
-
const [isLoading, setIsLoading] = useState(!!orgId);
|
|
46
|
-
const [error, setError] = useState<Error | null>(null);
|
|
47
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
48
45
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (!orgId) return;
|
|
67
|
-
|
|
68
|
-
const cancelled = { current: false };
|
|
69
|
-
|
|
70
|
-
stigmer.iamPolicy
|
|
71
|
-
.getPrincipalsCount(
|
|
72
|
-
create(GetPrincipalsCountInputSchema, {
|
|
73
|
-
orgId,
|
|
74
|
-
principalKind,
|
|
75
|
-
}),
|
|
76
|
-
)
|
|
77
|
-
.then(
|
|
78
|
-
(result) => {
|
|
79
|
-
if (cancelled.current) return;
|
|
80
|
-
setCount(result.count);
|
|
81
|
-
setIsLoading(false);
|
|
82
|
-
},
|
|
83
|
-
(err) => {
|
|
84
|
-
if (cancelled.current) return;
|
|
85
|
-
setError(toError(err));
|
|
86
|
-
setIsLoading(false);
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
return () => {
|
|
91
|
-
cancelled.current = true;
|
|
92
|
-
};
|
|
93
|
-
}, [orgId, principalKind, stigmer, fetchKey]);
|
|
94
|
-
|
|
95
|
-
return { count, isLoading, error, refetch };
|
|
46
|
+
const { data: count, isLoading, isRefetching, error, refetch } = useFetch(
|
|
47
|
+
orgId
|
|
48
|
+
? () =>
|
|
49
|
+
stigmer.iamPolicy
|
|
50
|
+
.getPrincipalsCount(
|
|
51
|
+
create(GetPrincipalsCountInputSchema, { orgId, principalKind }),
|
|
52
|
+
)
|
|
53
|
+
.then((r) => r.count)
|
|
54
|
+
: null,
|
|
55
|
+
[orgId, principalKind, stigmer],
|
|
56
|
+
0,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return { count, isLoading, isRefetching, error, refetch };
|
|
96
60
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
3
|
import { create } from "@bufbuild/protobuf";
|
|
5
4
|
import type { PrincipalAccess } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
|
|
6
5
|
import {
|
|
@@ -8,7 +7,7 @@ import {
|
|
|
8
7
|
} from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
|
|
9
8
|
import { ApiResourceRefSchema } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/spec_pb";
|
|
10
9
|
import { useStigmer } from "../hooks";
|
|
11
|
-
import {
|
|
10
|
+
import { useFetch } from "../internal/useFetch";
|
|
12
11
|
|
|
13
12
|
/** Resource reference for the access query. */
|
|
14
13
|
export interface ResourceAccessRef {
|
|
@@ -30,6 +29,8 @@ export interface UseResourceAccessReturn {
|
|
|
30
29
|
readonly members: readonly PrincipalAccess[];
|
|
31
30
|
/** `true` while the fetch is in flight. */
|
|
32
31
|
readonly isLoading: boolean;
|
|
32
|
+
/** `true` while a background refetch is in flight and stale data is shown. */
|
|
33
|
+
readonly isRefetching: boolean;
|
|
33
34
|
/** Error from the last failed request, or `null` when healthy. */
|
|
34
35
|
readonly error: Error | null;
|
|
35
36
|
/** Re-fetch the access list from the server. */
|
|
@@ -66,63 +67,25 @@ export function useResourceAccess(
|
|
|
66
67
|
options?: UseResourceAccessOptions,
|
|
67
68
|
): UseResourceAccessReturn {
|
|
68
69
|
const stigmer = useStigmer();
|
|
69
|
-
const [members, setMembers] = useState<PrincipalAccess[]>([]);
|
|
70
|
-
const [isLoading, setIsLoading] = useState(!!resource);
|
|
71
|
-
const [error, setError] = useState<Error | null>(null);
|
|
72
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
73
|
-
|
|
74
70
|
const kind = resource?.kind ?? null;
|
|
75
71
|
const id = resource?.id ?? null;
|
|
76
72
|
const includeInherited = options?.includeInherited ?? false;
|
|
77
73
|
|
|
78
|
-
const
|
|
79
|
-
kind && id
|
|
74
|
+
const { data: members, isLoading, isRefetching, error, refetch } = useFetch(
|
|
75
|
+
kind && id
|
|
76
|
+
? () => {
|
|
77
|
+
const input = create(ListResourceAccessInputSchema, {
|
|
78
|
+
resource: create(ApiResourceRefSchema, { kind, id }),
|
|
79
|
+
includeInherited,
|
|
80
|
+
});
|
|
81
|
+
return stigmer.iamPolicy
|
|
82
|
+
.listResourceAccessByPrincipal(input)
|
|
83
|
+
.then((r) => [...r.entries]);
|
|
84
|
+
}
|
|
85
|
+
: null,
|
|
86
|
+
[kind, id, includeInherited, stigmer],
|
|
87
|
+
[] as PrincipalAccess[],
|
|
80
88
|
);
|
|
81
|
-
const currentKey = kind && id ? `${kind}:${id}` : null;
|
|
82
|
-
if (currentKey !== prevKey) {
|
|
83
|
-
setPrevKey(currentKey);
|
|
84
|
-
if (currentKey) {
|
|
85
|
-
setIsLoading(true);
|
|
86
|
-
setMembers([]);
|
|
87
|
-
setError(null);
|
|
88
|
-
} else {
|
|
89
|
-
setIsLoading(false);
|
|
90
|
-
setMembers([]);
|
|
91
|
-
setError(null);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
|
|
96
|
-
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
if (!kind || !id) return;
|
|
99
|
-
|
|
100
|
-
const cancelled = { current: false };
|
|
101
|
-
|
|
102
|
-
const input = create(ListResourceAccessInputSchema, {
|
|
103
|
-
resource: create(ApiResourceRefSchema, { kind, id }),
|
|
104
|
-
includeInherited,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
stigmer.iamPolicy
|
|
108
|
-
.listResourceAccessByPrincipal(input)
|
|
109
|
-
.then(
|
|
110
|
-
(result) => {
|
|
111
|
-
if (cancelled.current) return;
|
|
112
|
-
setMembers([...result.entries]);
|
|
113
|
-
setIsLoading(false);
|
|
114
|
-
},
|
|
115
|
-
(err) => {
|
|
116
|
-
if (cancelled.current) return;
|
|
117
|
-
setError(toError(err));
|
|
118
|
-
setIsLoading(false);
|
|
119
|
-
},
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
return () => {
|
|
123
|
-
cancelled.current = true;
|
|
124
|
-
};
|
|
125
|
-
}, [kind, id, includeInherited, stigmer, fetchKey]);
|
|
126
89
|
|
|
127
|
-
return { members, isLoading, error, refetch };
|
|
90
|
+
return { members, isLoading, isRefetching, error, refetch };
|
|
128
91
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
3
|
import type { IdentityProvider } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
|
|
5
4
|
import { useStigmer } from "../hooks";
|
|
6
|
-
import {
|
|
5
|
+
import { useFetch } from "../internal/useFetch";
|
|
7
6
|
|
|
8
7
|
/** Return value of {@link useIdentityProvider}. */
|
|
9
8
|
export interface UseIdentityProviderReturn {
|
|
@@ -11,6 +10,8 @@ export interface UseIdentityProviderReturn {
|
|
|
11
10
|
readonly identityProvider: IdentityProvider | null;
|
|
12
11
|
/** `true` while the initial fetch or a refetch is in flight. */
|
|
13
12
|
readonly isLoading: boolean;
|
|
13
|
+
/** `true` while a background refetch is in flight and stale data is shown. */
|
|
14
|
+
readonly isRefetching: boolean;
|
|
14
15
|
/** Error from the last failed request, or `null` when healthy. */
|
|
15
16
|
readonly error: Error | null;
|
|
16
17
|
/** Discard cached data and re-fetch from the server. */
|
|
@@ -44,43 +45,12 @@ export function useIdentityProvider(
|
|
|
44
45
|
id: string | null,
|
|
45
46
|
): UseIdentityProviderReturn {
|
|
46
47
|
const stigmer = useStigmer();
|
|
47
|
-
const [identityProvider, setIdentityProvider] =
|
|
48
|
-
useState<IdentityProvider | null>(null);
|
|
49
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
50
|
-
const [error, setError] = useState<Error | null>(null);
|
|
51
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
52
48
|
|
|
53
|
-
const
|
|
49
|
+
const { data: identityProvider, isLoading, isRefetching, error, refetch } = useFetch(
|
|
50
|
+
id ? () => stigmer.identityProvider.get(id) : null,
|
|
51
|
+
[id, stigmer],
|
|
52
|
+
null as IdentityProvider | null,
|
|
53
|
+
);
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
if (!id) {
|
|
57
|
-
setIdentityProvider(null);
|
|
58
|
-
setIsLoading(false);
|
|
59
|
-
setError(null);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const cancelled = { current: false };
|
|
64
|
-
setIsLoading(true);
|
|
65
|
-
setError(null);
|
|
66
|
-
|
|
67
|
-
stigmer.identityProvider.get(id).then(
|
|
68
|
-
(result) => {
|
|
69
|
-
if (cancelled.current) return;
|
|
70
|
-
setIdentityProvider(result);
|
|
71
|
-
setIsLoading(false);
|
|
72
|
-
},
|
|
73
|
-
(err) => {
|
|
74
|
-
if (cancelled.current) return;
|
|
75
|
-
setError(toError(err));
|
|
76
|
-
setIsLoading(false);
|
|
77
|
-
},
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
return () => {
|
|
81
|
-
cancelled.current = true;
|
|
82
|
-
};
|
|
83
|
-
}, [id, stigmer, fetchKey]);
|
|
84
|
-
|
|
85
|
-
return { identityProvider, isLoading, error, refetch };
|
|
55
|
+
return { identityProvider, isLoading, isRefetching, error, refetch };
|
|
86
56
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
3
|
import { create } from "@bufbuild/protobuf";
|
|
5
4
|
import type { IdentityProvider } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
|
|
6
5
|
import { ListIdentityProvidersByOrgInputSchema } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/io_pb";
|
|
7
6
|
import { useStigmer } from "../hooks";
|
|
8
|
-
import {
|
|
7
|
+
import { useFetch } from "../internal/useFetch";
|
|
9
8
|
|
|
10
9
|
/** Return value of {@link useIdentityProviderList}. */
|
|
11
10
|
export interface UseIdentityProviderListReturn {
|
|
@@ -13,6 +12,8 @@ export interface UseIdentityProviderListReturn {
|
|
|
13
12
|
readonly identityProviders: readonly IdentityProvider[];
|
|
14
13
|
/** `true` while the initial fetch or a refetch is in flight. */
|
|
15
14
|
readonly isLoading: boolean;
|
|
15
|
+
/** `true` while a background refetch is in flight and stale data is shown. */
|
|
16
|
+
readonly isRefetching: boolean;
|
|
16
17
|
/** Error from the last failed request, or `null` when healthy. */
|
|
17
18
|
readonly error: Error | null;
|
|
18
19
|
/** Discard cached data and re-fetch from the server. */
|
|
@@ -57,44 +58,17 @@ export function useIdentityProviderList(
|
|
|
57
58
|
org: string | null,
|
|
58
59
|
): UseIdentityProviderListReturn {
|
|
59
60
|
const stigmer = useStigmer();
|
|
60
|
-
const [identityProviders, setIdentityProviders] = useState<
|
|
61
|
-
IdentityProvider[]
|
|
62
|
-
>([]);
|
|
63
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
64
|
-
const [error, setError] = useState<Error | null>(null);
|
|
65
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
66
61
|
|
|
67
|
-
const
|
|
62
|
+
const { data: identityProviders, isLoading, isRefetching, error, refetch } = useFetch(
|
|
63
|
+
org
|
|
64
|
+
? () =>
|
|
65
|
+
stigmer.identityProvider
|
|
66
|
+
.listByOrg(create(ListIdentityProvidersByOrgInputSchema, { org }))
|
|
67
|
+
.then((r) => [...r.entries])
|
|
68
|
+
: null,
|
|
69
|
+
[org, stigmer],
|
|
70
|
+
[] as IdentityProvider[],
|
|
71
|
+
);
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
if (!org) {
|
|
71
|
-
setIdentityProviders([]);
|
|
72
|
-
setIsLoading(false);
|
|
73
|
-
setError(null);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const cancelled = { current: false };
|
|
78
|
-
setIsLoading(true);
|
|
79
|
-
setError(null);
|
|
80
|
-
|
|
81
|
-
stigmer.identityProvider.listByOrg(create(ListIdentityProvidersByOrgInputSchema, { org })).then(
|
|
82
|
-
(result) => {
|
|
83
|
-
if (cancelled.current) return;
|
|
84
|
-
setIdentityProviders([...result.entries]);
|
|
85
|
-
setIsLoading(false);
|
|
86
|
-
},
|
|
87
|
-
(err) => {
|
|
88
|
-
if (cancelled.current) return;
|
|
89
|
-
setError(toError(err));
|
|
90
|
-
setIsLoading(false);
|
|
91
|
-
},
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
return () => {
|
|
95
|
-
cancelled.current = true;
|
|
96
|
-
};
|
|
97
|
-
}, [org, stigmer, fetchKey]);
|
|
98
|
-
|
|
99
|
-
return { identityProviders, isLoading, error, refetch };
|
|
73
|
+
return { identityProviders, isLoading, isRefetching, error, refetch };
|
|
100
74
|
}
|
package/src/index.ts
CHANGED
|
@@ -682,6 +682,7 @@ export type {
|
|
|
682
682
|
export {
|
|
683
683
|
useRunnerList,
|
|
684
684
|
useLaunchLocalRunner,
|
|
685
|
+
useRunnerCredential,
|
|
685
686
|
useStopRunner,
|
|
686
687
|
useDeleteRunner,
|
|
687
688
|
RunnerPicker,
|
|
@@ -689,6 +690,7 @@ export {
|
|
|
689
690
|
phaseLabel,
|
|
690
691
|
phaseDotColor,
|
|
691
692
|
isActivePhase,
|
|
693
|
+
isTransitionalPhase,
|
|
692
694
|
PHASE_SORT_ORDER,
|
|
693
695
|
} from "./runner";
|
|
694
696
|
export type {
|
|
@@ -697,6 +699,8 @@ export type {
|
|
|
697
699
|
UseLaunchLocalRunnerOptions,
|
|
698
700
|
UseLaunchLocalRunnerReturn,
|
|
699
701
|
LaunchLocalRunnerResult,
|
|
702
|
+
RunnerCredential,
|
|
703
|
+
UseRunnerCredentialReturn,
|
|
700
704
|
StopRunnerInput,
|
|
701
705
|
UseStopRunnerReturn,
|
|
702
706
|
UseDeleteRunnerReturn,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { renderHook, act } from "@testing-library/react";
|
|
3
|
+
import { useFetch } from "../useFetch";
|
|
4
|
+
|
|
5
|
+
async function flush(): Promise<void> {
|
|
6
|
+
await act(async () => {
|
|
7
|
+
await Promise.resolve();
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("useFetch — refetchInterval", () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.useFakeTimers();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.useRealTimers();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("polls at the specified interval", async () => {
|
|
21
|
+
let callCount = 0;
|
|
22
|
+
const fetchFn = vi.fn(async () => ++callCount);
|
|
23
|
+
|
|
24
|
+
const { result } = renderHook(() =>
|
|
25
|
+
useFetch(fetchFn, [], 0, { refetchInterval: 1000 }),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Flush the initial dep-change fetch.
|
|
29
|
+
await flush();
|
|
30
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
31
|
+
expect(result.current.data).toBe(1);
|
|
32
|
+
|
|
33
|
+
// Advance by one interval — should trigger a poll.
|
|
34
|
+
await act(async () => {
|
|
35
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
36
|
+
});
|
|
37
|
+
expect(fetchFn).toHaveBeenCalledTimes(2);
|
|
38
|
+
expect(result.current.data).toBe(2);
|
|
39
|
+
|
|
40
|
+
// Another interval tick.
|
|
41
|
+
await act(async () => {
|
|
42
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
43
|
+
});
|
|
44
|
+
expect(fetchFn).toHaveBeenCalledTimes(3);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("does not poll when refetchInterval is false", async () => {
|
|
48
|
+
const fetchFn = vi.fn(async () => "data");
|
|
49
|
+
|
|
50
|
+
renderHook(() => useFetch(fetchFn, [], "", { refetchInterval: false }));
|
|
51
|
+
|
|
52
|
+
await flush();
|
|
53
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
54
|
+
|
|
55
|
+
await act(async () => {
|
|
56
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
57
|
+
});
|
|
58
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("does not poll when fetchFn is null", async () => {
|
|
62
|
+
const { result } = renderHook(() =>
|
|
63
|
+
useFetch(null, [], "init", { refetchInterval: 1000 }),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
await act(async () => {
|
|
67
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(result.current.data).toBe("init");
|
|
71
|
+
expect(result.current.isLoading).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("cleans up interval on unmount", async () => {
|
|
75
|
+
const fetchFn = vi.fn(async () => "data");
|
|
76
|
+
|
|
77
|
+
const { unmount } = renderHook(() =>
|
|
78
|
+
useFetch(fetchFn, [], "", { refetchInterval: 1000 }),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
await flush();
|
|
82
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
83
|
+
|
|
84
|
+
unmount();
|
|
85
|
+
|
|
86
|
+
await act(async () => {
|
|
87
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
88
|
+
});
|
|
89
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("skips poll tick while a fetch is in flight", async () => {
|
|
93
|
+
let resolveInflight: ((v: string) => void) | null = null;
|
|
94
|
+
|
|
95
|
+
const fetchFn = vi.fn(async () => "first");
|
|
96
|
+
|
|
97
|
+
const { result } = renderHook(() =>
|
|
98
|
+
useFetch(fetchFn, [], "", { refetchInterval: 500 }),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Initial fetch resolves immediately.
|
|
102
|
+
await flush();
|
|
103
|
+
expect(result.current.data).toBe("first");
|
|
104
|
+
expect(fetchFn).toHaveBeenCalledTimes(1);
|
|
105
|
+
|
|
106
|
+
// Make the next fetch hang until manually resolved.
|
|
107
|
+
fetchFn.mockImplementation(
|
|
108
|
+
() =>
|
|
109
|
+
new Promise<string>((resolve) => {
|
|
110
|
+
resolveInflight = resolve;
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// First interval tick triggers a new fetch that hangs.
|
|
115
|
+
await act(async () => {
|
|
116
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
117
|
+
});
|
|
118
|
+
expect(fetchFn).toHaveBeenCalledTimes(2);
|
|
119
|
+
|
|
120
|
+
// Another tick fires but fetch is still in flight — should be skipped.
|
|
121
|
+
await act(async () => {
|
|
122
|
+
await vi.advanceTimersByTimeAsync(500);
|
|
123
|
+
});
|
|
124
|
+
expect(fetchFn).toHaveBeenCalledTimes(2);
|
|
125
|
+
|
|
126
|
+
// Resolve the in-flight fetch.
|
|
127
|
+
await act(async () => {
|
|
128
|
+
resolveInflight!("second");
|
|
129
|
+
await Promise.resolve();
|
|
130
|
+
});
|
|
131
|
+
expect(result.current.data).toBe("second");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type DependencyList, useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { toError } from "./toError";
|
|
5
|
+
|
|
6
|
+
/** Options for {@link useFetch}. */
|
|
7
|
+
export interface UseFetchOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Poll interval in milliseconds. When set to a positive number, the
|
|
10
|
+
* hook re-fetches on a timer. Set to `false` or `0` to disable.
|
|
11
|
+
*
|
|
12
|
+
* The timer is paused while a fetch is already in flight to prevent
|
|
13
|
+
* request piling on slow connections.
|
|
14
|
+
*/
|
|
15
|
+
readonly refetchInterval?: number | false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Return value of {@link useFetch}. */
|
|
19
|
+
export interface UseFetchReturn<T> {
|
|
20
|
+
/** The most recently resolved data, or `initialData` before the first success. */
|
|
21
|
+
readonly data: T;
|
|
22
|
+
/**
|
|
23
|
+
* `true` only when no data has been fetched yet (first load).
|
|
24
|
+
* Once data arrives, subsequent refetches keep this `false`.
|
|
25
|
+
*/
|
|
26
|
+
readonly isLoading: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* `true` while a background refetch is in flight and stale data is
|
|
29
|
+
* being shown. Always `false` during the initial load.
|
|
30
|
+
*/
|
|
31
|
+
readonly isRefetching: boolean;
|
|
32
|
+
/** Error from the last failed request, or `null` when healthy. */
|
|
33
|
+
readonly error: Error | null;
|
|
34
|
+
/** Imperatively trigger a re-fetch. Stale data remains visible. */
|
|
35
|
+
readonly refetch: () => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generic data-fetching hook with stale-while-revalidate semantics.
|
|
40
|
+
*
|
|
41
|
+
* - Pass `null` for `fetchFn` to disable fetching (idle state).
|
|
42
|
+
* - On the **first** fetch, `isLoading` is `true` so consumers can
|
|
43
|
+
* show a skeleton.
|
|
44
|
+
* - On **subsequent** fetches (refetch or dep change after first success),
|
|
45
|
+
* `isLoading` stays `false` and `isRefetching` becomes `true` —
|
|
46
|
+
* existing data remains visible, preventing skeleton flash.
|
|
47
|
+
* - On error during a refetch, stale data is preserved.
|
|
48
|
+
*
|
|
49
|
+
* @param fetchFn Async function that returns data, or `null` to skip.
|
|
50
|
+
* @param deps Dependency list — a new fetch fires when any dep changes.
|
|
51
|
+
* @param initialData Value returned before the first successful fetch.
|
|
52
|
+
* @param options Optional configuration (e.g. polling interval).
|
|
53
|
+
*
|
|
54
|
+
* @internal Not part of the public `@stigmer/react` API.
|
|
55
|
+
*/
|
|
56
|
+
export function useFetch<T>(
|
|
57
|
+
fetchFn: (() => Promise<T>) | null,
|
|
58
|
+
deps: DependencyList,
|
|
59
|
+
initialData: T,
|
|
60
|
+
options?: UseFetchOptions,
|
|
61
|
+
): UseFetchReturn<T> {
|
|
62
|
+
const [data, setData] = useState<T>(initialData);
|
|
63
|
+
const [error, setError] = useState<Error | null>(null);
|
|
64
|
+
const [fetchKey, setFetchKey] = useState(0);
|
|
65
|
+
|
|
66
|
+
const hasDataRef = useRef(false);
|
|
67
|
+
const isFetchingRef = useRef(false);
|
|
68
|
+
const [isFetching, setIsFetching] = useState(false);
|
|
69
|
+
|
|
70
|
+
const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!fetchFn) {
|
|
74
|
+
setData(initialData);
|
|
75
|
+
setIsFetching(false);
|
|
76
|
+
isFetchingRef.current = false;
|
|
77
|
+
setError(null);
|
|
78
|
+
hasDataRef.current = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const cancelled = { current: false };
|
|
83
|
+
setIsFetching(true);
|
|
84
|
+
isFetchingRef.current = true;
|
|
85
|
+
setError(null);
|
|
86
|
+
|
|
87
|
+
fetchFn().then(
|
|
88
|
+
(result) => {
|
|
89
|
+
if (cancelled.current) return;
|
|
90
|
+
setData(result);
|
|
91
|
+
hasDataRef.current = true;
|
|
92
|
+
setIsFetching(false);
|
|
93
|
+
isFetchingRef.current = false;
|
|
94
|
+
},
|
|
95
|
+
(err) => {
|
|
96
|
+
if (cancelled.current) return;
|
|
97
|
+
setError(toError(err));
|
|
98
|
+
setIsFetching(false);
|
|
99
|
+
isFetchingRef.current = false;
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return () => {
|
|
104
|
+
cancelled.current = true;
|
|
105
|
+
};
|
|
106
|
+
}, [...deps, fetchKey]);
|
|
107
|
+
|
|
108
|
+
const refetchInterval = options?.refetchInterval;
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!refetchInterval || refetchInterval <= 0 || !fetchFn) return;
|
|
111
|
+
const id = setInterval(() => {
|
|
112
|
+
if (!isFetchingRef.current) refetch();
|
|
113
|
+
}, refetchInterval);
|
|
114
|
+
return () => clearInterval(id);
|
|
115
|
+
}, [refetchInterval, fetchFn, refetch]);
|
|
116
|
+
|
|
117
|
+
const isLoading = isFetching && !hasDataRef.current;
|
|
118
|
+
const isRefetching = isFetching && hasDataRef.current;
|
|
119
|
+
|
|
120
|
+
return { data, isLoading, isRefetching, error, refetch };
|
|
121
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
4
3
|
import { create } from "@bufbuild/protobuf";
|
|
5
4
|
import type { InvitationPreview } from "@stigmer/protos/ai/stigmer/iam/invitation/v1/io_pb";
|
|
6
5
|
import { InvitationTokenInputSchema } from "@stigmer/protos/ai/stigmer/iam/invitation/v1/io_pb";
|
|
7
6
|
import { useStigmer } from "../hooks";
|
|
8
|
-
import {
|
|
7
|
+
import { useFetch } from "../internal/useFetch";
|
|
9
8
|
|
|
10
9
|
/** Return value of {@link useInvitationPreview}. */
|
|
11
10
|
export interface UseInvitationPreviewReturn {
|
|
@@ -13,6 +12,8 @@ export interface UseInvitationPreviewReturn {
|
|
|
13
12
|
readonly preview: InvitationPreview | null;
|
|
14
13
|
/** `true` while the initial fetch or a refetch is in flight. */
|
|
15
14
|
readonly isLoading: boolean;
|
|
15
|
+
/** `true` while a background refetch is in flight and stale data is shown. */
|
|
16
|
+
readonly isRefetching: boolean;
|
|
16
17
|
/** Error from the last failed request, or `null` when healthy. */
|
|
17
18
|
readonly error: Error | null;
|
|
18
19
|
/** Discard cached data and re-fetch the preview from the server. */
|
|
@@ -60,44 +61,17 @@ export function useInvitationPreview(
|
|
|
60
61
|
token: string | null,
|
|
61
62
|
): UseInvitationPreviewReturn {
|
|
62
63
|
const stigmer = useStigmer();
|
|
63
|
-
const [preview, setPreview] = useState<InvitationPreview | null>(null);
|
|
64
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
65
|
-
const [error, setError] = useState<Error | null>(null);
|
|
66
|
-
const [fetchKey, setFetchKey] = useState(0);
|
|
67
64
|
|
|
68
|
-
const
|
|
65
|
+
const { data: preview, isLoading, isRefetching, error, refetch } = useFetch(
|
|
66
|
+
token
|
|
67
|
+
? () =>
|
|
68
|
+
stigmer.invitation.getByToken(
|
|
69
|
+
create(InvitationTokenInputSchema, { token }),
|
|
70
|
+
)
|
|
71
|
+
: null,
|
|
72
|
+
[token, stigmer],
|
|
73
|
+
null as InvitationPreview | null,
|
|
74
|
+
);
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
if (!token) {
|
|
72
|
-
setPreview(null);
|
|
73
|
-
setIsLoading(false);
|
|
74
|
-
setError(null);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const cancelled = { current: false };
|
|
79
|
-
setIsLoading(true);
|
|
80
|
-
setError(null);
|
|
81
|
-
|
|
82
|
-
stigmer.invitation
|
|
83
|
-
.getByToken(create(InvitationTokenInputSchema, { token }))
|
|
84
|
-
.then(
|
|
85
|
-
(result) => {
|
|
86
|
-
if (cancelled.current) return;
|
|
87
|
-
setPreview(result);
|
|
88
|
-
setIsLoading(false);
|
|
89
|
-
},
|
|
90
|
-
(err) => {
|
|
91
|
-
if (cancelled.current) return;
|
|
92
|
-
setError(toError(err));
|
|
93
|
-
setIsLoading(false);
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
return () => {
|
|
98
|
-
cancelled.current = true;
|
|
99
|
-
};
|
|
100
|
-
}, [token, stigmer, fetchKey]);
|
|
101
|
-
|
|
102
|
-
return { preview, isLoading, error, refetch };
|
|
76
|
+
return { preview, isLoading, isRefetching, error, refetch };
|
|
103
77
|
}
|