feat(live-preview): enable Payload live preview for site settings global

- add  dependency
- configure  in  for
- add  client utility to refresh Next routes on live updates
- mount live preview refresh bridge in frontend layout
- enable drafts/autosave/schedule publish for  global
- regenerate  and update lockfile
This commit is contained in:
Francisco Ignácio Fontoura Solla 2026-02-15 11:13:29 -03:00
parent 56f2d48d8d
commit 375398af84
7 changed files with 195 additions and 2 deletions

View file

@ -35,6 +35,7 @@
},
"dependencies": {
"@payloadcms/db-postgres": "3.76.1",
"@payloadcms/live-preview-react": "^3.76.1",
"@payloadcms/next": "3.76.1",
"@payloadcms/richtext-lexical": "3.76.1",
"@payloadcms/ui": "3.76.1",

View file

@ -11,6 +11,9 @@ importers:
'@payloadcms/db-postgres':
specifier: 3.76.1
version: 3.76.1(payload@3.76.1(graphql@16.12.0)(typescript@5.7.3))
'@payloadcms/live-preview-react':
specifier: ^3.76.1
version: 3.76.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
'@payloadcms/next':
specifier: 3.76.1
version: 3.76.1(@types/react@19.2.9)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.11(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.76.1(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.3)
@ -1360,6 +1363,15 @@ packages:
graphql: ^16.8.1
payload: 3.76.1
'@payloadcms/live-preview-react@3.76.1':
resolution: {integrity: sha512-UwOAi2w2oYzPDncyANxgKkWiXq0KSFN5ajFzT/9IybSWJ1F9N1FIMphTeoEaT58GBHfX8vx/Mbqb8MSmVjh1mA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.1 || ^19.1.2 || ^19.2.1
'@payloadcms/live-preview@3.76.1':
resolution: {integrity: sha512-wD9955QDBlXRONKGsNpeB0Y2FBikUjifnPk2ydrE3vFn4H5X4WLekOc1lVOQ8XhAxn7lj7w3kJaARgjU54uSKQ==}
'@payloadcms/next@3.76.1':
resolution: {integrity: sha512-0d5Irrhr632OToX8hKRqDBZJN/2w9xbJJXcZnGZ73YB67Srcb/UYcdNjItahmCbA9APKqlmK2zihgVoQ5NN2wA==}
engines: {node: ^18.20.2 || >=20.9.0}
@ -5513,6 +5525,14 @@ snapshots:
transitivePeerDependencies:
- typescript
'@payloadcms/live-preview-react@3.76.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)':
dependencies:
'@payloadcms/live-preview': 3.76.1
react: 19.2.1
react-dom: 19.2.1(react@19.2.1)
'@payloadcms/live-preview@3.76.1': {}
'@payloadcms/next@3.76.1(@types/react@19.2.9)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.11(@babel/core@7.29.0)(@playwright/test@1.58.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.76.1(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.3)':
dependencies:
'@dnd-kit/core': 6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)

View file

@ -2,8 +2,10 @@ import { Footer } from '@/components/Footer'
import { Header } from '@/components/Header'
import React from 'react'
import './styles.css'
import { RefreshRouteOnSave } from '@/utilities/RefreshRouteOnSave'
import { Metadata } from 'next'
export const metadata = {
export const metadata: Metadata = {
description: 'Um template base usando Payload em uma aplicação Next.js.',
title: 'Template Base do Payload',
}
@ -14,6 +16,7 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
return (
<html lang="pt-BR">
<body>
<RefreshRouteOnSave />
<Header />
<main>{children}</main>
<Footer />

View file

@ -77,4 +77,13 @@ export const SiteSettings: GlobalConfig = {
hooks: {
afterChange: [revalidate],
},
versions: {
drafts: {
autosave: {
interval: 1000,
},
schedulePublish: true,
},
max: 10,
},
}

View file

@ -70,6 +70,7 @@ export interface Config {
users: User;
media: Media;
'payload-kv': PayloadKv;
'payload-jobs': PayloadJob;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
@ -79,6 +80,7 @@ export interface Config {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
'payload-jobs': PayloadJobsSelect<false> | PayloadJobsSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
@ -96,7 +98,13 @@ export interface Config {
locale: null;
user: User;
jobs: {
tasks: unknown;
tasks: {
schedulePublish: TaskSchedulePublish;
inline: {
input: unknown;
output: unknown;
};
};
workflows: unknown;
};
}
@ -182,6 +190,98 @@ export interface PayloadKv {
| boolean
| null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-jobs".
*/
export interface PayloadJob {
id: number;
/**
* Input data provided to the job
*/
input?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
taskStatus?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
completedAt?: string | null;
totalTried?: number | null;
/**
* If hasError is true this job will not be retried
*/
hasError?: boolean | null;
/**
* If hasError is true, this is the error that caused it
*/
error?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
/**
* Task execution log
*/
log?:
| {
executedAt: string;
completedAt: string;
taskSlug: 'inline' | 'schedulePublish';
taskID: string;
input?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
output?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
state: 'failed' | 'succeeded';
error?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
id?: string | null;
}[]
| null;
taskSlug?: ('inline' | 'schedulePublish') | null;
queue?: string | null;
waitUntil?: string | null;
processing?: boolean | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
@ -287,6 +387,37 @@ export interface PayloadKvSelect<T extends boolean = true> {
key?: T;
data?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-jobs_select".
*/
export interface PayloadJobsSelect<T extends boolean = true> {
input?: T;
taskStatus?: T;
completedAt?: T;
totalTried?: T;
hasError?: T;
error?: T;
log?:
| T
| {
executedAt?: T;
completedAt?: T;
taskSlug?: T;
taskID?: T;
input?: T;
output?: T;
state?: T;
error?: T;
id?: T;
};
taskSlug?: T;
queue?: T;
waitUntil?: T;
processing?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
@ -338,6 +469,7 @@ export interface SiteSetting {
id?: string | null;
}[]
| null;
_status?: ('draft' | 'published') | null;
updatedAt?: string | null;
createdAt?: string | null;
}
@ -356,10 +488,24 @@ export interface SiteSettingsSelect<T extends boolean = true> {
enabled?: T;
id?: T;
};
_status?: T;
updatedAt?: T;
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "TaskSchedulePublish".
*/
export interface TaskSchedulePublish {
input: {
type?: ('publish' | 'unpublish') | null;
locale?: string | null;
global?: 'site-settings' | null;
user?: (number | null) | User;
};
output?: unknown;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".

View file

@ -19,6 +19,10 @@ export default buildConfig({
importMap: {
baseDir: path.resolve(dirname),
},
livePreview: {
url: 'http://localhost:3000',
globals: ['site-settings'],
},
},
collections: [Users, Media],
globals: [SiteSettings],

View file

@ -0,0 +1,10 @@
'use client'
import { RefreshRouteOnSave as PayloadLivePreview } from '@payloadcms/live-preview-react'
import { useRouter } from 'next/navigation.js'
import React from 'react'
export const RefreshRouteOnSave: React.FC = () => {
const router = useRouter()
return <PayloadLivePreview refresh={() => router.refresh()} serverURL="http://localhost:3000" />
}