Merge branch 'feat/doc-permissions' into alpha
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -16,6 +16,9 @@ export const CreateFirstUserFields: React.FC<{
|
||||
<RenderFields
|
||||
fieldMap={[...(fieldMap || []), ...(createFirstUserFieldMap || [])]}
|
||||
operation="create"
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath={userSlug}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<main className={classes}>
|
||||
<FieldPathProvider path="" schemaPath={entitySlug}>
|
||||
<OperationProvider operation={operation}>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={!hasSavePermission}
|
||||
initialState={initialState}
|
||||
method={id ? 'PATCH' : 'POST'}
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
>
|
||||
<FormLoadingOverlayToggle
|
||||
action={operation}
|
||||
// formIsLoading={isLoading}
|
||||
// loadingSuffix={getTranslation(collectionConfig.labels.singular, i18n)}
|
||||
name={`collection-edit--${
|
||||
typeof collectionConfig?.labels?.singular === 'string'
|
||||
? collectionConfig.labels.singular
|
||||
: 'document'
|
||||
}`}
|
||||
type="withoutNav"
|
||||
/>
|
||||
{BeforeDocument}
|
||||
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
globalSlug={globalConfig?.slug}
|
||||
id={id}
|
||||
pluralLabel={collectionConfig?.labels?.plural}
|
||||
useAsTitle={collectionConfig?.admin?.useAsTitle}
|
||||
/>
|
||||
<SetDocumentTitle
|
||||
collectionConfig={collectionConfig}
|
||||
config={config}
|
||||
fallback={depth <= 1 ? id?.toString() : undefined}
|
||||
globalConfig={globalConfig}
|
||||
/>
|
||||
<DocumentControls
|
||||
apiURL={apiURL}
|
||||
data={data}
|
||||
disableActions={disableActions}
|
||||
hasSavePermission={hasSavePermission}
|
||||
id={id}
|
||||
isEditing={Boolean(id)}
|
||||
permissions={docPermissions}
|
||||
slug={collectionConfig?.slug}
|
||||
/>
|
||||
<DocumentFields
|
||||
AfterFields={AfterFields}
|
||||
BeforeFields={
|
||||
BeforeFields || (
|
||||
<Fragment>
|
||||
{auth && (
|
||||
<Auth
|
||||
className={`${baseClass}__auth`}
|
||||
<OperationProvider operation={operation}>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={!hasSavePermission}
|
||||
initialState={initialState}
|
||||
method={id ? 'PATCH' : 'POST'}
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
>
|
||||
<FormLoadingOverlayToggle
|
||||
action={operation}
|
||||
// formIsLoading={isLoading}
|
||||
// loadingSuffix={getTranslation(collectionConfig.labels.singular, i18n)}
|
||||
name={`collection-edit--${
|
||||
typeof collectionConfig?.labels?.singular === 'string'
|
||||
? collectionConfig.labels.singular
|
||||
: 'document'
|
||||
}`}
|
||||
type="withoutNav"
|
||||
/>
|
||||
{BeforeDocument}
|
||||
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
collectionSlug={collectionConfig?.slug}
|
||||
globalSlug={globalConfig?.slug}
|
||||
id={id}
|
||||
pluralLabel={collectionConfig?.labels?.plural}
|
||||
useAsTitle={collectionConfig?.admin?.useAsTitle}
|
||||
/>
|
||||
<SetDocumentTitle
|
||||
collectionConfig={collectionConfig}
|
||||
config={config}
|
||||
fallback={depth <= 1 ? id?.toString() : undefined}
|
||||
globalConfig={globalConfig}
|
||||
/>
|
||||
<DocumentControls
|
||||
apiURL={apiURL}
|
||||
data={data}
|
||||
disableActions={disableActions}
|
||||
hasSavePermission={hasSavePermission}
|
||||
id={id}
|
||||
isEditing={Boolean(id)}
|
||||
permissions={docPermissions}
|
||||
slug={collectionConfig?.slug}
|
||||
/>
|
||||
<DocumentFields
|
||||
AfterFields={AfterFields}
|
||||
BeforeFields={
|
||||
BeforeFields || (
|
||||
<Fragment>
|
||||
{auth && (
|
||||
<Auth
|
||||
className={`${baseClass}__auth`}
|
||||
collectionSlug={collectionConfig.slug}
|
||||
email={data?.email}
|
||||
operation={operation}
|
||||
readOnly={!hasSavePermission}
|
||||
requirePassword={!id}
|
||||
useAPIKey={auth.useAPIKey}
|
||||
verify={auth.verify}
|
||||
/>
|
||||
)}
|
||||
{upload && (
|
||||
<React.Fragment>
|
||||
{RegisterGetThumbnailFunction && <RegisterGetThumbnailFunction />}
|
||||
<Upload
|
||||
collectionSlug={collectionConfig.slug}
|
||||
email={data?.email}
|
||||
operation={operation}
|
||||
readOnly={!hasSavePermission}
|
||||
requirePassword={!id}
|
||||
useAPIKey={auth.useAPIKey}
|
||||
verify={auth.verify}
|
||||
initialState={initialState}
|
||||
uploadConfig={upload}
|
||||
/>
|
||||
)}
|
||||
{upload && (
|
||||
<React.Fragment>
|
||||
{RegisterGetThumbnailFunction && <RegisterGetThumbnailFunction />}
|
||||
<Upload
|
||||
collectionSlug={collectionConfig.slug}
|
||||
initialState={initialState}
|
||||
uploadConfig={upload}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
fieldMap={fieldMap}
|
||||
/>
|
||||
{AfterDocument}
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</FieldPathProvider>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
docPermissions={docPermissions}
|
||||
fieldMap={fieldMap}
|
||||
readOnly={!hasSavePermission}
|
||||
schemaPath={entitySlug}
|
||||
/>
|
||||
{AfterDocument}
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<Fragment>
|
||||
<FieldPathProvider path="" schemaPath={schemaPath}>
|
||||
<OperationProvider operation={operation}>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={!hasSavePermission}
|
||||
initialState={initialState}
|
||||
method={id ? 'PATCH' : 'POST'}
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
<OperationProvider operation={operation}>
|
||||
<Form
|
||||
action={action}
|
||||
className={`${baseClass}__form`}
|
||||
disabled={!hasSavePermission}
|
||||
initialState={initialState}
|
||||
method={id ? 'PATCH' : 'POST'}
|
||||
onChange={[onChange]}
|
||||
onSuccess={onSave}
|
||||
>
|
||||
{((collectionConfig &&
|
||||
!(collectionConfig.versions?.drafts && collectionConfig.versions?.drafts?.autosave)) ||
|
||||
(global && !(global.versions?.drafts && global.versions?.drafts?.autosave))) &&
|
||||
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
collectionSlug={collectionSlug}
|
||||
globalLabel={globalConfig?.label}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
view={t('general:livePreview')}
|
||||
/>
|
||||
<SetDocumentTitle
|
||||
collectionConfig={collectionConfig}
|
||||
config={config}
|
||||
fallback={id?.toString() || ''}
|
||||
globalConfig={globalConfig}
|
||||
/>
|
||||
<DocumentControls
|
||||
apiURL={apiURL}
|
||||
data={data}
|
||||
disableActions={disableActions}
|
||||
hasSavePermission={hasSavePermission}
|
||||
id={id}
|
||||
isEditing={Boolean(id)}
|
||||
permissions={docPermissions}
|
||||
slug={collectionConfig?.slug}
|
||||
/>
|
||||
<div
|
||||
className={[baseClass, previewWindowType === 'popup' && `${baseClass}--detached`]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{((collectionConfig &&
|
||||
!(
|
||||
collectionConfig.versions?.drafts && collectionConfig.versions?.drafts?.autosave
|
||||
)) ||
|
||||
(global && !(global.versions?.drafts && global.versions?.drafts?.autosave))) &&
|
||||
!disableLeaveWithoutSaving && <LeaveWithoutSaving />}
|
||||
<SetStepNav
|
||||
collectionSlug={collectionSlug}
|
||||
globalLabel={globalConfig?.label}
|
||||
globalSlug={globalSlug}
|
||||
id={id}
|
||||
view={t('general:livePreview')}
|
||||
/>
|
||||
<SetDocumentTitle
|
||||
collectionConfig={collectionConfig}
|
||||
config={config}
|
||||
fallback={id?.toString() || ''}
|
||||
globalConfig={globalConfig}
|
||||
/>
|
||||
<DocumentControls
|
||||
apiURL={apiURL}
|
||||
data={data}
|
||||
disableActions={disableActions}
|
||||
hasSavePermission={hasSavePermission}
|
||||
id={id}
|
||||
isEditing={Boolean(id)}
|
||||
permissions={docPermissions}
|
||||
slug={collectionConfig?.slug}
|
||||
/>
|
||||
<div
|
||||
className={[baseClass, previewWindowType === 'popup' && `${baseClass}--detached`]
|
||||
className={[
|
||||
`${baseClass}__main`,
|
||||
previewWindowType === 'popup' && `${baseClass}__main--popup-open`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
<div
|
||||
className={[
|
||||
`${baseClass}__main`,
|
||||
previewWindowType === 'popup' && `${baseClass}__main--popup-open`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{BeforeDocument}
|
||||
<DocumentFields
|
||||
AfterFields={AfterFields}
|
||||
BeforeFields={BeforeFields}
|
||||
fieldMap={fieldMap}
|
||||
forceSidebarWrap
|
||||
/>
|
||||
{AfterDocument}
|
||||
</div>
|
||||
<LivePreview {...props} />
|
||||
{BeforeDocument}
|
||||
<DocumentFields
|
||||
AfterFields={AfterFields}
|
||||
BeforeFields={BeforeFields}
|
||||
docPermissions={docPermissions}
|
||||
fieldMap={fieldMap}
|
||||
forceSidebarWrap
|
||||
readOnly={!hasSavePermission}
|
||||
schemaPath={collectionSlug}
|
||||
/>
|
||||
{AfterDocument}
|
||||
</div>
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</FieldPathProvider>
|
||||
<LivePreview {...props} />
|
||||
</div>
|
||||
</Form>
|
||||
</OperationProvider>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -65,7 +65,7 @@ export const BlockContent: React.FC<Props> = (props) => {
|
||||
const [collapsed, setCollapsed] = React.useState<boolean>(() => {
|
||||
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> = (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> = (props) => {
|
||||
fieldMap={Array.isArray(formSchema) ? formSchema : []}
|
||||
forceRender
|
||||
margins="small"
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath=""
|
||||
/>
|
||||
</Collapsible>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
import {
|
||||
FieldPathProvider,
|
||||
Form,
|
||||
type FormProps,
|
||||
getFormState,
|
||||
@@ -124,25 +123,23 @@ export const BlockComponent: React.FC<Props> = (props) => {
|
||||
return (
|
||||
reducedBlock &&
|
||||
initialState !== false && (
|
||||
<FieldPathProvider path="" schemaPath="">
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={fieldMap}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
submitted={submitted}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<BlockContent
|
||||
baseClass={baseClass}
|
||||
field={parentLexicalRichTextField}
|
||||
formData={formData}
|
||||
formSchema={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
nodeKey={nodeKey}
|
||||
reducedBlock={reducedBlock}
|
||||
/>
|
||||
</Form>
|
||||
</FieldPathProvider>
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={fieldMap}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
submitted={submitted}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<BlockContent
|
||||
baseClass={baseClass}
|
||||
field={parentLexicalRichTextField}
|
||||
formData={formData}
|
||||
formSchema={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
nodeKey={nodeKey}
|
||||
reducedBlock={reducedBlock}
|
||||
/>
|
||||
</Form>
|
||||
)
|
||||
)
|
||||
}, [
|
||||
|
||||
@@ -78,20 +78,24 @@ export const LinkDrawer: React.FC<Props> = ({ drawerSlug, handleModalSubmit, sta
|
||||
return (
|
||||
<Drawer className={baseClass} slug={drawerSlug} title={t('fields:editLink') ?? ''}>
|
||||
{initialState !== false && (
|
||||
<FieldPathProvider path="" schemaPath="">
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
onSubmit={handleModalSubmit}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<RenderFields fieldMap={Array.isArray(fieldMap) ? fieldMap : []} forceRender />
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
onSubmit={handleModalSubmit}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<RenderFields
|
||||
fieldMap={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
forceRender
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath=""
|
||||
/>
|
||||
|
||||
<FormSubmit>{t('general:submit')}</FormSubmit>
|
||||
</Form>
|
||||
</FieldPathProvider>
|
||||
<FormSubmit>{t('general:submit')}</FormSubmit>
|
||||
</Form>
|
||||
)}
|
||||
</Drawer>
|
||||
)
|
||||
|
||||
@@ -130,19 +130,23 @@ export const ExtraFieldsUploadDrawer: React.FC<
|
||||
})}
|
||||
>
|
||||
{initialState !== false && (
|
||||
<FieldPathProvider path="" schemaPath="">
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={fieldMap}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
onSubmit={handleUpdateEditData}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<RenderFields fieldMap={Array.isArray(fieldMap) ? fieldMap : []} forceRender />
|
||||
<FormSubmit>{t('fields:saveChanges')}</FormSubmit>
|
||||
</Form>
|
||||
</FieldPathProvider>
|
||||
<Form
|
||||
// @ts-expect-error // TODO: Fix this type. Is this correct?
|
||||
fields={fieldMap}
|
||||
initialState={initialState}
|
||||
onChange={[onChange]}
|
||||
onSubmit={handleUpdateEditData}
|
||||
uuid={uuid()}
|
||||
>
|
||||
<RenderFields
|
||||
fieldMap={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
forceRender
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath=""
|
||||
/>
|
||||
<FormSubmit>{t('fields:saveChanges')}</FormSubmit>
|
||||
</Form>
|
||||
)}
|
||||
</Drawer>
|
||||
)
|
||||
|
||||
@@ -82,7 +82,6 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: sanitizedFields,
|
||||
permissions: {},
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
|
||||
@@ -54,14 +54,12 @@ export const LinkDrawer: React.FC<Props> = ({
|
||||
)
|
||||
|
||||
return (
|
||||
<FieldPathProvider path="" schemaPath="">
|
||||
<Drawer className={baseClass} slug={drawerSlug} title={t('fields:editLink')}>
|
||||
<Form initialState={initialState} onChange={[onChange]} onSubmit={handleModalSubmit}>
|
||||
<RenderFields fieldMap={fieldMap} forceRender />
|
||||
<LinkSubmit />
|
||||
</Form>
|
||||
</Drawer>
|
||||
</FieldPathProvider>
|
||||
<Drawer className={baseClass} slug={drawerSlug} title={t('fields:editLink')}>
|
||||
<Form initialState={initialState} onChange={[onChange]} onSubmit={handleModalSubmit}>
|
||||
<RenderFields fieldMap={fieldMap} forceRender path="" readOnly={false} schemaPath="" />
|
||||
<LinkSubmit />
|
||||
</Form>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -109,12 +109,15 @@ export const UploadDrawer: React.FC<{
|
||||
label: getTranslation(relatedCollection.labels.singular, i18n),
|
||||
})}
|
||||
>
|
||||
<FieldPathProvider path="" schemaPath="">
|
||||
<Form initialState={initialState} onSubmit={handleUpdateEditData}>
|
||||
<RenderFields fieldMap={Array.isArray(fieldMap) ? fieldMap : []} />
|
||||
<FormSubmit>{t('fields:saveChanges')}</FormSubmit>
|
||||
</Form>
|
||||
</FieldPathProvider>
|
||||
<Form initialState={initialState} onSubmit={handleUpdateEditData}>
|
||||
<RenderFields
|
||||
fieldMap={Array.isArray(fieldMap) ? fieldMap : []}
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath=""
|
||||
/>
|
||||
<FormSubmit>{t('fields:saveChanges')}</FormSubmit>
|
||||
</Form>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
|
||||
@@ -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<DocumentDrawerProps> = ({
|
||||
|
||||
const { permissions } = useAuth()
|
||||
|
||||
const { schemaPath } = useFieldPath()
|
||||
const { schemaPath } = useFieldProps()
|
||||
|
||||
const { componentMap } = useComponentMap()
|
||||
|
||||
@@ -197,9 +197,5 @@ export const DocumentDrawerContent: React.FC<DocumentDrawerProps> = (props) => {
|
||||
[onSaveFromProps, collectionConfig],
|
||||
)
|
||||
|
||||
return (
|
||||
<FieldPathProvider path="" schemaPath={collectionSlug}>
|
||||
<Content {...props} id={idFromProps || doc?.id} initialData={doc} onSave={onSave} />
|
||||
</FieldPathProvider>
|
||||
)
|
||||
return <Content {...props} id={idFromProps || doc?.id} initialData={doc} onSave={onSave} />
|
||||
}
|
||||
|
||||
@@ -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<Args> = ({
|
||||
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<{
|
||||
)}
|
||||
</header>
|
||||
{BeforeFields}
|
||||
<RenderFields className={`${baseClass}__fields`} fieldMap={mainFields} />
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={mainFields}
|
||||
path=""
|
||||
permissions={docPermissions?.['fields']}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
{AfterFields}
|
||||
</Gutter>
|
||||
</div>
|
||||
@@ -55,7 +74,13 @@ export const DocumentFields: React.FC<{
|
||||
<div className={`${baseClass}__sidebar-wrap`}>
|
||||
<div className={`${baseClass}__sidebar`}>
|
||||
<div className={`${baseClass}__sidebar-fields`}>
|
||||
<RenderFields fieldMap={sidebarFields} />
|
||||
<RenderFields
|
||||
fieldMap={sidebarFields}
|
||||
path=""
|
||||
permissions={docPermissions?.fields}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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> = (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> = (props) => {
|
||||
<X />
|
||||
</button>
|
||||
</div>
|
||||
<FieldPathProvider path="" schemaPath={slug}>
|
||||
<Form
|
||||
className={`${baseClass}__form`}
|
||||
initialState={initialState}
|
||||
onSuccess={onSuccess}
|
||||
>
|
||||
<FieldSelect fields={fields} setSelected={setSelected} />
|
||||
{reducedFieldMap.length === 0 ? null : (
|
||||
<RenderFields fieldMap={reducedFieldMap} />
|
||||
)}
|
||||
<div className={`${baseClass}__sidebar-wrap`}>
|
||||
<div className={`${baseClass}__sidebar`}>
|
||||
<div className={`${baseClass}__sidebar-sticky-wrap`}>
|
||||
<div className={`${baseClass}__document-actions`}>
|
||||
{collection?.versions?.drafts ? (
|
||||
<React.Fragment>
|
||||
<Publish
|
||||
action={`${serverURL}${apiRoute}/${slug}${getQueryParams()}`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
<SaveDraft
|
||||
action={`${serverURL}${apiRoute}/${slug}${getQueryParams()}`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<Submit
|
||||
<Form
|
||||
className={`${baseClass}__form`}
|
||||
initialState={initialState}
|
||||
onSuccess={onSuccess}
|
||||
>
|
||||
<FieldSelect fields={fields} setSelected={setSelected} />
|
||||
{reducedFieldMap.length === 0 ? null : (
|
||||
<RenderFields
|
||||
fieldMap={reducedFieldMap}
|
||||
path=""
|
||||
readOnly={false}
|
||||
schemaPath={slug}
|
||||
/>
|
||||
)}
|
||||
<div className={`${baseClass}__sidebar-wrap`}>
|
||||
<div className={`${baseClass}__sidebar`}>
|
||||
<div className={`${baseClass}__sidebar-sticky-wrap`}>
|
||||
<div className={`${baseClass}__document-actions`}>
|
||||
{collection?.versions?.drafts ? (
|
||||
<React.Fragment>
|
||||
<Publish
|
||||
action={`${serverURL}${apiRoute}/${slug}${getQueryParams()}`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<SaveDraft
|
||||
action={`${serverURL}${apiRoute}/${slug}${getQueryParams()}`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<Submit
|
||||
action={`${serverURL}${apiRoute}/${slug}${getQueryParams()}`}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</FieldPathProvider>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</OperationContext.Provider>
|
||||
</DocumentInfoProvider>
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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<ErrorProps> = (props) => {
|
||||
showError: showErrorFromProps,
|
||||
} = props
|
||||
|
||||
const { path: pathFromContext } = useFieldPath()
|
||||
const { path: pathFromContext } = useFieldProps()
|
||||
const path = pathFromProps || pathFromContext
|
||||
|
||||
const hasSubmitted = useFormSubmitted()
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
type FieldPathContextType = {
|
||||
path: string
|
||||
schemaPath: string
|
||||
}
|
||||
|
||||
const FieldPathContext = React.createContext<FieldPathContextType>({
|
||||
path: '',
|
||||
schemaPath: '',
|
||||
})
|
||||
|
||||
export const FieldPathProvider: React.FC<{
|
||||
children: React.ReactNode
|
||||
path: string
|
||||
schemaPath: string
|
||||
}> = (props) => {
|
||||
const { children, path, schemaPath } = props
|
||||
|
||||
return (
|
||||
<FieldPathContext.Provider
|
||||
value={{
|
||||
path,
|
||||
schemaPath,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</FieldPathContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useFieldPath = () => {
|
||||
const path = React.useContext(FieldPathContext)
|
||||
return path
|
||||
}
|
||||
61
packages/ui/src/forms/FieldPropsProvider/index.tsx
Normal file
61
packages/ui/src/forms/FieldPropsProvider/index.tsx
Normal file
@@ -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<FieldPropsContextType>({
|
||||
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<Props> = ({
|
||||
children,
|
||||
path,
|
||||
permissions,
|
||||
readOnly,
|
||||
schemaPath,
|
||||
siblingPermissions,
|
||||
}) => {
|
||||
return (
|
||||
<FieldPropsContext.Provider
|
||||
value={{
|
||||
path,
|
||||
permissions,
|
||||
readOnly,
|
||||
schemaPath,
|
||||
siblingPermissions,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</FieldPropsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useFieldProps = () => {
|
||||
const path = React.useContext(FieldPropsContext)
|
||||
return path
|
||||
}
|
||||
@@ -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<LabelProps> = (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()
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
|
||||
const ReadOnlyContext = React.createContext<boolean | undefined>(undefined)
|
||||
|
||||
export const ReadOnlyProvider: React.FC<{
|
||||
children: React.ReactNode
|
||||
readOnly?: boolean
|
||||
}> = (props) => {
|
||||
const { children, readOnly } = props
|
||||
|
||||
return <ReadOnlyContext.Provider value={readOnly}>{children}</ReadOnlyContext.Provider>
|
||||
}
|
||||
|
||||
export const useReadOnly = () => {
|
||||
const path = React.useContext(ReadOnlyContext)
|
||||
return path
|
||||
}
|
||||
@@ -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<Props> = ({
|
||||
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 (
|
||||
<ReadOnlyProvider readOnly={readOnly}>
|
||||
<FieldPathProvider path={path} schemaPath={schemaPath}>
|
||||
{Field}
|
||||
</FieldPathProvider>
|
||||
</ReadOnlyProvider>
|
||||
<FieldPropsProvider
|
||||
path={path}
|
||||
permissions={permissions}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
siblingPermissions={siblingPermissions}
|
||||
>
|
||||
{Field}
|
||||
</FieldPropsProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import './index.scss'
|
||||
|
||||
const baseClass = 'render-fields'
|
||||
|
||||
const RenderFields: React.FC<Props> = (props) => {
|
||||
const { className, fieldMap, forceRender, margins } = props
|
||||
export const RenderFields: React.FC<Props> = (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> = (props) => {
|
||||
ref={intersectionRef}
|
||||
>
|
||||
{hasRendered &&
|
||||
fieldMap?.map(({ name, Field, fieldPermissions, readOnly }, fieldIndex) => (
|
||||
<RenderField
|
||||
Field={Field}
|
||||
fieldPermissions={fieldPermissions}
|
||||
key={fieldIndex}
|
||||
name={name}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
))}
|
||||
fieldMap?.map(({ name, Field, disabled, readOnly }, fieldIndex) => {
|
||||
return (
|
||||
<RenderField
|
||||
Field={Field}
|
||||
disabled={disabled}
|
||||
key={fieldIndex}
|
||||
name={name}
|
||||
path={path}
|
||||
permissions={permissions?.[name]}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
siblingPermissions={permissions}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default RenderFields
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<ArrayRowProps> = ({
|
||||
listeners,
|
||||
moveRow,
|
||||
path: parentPath,
|
||||
permissions,
|
||||
readOnly,
|
||||
removeRow,
|
||||
row,
|
||||
@@ -122,17 +123,16 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
onToggle={(collapsed) => setCollapse(row.id, collapsed)}
|
||||
>
|
||||
<HiddenInput name={`${path}.id`} value={row.id} />
|
||||
<FieldPathProvider path={path} schemaPath={parentPath}>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={fieldMap}
|
||||
forceRender={forceRender}
|
||||
// indexPath={indexPath}
|
||||
margins="small"
|
||||
// permissions={permissions?.fields}
|
||||
// readOnly={readOnly}
|
||||
/>
|
||||
</FieldPathProvider>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={fieldMap}
|
||||
forceRender={forceRender}
|
||||
margins="small"
|
||||
path={path}
|
||||
permissions={permissions?.fields}
|
||||
readOnly={readOnly}
|
||||
schemaPath={parentPath}
|
||||
/>
|
||||
</Collapsible>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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<BlockFieldProps> = ({
|
||||
listeners,
|
||||
moveRow,
|
||||
path: parentPath,
|
||||
permissions,
|
||||
readOnly,
|
||||
removeRow,
|
||||
row,
|
||||
@@ -132,17 +133,16 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
onToggle={(collapsed) => setCollapse(row.id, collapsed)}
|
||||
>
|
||||
<HiddenInput name={`${path}.id`} value={row.id} />
|
||||
<FieldPathProvider path={path} schemaPath={`${schemaPath}.${block.slug}`}>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={block.subfields}
|
||||
forceRender={forceRender}
|
||||
// indexPath={indexPath}
|
||||
margins="small"
|
||||
// permissions={permissions?.blocks?.[row.blockType]?.fields}
|
||||
// readOnly={readOnly}
|
||||
/>
|
||||
</FieldPathProvider>
|
||||
<RenderFields
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={block.subfields}
|
||||
forceRender={forceRender}
|
||||
margins="small"
|
||||
path={path}
|
||||
permissions={permissions?.blocks?.[block.slug]?.fields}
|
||||
readOnly={readOnly}
|
||||
schemaPath={`${schemaPath}.${block.slug}`}
|
||||
/>
|
||||
</Collapsible>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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> = (props) => {
|
||||
label,
|
||||
localized,
|
||||
path: pathFromProps,
|
||||
permissions,
|
||||
readOnly,
|
||||
required,
|
||||
validate,
|
||||
@@ -91,6 +90,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
const {
|
||||
path,
|
||||
permissions,
|
||||
rows = [],
|
||||
schemaPath,
|
||||
showError,
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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> = (props) => {
|
||||
const {
|
||||
Description,
|
||||
Error,
|
||||
Label: LabelFromProps,
|
||||
className,
|
||||
fieldMap,
|
||||
label,
|
||||
path: pathFromProps,
|
||||
permissions,
|
||||
readOnly,
|
||||
required,
|
||||
} = props
|
||||
|
||||
const Label = LabelFromProps || <LabelComp label={label} required={required} />
|
||||
|
||||
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> = (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> = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
fetchInitialState()
|
||||
void fetchInitialState()
|
||||
}, [getPreference, preferencesKey, fieldPreferencesKey, initCollapsed, path])
|
||||
|
||||
if (typeof collapsedOnMount !== 'boolean') return null
|
||||
@@ -125,10 +123,11 @@ const CollapsibleField: React.FC<Props> = (props) => {
|
||||
<RenderFields
|
||||
fieldMap={fieldMap}
|
||||
forceRender
|
||||
// indexPath={path}
|
||||
margins="small"
|
||||
// permissions={permissions}
|
||||
// readOnly={readOnly}
|
||||
path={path}
|
||||
permissions={siblingPermissions}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
</Collapsible>
|
||||
{Description}
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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> = (props) => {
|
||||
const {
|
||||
name,
|
||||
Description,
|
||||
Label: LabelFromProps,
|
||||
className,
|
||||
@@ -35,7 +34,7 @@ const Group: React.FC<Props> = (props) => {
|
||||
|
||||
const Label = LabelFromProps || <LabelComp label={label} required={required} />
|
||||
|
||||
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> = (props) => {
|
||||
width,
|
||||
}}
|
||||
>
|
||||
<FieldPathProvider path={path} schemaPath={schemaPath}>
|
||||
<GroupProvider>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<div className={`${baseClass}__header`}>
|
||||
{(Label || Description) && (
|
||||
<header>
|
||||
{Label}
|
||||
{Description}
|
||||
</header>
|
||||
)}
|
||||
{fieldHasErrors && <ErrorPill count={errorCount} i18n={i18n} withMessage />}
|
||||
</div>
|
||||
<RenderFields fieldMap={fieldMap} />
|
||||
<GroupProvider>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<div className={`${baseClass}__header`}>
|
||||
{(Label || Description) && (
|
||||
<header>
|
||||
{Label}
|
||||
{Description}
|
||||
</header>
|
||||
)}
|
||||
{fieldHasErrors && <ErrorPill count={errorCount} i18n={i18n} withMessage />}
|
||||
</div>
|
||||
</GroupProvider>
|
||||
</FieldPathProvider>
|
||||
<RenderFields
|
||||
fieldMap={fieldMap}
|
||||
path={path}
|
||||
permissions={permissions?.fields}
|
||||
readOnly={readOnly}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
</div>
|
||||
</GroupProvider>
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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> = (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> = (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> = (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> = (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> = (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> = (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> = (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> = (props) => {
|
||||
onMenuOpen={() => {
|
||||
if (!hasLoadedFirstPage) {
|
||||
setIsLoading(true)
|
||||
getResults({
|
||||
void getResults({
|
||||
onSuccess: () => {
|
||||
setHasLoadedFirstPage(true)
|
||||
setIsLoading(false)
|
||||
@@ -508,7 +508,7 @@ const Relationship: React.FC<Props> = (props) => {
|
||||
}
|
||||
}}
|
||||
onMenuScrollToBottom={() => {
|
||||
getResults({
|
||||
void getResults({
|
||||
lastFullyLoadedRelation,
|
||||
search,
|
||||
sort: false,
|
||||
|
||||
@@ -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> = (props) => {
|
||||
const { className, fieldMap, forceRender = false, indexPath, permissions, readOnly } = props
|
||||
const { className, fieldMap, forceRender = false } = props
|
||||
|
||||
const { path, readOnly, schemaPath, siblingPermissions } = useFieldProps()
|
||||
|
||||
return (
|
||||
<RowProvider>
|
||||
<div className={[fieldBaseClass, baseClass, className].filter(Boolean).join(' ')}>
|
||||
<RenderFields
|
||||
{...{ fieldMap, forceRender, path, readOnly, schemaPath }}
|
||||
className={`${baseClass}__fields`}
|
||||
fieldMap={fieldMap}
|
||||
forceRender={forceRender}
|
||||
// indexPath={indexPath}
|
||||
margins={false}
|
||||
// permissions={permissions}
|
||||
// readOnly={readOnly}
|
||||
permissions={siblingPermissions}
|
||||
/>
|
||||
</div>
|
||||
</RowProvider>
|
||||
|
||||
@@ -8,5 +8,5 @@ export type Props = FormFieldBase & {
|
||||
forceRender?: boolean
|
||||
indexPath: string
|
||||
path?: string
|
||||
permissions: FieldPermissions
|
||||
permissions?: FieldPermissions
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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> = (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> = (props) => {
|
||||
.join(' ')}
|
||||
>
|
||||
{Description}
|
||||
<FieldPathProvider
|
||||
<RenderFields
|
||||
fieldMap={activeTabConfig.subfields}
|
||||
forceRender={forceRender}
|
||||
key={
|
||||
activeTabConfig.label
|
||||
? getTranslation(activeTabConfig.label, i18n)
|
||||
: activeTabConfig['name']
|
||||
}
|
||||
margins="small"
|
||||
path={`${path ? `${path}.` : ''}${activeTabConfig.name ? `${activeTabConfig.name}` : ''}`}
|
||||
permissions={
|
||||
'name' in activeTabConfig && permissions?.fields?.[activeTabConfig.name]?.fields
|
||||
? permissions?.fields?.[activeTabConfig.name]?.fields
|
||||
: permissions?.fields
|
||||
}
|
||||
readOnly={readOnly}
|
||||
schemaPath={`${schemaPath ? `${schemaPath}` : ''}${activeTabConfig.name ? `.${activeTabConfig.name}` : ''}`}
|
||||
>
|
||||
<RenderFields
|
||||
fieldMap={activeTabConfig.subfields}
|
||||
forceRender={forceRender}
|
||||
// indexPath={indexPath}
|
||||
key={
|
||||
activeTabConfig.label
|
||||
? getTranslation(activeTabConfig.label, i18n)
|
||||
: activeTabConfig['name']
|
||||
}
|
||||
margins="small"
|
||||
// permissions={
|
||||
// 'name' in activeTabConfig && permissions?.[activeTabConfig.name]
|
||||
// ? permissions[activeTabConfig.name].fields
|
||||
// : permissions
|
||||
// }
|
||||
// readOnly={readOnly}
|
||||
/>
|
||||
</FieldPathProvider>
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = <T,>(options: Options): FieldType<T> => {
|
||||
export const useField = <T,>(options: Options): FieldType<T> => {
|
||||
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 = <T,>(options: Options): FieldType<T> => {
|
||||
formSubmitted: submitted,
|
||||
initialValue,
|
||||
path,
|
||||
permissions,
|
||||
readOnly: readOnly || false,
|
||||
rows: field?.rows,
|
||||
schemaPath,
|
||||
@@ -107,6 +105,7 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
path,
|
||||
schemaPath,
|
||||
readOnly,
|
||||
permissions,
|
||||
],
|
||||
)
|
||||
|
||||
@@ -190,5 +189,3 @@ const useField = <T,>(options: Options): FieldType<T> => {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export default useField
|
||||
|
||||
@@ -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<T> = {
|
||||
formSubmitted: boolean
|
||||
initialValue?: T
|
||||
path: string
|
||||
permissions: FieldPermissions
|
||||
readOnly?: boolean
|
||||
rows?: Row[]
|
||||
schemaPath: string
|
||||
|
||||
@@ -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 = <P extends Record<string, unknown>>(
|
||||
@@ -9,7 +9,7 @@ export const withCondition = <P extends Record<string, unknown>>(
|
||||
): React.FC<P> => {
|
||||
const CheckForCondition: React.FC<P> = (props) => {
|
||||
const { name } = props
|
||||
const { path: pathFromContext } = useFieldPath()
|
||||
const { path: pathFromContext } = useFieldProps()
|
||||
const path = pathFromContext || name
|
||||
|
||||
return (
|
||||
|
||||
@@ -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<EditViewProps>
|
||||
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,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -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: <HiddenInput name="id" />,
|
||||
Heading: <SortColumn label="ID" name="id" />,
|
||||
fieldIsPresentational: false,
|
||||
fieldPermissions: {} as FieldPermissions,
|
||||
isFieldAffectingData: true,
|
||||
isSidebar: false,
|
||||
label: 'ID',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
"./packages/graphql/src"
|
||||
],
|
||||
"@payload-config": [
|
||||
"./test/admin/config.ts"
|
||||
"./test/access-control/config.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user