Skip to content

feat: allow static primary CTA url templates in locator result cards#1072

Open
mkouzel-yext wants to merge 29 commits intomainfrom
locator-destination-prop
Open

feat: allow static primary CTA url templates in locator result cards#1072
mkouzel-yext wants to merge 29 commits intomainfrom
locator-destination-prop

Conversation

@mkouzel-yext
Copy link
Contributor

Updates the LocatorResultCard component to support custom links on the primary CTA. Previously, these were always resolved from the source entity page set, but now the result entities may not be associated with any page set. Two propertys were added to the primaryCTA:

  • Destination: whether to derive the URL from the source page set or from the static template in the link field
  • Link: the template to use if the destination field is "custom"

The following display logic is implemented:

  • If the locator has no source page set, do not render the Destination select - it will always be "custom"
  • If the locator has a source page set, render the Destination select (either "entity page" or "custom")
  • If Destination is "entity page", do not render the Link field input because it is not used
  • If Destination is "custom", render the Link field input

J=WAT-5361

mkouzel-yext and others added 20 commits February 25, 2026 18:08
When resolving the URL for the primary CTA in Locator result cards, the URL template is now read from whichever source entity page set in __.locatorSourcePageSets includes the result entity in the Locator config rather than the __.pathInfo.sourceEntityPageSetTemplate field or the legacy __.entityPageSetUrlTemplates field.
The __.locatorSourcePageSets field on the stream document contains the entity type API name, internal saved search ID, and a pathInfo object for each source entity page set of the locator. The pathInfo object contains the necessary data to resolve the CTA url for a search result: URL template, primary locale, and whether to include a locale prefix for the primary locale. Makes use of the existing resolveUrlFromPathInfo to handle actual URL resolution.

Also updates Puck options for facet fields to include all options that apply to either entity type.

J=WAT-5361
TEST=manual

Confirmed that CTA urls used the template of the correct page set and that expected facet options were shown without duplicates.
Doesn't assume a locatorSourcePageSet exists
Updates the LocatorResultCard component to support custom links on the primary CTA. Previously, these were always resolved from the source entity page set, but now the result entities may not be associated with any page set. Two propertys were added to the primaryCTA:
* Destination: whether to derive the URL from the source page set or from the static template in the link field
* Link: the template to use if the destination field is "custom"

The following display logic is implemented:
* If the locator has no source page set, do not render the Destination select - it will always be "custom"
* If the locator has a source page set, render the Destination select (either "entity page" or "custom")
* If Destination is "entity page", do not render the Link field input because it is not used
* If Destination is "custom", render the Link field input

J=WAT-5361
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

Warning: Component files have been updated but no migrations have been added. See https://github.com/yext/visual-editor/blob/main/packages/visual-editor/src/components/migrations/README.md for more information.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 826657a and 8aade35.

📒 Files selected for processing (2)
  • packages/visual-editor/locales/platform/zh/visual-editor.json
  • packages/visual-editor/src/components/migrations/migrationRegistry.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/visual-editor/src/components/migrations/migrationRegistry.ts

Walkthrough

Adds a selectable destination for the Locator result card's primary CTA ("entityPage" | "custom") and a translatable custom link field. Introduces an internal PrimaryCTA component that resolves the CTA URL from primaryCTA.link when destination === "custom" or via locator routing (resolveLocatorResultUrl) for "entityPage". Fixes a typo in a visibility helper and hides the custom link field unless the destination is "custom". Adds a migration to default existing Locator primary CTA destinations to "entityPage", updates default layout data, and adds locale keys and docs for the new option.

Sequence Diagram(s)

