Skip to content

feat: locator static content toggles#1040

Open
k-gerner wants to merge 19 commits intomainfrom
locator-static-content
Open

feat: locator static content toggles#1040
k-gerner wants to merge 19 commits intomainfrom
locator-static-content

Conversation

@k-gerner
Copy link
Contributor

Added toggles to Primary/Secondary/Tertiary heading fields, and Image field, which control whether to use static values for those fields, or to pull them from the entity.

Additionally, fixes a small bug in the Locator where updating the map style would not propagate immediately.

J=WAT-5364

vle_static_content_toggles.mov

@k-gerner k-gerner requested review from a team February 11, 2026 00:24
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 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

Walkthrough

This PR adds constant/static value support for Locator result cards by introducing constantValue and constantValueEnabled for primary, secondary, tertiary headings and image; updates defaults, editor fields, and tests; adds LocatorComponent.resolveFields(data) to compute visible fields; refactors Locator internal map state to use centerCoords; adds optional altTextEntity for image alt-text resolution; registers migration 0062 to backfill defaults; and updates resolveComponentData to handle TranslatableAssetImage.

Sequence Diagram(s)

sequenceDiagram
    participant Editor as Visual Editor UI
    participant Locator as LocatorComponent
    participant ResultCard as LocatorResultCard
    participant Image as Image Component
    participant Migration as Migration Registry

    Editor->>Locator: update resultCard props (toggle constantValue / set values)
    Locator->>Locator: resolveFields(data) -> compute visible fields
    Locator->>ResultCard: render with resolved fields & props
    ResultCard->>ResultCard: for each heading -> resolveText(constantValueEnabled ? constantValue : fieldValue)
    alt image uses constant value
        ResultCard->>Image: pass constant image value + altTextEntity
        Image->>Image: getImageAltText(image, locale, altTextEntity)
    else image uses field/selector
        ResultCard->>Image: pass image field id / selector
        Image->>Image: getImageAltText(image, locale, streamDocument)
    end
    Migration->>Locator: migrationRegistry includes 0062 to ensure defaults on load
Loading

Possibly related PRs

Suggested labels

create-dev-release

Suggested reviewers

  • mkouzel-yext
  • benlife5
  • jwartofsky-yext
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: locator static content toggles' directly and clearly describes the main feature added in this pull request: static content toggles for locator fields.
Description check ✅ Passed The description is well-related to the changeset, explaining the primary feature (toggles for heading and image fields) and mentioning a bug fix for map style propagation.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch locator-static-content

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: 3

🤖 Fix all issues with AI agents
In `@packages/visual-editor/src/components/Locator.tsx`:
- Around line 600-653: The resolveFields function is currently calling
setDeep(...) but not using its return value, so updates are lost; change each
call inside resolveFields to assign the returned object back into updatedFields
(e.g., updatedFields = setDeep(updatedFields,
"resultCard.objectFields.primaryHeading.objectFields.field.visible",
!staticEnabled)) for all setDeep invocations (primaryHeading, secondaryHeading,
tertiaryHeading, image and their constantValue equivalents) so the immutable
updates are preserved before returning updatedFields.

In `@packages/visual-editor/src/components/LocatorResultCard.tsx`:
- Around line 1185-1211: resolveText currently treats an empty string from
resolveComponentData as "no value" and falls back to parseStringFromLocation,
which breaks the intent of config.constantValueEnabled; change the logic in
resolveText so that when config.constantValueEnabled is true you return the
resolvedConstantValue as-is (including an empty string) instead of falling
through to entity data—use config.constantValueEnabled and config.constantValue
with resolveComponentData to decide to return resolvedConstantValue (even if
empty), otherwise call parseStringFromLocation; keep the final fallback behavior
(fallback param) if resolvedConstantValue is undefined.
- Around line 269-278: The image default in LocatorResultCard (the "image"
constantValue) uses a plain AssetImageType instead of the localized shape;
update the constantValue to match the localized form used by headings and tests
by wrapping the asset in an "en" key and adding hasLocalizedValue: "true" (i.e.,
set constantValue to { en: { url: "", height: 0, width: 0 }, hasLocalizedValue:
"true" }) so code expecting LocalizedAssetImage/TranslatableAssetImage will
receive a consistent shape.
🧹 Nitpick comments (3)
packages/visual-editor/src/components/Locator.test.tsx (1)

1037-1039: Weak assertion — getByText already throws if the element is missing.

page.getByText("Custom Heading") will throw if the element doesn't exist, making .toBeTruthy() a no-op. Consider using toBeVisible() or wrapping in waitFor for a more meaningful check, especially since this runs as an interaction callback and the text comes from a static constant value that may be rendered asynchronously.

