-
Notifications
You must be signed in to change notification settings - Fork 231
Expand file tree
/
Copy pathworkspace-provider.tsx
More file actions
122 lines (108 loc) · 4.25 KB
/
workspace-provider.tsx
File metadata and controls
122 lines (108 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { useQuery } from '@connectrpc/connect-query';
import { getWorkspace } from '@wundergraph/cosmo-connect/dist/platform/v1/platform-PlatformService_connectquery';
import { createContext, useCallback, useEffect, useMemo, useState } from 'react';
import { WorkspaceNamespace } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
import { useRouter } from 'next/router';
import { useApplyParams } from '@/components/analytics/use-apply-params';
import { useLocalStorage } from '@/hooks/use-local-storage';
import { useOnboardingNavigation } from '@/hooks/use-onboarding-navigation';
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
const DEFAULT_NAMESPACE_NAME = 'default';
export interface WorkspaceContextType {
isLoading: boolean;
namespace: WorkspaceNamespace;
namespaceByName: ReadonlyMap<string, WorkspaceNamespace>;
setNamespace(namespace: string, applyParams: boolean): void;
}
export const WorkspaceContext = createContext<WorkspaceContextType | null>(null);
export function WorkspaceProvider({ children }: React.PropsWithChildren) {
const router = useRouter();
const applyParams = useApplyParams();
const { data, isLoading } = useQuery(getWorkspace, {});
// Initialize the namespace
const namespaceParam = router.query.namespace as string;
const [storedNamespace, setStoredNamespace] = useLocalStorage('wg-namespace', DEFAULT_NAMESPACE_NAME);
const [namespace, setNamespace] = useState(namespaceParam || storedNamespace || DEFAULT_NAMESPACE_NAME);
const [namespaces, setNamespaces] = useState([DEFAULT_NAMESPACE_NAME]);
// Correct namespace
useEffect(() => {
if (data?.response?.code !== EnumStatusCode.OK || !data?.namespaces?.length) {
return;
}
const actualNamespace = (router.query.namespace as string) || namespace;
const currentNamespaces = data.namespaces.map((wns) => wns.name);
if (!currentNamespaces.some((ns) => ns.toLowerCase() === actualNamespace.toLowerCase())) {
// The authenticated user doesn't have access to the namespace, pick between the `default` or the
// first available namespace if the user doesn't have access to the `default` namespace
const ns = currentNamespaces.find((n) => n === DEFAULT_NAMESPACE_NAME) || currentNamespaces[0];
if (ns) {
// Only apply the namespace parameter when we found a valid namespace
setNamespace(ns);
setStoredNamespace(ns);
applyParams({
namespace: ns,
});
}
} else if (actualNamespace.toLowerCase() !== namespace.toLowerCase()) {
setNamespace(actualNamespace);
setStoredNamespace(actualNamespace);
}
setNamespaces(currentNamespaces);
}, [
applyParams,
data?.response?.code,
data?.namespaces,
router.query.namespace,
namespace,
namespaceParam,
setStoredNamespace,
]);
// Memoize context components
const currentNamespace = useMemo(
() =>
isLoading
? new WorkspaceNamespace({ id: '', name: namespace, graphs: [] })
: (data?.namespaces.find((wns) => wns.name.toLowerCase() === namespace.toLowerCase()) ??
new WorkspaceNamespace({
id: '',
name: DEFAULT_NAMESPACE_NAME,
graphs: [],
})),
[isLoading, data?.namespaces, namespace],
);
const namespaceByName = useMemo(
() =>
data?.namespaces.reduce((acc, wns) => {
acc.set(wns.name, wns);
return acc;
}, new Map<string, WorkspaceNamespace>()) ?? new Map<string, WorkspaceNamespace>(),
[data?.namespaces],
);
const setNamespaceCallback = useCallback(
(newNs: string, applyRouteParams: boolean) => {
if (!newNs || namespace === newNs || !namespaces.some((ns) => ns.toLowerCase() === newNs.toLowerCase())) {
return;
}
setNamespace(newNs);
setStoredNamespace(newNs);
if (applyRouteParams) {
applyParams({ namespace: newNs });
}
},
[namespace, namespaces, setStoredNamespace, applyParams],
);
useOnboardingNavigation();
// Finally, render :)
return (
<WorkspaceContext.Provider
value={{
isLoading,
namespace: currentNamespace,
namespaceByName,
setNamespace: setNamespaceCallback,
}}
>
{children}
</WorkspaceContext.Provider>
);
}