Skip to content

Commit f19053e

Browse files
authored
fix(next): properly threads field permissions through versions diff (#9543)
The version diff view at `/admin/collections/:collection/:id/versions/:version` was not properly displaying diffs for iterable fields, such as blocks. There were two main things wrong here: 1. Fields not properly inheriting parent permissions based on the new sanitized permissions pattern in #7335 1. The diff components were expecting `permissions` but receiving `fieldPermissions`. This was not picked up by TS because of our use of dynamic keys when choosing which component to render for that particular field. We should change this in the future to use a switch case that explicitly renders each diff component. This way props are strictly typed.
1 parent b616220 commit f19053e

File tree

8 files changed

+114
-17
lines changed

8 files changed

+114
-17
lines changed

packages/next/src/views/Version/RenderFieldsToDiff/fields/Iterable/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ const Iterable: React.FC<DiffComponentProps> = ({
1717
comparison,
1818
diffComponents,
1919
field,
20+
fieldPermissions,
2021
i18n,
2122
locale,
2223
locales,
23-
permissions,
2424
version,
2525
}) => {
2626
const versionRowCount = Array.isArray(version) ? version.length : 0
@@ -86,7 +86,7 @@ const Iterable: React.FC<DiffComponentProps> = ({
8686
<RenderFieldsToDiff
8787
comparison={comparisonRow}
8888
diffComponents={diffComponents}
89-
fieldPermissions={permissions}
89+
fieldPermissions={fieldPermissions}
9090
fields={fields}
9191
i18n={i18n}
9292
locales={locales}

packages/next/src/views/Version/RenderFieldsToDiff/fields/Nested/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ const Nested: React.FC<DiffComponentProps> = ({
1515
diffComponents,
1616
disableGutter = false,
1717
field,
18+
fieldPermissions,
1819
fields,
1920
i18n,
2021
locale,
2122
locales,
22-
permissions,
2323
version,
2424
}) => {
2525
return (
@@ -38,7 +38,7 @@ const Nested: React.FC<DiffComponentProps> = ({
3838
<RenderFieldsToDiff
3939
comparison={comparison}
4040
diffComponents={diffComponents}
41-
fieldPermissions={permissions}
41+
fieldPermissions={fieldPermissions}
4242
fields={fields}
4343
i18n={i18n}
4444
locales={locales}

packages/next/src/views/Version/RenderFieldsToDiff/fields/Tabs/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ const Tabs: React.FC<DiffComponentProps<TabsFieldClient>> = ({
1414
comparison,
1515
diffComponents,
1616
field,
17+
fieldPermissions,
1718
i18n,
1819
locale,
1920
locales,
20-
permissions,
2121
version,
2222
}) => {
2323
return (
@@ -30,12 +30,12 @@ const Tabs: React.FC<DiffComponentProps<TabsFieldClient>> = ({
3030
comparison={comparison?.[tab.name]}
3131
diffComponents={diffComponents}
3232
field={field}
33+
fieldPermissions={fieldPermissions}
3334
fields={tab.fields}
3435
i18n={i18n}
3536
key={i}
3637
locale={locale}
3738
locales={locales}
38-
permissions={permissions}
3939
version={version?.[tab.name]}
4040
/>
4141
)
@@ -45,7 +45,7 @@ const Tabs: React.FC<DiffComponentProps<TabsFieldClient>> = ({
4545
<RenderFieldsToDiff
4646
comparison={comparison}
4747
diffComponents={diffComponents}
48-
fieldPermissions={permissions}
48+
fieldPermissions={fieldPermissions}
4949
fields={tab.fields}
5050
i18n={i18n}
5151
key={i}

packages/next/src/views/Version/RenderFieldsToDiff/fields/types.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ export type DiffComponentProps<TField extends ClientField = ClientField> = {
1111
readonly diffMethod?: DiffMethod
1212
readonly disableGutter?: boolean
1313
readonly field: TField
14+
readonly fieldPermissions?:
15+
| {
16+
[key: string]: SanitizedFieldPermissions
17+
}
18+
| true
1419
readonly fields: ClientField[]
1520
readonly i18n: I18nClient
1621
readonly isRichText?: boolean
1722
readonly locale?: string
1823
readonly locales?: string[]
19-
readonly permissions?:
20-
| {
21-
[key: string]: SanitizedFieldPermissions
22-
}
23-
| true
2424
readonly version: any
2525
}

packages/next/src/views/Version/RenderFieldsToDiff/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ const RenderFieldsToDiff: React.FC<Props> = ({
5757
fieldPermissions?.[fieldName]?.read
5858

5959
const subFieldPermissions =
60-
fieldPermissions?.[fieldName] === true || fieldPermissions?.[fieldName]?.fields
60+
fieldPermissions === true ||
61+
fieldPermissions?.[fieldName] === true ||
62+
fieldPermissions?.[fieldName]?.fields
6163

6264
if (!hasPermission) {
6365
return null
@@ -116,6 +118,7 @@ const RenderFieldsToDiff: React.FC<Props> = ({
116118
comparison={comparison}
117119
diffComponents={diffComponents}
118120
field={field}
121+
fieldPermissions={fieldPermissions}
119122
fields={[]}
120123
i18n={i18n}
121124
key={i}
@@ -133,11 +136,11 @@ const RenderFieldsToDiff: React.FC<Props> = ({
133136
diffComponents={diffComponents}
134137
disableGutter
135138
field={field}
139+
fieldPermissions={fieldPermissions}
136140
fields={field.fields}
137141
i18n={i18n}
138142
key={i}
139143
locales={locales}
140-
permissions={fieldPermissions}
141144
version={version}
142145
/>
143146
)

test/helpers/sdk/index.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
2121
'Content-Type': 'application/json',
2222
}
2323

24-
if (jwt) headers.Authorization = `JWT ${jwt}`
24+
if (jwt) {
25+
headers.Authorization = `JWT ${jwt}`
26+
}
2527

2628
const json: T = await fetch(`${this.serverURL}/api/local-api`, {
2729
method: 'post',
@@ -32,7 +34,9 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
3234
}),
3335
}).then((res) => res.json())
3436

35-
if (reduceJSON) return reduceJSON<T>(json)
37+
if (reduceJSON) {
38+
return reduceJSON<T>(json)
39+
}
3640

3741
return json
3842
}
@@ -70,6 +74,17 @@ export class PayloadTestSDK<TGeneratedTypes extends GeneratedTypes<TGeneratedTyp
7074
})
7175
}
7276

77+
findVersions = async <T extends keyof TGeneratedTypes['collections']>({
78+
jwt,
79+
...args
80+
}: FindArgs<TGeneratedTypes, T>) => {
81+
return this.fetch<PaginatedDocs<TGeneratedTypes['collections'][T]>>({
82+
operation: 'findVersions',
83+
args,
84+
jwt,
85+
})
86+
}
87+
7388
login = async <T extends keyof TGeneratedTypes['collections']>({
7489
jwt,
7590
...args

test/helpers/sdk/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,15 @@ export type GeneratedTypes<T extends BaseTypes> = {
2525
export type FetchOptions = {
2626
args?: Record<string, unknown>
2727
jwt?: string
28-
operation: 'create' | 'delete' | 'find' | 'login' | 'sendEmail' | 'update' | 'updateGlobal'
28+
operation:
29+
| 'create'
30+
| 'delete'
31+
| 'find'
32+
| 'findVersions'
33+
| 'login'
34+
| 'sendEmail'
35+
| 'update'
36+
| 'updateGlobal'
2937
reduceJSON?: <R>(json: any) => R
3038
}
3139

test/versions/e2e.spec.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,4 +734,75 @@ describe('versions', () => {
734734
await expect(publishSpecificLocale).toContainText('English')
735735
})
736736
})
737+
738+
describe('Versions diff view', () => {
739+
let postID: string
740+
let versionID: string
741+
742+
beforeAll(() => {
743+
url = new AdminUrlUtil(serverURL, draftCollectionSlug)
744+
})
745+
746+
beforeEach(async () => {
747+
const newPost = await payload.create({
748+
collection: draftCollectionSlug,
749+
data: {
750+
title: 'new post',
751+
description: 'new description',
752+
},
753+
})
754+
755+
postID = newPost.id
756+
757+
await payload.update({
758+
collection: draftCollectionSlug,
759+
id: postID,
760+
draft: true,
761+
data: {
762+
title: 'draft post',
763+
description: 'draft description',
764+
blocksField: [
765+
{
766+
blockName: 'block1',
767+
blockType: 'block',
768+
text: 'block text',
769+
},
770+
],
771+
},
772+
})
773+
774+
const versions = await payload.findVersions({
775+
collection: draftCollectionSlug,
776+
where: {
777+
parent: { equals: postID },
778+
},
779+
})
780+
781+
versionID = versions.docs[0].id
782+
})
783+
784+
test('should render diff', async () => {
785+
const versionURL = `${serverURL}/admin/collections/${draftCollectionSlug}/${postID}/versions/${versionID}`
786+
await page.goto(versionURL)
787+
await page.waitForURL(versionURL)
788+
await expect(page.locator('.render-field-diffs').first()).toBeVisible()
789+
})
790+
791+
test('should render diff for nested fields', async () => {
792+
const versionURL = `${serverURL}/admin/collections/${draftCollectionSlug}/${postID}/versions/${versionID}`
793+
await page.goto(versionURL)
794+
await page.waitForURL(versionURL)
795+
await expect(page.locator('.render-field-diffs').first()).toBeVisible()
796+
797+
const blocksDiffLabel = page.locator('.field-diff-label', {
798+
hasText: exactText('Blocks Field'),
799+
})
800+
801+
await expect(blocksDiffLabel).toBeVisible()
802+
const blocksDiff = blocksDiffLabel.locator('+ .iterable-diff__wrap > .render-field-diffs')
803+
await expect(blocksDiff).toBeVisible()
804+
const blockTypeDiffLabel = blocksDiff.locator('.render-field-diffs__field').first()
805+
await expect(blockTypeDiffLabel).toBeVisible()
806+
})
807+
})
737808
})

0 commit comments

Comments
 (0)