fix(ui): field bulk upload showing stale data (#13006)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { useRouter, useSearchParams } from 'next/navigation.js'
|
||||
import { formatAdminURL } from 'payload/shared'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
|
||||
import type { EditFormProps } from './types.js'
|
||||
@@ -12,9 +10,7 @@ import { WatchChildErrors } from '../../../forms/WatchChildErrors/index.js'
|
||||
import { useConfig } from '../../../providers/Config/index.js'
|
||||
import { useDocumentEvents } from '../../../providers/DocumentEvents/index.js'
|
||||
import { useDocumentInfo } from '../../../providers/DocumentInfo/index.js'
|
||||
import { useEditDepth } from '../../../providers/EditDepth/index.js'
|
||||
import { OperationProvider } from '../../../providers/Operation/index.js'
|
||||
import { useRouteTransition } from '../../../providers/RouteTransition/index.js'
|
||||
import { useServerFunctions } from '../../../providers/ServerFunctions/index.js'
|
||||
import { abortAndIgnore, handleAbortRef } from '../../../utilities/abortAndIgnore.js'
|
||||
import { useDocumentDrawerContext } from '../../DocumentDrawer/Provider.js'
|
||||
@@ -23,7 +19,6 @@ import { MoveDocToFolder } from '../../FolderView/MoveDocToFolder/index.js'
|
||||
import { Upload_v4 } from '../../Upload/index.js'
|
||||
import { useFormsManager } from '../FormsManager/index.js'
|
||||
import './index.scss'
|
||||
import { BulkUploadProvider } from '../index.js'
|
||||
|
||||
const baseClass = 'collection-edit'
|
||||
|
||||
@@ -44,7 +39,6 @@ export function EditForm({
|
||||
getDocPreferences,
|
||||
hasSavePermission,
|
||||
initialState,
|
||||
isEditing,
|
||||
isInitializing,
|
||||
Upload: CustomUpload,
|
||||
} = useDocumentInfo()
|
||||
@@ -54,23 +48,14 @@ export function EditForm({
|
||||
const { getFormState } = useServerFunctions()
|
||||
|
||||
const {
|
||||
config: {
|
||||
folders,
|
||||
routes: { admin: adminRoute },
|
||||
},
|
||||
config: { folders },
|
||||
getEntityConfig,
|
||||
} = useConfig()
|
||||
|
||||
const abortOnChangeRef = React.useRef<AbortController>(null)
|
||||
|
||||
const collectionConfig = getEntityConfig({ collectionSlug: docSlug })
|
||||
const router = useRouter()
|
||||
const depth = useEditDepth()
|
||||
const params = useSearchParams()
|
||||
const { reportUpdate } = useDocumentEvents()
|
||||
const { startRouteTransition } = useRouteTransition()
|
||||
|
||||
const locale = params.get('locale')
|
||||
|
||||
const collectionSlug = collectionConfig.slug
|
||||
|
||||
@@ -89,31 +74,9 @@ export function EditForm({
|
||||
operation: 'create',
|
||||
})
|
||||
}
|
||||
|
||||
if (!isEditing && depth < 2) {
|
||||
// Redirect to the same locale if it's been set
|
||||
const redirectRoute = formatAdminURL({
|
||||
adminRoute,
|
||||
path: `/collections/${collectionSlug}/${json?.doc?.id}${locale ? `?locale=${locale}` : ''}`,
|
||||
})
|
||||
|
||||
startRouteTransition(() => router.push(redirectRoute))
|
||||
} else {
|
||||
resetUploadEdits()
|
||||
}
|
||||
resetUploadEdits()
|
||||
},
|
||||
[
|
||||
adminRoute,
|
||||
collectionSlug,
|
||||
depth,
|
||||
isEditing,
|
||||
locale,
|
||||
onSaveFromContext,
|
||||
reportUpdate,
|
||||
resetUploadEdits,
|
||||
router,
|
||||
startRouteTransition,
|
||||
],
|
||||
[collectionSlug, onSaveFromContext, reportUpdate, resetUploadEdits],
|
||||
)
|
||||
|
||||
const onChange: NonNullable<FormProps['onChange']>[0] = useCallback(
|
||||
@@ -150,54 +113,52 @@ export function EditForm({
|
||||
|
||||
return (
|
||||
<OperationProvider operation="create">
|
||||
<BulkUploadProvider>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={isInitializing || !hasSavePermission}
|
||||
initialState={isInitializing ? undefined : initialState}
|
||||
isInitializing={isInitializing}
|
||||
method="POST"
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
submitted={submitted}
|
||||
>
|
||||
<DocumentFields
|
||||
BeforeFields={
|
||||
<React.Fragment>
|
||||
{CustomUpload || (
|
||||
<Upload_v4
|
||||
collectionSlug={collectionConfig.slug}
|
||||
customActions={[
|
||||
folders && collectionConfig.folders && (
|
||||
<MoveDocToFolder
|
||||
buttonProps={{
|
||||
buttonStyle: 'pill',
|
||||
size: 'small',
|
||||
}}
|
||||
folderCollectionSlug={folders.slug}
|
||||
folderFieldName={folders.fieldName}
|
||||
key="move-doc-to-folder"
|
||||
/>
|
||||
),
|
||||
].filter(Boolean)}
|
||||
initialState={initialState}
|
||||
resetUploadEdits={resetUploadEdits}
|
||||
updateUploadEdits={updateUploadEdits}
|
||||
uploadConfig={collectionConfig.upload}
|
||||
uploadEdits={uploadEdits}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
}
|
||||
docPermissions={docPermissions}
|
||||
fields={collectionConfig.fields}
|
||||
schemaPathSegments={[collectionConfig.slug]}
|
||||
/>
|
||||
<ReportAllErrors />
|
||||
<GetFieldProxy />
|
||||
</Form>
|
||||
</BulkUploadProvider>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={isInitializing || !hasSavePermission}
|
||||
initialState={isInitializing ? undefined : initialState}
|
||||
isInitializing={isInitializing}
|
||||
method="POST"
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
submitted={submitted}
|
||||
>
|
||||
<DocumentFields
|
||||
BeforeFields={
|
||||
<React.Fragment>
|
||||
{CustomUpload || (
|
||||
<Upload_v4
|
||||
collectionSlug={collectionConfig.slug}
|
||||
customActions={[
|
||||
folders && collectionConfig.folders && (
|
||||
<MoveDocToFolder
|
||||
buttonProps={{
|
||||
buttonStyle: 'pill',
|
||||
size: 'small',
|
||||
}}
|
||||
folderCollectionSlug={folders.slug}
|
||||
folderFieldName={folders.fieldName}
|
||||
key="move-doc-to-folder"
|
||||
/>
|
||||
),
|
||||
].filter(Boolean)}
|
||||
initialState={initialState}
|
||||
resetUploadEdits={resetUploadEdits}
|
||||
updateUploadEdits={updateUploadEdits}
|
||||
uploadConfig={collectionConfig.upload}
|
||||
uploadEdits={uploadEdits}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
}
|
||||
docPermissions={docPermissions}
|
||||
fields={collectionConfig.fields}
|
||||
schemaPathSegments={[collectionConfig.slug]}
|
||||
/>
|
||||
<ReportAllErrors />
|
||||
<GetFieldProxy />
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@ import type { FormProps } from '../../../forms/Form/index.js'
|
||||
import type { OnFieldSelect } from '../../FieldSelect/index.js'
|
||||
import type { FieldOption } from '../../FieldSelect/reduceFieldOptions.js'
|
||||
import type { State } from '../FormsManager/reducer.js'
|
||||
import type { EditManyBulkUploadsProps } from './index.js'
|
||||
|
||||
import { Button } from '../../../elements/Button/index.js'
|
||||
import { Form } from '../../../forms/Form/index.js'
|
||||
import { FieldPathContext } from '../../../forms/RenderFields/context.js'
|
||||
import { RenderField } from '../../../forms/RenderFields/RenderField.js'
|
||||
import { XIcon } from '../../../icons/X/index.js'
|
||||
import { useAuth } from '../../../providers/Auth/index.js'
|
||||
@@ -22,7 +24,7 @@ import { useTranslation } from '../../../providers/Translation/index.js'
|
||||
import { abortAndIgnore, handleAbortRef } from '../../../utilities/abortAndIgnore.js'
|
||||
import { FieldSelect } from '../../FieldSelect/index.js'
|
||||
import { useFormsManager } from '../FormsManager/index.js'
|
||||
import { baseClass, type EditManyBulkUploadsProps } from './index.js'
|
||||
import { baseClass } from './index.js'
|
||||
import './index.scss'
|
||||
import '../../../forms/RenderFields/index.scss'
|
||||
|
||||
@@ -169,23 +171,25 @@ export const EditManyBulkUploadsDrawerContent: React.FC<
|
||||
/>
|
||||
{selectedFields.length === 0 ? null : (
|
||||
<div className="render-fields">
|
||||
{selectedFields.map((option, i) => {
|
||||
const {
|
||||
value: { field, fieldPermissions, path },
|
||||
} = option
|
||||
<FieldPathContext value={undefined}>
|
||||
{selectedFields.map((option, i) => {
|
||||
const {
|
||||
value: { field, fieldPermissions, path },
|
||||
} = option
|
||||
|
||||
return (
|
||||
<RenderField
|
||||
clientFieldConfig={field}
|
||||
indexPath=""
|
||||
key={`${path}-${i}`}
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path={path}
|
||||
permissions={fieldPermissions}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
return (
|
||||
<RenderField
|
||||
clientFieldConfig={field}
|
||||
indexPath=""
|
||||
key={`${path}-${i}`}
|
||||
parentPath=""
|
||||
parentSchemaPath=""
|
||||
path={path}
|
||||
permissions={fieldPermissions}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</FieldPathContext>
|
||||
</div>
|
||||
)}
|
||||
<div className={`${baseClass}__sidebar-wrap`}>
|
||||
|
||||
@@ -118,7 +118,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) {
|
||||
|
||||
const { toggleLoadingOverlay } = useLoadingOverlay()
|
||||
const { closeModal } = useModal()
|
||||
const { collectionSlug, drawerSlug, initialFiles, onSuccess } = useBulkUpload()
|
||||
const { collectionSlug, drawerSlug, initialFiles, onSuccess, setInitialFiles } = useBulkUpload()
|
||||
|
||||
const [isUploading, setIsUploading] = React.useState(false)
|
||||
const [loadingText, setLoadingText] = React.useState('')
|
||||
@@ -366,13 +366,10 @@ export function FormsManagerProvider({ children }: FormsManagerProps) {
|
||||
setIsUploading(false)
|
||||
|
||||
const remainingForms = []
|
||||
const thumbnailIndexesToRemove = []
|
||||
|
||||
currentForms.forEach(({ errorCount }, i) => {
|
||||
if (errorCount) {
|
||||
remainingForms.push(currentForms[i])
|
||||
} else {
|
||||
thumbnailIndexesToRemove.push(i)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -401,8 +398,13 @@ export function FormsManagerProvider({ children }: FormsManagerProps) {
|
||||
totalErrorCount: remainingForms.reduce((acc, { errorCount }) => acc + errorCount, 0),
|
||||
},
|
||||
})
|
||||
|
||||
if (remainingForms.length === 0) {
|
||||
setInitialFiles(undefined)
|
||||
}
|
||||
},
|
||||
[
|
||||
setInitialFiles,
|
||||
actionURL,
|
||||
collectionSlug,
|
||||
getUploadHandler,
|
||||
|
||||
@@ -89,61 +89,57 @@ export function BulkUploadDrawer() {
|
||||
|
||||
type BulkUploadContext = {
|
||||
collectionSlug: string
|
||||
currentActivePath: string
|
||||
drawerSlug: string
|
||||
initialFiles: FileList
|
||||
maxFiles: number
|
||||
onCancel: () => void
|
||||
onSuccess: (newDocs: JsonObject[], errorCount: number) => void
|
||||
setCollectionSlug: (slug: string) => void
|
||||
setCurrentActivePath: (path: string) => void
|
||||
setInitialFiles: (files: FileList) => void
|
||||
setMaxFiles: (maxFiles: number) => void
|
||||
setOnCancel: (onCancel: BulkUploadContext['onCancel']) => void
|
||||
setOnSuccess: (path: string, onSuccess: BulkUploadContext['onSuccess']) => void
|
||||
setOnSuccess: (onSuccess: BulkUploadContext['onSuccess']) => void
|
||||
}
|
||||
|
||||
const Context = React.createContext<BulkUploadContext>({
|
||||
collectionSlug: '',
|
||||
currentActivePath: undefined,
|
||||
drawerSlug: '',
|
||||
initialFiles: undefined,
|
||||
maxFiles: undefined,
|
||||
onCancel: () => null,
|
||||
onSuccess: () => null,
|
||||
setCollectionSlug: () => null,
|
||||
setCurrentActivePath: () => null,
|
||||
setInitialFiles: () => null,
|
||||
setMaxFiles: () => null,
|
||||
setOnCancel: () => null,
|
||||
setOnSuccess: () => null,
|
||||
})
|
||||
export function BulkUploadProvider({ children }: { readonly children: React.ReactNode }) {
|
||||
export function BulkUploadProvider({
|
||||
children,
|
||||
drawerSlugPrefix,
|
||||
}: {
|
||||
readonly children: React.ReactNode
|
||||
readonly drawerSlugPrefix?: string
|
||||
}) {
|
||||
const [collection, setCollection] = React.useState<string>()
|
||||
const [onSuccessFunctionMap, setOnSuccessFunctionMap] =
|
||||
React.useState<Record<string, BulkUploadContext['onSuccess']>>()
|
||||
const [onSuccessFunction, setOnSuccessFunction] = React.useState<BulkUploadContext['onSuccess']>()
|
||||
const [onCancelFunction, setOnCancelFunction] = React.useState<BulkUploadContext['onCancel']>()
|
||||
const [initialFiles, setInitialFiles] = React.useState<FileList>(undefined)
|
||||
const [maxFiles, setMaxFiles] = React.useState<number>(undefined)
|
||||
const [currentActivePath, setCurrentActivePath] = React.useState<string>(undefined)
|
||||
const drawerSlug = useBulkUploadDrawerSlug()
|
||||
const drawerSlug = `${drawerSlugPrefix ? `${drawerSlugPrefix}-` : ''}${useBulkUploadDrawerSlug()}`
|
||||
|
||||
const setCollectionSlug: BulkUploadContext['setCollectionSlug'] = (slug) => {
|
||||
setCollection(slug)
|
||||
}
|
||||
|
||||
const setOnSuccess: BulkUploadContext['setOnSuccess'] = React.useCallback((path, onSuccess) => {
|
||||
setOnSuccessFunctionMap((prev) => ({
|
||||
...prev,
|
||||
[path]: onSuccess,
|
||||
}))
|
||||
}, [])
|
||||
const setOnSuccess: BulkUploadContext['setOnSuccess'] = (onSuccess) => {
|
||||
setOnSuccessFunction(() => onSuccess)
|
||||
}
|
||||
|
||||
return (
|
||||
<Context
|
||||
value={{
|
||||
collectionSlug: collection,
|
||||
currentActivePath,
|
||||
drawerSlug,
|
||||
initialFiles,
|
||||
maxFiles,
|
||||
@@ -153,13 +149,11 @@ export function BulkUploadProvider({ children }: { readonly children: React.Reac
|
||||
}
|
||||
},
|
||||
onSuccess: (docIDs, errorCount) => {
|
||||
if (onSuccessFunctionMap && Object.hasOwn(onSuccessFunctionMap, currentActivePath)) {
|
||||
const onSuccessFunction = onSuccessFunctionMap[currentActivePath]
|
||||
if (typeof onSuccessFunction === 'function') {
|
||||
onSuccessFunction(docIDs, errorCount)
|
||||
}
|
||||
},
|
||||
setCollectionSlug,
|
||||
setCurrentActivePath,
|
||||
setInitialFiles,
|
||||
setMaxFiles,
|
||||
setOnCancel: setOnCancelFunction,
|
||||
|
||||
Reference in New Issue
Block a user