diff --git a/packages/next/src/layouts/Root/index.tsx b/packages/next/src/layouts/Root/index.tsx index 982ff6d8f..d1dcfb319 100644 --- a/packages/next/src/layouts/Root/index.tsx +++ b/packages/next/src/layouts/Root/index.tsx @@ -4,13 +4,12 @@ import { translations } from '@payloadcms/translations/client' import { RootProvider, buildComponentMap } from '@payloadcms/ui' import '@payloadcms/ui/scss/app.scss' import { headers as getHeaders } from 'next/headers.js' +import { parseCookies } from 'payload/auth' import { createClientConfig } from 'payload/config' import { deepMerge } from 'payload/utilities' import React from 'react' import 'react-toastify/dist/ReactToastify.css' -import { auth } from '../../utilities/auth.js' -import { getPayloadHMR } from '../../utilities/getPayloadHMR.js' import { getRequestLanguage } from '../../utilities/getRequestLanguage.js' import { DefaultEditView } from '../../views/Edit/Default/index.js' import { DefaultCell } from '../../views/List/Default/Cell/index.js' @@ -34,13 +33,7 @@ export const RootLayout = async ({ const clientConfig = await createClientConfig(config) const headers = getHeaders() - - const payload = await getPayloadHMR({ config: configPromise }) - - const { cookies, permissions } = await auth({ - headers, - payload, - }) + const cookies = parseCookies(headers) const lang = getRequestLanguage({ @@ -63,7 +56,6 @@ export const RootLayout = async ({ DefaultListView, children, config, - permissions, }) return ( diff --git a/packages/next/src/views/CreateFirstUser/index.client.tsx b/packages/next/src/views/CreateFirstUser/index.client.tsx index 32e9eaa6c..556dc6a98 100644 --- a/packages/next/src/views/CreateFirstUser/index.client.tsx +++ b/packages/next/src/views/CreateFirstUser/index.client.tsx @@ -16,6 +16,9 @@ export const CreateFirstUserFields: React.FC<{ ) } diff --git a/packages/next/src/views/Edit/Default/index.tsx b/packages/next/src/views/Edit/Default/index.tsx index 7634c3894..1bd76bce4 100644 --- a/packages/next/src/views/Edit/Default/index.tsx +++ b/packages/next/src/views/Edit/Default/index.tsx @@ -4,7 +4,6 @@ import type { FormProps } from '@payloadcms/ui' import { DocumentControls, DocumentFields, - FieldPathProvider, Form, FormLoadingOverlayToggle, OperationProvider, @@ -140,89 +139,90 @@ export const DefaultEditView: React.FC = () => { return (
- - -
- - {BeforeDocument} - {preventLeaveWithoutSaving && } - - - - - {auth && ( - + + + {BeforeDocument} + {preventLeaveWithoutSaving && } + + + + + {auth && ( + + )} + {upload && ( + + {RegisterGetThumbnailFunction && } + - )} - {upload && ( - - {RegisterGetThumbnailFunction && } - - - )} - - ) - } - fieldMap={fieldMap} - /> - {AfterDocument} - -
-
+ + )} + + ) + } + docPermissions={docPermissions} + fieldMap={fieldMap} + readOnly={!hasSavePermission} + schemaPath={entitySlug} + /> + {AfterDocument} + +
) } diff --git a/packages/next/src/views/LivePreview/index.client.tsx b/packages/next/src/views/LivePreview/index.client.tsx index 07bdbcee3..3d17ddd3f 100644 --- a/packages/next/src/views/LivePreview/index.client.tsx +++ b/packages/next/src/views/LivePreview/index.client.tsx @@ -6,7 +6,6 @@ import type { Data } from 'payload/types' import { DocumentControls, DocumentFields, - FieldPathProvider, Form, LoadingOverlay, OperationProvider, @@ -127,73 +126,72 @@ const PreviewView: React.FC = (props) => { return ( - - -
+ + {((collectionConfig && + !(collectionConfig.versions?.drafts && collectionConfig.versions?.drafts?.autosave)) || + (global && !(global.versions?.drafts && global.versions?.drafts?.autosave))) && + !disableLeaveWithoutSaving && } + + + +
- {((collectionConfig && - !( - collectionConfig.versions?.drafts && collectionConfig.versions?.drafts?.autosave - )) || - (global && !(global.versions?.drafts && global.versions?.drafts?.autosave))) && - !disableLeaveWithoutSaving && } - - -
-
- {BeforeDocument} - - {AfterDocument} -
- + {BeforeDocument} + + {AfterDocument}
- - - + +
+ +
) } diff --git a/packages/payload/src/exports/types.ts b/packages/payload/src/exports/types.ts index 00d16c60b..a3b99d409 100644 --- a/packages/payload/src/exports/types.ts +++ b/packages/payload/src/exports/types.ts @@ -2,7 +2,7 @@ export * from './../types/index.js' export type * from '../admin/types.js' export type * from '../uploads/types.js' -export type { DocumentPermissions } from '../auth/index.js' +export type { DocumentPermissions, FieldPermissions } from '../auth/index.js' export type { AfterChangeHook as CollectionAfterChangeHook, diff --git a/packages/richtext-lexical/src/field/features/blocks/component/BlockContent.tsx b/packages/richtext-lexical/src/field/features/blocks/component/BlockContent.tsx index a2f70d41d..71fe3e3f3 100644 --- a/packages/richtext-lexical/src/field/features/blocks/component/BlockContent.tsx +++ b/packages/richtext-lexical/src/field/features/blocks/component/BlockContent.tsx @@ -65,7 +65,7 @@ export const BlockContent: React.FC = (props) => { const [collapsed, setCollapsed] = React.useState(() => { let initialState = false - getDocPreferences().then((currentDocPreferences) => { + void getDocPreferences().then((currentDocPreferences) => { const currentFieldPreferences = currentDocPreferences?.fields[field.name] const collapsedMap: { [key: string]: boolean } = currentFieldPreferences?.collapsed @@ -154,7 +154,7 @@ export const BlockContent: React.FC = (props) => { ) const onCollapsedChange = useCallback(() => { - getDocPreferences().then((currentDocPreferences) => { + void getDocPreferences().then((currentDocPreferences) => { const currentFieldPreferences = currentDocPreferences?.fields[field.name] const collapsedMap: { [key: string]: boolean } = currentFieldPreferences?.collapsed @@ -223,6 +223,9 @@ export const BlockContent: React.FC = (props) => { fieldMap={Array.isArray(formSchema) ? formSchema : []} forceRender margins="small" + path="" + readOnly={false} + schemaPath="" /> diff --git a/packages/richtext-lexical/src/field/features/blocks/component/index.tsx b/packages/richtext-lexical/src/field/features/blocks/component/index.tsx index d15f42a81..97c6d5476 100644 --- a/packages/richtext-lexical/src/field/features/blocks/component/index.tsx +++ b/packages/richtext-lexical/src/field/features/blocks/component/index.tsx @@ -1,6 +1,5 @@ 'use client' import { - FieldPathProvider, Form, type FormProps, getFormState, @@ -124,25 +123,23 @@ export const BlockComponent: React.FC = (props) => { return ( reducedBlock && initialState !== false && ( - -
- - -
+
+ + ) ) }, [ diff --git a/packages/richtext-lexical/src/field/features/link/drawer/index.tsx b/packages/richtext-lexical/src/field/features/link/drawer/index.tsx index e7818e822..440971b36 100644 --- a/packages/richtext-lexical/src/field/features/link/drawer/index.tsx +++ b/packages/richtext-lexical/src/field/features/link/drawer/index.tsx @@ -78,20 +78,24 @@ export const LinkDrawer: React.FC = ({ drawerSlug, handleModalSubmit, sta return ( {initialState !== false && ( - -
- + + - {t('general:submit')} - -
+ {t('general:submit')} + )}
) diff --git a/packages/richtext-lexical/src/field/features/upload/component/ExtraFieldsDrawer/index.tsx b/packages/richtext-lexical/src/field/features/upload/component/ExtraFieldsDrawer/index.tsx index e10c2ab26..204e6bc83 100644 --- a/packages/richtext-lexical/src/field/features/upload/component/ExtraFieldsDrawer/index.tsx +++ b/packages/richtext-lexical/src/field/features/upload/component/ExtraFieldsDrawer/index.tsx @@ -130,19 +130,23 @@ export const ExtraFieldsUploadDrawer: React.FC< })} > {initialState !== false && ( - -
- - {t('fields:saveChanges')} - -
+
+ + {t('fields:saveChanges')} + )} ) diff --git a/packages/richtext-lexical/src/generateComponentMap.tsx b/packages/richtext-lexical/src/generateComponentMap.tsx index 37cd9e523..639ef17bc 100644 --- a/packages/richtext-lexical/src/generateComponentMap.tsx +++ b/packages/richtext-lexical/src/generateComponentMap.tsx @@ -82,7 +82,6 @@ export const getGenerateComponentMap = const mappedFields = mapFields({ config, fieldSchema: sanitizedFields, - permissions: {}, readOnly: false, }) diff --git a/packages/richtext-slate/src/field/elements/link/LinkDrawer/index.tsx b/packages/richtext-slate/src/field/elements/link/LinkDrawer/index.tsx index f99d95a62..c01ac77dc 100644 --- a/packages/richtext-slate/src/field/elements/link/LinkDrawer/index.tsx +++ b/packages/richtext-slate/src/field/elements/link/LinkDrawer/index.tsx @@ -54,14 +54,12 @@ export const LinkDrawer: React.FC = ({ ) return ( - - -
- - - -
-
+ +
+ + + +
) } diff --git a/packages/richtext-slate/src/field/elements/upload/Element/UploadDrawer/index.tsx b/packages/richtext-slate/src/field/elements/upload/Element/UploadDrawer/index.tsx index 3f424d3df..e4863ec6b 100644 --- a/packages/richtext-slate/src/field/elements/upload/Element/UploadDrawer/index.tsx +++ b/packages/richtext-slate/src/field/elements/upload/Element/UploadDrawer/index.tsx @@ -109,12 +109,15 @@ export const UploadDrawer: React.FC<{ label: getTranslation(relatedCollection.labels.singular, i18n), })} > - -
- - {t('fields:saveChanges')} - -
+
+ + {t('fields:saveChanges')} + ) } diff --git a/packages/richtext-slate/src/generateComponentMap.tsx b/packages/richtext-slate/src/generateComponentMap.tsx index 9af3a813f..311fa5808 100644 --- a/packages/richtext-slate/src/generateComponentMap.tsx +++ b/packages/richtext-slate/src/generateComponentMap.tsx @@ -78,7 +78,6 @@ export const getGenerateComponentMap = const mappedFields = mapFields({ config, fieldSchema: linkFields, - permissions: {}, readOnly: false, }) @@ -109,7 +108,6 @@ export const getGenerateComponentMap = const mappedFields = mapFields({ config, fieldSchema: uploadFields, - permissions: {}, readOnly: false, }) diff --git a/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx b/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx index 82af2e722..a85ec6dfe 100644 --- a/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx +++ b/packages/ui/src/elements/DocumentDrawer/DrawerContent.tsx @@ -9,7 +9,7 @@ import { toast } from 'react-toastify' import type { DocumentDrawerProps } from './types.js' -import { FieldPathProvider, useFieldPath } from '../../forms/FieldPathProvider/index.js' +import { useFieldProps } from '../../forms/FieldPropsProvider/index.js' import { useRelatedCollections } from '../../forms/fields/Relationship/AddNew/useRelatedCollections.js' import usePayloadAPI from '../../hooks/usePayloadAPI.js' import { X } from '../../icons/X/index.js' @@ -56,7 +56,7 @@ const Content: React.FC = ({ const { permissions } = useAuth() - const { schemaPath } = useFieldPath() + const { schemaPath } = useFieldProps() const { componentMap } = useComponentMap() @@ -197,9 +197,5 @@ export const DocumentDrawerContent: React.FC = (props) => { [onSaveFromProps, collectionConfig], ) - return ( - - - - ) + return } diff --git a/packages/ui/src/elements/DocumentFields/index.tsx b/packages/ui/src/elements/DocumentFields/index.tsx index e4b3008cc..01c519ed9 100644 --- a/packages/ui/src/elements/DocumentFields/index.tsx +++ b/packages/ui/src/elements/DocumentFields/index.tsx @@ -1,25 +1,37 @@ 'use client' -import type { Description, Operation } from 'payload/types' +import type { Description, DocumentPermissions } from 'payload/types' import React from 'react' import type { FieldMap } from '../../utilities/buildComponentMap/types.js' -import RenderFields from '../../forms/RenderFields/index.js' +import { RenderFields } from '../../forms/RenderFields/index.js' import { Gutter } from '../Gutter/index.js' import './index.scss' const baseClass = 'document-fields' -export const DocumentFields: React.FC<{ +type Args = { AfterFields?: React.ReactNode BeforeFields?: React.ReactNode description?: Description + docPermissions: DocumentPermissions fieldMap: FieldMap forceSidebarWrap?: boolean -}> = (props) => { - const { AfterFields, BeforeFields, description, fieldMap, forceSidebarWrap } = props + readOnly: boolean + schemaPath: string +} +export const DocumentFields: React.FC = ({ + AfterFields, + BeforeFields, + description, + docPermissions, + fieldMap, + forceSidebarWrap, + readOnly, + schemaPath, +}) => { const mainFields = fieldMap.filter(({ isSidebar }) => !isSidebar) const sidebarFields = fieldMap.filter(({ isSidebar }) => isSidebar) @@ -47,7 +59,14 @@ export const DocumentFields: React.FC<{ )} {BeforeFields} - + {AfterFields} @@ -55,7 +74,13 @@ export const DocumentFields: React.FC<{
- +
diff --git a/packages/ui/src/elements/EditMany/index.tsx b/packages/ui/src/elements/EditMany/index.tsx index e9643fe51..f4990d894 100644 --- a/packages/ui/src/elements/EditMany/index.tsx +++ b/packages/ui/src/elements/EditMany/index.tsx @@ -8,10 +8,9 @@ import React, { useCallback, useState } from 'react' import type { Props } from './types.js' -import { FieldPathProvider } from '../../forms/FieldPathProvider/index.js' import { useForm } from '../../forms/Form/context.js' import Form from '../../forms/Form/index.js' -import RenderFields from '../../forms/RenderFields/index.js' +import { RenderFields } from '../../forms/RenderFields/index.js' import FormSubmit from '../../forms/Submit/index.js' import { X } from '../../icons/X/index.js' import { useAuth } from '../../providers/Auth/index.js' @@ -34,7 +33,7 @@ const Submit: React.FC<{ action: string; disabled: boolean }> = ({ action, disab const { t } = useTranslation() const save = useCallback(() => { - submit({ + void submit({ action, method: 'PATCH', skipValidation: true, @@ -52,7 +51,7 @@ const Publish: React.FC<{ action: string; disabled: boolean }> = ({ action, disa const { t } = useTranslation() const save = useCallback(() => { - submit({ + void submit({ action, method: 'PATCH', overrides: { @@ -73,7 +72,7 @@ const SaveDraft: React.FC<{ action: string; disabled: boolean }> = ({ action, di const { t } = useTranslation() const save = useCallback(() => { - submit({ + void submit({ action, method: 'PATCH', overrides: { @@ -90,7 +89,7 @@ const SaveDraft: React.FC<{ action: string; disabled: boolean }> = ({ action, di ) } export const EditMany: React.FC = (props) => { - const { Modal, useModal } = facelessUIImport + const { useModal } = facelessUIImport const { collection: { slug, fields, labels: { plural } } = {}, collection } = props @@ -195,43 +194,46 @@ export const EditMany: React.FC = (props) => { - -
- - {reducedFieldMap.length === 0 ? null : ( - - )} -
-
-
-
- {collection?.versions?.drafts ? ( - - - - - ) : ( - + + {reducedFieldMap.length === 0 ? null : ( + + )} +
+
+
+
+ {collection?.versions?.drafts ? ( + + - )} -
+ + + ) : ( + + )}
- - +
+
diff --git a/packages/ui/src/elements/Upload/index.tsx b/packages/ui/src/elements/Upload/index.tsx index 7eff7e5de..3f2a06db3 100644 --- a/packages/ui/src/elements/Upload/index.tsx +++ b/packages/ui/src/elements/Upload/index.tsx @@ -8,7 +8,7 @@ import Error from '../../forms/Error/index.js' import { useFormSubmitted } from '../../forms/Form/context.js' import reduceFieldsToValues from '../../forms/Form/reduceFieldsToValues.js' import { fieldBaseClass } from '../../forms/fields/shared.js' -import useField from '../../forms/useField/index.js' +import { useField } from '../../forms/useField/index.js' import { useDocumentInfo } from '../../providers/DocumentInfo/index.js' import { useTranslation } from '../../providers/Translation/index.js' import { Button } from '../Button/index.js' diff --git a/packages/ui/src/exports/forms.ts b/packages/ui/src/exports/forms.ts index d542f9927..4352719ec 100644 --- a/packages/ui/src/exports/forms.ts +++ b/packages/ui/src/exports/forms.ts @@ -1,6 +1,9 @@ export { default as Error } from '../forms/Error/index.js' export { default as FieldDescription } from '../forms/FieldDescription/index.js' -export { FieldPathProvider, useFieldPath } from '../forms/FieldPathProvider/index.js' +export { + FieldPropsProvider as FieldPathProvider, + useFieldProps as useFieldPath, +} from '../forms/FieldPropsProvider/index.js' export { useAllFormFields, useForm, @@ -14,7 +17,7 @@ export { default as Form } from '../forms/Form/index.js' export { default as reduceFieldsToValues } from '../forms/Form/reduceFieldsToValues.js' export type { Props as FormProps } from '../forms/Form/types.js' export { default as Label } from '../forms/Label/index.js' -export { default as RenderFields } from '../forms/RenderFields/index.js' +export { RenderFields } from '../forms/RenderFields/index.js' export { default as FormSubmit } from '../forms/Submit/index.js' export { default as Submit } from '../forms/Submit/index.js' export { default as SectionTitle } from '../forms/fields/Blocks/SectionTitle/index.js' @@ -40,7 +43,7 @@ export { default as UploadField } from '../forms/fields/Upload/index.js' export { fieldTypes } from '../forms/fields/index.js' export { fieldBaseClass } from '../forms/fields/shared.js' -export { default as useField } from '../forms/useField/index.js' +export { useField } from '../forms/useField/index.js' export type { FieldType, Options } from '../forms/useField/types.js' export { default as buildStateFromSchema } from '../forms/utilities/buildStateFromSchema/index.js' export type { BuildFormStateArgs } from '../forms/utilities/buildStateFromSchema/index.js' diff --git a/packages/ui/src/forms/Error/index.tsx b/packages/ui/src/forms/Error/index.tsx index c31ab41c9..6fe66abe4 100644 --- a/packages/ui/src/forms/Error/index.tsx +++ b/packages/ui/src/forms/Error/index.tsx @@ -4,7 +4,7 @@ import type { ErrorProps } from 'payload/types' import React from 'react' import { Tooltip } from '../../elements/Tooltip/index.js' -import { useFieldPath } from '../FieldPathProvider/index.js' +import { useFieldProps } from '../FieldPropsProvider/index.js' import { useFormFields, useFormSubmitted } from '../Form/context.js' import './index.scss' @@ -18,7 +18,7 @@ const Error: React.FC = (props) => { showError: showErrorFromProps, } = props - const { path: pathFromContext } = useFieldPath() + const { path: pathFromContext } = useFieldProps() const path = pathFromProps || pathFromContext const hasSubmitted = useFormSubmitted() diff --git a/packages/ui/src/forms/FieldPathProvider/index.tsx b/packages/ui/src/forms/FieldPathProvider/index.tsx deleted file mode 100644 index cfc0aa16a..000000000 --- a/packages/ui/src/forms/FieldPathProvider/index.tsx +++ /dev/null @@ -1,36 +0,0 @@ -'use client' -import React from 'react' - -type FieldPathContextType = { - path: string - schemaPath: string -} - -const FieldPathContext = React.createContext({ - path: '', - schemaPath: '', -}) - -export const FieldPathProvider: React.FC<{ - children: React.ReactNode - path: string - schemaPath: string -}> = (props) => { - const { children, path, schemaPath } = props - - return ( - - {children} - - ) -} - -export const useFieldPath = () => { - const path = React.useContext(FieldPathContext) - return path -} diff --git a/packages/ui/src/forms/FieldPropsProvider/index.tsx b/packages/ui/src/forms/FieldPropsProvider/index.tsx new file mode 100644 index 000000000..cee712966 --- /dev/null +++ b/packages/ui/src/forms/FieldPropsProvider/index.tsx @@ -0,0 +1,61 @@ +'use client' +import type { FieldPermissions } from 'payload/types' + +import React from 'react' + +type FieldPropsContextType = { + path: string + permissions?: FieldPermissions + readOnly: boolean + schemaPath: string + siblingPermissions: { + [fieldName: string]: FieldPermissions + } +} + +const FieldPropsContext = React.createContext({ + path: '', + permissions: {} as FieldPermissions, + readOnly: false, + schemaPath: '', + siblingPermissions: {}, +}) + +type Props = { + children: React.ReactNode + path: string + permissions?: FieldPermissions + readOnly: boolean + schemaPath: string + siblingPermissions: { + [fieldName: string]: FieldPermissions + } +} + +export const FieldPropsProvider: React.FC = ({ + children, + path, + permissions, + readOnly, + schemaPath, + siblingPermissions, +}) => { + return ( + + {children} + + ) +} + +export const useFieldProps = () => { + const path = React.useContext(FieldPropsContext) + return path +} diff --git a/packages/ui/src/forms/Label/index.tsx b/packages/ui/src/forms/Label/index.tsx index c6746f631..35d8f5f8c 100644 --- a/packages/ui/src/forms/Label/index.tsx +++ b/packages/ui/src/forms/Label/index.tsx @@ -6,14 +6,14 @@ import React from 'react' import { useTranslation } from '../../providers/Translation/index.js' import { generateFieldID } from '../../utilities/generateFieldID.js' -import { useFieldPath } from '../FieldPathProvider/index.js' +import { useFieldProps } from '../FieldPropsProvider/index.js' import { useForm } from '../Form/context.js' import './index.scss' const Label: React.FC = (props) => { const { htmlFor: htmlForFromProps, label, required = false } = props const { uuid } = useForm() - const { path } = useFieldPath() + const { path } = useFieldProps() const htmlFor = htmlForFromProps || generateFieldID(path, uuid) const { i18n } = useTranslation() diff --git a/packages/ui/src/forms/ReadOnlyProvider/index.tsx b/packages/ui/src/forms/ReadOnlyProvider/index.tsx deleted file mode 100644 index b45da2765..000000000 --- a/packages/ui/src/forms/ReadOnlyProvider/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -'use client' -import React from 'react' - -const ReadOnlyContext = React.createContext(undefined) - -export const ReadOnlyProvider: React.FC<{ - children: React.ReactNode - readOnly?: boolean -}> = (props) => { - const { children, readOnly } = props - - return {children} -} - -export const useReadOnly = () => { - const path = React.useContext(ReadOnlyContext) - return path -} diff --git a/packages/ui/src/forms/RenderFields/RenderField.tsx b/packages/ui/src/forms/RenderFields/RenderField.tsx index d3b036090..3641ec7f2 100644 --- a/packages/ui/src/forms/RenderFields/RenderField.tsx +++ b/packages/ui/src/forms/RenderFields/RenderField.tsx @@ -1,32 +1,44 @@ 'use client' -import type { FieldPermissions } from 'payload/auth' + +import type { FieldPermissions } from 'payload/types' import React from 'react' import { useOperation } from '../../providers/OperationProvider/index.js' -import { FieldPathProvider, useFieldPath } from '../FieldPathProvider/index.js' -import { ReadOnlyProvider, useReadOnly } from '../ReadOnlyProvider/index.js' +import { FieldPropsProvider, useFieldProps } from '../FieldPropsProvider/index.js' -export const RenderField: React.FC<{ +type Props = { Field: React.ReactNode - fieldPermissions: FieldPermissions + disabled: boolean name?: string + path: string + permissions?: FieldPermissions readOnly?: boolean -}> = (props) => { - const { name, Field, fieldPermissions, readOnly: readOnlyFromProps } = props - - const { path: pathFromContext, schemaPath: schemaPathFromContext } = useFieldPath() - - const readOnlyFromContext = useReadOnly() + schemaPath: string + siblingPermissions: { + [fieldName: string]: FieldPermissions + } +} +export const RenderField: React.FC = ({ + name, + Field, + disabled, + path: pathFromProps, + permissions, + readOnly: readOnlyFromProps, + schemaPath: schemaPathFromProps, + siblingPermissions, +}) => { const operation = useOperation() + const { readOnly: readOnlyFromContext } = useFieldProps() - const path = `${pathFromContext ? `${pathFromContext}.` : ''}${name ? `${name}` : ''}` - const schemaPath = `${schemaPathFromContext ? `${schemaPathFromContext}` : ''}${name ? `.${name}` : ''}` + const path = `${pathFromProps ? `${pathFromProps}.` : ''}${name ? `${name}` : ''}` + const schemaPath = `${schemaPathFromProps ? `${schemaPathFromProps}` : ''}${name ? `.${name}` : ''}` // if the user cannot read the field, then filter it out // this is different from `admin.readOnly` which is executed based on `operation` - if (fieldPermissions?.read?.permission === false) { + if (permissions?.read?.permission === false || disabled) { return null } @@ -37,15 +49,19 @@ export const RenderField: React.FC<{ if (readOnlyFromContext && readOnly !== false) readOnly = true // if the user does not have access control to begin with, force it to be read-only - if (fieldPermissions?.[operation]?.permission === false) { + if (permissions?.[operation]?.permission === false) { readOnly = true } return ( - - - {Field} - - + + {Field} + ) } diff --git a/packages/ui/src/forms/RenderFields/index.tsx b/packages/ui/src/forms/RenderFields/index.tsx index d52a8741e..e4c065de3 100644 --- a/packages/ui/src/forms/RenderFields/index.tsx +++ b/packages/ui/src/forms/RenderFields/index.tsx @@ -10,8 +10,8 @@ import './index.scss' const baseClass = 'render-fields' -const RenderFields: React.FC = (props) => { - const { className, fieldMap, forceRender, margins } = props +export const RenderFields: React.FC = (props) => { + const { className, fieldMap, forceRender, margins, path, permissions, schemaPath } = props const { i18n } = useTranslation() const [hasRendered, setHasRendered] = React.useState(Boolean(forceRender)) @@ -53,20 +53,24 @@ const RenderFields: React.FC = (props) => { ref={intersectionRef} > {hasRendered && - fieldMap?.map(({ name, Field, fieldPermissions, readOnly }, fieldIndex) => ( - - ))} + fieldMap?.map(({ name, Field, disabled, readOnly }, fieldIndex) => { + return ( + + ) + })}
) } return null } - -export default RenderFields diff --git a/packages/ui/src/forms/RenderFields/types.ts b/packages/ui/src/forms/RenderFields/types.ts index e0d7360ff..bd675b2d3 100644 --- a/packages/ui/src/forms/RenderFields/types.ts +++ b/packages/ui/src/forms/RenderFields/types.ts @@ -1,4 +1,4 @@ -import type { Operation } from 'payload/types' +import type { FieldPermissions, Operation } from 'payload/types' import type { FieldMap } from '../../utilities/buildComponentMap/types.js' @@ -8,4 +8,10 @@ export type Props = { forceRender?: boolean margins?: 'small' | false operation?: Operation + path: string + permissions?: { + [fieldName: string]: FieldPermissions + } + readOnly: boolean + schemaPath: string } diff --git a/packages/ui/src/forms/fields/Array/ArrayRow.tsx b/packages/ui/src/forms/fields/Array/ArrayRow.tsx index 9ccd54f6f..f4efe6851 100644 --- a/packages/ui/src/forms/fields/Array/ArrayRow.tsx +++ b/packages/ui/src/forms/fields/Array/ArrayRow.tsx @@ -1,5 +1,5 @@ import type { FieldPermissions } from 'payload/auth' -import type { ArrayField, Operation, Row, RowLabel as RowLabelType } from 'payload/types' +import type { ArrayField, Row, RowLabel as RowLabelType } from 'payload/types' import { getTranslation } from '@payloadcms/translations' import React from 'react' @@ -11,9 +11,9 @@ import { ArrayAction } from '../../../elements/ArrayAction/index.js' import { Collapsible } from '../../../elements/Collapsible/index.js' import { ErrorPill } from '../../../elements/ErrorPill/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import { FieldPathProvider } from '../../FieldPathProvider/index.js' +import { FieldPropsProvider } from '../../FieldPropsProvider/index.js' import { useFormSubmitted } from '../../Form/context.js' -import RenderFields from '../../RenderFields/index.js' +import { RenderFields } from '../../RenderFields/index.js' import HiddenInput from '../HiddenInput/index.js' import './index.scss' @@ -50,6 +50,7 @@ export const ArrayRow: React.FC = ({ listeners, moveRow, path: parentPath, + permissions, readOnly, removeRow, row, @@ -122,17 +123,16 @@ export const ArrayRow: React.FC = ({ onToggle={(collapsed) => setCollapse(row.id, collapsed)} > - - - +
) diff --git a/packages/ui/src/forms/fields/Array/index.tsx b/packages/ui/src/forms/fields/Array/index.tsx index aff70e16d..c43467143 100644 --- a/packages/ui/src/forms/fields/Array/index.tsx +++ b/packages/ui/src/forms/fields/Array/index.tsx @@ -17,7 +17,7 @@ import { scrollToID } from '../../../utilities/scrollToID.js' import { useForm, useFormSubmitted } from '../../Form/context.js' import LabelComp from '../../Label/index.js' import { NullifyLocaleField } from '../../NullifyField/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { fieldBaseClass } from '../shared.js' import { ArrayRow } from './ArrayRow.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Blocks/BlockRow.tsx b/packages/ui/src/forms/fields/Blocks/BlockRow.tsx index eb1336b39..d2f9916e1 100644 --- a/packages/ui/src/forms/fields/Blocks/BlockRow.tsx +++ b/packages/ui/src/forms/fields/Blocks/BlockRow.tsx @@ -12,9 +12,9 @@ import { Collapsible } from '../../../elements/Collapsible/index.js' import { ErrorPill } from '../../../elements/ErrorPill/index.js' import Pill from '../../../elements/Pill/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import { FieldPathProvider } from '../../FieldPathProvider/index.js' +import { FieldPropsProvider } from '../../FieldPropsProvider/index.js' import { useFormSubmitted } from '../../Form/context.js' -import RenderFields from '../../RenderFields/index.js' +import { RenderFields } from '../../RenderFields/index.js' import HiddenInput from '../HiddenInput/index.js' import { RowActions } from './RowActions.js' import SectionTitle from './SectionTitle/index.js' @@ -54,6 +54,7 @@ export const BlockRow: React.FC = ({ listeners, moveRow, path: parentPath, + permissions, readOnly, removeRow, row, @@ -132,17 +133,16 @@ export const BlockRow: React.FC = ({ onToggle={(collapsed) => setCollapse(row.id, collapsed)} > - - - + ) diff --git a/packages/ui/src/forms/fields/Blocks/SectionTitle/index.tsx b/packages/ui/src/forms/fields/Blocks/SectionTitle/index.tsx index dfb5d7e10..9b1ba85ce 100644 --- a/packages/ui/src/forms/fields/Blocks/SectionTitle/index.tsx +++ b/packages/ui/src/forms/fields/Blocks/SectionTitle/index.tsx @@ -3,7 +3,7 @@ import React from 'react' import type { Props } from './types.js' import { useTranslation } from '../../../../providers/Translation/index.js' -import useField from '../../../useField/index.js' +import { useField } from '../../../useField/index.js' import './index.scss' const baseClass = 'section-title' diff --git a/packages/ui/src/forms/fields/Blocks/index.tsx b/packages/ui/src/forms/fields/Blocks/index.tsx index 548ca515f..bc5c088fb 100644 --- a/packages/ui/src/forms/fields/Blocks/index.tsx +++ b/packages/ui/src/forms/fields/Blocks/index.tsx @@ -19,7 +19,7 @@ import { scrollToID } from '../../../utilities/scrollToID.js' import { useForm, useFormSubmitted } from '../../Form/context.js' import LabelComp from '../../Label/index.js' import { NullifyLocaleField } from '../../NullifyField/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { fieldBaseClass } from '../shared.js' import { BlockRow } from './BlockRow.js' import { BlocksDrawer } from './BlocksDrawer/index.js' @@ -41,7 +41,6 @@ const BlocksField: React.FC = (props) => { label, localized, path: pathFromProps, - permissions, readOnly, required, validate, @@ -91,6 +90,7 @@ const BlocksField: React.FC = (props) => { const { path, + permissions, rows = [], schemaPath, showError, diff --git a/packages/ui/src/forms/fields/Checkbox/index.tsx b/packages/ui/src/forms/fields/Checkbox/index.tsx index 45428bbd8..cd6047780 100644 --- a/packages/ui/src/forms/fields/Checkbox/index.tsx +++ b/packages/ui/src/forms/fields/Checkbox/index.tsx @@ -8,7 +8,7 @@ import type { Props } from './types.js' import { generateFieldID } from '../../../utilities/generateFieldID.js' import { useForm } from '../../Form/context.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import { CheckboxInput } from './Input.js' diff --git a/packages/ui/src/forms/fields/Code/index.tsx b/packages/ui/src/forms/fields/Code/index.tsx index cc8868d32..1725239d9 100644 --- a/packages/ui/src/forms/fields/Code/index.tsx +++ b/packages/ui/src/forms/fields/Code/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import React, { useCallback } from 'react' @@ -5,7 +6,7 @@ import type { Props } from './types.js' import { CodeEditor } from '../../../elements/CodeEditor/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Collapsible/index.tsx b/packages/ui/src/forms/fields/Collapsible/index.tsx index a4407a1c6..2ab70ea4b 100644 --- a/packages/ui/src/forms/fields/Collapsible/index.tsx +++ b/packages/ui/src/forms/fields/Collapsible/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import type { DocumentPreferences } from 'payload/types' @@ -10,9 +11,9 @@ import { ErrorPill } from '../../../elements/ErrorPill/index.js' import { useDocumentInfo } from '../../../providers/DocumentInfo/index.js' import { usePreferences } from '../../../providers/Preferences/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import { useFieldPath } from '../../FieldPathProvider/index.js' +import { useFieldProps } from '../../FieldPropsProvider/index.js' import LabelComp from '../../Label/index.js' -import RenderFields from '../../RenderFields/index.js' +import { RenderFields } from '../../RenderFields/index.js' import { WatchChildErrors } from '../../WatchChildErrors/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' @@ -23,20 +24,17 @@ const baseClass = 'collapsible-field' const CollapsibleField: React.FC = (props) => { const { Description, - Error, Label: LabelFromProps, className, fieldMap, label, path: pathFromProps, - permissions, - readOnly, required, } = props const Label = LabelFromProps || - const { path: pathFromContext } = useFieldPath() + const { path: pathFromContext, readOnly, schemaPath, siblingPermissions } = useFieldProps() const path = pathFromProps || pathFromContext const { i18n } = useTranslation() @@ -52,7 +50,7 @@ const CollapsibleField: React.FC = (props) => { async (newCollapsedState: boolean) => { const existingPreferences: DocumentPreferences = await getPreference(preferencesKey) - setPreference(preferencesKey, { + void setPreference(preferencesKey, { ...existingPreferences, ...(path ? { @@ -91,7 +89,7 @@ const CollapsibleField: React.FC = (props) => { } } - fetchInitialState() + void fetchInitialState() }, [getPreference, preferencesKey, fieldPreferencesKey, initCollapsed, path]) if (typeof collapsedOnMount !== 'boolean') return null @@ -125,10 +123,11 @@ const CollapsibleField: React.FC = (props) => { {Description} diff --git a/packages/ui/src/forms/fields/ConfirmPassword/index.tsx b/packages/ui/src/forms/fields/ConfirmPassword/index.tsx index ca990ca20..1c1ffc5c1 100644 --- a/packages/ui/src/forms/fields/ConfirmPassword/index.tsx +++ b/packages/ui/src/forms/fields/ConfirmPassword/index.tsx @@ -9,7 +9,7 @@ import { useTranslation } from '../../../providers/Translation/index.js' import Error from '../../Error/index.js' import { useFormFields } from '../../Form/context.js' import Label from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/DateTime/index.tsx b/packages/ui/src/forms/fields/DateTime/index.tsx index 0da8d5d42..036aa87d7 100644 --- a/packages/ui/src/forms/fields/DateTime/index.tsx +++ b/packages/ui/src/forms/fields/DateTime/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import type { ClientValidate } from 'payload/types' @@ -8,7 +9,7 @@ import type { Props } from './types.js' import { DatePickerField } from '../../../elements/DatePicker/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Email/index.tsx b/packages/ui/src/forms/fields/Email/index.tsx index 26cdfdf7d..84dc26683 100644 --- a/packages/ui/src/forms/fields/Email/index.tsx +++ b/packages/ui/src/forms/fields/Email/index.tsx @@ -8,7 +8,7 @@ import type { Props } from './types.js' import { useTranslation } from '../../../providers/Translation/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Group/index.tsx b/packages/ui/src/forms/fields/Group/index.tsx index f6792ceae..bfdc4548b 100644 --- a/packages/ui/src/forms/fields/Group/index.tsx +++ b/packages/ui/src/forms/fields/Group/index.tsx @@ -6,9 +6,9 @@ import type { Props } from './types.js' import { useCollapsible } from '../../../elements/Collapsible/provider.js' import { ErrorPill } from '../../../elements/ErrorPill/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import { FieldPathProvider, useFieldPath } from '../../FieldPathProvider/index.js' +import { useFieldProps } from '../../FieldPropsProvider/index.js' import LabelComp from '../../Label/index.js' -import RenderFields from '../../RenderFields/index.js' +import { RenderFields } from '../../RenderFields/index.js' import { WatchChildErrors } from '../../WatchChildErrors/index.js' import { withCondition } from '../../withCondition/index.js' import { useRow } from '../Row/provider.js' @@ -21,7 +21,6 @@ const baseClass = 'group-field' const Group: React.FC = (props) => { const { - name, Description, Label: LabelFromProps, className, @@ -35,7 +34,7 @@ const Group: React.FC = (props) => { const Label = LabelFromProps || - const { path, schemaPath } = useFieldPath() + const { path, permissions, readOnly, schemaPath } = useFieldProps() const { i18n } = useTranslation() const isWithinCollapsible = useCollapsible() const isWithinGroup = useGroup() @@ -70,22 +69,26 @@ const Group: React.FC = (props) => { width, }} > - - -
-
- {(Label || Description) && ( -
- {Label} - {Description} -
- )} - {fieldHasErrors && } -
- + +
+
+ {(Label || Description) && ( +
+ {Label} + {Description} +
+ )} + {fieldHasErrors && }
- - + +
+
) diff --git a/packages/ui/src/forms/fields/HiddenInput/index.tsx b/packages/ui/src/forms/fields/HiddenInput/index.tsx index 7238a7824..5e464ceef 100644 --- a/packages/ui/src/forms/fields/HiddenInput/index.tsx +++ b/packages/ui/src/forms/fields/HiddenInput/index.tsx @@ -3,7 +3,7 @@ import React, { useEffect } from 'react' import type { Props } from './types.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' /** diff --git a/packages/ui/src/forms/fields/JSON/index.tsx b/packages/ui/src/forms/fields/JSON/index.tsx index 97c030e3c..3b6d9c834 100644 --- a/packages/ui/src/forms/fields/JSON/index.tsx +++ b/packages/ui/src/forms/fields/JSON/index.tsx @@ -7,7 +7,7 @@ import type { Props } from './types.js' import { CodeEditor } from '../../../elements/CodeEditor/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Number/index.tsx b/packages/ui/src/forms/fields/Number/index.tsx index fbde7b52e..35a527ff1 100644 --- a/packages/ui/src/forms/fields/Number/index.tsx +++ b/packages/ui/src/forms/fields/Number/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import { getTranslation } from '@payloadcms/translations' import { isNumber } from 'payload/utilities' @@ -9,7 +10,7 @@ import type { Props } from './types.js' import ReactSelect from '../../../elements/ReactSelect/index.js' import { useTranslation } from '../../../providers/Translation/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Password/index.tsx b/packages/ui/src/forms/fields/Password/index.tsx index ef3ac8492..cfd9b7d83 100644 --- a/packages/ui/src/forms/fields/Password/index.tsx +++ b/packages/ui/src/forms/fields/Password/index.tsx @@ -6,7 +6,7 @@ import React, { useCallback } from 'react' import type { Props } from './types.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Point/index.tsx b/packages/ui/src/forms/fields/Point/index.tsx index 3bb7a1355..f9b8e7727 100644 --- a/packages/ui/src/forms/fields/Point/index.tsx +++ b/packages/ui/src/forms/fields/Point/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import type { ClientValidate } from 'payload/types' @@ -8,7 +9,7 @@ import type { Props } from './types.js' import { useTranslation } from '../../../providers/Translation/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/RadioGroup/index.tsx b/packages/ui/src/forms/fields/RadioGroup/index.tsx index f7f17083e..9f1545d7b 100644 --- a/packages/ui/src/forms/fields/RadioGroup/index.tsx +++ b/packages/ui/src/forms/fields/RadioGroup/index.tsx @@ -1,3 +1,5 @@ +/* eslint-disable react/destructuring-assignment */ +/* eslint-disable react-hooks/exhaustive-deps */ 'use client' import { optionIsObject } from 'payload/types' import React, { useCallback } from 'react' @@ -6,7 +8,7 @@ import type { Props } from './types.js' import { useForm } from '../../Form/context.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import { Radio } from './Radio/index.js' diff --git a/packages/ui/src/forms/fields/Relationship/index.tsx b/packages/ui/src/forms/fields/Relationship/index.tsx index 617f9df74..a806caf34 100644 --- a/packages/ui/src/forms/fields/Relationship/index.tsx +++ b/packages/ui/src/forms/fields/Relationship/index.tsx @@ -17,7 +17,7 @@ import { useConfig } from '../../../providers/Config/index.js' import { useLocale } from '../../../providers/Locale/index.js' import { useTranslation } from '../../../providers/Translation/index.js' import { useFormProcessing } from '../../Form/context.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import { AddNewRelation } from './AddNew/index.js' @@ -122,7 +122,7 @@ const Relationship: React.FC = (props) => { }) if (!errorLoading) { - relationsToFetch.reduce(async (priorRelation, relation) => { + await relationsToFetch.reduce(async (priorRelation, relation) => { const relationFilterOption = filterOptionsResult?.[relation] let lastLoadedPageToUse if (search !== searchArg) { @@ -208,7 +208,7 @@ const Relationship: React.FC = (props) => { type: 'ADD', collection, // TODO: fix this - // @ts-ignore-next-line + // @ts-expect-error-next-line config, docs: data.docs, i18n, @@ -221,7 +221,7 @@ const Relationship: React.FC = (props) => { type: 'ADD', collection, // TODO: fix this - // @ts-ignore-next-line + // @ts-expect-error-next-line config, docs: [], i18n, @@ -257,7 +257,7 @@ const Relationship: React.FC = (props) => { ) const updateSearch = useDebouncedCallback((searchArg: string, valueArg: Value | Value[]) => { - getResults({ search: searchArg, sort: true, value: valueArg }) + void getResults({ search: searchArg, sort: true, value: valueArg }) setSearch(searchArg) }, 300) @@ -282,7 +282,7 @@ const Relationship: React.FC = (props) => { value, }) - Object.entries(relationMap).reduce(async (priorRelation, [relation, ids]) => { + void Object.entries(relationMap).reduce(async (priorRelation, [relation, ids]) => { await priorRelation const idsToLoad = ids.filter((id) => { @@ -326,7 +326,7 @@ const Relationship: React.FC = (props) => { type: 'ADD', collection, // TODO: fix this - // @ts-ignore-next-line + // @ts-expect-error-next-line config, docs, i18n, @@ -382,7 +382,7 @@ const Relationship: React.FC = (props) => { type: 'UPDATE', collection: args.collectionConfig, // TODO: fix this - // @ts-ignore-next-line + // @ts-expect-error-next-line config, doc: args.doc, i18n, @@ -498,7 +498,7 @@ const Relationship: React.FC = (props) => { onMenuOpen={() => { if (!hasLoadedFirstPage) { setIsLoading(true) - getResults({ + void getResults({ onSuccess: () => { setHasLoadedFirstPage(true) setIsLoading(false) @@ -508,7 +508,7 @@ const Relationship: React.FC = (props) => { } }} onMenuScrollToBottom={() => { - getResults({ + void getResults({ lastFullyLoadedRelation, search, sort: false, diff --git a/packages/ui/src/forms/fields/Row/index.tsx b/packages/ui/src/forms/fields/Row/index.tsx index 485c5b59c..98bf5cfd8 100644 --- a/packages/ui/src/forms/fields/Row/index.tsx +++ b/packages/ui/src/forms/fields/Row/index.tsx @@ -3,7 +3,8 @@ import React from 'react' import type { Props } from './types.js' -import RenderFields from '../../RenderFields/index.js' +import { useFieldProps } from '../../FieldPropsProvider/index.js' +import { RenderFields } from '../../RenderFields/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' @@ -12,19 +13,20 @@ import { RowProvider } from './provider.js' const baseClass = 'row' const Row: React.FC = (props) => { - const { className, fieldMap, forceRender = false, indexPath, permissions, readOnly } = props + const { className, fieldMap, forceRender = false } = props + + const { path, readOnly, schemaPath, siblingPermissions } = useFieldProps() return (
diff --git a/packages/ui/src/forms/fields/Row/types.ts b/packages/ui/src/forms/fields/Row/types.ts index 4ae263c7d..93f3d7847 100644 --- a/packages/ui/src/forms/fields/Row/types.ts +++ b/packages/ui/src/forms/fields/Row/types.ts @@ -8,5 +8,5 @@ export type Props = FormFieldBase & { forceRender?: boolean indexPath: string path?: string - permissions: FieldPermissions + permissions?: FieldPermissions } diff --git a/packages/ui/src/forms/fields/Select/index.tsx b/packages/ui/src/forms/fields/Select/index.tsx index f4d4c255d..a635d2cca 100644 --- a/packages/ui/src/forms/fields/Select/index.tsx +++ b/packages/ui/src/forms/fields/Select/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import type { ClientValidate, Option, OptionObject } from 'payload/types' @@ -9,7 +10,7 @@ import type { Props } from './types.js' import ReactSelect from '../../../elements/ReactSelect/index.js' import { useTranslation } from '../../../providers/Translation/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/Tabs/index.tsx b/packages/ui/src/forms/fields/Tabs/index.tsx index 0c76aa359..93a9863d0 100644 --- a/packages/ui/src/forms/fields/Tabs/index.tsx +++ b/packages/ui/src/forms/fields/Tabs/index.tsx @@ -11,8 +11,8 @@ import { useCollapsible } from '../../../elements/Collapsible/provider.js' import { useDocumentInfo } from '../../../providers/DocumentInfo/index.js' import { usePreferences } from '../../../providers/Preferences/index.js' import { useTranslation } from '../../../providers/Translation/index.js' -import { FieldPathProvider, useFieldPath } from '../../FieldPathProvider/index.js' -import RenderFields from '../../RenderFields/index.js' +import { useFieldProps } from '../../FieldPropsProvider/index.js' +import { RenderFields } from '../../RenderFields/index.js' import { withCondition } from '../../withCondition/index.js' import { fieldBaseClass } from '../shared.js' import { TabComponent } from './Tab/index.js' @@ -26,16 +26,14 @@ const TabsField: React.FC = (props) => { name, Description, className, - fieldMap, forceRender = false, indexPath, path: pathFromProps, - permissions, readOnly, tabs = [], } = props - const { path: pathFromContext, schemaPath } = useFieldPath() + const { path: pathFromContext, permissions, schemaPath } = useFieldProps() const path = pathFromContext || pathFromProps || name const { getPreference, setPreference } = usePreferences() const { preferencesKey } = useDocumentInfo() @@ -131,28 +129,24 @@ const TabsField: React.FC = (props) => { .join(' ')} > {Description} - - - + /> )} diff --git a/packages/ui/src/forms/fields/Text/index.tsx b/packages/ui/src/forms/fields/Text/index.tsx index d0cea9195..196f8079d 100644 --- a/packages/ui/src/forms/fields/Text/index.tsx +++ b/packages/ui/src/forms/fields/Text/index.tsx @@ -9,7 +9,7 @@ import type { Props } from './types.js' import { useConfig } from '../../../providers/Config/index.js' import { useLocale } from '../../../providers/Locale/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { isFieldRTL } from '../shared.js' import { TextInput } from './Input.js' diff --git a/packages/ui/src/forms/fields/Textarea/index.tsx b/packages/ui/src/forms/fields/Textarea/index.tsx index 9c8152790..2a9792abc 100644 --- a/packages/ui/src/forms/fields/Textarea/index.tsx +++ b/packages/ui/src/forms/fields/Textarea/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/destructuring-assignment */ 'use client' import type { ClientValidate } from 'payload/types' @@ -9,7 +10,7 @@ import type { Props } from './types.js' import { useConfig } from '../../../providers/Config/index.js' import { useTranslation } from '../../../providers/Translation/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { withCondition } from '../../withCondition/index.js' import { isFieldRTL } from '../shared.js' import { TextareaInput } from './Input.js' diff --git a/packages/ui/src/forms/fields/Upload/index.tsx b/packages/ui/src/forms/fields/Upload/index.tsx index 1ee5b20df..3748c542f 100644 --- a/packages/ui/src/forms/fields/Upload/index.tsx +++ b/packages/ui/src/forms/fields/Upload/index.tsx @@ -5,7 +5,7 @@ import type { Props } from './types.js' import { useConfig } from '../../../providers/Config/index.js' import LabelComp from '../../Label/index.js' -import useField from '../../useField/index.js' +import { useField } from '../../useField/index.js' import { UploadInput } from './Input.js' import './index.scss' diff --git a/packages/ui/src/forms/fields/shared.ts b/packages/ui/src/forms/fields/shared.ts index 7ef95b567..7bff8e457 100644 --- a/packages/ui/src/forms/fields/shared.ts +++ b/packages/ui/src/forms/fields/shared.ts @@ -31,9 +31,9 @@ export type FormFieldBase = { Error?: React.ReactNode Label?: React.ReactNode className?: string + disabled?: boolean docPreferences?: DocumentPreferences fieldMap?: FieldMap - fieldPermissions?: FieldPermissions initialSubfieldState?: FormState label?: string locale?: Locale diff --git a/packages/ui/src/forms/useField/index.tsx b/packages/ui/src/forms/useField/index.tsx index 70bdce188..b0af1a79f 100644 --- a/packages/ui/src/forms/useField/index.tsx +++ b/packages/ui/src/forms/useField/index.tsx @@ -10,21 +10,18 @@ import { useConfig } from '../../providers/Config/index.js' import { useDocumentInfo } from '../../providers/DocumentInfo/index.js' import { useOperation } from '../../providers/OperationProvider/index.js' import { useTranslation } from '../../providers/Translation/index.js' -import { useFieldPath } from '../FieldPathProvider/index.js' +import { useFieldProps } from '../FieldPropsProvider/index.js' import { useForm, useFormFields, useFormProcessing, useFormSubmitted } from '../Form/context.js' -import { useReadOnly } from '../ReadOnlyProvider/index.js' /** * Get and set the value of a form field. * * @see https://payloadcms.com/docs/admin/hooks#usefield */ -const useField = (options: Options): FieldType => { +export const useField = (options: Options): FieldType => { const { disableFormData = false, hasRows, validate } = options - const { path: pathFromContext, schemaPath } = useFieldPath() - - const readOnly = useReadOnly() + const { path: pathFromContext, permissions, readOnly, schemaPath } = useFieldProps() const path = options.path || pathFromContext @@ -86,6 +83,7 @@ const useField = (options: Options): FieldType => { formSubmitted: submitted, initialValue, path, + permissions, readOnly: readOnly || false, rows: field?.rows, schemaPath, @@ -107,6 +105,7 @@ const useField = (options: Options): FieldType => { path, schemaPath, readOnly, + permissions, ], ) @@ -190,5 +189,3 @@ const useField = (options: Options): FieldType => { return result } - -export default useField diff --git a/packages/ui/src/forms/useField/types.ts b/packages/ui/src/forms/useField/types.ts index ca30f11bc..f577598b9 100644 --- a/packages/ui/src/forms/useField/types.ts +++ b/packages/ui/src/forms/useField/types.ts @@ -1,4 +1,4 @@ -import type { ClientValidate, Row } from 'payload/types' +import type { ClientValidate, FieldPermissions, Row } from 'payload/types' export type Options = { disableFormData?: boolean @@ -16,6 +16,7 @@ export type FieldType = { formSubmitted: boolean initialValue?: T path: string + permissions: FieldPermissions readOnly?: boolean rows?: Row[] schemaPath: string diff --git a/packages/ui/src/forms/withCondition/index.tsx b/packages/ui/src/forms/withCondition/index.tsx index 6f0c33891..5b7da2647 100644 --- a/packages/ui/src/forms/withCondition/index.tsx +++ b/packages/ui/src/forms/withCondition/index.tsx @@ -1,7 +1,7 @@ 'use client' import React from 'react' -import { useFieldPath } from '../FieldPathProvider/index.js' +import { useFieldProps } from '../FieldPropsProvider/index.js' import { WatchCondition } from './WatchCondition.js' export const withCondition =

>( @@ -9,7 +9,7 @@ export const withCondition =

>( ): React.FC

=> { const CheckForCondition: React.FC

= (props) => { const { name } = props - const { path: pathFromContext } = useFieldPath() + const { path: pathFromContext } = useFieldProps() const path = pathFromContext || name return ( diff --git a/packages/ui/src/utilities/buildComponentMap/index.tsx b/packages/ui/src/utilities/buildComponentMap/index.tsx index 3660a9921..5fb7a087c 100644 --- a/packages/ui/src/utilities/buildComponentMap/index.tsx +++ b/packages/ui/src/utilities/buildComponentMap/index.tsx @@ -1,4 +1,3 @@ -import type { CollectionPermission, GlobalPermission, Permissions } from 'payload/auth' import type { EditViewProps, SanitizedConfig } from 'payload/types' import React from 'react' @@ -14,7 +13,6 @@ export const buildComponentMap = (args: { DefaultListView: React.FC children: React.ReactNode config: SanitizedConfig - permissions?: Permissions readOnly?: boolean }): { componentMap: ComponentMap @@ -26,18 +24,13 @@ export const buildComponentMap = (args: { DefaultListView, children, config, - permissions, readOnly: readOnlyOverride, } = args - let entityPermissions: CollectionPermission | GlobalPermission - // Collections const collections = config.collections.reduce((acc, collectionConfig) => { const { slug, fields } = collectionConfig - entityPermissions = permissions?.collections?.[collectionConfig.slug] - const editViewFromConfig = collectionConfig?.admin?.components?.views?.Edit const listViewFromConfig = collectionConfig?.admin?.components?.views?.List @@ -113,7 +106,6 @@ export const buildComponentMap = (args: { DefaultCell, config, fieldSchema: fields, - permissions: entityPermissions?.fields, readOnly: readOnlyOverride, }), } @@ -128,8 +120,6 @@ export const buildComponentMap = (args: { const globals = config.globals.reduce((acc, globalConfig) => { const { slug, fields } = globalConfig - entityPermissions = permissions?.globals?.[globalConfig.slug] - const editViewFromConfig = globalConfig?.admin?.components?.views?.Edit const CustomEditView = @@ -154,7 +144,6 @@ export const buildComponentMap = (args: { DefaultCell, config, fieldSchema: fields, - permissions: entityPermissions?.fields, readOnly: readOnlyOverride, }), } diff --git a/packages/ui/src/utilities/buildComponentMap/mapFields.tsx b/packages/ui/src/utilities/buildComponentMap/mapFields.tsx index e429948d2..3d877ece0 100644 --- a/packages/ui/src/utilities/buildComponentMap/mapFields.tsx +++ b/packages/ui/src/utilities/buildComponentMap/mapFields.tsx @@ -1,4 +1,3 @@ -import type { CollectionPermission, FieldPermissions, GlobalPermission } from 'payload/auth' import type { CellProps, Field, FieldWithPath, LabelProps, SanitizedConfig } from 'payload/types' import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/types' @@ -22,18 +21,9 @@ export const mapFields = (args: { fieldSchema: FieldWithPath[] filter?: (field: Field) => boolean parentPath?: string - permissions?: CollectionPermission['fields'] | GlobalPermission['fields'] readOnly?: boolean }): FieldMap => { - const { - DefaultCell, - config, - fieldSchema, - filter, - parentPath, - permissions, - readOnly: readOnlyOverride, - } = args + const { DefaultCell, config, fieldSchema, filter, parentPath, readOnly: readOnlyOverride } = args const result: FieldMap = fieldSchema.reduce((acc, field): FieldMap => { const fieldIsPresentational = fieldIsPresentationalOnly(field) @@ -51,8 +41,6 @@ export const mapFields = (args: { field.path || (isFieldAffectingData && 'name' in field ? field.name : '') }` - const fieldPermissions = isFieldAffectingData ? permissions?.[field.name] : undefined - const labelProps: LabelProps = { // @ts-expect-error-next-line label: 'label' in field ? field.label : null, @@ -78,7 +66,6 @@ export const mapFields = (args: { fieldSchema: field.fields, filter, parentPath: path, - permissions, readOnly: readOnlyOverride, }) @@ -94,7 +81,6 @@ export const mapFields = (args: { fieldSchema: tab.fields, filter, parentPath: path, - permissions, readOnly: readOnlyOverride, }) @@ -119,7 +105,6 @@ export const mapFields = (args: { fieldSchema: block.fields, filter, parentPath: `${path}.${block.slug}`, - permissions, readOnly: readOnlyOverride, }) @@ -199,8 +184,8 @@ export const mapFields = (args: { className: 'admin' in field && 'className' in field.admin ? field?.admin?.className : undefined, date: 'admin' in field && 'date' in field.admin ? field.admin.date : undefined, + disabled: field?.admin && 'disabled' in field.admin ? field.admin?.disabled : false, fieldMap: nestedFieldMap, - fieldPermissions, hasMany: 'hasMany' in field ? field.hasMany : undefined, label: 'label' in field && typeof field.label === 'string' ? field.label : undefined, max: 'max' in field ? field.max : undefined, @@ -318,8 +303,8 @@ export const mapFields = (args: { /> ), blocks, + disabled: field?.admin && 'disabled' in field.admin ? field.admin?.disabled : false, fieldIsPresentational, - fieldPermissions, hasMany: 'hasMany' in field ? field.hasMany : undefined, isFieldAffectingData, isSidebar: 'admin' in field && field.admin?.position === 'sidebar', @@ -354,7 +339,6 @@ export const mapFields = (args: { Field: , Heading: , fieldIsPresentational: false, - fieldPermissions: {} as FieldPermissions, isFieldAffectingData: true, isSidebar: false, label: 'ID', diff --git a/packages/ui/src/utilities/buildComponentMap/types.ts b/packages/ui/src/utilities/buildComponentMap/types.ts index ac7db4fdf..770ffa0c5 100644 --- a/packages/ui/src/utilities/buildComponentMap/types.ts +++ b/packages/ui/src/utilities/buildComponentMap/types.ts @@ -1,4 +1,3 @@ -import type { FieldPermissions } from 'payload/auth' import type { BlockField, FieldBase, @@ -35,13 +34,13 @@ export type MappedField = { * On `block` fields only */ blocks?: ReducedBlock[] + disabled?: boolean /** * On `richText` fields only */ editor?: RichTextField['editor'] fieldIsPresentational: boolean fieldMap?: FieldMap - fieldPermissions: FieldPermissions hasMany?: boolean isFieldAffectingData: boolean isSidebar: boolean diff --git a/tsconfig.json b/tsconfig.json index 6cab4e76d..0fa2bc28b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -88,7 +88,7 @@ "./packages/graphql/src" ], "@payload-config": [ - "./test/admin/config.ts" + "./test/access-control/config.ts" ] } },