sequenceDiagram
    participant Editor as Visual Editor
    participant ResultCard as LocatorResultCard
    participant PrimaryCTA as PrimaryCTA
    participant LocatorConfig as useLocatorConfig
    participant Document as Pageset Document

    Editor->>ResultCard: provide resultCard.primaryCTA props
    ResultCard->>PrimaryCTA: render with primaryCTA props
    PrimaryCTA->>PrimaryCTA: inspect destination

    alt destination == "custom"
        PrimaryCTA->>PrimaryCTA: use primaryCTA.link as URL
    else destination == "entityPage"
        PrimaryCTA->>LocatorConfig: request locator routing info
        LocatorConfig->>Document: read pageset locator config
        Document-->>LocatorConfig: return config
        LocatorConfig-->>PrimaryCTA: provide routing info
        PrimaryCTA->>PrimaryCTA: resolve URL via resolveLocatorResultUrl
    end

    PrimaryCTA-->>ResultCard: return resolved URL
    ResultCard-->>Editor: render CTA
Loading

Possibly related PRs

Suggested labels

create-dev-release

Suggested reviewers

  • mkilpatrick
  • benlife5
  • asanehisa
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: allow static primary CTA url templates in locator result cards' clearly and specifically describes the main change: enabling custom URL templates for primary CTAs in locator result cards, moving away from always deriving URLs from the entity page set.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation, implementation details (two new properties: Destination and Link), and the display logic for the feature, which aligns with the changes across multiple files including LocatorResultCard, Locator, and migration files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch locator-destination-prop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/visual-editor/src/components/LocatorResultCard.tsx`:
- Around line 314-323: Rename the function getLocatorConfig to useLocatorConfig
(it calls the React hook useDocument), update its definition accordingly, and
update all call sites that reference getLocatorConfig (e.g., the place where it
is invoked to obtain locatorConfig) to call useLocatorConfig instead; ensure the
renamed function remains a top-level function (not used inside non-hook
callbacks) so it obeys the Rules of Hooks and returns the same value
(pageSet?.typeConfig?.locatorConfig ?? {}) after parsing streamDocument._pageset
with the same try/catch behavior.

In
`@packages/visual-editor/src/components/migrations/0065_add_locator_primary_cta_destination.ts`:
- Around line 5-25: Import the new migration symbol
addLocatorPrimaryCtaDestination into the migrations registry module and append
it to the migrationRegistry array so it will run; specifically, in
migrationRegistry.ts add an import for addLocatorPrimaryCtaDestination from its
module and include addLocatorPrimaryCtaDestination in the exported
migrationRegistry array alongside the other migrations.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd377a and 51a8ab9.

