Skip to content

Commit cfc7adc

Browse files
authored
fix: strict custom view paths (#12968)
1 parent 16f5538 commit cfc7adc

File tree

5 files changed

+81
-38
lines changed

5 files changed

+81
-38
lines changed

docs/admin/overview.mdx

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ The Admin Panel serves as the entire HTTP layer for Payload, providing a full CR
3232
Once you [install Payload](../getting-started/installation), the following files and directories will be created in your app:
3333

3434
```plaintext
35-
app/
36-
├─ (payload)/
37-
├── admin/
38-
├─── [[...segments]]/
35+
app
36+
├─ (payload)
37+
├── admin
38+
├─── [[...segments]]
3939
├──── page.tsx
4040
├──── not-found.tsx
41-
├── api/
42-
├─── [...slug]/
41+
├── api
42+
├─── [...slug]
4343
├──── route.ts
44-
├── graphql/
44+
├── graphql
4545
├──── route.ts
46-
├── graphql-playground/
46+
├── graphql-playground
4747
├──── route.ts
4848
├── custom.scss
4949
├── layout.tsx
@@ -84,29 +84,30 @@ import { buildConfig } from 'payload'
8484

8585
const config = buildConfig({
8686
// ...
87+
// highlight-start
8788
admin: {
88-
// highlight-line
8989
// ...
9090
},
91+
// highlight-end
9192
})
9293
```
9394

9495
The following options are available:
9596

96-
| Option | Description |
97-
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
98-
| **`avatar`** | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
99-
| **`autoLogin`** | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
100-
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](../custom-components/overview). |
101-
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
102-
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
103-
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
104-
| **`meta`** | Base metadata to use for the Admin Panel. [More details](./metadata). |
105-
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
106-
| **`suppressHydrationWarning`** | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
107-
| **`theme`** | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
108-
| **`timezones`** | Configure the timezone settings for the admin panel. [More details](#timezones) |
109-
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
97+
| Option | Description |
98+
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
99+
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
100+
| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
101+
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](../custom-components/overview). |
102+
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
103+
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
104+
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
105+
| `meta` | Base metadata to use for the Admin Panel. [More details](./metadata). |
106+
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
107+
| `suppressHydrationWarning` | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
108+
| `theme` | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
109+
| `timezones` | Configure the timezone settings for the admin panel. [More details](#timezones) |
110+
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
110111

111112
<Banner type="success">
112113
**Reminder:** These are the _root-level_ options for the Admin Panel. You can
@@ -186,6 +187,12 @@ The following options are available:
186187
| `graphQL` | `/graphql` | The [GraphQL API](../graphql/overview) base path. |
187188
| `graphQLPlayground` | `/graphql-playground` | The GraphQL Playground. |
188189

190+
<Banner type="warning">
191+
**Important:** Changing Root-level Routes also requires a change to [Project
192+
Structure](#project-structure) to match the new route. [More
193+
details](#customizing-root-level-routes).
194+
</Banner>
195+
189196
<Banner type="success">
190197
**Tip:** You can easily add _new_ routes to the Admin Panel through [Custom
191198
Endpoints](../rest-api/overview#custom-endpoints) and [Custom
@@ -196,13 +203,29 @@ The following options are available:
196203

197204
You can change the Root-level Routes as needed, such as to mount the Admin Panel at the root of your application.
198205

199-
Changing Root-level Routes also requires a change to [Project Structure](#project-structure) to match the new route. For example, if you set `routes.admin` to `/`, you would need to completely remove the `admin` directory from the project structure:
206+
This change, however, also requires a change to your [Project Structure](#project-structure) to match the new route.
207+
208+
For example, if you set `routes.admin` to `/`:
209+
210+
```ts
211+
import { buildConfig } from 'payload'
212+
213+
const config = buildConfig({
214+
// ...
215+
routes: {
216+
admin: '/', // highlight-line
217+
},
218+
})
219+
```
220+
221+
Then you would need to completely remove the `admin` directory from the project structure:
200222

201223
```plaintext
202-
app/
203-
├─ (payload)/
204-
├── [[...segments]]/
224+
app
225+
├─ (payload)
226+
├── [[...segments]]
205227
├──── ...
228+
├── layout.tsx
206229
```
207230

208231
<Banner type="warning">

docs/custom-components/custom-views.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ For more granular control, pass a configuration object instead. Payload exposes
5151
| Property | Description |
5252
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5353
| `Component` \* | Pass in the component path that should be rendered when a user navigates to this route. |
54-
| `path` \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
54+
| `path` \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. Must begin with a forward slash (`/`). |
5555
| `exact` | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
5656
| `strict` | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
5757
| `sensitive` | When true, will match if the path is case sensitive. |

packages/payload/src/admin/views/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ export type AdminViewConfig = {
2323
/** Whether the path should be matched exactly or as a prefix */
2424
exact?: boolean
2525
meta?: MetaConfig
26-
path?: string
26+
/**
27+
* Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. Must begin with a forward slash (`/`).
28+
*/
29+
path?: `/${string}`
2730
sensitive?: boolean
2831
strict?: boolean
2932
}

packages/payload/src/config/types.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ type BaseDocumentViewConfig = {
375375
export type CustomDocumentViewConfig =
376376
| ({
377377
Component: DocumentViewComponent
378-
path: string
378+
path: `/${string}`
379379
} & BaseDocumentViewConfig)
380380
| ({
381381
Component?: DocumentViewComponent
@@ -1162,18 +1162,35 @@ export type Config = {
11621162
filterConstraints?: SelectField['filterOptions']
11631163
labels?: CollectionConfig['labels']
11641164
}
1165-
/** Control the routing structure that Payload binds itself to. */
1165+
/**
1166+
* Control the routing structure that Payload binds itself to.
1167+
* @link https://payloadcms.com/docs/admin/overview#root-level-routes
1168+
*/
11661169
routes?: {
1167-
/** The route for the admin panel.
1168-
* @example "/my-admin"
1170+
/**
1171+
* The route for the admin panel.
1172+
* @example "/my-admin" or "/"
11691173
* @default "/admin"
1174+
* @link https://payloadcms.com/docs/admin/overview#root-level-routes
11701175
*/
11711176
admin?: string
1172-
/** @default "/api" */
1177+
/**
1178+
* The base route for all REST API endpoints.
1179+
* @default "/api"
1180+
* @link https://payloadcms.com/docs/admin/overview#root-level-routes
1181+
*/
11731182
api?: string
1174-
/** @default "/graphql" */
1183+
/**
1184+
* The base route for all GraphQL endpoints.
1185+
* @default "/graphql"
1186+
* @link https://payloadcms.com/docs/admin/overview#root-level-routes
1187+
*/
11751188
graphQL?: string
1176-
/** @default "/graphql-playground" */
1189+
/**
1190+
* The route for the GraphQL Playground.
1191+
* @default "/graphql-playground"
1192+
* @link https://payloadcms.com/docs/admin/overview#root-level-routes
1193+
*/
11771194
graphQLPlayground?: string
11781195
}
11791196
/** Secure string that Payload will use for any encryption workflows */

test/types/types.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,12 @@ describe('Types testing', () => {
164164
describe('views', () => {
165165
test('default view config', () => {
166166
expect<DefaultDocumentViewConfig>().type.not.toBeAssignableWith<{
167-
path: string
167+
path: `/${string}`
168168
}>()
169169

170170
expect<CustomDocumentViewConfig>().type.toBeAssignableWith<{
171171
Component: string
172-
path: string
172+
path: `/${string}`
173173
}>()
174174
})
175175
})

0 commit comments

Comments
 (0)