packages/visual-editor/src/components/Locator.tsx (1)

925-937: handleDrag is not memoized, causing mapProps to recompute every render.

handleDrag (line 744) is a plain function declaration that gets a new identity on every render. Since it's listed in the useMemo dependency array, mapProps will be recomputed on every render, negating the memoization benefit.

This predates this PR's changes, but the refactoring introduces mapProps as a new useMemo — worth wrapping handleDrag in useCallback to get the intended benefit.

Wrap handleDrag in useCallback
- const handleDrag: OnDragHandler = (center: LngLat, bounds: LngLatBounds) => {
-   setMapCenter(center);
-   setMapBounds(bounds);
-   setShowSearchAreaButton(true);
- };
+ const handleDrag: OnDragHandler = React.useCallback(
+   (center: LngLat, bounds: LngLatBounds) => {
+     setMapCenter(center);
+     setMapBounds(bounds);
+     setShowSearchAreaButton(true);
+   },
+   []
+ );
packages/visual-editor/src/components/LocatorResultCard.tsx (1)

309-329: Repetitive toggle + constant-value field pattern across four sections.

The constantValueEnabled / constantValue field pair is duplicated nearly identically for primary, secondary, tertiary headings and image. Consider extracting a helper (e.g., createConstantValueToggleFields(label, fieldTypeFilter, getOptions)) to reduce boilerplate.

Also applies to: 353-373, 402-422, 661-675

Comment on lines 269 to 278
image: {
field: { selection: { value: "headshot" } },
constantValue: {
url: "",
height: 0,
width: 0,
},
constantValueEnabled: false,
liveVisibility: false,
},
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

🧩 Analysis chain

🏁 Script executed:

# First, find the relevant files
fd "LocatorResultCard.tsx" -x wc -l {}

Repository: yext/visual-editor

Length of output: 128


🏁 Script executed:

# Also check for the test file
fd "Locator.test.tsx" -x wc -l {}

Repository: yext/visual-editor

Length of output: 123


🏁 Script executed:

# Check directory structure to understand the project layout
git ls-files packages/visual-editor/src/components/ | head -20

Repository: yext/visual-editor

Length of output: 1203


🏁 Script executed:

# Read the LocatorResultCard.tsx file focusing on the relevant sections
sed -n '210,230p' packages/visual-editor/src/components/LocatorResultCard.tsx

Repository: yext/visual-editor

Length of output: 739


🏁 Script executed:

# Read the image default section
sed -n '265,280p' packages/visual-editor/src/components/LocatorResultCard.tsx

Repository: yext/visual-editor

Length of output: 339


🏁 Script executed:

# Read the test file to check test data
sed -n '165,175p' packages/visual-editor/src/components/Locator.test.tsx

Repository: yext/visual-editor

Length of output: 339


🏁 Script executed:

# Find the type definitions for TranslatableAssetImage and AssetImageType
rg "TranslatableAssetImage|AssetImageType" --type ts --type tsx -A 3 packages/visual-editor/

Repository: yext/visual-editor

Length of output: 89


🏁 Script executed:

# Also check for LocalizedAssetImage type definition
rg "LocalizedAssetImage" --type ts --type tsx -A 3 packages/visual-editor/

Repository: yext/visual-editor

Length of output: 89


🏁 Script executed:

# Find the type definitions for TranslatableAssetImage and related types
rg "TranslatableAssetImage|AssetImageType" -A 3 packages/visual-editor/

Repository: yext/visual-editor

Length of output: 34246


🏁 Script executed:

# Also check for LocalizedAssetImage type definition
rg "LocalizedAssetImage" -A 3 packages/visual-editor/

Repository: yext/visual-editor

Length of output: 1121


🏁 Script executed:

# Check the TranslatableString type definition to understand the pattern
rg "TranslatableString" -B 2 -A 3 packages/visual-editor/src/types/

Repository: yext/visual-editor

Length of output: 6878


🏁 Script executed:

# Let's also check how these types are used in resolveComponentData
sed -n '1,80p' packages/visual-editor/src/utils/resolveComponentData.tsx

Repository: yext/visual-editor

Length of output: 2717


Image default constantValue uses non-localized shape, inconsistent with heading defaults.

Heading defaults (lines 213, 219, 226) use { en: "", hasLocalizedValue: "true" } (localized), while the image default uses { url: "", height: 0, width: 0 } (plain AssetImageType). Both are valid per TranslatableAssetImage = AssetImageType | LocalizedAssetImage, but this inconsistency may cause issues if code elsewhere assumes the localized shape. The test data (Locator.test.tsx ~168) uses the localized form { en: { url: "", height: 0, width: 0 }, hasLocalizedValue: "true" }, which differs from this default.

