Skip to content

Commit ad0e7b2

Browse files
authored
fix(ui): preview button not responding to conditional URL (#14277)
Fixes #14241 and #11253. Preview URL is now part of the form state as well so we can conditionally show the preview button based on its value, previously this was not possible because we were fetching the URL on click. Similar to #14012.
1 parent b68715e commit ad0e7b2

File tree

19 files changed

+280
-228
lines changed

19 files changed

+280
-228
lines changed

docs/admin/preview.mdx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ import type { CollectionConfig } from 'payload'
8181
export const Pages: CollectionConfig = {
8282
slug: 'pages',
8383
admin: {
84-
preview: ({ slug, collection }) => {
84+
preview: ({ slug }) => {
8585
const encodedParams = new URLSearchParams({
8686
slug,
87-
collection,
87+
collection: 'pages',
8888
path: `/${slug}`,
8989
previewSecret: process.env.PREVIEW_SECRET || '',
9090
})
@@ -231,3 +231,32 @@ export default async function Page({ params: paramsPromise }) {
231231
in the [Examples
232232
Directory](https://github.com/payloadcms/payload/tree/main/examples).
233233
</Banner>
234+
235+
### Conditional Preview URLs
236+
237+
You can also conditionally enable or disable the preview button based on the document's data. This is useful for scenarios where you only want to show the preview button when certain criteria are met.
238+
239+
To do this, simply return `null` from the `preview` function when you want to hide the preview button:
240+
241+
```ts
242+
import type { CollectionConfig } from 'payload'
243+
244+
export const Pages: CollectionConfig = {
245+
slug: 'pages',
246+
admin: {
247+
preview: (doc) => {
248+
return doc?.enabled ? `http://localhost:3000/${doc.slug}` : null
249+
},
250+
},
251+
fields: [
252+
{
253+
name: 'slug',
254+
type: 'text',
255+
},
256+
{
257+
name: 'enabled',
258+
type: 'checkbox',
259+
},
260+
],
261+
}
262+
```

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
LivePreviewProvider,
1818
} from '@payloadcms/ui'
1919
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
20-
import { handleLivePreview } from '@payloadcms/ui/rsc'
20+
import { handleLivePreview, handlePreview } from '@payloadcms/ui/rsc'
2121
import { isEditing as getIsEditing } from '@payloadcms/ui/shared'
2222
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
2323
import { notFound, redirect } from 'next/navigation.js'
@@ -360,6 +360,15 @@ export const renderDocument = async ({
360360
req,
361361
})
362362

363+
const { isPreviewEnabled, previewURL } = await handlePreview({
364+
collectionSlug,
365+
config,
366+
data: doc,
367+
globalSlug,
368+
operation,
369+
req,
370+
})
371+
363372
return {
364373
data: doc,
365374
Document: (
@@ -395,6 +404,8 @@ export const renderDocument = async ({
395404
isLivePreviewing={Boolean(
396405
entityPreferences?.value?.editViewType === 'live-preview' && livePreviewURL,
397406
)}
407+
isPreviewEnabled={Boolean(isPreviewEnabled)}
408+
previewURL={previewURL}
398409
typeofLivePreviewURL={typeof livePreviewConfig?.url as 'function' | 'string' | undefined}
399410
url={livePreviewURL}
400411
>

packages/payload/src/admin/forms/Form.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ export type BuildFormStateArgs = {
142142
*/
143143
returnLivePreviewURL?: boolean
144144
returnLockStatus?: boolean
145+
/**
146+
* If true, will return a fresh URL for preview based on the current form state.
147+
* Note: this will run on every form state event, so if your `preview` function is long running or expensive,
148+
* ensure it caches itself as needed.
149+
*/
150+
returnPreviewURL?: boolean
145151
schemaPath: string
146152
select?: SelectType
147153
/**

packages/payload/src/collections/endpoints/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { findByIDHandler } from './findByID.js'
1212
// import { findDistinctHandler } from './findDistinct.js'
1313
import { findVersionByIDHandler } from './findVersionByID.js'
1414
import { findVersionsHandler } from './findVersions.js'
15-
import { previewHandler } from './preview.js'
1615
import { restoreVersionHandler } from './restoreVersion.js'
1716
import { updateHandler } from './update.js'
1817
import { updateByIDHandler } from './updateByID.js'
@@ -75,11 +74,6 @@ export const defaultCollectionEndpoints: Endpoint[] = [
7574
method: 'get',
7675
path: '/versions/:id',
7776
},
78-
{
79-
handler: previewHandler,
80-
method: 'get',
81-
path: '/:id/preview',
82-
},
8377
{
8478
handler: restoreVersionHandler,
8579
method: 'post',

packages/payload/src/collections/endpoints/preview.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

packages/payload/src/globals/endpoints/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { docAccessHandler } from './docAccess.js'
55
import { findOneHandler } from './findOne.js'
66
import { findVersionByIDHandler } from './findVersionByID.js'
77
import { findVersionsHandler } from './findVersions.js'
8-
import { previewHandler } from './preview.js'
98
import { restoreVersionHandler } from './restoreVersion.js'
109
import { updateHandler } from './update.js'
1110

@@ -30,11 +29,6 @@ export const defaultGlobalEndpoints: Endpoint[] = wrapInternalEndpoints([
3029
method: 'get',
3130
path: '/versions',
3231
},
33-
{
34-
handler: previewHandler,
35-
method: 'get',
36-
path: '/preview',
37-
},
3832
{
3933
handler: restoreVersionHandler,
4034
method: 'post',

packages/payload/src/globals/endpoints/preview.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

packages/ui/src/elements/PreviewButton/index.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,30 @@ import type { PreviewButtonClientProps } from 'payload'
44
import React from 'react'
55

66
import { ExternalLinkIcon } from '../../icons/ExternalLink/index.js'
7-
import { usePreviewURL } from './usePreviewURL.js'
87
import './index.scss'
8+
import { usePreviewURL } from '../../providers/LivePreview/context.js'
9+
import { useTranslation } from '../../providers/Translation/index.js'
910

1011
const baseClass = 'preview-btn'
1112

1213
export function PreviewButton(props: PreviewButtonClientProps) {
13-
const { generatePreviewURL, label } = usePreviewURL()
14+
const { previewURL } = usePreviewURL()
15+
const { t } = useTranslation()
16+
17+
if (!previewURL) {
18+
return null
19+
}
1420

1521
return (
16-
<button
17-
aria-label={label}
22+
<a
23+
aria-label={t('version:preview')}
1824
className={baseClass}
25+
href={previewURL}
1926
id="preview-button"
20-
onClick={() => {
21-
generatePreviewURL({
22-
openPreviewWindow: true,
23-
})
24-
}}
25-
title={label}
26-
type="button"
27+
target="_blank"
28+
title={t('version:preview')}
2729
>
2830
<ExternalLinkIcon />
29-
</button>
31+
</a>
3032
)
3133
}

packages/ui/src/elements/PreviewButton/usePreviewURL.tsx

Lines changed: 0 additions & 100 deletions
This file was deleted.

packages/ui/src/exports/rsc/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export { copyDataFromLocaleHandler } from '../../utilities/copyDataFromLocale.js
1010
export { getColumns } from '../../utilities/getColumns.js'
1111
export { getFolderResultsComponentAndData } from '../../utilities/getFolderResultsComponentAndData.js'
1212
export { handleLivePreview } from '../../utilities/handleLivePreview.js'
13+
export { handlePreview } from '../../utilities/handlePreview.js'
1314
export { renderFilters, renderTable } from '../../utilities/renderTable.js'
1415
export { resolveFilterOptions } from '../../utilities/resolveFilterOptions.js'
1516
export { upsertPreferences } from '../../utilities/upsertPreferences.js'

0 commit comments

Comments
 (0)