Skip to content

Commit b82356b

Browse files
fix: passes serverURL through to all formatAdminURL calls (#14869)
Fixes issues with basePath and NextJS. Many of the links created in the admin panel were not passing a `serverURL` through to the `formatAdminURL` helper. This PR adds all the missing `serverURL` instances and adds a new helper `formatApiURL` that allows for similar route creation but for api routes.
1 parent 309ae51 commit b82356b

File tree

51 files changed

+317
-92
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+317
-92
lines changed

packages/next/src/elements/DocumentHeader/Tabs/Tab/TabLink.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22
import type { SanitizedConfig } from 'payload'
33

4-
import { Button } from '@payloadcms/ui'
4+
import { Button, useConfig } from '@payloadcms/ui'
55
import { useParams, usePathname, useSearchParams } from 'next/navigation.js'
66
import { formatAdminURL } from 'payload/shared'
77
import React from 'react'
@@ -25,6 +25,7 @@ export const DocumentTabLink: React.FC<{
2525
}) => {
2626
const pathname = usePathname()
2727
const params = useParams()
28+
const { config } = useConfig()
2829

2930
const searchParams = useSearchParams()
3031

@@ -36,6 +37,7 @@ export const DocumentTabLink: React.FC<{
3637
let docPath = formatAdminURL({
3738
adminRoute,
3839
path: `/${isCollection ? 'collections' : 'globals'}/${entitySlug}`,
40+
serverURL: config.serverURL,
3941
})
4042

4143
if (isCollection) {

packages/next/src/elements/Nav/index.client.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const DefaultNavClient: React.FC<{
2828
},
2929
folders,
3030
routes: { admin: adminRoute },
31+
serverURL,
3132
},
3233
} = useConfig()
3334

@@ -36,6 +37,7 @@ export const DefaultNavClient: React.FC<{
3637
const folderURL = formatAdminURL({
3738
adminRoute,
3839
path: foldersRoute,
40+
serverURL,
3941
})
4042

4143
const viewingRootFolderView = pathname.startsWith(folderURL)
@@ -51,12 +53,12 @@ export const DefaultNavClient: React.FC<{
5153
let id: string
5254

5355
if (type === EntityType.collection) {
54-
href = formatAdminURL({ adminRoute, path: `/collections/${slug}` })
56+
href = formatAdminURL({ adminRoute, path: `/collections/${slug}`, serverURL })
5557
id = `nav-${slug}`
5658
}
5759

5860
if (type === EntityType.global) {
59-
href = formatAdminURL({ adminRoute, path: `/globals/${slug}` })
61+
href = formatAdminURL({ adminRoute, path: `/globals/${slug}`, serverURL })
6062
id = `nav-global-${slug}`
6163
}
6264

packages/next/src/utilities/handleAuthRedirect.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const handleAuthRedirect = ({ config, route, searchParams, user }: Args):
3131
const redirectTo = formatAdminURL({
3232
adminRoute,
3333
path: user ? unauthorizedRoute : loginRouteFromConfig,
34+
serverURL: config.serverURL,
3435
})
3536

3637
const parsedLoginRouteSearchParams = qs.parse(redirectTo.split('?')[1] ?? '')

packages/next/src/views/Account/ResetPreferences/index.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import type { TypedUser } from 'payload'
33

44
import { Button, ConfirmationModal, toast, useModal, useTranslation } from '@payloadcms/ui'
5+
import { formatApiURL } from 'payload/shared'
56
import * as qs from 'qs-esm'
67
import { Fragment, useCallback } from 'react'
78

@@ -34,13 +35,20 @@ export const ResetPreferences: React.FC<{
3435
)
3536

3637
try {
37-
const res = await fetch(`${apiRoute}/payload-preferences${stringifiedQuery}`, {
38-
credentials: 'include',
39-
headers: {
40-
'Content-Type': 'application/json',
38+
const res = await fetch(
39+
formatApiURL({
40+
apiRoute,
41+
path: `/payload-preferences${stringifiedQuery}`,
42+
serverURL: undefined,
43+
}),
44+
{
45+
credentials: 'include',
46+
headers: {
47+
'Content-Type': 'application/json',
48+
},
49+
method: 'DELETE',
4150
},
42-
method: 'DELETE',
43-
})
51+
)
4452

4553
const json = await res.json()
4654
const message = json.message

packages/next/src/views/CreateFirstUser/index.client.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
useTranslation,
2121
} from '@payloadcms/ui'
2222
import { abortAndIgnore, handleAbortRef } from '@payloadcms/ui/shared'
23+
import { formatApiURL } from 'payload/shared'
2324
import React, { useEffect } from 'react'
2425

2526
export const CreateFirstUserClient: React.FC<{
@@ -84,7 +85,11 @@ export const CreateFirstUserClient: React.FC<{
8485

8586
return (
8687
<Form
87-
action={`${serverURL}${apiRoute}/${userSlug}/first-register`}
88+
action={formatApiURL({
89+
apiRoute,
90+
path: `/${userSlug}/first-register`,
91+
serverURL,
92+
})}
8893
initialState={{
8994
...initialState,
9095
'confirm-password': {

packages/next/src/views/Dashboard/Default/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function DefaultDashboard(props: DashboardViewServerProps) {
4747
components: { afterDashboard, beforeDashboard },
4848
},
4949
routes: { admin: adminRoute },
50+
serverURL,
5051
},
5152
},
5253
payload,
@@ -96,11 +97,16 @@ export function DefaultDashboard(props: DashboardViewServerProps) {
9697

9798
buttonAriaLabel = t('general:showAllLabel', { label: title })
9899

99-
href = formatAdminURL({ adminRoute, path: `/collections/${slug}` })
100+
href = formatAdminURL({
101+
adminRoute,
102+
path: `/collections/${slug}`,
103+
serverURL,
104+
})
100105

101106
createHREF = formatAdminURL({
102107
adminRoute,
103108
path: `/collections/${slug}/create`,
109+
serverURL,
104110
})
105111

106112
hasCreatePermission = permissions?.collections?.[slug]?.create
@@ -116,6 +122,7 @@ export function DefaultDashboard(props: DashboardViewServerProps) {
116122
href = formatAdminURL({
117123
adminRoute,
118124
path: `/globals/${slug}`,
125+
serverURL,
119126
})
120127

121128
// Find the lock status for the global

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { isEditing as getIsEditing } from '@payloadcms/ui/shared'
2222
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
2323
import { notFound, redirect } from 'next/navigation.js'
2424
import { isolateObjectProperty, logError } from 'payload'
25-
import { formatAdminURL, hasAutosaveEnabled, hasDraftsEnabled } from 'payload/shared'
25+
import { formatAdminURL, formatApiURL, hasAutosaveEnabled, hasDraftsEnabled } from 'payload/shared'
2626
import React from 'react'
2727

2828
import type { GenerateEditViewMetadata } from './getMetaBySegment.js'
@@ -274,11 +274,15 @@ export const renderDocument = async ({
274274

275275
const apiQueryParams = `?${formattedParams.toString()}`
276276

277-
const apiURL = collectionSlug
278-
? `${serverURL}${apiRoute}/${collectionSlug}/${idFromArgs}${apiQueryParams}`
279-
: globalSlug
280-
? `${serverURL}${apiRoute}/${globalSlug}${apiQueryParams}`
281-
: ''
277+
const apiURL = formatApiURL({
278+
apiRoute,
279+
path: collectionSlug
280+
? `/${collectionSlug}/${idFromArgs}${apiQueryParams}`
281+
: globalSlug
282+
? `/${globalSlug}${apiQueryParams}`
283+
: '',
284+
serverURL,
285+
})
282286

283287
let View: ViewToRender = null
284288

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) {
2424
routes: { account: accountRoute, login: loginRoute },
2525
},
2626
routes: { admin: adminRoute },
27+
serverURL,
2728
} = config
2829

2930
if (user) {
@@ -38,6 +39,7 @@ export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) {
3839
href={formatAdminURL({
3940
adminRoute,
4041
path: accountRoute,
42+
serverURL,
4143
})}
4244
prefetch={false}
4345
>
@@ -65,6 +67,7 @@ export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) {
6567
href={formatAdminURL({
6668
adminRoute,
6769
path: loginRoute,
70+
serverURL,
6871
})}
6972
prefetch={false}
7073
>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ export const renderListView = async (
346346
const newDocumentURL = formatAdminURL({
347347
adminRoute,
348348
path: `/collections/${collectionSlug}/create`,
349+
serverURL: config.serverURL,
349350
})
350351

351352
const hasCreatePermission = permissions?.collections?.[collectionSlug]?.create

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
useConfig,
1717
useTranslation,
1818
} from '@payloadcms/ui'
19-
import { formatAdminURL, getLoginOptions, getSafeRedirect } from 'payload/shared'
19+
import { formatAdminURL, formatApiURL, getLoginOptions, getSafeRedirect } from 'payload/shared'
2020

2121
import type { LoginFieldProps } from '../LoginField/index.js'
2222

@@ -37,6 +37,7 @@ export const LoginForm: React.FC<{
3737
user: userSlug,
3838
},
3939
routes: { admin: adminRoute, api: apiRoute },
40+
serverURL,
4041
} = config
4142

4243
const collectionConfig = getEntityConfig({ collectionSlug: userSlug })
@@ -85,7 +86,11 @@ export const LoginForm: React.FC<{
8586

8687
return (
8788
<Form
88-
action={`${apiRoute}/${userSlug}/login`}
89+
action={formatApiURL({
90+
apiRoute,
91+
path: `/${userSlug}/login`,
92+
serverURL,
93+
})}
8994
className={baseClass}
9095
disableSuccessStatus
9196
initialState={initialState}
@@ -109,6 +114,7 @@ export const LoginForm: React.FC<{
109114
href={formatAdminURL({
110115
adminRoute,
111116
path: forgotRoute,
117+
serverURL,
112118
})}
113119
prefetch={false}
114120
>

0 commit comments

Comments
 (0)