Skip to content

Commit 00771b1

Browse files
authored
fix(ui): uploading from drawer & focal point positioning (#7117)
Fixes #7101 Fixes #7006 Drawers were sending duplicate query params. This new approach modeled after the fix in V2, ensures that each drawer has its own action url created per document and the query params will be created when that is generated. Also fixes the following: - incorrect focal point cropping - generated filenames for animated image names used incorrect heights
1 parent 448186f commit 00771b1

File tree

21 files changed

+460
-392
lines changed

21 files changed

+460
-392
lines changed

docs/migration-guide/overview.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ import {
180180
useFormInitializing,
181181
useFormModified,
182182
useFormProcessing,
183-
useFormQueryParams,
184183
useFormSubmitted,
185184
useHotkey,
186185
useIntersect,
@@ -221,7 +220,6 @@ import {
221220
EntityVisibilityProvider,
222221
FieldComponentsProvider,
223222
FieldPropsProvider,
224-
FormQueryParamsProvider,
225223
ListInfoProvider,
226224
ListQueryProvider,
227225
LocaleProvider,

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

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { AdminViewProps, ServerSideEditViewProps } from 'payload'
22

3-
import { DocumentInfoProvider, FormQueryParamsProvider, HydrateClientUser } from '@payloadcms/ui'
3+
import { DocumentInfoProvider, HydrateClientUser } from '@payloadcms/ui'
44
import { RenderCustomComponent } from '@payloadcms/ui/shared'
55
import { notFound } from 'next/navigation.js'
66
import React from 'react'
@@ -65,7 +65,6 @@ export const Account: React.FC<AdminViewProps> = async ({
6565
return (
6666
<DocumentInfoProvider
6767
AfterFields={<Settings i18n={i18n} languageOptions={languageOptions} />}
68-
action={`${serverURL}${api}/${userSlug}${user?.id ? `/${user.id}` : ''}`}
6968
apiURL={`${serverURL}${api}/${userSlug}${user?.id ? `/${user.id}` : ''}`}
7069
collectionSlug={userSlug}
7170
docPermissions={docPermissions}
@@ -84,31 +83,22 @@ export const Account: React.FC<AdminViewProps> = async ({
8483
permissions={permissions}
8584
/>
8685
<HydrateClientUser permissions={permissions} user={user} />
87-
<FormQueryParamsProvider
88-
initialParams={{
89-
depth: 0,
90-
'fallback-locale': 'null',
91-
locale: locale?.code,
92-
uploadEdits: undefined,
86+
<RenderCustomComponent
87+
CustomComponent={
88+
typeof CustomAccountComponent === 'function' ? CustomAccountComponent : undefined
89+
}
90+
DefaultComponent={EditView}
91+
componentProps={viewComponentProps}
92+
serverOnlyProps={{
93+
i18n,
94+
locale,
95+
params,
96+
payload,
97+
permissions,
98+
searchParams,
99+
user,
93100
}}
94-
>
95-
<RenderCustomComponent
96-
CustomComponent={
97-
typeof CustomAccountComponent === 'function' ? CustomAccountComponent : undefined
98-
}
99-
DefaultComponent={EditView}
100-
componentProps={viewComponentProps}
101-
serverOnlyProps={{
102-
i18n,
103-
locale,
104-
params,
105-
payload,
106-
permissions,
107-
searchParams,
108-
user,
109-
}}
110-
/>
111-
</FormQueryParamsProvider>
101+
/>
112102
</DocumentInfoProvider>
113103
)
114104
}

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

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
1-
import type {
2-
AdminViewComponent,
3-
AdminViewProps,
4-
EditViewComponent,
5-
ServerSideEditViewProps,
6-
} from 'payload'
1+
import type { AdminViewComponent, AdminViewProps, EditViewComponent } from 'payload'
72

8-
import {
9-
DocumentInfoProvider,
10-
EditDepthProvider,
11-
FormQueryParamsProvider,
12-
HydrateClientUser,
13-
} from '@payloadcms/ui'
3+
import { DocumentInfoProvider, EditDepthProvider, HydrateClientUser } from '@payloadcms/ui'
144
import { RenderCustomComponent, isEditing as getIsEditing } from '@payloadcms/ui/shared'
155
import { notFound, redirect } from 'next/navigation.js'
166
import React from 'react'
@@ -65,7 +55,6 @@ export const Document: React.FC<AdminViewProps> = async ({
6555
let ErrorView: AdminViewComponent
6656

6757
let apiURL: string
68-
let action: string
6958

7059
const { data, formState } = await getDocumentData({
7160
id,
@@ -88,8 +77,6 @@ export const Document: React.FC<AdminViewProps> = async ({
8877
notFound()
8978
}
9079

91-
action = `${serverURL}${apiRoute}/${collectionSlug}${isEditing ? `/${id}` : ''}`
92-
9380
const params = new URLSearchParams()
9481
if (collectionConfig.versions?.drafts) {
9582
params.append('draft', 'true')
@@ -128,8 +115,6 @@ export const Document: React.FC<AdminViewProps> = async ({
128115
notFound()
129116
}
130117

131-
action = `${serverURL}${apiRoute}/globals/${globalSlug}`
132-
133118
const params = new URLSearchParams({
134119
locale: locale?.code,
135120
})
@@ -198,7 +183,6 @@ export const Document: React.FC<AdminViewProps> = async ({
198183

199184
return (
200185
<DocumentInfoProvider
201-
action={action}
202186
apiURL={apiURL}
203187
collectionSlug={collectionConfig?.slug}
204188
disableActions={false}
@@ -225,34 +209,25 @@ export const Document: React.FC<AdminViewProps> = async ({
225209
depth={1}
226210
key={`${collectionSlug || globalSlug}${locale?.code ? `-${locale?.code}` : ''}`}
227211
>
228-
<FormQueryParamsProvider
229-
initialParams={{
230-
depth: 0,
231-
'fallback-locale': 'null',
232-
locale: locale?.code,
233-
uploadEdits: undefined,
234-
}}
235-
>
236-
{ErrorView ? (
237-
<ErrorView initPageResult={initPageResult} searchParams={searchParams} />
238-
) : (
239-
<RenderCustomComponent
240-
CustomComponent={ViewOverride || CustomView}
241-
DefaultComponent={DefaultView}
242-
serverOnlyProps={{
243-
i18n,
244-
initPageResult,
245-
locale,
246-
params,
247-
payload,
248-
permissions,
249-
routeSegments: segments,
250-
searchParams,
251-
user,
252-
}}
253-
/>
254-
)}
255-
</FormQueryParamsProvider>
212+
{ErrorView ? (
213+
<ErrorView initPageResult={initPageResult} searchParams={searchParams} />
214+
) : (
215+
<RenderCustomComponent
216+
CustomComponent={ViewOverride || CustomView}
217+
DefaultComponent={DefaultView}
218+
serverOnlyProps={{
219+
i18n,
220+
initPageResult,
221+
locale,
222+
params,
223+
payload,
224+
permissions,
225+
routeSegments: segments,
226+
searchParams,
227+
user,
228+
}}
229+
/>
230+
)}
256231
</EditDepthProvider>
257232
</DocumentInfoProvider>
258233
)

packages/next/src/views/Edit/Default/index.tsx

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
useDocumentEvents,
1414
useDocumentInfo,
1515
useEditDepth,
16-
useFormQueryParams,
16+
useUploadEdits,
1717
} from '@payloadcms/ui'
1818
import { getFormState } from '@payloadcms/ui/shared'
1919
import { useRouter, useSearchParams } from 'next/navigation.js'
@@ -58,11 +58,13 @@ export const DefaultEditView: React.FC = () => {
5858
const { refreshCookieAsync, user } = useAuth()
5959
const config = useConfig()
6060
const router = useRouter()
61-
const { dispatchFormQueryParams } = useFormQueryParams()
6261
const { getComponentMap, getFieldMap } = useComponentMap()
63-
const params = useSearchParams()
6462
const depth = useEditDepth()
63+
const params = useSearchParams()
6564
const { reportUpdate } = useDocumentEvents()
65+
const { resetUploadEdits } = useUploadEdits()
66+
67+
const locale = params.get('locale')
6668

6769
const {
6870
admin: { user: userSlug },
@@ -72,8 +74,6 @@ export const DefaultEditView: React.FC = () => {
7274
serverURL,
7375
} = config
7476

75-
const locale = params.get('locale')
76-
7777
const collectionConfig =
7878
collectionSlug && collections.find((collection) => collection.slug === collectionSlug)
7979

@@ -130,12 +130,7 @@ export const DefaultEditView: React.FC = () => {
130130
const redirectRoute = `${adminRoute}/collections/${collectionSlug}/${json?.doc?.id}${locale ? `?locale=${locale}` : ''}`
131131
router.push(redirectRoute)
132132
} else {
133-
dispatchFormQueryParams({
134-
type: 'SET',
135-
params: {
136-
uploadEdits: null,
137-
},
138-
})
133+
resetUploadEdits()
139134
}
140135
},
141136
[
@@ -151,9 +146,9 @@ export const DefaultEditView: React.FC = () => {
151146
isEditing,
152147
refreshCookieAsync,
153148
adminRoute,
154-
locale,
155149
router,
156-
dispatchFormQueryParams,
150+
locale,
151+
resetUploadEdits,
157152
],
158153
)
159154

packages/payload/src/uploads/cropImage.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
import type { SharpOptions } from 'sharp'
22

3+
import type { SanitizedConfig } from '../config/types.js'
4+
import type { PayloadRequest } from '../types/index.js'
5+
import type { UploadEdits } from './types.js'
6+
37
export const percentToPixel = (value, dimension) => {
48
return Math.floor((parseFloat(value) / 100) * dimension)
59
}
610

7-
export async function cropImage({ cropData, dimensions, file, sharp }) {
11+
type CropImageArgs = {
12+
cropData: UploadEdits['crop']
13+
dimensions: { height: number; width: number }
14+
file: PayloadRequest['file']
15+
heightInPixels: number
16+
sharp: SanitizedConfig['sharp']
17+
widthInPixels: number
18+
}
19+
export async function cropImage({
20+
cropData,
21+
dimensions,
22+
file,
23+
heightInPixels,
24+
sharp,
25+
widthInPixels,
26+
}: CropImageArgs) {
827
try {
9-
const { heightPixels, widthPixels, x, y } = cropData
28+
const { x, y } = cropData
1029

1130
const fileIsAnimatedType = ['image/avif', 'image/gif', 'image/webp'].includes(file.mimetype)
1231

@@ -15,10 +34,10 @@ export async function cropImage({ cropData, dimensions, file, sharp }) {
1534
if (fileIsAnimatedType) sharpOptions.animated = true
1635

1736
const formattedCropData = {
18-
height: Number(heightPixels),
37+
height: Number(heightInPixels),
1938
left: percentToPixel(x, dimensions.width),
2039
top: percentToPixel(y, dimensions.height),
21-
width: Number(widthPixels),
40+
width: Number(widthInPixels),
2241
}
2342

2443
const cropped = sharp(file.tempFilePath || file.data, sharpOptions).extract(formattedCropData)

packages/payload/src/uploads/generateFileData.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,14 @@ export const generateFileData = async <T>({
203203
let fileForResize = file
204204

205205
if (cropData && sharp) {
206-
const { data: croppedImage, info } = await cropImage({ cropData, dimensions, file, sharp })
206+
const { data: croppedImage, info } = await cropImage({
207+
cropData,
208+
dimensions,
209+
file,
210+
heightInPixels: uploadEdits.heightInPixels,
211+
sharp,
212+
widthInPixels: uploadEdits.widthInPixels,
213+
})
207214

208215
filesToSave.push({
209216
buffer: croppedImage,

0 commit comments

Comments
 (0)