fix(ui): monomorphic relationship fields should not show relationTo option labels (#13245)

This commit is contained in:
Jarrod Flesch
2025-07-23 16:31:05 -04:00
committed by GitHub
parent 0eac58ed72
commit 29fb9ee5b4
4 changed files with 31 additions and 19 deletions

View File

@@ -49,6 +49,7 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
Description, Description,
Error, Error,
filterOptions, filterOptions,
formatDisplayedOptions,
hasMany, hasMany,
initialValue, initialValue,
isSortable = true, isSortable = true,
@@ -100,9 +101,6 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
const [options, dispatchOptions] = useReducer(optionsReducer, []) const [options, dispatchOptions] = useReducer(optionsReducer, [])
const valueRef = useRef(value) const valueRef = useRef(value)
// the line below seems odd
valueRef.current = value
const [DocumentDrawer, , { isDrawerOpen, openDrawer }] = useDocumentDrawer({ const [DocumentDrawer, , { isDrawerOpen, openDrawer }] = useDocumentDrawer({
id: currentlyOpenRelationship.id, id: currentlyOpenRelationship.id,
@@ -474,11 +472,7 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
const docID = args.doc.id const docID = args.doc.id
if (hasMany) { if (hasMany) {
const currentValue = valueRef.current const currentValue = value ? (Array.isArray(value) ? value : [value]) : []
? Array.isArray(valueRef.current)
? valueRef.current
: [valueRef.current]
: []
const valuesToSet = currentValue.map((option: ValueWithRelation) => { const valuesToSet = currentValue.map((option: ValueWithRelation) => {
return { return {
@@ -492,7 +486,7 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
onChange({ relationTo: args.collectionConfig.slug, value: docID }) onChange({ relationTo: args.collectionConfig.slug, value: docID })
} }
}, },
[i18n, config, hasMany, onChange], [i18n, config, hasMany, onChange, value],
) )
const onDuplicate = useCallback<DocumentDrawerProps['onDuplicate']>( const onDuplicate = useCallback<DocumentDrawerProps['onDuplicate']>(
@@ -508,8 +502,8 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
if (hasMany) { if (hasMany) {
onChange( onChange(
valueRef.current value
? (valueRef.current as ValueWithRelation[]).concat({ ? value.concat({
relationTo: args.collectionConfig.slug, relationTo: args.collectionConfig.slug,
value: args.doc.id, value: args.doc.id,
}) })
@@ -522,7 +516,7 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
}) })
} }
}, },
[i18n, config, hasMany, onChange], [i18n, config, hasMany, onChange, value],
) )
const onDelete = useCallback<DocumentDrawerProps['onDelete']>( const onDelete = useCallback<DocumentDrawerProps['onDelete']>(
@@ -537,8 +531,8 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
if (hasMany) { if (hasMany) {
onChange( onChange(
valueRef.current value
? (valueRef.current as ValueWithRelation[]).filter((option) => { ? value.filter((option) => {
return option.value !== args.id return option.value !== args.id
}) })
: null, : null,
@@ -549,7 +543,7 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
return return
}, },
[i18n, config, hasMany, onChange], [i18n, config, hasMany, onChange, value],
) )
const filterOption = useCallback((item: Option, searchFilter: string) => { const filterOption = useCallback((item: Option, searchFilter: string) => {
@@ -671,6 +665,12 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
} }
}, [openDrawer, currentlyOpenRelationship]) }, [openDrawer, currentlyOpenRelationship])
useEffect(() => {
// needed to sync the ref value when other fields influence the value
// i.e. when a drawer is opened and the value is set
valueRef.current = value
}, [value])
const valueToRender = findOptionsByValue({ allowEdit, options, value }) const valueToRender = findOptionsByValue({ allowEdit, options, value })
if (!Array.isArray(valueToRender) && valueToRender?.value === 'null') { if (!Array.isArray(valueToRender) && valueToRender?.value === 'null') {
@@ -742,14 +742,18 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
? (selected) => { ? (selected) => {
if (hasMany) { if (hasMany) {
if (selected === null) { if (selected === null) {
valueRef.current = []
onChange([]) onChange([])
} else { } else {
valueRef.current = selected as ValueWithRelation[]
onChange(selected as ValueWithRelation[]) onChange(selected as ValueWithRelation[])
} }
} else if (hasMany === false) { } else if (hasMany === false) {
if (selected === null) { if (selected === null) {
valueRef.current = null
onChange(null) onChange(null)
} else { } else {
valueRef.current = selected as ValueWithRelation
onChange(selected as ValueWithRelation) onChange(selected as ValueWithRelation)
} }
} }
@@ -822,7 +826,11 @@ export const RelationshipInput: React.FC<RelationshipInputProps> = (props) => {
}), }),
}) })
}} }}
options={options} options={
typeof formatDisplayedOptions === 'function'
? formatDisplayedOptions(options)
: options
}
placeholder={placeholder} placeholder={placeholder}
showError={showError} showError={showError}
value={valueToRender ?? null} value={valueToRender ?? null}

