Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions docs/admin/preview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
preview: ({ slug, collection }) => {
preview: ({ slug }) => {
const encodedParams = new URLSearchParams({
slug,
collection,
collection: 'pages',
path: `/${slug}`,
previewSecret: process.env.PREVIEW_SECRET || '',
})
Expand Down Expand Up @@ -231,3 +231,32 @@ export default async function Page({ params: paramsPromise }) {
in the [Examples
Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>

### Conditional Preview URLs

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.

To do this, simply return `null` from the `preview` function when you want to hide the preview button:

```ts
import type { CollectionConfig } from 'payload'

export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
preview: (doc) => {
return doc?.enabled ? `http://localhost:3000/${doc.slug}` : null
},
},
fields: [
{
name: 'slug',
type: 'text',
},
{
name: 'enabled',
type: 'checkbox',
},
],
}
```
13 changes: 12 additions & 1 deletion packages/next/src/views/Document/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
LivePreviewProvider,
} from '@payloadcms/ui'
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
import { handleLivePreview } from '@payloadcms/ui/rsc'
import { handleLivePreview, handlePreview } from '@payloadcms/ui/rsc'
import { isEditing as getIsEditing } from '@payloadcms/ui/shared'
import { buildFormState } from '@payloadcms/ui/utilities/buildFormState'
import { notFound, redirect } from 'next/navigation.js'
Expand Down Expand Up @@ -360,6 +360,15 @@ export const renderDocument = async ({
req,
})

const { isPreviewEnabled, previewURL } = await handlePreview({
collectionSlug,
config,
data: doc,
globalSlug,
operation,
req,
})

return {
data: doc,
Document: (
Expand Down Expand Up @@ -395,6 +404,8 @@ export const renderDocument = async ({
isLivePreviewing={Boolean(
entityPreferences?.value?.editViewType === 'live-preview' && livePreviewURL,
)}
isPreviewEnabled={Boolean(isPreviewEnabled)}
previewURL={previewURL}
typeofLivePreviewURL={typeof livePreviewConfig?.url as 'function' | 'string' | undefined}
url={livePreviewURL}
>
Expand Down
6 changes: 6 additions & 0 deletions packages/payload/src/admin/forms/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ export type BuildFormStateArgs = {
*/
returnLivePreviewURL?: boolean
returnLockStatus?: boolean
/**
* If true, will return a fresh URL for preview based on the current form state.
* Note: this will run on every form state event, so if your `preview` function is long running or expensive,
* ensure it caches itself as needed.
*/
returnPreviewURL?: boolean
schemaPath: string
select?: SelectType
/**
Expand Down
6 changes: 0 additions & 6 deletions packages/payload/src/collections/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { findByIDHandler } from './findByID.js'
// import { findDistinctHandler } from './findDistinct.js'
import { findVersionByIDHandler } from './findVersionByID.js'
import { findVersionsHandler } from './findVersions.js'
import { previewHandler } from './preview.js'
import { restoreVersionHandler } from './restoreVersion.js'
import { updateHandler } from './update.js'
import { updateByIDHandler } from './updateByID.js'
Expand Down Expand Up @@ -75,11 +74,6 @@ export const defaultCollectionEndpoints: Endpoint[] = [
method: 'get',
path: '/versions/:id',
},
{
handler: previewHandler,
method: 'get',
path: '/:id/preview',
},
{
handler: restoreVersionHandler,
method: 'post',
Expand Down
47 changes: 0 additions & 47 deletions packages/payload/src/collections/endpoints/preview.ts

This file was deleted.

6 changes: 0 additions & 6 deletions packages/payload/src/globals/endpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { docAccessHandler } from './docAccess.js'
import { findOneHandler } from './findOne.js'
import { findVersionByIDHandler } from './findVersionByID.js'
import { findVersionsHandler } from './findVersions.js'
import { previewHandler } from './preview.js'
import { restoreVersionHandler } from './restoreVersion.js'
import { updateHandler } from './update.js'

Expand All @@ -30,11 +29,6 @@ export const defaultGlobalEndpoints: Endpoint[] = wrapInternalEndpoints([
method: 'get',
path: '/versions',
},
{
handler: previewHandler,
method: 'get',
path: '/preview',
},
{
handler: restoreVersionHandler,
method: 'post',
Expand Down
47 changes: 0 additions & 47 deletions packages/payload/src/globals/endpoints/preview.ts

This file was deleted.

26 changes: 14 additions & 12 deletions packages/ui/src/elements/PreviewButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,30 @@ import type { PreviewButtonClientProps } from 'payload'
import React from 'react'

import { ExternalLinkIcon } from '../../icons/ExternalLink/index.js'
import { usePreviewURL } from './usePreviewURL.js'
import './index.scss'
import { usePreviewURL } from '../../providers/LivePreview/context.js'
import { useTranslation } from '../../providers/Translation/index.js'

const baseClass = 'preview-btn'

export function PreviewButton(props: PreviewButtonClientProps) {
const { generatePreviewURL, label } = usePreviewURL()
const { previewURL } = usePreviewURL()
const { t } = useTranslation()

if (!previewURL) {
return null
}

return (
<button
aria-label={label}
<a
aria-label={t('version:preview')}
className={baseClass}
href={previewURL}
id="preview-button"
onClick={() => {
generatePreviewURL({
openPreviewWindow: true,
})
}}
title={label}
type="button"
target="_blank"
title={t('version:preview')}
>
<ExternalLinkIcon />
</button>
</a>
)
}
100 changes: 0 additions & 100 deletions packages/ui/src/elements/PreviewButton/usePreviewURL.tsx

This file was deleted.

1 change: 1 addition & 0 deletions packages/ui/src/exports/rsc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { copyDataFromLocaleHandler } from '../../utilities/copyDataFromLocale.js
export { getColumns } from '../../utilities/getColumns.js'
export { getFolderResultsComponentAndData } from '../../utilities/getFolderResultsComponentAndData.js'
export { handleLivePreview } from '../../utilities/handleLivePreview.js'
export { handlePreview } from '../../utilities/handlePreview.js'
export { renderFilters, renderTable } from '../../utilities/renderTable.js'
export { resolveFilterOptions } from '../../utilities/resolveFilterOptions.js'
export { upsertPreferences } from '../../utilities/upsertPreferences.js'
Loading
Loading