Skip to content

Commit b83f9c2

Browse files
committed
refactor auth provider
1 parent 47c3d72 commit b83f9c2

File tree

16 files changed

+78
-79
lines changed

16 files changed

+78
-79
lines changed

site/src/AppRouter.tsx

Lines changed: 2 additions & 28 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,11 +10,8 @@ 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"
13+
import { FC, lazy, Suspense } from "react"
1614
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"
2015
import { DashboardLayout } from "./components/DashboardLayout/DashboardLayout"
2116
import { RequireAuth } from "./components/RequireAuth/RequireAuth"
2217
import { SettingsLayout } from "./components/SettingsLayout/SettingsLayout"
@@ -123,13 +118,6 @@ 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 />}>
135123
<Routes>
@@ -188,21 +176,7 @@ export const AppRouter: FC = () => {
188176
<Route path=":groupId/settings" element={<SettingsGroupPage />} />
189177
</Route>
190178

191-
<Route path="/audit">
192-
<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>
179+
<Route path="/audit" element={<AuditPage />} />
206180

207181
<Route
208182
path="/settings/deployment"

site/src/app.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
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"
56
import { BrowserRouter as Router } from "react-router-dom"
@@ -8,7 +9,6 @@ import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary"
89
import { GlobalSnackbar } from "./components/GlobalSnackbar/GlobalSnackbar"
910
import { dark } from "./theme"
1011
import "./theme/globalFonts"
11-
import { XServiceProvider } from "./xServices/StateContext"
1212

1313
export const App: FC = () => {
1414
return (
@@ -17,10 +17,10 @@ export const App: FC = () => {
1717
<ThemeProvider theme={dark}>
1818
<CssBaseline />
1919
<ErrorBoundary>
20-
<XServiceProvider>
20+
<AuthProvider>
2121
<AppRouter />
2222
<GlobalSnackbar />
23-
</XServiceProvider>
23+
</AuthProvider>
2424
</ErrorBoundary>
2525
</ThemeProvider>
2626
</HelmetProvider>
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 AuthProviderContextValue {
7+
authService: ActorRefFrom<typeof authMachine>
8+
}
9+
10+
const AuthProviderContext = createContext<AuthProviderContextValue | undefined>(
11+
undefined,
12+
)
13+
14+
export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
15+
const authService = useInterpret(authMachine)
16+
17+
return (
18+
<AuthProviderContext.Provider value={{ authService }}>
19+
{children}
20+
</AuthProviderContext.Provider>
21+
)
22+
}
23+
24+
// The returned type is kinda complex to rewrite it
25+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -- Read above
26+
export const useAuth = () => {
27+
const context = useContext(AuthProviderContext)
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/Navbar/Navbar.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { shallowEqual, useActor, useSelector } from "@xstate/react"
2+
import { useAuth } from "components/AuthProvider/AuthProvider"
3+
import { useMe } from "hooks/useMe"
4+
import { usePermissions } from "hooks/usePermissions"
25
import { useContext, FC } from "react"
36
import { selectFeatureVisibility } from "xServices/entitlements/entitlementsSelectors"
47
import { XServiceContext } from "../../xServices/StateContext"
@@ -7,17 +10,18 @@ import { NavbarView } from "../NavbarView/NavbarView"
710
export const Navbar: FC = () => {
811
const xServices = useContext(XServiceContext)
912
const [appearanceState] = useActor(xServices.appearanceXService)
10-
const [authState, authSend] = useActor(xServices.authXService)
1113
const [buildInfoState] = useActor(xServices.buildInfoXService)
12-
const { me, permissions } = authState.context
14+
const [_, authSend] = useAuth()
15+
const me = useMe()
16+
const permissions = usePermissions()
1317
const featureVisibility = useSelector(
1418
xServices.entitlementsXService,
1519
selectFeatureVisibility,
1620
shallowEqual,
1721
)
1822
const canViewAuditLog =
19-
featureVisibility["audit_log"] && Boolean(permissions?.viewAuditLog)
20-
const canViewDeployment = Boolean(permissions?.viewDeploymentConfig)
23+
featureVisibility["audit_log"] && Boolean(permissions.viewAuditLog)
24+
const canViewDeployment = Boolean(permissions.viewDeploymentConfig)
2125
const onSignOut = () => authSend("SIGN_OUT")
2226

2327
return (

site/src/components/RequireAuth/RequireAuth.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import { useActor } from "@xstate/react"
2-
import { useContext, FC } from "react"
1+
import { useAuth } from "components/AuthProvider/AuthProvider"
2+
import { FC } from "react"
33
import { Navigate, useLocation } from "react-router"
44
import { Outlet } from "react-router-dom"
55
import { embedRedirect } from "../../util/redirect"
6-
import { XServiceContext } from "../../xServices/StateContext"
76
import { FullScreenLoader } from "../Loader/FullScreenLoader"
87

98
export const RequireAuth: FC = () => {
10-
const xServices = useContext(XServiceContext)
11-
const [authState] = useActor(xServices.authXService)
9+
const [authState] = useAuth()
1210
const location = useLocation()
1311
const isHomePage = location.pathname === "/"
1412
const navigateTo = isHomePage ? "/login" : embedRedirect(location.pathname)

site/src/components/ServiceBanner/ServiceBanner.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useActor } from "@xstate/react"
2+
import { useAuth } from "components/AuthProvider/AuthProvider"
23
import { useContext, useEffect } from "react"
34
import { XServiceContext } from "xServices/StateContext"
45
import { ServiceBannerView } from "./ServiceBannerView"
@@ -8,7 +9,7 @@ export const ServiceBanner: React.FC = () => {
89
const [appearanceState, appearanceSend] = useActor(
910
xServices.appearanceXService,
1011
)
11-
const [authState] = useActor(xServices.authXService)
12+
const [authState] = useAuth()
1213
const { message, background_color, enabled } =
1314
appearanceState.context.appearance.service_banner
1415

site/src/components/SettingsAccountForm/SettingsAccountForm.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AccountForm, AccountFormValues } from "./SettingsAccountForm"
55

66
// NOTE: it does not matter what the role props of MockUser are set to,
77
// only that editable is set to true or false. This is passed from
8-
// the call to /authorization done by authXService
8+
// the call to /authorization done by auth provider
99
describe("AccountForm", () => {
1010
describe("when editable is set to true", () => {
1111
it("allows updating username", async () => {

site/src/components/TemplateLayout/TemplateLayout.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Link from "@material-ui/core/Link"
44
import { makeStyles } from "@material-ui/core/styles"
55
import AddCircleOutline from "@material-ui/icons/AddCircleOutline"
66
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
7-
import { useMachine, useSelector } from "@xstate/react"
7+
import { useMachine } from "@xstate/react"
88
import {
99
PageHeader,
1010
PageHeaderSubtitle,
@@ -20,8 +20,6 @@ import {
2020
} from "react-router-dom"
2121
import { combineClasses } from "util/combineClasses"
2222
import { firstLetter } from "util/firstLetter"
23-
import { selectPermissions } from "xServices/auth/authSelectors"
24-
import { XServiceContext } from "xServices/StateContext"
2523
import {
2624
TemplateContext,
2725
templateMachine,
@@ -30,6 +28,7 @@ import { Margins } from "components/Margins/Margins"
3028
import { Stack } from "components/Stack/Stack"
3129
import { Permissions } from "xServices/auth/authXService"
3230
import { Loader } from "components/Loader/Loader"
31+
import { usePermissions } from "hooks/usePermissions"
3332

3433
const Language = {
3534
settingsButton: "Settings",
@@ -108,8 +107,7 @@ export const TemplateLayout: FC<{ children?: JSX.Element }> = ({
108107
},
109108
})
110109
const { template, permissions: templatePermissions } = templateState.context
111-
const xServices = useContext(XServiceContext)
112-
const permissions = useSelector(xServices.authXService, selectPermissions)
110+
const permissions = usePermissions()
113111
const hasIcon = template && template.icon && template.icon !== ""
114112

115113
if (!template) {

site/src/hooks/useMe.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import { useSelector } from "@xstate/react"
21
import { User } from "api/typesGenerated"
3-
import { useContext } from "react"
2+
import { useAuth } from "components/AuthProvider/AuthProvider"
43
import { selectUser } from "xServices/auth/authSelectors"
5-
import { XServiceContext } from "xServices/StateContext"
64

75
export const useMe = (): User => {
8-
const xServices = useContext(XServiceContext)
9-
const me = useSelector(xServices.authXService, selectUser)
6+
const [authState] = useAuth()
7+
const me = selectUser(authState)
108

119
if (!me) {
1210
throw new Error("User not found.")

site/src/hooks/useOrganizationId.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { useSelector } from "@xstate/react"
2-
import { useContext } from "react"
1+
import { useAuth } from "components/AuthProvider/AuthProvider"
32
import { selectOrgId } from "../xServices/auth/authSelectors"
4-
import { XServiceContext } from "../xServices/StateContext"
53

64
export const useOrganizationId = (): string => {
7-
const xServices = useContext(XServiceContext)
8-
const organizationId = useSelector(xServices.authXService, selectOrgId)
5+
const [authState] = useAuth()
6+
const organizationId = selectOrgId(authState)
97

108
if (!organizationId) {
119
throw new Error("No organization ID found")

site/src/hooks/usePermissions.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import { useActor } from "@xstate/react"
2-
import { useContext } from "react"
1+
import { useAuth } from "components/AuthProvider/AuthProvider"
32
import { AuthContext } from "xServices/auth/authXService"
4-
import { XServiceContext } from "xServices/StateContext"
53

64
export const usePermissions = (): NonNullable<AuthContext["permissions"]> => {
7-
const xServices = useContext(XServiceContext)
8-
const [authState, _] = useActor(xServices.authXService)
5+
const [authState] = useAuth()
96
const { permissions } = authState.context
7+
108
if (!permissions) {
119
throw new Error("Permissions are not loaded yet.")
1210
}
11+
1312
return permissions
1413
}

site/src/pages/LoginPage/LoginPage.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import { useActor } from "@xstate/react"
2-
import { FC, useContext } from "react"
1+
import { useAuth } from "components/AuthProvider/AuthProvider"
2+
import { FC } from "react"
33
import { Helmet } from "react-helmet-async"
44
import { useTranslation } from "react-i18next"
55
import { Navigate, useLocation } from "react-router-dom"
66
import { retrieveRedirect } from "../../util/redirect"
7-
import { XServiceContext } from "../../xServices/StateContext"
87
import { LoginPageView } from "./LoginPageView"
98

109
export const LoginPage: FC = () => {
1110
const location = useLocation()
12-
const xServices = useContext(XServiceContext)
13-
const [authState, authSend] = useActor(xServices.authXService)
11+
const [authState, authSend] = useAuth()
1412
const redirectTo = retrieveRedirect(location.search)
1513
const commonTranslation = useTranslation("common")
1614
const loginPageTranslation = useTranslation("loginPage")

site/src/pages/SetupPage/SetupPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { SetupPageView } from "./SetupPageView"
88

99
export const SetupPage: FC = () => {
1010
const xServices = useContext(XServiceContext)
11-
const [authState, authSend] = useActor(xServices.authXService)
11+
const [authState, authSend] = useAuth()
1212
const [setupState, setupSend] = useMachine(setupMachine, {
1313
actions: {
1414
onCreateFirstUser: ({ firstUser }) => {

site/src/pages/UserSettingsPage/AccountPage/AccountPage.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import { useActor } from "@xstate/react"
2-
import { FC, useContext } from "react"
1+
import { FC } from "react"
32
import { Section } from "../../../components/SettingsLayout/Section"
43
import { AccountForm } from "../../../components/SettingsAccountForm/SettingsAccountForm"
5-
import { XServiceContext } from "../../../xServices/StateContext"
4+
import { useAuth } from "components/AuthProvider/AuthProvider"
65

76
export const Language = {
87
title: "Account",
98
}
109

1110
export const AccountPage: FC = () => {
12-
const xServices = useContext(XServiceContext)
13-
const [authState, authSend] = useActor(xServices.authXService)
11+
const [authState, authSend] = useAuth()
1412
const { me, permissions, updateProfileError } = authState.context
1513
const canEditUsers = permissions && permissions.updateUsers
1614

site/src/xServices/StateContext.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { useInterpret } from "@xstate/react"
22
import { createContext, FC, ReactNode } from "react"
33
import { ActorRefFrom } from "xstate"
4-
import { authMachine } from "./auth/authXService"
54
import { buildInfoMachine } from "./buildInfo/buildInfoXService"
65
import { entitlementsMachine } from "./entitlements/entitlementsXService"
76
import { appearanceMachine } from "./appearance/appearanceXService"
87

98
interface XServiceContextType {
10-
authXService: ActorRefFrom<typeof authMachine>
119
buildInfoXService: ActorRefFrom<typeof buildInfoMachine>
1210
entitlementsXService: ActorRefFrom<typeof entitlementsMachine>
1311
appearanceXService: ActorRefFrom<typeof appearanceMachine>
@@ -27,7 +25,6 @@ export const XServiceProvider: FC<{ children: ReactNode }> = ({ children }) => {
2725
return (
2826
<XServiceContext.Provider
2927
value={{
30-
authXService: useInterpret(authMachine),
3128
buildInfoXService: useInterpret(buildInfoMachine),
3229
entitlementsXService: useInterpret(entitlementsMachine),
3330
appearanceXService: useInterpret(appearanceMachine),

site/src/xServices/auth/authSelectors.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { State } from "xstate"
2-
import { AuthContext, AuthEvent } from "./authXService"
1+
import { StateFrom } from "xstate"
2+
import { AuthContext, authMachine } from "./authXService"
33

4-
type AuthState = State<AuthContext, AuthEvent>
4+
type AuthState = StateFrom<typeof authMachine>
55

66
export const selectOrgId = (state: AuthState): string | undefined => {
77
return state.context.me?.organization_ids[0]

0 commit comments

Comments
 (0)