Skip to content

Commit 6a0fffe

Browse files
authored
feat!: consolidates admin.logoutRoute and admin.inactivityRoute into admin.routes (#6354)
1 parent 6e116a7 commit 6a0fffe

File tree

26 files changed

+368
-104
lines changed

26 files changed

+368
-104
lines changed

docs/admin/overview.mdx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ All options for the Admin panel are defined in your base Payload config file.
4545
| `components` | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components) |
4646
| `webpack` | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack) |
4747
| `vite` | Customize the Vite config that's used to generate the Admin panel. [More](/docs/admin/vite) |
48-
| `logoutRoute` | The route for the `logout` page. |
49-
| `inactivityRoute` | The route for the `logout` inactivity page. |
48+
| `routes` | Replace built-in Admin Panel routes with your own custom routes. I.e. `{ logout: '/custom-logout', inactivity: 'custom-inactivity' }` |
5049

5150
### The Admin User Collection
5251

packages/next/src/utilities/initPage/handleAdminPage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const handleAdminPage = ({
4646
}
4747
}
4848

49-
if (!permissions.canAccessAdmin && !isAdminAuthRoute(route, adminRoute)) {
49+
if (!permissions.canAccessAdmin && !isAdminAuthRoute(config, route, adminRoute)) {
5050
notFound()
5151
}
5252

packages/next/src/utilities/initPage/handleAuthRedirect.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,24 @@ import QueryString from 'qs'
44
import { isAdminAuthRoute, isAdminRoute } from './shared.js'
55

66
export const handleAuthRedirect = ({
7-
adminRoute,
7+
config,
88
redirectUnauthenticatedUser,
99
route,
1010
searchParams,
1111
}: {
12-
adminRoute: string
12+
config
1313
redirectUnauthenticatedUser: boolean | string
1414
route: string
1515
searchParams: { [key: string]: string | string[] }
1616
}) => {
17-
if (!isAdminAuthRoute(route, adminRoute)) {
17+
const {
18+
admin: {
19+
routes: { login: loginRouteFromConfig },
20+
},
21+
routes: { admin: adminRoute },
22+
} = config
23+
24+
if (!isAdminAuthRoute(config, route, adminRoute)) {
1825
if (searchParams && 'redirect' in searchParams) delete searchParams.redirect
1926

2027
const redirectRoute = encodeURIComponent(
@@ -23,14 +30,14 @@ export const handleAuthRedirect = ({
2330
: undefined,
2431
)
2532

26-
const adminLoginRoute = `${adminRoute}/login`
33+
const adminLoginRoute = `${adminRoute}${loginRouteFromConfig}`
2734

2835
const customLoginRoute =
2936
typeof redirectUnauthenticatedUser === 'string' ? redirectUnauthenticatedUser : undefined
3037

3138
const loginRoute = isAdminRoute(route, adminRoute)
3239
? adminLoginRoute
33-
: customLoginRoute || '/login'
40+
: customLoginRoute || loginRouteFromConfig
3441

3542
const parsedLoginRouteSearchParams = QueryString.parse(loginRoute.split('?')[1] ?? '')
3643

packages/next/src/utilities/initPage/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export const initPage = async ({
7878

7979
if (redirectUnauthenticatedUser && !user) {
8080
handleAuthRedirect({
81-
adminRoute,
81+
config: payload.config,
8282
redirectUnauthenticatedUser,
8383
route,
8484
searchParams,
Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
export const authRoutes = [
2-
'/login',
3-
'/logout',
4-
'/create-first-user',
5-
'/forgot',
6-
'/reset',
7-
'/verify',
8-
'/logout-inactivity',
1+
import type { SanitizedConfig } from 'payload/types'
2+
3+
const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [
4+
'account',
5+
'createFirstUser',
6+
'forgot',
7+
'login',
8+
'logout',
9+
'forgot',
10+
'inactivity',
11+
'unauthorized',
912
]
1013

1114
export const isAdminRoute = (route: string, adminRoute: string) => {
1215
return route.startsWith(adminRoute)
1316
}
1417

15-
export const isAdminAuthRoute = (route: string, adminRoute: string) => {
18+
export const isAdminAuthRoute = (config: SanitizedConfig, route: string, adminRoute: string) => {
19+
const authRoutes = config.admin?.routes
20+
? Object.entries(config.admin.routes)
21+
.filter(([key]) => authRouteKeys.includes(key as keyof SanitizedConfig['admin']['routes']))
22+
.map(([_, value]) => value)
23+
: []
24+
1625
return authRoutes.some((r) => route.replace(adminRoute, '').startsWith(r))
1726
}

packages/next/src/views/ForgotPassword/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult })
2222
} = initPageResult
2323

2424
const {
25+
admin: {
26+
routes: { account: accountRoute },
27+
},
2528
routes: { admin },
2629
} = config
2730

@@ -32,7 +35,7 @@ export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult })
3235
<p>
3336
<Translation
3437
elements={{
35-
'0': ({ children }) => <Link href={`${admin}/account`}>{children}</Link>,
38+
'0': ({ children }) => <Link href={`${admin}${accountRoute}`}>{children}</Link>,
3639
}}
3740
i18nKey="authentication:loggedInChangePassword"
3841
t={i18n.t}

packages/next/src/views/Login/LoginForm/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ export const LoginForm: React.FC<{
2525
const config = useConfig()
2626

2727
const {
28-
admin: { autoLogin, user: userSlug },
28+
admin: {
29+
autoLogin,
30+
routes: { forgot: forgotRoute },
31+
user: userSlug,
32+
},
2933
routes: { admin, api },
3034
} = config
3135

@@ -98,7 +102,7 @@ export const LoginForm: React.FC<{
98102
}
99103
/>
100104
</div>
101-
<Link href={`${admin}/forgot`}>{t('authentication:forgotPasswordQuestion')}</Link>
105+
<Link href={`${admin}${forgotRoute}`}>{t('authentication:forgotPasswordQuestion')}</Link>
102106
<FormSubmit>{t('authentication:login')}</FormSubmit>
103107
</Form>
104108
)

packages/next/src/views/ResetPassword/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
2929
} = req
3030

3131
const {
32+
admin: {
33+
routes: { account: accountRoute },
34+
},
3235
routes: { admin },
3336
} = config
3437

@@ -40,7 +43,7 @@ export const ResetPassword: React.FC<AdminViewProps> = ({ initPageResult, params
4043
<p>
4144
<Translation
4245
elements={{
43-
'0': ({ children }) => <Link href={`${admin}/account`}>{children}</Link>,
46+
'0': ({ children }) => <Link href={`${admin}${accountRoute}`}>{children}</Link>,
4447
}}
4548
i18nKey="authentication:loggedInChangePassword"
4649
t={i18n.t}

packages/next/src/views/Root/getViewFromConfig.tsx

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,27 @@ import { ResetPassword, resetPasswordBaseClass } from '../ResetPassword/index.js
1515
import { UnauthorizedView } from '../Unauthorized/index.js'
1616
import { Verify, verifyBaseClass } from '../Verify/index.js'
1717
import { getCustomViewByRoute } from './getCustomViewByRoute.js'
18+
import { isPathMatchingRoute } from './isPathMatchingRoute.js'
1819

1920
const baseClasses = {
21+
account: 'account',
2022
forgot: forgotPasswordBaseClass,
2123
login: loginBaseClass,
2224
reset: resetPasswordBaseClass,
2325
verify: verifyBaseClass,
2426
}
2527

26-
const oneSegmentViews = {
27-
'create-first-user': CreateFirstUserView,
28+
type OneSegmentViews = {
29+
[K in keyof SanitizedConfig['admin']['routes']]: AdminViewComponent
30+
}
31+
32+
const oneSegmentViews: OneSegmentViews = {
33+
account: Account,
34+
createFirstUser: CreateFirstUserView,
2835
forgot: ForgotPasswordView,
36+
inactivity: LogoutInactivity,
2937
login: LoginView,
3038
logout: LogoutView,
31-
'logout-inactivity': LogoutInactivity,
3239
unauthorized: UnauthorizedView,
3340
}
3441

@@ -78,22 +85,41 @@ export const getViewFromConfig = ({
7885
break
7986
}
8087
case 1: {
81-
if (oneSegmentViews[segmentOne] && segmentOne !== 'account') {
88+
// users can override the default routes via `admin.routes` config
89+
// i.e.{ admin: { routes: { logout: '/sign-out', inactivity: '/idle' }}}
90+
let viewToRender: keyof typeof oneSegmentViews
91+
92+
if (config.admin.routes) {
93+
const matchedRoute = Object.entries(config.admin.routes).find(([, route]) => {
94+
return isPathMatchingRoute({
95+
currentRoute,
96+
exact: true,
97+
path: `${adminRoute}${route}`,
98+
})
99+
})
100+
101+
if (matchedRoute) {
102+
viewToRender = matchedRoute[0] as keyof typeof oneSegmentViews
103+
}
104+
}
105+
106+
if (oneSegmentViews[viewToRender]) {
107+
// --> /account
82108
// --> /create-first-user
83109
// --> /forgot
84110
// --> /login
85111
// --> /logout
86112
// --> /logout-inactivity
87113
// --> /unauthorized
88-
ViewToRender = oneSegmentViews[segmentOne]
89-
templateClassName = baseClasses[segmentOne]
114+
115+
ViewToRender = oneSegmentViews[viewToRender]
116+
templateClassName = baseClasses[viewToRender]
90117
templateType = 'minimal'
91-
} else if (segmentOne === 'account') {
92-
// --> /account
93-
initPageOptions.redirectUnauthenticatedUser = true
94-
ViewToRender = Account
95-
templateClassName = 'account'
96-
templateType = 'default'
118+
119+
if (viewToRender === 'account') {
120+
initPageOptions.redirectUnauthenticatedUser = true
121+
templateType = 'default'
122+
}
97123
}
98124
break
99125
}

packages/next/src/views/Root/index.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ export const RootPage = async ({
3434
const config = await configPromise
3535

3636
const {
37-
admin: { user: userSlug },
37+
admin: {
38+
routes: { createFirstUser: createFirstUserRoute },
39+
user: userSlug,
40+
},
3841
routes: { admin: adminRoute },
3942
} = config
4043

@@ -66,13 +69,13 @@ export const RootPage = async ({
6669
})
6770
?.then((doc) => !!doc)
6871

69-
const createFirstUserRoute = `${adminRoute}/create-first-user`
72+
const routeWithAdmin = `${adminRoute}${createFirstUserRoute}`
7073

71-
if (!dbHasUser && currentRoute !== createFirstUserRoute) {
72-
redirect(createFirstUserRoute)
74+
if (!dbHasUser && currentRoute !== routeWithAdmin) {
75+
redirect(routeWithAdmin)
7376
}
7477

75-
if (dbHasUser && currentRoute === createFirstUserRoute) {
78+
if (dbHasUser && currentRoute === routeWithAdmin) {
7679
redirect(adminRoute)
7780
}
7881
}

0 commit comments

Comments
 (0)