Skip to content

Commit ff69c0e

Browse files
refactor: Refactor auth provider (coder#5782)
1 parent a0a959c commit ff69c0e

39 files changed

+519
-547
lines changed

site/src/AppRouter.tsx

Lines changed: 90 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { useSelector } from "@xstate/react"
21
import { FullScreenLoader } from "components/Loader/FullScreenLoader"
3-
import { RequirePermission } from "components/RequirePermission/RequirePermission"
42
import { TemplateLayout } from "components/TemplateLayout/TemplateLayout"
53
import { UsersLayout } from "components/UsersLayout/UsersLayout"
64
import IndexPage from "pages"
@@ -12,12 +10,9 @@ import { TemplateSettingsPage } from "pages/TemplateSettingsPage/TemplateSetting
1210
import TemplatesPage from "pages/TemplatesPage/TemplatesPage"
1311
import UsersPage from "pages/UsersPage/UsersPage"
1412
import WorkspacesPage from "pages/WorkspacesPage/WorkspacesPage"
15-
import { FC, lazy, Suspense, useContext } from "react"
16-
import { Route, Routes } from "react-router-dom"
17-
import { selectPermissions } from "xServices/auth/authSelectors"
18-
import { selectFeatureVisibility } from "xServices/entitlements/entitlementsSelectors"
19-
import { XServiceContext } from "xServices/StateContext"
20-
import { DashboardLayout } from "./components/DashboardLayout/DashboardLayout"
13+
import { FC, lazy, Suspense } from "react"
14+
import { Route, Routes, BrowserRouter as Router } from "react-router-dom"
15+
import { DashboardLayout } from "./components/Dashboard/DashboardLayout"
2116
import { RequireAuth } from "./components/RequireAuth/RequireAuth"
2217
import { SettingsLayout } from "./components/SettingsLayout/SettingsLayout"
2318
import { DeploySettingsLayout } from "components/DeploySettingsLayout/DeploySettingsLayout"
@@ -123,135 +118,119 @@ const CreateTemplatePage = lazy(
123118
)
124119

125120
export const AppRouter: FC = () => {
126-
const xServices = useContext(XServiceContext)
127-
const permissions = useSelector(xServices.authXService, selectPermissions)
128-
const featureVisibility = useSelector(
129-
xServices.entitlementsXService,
130-
selectFeatureVisibility,
131-
)
132-
133121
return (
134122
<Suspense fallback={<FullScreenLoader />}>
135-
<Routes>
136-
<Route path="login" element={<LoginPage />} />
137-
<Route path="setup" element={<SetupPage />} />
123+
<Router>
124+
<Routes>
125+
<Route path="login" element={<LoginPage />} />
126+
<Route path="setup" element={<SetupPage />} />
138127

139-
{/* Dashboard routes */}
140-
<Route element={<RequireAuth />}>
141-
<Route element={<DashboardLayout />}>
142-
<Route index element={<IndexPage />} />
128+
{/* Dashboard routes */}
129+
<Route element={<RequireAuth />}>
130+
<Route element={<DashboardLayout />}>
131+
<Route index element={<IndexPage />} />
143132

144-
<Route path="gitauth" element={<GitAuthPage />} />
133+
<Route path="gitauth" element={<GitAuthPage />} />
145134

146-
<Route path="workspaces" element={<WorkspacesPage />} />
135+
<Route path="workspaces" element={<WorkspacesPage />} />
147136

148-
<Route path="starter-templates">
149-
<Route index element={<StarterTemplatesPage />} />
150-
<Route path=":exampleId" element={<StarterTemplatePage />} />
151-
</Route>
137+
<Route path="starter-templates">
138+
<Route index element={<StarterTemplatesPage />} />
139+
<Route path=":exampleId" element={<StarterTemplatePage />} />
140+
</Route>
152141

153-
<Route path="templates">
154-
<Route index element={<TemplatesPage />} />
155-
<Route path="new" element={<CreateTemplatePage />} />
156-
<Route path=":template">
157-
<Route element={<TemplateLayout />}>
158-
<Route index element={<TemplateSummaryPage />} />
159-
<Route
160-
path="permissions"
161-
element={<TemplatePermissionsPage />}
162-
/>
142+
<Route path="templates">
143+
<Route index element={<TemplatesPage />} />
144+
<Route path="new" element={<CreateTemplatePage />} />
145+
<Route path=":template">
146+
<Route element={<TemplateLayout />}>
147+
<Route index element={<TemplateSummaryPage />} />
148+
<Route
149+
path="permissions"
150+
element={<TemplatePermissionsPage />}
151+
/>
152+
</Route>
153+
154+
<Route path="workspace" element={<CreateWorkspacePage />} />
155+
<Route path="settings" element={<TemplateSettingsPage />} />
156+
<Route path="versions">
157+
<Route path=":version" element={<TemplateVersionPage />} />
158+
</Route>
163159
</Route>
160+
</Route>
164161

165-
<Route path="workspace" element={<CreateWorkspacePage />} />
166-
<Route path="settings" element={<TemplateSettingsPage />} />
167-
<Route path="versions">
168-
<Route path=":version" element={<TemplateVersionPage />} />
162+
<Route path="users">
163+
<Route element={<UsersLayout />}>
164+
<Route index element={<UsersPage />} />
169165
</Route>
170-
</Route>
171-
</Route>
172166

173-
<Route path="users">
174-
<Route element={<UsersLayout />}>
175-
<Route index element={<UsersPage />} />
167+
<Route path="create" element={<CreateUserPage />} />
176168
</Route>
177169

178-
<Route path="create" element={<CreateUserPage />} />
179-
</Route>
170+
<Route path="/groups">
171+
<Route element={<UsersLayout />}>
172+
<Route index element={<GroupsPage />} />
173+
</Route>
180174

181-
<Route path="/groups">
182-
<Route element={<UsersLayout />}>
183-
<Route index element={<GroupsPage />} />
175+
<Route path="create" element={<CreateGroupPage />} />
176+
<Route path=":groupId" element={<GroupPage />} />
177+
<Route
178+
path=":groupId/settings"
179+
element={<SettingsGroupPage />}
180+
/>
184181
</Route>
185182

186-
<Route path="create" element={<CreateGroupPage />} />
187-
<Route path=":groupId" element={<GroupPage />} />
188-
<Route path=":groupId/settings" element={<SettingsGroupPage />} />
189-
</Route>
183+
<Route path="/audit" element={<AuditPage />} />
190184

191-
<Route path="/audit">
192185
<Route
193-
index
194-
element={
195-
<RequirePermission
196-
isFeatureVisible={
197-
featureVisibility["audit_log"] &&
198-
Boolean(permissions?.viewAuditLog)
199-
}
200-
>
201-
<AuditPage />
202-
</RequirePermission>
203-
}
204-
/>
205-
</Route>
206-
207-
<Route
208-
path="/settings/deployment"
209-
element={<DeploySettingsLayout />}
210-
>
211-
<Route path="general" element={<GeneralSettingsPage />} />
212-
<Route path="security" element={<SecuritySettingsPage />} />
213-
<Route path="appearance" element={<AppearanceSettingsPage />} />
214-
<Route path="network" element={<NetworkSettingsPage />} />
215-
<Route path="userauth" element={<UserAuthSettingsPage />} />
216-
<Route path="gitauth" element={<GitAuthSettingsPage />} />
217-
</Route>
186+
path="/settings/deployment"
187+
element={<DeploySettingsLayout />}
188+
>
189+
<Route path="general" element={<GeneralSettingsPage />} />
190+
<Route path="security" element={<SecuritySettingsPage />} />
191+
<Route path="appearance" element={<AppearanceSettingsPage />} />
192+
<Route path="network" element={<NetworkSettingsPage />} />
193+
<Route path="userauth" element={<UserAuthSettingsPage />} />
194+
<Route path="gitauth" element={<GitAuthSettingsPage />} />
195+
</Route>
218196

219-
<Route path="settings" element={<SettingsLayout />}>
220-
<Route path="account" element={<AccountPage />} />
221-
<Route path="security" element={<SecurityPage />} />
222-
<Route path="ssh-keys" element={<SSHKeysPage />} />
223-
<Route path="tokens" element={<TokensPage />} />
224-
</Route>
197+
<Route path="settings" element={<SettingsLayout />}>
198+
<Route path="account" element={<AccountPage />} />
199+
<Route path="security" element={<SecurityPage />} />
200+
<Route path="ssh-keys" element={<SSHKeysPage />} />
201+
<Route path="tokens" element={<TokensPage />} />
202+
</Route>
225203

226-
<Route path="/@:username">
227-
<Route path=":workspace">
228-
<Route index element={<WorkspacePage />} />
229-
<Route path="schedule" element={<WorkspaceSchedulePage />} />
230-
<Route
231-
path="builds/:buildNumber"
232-
element={<WorkspaceBuildPage />}
233-
/>
234-
<Route
235-
path="change-version"
236-
element={<WorkspaceChangeVersionPage />}
237-
/>
204+
<Route path="/@:username">
205+
<Route path=":workspace">
206+
<Route index element={<WorkspacePage />} />
207+
<Route path="schedule" element={<WorkspaceSchedulePage />} />
208+
<Route
209+
path="builds/:buildNumber"
210+
element={<WorkspaceBuildPage />}
211+
/>
212+
<Route
213+
path="change-version"
214+
element={<WorkspaceChangeVersionPage />}
215+
/>
216+
</Route>
238217
</Route>
239218
</Route>
240-
</Route>
241219

242-
{/* Terminal and CLI auth pages don't have the dashboard layout */}
243-
<Route
244-
path="/@:username/:workspace/terminal"
245-
element={<TerminalPage />}
246-
/>
247-
<Route path="cli-auth" element={<CliAuthenticationPage />} />
248-
</Route>
220+
{/* Terminal and CLI auth pages don't have the dashboard layout */}
221+
<Route
222+
path="/@:username/:workspace/terminal"
223+
element={<TerminalPage />}
224+
/>
225+
<Route path="cli-auth" element={<CliAuthenticationPage />} />
226+
</Route>
249227

250-
{/* Using path="*"" means "match anything", so this route
228+
{/* Using path="*"" means "match anything", so this route
251229
acts like a catch-all for URLs that we don't have explicit
252230
routes for. */}
253-
<Route path="*" element={<NotFoundPage />} />
254-
</Routes>
231+
<Route path="*" element={<NotFoundPage />} />
232+
</Routes>
233+
</Router>
255234
</Suspense>
256235
)
257236
}

site/src/api/api.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,6 @@ export const withDefaultFeatures = (
3434
return fs as TypesGen.Entitlements["features"]
3535
}
3636

37-
// defaultEntitlements has a default set of disabled functionality.
38-
export const defaultEntitlements = (): TypesGen.Entitlements => {
39-
return {
40-
features: withDefaultFeatures({}),
41-
has_license: false,
42-
errors: [],
43-
warnings: [],
44-
experimental: false,
45-
trial: false,
46-
}
47-
}
48-
4937
// Always attach CSRF token to all requests.
5038
// In puppeteer the document is undefined. In those cases, just
5139
// do nothing.
@@ -625,15 +613,8 @@ export const putWorkspaceExtension = async (
625613
}
626614

627615
export const getEntitlements = async (): Promise<TypesGen.Entitlements> => {
628-
try {
629-
const response = await axios.get("/api/v2/entitlements")
630-
return response.data
631-
} catch (error) {
632-
if (axios.isAxiosError(error) && error.response?.status === 404) {
633-
return defaultEntitlements()
634-
}
635-
throw error
636-
}
616+
const response = await axios.get("/api/v2/entitlements")
617+
return response.data
637618
}
638619

639620
export const getExperiments = async (): Promise<TypesGen.Experiment[]> => {

site/src/app.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import CssBaseline from "@material-ui/core/CssBaseline"
22
import ThemeProvider from "@material-ui/styles/ThemeProvider"
3+
import { AuthProvider } from "components/AuthProvider/AuthProvider"
34
import { FC } from "react"
45
import { HelmetProvider } from "react-helmet-async"
5-
import { BrowserRouter as Router } from "react-router-dom"
66
import { AppRouter } from "./AppRouter"
77
import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary"
88
import { GlobalSnackbar } from "./components/GlobalSnackbar/GlobalSnackbar"
99
import { dark } from "./theme"
1010
import "./theme/globalFonts"
11-
import { XServiceProvider } from "./xServices/StateContext"
1211

1312
export const App: FC = () => {
1413
return (
15-
<Router>
16-
<HelmetProvider>
17-
<ThemeProvider theme={dark}>
18-
<CssBaseline />
19-
<ErrorBoundary>
20-
<XServiceProvider>
21-
<AppRouter />
22-
<GlobalSnackbar />
23-
</XServiceProvider>
24-
</ErrorBoundary>
25-
</ThemeProvider>
26-
</HelmetProvider>
27-
</Router>
14+
<HelmetProvider>
15+
<ThemeProvider theme={dark}>
16+
<CssBaseline />
17+
<ErrorBoundary>
18+
<AuthProvider>
19+
<AppRouter />
20+
<GlobalSnackbar />
21+
</AuthProvider>
22+
</ErrorBoundary>
23+
</ThemeProvider>
24+
</HelmetProvider>
2825
)
2926
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useActor, useInterpret } from "@xstate/react"
2+
import { createContext, FC, PropsWithChildren, useContext } from "react"
3+
import { authMachine } from "xServices/auth/authXService"
4+
import { ActorRefFrom } from "xstate"
5+
6+
interface AuthContextValue {
7+
authService: ActorRefFrom<typeof authMachine>
8+
}
9+
10+
const AuthContext = createContext<AuthContextValue | undefined>(undefined)
11+
12+
export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
13+
const authService = useInterpret(authMachine)
14+
15+
return (
16+
<AuthContext.Provider value={{ authService }}>
17+
{children}
18+
</AuthContext.Provider>
19+
)
20+
}
21+
22+
type UseAuthReturnType = ReturnType<
23+
typeof useActor<AuthContextValue["authService"]>
24+
>
25+
26+
export const useAuth = (): UseAuthReturnType => {
27+
const context = useContext(AuthContext)
28+
29+
if (!context) {
30+
throw new Error("useAuth should be used inside of <AuthProvider />")
31+
}
32+
33+
const auth = useActor(context.authService)
34+
35+
return auth
36+
}

site/src/components/DashboardLayout/DashboardLayout.tsx renamed to site/src/components/Dashboard/DashboardLayout.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ServiceBanner } from "components/ServiceBanner/ServiceBanner"
1111
import { updateCheckMachine } from "xServices/updateCheck/updateCheckXService"
1212
import { usePermissions } from "hooks/usePermissions"
1313
import { UpdateCheckResponse } from "api/typesGenerated"
14+
import { DashboardProvider } from "./DashboardProvider"
1415

1516
export const DashboardLayout: FC = () => {
1617
const styles = useStyles()
@@ -23,7 +24,7 @@ export const DashboardLayout: FC = () => {
2324
const { error: updateCheckError, updateCheck } = updateCheckState.context
2425

2526
return (
26-
<>
27+
<DashboardProvider>
2728
<ServiceBanner />
2829
<LicenseBanner />
2930

@@ -50,7 +51,7 @@ export const DashboardLayout: FC = () => {
5051
</Suspense>
5152
</div>
5253
</div>
53-
</>
54+
</DashboardProvider>
5455
)
5556
}
5657

0 commit comments

Comments
 (0)