Skip to content

[DRAFT] Support analytics for custom code section#1262

Draft
jhelenek wants to merge 1 commit into
mainfrom
analytics-branch
Draft

[DRAFT] Support analytics for custom code section#1262
jhelenek wants to merge 1 commit into
mainfrom
analytics-branch

Conversation

@jhelenek

@jhelenek jhelenek commented Jul 9, 2026

Copy link
Copy Markdown

This PR supports analytics for custom code section. It adds the Analytics track method to the window so that inner-components are able to reference it. Each analytics is registered by componentId so multiple custom code components can coexist without overwriting each other's handlers.

@jhelenek jhelenek added the create-dev-release Triggers dev release workflow label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

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.

@pkg-pr-new

pkg-pr-new Bot commented Jul 9, 2026

Copy link
Copy Markdown

commit: cbe76b4

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change modifies CustomCodeSection.tsx to route injected user JavaScript through a new analytics bridge and script runner. A shared window.YextCustomCodeAnalytics object maintains per-componentId track handlers in a scopes map, exposing register/unregister/track operations with a default C_CUSTOM action and warnings for untracked scopes. A new CustomCodeAnalyticsBridgeAndScriptRunner component registers this bridge, replaces the previous script-tag injection effect, wraps the user script with a yextAnalytics.track helper forwarding to the shared bridge, and cleans up the script and registration on unmount. The runner is wired into CustomCodeSectionWrapper with componentId, containerRef, processedJavascript, and scriptTagId.

Sequence Diagram(s)

sequenceDiagram
  participant CustomCodeSectionWrapper
  participant CustomCodeAnalyticsBridgeAndScriptRunner
  participant WindowBridge as window.YextCustomCodeAnalytics
  participant ScriptTag as Injected Script

  CustomCodeSectionWrapper->>CustomCodeAnalyticsBridgeAndScriptRunner: render(componentId, processedJavascript, scriptTagId)
  CustomCodeAnalyticsBridgeAndScriptRunner->>WindowBridge: register(componentId, track handler)
  CustomCodeAnalyticsBridgeAndScriptRunner->>ScriptTag: remove existing script by scriptTagId
  CustomCodeAnalyticsBridgeAndScriptRunner->>ScriptTag: append new script with yextAnalytics.track wrapper
  ScriptTag->>WindowBridge: track(componentId, data)
  WindowBridge->>WindowBridge: lookup scope handler
  CustomCodeAnalyticsBridgeAndScriptRunner->>WindowBridge: unregister(componentId) on cleanup
  CustomCodeAnalyticsBridgeAndScriptRunner->>ScriptTag: remove script on cleanup
Loading

Possibly related PRs

  • yext/visual-editor#1141: Both PRs modify the same CustomCodeSection.tsx script-injection logic, including how the script tag is created/updated via scriptTagId.

Suggested reviewers: mkilpatrick, briantstephan, benlife5, asanehisa

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding analytics support to the custom code section.
Description check ✅ Passed The description matches the changeset by explaining window analytics tracking and componentId-based registration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch analytics-branch

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/visual-editor/src/components/customCode/CustomCodeSection.tsx`:
- Around line 205-216: The injected user script in CustomCodeSection’s script
creation is wrapped in a block, which prevents global handler resolution for
inline callbacks like onclick="changeColor(this)". Update the script injection
around processedJavascript so user code runs at top level instead of inside a
block, and provide yextAnalytics through another mechanism in the same
CustomCodeSection flow without relying on block-scoped declarations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f613126d-9a2d-4221-aba2-0222a8921d7f

📥 Commits

Reviewing files that changed from the base of the PR and between 99d3414 and cbe76b4.

📒 Files selected for processing (1)
  • packages/visual-editor/src/components/customCode/CustomCodeSection.tsx

Comment on lines +205 to +216
// Wrap user code in a block so each component gets a local yextAnalytics helper without leaking a global.
script.text = `
{
const yextAnalytics = {
track: (eventName, data) =>
window.YextCustomCodeAnalytics.track(${JSON.stringify(componentId)}, eventName, data),
};

${processedJavascript}
}
`;
containerRef.current.appendChild(script);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the test to confirm reliance on global-scope handler resolution
fd -t f 'CustomCodeSection.test.tsx' packages/visual-editor/src/components/customCode --exec sed -n '1,80p' {}

Repository: yext/visual-editor

Length of output: 2587


🏁 Script executed:

python3 - <<'PY'
import subprocess, textwrap, json, os, sys, tempfile

# Use node's vm to run code as a script in a fresh global-like context.
js = r"""
const vm = require('vm');

function run(src) {
  const sandbox = { console };
  vm.createContext(sandbox);
  try {
    vm.runInContext(src, sandbox);
  } catch (e) {
    return { error: String(e), sandbox };
  }
  return { sandbox };
}

for (const [name, src] of [
  ['direct function', `function changeColor() {}`],
  ['block function', `{ function changeColor() {} }`],
  ['block const func expr', `{ const changeColor = () => {} }`],
  ['block let class', `{ let changeColor = 1; class Foo {} }`],
]) {
  const res = run(src);
  const sandbox = res.sandbox || {};
  console.log('---', name);
  console.log('error:', res.error || null);
  console.log('has changeColor in sandbox:', Object.prototype.hasOwnProperty.call(sandbox, 'changeColor'));
  console.log('typeof sandbox.changeColor:', typeof sandbox.changeColor);
  console.log('has Foo in sandbox:', Object.prototype.hasOwnProperty.call(sandbox, 'Foo'));
  console.log('typeof sandbox.Foo:', typeof sandbox.Foo);
}
"""
subprocess.run(["node", "-e", js], check=False)
PY

Repository: yext/visual-editor

Length of output: 797


Wrapping user JS in a block breaks global handler resolution.
let/const/class declarations inside the injected script stay block-scoped, so inline handlers like onclick="changeColor(this)" will fail unless the handler is a function declaration. That still works only because of sloppy-mode Annex B semantics, so the current test can miss the regression. Keep the user script at top level and inject yextAnalytics another way.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/visual-editor/src/components/customCode/CustomCodeSection.tsx`
around lines 205 - 216, The injected user script in CustomCodeSection’s script
creation is wrapped in a block, which prevents global handler resolution for
inline callbacks like onclick="changeColor(this)". Update the script injection
around processedJavascript so user code runs at top level instead of inside a
block, and provide yextAnalytics through another mechanism in the same
CustomCodeSection flow without relying on block-scoped declarations.

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

Labels

create-dev-release Triggers dev release workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant