feat(ui): allows customizing version diff components, render versions ui on the server (#10815)

This PR moves the logic for rendering diff field components in the
version comparison view from the client to the server.

This allows us to expose more customization options to the server-side
Payload Config. For example, users can now pass their own diff
components for fields - even including RSCs.

This PR also cleans up the version view types

Implements the following from
https://github.com/payloadcms/payload/discussions/4197:
- allow for customization of diff components
- more control over versions screens in general

TODO:
- [x] Bring getFieldPaths fixes into core
- [x] Cleanup and test with scrutiny. Ensure all field types display
their diffs correctly
- [x] Review public API for overriding field types, add docs
- [x] Add e2e test for new public API
This commit is contained in:
Alessio Gravili
2025-01-28 15:17:24 -07:00
committed by GitHub
parent 33ac13df28
commit c562fbfa94
70 changed files with 11006 additions and 3702 deletions

View File

@@ -19,6 +19,8 @@ export interface Config {
'localized-posts': LocalizedPost;
'version-posts': VersionPost;
'custom-ids': CustomId;
diff: Diff;
media: Media;
users: User;
'payload-jobs': PayloadJob;
'payload-locked-documents': PayloadLockedDocument;
@@ -35,6 +37,8 @@ export interface Config {
'localized-posts': LocalizedPostsSelect<false> | LocalizedPostsSelect<true>;
'version-posts': VersionPostsSelect<false> | VersionPostsSelect<true>;
'custom-ids': CustomIdsSelect<false> | CustomIdsSelect<true>;
diff: DiffSelect<false> | DiffSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
users: UsersSelect<false> | UsersSelect<true>;
'payload-jobs': PayloadJobsSelect<false> | PayloadJobsSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
@@ -208,6 +212,102 @@ export interface CustomId {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "diff".
*/
export interface Diff {
id: string;
array?:
| {
textInArray?: string | null;
id?: string | null;
}[]
| null;
blocks?:
| {
textInBlock?: string | null;
id?: string | null;
blockName?: string | null;
blockType: 'TextBlock';
}[]
| null;
checkbox?: boolean | null;
code?: string | null;
textInCollapsible?: string | null;
date?: string | null;
email?: string | null;
group?: {
textInGroup?: string | null;
};
number?: number | null;
/**
* @minItems 2
* @maxItems 2
*/
point?: [number, number] | null;
radio?: ('option1' | 'option2') | null;
relationship?: (string | null) | DraftPost;
richtext?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
richtextWithCustomDiff?: {
root: {
type: string;
children: {
type: string;
version: number;
[k: string]: unknown;
}[];
direction: ('ltr' | 'rtl') | null;
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
indent: number;
version: number;
};
[k: string]: unknown;
} | null;
textInRow?: string | null;
select?: ('option1' | 'option2') | null;
namedTab1?: {
textInNamedTab1?: string | null;
};
textInUnnamedTab2?: string | null;
text?: string | null;
textArea?: string | null;
upload?: (string | null) | Media;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
@@ -356,6 +456,14 @@ export interface PayloadLockedDocument {
relationTo: 'custom-ids';
value: string | CustomId;
} | null)
| ({
relationTo: 'diff';
value: string | Diff;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null)
| ({
relationTo: 'users';
value: string | User;
@@ -522,6 +630,75 @@ export interface CustomIdsSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "diff_select".
*/
export interface DiffSelect<T extends boolean = true> {
array?:
| T
| {
textInArray?: T;
id?: T;
};
blocks?:
| T
| {
TextBlock?:
| T
| {
textInBlock?: T;
id?: T;
blockName?: T;
};
};
checkbox?: T;
code?: T;
textInCollapsible?: T;
date?: T;
email?: T;
group?:
| T
| {
textInGroup?: T;
};
number?: T;
point?: T;
radio?: T;
relationship?: T;
richtext?: T;
richtextWithCustomDiff?: T;
textInRow?: T;
select?: T;
namedTab1?:
| T
| {
textInNamedTab1?: T;
};
textInUnnamedTab2?: T;
text?: T;
textArea?: T;
upload?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".