Site: add configurable right-gutter CTA templates#3602
Conversation
Docsets can now define named CTA templates under docset.yml's `cta` map (label, url, benefits) and select one per-page via frontmatter `cta: <name>`, instead of the previously hardcoded trial card. Clicks and impressions are tracked via OpenTelemetry. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Documents the docset.yml `cta` map and the page-level `cta` frontmatter field on a new content-set page, linked from navigation.md and frontmatter.md. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Defines a 'docs-builder' CTA template in docs/_docset.yml and selects it on the CTA docs page itself, so the feature has a working example to preview and test against. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughChangesThis PR adds configurable right-gutter CTAs. CTA templates are defined in Related PRs: #3167 Suggested labels: feature, documentation Suggested reviewers: None identified Poem 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches✨ Simplify code
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs`:
- Around line 305-320: The CTA validation in ConfigurationFile should reject
unsafe values for definition.Button.Url before storing them in _ctas, not just
check for non-empty text. Add URI validation in the CTA parsing block for Cta
definitions so only the intended schemes/forms are accepted and anything like
javascript: or data: triggers context.EmitError; keep the check рядом with the
existing label/url presence validation and the Cta construction.
In `@src/Elastic.Markdown/Layout/_TableOfContents.cshtml`:
- Around line 75-80: The sidebar trial CTA condition in _TableOfContents should
also respect white-label mode, not just BuildType and Cta.Name. Update the
rendering guard around the sidebar-trial-card anchor so the default trial card
is skipped when Model.Branding is present, matching the rest of the sidebar’s
Elastic-chrome suppression. Use the existing Model.BuildType, Model.Cta, and
Model.Branding checks in this Razor block to keep the CTA hidden for branded
builds unless a custom CTA is explicitly provided.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: ab011318-5c00-407f-8754-25254108acc8
📒 Files selected for processing (16)
docs/_docset.ymldocs/configure/content-set/cta.mddocs/configure/content-set/index.mddocs/configure/content-set/navigation.mddocs/syntax/frontmatter.mdsrc/Elastic.Codex/Page/Index.cshtmlsrc/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cssrc/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cssrc/Elastic.Documentation.Site/Assets/main.tssrc/Elastic.Documentation.Site/Assets/telemetry/semconv.tssrc/Elastic.Markdown/HtmlWriter.cssrc/Elastic.Markdown/Layout/_TableOfContents.cshtmlsrc/Elastic.Markdown/MarkdownLayoutViewModel.cssrc/Elastic.Markdown/Myst/FrontMatter/FrontMatterParser.cssrc/Elastic.Markdown/Page/Index.cshtmlsrc/Elastic.Markdown/Page/IndexViewModel.cs
The button used text-nowrap with a fixed width and a single-line leading, so longer custom labels overflowed into the horizontal padding instead of wrapping — verified with devtools that a label like "Star docs-builder on GitHub" left ~7px of visible padding instead of the intended 24px. Dropping text-nowrap/leading-[30px] in favor of normal wrapping fixes this without affecting the short default label, which stays single-line as before. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Swaps the illustrative docset.yml/frontmatter example from an Elastic Cloud trial CTA to a generic beta-signup CTA, so the example reads as a general-purpose feature rather than something Elastic-specific. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
`cta: <name>` becomes `cta: { id: <name> }`, via a new CtaFrontMatter
type. This leaves room to add other per-page CTA options (e.g. a
future `hidden: true`) without another frontmatter format change.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Move CTA name-lookup/unknown-id-warning logic from HtmlWriter into ConfigurationFile.ResolveCta, alongside the Ctas dictionary it resolves against, so any future caller gets the same fallback behavior for free instead of reimplementing it. - Extract the CTA validation loop body into ValidateCta, matching the existing ValidateBranding convention in the same file. - Reuse a single IntersectionObserver across htmx swaps instead of disconnecting and recreating it on every navigation; re-observing an already-observed element is a documented no-op. - Reorder the sidebar CTA render condition so "show it" and "except in Codex" read as separate clauses (same truth table). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs (1)
378-397: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winCTA
button.urlstill isn't scheme-validated.
ValidateCtaonly checks thatUrlis non-empty before storing it verbatim intoCta.Url, which flows straight into<a href="@Model.Cta.Url">in_TableOfContents.cshtml. Ajavascript:/data:URL indocset.ymlwould become an executable link. This was already flagged on a previous revision of this PR and remains unaddressed.🔒 Proposed fix
private static Cta? ValidateCta(string name, CtaDefinition definition, IDocumentationSetContext context) { if (string.IsNullOrWhiteSpace(definition.Button?.Label) || string.IsNullOrWhiteSpace(definition.Button?.Url)) { context.EmitError(context.ConfigurationPath, $"'cta.{name}' must define both 'button.label' and 'button.url'."); return null; } + var url = definition.Button.Url.Trim(); + if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri && + uri.Scheme is not Uri.UriSchemeHttp and not Uri.UriSchemeHttps) + { + context.EmitError(context.ConfigurationPath, $"'cta.{name}.button.url' must use http/https or an allowed relative URL."); + return null; + } if (definition.Benefits.Count > Cta.MaxBenefits) { context.EmitError(context.ConfigurationPath, $"'cta.{name}.benefits' has {definition.Benefits.Count} entries; a maximum of {Cta.MaxBenefits} is allowed."); return null; } return new Cta { Name = name, Label = definition.Button.Label, - Url = definition.Button.Url, + Url = url, Benefits = definition.Benefits }; }🤖 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 `@src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs` around lines 378 - 397, Validate the CTA URL scheme in ValidateCta before assigning Cta.Url, not just for non-empty input. Update the CtaDefinition/Button validation path in ConfigurationFile.cs to reject unsafe schemes like javascript: and data:, and emit a configuration error through context.EmitError when the URL is not an allowed http/https (or relative) link. Keep the existing name, label, benefits, and return-new-Cta flow unchanged, but ensure the value stored in Cta.Url is sanitized/validated before _TableOfContents.cshtml can render it.
🤖 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.
Duplicate comments:
In `@src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs`:
- Around line 378-397: Validate the CTA URL scheme in ValidateCta before
assigning Cta.Url, not just for non-empty input. Update the CtaDefinition/Button
validation path in ConfigurationFile.cs to reject unsafe schemes like
javascript: and data:, and emit a configuration error through context.EmitError
when the URL is not an allowed http/https (or relative) link. Keep the existing
name, label, benefits, and return-new-Cta flow unchanged, but ensure the value
stored in Cta.Url is sanitized/validated before _TableOfContents.cshtml can
render it.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: ab36896f-799b-4d35-8bac-47c90ad4b3b5
📒 Files selected for processing (8)
docs/_docset.ymldocs/configure/content-set/cta.mddocs/syntax/frontmatter.mdsrc/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cssrc/Elastic.Documentation.Site/Assets/main.tssrc/Elastic.Markdown/HtmlWriter.cssrc/Elastic.Markdown/Layout/_TableOfContents.cshtmlsrc/Elastic.Markdown/Myst/FrontMatter/FrontMatterParser.cs
✅ Files skipped from review due to trivial changes (2)
- docs/syntax/frontmatter.md
- docs/configure/content-set/cta.md
🚧 Files skipped from review as they are similar to previous changes (2)
- src/Elastic.Markdown/Layout/_TableOfContents.cshtml
- src/Elastic.Documentation.Site/Assets/main.ts
…erabbitai) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Why
The right-gutter CTA card (the "Get started free" trial widget) was hardcoded sitewide, with no way for a docset or page to show a different offer, and no click/impression tracking to measure its effectiveness.
What
Docsets can now define named CTA templates (button label/url, up to 3 benefit bullets) under a
ctamap indocset.yml, and individual pages select one via thectafrontmatter field. Pages that don't opt in keep the existing built-intrialcard. An unknownctaname falls back to the default and emits a build warning with a "did you mean" hint. CTA clicks and impressions are now tracked via OpenTelemetry (cta_clicked/cta_viewed) so click-through rate can be compared across templates and placements.Codex builds are explicitly excluded from rendering the CTA card, matching their existing exclusion from other assembler-only sidebar chrome.
Docs for the new
docset.ymlkey and frontmatter field are added underdocs/configure/content-set/cta.md, linked fromnavigation.mdandfrontmatter.md.Test plan
dotnet buildonElastic.MarkdownandElastic.Codexsucceedsdocs-builder build --path docssucceeds with 0 errors/warnings on the new docs page and linkscta:template renders the correct label/url/benefits in the sidebar, and that an unknown name falls back totrialwith a warningcta:frontmatter value setCo-Authored-By: Claude Sonnet 4.6 (1M context) noreply@anthropic.com