diff --git a/packages/visual-editor/src/editor/yextEntityFieldUtils.test.ts b/packages/visual-editor/src/editor/yextEntityFieldUtils.test.ts index 5699749e05..18d0e5d7be 100644 --- a/packages/visual-editor/src/editor/yextEntityFieldUtils.test.ts +++ b/packages/visual-editor/src/editor/yextEntityFieldUtils.test.ts @@ -1,4 +1,6 @@ import { describe, expect, it } from "vitest"; +import { productCardsSource } from "../components/pageSections/ProductSection/ProductCardsWrapper.tsx"; +import { type EntityFieldSelectorField } from "../fields/EntityFieldSelectorField.tsx"; import { getEntityFieldDisplayName, getFieldsForSelector, @@ -140,6 +142,79 @@ describe("getFieldsForSelector", () => { ); }); + it("treats c_productReference as a valid source for product cards requirements, despite missing CTA", () => { + const fields = getFieldsForSelector( + { + fields: [ + { + name: "c_productReference", + definition: { + name: "c_productReference", + typeRegistryId: "type.entity_reference", + isList: true, + type: { + documentType: "DOCUMENT_TYPE_ENTITY", + }, + }, + children: { + fields: [ + { + name: "brand", + definition: { + name: "brand", + typeName: "type.string", + type: {}, + }, + }, + { + name: "name", + definition: { + name: "name", + typeName: "type.string", + type: {}, + }, + }, + { + name: "price", + definition: { + name: "price", + typeName: "type.price", + type: {}, + }, + }, + { + name: "primaryPhoto", + definition: { + name: "primaryPhoto", + typeName: "type.image", + type: {}, + }, + }, + ], + }, + }, + ], + displayNames: { + c_productReference: "Product Reference", + "c_productReference.brand": "Product Reference > Brand", + "c_productReference.name": "Product Reference > Name", + "c_productReference.price": "Product Reference > Price", + "c_productReference.primaryPhoto": + "Product Reference > Primary Photo", + }, + }, + (productCardsSource.field as EntityFieldSelectorField).filter + ); + + expect(fields).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: "c_productReference", + }), + ]) + ); + }); + it("merges duplicate scoped fields when one has a display name and another has nested children", () => { const fields = getFieldsForSelector( { diff --git a/packages/visual-editor/src/utils/itemSource/createItemSource.test.ts b/packages/visual-editor/src/utils/itemSource/createItemSource.test.ts index 86ae55cc91..2e2145158f 100644 --- a/packages/visual-editor/src/utils/itemSource/createItemSource.test.ts +++ b/packages/visual-editor/src/utils/itemSource/createItemSource.test.ts @@ -75,6 +75,25 @@ describe("createItemSource", () => { }); }); + it("treats text and rich text as compatible CTA source requirements", () => { + const ctaSource = createItemSource({ + label: "Articles", + mappingFields: { + cta: { + type: "entityField", + label: "CTA", + filter: { types: ["type.cta"] }, + }, + }, + }); + + expect(ctaSource.field).toMatchObject({ + filter: { + itemSourceTypes: [["type.cta", "type.string"]], + }, + }); + }); + it("uses the first default value as the add-item template and seeds manual items", () => { const customizedSource = createItemSource({ label: "Articles", diff --git a/packages/visual-editor/src/utils/itemSource/createSlottedItemSource.test.ts b/packages/visual-editor/src/utils/itemSource/createSlottedItemSource.test.ts index b4e32f8cc9..35f63c9782 100644 --- a/packages/visual-editor/src/utils/itemSource/createSlottedItemSource.test.ts +++ b/packages/visual-editor/src/utils/itemSource/createSlottedItemSource.test.ts @@ -72,6 +72,26 @@ describe("createSlottedItemSource", () => { }); }); + it("treats text and rich text as compatible CTA source requirements", () => { + const ctaSource = createSlottedItemSource({ + label: "Featured Items", + itemLabel: "Featured Item", + mappingFields: { + cta: { + type: "entityField", + label: "CTA", + filter: { types: ["type.cta"] }, + }, + }, + }); + + expect(ctaSource.field).toMatchObject({ + filter: { + itemSourceTypes: [["type.cta", "type.string"]], + }, + }); + }); + it("resolves linked slot mappings against the current mapped item", () => { const resolved = featuredItemsSource.resolveItems( { diff --git a/packages/visual-editor/src/utils/itemSource/itemSourceFieldTransforms.ts b/packages/visual-editor/src/utils/itemSource/itemSourceFieldTransforms.ts index a5f4ba3ad9..99c80871f5 100644 --- a/packages/visual-editor/src/utils/itemSource/itemSourceFieldTransforms.ts +++ b/packages/visual-editor/src/utils/itemSource/itemSourceFieldTransforms.ts @@ -128,6 +128,11 @@ const MAPPING_CONSTANT_VALUE_TYPES: EntityFieldTypes[] = [ ]; const MAPPING_CONSTANT_VALUE_LIST_TYPES: EntityFieldTypes[] = ["type.string"]; +const ITEM_SOURCE_TYPE_COMPATIBILITY: Partial< + Record +> = { + "type.cta": ["type.string"], +}; function shouldEnableMappingConstantValue( field: EntityFieldSelectorField @@ -197,7 +202,14 @@ function getNestedItemSourceTypes( field: YextFieldDefinition ): EntityFieldTypes[][] { if (isEntityFieldDefinition(field)) { - return field.filter.types?.length ? [field.filter.types] : []; + return field.filter.types?.length + ? [ + field.filter.types.flatMap((entityFieldType) => [ + entityFieldType, + ...(ITEM_SOURCE_TYPE_COMPATIBILITY[entityFieldType] ?? []), + ]), + ] + : []; } if (field.type === "object" && "objectFields" in field) {