🤖 Prompt for AI Agents
In `@packages/visual-editor/src/components/LocatorResultCard.tsx` around lines 269
- 278, The image default in LocatorResultCard (the "image" constantValue) uses a
plain AssetImageType instead of the localized shape; update the constantValue to
match the localized form used by headings and tests by wrapping the asset in an
"en" key and adding hasLocalizedValue: "true" (i.e., set constantValue to { en:
{ url: "", height: 0, width: 0 }, hasLocalizedValue: "true" }) so code expecting
LocalizedAssetImage/TranslatableAssetImage will receive a consistent shape.

github-actions bot and others added 6 commits February 11, 2026 00:34
…ic (#1038)

Adds styling for primary header links and secondary header links. (per
discussion with aaron and item)
Adds collapse links section to the Primary Header but removes it from
Secondary Header. (per
[slack](https://yext.slack.com/archives/C0A1G447MPD/p1770407836981439?thread_ts=1770394463.419749&cid=C0A1G447MPD))
In tablet viewport, the hamburger menu resolves differently then desktop
and mobile. (according to
[mocks](https://www.figma.com/proto/sX3bkzkEpQ3g2mJrfSSdmd/Quickstart-Template--2025-?page-id=14531%3A79278&node-id=20461-3516&viewport=-1754%2C-4161%2C0.61&t=jINYTsjrohkhlpmj-1&scaling=min-zoom&content-scaling=fixed&starting-point-node-id=20461%3A3516)
from Ming)

Editor in platform:
https://www.yext.com/s/4412098/yextsites/162218/pagesets

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Follow up to #985

Also removes some unused packages and code

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
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

🤖 Fix all issues with AI agents
In `@packages/visual-editor/src/components/Locator.test.tsx`:
- Around line 702-704: The test currently asserts expect(page.getByText("Custom
Heading")).toBeTruthy(), which always passes because page.getByText(...) returns
a Locator object; change the assertion to use a DOM-level expectation so it
actually checks presence/visibility — for example, in the interactions async
function replace the truthy check on page.getByText("Custom Heading") with a
proper DOM assertion such as using expect.element(page.getByText("Custom
Heading")).toExist() or await expect(page.getByText("Custom
Heading")).toBeVisible(), ensuring the test verifies the element is rendered.

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

🤖 Fix all issues with AI agents
In `@packages/visual-editor/src/components/Locator.test.tsx`:
- Around line 218-222: Tests for older (pre-migration-62) variants
inconsistently include primaryHeading.constantValue and
primaryHeading.constantValueEnabled; remove those two properties from the
primaryHeading fixture in all pre-62 test variants (e.g., the "version 24 with
filters" and all "version 60" variants) so the migration-62 code is the single
source of truth that injects them, ensuring all pre-62 tests omit constantValue
and constantValueEnabled consistently rather than adding them ad hoc.
🧹 Nitpick comments (1)
packages/visual-editor/src/components/Locator.tsx (1)

925-937: handleDrag is recreated every render, making useMemo effectively a no-op.

handleDrag (Line 744) is not wrapped in useCallback, so it produces a new reference on every render. Since it's listed as a dependency of this useMemo, mapProps will be recomputed on every render regardless.

This doesn't cause a correctness bug (the Map component isn't memoized anyway), but if you later add React.memo to Map, the stale optimization here would be surprising.

Optional: wrap handleDrag in useCallback
-  const handleDrag: OnDragHandler = (center: LngLat, bounds: LngLatBounds) => {
+  const handleDrag: OnDragHandler = React.useCallback((center: LngLat, bounds: LngLatBounds) => {
     setMapCenter(center);
     setMapBounds(bounds);
     setShowSearchAreaButton(true);
-  };
+  }, []);

Fondryext
Fondryext previously approved these changes Feb 12, 2026
Copy link
Contributor

@Fondryext Fondryext left a comment

Choose a reason for hiding this comment

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

changes make sense, I know there's some open questions on the coderabbit stuff

Copy link

@vijay267 vijay267 left a comment

Choose a reason for hiding this comment

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

Overall looks fine to me outside of my one comment about refactoring and existing comments

updatedFields,
"resultCard.objectFields.primaryHeading.objectFields.constantValue.visible",
staticEnabled
);

Choose a reason for hiding this comment

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

Can we refactor this into a helper or something to avoid the repetition? It feels like we're doing the same thing 4 times, once for each 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.

5 participants