fix: simplifies field error paths (#5504)
This commit is contained in:
@@ -22,6 +22,7 @@ type ArrayRowProps = UseDraggableSortableReturn & {
|
||||
CustomRowLabel?: React.ReactNode
|
||||
addRow: (rowIndex: number) => void
|
||||
duplicateRow: (rowIndex: number) => void
|
||||
errorCount: number
|
||||
fieldMap: FieldMap
|
||||
forceRender?: boolean
|
||||
hasMaxRows?: boolean
|
||||
@@ -35,6 +36,7 @@ type ArrayRowProps = UseDraggableSortableReturn & {
|
||||
row: Row
|
||||
rowCount: number
|
||||
rowIndex: number
|
||||
schemaPath: string
|
||||
setCollapse: (rowID: string, collapsed: boolean) => void
|
||||
}
|
||||
|
||||
@@ -43,6 +45,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
addRow,
|
||||
attributes,
|
||||
duplicateRow,
|
||||
errorCount,
|
||||
fieldMap,
|
||||
forceRender = false,
|
||||
hasMaxRows,
|
||||
@@ -57,6 +60,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
row,
|
||||
rowCount,
|
||||
rowIndex,
|
||||
schemaPath,
|
||||
setCollapse,
|
||||
setNodeRef,
|
||||
transform,
|
||||
@@ -70,7 +74,6 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
'0',
|
||||
)}`
|
||||
|
||||
const errorCount = row.errorPaths?.length
|
||||
const fieldHasErrors = errorCount > 0 && hasSubmitted
|
||||
|
||||
const classNames = [
|
||||
@@ -134,7 +137,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
path={path}
|
||||
permissions={permissions?.fields}
|
||||
readOnly={readOnly}
|
||||
schemaPath={parentPath}
|
||||
schemaPath={schemaPath}
|
||||
/>
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
||||
@@ -112,6 +112,7 @@ export const _ArrayField: React.FC<ArrayFieldProps> = (props) => {
|
||||
const { path: pathFromContext } = useFieldProps()
|
||||
|
||||
const {
|
||||
errorPaths,
|
||||
path,
|
||||
rows = [],
|
||||
schemaPath,
|
||||
@@ -180,10 +181,8 @@ export const _ArrayField: React.FC<ArrayFieldProps> = (props) => {
|
||||
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows
|
||||
|
||||
const fieldErrorCount =
|
||||
rows.reduce((total, row) => total + (row?.errorPaths?.length || 0), 0) + (valid ? 0 : 1)
|
||||
|
||||
const fieldHasErrors = submitted && fieldErrorCount > 0
|
||||
const fieldErrorCount = errorPaths.length
|
||||
const fieldHasErrors = submitted && errorPaths.length > 0
|
||||
|
||||
const showRequired = readOnly && rows.length === 0
|
||||
const showMinRows = rows.length < minRows || (required && rows.length === 0)
|
||||
@@ -209,7 +208,7 @@ export const _ArrayField: React.FC<ArrayFieldProps> = (props) => {
|
||||
<div className={`${baseClass}__header-wrap`}>
|
||||
<div className={`${baseClass}__header-content`}>
|
||||
<h3 className={`${baseClass}__title`}>
|
||||
<FieldLabel CustomLabel={CustomLabel} {...(labelProps || {})} />
|
||||
<FieldLabel CustomLabel={CustomLabel} as="span" unstyled {...(labelProps || {})} />
|
||||
</h3>
|
||||
{fieldHasErrors && fieldErrorCount > 0 && (
|
||||
<ErrorPill count={fieldErrorCount} i18n={i18n} withMessage />
|
||||
@@ -247,32 +246,39 @@ export const _ArrayField: React.FC<ArrayFieldProps> = (props) => {
|
||||
ids={rows.map((row) => row.id)}
|
||||
onDragEnd={({ moveFromIndex, moveToIndex }) => moveRow(moveFromIndex, moveToIndex)}
|
||||
>
|
||||
{rows.map((row, i) => (
|
||||
<DraggableSortableItem disabled={readOnly} id={row.id} key={row.id}>
|
||||
{(draggableSortableItemProps) => (
|
||||
<ArrayRow
|
||||
{...draggableSortableItemProps}
|
||||
CustomRowLabel={CustomRowLabel}
|
||||
addRow={addRow}
|
||||
duplicateRow={duplicateRow}
|
||||
fieldMap={fieldMap}
|
||||
forceRender={forceRender}
|
||||
hasMaxRows={hasMaxRows}
|
||||
indexPath={indexPath}
|
||||
labels={labels}
|
||||
moveRow={moveRow}
|
||||
path={path}
|
||||
permissions={permissions}
|
||||
readOnly={readOnly}
|
||||
removeRow={removeRow}
|
||||
row={row}
|
||||
rowCount={rows.length}
|
||||
rowIndex={i}
|
||||
setCollapse={setCollapse}
|
||||
/>
|
||||
)}
|
||||
</DraggableSortableItem>
|
||||
))}
|
||||
{rows.map((row, i) => {
|
||||
const rowErrorCount = errorPaths?.filter((errorPath) =>
|
||||
errorPath.startsWith(`${path}.${i}.`),
|
||||
).length
|
||||
return (
|
||||
<DraggableSortableItem disabled={readOnly} id={row.id} key={row.id}>
|
||||
{(draggableSortableItemProps) => (
|
||||
<ArrayRow
|
||||
{...draggableSortableItemProps}
|
||||
CustomRowLabel={CustomRowLabel}
|
||||
addRow={addRow}
|
||||
duplicateRow={duplicateRow}
|
||||
errorCount={rowErrorCount}
|
||||
fieldMap={fieldMap}
|
||||
forceRender={forceRender}
|
||||
hasMaxRows={hasMaxRows}
|
||||
indexPath={indexPath}
|
||||
labels={labels}
|
||||
moveRow={moveRow}
|
||||
path={path}
|
||||
permissions={permissions}
|
||||
readOnly={readOnly}
|
||||
removeRow={removeRow}
|
||||
row={row}
|
||||
rowCount={rows.length}
|
||||
rowIndex={i}
|
||||
schemaPath={schemaPath}
|
||||
setCollapse={setCollapse}
|
||||
/>
|
||||
)}
|
||||
</DraggableSortableItem>
|
||||
)
|
||||
})}
|
||||
{!valid && (
|
||||
<React.Fragment>
|
||||
{showRequired && (
|
||||
|
||||
@@ -24,6 +24,7 @@ type BlockFieldProps = UseDraggableSortableReturn & {
|
||||
block: ReducedBlock
|
||||
blocks: ReducedBlock[]
|
||||
duplicateRow: (rowIndex: number) => void
|
||||
errorCount: number
|
||||
forceRender?: boolean
|
||||
hasMaxRows?: boolean
|
||||
indexPath: string
|
||||
@@ -46,6 +47,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
block,
|
||||
blocks,
|
||||
duplicateRow,
|
||||
errorCount,
|
||||
forceRender,
|
||||
hasMaxRows,
|
||||
labels,
|
||||
@@ -67,8 +69,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
const { i18n } = useTranslation()
|
||||
const hasSubmitted = useFormSubmitted()
|
||||
|
||||
const errorCount = row.errorPaths?.length
|
||||
const fieldHasErrors = errorCount > 0 && hasSubmitted
|
||||
const fieldHasErrors = hasSubmitted && errorCount > 0
|
||||
|
||||
const classNames = [
|
||||
`${baseClass}__row`,
|
||||
|
||||
@@ -113,6 +113,7 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
|
||||
const { path: pathFromContext } = useFieldProps()
|
||||
|
||||
const {
|
||||
errorPaths,
|
||||
path,
|
||||
permissions,
|
||||
rows = [],
|
||||
@@ -192,7 +193,7 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
|
||||
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows
|
||||
|
||||
const fieldErrorCount = rows.reduce((total, row) => total + (row?.errorPaths?.length || 0), 0)
|
||||
const fieldErrorCount = errorPaths.length
|
||||
const fieldHasErrors = submitted && fieldErrorCount + (valid ? 0 : 1) > 0
|
||||
|
||||
const showMinRows = rows.length < minRows || (required && rows.length === 0)
|
||||
@@ -219,7 +220,7 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
|
||||
<div className={`${baseClass}__header-wrap`}>
|
||||
<div className={`${baseClass}__heading-with-error`}>
|
||||
<h3>
|
||||
<FieldLabel CustomLabel={CustomLabel} {...(labelProps || {})} />
|
||||
<FieldLabel CustomLabel={CustomLabel} as="span" unstyled {...(labelProps || {})} />
|
||||
</h3>
|
||||
{fieldHasErrors && fieldErrorCount > 0 && (
|
||||
<ErrorPill count={fieldErrorCount} i18n={i18n} withMessage />
|
||||
@@ -262,6 +263,9 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
|
||||
const blockToRender = blocks.find((block) => block.slug === blockType)
|
||||
|
||||
if (blockToRender) {
|
||||
const rowErrorCount = errorPaths.filter((errorPath) =>
|
||||
errorPath.startsWith(`${path}.${i}`),
|
||||
).length
|
||||
return (
|
||||
<DraggableSortableItem disabled={readOnly} id={row.id} key={row.id}>
|
||||
{(draggableSortableItemProps) => (
|
||||
@@ -271,6 +275,7 @@ const _BlocksField: React.FC<BlocksFieldProps> = (props) => {
|
||||
block={blockToRender}
|
||||
blocks={blocks}
|
||||
duplicateRow={duplicateRow}
|
||||
errorCount={rowErrorCount}
|
||||
forceRender={forceRender}
|
||||
hasMaxRows={hasMaxRows}
|
||||
indexPath={indexPath}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { DocumentPreferences, FieldBase, RowLabel as RowLabelType } from 'payload/types'
|
||||
import type { DocumentPreferences, FieldBase } from 'payload/types'
|
||||
|
||||
import React, { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@ import type { FormFieldBase } from '../shared/index.js'
|
||||
import { useCollapsible } from '../../elements/Collapsible/provider.js'
|
||||
import { ErrorPill } from '../../elements/ErrorPill/index.js'
|
||||
import { useFieldProps } from '../../forms/FieldPropsProvider/index.js'
|
||||
import { useFormSubmitted } from '../../forms/Form/context.js'
|
||||
import { RenderFields } from '../../forms/RenderFields/index.js'
|
||||
import { WatchChildErrors } from '../../forms/WatchChildErrors/index.js'
|
||||
import { useField } from '../../forms/useField/index.js'
|
||||
import { withCondition } from '../../forms/withCondition/index.js'
|
||||
import { useTranslation } from '../../providers/Translation/index.js'
|
||||
import { useRow } from '../Row/provider.js'
|
||||
@@ -53,14 +54,15 @@ const GroupField: React.FC<GroupFieldProps> = (props) => {
|
||||
const isWithinGroup = useGroup()
|
||||
const isWithinRow = useRow()
|
||||
const isWithinTab = useTabs()
|
||||
const [errorCount, setErrorCount] = React.useState(undefined)
|
||||
const fieldHasErrors = errorCount > 0
|
||||
const { errorPaths } = useField({ path })
|
||||
const submitted = useFormSubmitted()
|
||||
const errorCount = errorPaths.length
|
||||
const fieldHasErrors = submitted && errorCount > 0
|
||||
|
||||
const isTopLevel = !(isWithinCollapsible || isWithinGroup || isWithinRow)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<WatchChildErrors fieldMap={fieldMap} path={path} setErrorCount={setErrorCount} />
|
||||
<div
|
||||
className={[
|
||||
fieldBaseClass,
|
||||
|
||||
Reference in New Issue
Block a user