fix: join field description, custom components and loading state (#9703)
- [fix: join field shows loading when creating a document](9f7a2e7936) - [fix: join field descriptions](90e8cdb464) - [feat(ui): adds before & after inputs to join field](19d43329ad) --------- Co-authored-by: Patrik <patrik@payloadcms.com>
This commit is contained in:
@@ -1372,6 +1372,8 @@ export type JoinField = {
|
||||
admin?: {
|
||||
allowCreate?: boolean
|
||||
components?: {
|
||||
afterInput?: CustomComponent[]
|
||||
beforeInput?: CustomComponent[]
|
||||
Error?: CustomComponent<JoinFieldErrorClientComponent | JoinFieldErrorServerComponent>
|
||||
Label?: CustomComponent<JoinFieldLabelClientComponent | JoinFieldLabelServerComponent>
|
||||
} & Admin['components']
|
||||
|
||||
@@ -35,7 +35,9 @@ import { RelationshipTablePagination } from './Pagination.js'
|
||||
const baseClass = 'relationship-table'
|
||||
|
||||
type RelationshipTableComponentProps = {
|
||||
readonly AfterInput?: React.ReactNode
|
||||
readonly allowCreate?: boolean
|
||||
readonly BeforeInput?: React.ReactNode
|
||||
readonly disableTable?: boolean
|
||||
readonly field: JoinFieldClient
|
||||
readonly filterOptions?: Where
|
||||
@@ -47,7 +49,9 @@ type RelationshipTableComponentProps = {
|
||||
|
||||
export const RelationshipTable: React.FC<RelationshipTableComponentProps> = (props) => {
|
||||
const {
|
||||
AfterInput,
|
||||
allowCreate = true,
|
||||
BeforeInput,
|
||||
disableTable = false,
|
||||
filterOptions,
|
||||
initialData: initialDataFromProps,
|
||||
@@ -91,7 +95,7 @@ export const RelationshipTable: React.FC<RelationshipTableComponentProps> = (pro
|
||||
() => getEntityConfig({ collectionSlug: relationTo }) as ClientCollectionConfig,
|
||||
)
|
||||
|
||||
const [isLoadingTable, setIsLoadingTable] = useState(true)
|
||||
const [isLoadingTable, setIsLoadingTable] = useState(!disableTable)
|
||||
const [data, setData] = useState<PaginatedDocs>(initialData)
|
||||
const [columnState, setColumnState] = useState<Column[]>()
|
||||
|
||||
@@ -197,6 +201,7 @@ export const RelationshipTable: React.FC<RelationshipTableComponentProps> = (pro
|
||||
</Pill>
|
||||
</div>
|
||||
</div>
|
||||
{BeforeInput}
|
||||
{isLoadingTable ? (
|
||||
<p>{t('general:loading')}</p>
|
||||
) : (
|
||||
@@ -257,6 +262,7 @@ export const RelationshipTable: React.FC<RelationshipTableComponentProps> = (pro
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
{AfterInput}
|
||||
<DocumentDrawer initialData={initialDrawerData} onSave={onDrawerCreate} />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,9 +5,11 @@ import type { JoinFieldClient, JoinFieldClientComponent, PaginatedDocs, Where }
|
||||
import React, { useMemo } from 'react'
|
||||
|
||||
import { RelationshipTable } from '../../elements/RelationshipTable/index.js'
|
||||
import { RenderCustomComponent } from '../../elements/RenderCustomComponent/index.js'
|
||||
import { useField } from '../../forms/useField/index.js'
|
||||
import { withCondition } from '../../forms/withCondition/index.js'
|
||||
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
|
||||
import { FieldDescription } from '../FieldDescription/index.js'
|
||||
import { FieldLabel } from '../FieldLabel/index.js'
|
||||
import { fieldBaseClass } from '../index.js'
|
||||
|
||||
@@ -15,7 +17,7 @@ const JoinFieldComponent: JoinFieldClientComponent = (props) => {
|
||||
const {
|
||||
field,
|
||||
field: {
|
||||
admin: { allowCreate },
|
||||
admin: { allowCreate, description },
|
||||
collection,
|
||||
label,
|
||||
localized,
|
||||
@@ -27,7 +29,7 @@ const JoinFieldComponent: JoinFieldClientComponent = (props) => {
|
||||
|
||||
const { id: docID } = useDocumentInfo()
|
||||
|
||||
const { customComponents: { AfterInput, BeforeInput, Label } = {}, value } =
|
||||
const { customComponents: { AfterInput, BeforeInput, Description, Label } = {}, value } =
|
||||
useField<PaginatedDocs>({
|
||||
path,
|
||||
})
|
||||
@@ -57,9 +59,10 @@ const JoinFieldComponent: JoinFieldClientComponent = (props) => {
|
||||
className={[fieldBaseClass, 'join'].filter(Boolean).join(' ')}
|
||||
id={`field-${path?.replace(/\./g, '__')}`}
|
||||
>
|
||||
{BeforeInput}
|
||||
<RelationshipTable
|
||||
AfterInput={AfterInput}
|
||||
allowCreate={typeof docID !== 'undefined' && allowCreate}
|
||||
BeforeInput={BeforeInput}
|
||||
disableTable={filterOptions === null}
|
||||
field={field as JoinFieldClient}
|
||||
filterOptions={filterOptions}
|
||||
@@ -76,7 +79,10 @@ const JoinFieldComponent: JoinFieldClientComponent = (props) => {
|
||||
}
|
||||
relationTo={collection}
|
||||
/>
|
||||
{AfterInput}
|
||||
<RenderCustomComponent
|
||||
CustomComponent={Description}
|
||||
Fallback={<FieldDescription description={description} path={path} />}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -47,6 +47,13 @@ export const Categories: CollectionConfig = {
|
||||
name: 'relatedPosts',
|
||||
label: 'Related Posts',
|
||||
type: 'join',
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: ['/components/AfterInput.js#AfterInput'],
|
||||
beforeInput: ['/components/BeforeInput.js#BeforeInput'],
|
||||
Description: '/components/CustomDescription/index.js#FieldDescriptionComponent',
|
||||
},
|
||||
},
|
||||
collection: postsSlug,
|
||||
defaultSort: '-title',
|
||||
defaultLimit: 5,
|
||||
@@ -57,6 +64,9 @@ export const Categories: CollectionConfig = {
|
||||
name: 'hasManyPosts',
|
||||
type: 'join',
|
||||
collection: postsSlug,
|
||||
admin: {
|
||||
description: 'Static Description',
|
||||
},
|
||||
on: 'categories',
|
||||
},
|
||||
{
|
||||
|
||||
7
test/joins/components/AfterInput.tsx
Normal file
7
test/joins/components/AfterInput.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export const AfterInput: React.FC = () => {
|
||||
return <div className="after-input">#after-input</div>
|
||||
}
|
||||
7
test/joins/components/BeforeInput.tsx
Normal file
7
test/joins/components/BeforeInput.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export const BeforeInput: React.FC = () => {
|
||||
return <div className="before-input">#before-input</div>
|
||||
}
|
||||
8
test/joins/components/CustomDescription/index.tsx
Normal file
8
test/joins/components/CustomDescription/index.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
'use client'
|
||||
import type { FieldDescriptionClientComponent } from 'payload'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export const FieldDescriptionComponent: FieldDescriptionClientComponent = ({ path }) => {
|
||||
return <div className={`field-description-${path}`}>Component description: {path}</div>
|
||||
}
|
||||
@@ -22,6 +22,11 @@ const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
admin: {
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname),
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
Posts,
|
||||
Categories,
|
||||
|
||||
@@ -88,6 +88,22 @@ test.describe('Admin Panel', () => {
|
||||
await page.goto(categoriesURL.create)
|
||||
const nameField = page.locator('#field-name')
|
||||
await expect(nameField).toBeVisible()
|
||||
|
||||
// assert that the join field is visible and is not stuck in a loading state
|
||||
await expect(page.locator('#field-relatedPosts')).toContainText('No Posts found.')
|
||||
await expect(page.locator('#field-relatedPosts')).not.toContainText('loading')
|
||||
|
||||
// assert that the create new button is not visible
|
||||
await expect(page.locator('#field-relatedPosts > .relationship-table__add-new')).toBeHidden()
|
||||
|
||||
// assert that the admin.description is visible
|
||||
await expect(page.locator('.field-description-hasManyPosts')).toHaveText('Static Description')
|
||||
|
||||
//assert that the admin.components.Description is visible
|
||||
await expect(page.locator('.field-description-relatedPosts')).toHaveText(
|
||||
'Component description: relatedPosts',
|
||||
)
|
||||
|
||||
await nameField.fill('test category')
|
||||
await saveDocAndAssert(page)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user