Context
#7090 fixed #7089 (wrong feedback button target for InfluxDB 3 Enterprise) with a minimal, behavior-preserving refactor: extract product issue URLs into data/products.yml (product_issue_url field) so layouts/partials/article/feedback.html reads from config instead of computing URLs with conditional logic.
That fix is ready to merge, but subsequent discussion on the PR surfaced a more nuanced routing policy than the original template expressed. The current product_issue_url field is too coarse for what real user needs look like, and the hardcoded Submit issue button label doesn't fit every destination.
Correct per-product routing
Per product characteristics (has-public-repo × support-contract-required), feedback button destinations should be:
| Product |
Repo? |
Contract? |
Destination |
State after #7090 |
| InfluxDB 3 Core |
✅ influxdb |
free |
GitHub influxdata/influxdb |
✅ correct |
| InfluxDB 3 Enterprise |
❌ |
optional |
Discord (preferred channel per feedback template) |
Support ❌ |
| InfluxDB 3 Explorer |
❌ |
optional |
Discord (preferred channel) |
GitHub influxdata/influxdb ❌ |
| InfluxDB 3 Cloud Serverless |
❌ |
optional |
Slack (preferred channel for non-v3-monolith) |
Support ❌ |
| InfluxDB 3 Cloud Dedicated |
❌ |
required |
Support site |
✅ correct |
| InfluxDB 3 Clustered |
❌ |
required |
Support site |
✅ correct |
| InfluxDB OSS v1/v2 |
✅ influxdb |
free |
GitHub influxdata/influxdb |
✅ correct |
| InfluxDB Cloud (TSM) |
❌ |
optional |
Slack (preferred channel) |
Support ❌ |
| Telegraf |
✅ telegraf |
optional |
GitHub influxdata/telegraf |
✅ correct |
| Chronograf |
✅ chronograf |
free |
GitHub influxdata/chronograf |
✅ correct |
| Kapacitor |
✅ kapacitor |
free |
GitHub influxdata/kapacitor |
✅ correct |
| InfluxDB Enterprise v1 |
❌ |
required |
Support site |
✅ correct |
| Flux |
✅ flux |
free |
GitHub influxdata/flux |
✅ correct |
Incorrect after #7090: v3 Enterprise, v3 Explorer, Cloud Serverless, Cloud (TSM) — 4 products.
"Preferred channel" refers to the existing conditional in layouts/partials/article/feedback.html:
{{ if and (eq $product "influxdb3") (or (eq $version "core") (eq $version "enterprise") (eq $version "explorer")) }}
Discord (Preferred)
{{ else }}
Slack (Preferred)
{{ end }}
So for v3 monolith products (Enterprise, Explorer) Discord is preferred; for v3 distributed + Cloud (TSM), Slack is preferred.
Button label mismatch
The third feedback button hardcodes Submit {{ $productName }} issue. This label fits GitHub and Support destinations, but not Discord, Slack, or Community forum — users don't "submit issues" on Discord, they ask questions. #7090 preserves this label and only changes the URL.
Product identification bug — .RelPermalink vs .File.Path
Added during PR review of #7090: the Enterprise "Submit issue" button on the PR preview was observed to link to the preview page URL itself instead of the Support site.
Root cause
The feedback template identifies the current product by parsing .RelPermalink:
{{ $productPathData := findRE "[^/]+.*?" .RelPermalink }}
{{ $product := index $productPathData 0 }}
{{ $version := index $productPathData 1 }}
Hugo's .RelPermalink returns the page URL path relative to the baseURL's host, so it includes any path prefix from baseURL. The PR preview builds with:
--baseURL https://influxdata.github.io/docs-v2/pr-preview/pr-7090/
For content/influxdb3/enterprise/get-started/_index.md, this makes .RelPermalink = /docs-v2/pr-preview/pr-7090/influxdb3/enterprise/get-started/. The findRE then assigns:
$product = "docs-v2" (wrong)
$version = "pr-preview" (wrong)
$productKey = "docs-v2" → lookup in data/products.yml returns nil
$productIssueUrl = "" → empty href="" → browser resolves to current page URL
This is pre-existing, not a regression from #7090
The pre-#7090 template used the same findRE "[^/]+.*?" .RelPermalink pattern. In the pre-refactor code, $product = "docs-v2" flowed into $productNamespace and produced https://github.com/influxdata/docs-v2/issues/new/choose/ — a wrong-but-existing URL. The refactor didn't introduce the parsing bug; it changed the failure mode from "wrong URL that happens to resolve" to "empty href that falls back to current page", making the latent bug visibly manifest.
Why the CI check didn't catch it
.github/workflows/pr-feedback-links.yml builds Hugo with the default baseURL (no subpath), so Layer 2 correctly identifies products and verifies hrefs. It never exercises the preview-baseURL code path.
Is there a reason to keep .RelPermalink?
Arguments for:
- Pages without
.File — taxonomy/term pages, paginator pages, pages generated from data files. .File is nil on those; .File.Path errors. .RelPermalink always exists.
- Permalink/url frontmatter overrides —
.RelPermalink reflects the custom URL.
- Shared content via
source: frontmatter — does .File.Path point to the consumer or the source? Answer: consumer. .File.Path = path of the .md file that declared source:. So shared content works identically with either approach.
Arguments against:
- Breaks on any non-root baseURL — observed on PR preview; would fire on any GH Pages subpath deployment, any branch-preview infrastructure, any tunnel that rewrites paths.
- Brittle regex.
findRE "[^/]+.*?" is hard to reason about. The .*? is lazy and effectively matches empty — a single anchor is doing no real work. findRE "[^/]+" would be clearer with either path source.
- Inconsistent with the rest of the template. The
pageGithubLink already uses .File.Path. Product detection should use the same signal.
- Harder to test. Layer 2 of the CI check runs Hugo with default baseURL and passes — the bug is invisible to the test unless we deliberately build with a subpath baseURL.
Verdict: no strong reason to keep .RelPermalink as primary source. The one concern (virtual pages without .File) is addressable with a guarded fallback:
{{ $path := "" }}
{{ if .File }}
{{ $path = path.Dir .File.Path | string }}
{{ else }}
{{ $path = strings.TrimPrefix site.BaseURL.Path .RelPermalink }}
{{ end }}
{{ $productPathData := findRE "[^/]+" $path }}
{{ $product := index $productPathData 0 }}
{{ $version := index $productPathData 1 }}
This:
- Fixes the preview-baseURL bug class
- Preserves behavior on virtual pages via baseURL-stripped
.RelPermalink fallback
- Uses
.File.Path consistently with the edit-link logic elsewhere in the same partial
- Replaces the brittle
[^/]+.*? regex with a clean [^/]+
If investigation confirms the feedback partial is only rendered on content pages with .File, the fallback could be dropped entirely.
CI test gap
The current pr-feedback-links.yml only runs Hugo with default baseURL. To catch this bug class, the workflow should either:
- Run Layer 2 a second time with
--baseURL https://example.com/subpath/ and verify hrefs still resolve to the expected values; or
- Add a dedicated smoke test that confirms every feedback button on a preview-style build has a non-empty
href that doesn't end with the current page path.
Proposed redesign options
Option A — Add product_issue_label field to products.yml
influxdb3_enterprise:
product_issue_url: https://discord.gg/9zaNCW2PRT
product_issue_label: Ask on Discord
influxdb3_cloud_dedicated:
product_issue_url: https://support.influxdata.com/s/
product_issue_label: Contact InfluxData Support
influxdb3_core:
product_issue_url: https://github.com/influxdata/influxdb/issues/new/choose/
product_issue_label: Submit InfluxDB 3 Core issue
Template reads {{ $productData.product_issue_label }} with a fallback to Submit {{ $productName }} issue.
Option B — Hide the third button entirely for non-repo products
The community links (Discord, Slack, Community, Reddit) are already rendered in the support section above the button row. Duplicating them as a button adds no value. Products without a repo-or-Support destination would show only Edit this page + Submit docs issue, which is cleaner.
Option C — Collapse into product_help object with type discrimination
product_help:
type: github # or: support | discord | slack | community | hidden
url: https://github.com/influxdata/influxdb/issues/new/choose/
Template branches on type for label, icon, and aria-label. Most structured but adds complexity.
Recommendation: Option A. Lowest churn, composable with existing product_issue_url, extends the data-driven pattern from #7090 without reintroducing conditional logic in the template.
Related cleanup worth bundling
- Simplify the whole feedback section. The current block contains: a Yes/No helpfulness widget, a support-resource list (Discord/Slack/Community/Reddit/Support/trial email), and three action buttons (Edit / Submit docs issue / Submit product issue). That's at least 9 distinct CTAs. Most pages probably only need 2–3.
- Switch product identification from
.RelPermalink to .File.Path with a baseURL-stripped fallback (see the root-cause section above).
- Remove the
$supportBlacklist hardcoded slice (chronograf, kapacitor) — data-drivable via a show_support_contact: false field per product.
- Data-drive the preferred-community-channel conditional — move to
products.yml as preferred_community_channel: discord | slack instead of the inline template check.
- Extend
check-feedback-links.js Layer 2 to assert rendered button labels match product_issue_label once that field lands, and to run a second pass with a subpath baseURL to catch preview-style regressions.
Acceptance criteria
Related
Context
#7090 fixed #7089 (wrong feedback button target for InfluxDB 3 Enterprise) with a minimal, behavior-preserving refactor: extract product issue URLs into
data/products.yml(product_issue_urlfield) solayouts/partials/article/feedback.htmlreads from config instead of computing URLs with conditional logic.That fix is ready to merge, but subsequent discussion on the PR surfaced a more nuanced routing policy than the original template expressed. The current
product_issue_urlfield is too coarse for what real user needs look like, and the hardcodedSubmit issuebutton label doesn't fit every destination.Correct per-product routing
Per product characteristics (has-public-repo × support-contract-required), feedback button destinations should be:
influxdbinfluxdata/influxdbinfluxdata/influxdb❌influxdbinfluxdata/influxdbtelegrafinfluxdata/telegrafchronografinfluxdata/chronografkapacitorinfluxdata/kapacitorfluxinfluxdata/fluxIncorrect after #7090: v3 Enterprise, v3 Explorer, Cloud Serverless, Cloud (TSM) — 4 products.
"Preferred channel" refers to the existing conditional in
layouts/partials/article/feedback.html:So for v3 monolith products (Enterprise, Explorer) Discord is preferred; for v3 distributed + Cloud (TSM), Slack is preferred.
Button label mismatch
The third feedback button hardcodes
Submit {{ $productName }} issue. This label fits GitHub and Support destinations, but not Discord, Slack, or Community forum — users don't "submit issues" on Discord, they ask questions. #7090 preserves this label and only changes the URL.Product identification bug —
.RelPermalinkvs.File.PathAdded during PR review of #7090: the Enterprise "Submit issue" button on the PR preview was observed to link to the preview page URL itself instead of the Support site.
Root cause
The feedback template identifies the current product by parsing
.RelPermalink:Hugo's
.RelPermalinkreturns the page URL path relative to the baseURL's host, so it includes any path prefix frombaseURL. The PR preview builds with:For
content/influxdb3/enterprise/get-started/_index.md, this makes.RelPermalink = /docs-v2/pr-preview/pr-7090/influxdb3/enterprise/get-started/. ThefindREthen assigns:$product = "docs-v2"(wrong)$version = "pr-preview"(wrong)$productKey = "docs-v2"→ lookup indata/products.ymlreturns nil$productIssueUrl = ""→ emptyhref=""→ browser resolves to current page URLThis is pre-existing, not a regression from #7090
The pre-#7090 template used the same
findRE "[^/]+.*?" .RelPermalinkpattern. In the pre-refactor code,$product = "docs-v2"flowed into$productNamespaceand producedhttps://github.com/influxdata/docs-v2/issues/new/choose/— a wrong-but-existing URL. The refactor didn't introduce the parsing bug; it changed the failure mode from "wrong URL that happens to resolve" to "empty href that falls back to current page", making the latent bug visibly manifest.Why the CI check didn't catch it
.github/workflows/pr-feedback-links.ymlbuilds Hugo with the default baseURL (no subpath), so Layer 2 correctly identifies products and verifies hrefs. It never exercises the preview-baseURL code path.Is there a reason to keep
.RelPermalink?Arguments for:
.File— taxonomy/term pages, paginator pages, pages generated from data files..Fileis nil on those;.File.Patherrors..RelPermalinkalways exists..RelPermalinkreflects the custom URL.source:frontmatter — does.File.Pathpoint to the consumer or the source? Answer: consumer..File.Path= path of the.mdfile that declaredsource:. So shared content works identically with either approach.Arguments against:
findRE "[^/]+.*?"is hard to reason about. The.*?is lazy and effectively matches empty — a single anchor is doing no real work.findRE "[^/]+"would be clearer with either path source.pageGithubLinkalready uses.File.Path. Product detection should use the same signal.Verdict: no strong reason to keep
.RelPermalinkas primary source. The one concern (virtual pages without.File) is addressable with a guarded fallback:This:
.RelPermalinkfallback.File.Pathconsistently with the edit-link logic elsewhere in the same partial[^/]+.*?regex with a clean[^/]+If investigation confirms the feedback partial is only rendered on content pages with
.File, the fallback could be dropped entirely.CI test gap
The current
pr-feedback-links.ymlonly runs Hugo with default baseURL. To catch this bug class, the workflow should either:--baseURL https://example.com/subpath/and verify hrefs still resolve to the expected values; orhrefthat doesn't end with the current page path.Proposed redesign options
Option A — Add
product_issue_labelfield toproducts.ymlTemplate reads
{{ $productData.product_issue_label }}with a fallback toSubmit {{ $productName }} issue.Option B — Hide the third button entirely for non-repo products
The community links (Discord, Slack, Community, Reddit) are already rendered in the support section above the button row. Duplicating them as a button adds no value. Products without a repo-or-Support destination would show only
Edit this page+Submit docs issue, which is cleaner.Option C — Collapse into
product_helpobject with type discriminationTemplate branches on
typefor label, icon, and aria-label. Most structured but adds complexity.Recommendation: Option A. Lowest churn, composable with existing
product_issue_url, extends the data-driven pattern from #7090 without reintroducing conditional logic in the template.Related cleanup worth bundling
.RelPermalinkto.File.Pathwith a baseURL-stripped fallback (see the root-cause section above).$supportBlacklisthardcoded slice (chronograf,kapacitor) — data-drivable via ashow_support_contact: falsefield per product.products.ymlaspreferred_community_channel: discord | slackinstead of the inline template check.check-feedback-links.jsLayer 2 to assert rendered button labels matchproduct_issue_labelonce that field lands, and to run a second pass with a subpath baseURL to catch preview-style regressions.Acceptance criteria
content_pathindata/products.ymlroutes to the correct destination per the table abovelayouts/partials/article/feedback.htmlcontains no conditional URL or label logic (fully data-driven)feedback.htmluses.File.Path(or equivalent baseURL-independent source) so preview-baseURL builds resolve correctly.ci/scripts/check-feedback-links.jsLayer 2 verifies button labels againstproduct_issue_label.RelPermalink-style regressionsRelated
findRE "[^/]+.*?"regex as worked examples of "brittle test passes locally, fails on infrastructure the dev environment doesn't exercise")