View File

@@ -196,6 +196,9 @@ const RelationshipFieldComponent: RelationshipFieldClientComponent = (props) =>
description={description} description={description}
Error={Error} Error={Error}
filterOptions={filterOptions} filterOptions={filterOptions}
formatDisplayedOptions={
isPolymorphic ? undefined : (options) => options.map((opt) => opt.options).flat()
}
isSortable={isSortable} isSortable={isSortable}
Label={Label} Label={Label}
label={label} label={label}

View File

@@ -100,6 +100,7 @@ export type RelationshipInputProps = {
readonly description?: StaticDescription readonly description?: StaticDescription
readonly Error?: React.ReactNode readonly Error?: React.ReactNode
readonly filterOptions?: FilterOptionsResult readonly filterOptions?: FilterOptionsResult
readonly formatDisplayedOptions?: (options: OptionGroup[]) => Option[] | OptionGroup[]
readonly isSortable?: boolean readonly isSortable?: boolean
readonly Label?: React.ReactNode readonly Label?: React.ReactNode
readonly label?: StaticLabel readonly label?: StaticLabel

View File

@@ -240,7 +240,7 @@ describe('lexicalBlocks', () => {
) )
await dependsOnDocData.locator('.rs__control').click() await dependsOnDocData.locator('.rs__control').click()
await expect(newBlock.locator('.rs__menu')).toHaveText('Text Fieldsinvalid') await expect(newBlock.locator('.rs__menu')).toHaveText('invalid')
await dependsOnDocData.locator('.rs__control').click() await dependsOnDocData.locator('.rs__control').click()
await dependsOnSiblingData.locator('.rs__control').click() await dependsOnSiblingData.locator('.rs__control').click()
@@ -281,7 +281,7 @@ describe('lexicalBlocks', () => {
await dependsOnDocData.locator('.rs__control').click() await dependsOnDocData.locator('.rs__control').click()
await dependsOnSiblingData.locator('.rs__control').click() await dependsOnSiblingData.locator('.rs__control').click()
await expect(newBlock.locator('.rs__menu')).toHaveText('Text Fieldsinvalid') await expect(newBlock.locator('.rs__menu')).toHaveText('invalid')
await dependsOnSiblingData.locator('.rs__control').click() await dependsOnSiblingData.locator('.rs__control').click()
await dependsOnBlockData.locator('.rs__control').click() await dependsOnBlockData.locator('.rs__control').click()
@@ -322,7 +322,7 @@ describe('lexicalBlocks', () => {
await dependsOnSiblingData.locator('.rs__control').click() await dependsOnSiblingData.locator('.rs__control').click()
await dependsOnBlockData.locator('.rs__control').click() await dependsOnBlockData.locator('.rs__control').click()
await expect(newBlock.locator('.rs__menu')).toHaveText('Text Fieldsinvalid') await expect(newBlock.locator('.rs__menu')).toHaveText('invalid')
await dependsOnBlockData.locator('.rs__control').click() await dependsOnBlockData.locator('.rs__control').click()
await saveDocAndAssert(page) await saveDocAndAssert(page)