📒 Files selected for processing (5)
  • packages/visual-editor/src/components/Locator.tsx
  • packages/visual-editor/src/components/LocatorResultCard.tsx
  • packages/visual-editor/src/components/migrations/0065_add_locator_primary_cta_destination.ts
  • packages/visual-editor/src/docs/components.md
  • packages/visual-editor/src/vite-plugin/defaultLayoutData.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/visual-editor/locales/platform/cs/visual-editor.json`:
- Line 288: The "custom" translation value in the locales file is
incorrect—replace the value for the "custom" key in
packages/visual-editor/locales/platform/cs/visual-editor.json (the entry
currently reading "Zvyk") with "Vlastní" so it matches existing UI terminology
and the intended meaning for CTA destination behavior.

In `@packages/visual-editor/locales/platform/da/visual-editor.json`:
- Line 288: The translation for the JSON key "custom" currently uses the Danish
word "Skik" (value "Skik"); replace it with a UI-appropriate Danish term such as
"Tilpasset" or "Brugerdefineret" so it matches the surrounding settings labels
and conveys "user-defined/customized" rather than "tradition". Update the value
for the "custom" key accordingly in the visual-editor.json locale entry.

In `@packages/visual-editor/locales/platform/de/visual-editor.json`:
- Line 288: The translation for the JSON key "custom" is the UI-inappropriate
noun "Brauch"; update the value for the "custom" key in visual-editor.json to a
proper UI label such as "Benutzerdefiniert" (or "Eigenes"/"Eigene") so it
clearly conveys "custom/user-defined" in the destination selector.

In `@packages/visual-editor/locales/platform/es/visual-editor.json`:
- Line 288: Replace the incorrect Spanish translation for the "custom" key
(currently "Costumbre") with the UI-config option wording; update the value for
the "custom" entry to "Personalizado" (or "Personalizada" per product glossary)
so the option reads as a configurable/customized choice rather than a cultural
“habit” meaning.

In `@packages/visual-editor/locales/platform/hr/visual-editor.json`:
- Line 288: Update the Croatian translation for the JSON key "custom" in the
visual-editor locale so the UI conveys "customized" style instead of the noun
"tradition"; replace the current value "Običaj" with a configurable-style term
such as "Prilagođeno" for the "custom" entry.

In `@packages/visual-editor/locales/platform/hu/visual-editor.json`:
- Line 288: The translation for the JSON key "custom" is incorrect—replace the
value "Szokás" with a software-appropriate Hungarian term such as "Egyéni" or
"Egyedi" for the "custom" key in the visual-editor locale (look for the "custom"
property in packages/visual-editor/locales/platform/hu/visual-editor.json and
update its value to "Egyéni" or "Egyedi").

In `@packages/visual-editor/locales/platform/nb/visual-editor.json`:
- Line 288: The JSON translation key "custom" currently has the value "Skikk"
which is misleading; change the value for the "custom" key in the Norwegian
locale (visual-editor.json) to "Tilpasset" so the UI shows the more accurate
label. Locate the "custom" entry and replace "Skikk" with "Tilpasset",
preserving JSON formatting and quotes.

In `@packages/visual-editor/locales/platform/pl/visual-editor.json`:
- Line 288: The locale key "custom" in visual-editor.json currently maps to the
noun "Zwyczaj" which is not appropriate for a UI selection; update the
translation for the "custom" key to a UI-appropriate label such as
"Niestandardowe" (or your product-approved equivalent) so the selectable option
reads correctly in Polish; locate the "custom" entry in
packages/visual-editor/locales/platform/pl/visual-editor.json and replace the
value "Zwyczaj" with the approved label.

In `@packages/visual-editor/locales/platform/tr/visual-editor.json`:
- Line 288: The translation for the "custom" UI key is incorrect ("Gelenek");
update the value for the JSON key "custom" in visual-editor.json to the accurate
UI term "Özel" (or the approved Turkish glossary term) so the selector displays
the correct meaning in the product UI; locate the entry with the key "custom"
and replace its string value accordingly.

In `@packages/visual-editor/locales/platform/zh-TW/visual-editor.json`:
- Line 288: The "custom" label in the localization JSON is mistranslated: the
key "custom" currently maps to "風俗" (which means customs/traditions) — replace
it with the correct Traditional Chinese term for user-defined/custom, e.g.,
change the value for the "custom" key to "自訂" (or "自定義") in the
visual-editor.json so the destination selector reads as expected.

In `@packages/visual-editor/locales/platform/zh/visual-editor.json`:
- Line 288: The translation for the JSON key "custom" is incorrect — replace the
value "风俗" with the context-appropriate string "自定义" so the CTA destination
option reads as “custom/configurable” (update the value for the "custom" key in
the visual-editor.json entry).

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51a8ab9 and a8e093e.

📒 Files selected for processing (26)
  • packages/visual-editor/locales/platform/cs/visual-editor.json
  • packages/visual-editor/locales/platform/da/visual-editor.json
  • packages/visual-editor/locales/platform/de/visual-editor.json
  • packages/visual-editor/locales/platform/en-GB/visual-editor.json
  • packages/visual-editor/locales/platform/en/visual-editor.json
  • packages/visual-editor/locales/platform/es/visual-editor.json
  • packages/visual-editor/locales/platform/et/visual-editor.json
  • packages/visual-editor/locales/platform/fi/visual-editor.json
  • packages/visual-editor/locales/platform/fr/visual-editor.json
  • packages/visual-editor/locales/platform/hr/visual-editor.json
  • packages/visual-editor/locales/platform/hu/visual-editor.json
  • packages/visual-editor/locales/platform/it/visual-editor.json
  • packages/visual-editor/locales/platform/ja/visual-editor.json
  • packages/visual-editor/locales/platform/lt/visual-editor.json
  • packages/visual-editor/locales/platform/lv/visual-editor.json
  • packages/visual-editor/locales/platform/nb/visual-editor.json
  • packages/visual-editor/locales/platform/nl/visual-editor.json
  • packages/visual-editor/locales/platform/pl/visual-editor.json
  • packages/visual-editor/locales/platform/pt/visual-editor.json
  • packages/visual-editor/locales/platform/ro/visual-editor.json
  • packages/visual-editor/locales/platform/sk/visual-editor.json
  • packages/visual-editor/locales/platform/sv/visual-editor.json
  • packages/visual-editor/locales/platform/tr/visual-editor.json
  • packages/visual-editor/locales/platform/zh-TW/visual-editor.json
  • packages/visual-editor/locales/platform/zh/visual-editor.json
  • packages/visual-editor/src/components/Locator.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/visual-editor/locales/platform/fr/visual-editor.json

Base automatically changed from update-locator-cta to main March 3, 2026 20:27
Also renames function
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/visual-editor/src/components/migrations/migrationRegistry.ts (1)

66-66: Import missing .ts extension for consistency.

All other imports in this file include the .ts extension. This import should follow the same pattern for consistency.

🧹 Proposed fix
-import { addLocatorPrimaryCtaDestination } from "./0065_add_locator_primary_cta_destination";
+import { addLocatorPrimaryCtaDestination } from "./0065_add_locator_primary_cta_destination.ts";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/migrations/migrationRegistry.ts` at
line 66, The import of addLocatorPrimaryCtaDestination is missing the .ts
extension; update the import statement for addLocatorPrimaryCtaDestination (the
symbol named addLocatorPrimaryCtaDestination) to include the ".ts" suffix so it
matches the other imports in migrationRegistry and maintains consistent module
resolution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/visual-editor/src/components/LocatorResultCard.tsx`:
- Around line 702-709: The Link field (TranslatableStringField) is always
visible; change it to only render when the sibling destination equals "custom"
by wrapping it in the same conditional field pattern used by
PrimaryCtaDestinationField/PrimaryCtaDestinationField()—i.e. create a small
wrapper/custom field inside LocatorResultCard (or the same field definitions
block) that reads the sibling value for destination (using the same
locatorConfig access pattern) and returns the TranslatableStringField only when
destination === "custom", otherwise returns null or an empty field.

---

Nitpick comments:
In `@packages/visual-editor/src/components/migrations/migrationRegistry.ts`:
- Line 66: The import of addLocatorPrimaryCtaDestination is missing the .ts
extension; update the import statement for addLocatorPrimaryCtaDestination (the
symbol named addLocatorPrimaryCtaDestination) to include the ".ts" suffix so it
matches the other imports in migrationRegistry and maintains consistent module
resolution.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8e093e and 762a148.

📒 Files selected for processing (2)
  • packages/visual-editor/src/components/LocatorResultCard.tsx
  • packages/visual-editor/src/components/migrations/migrationRegistry.ts

Comment on lines +702 to +709
destination: PrimaryCtaDestinationField(),
link: TranslatableStringField<TranslatableString | undefined>(
msg("fields.link", "Link"),
undefined,
false,
true,
() => getDisplayFieldOptions("type.string")
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Link field visibility not conditional on destination.

Per PR objectives, the Link field should only render when Destination is "custom". Currently, the link field is always visible regardless of the destination value. While this doesn't cause functional issues (the link is only used when destination === "custom"), it may confuse users.

Consider wrapping TranslatableStringField in a custom field that checks the sibling destination value, similar to how PrimaryCtaDestinationField conditionally renders based on locatorConfig.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/visual-editor/src/components/LocatorResultCard.tsx` around lines 702
- 709, The Link field (TranslatableStringField) is always visible; change it to
only render when the sibling destination equals "custom" by wrapping it in the
same conditional field pattern used by
PrimaryCtaDestinationField/PrimaryCtaDestinationField()—i.e. create a small
wrapper/custom field inside LocatorResultCard (or the same field definitions
block) that reads the sibling value for destination (using the same
locatorConfig access pattern) and returns the TranslatableStringField only when
destination === "custom", otherwise returns null or an empty field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant