diff --git a/assets/js/content-interactions.js b/assets/js/content-interactions.js
index eb9b4e1bc..3de1386ea 100644
--- a/assets/js/content-interactions.js
+++ b/assets/js/content-interactions.js
@@ -122,7 +122,7 @@ function expandAccordions() {
// Expand accordions on load based on URL anchor
function openAccordionByHash() {
- var anchor = window.location.hash;
+ var anchor = window.location.hash.split('?')[0];
function expandElement() {
if ($(anchor).parents('.expand').length > 0) {
diff --git a/assets/js/main.js b/assets/js/main.js
index 826ad9a11..abe0792c3 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -19,6 +19,7 @@ import * as pageContext from './page-context.js';
import * as pageFeedback from './page-feedback.js';
import * as tabbedContent from './tabbed-content.js';
import * as v3Wayfinding from './v3-wayfinding.js';
+import * as tcDownloads from './tc-downloads.js';
/** Import component modules
* The component pattern organizes JavaScript, CSS, and HTML for a specific UI element or interaction:
@@ -162,6 +163,7 @@ function initModules() {
pageFeedback.initialize();
tabbedContent.initialize();
v3Wayfinding.initialize();
+ tcDownloads.initialize();
}
/**
diff --git a/assets/js/tc-downloads.js b/assets/js/tc-downloads.js
new file mode 100644
index 000000000..cc17837d4
--- /dev/null
+++ b/assets/js/tc-downloads.js
@@ -0,0 +1,221 @@
+////////////////////////////////////////////////////////////////////////////////
+///////////////// Telegraf Controller gated downloads module ////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+import { toggleModal } from './modals.js';
+
+const STORAGE_KEY = 'influxdata_docs_tc_dl';
+const QUERY_PARAM = 'ref';
+const QUERY_VALUE = 'tc';
+
+// ─── localStorage helpers ───────────────────────────────────────────────────
+
+function setDownloadKey() {
+ localStorage.setItem(STORAGE_KEY, 'true');
+}
+
+function hasDownloadKey() {
+ return localStorage.getItem(STORAGE_KEY) === 'true';
+}
+
+// ─── Query param helpers ────────────────────────────────────────────────────
+
+function hasRefParam() {
+ // Check query string first (?ref=tc before the hash)
+ const params = new URLSearchParams(window.location.search);
+ if (params.get(QUERY_PARAM) === QUERY_VALUE) return true;
+
+ // Also check inside the fragment (#heading?ref=tc)
+ const hash = window.location.hash;
+ const qIndex = hash.indexOf('?');
+ if (qIndex !== -1) {
+ const hashParams = new URLSearchParams(hash.substring(qIndex));
+ if (hashParams.get(QUERY_PARAM) === QUERY_VALUE) return true;
+ }
+ return false;
+}
+
+function stripRefParam() {
+ const url = new URL(window.location.href);
+
+ // Remove from query string
+ url.searchParams.delete(QUERY_PARAM);
+
+ // Remove from fragment if present (#heading?ref=tc → #heading)
+ let hash = url.hash;
+ const qIndex = hash.indexOf('?');
+ if (qIndex !== -1) {
+ const hashBase = hash.substring(0, qIndex);
+ const hashParams = new URLSearchParams(hash.substring(qIndex));
+ hashParams.delete(QUERY_PARAM);
+ const remaining = hashParams.toString();
+ hash = remaining ? `${hashBase}?${remaining}` : hashBase;
+ }
+
+ window.history.replaceState({}, '', url.pathname + url.search + hash);
+}
+
+// ─── Download link rendering ────────────────────────────────────────────────
+
+function renderDownloadLinks(container, data) {
+ const version = data.version;
+ const platforms = data.platforms;
+
+ let html = '
';
+
+ platforms.forEach((platform) => {
+ html += `
${platform.name} `;
+ html +=
+ '
' +
+ `Telegraf Controller v${version} ` +
+ '
';
+ html += '
';
+
+ platform.builds.forEach((build) => {
+ const link =
+ `
${platform.name}` +
+ ` (${build.arch}) `;
+ const sha =
+ `
sha256:${build.sha256}` +
+ '
` +
+ ' ';
+ html +=
+ '
' +
+ `
${link}
` +
+ `
${sha}
` +
+ '
';
+ });
+
+ html += '
';
+ });
+
+ container.innerHTML = html;
+}
+
+// ─── Clipboard copy ─────────────────────────────────────────────────────────
+
+function copyToClipboard(sha, button) {
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(sha).then(() => {
+ showCopiedFeedback(button);
+ });
+ } else {
+ // Fallback for older browsers
+ const textArea = document.createElement('textarea');
+ textArea.value = sha;
+ textArea.style.position = 'fixed';
+ textArea.style.opacity = '0';
+ document.body.appendChild(textArea);
+ textArea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textArea);
+ showCopiedFeedback(button);
+ }
+}
+
+function showCopiedFeedback(button) {
+ const original = button.innerHTML;
+ button.innerHTML = '';
+ setTimeout(() => {
+ button.innerHTML = original;
+ }, 2000);
+}
+
+// ─── Marketo form ───────────────────────────────────────────────────────────
+
+function initMarketoForm() {
+ /* global MktoForms2 */
+ if (typeof MktoForms2 === 'undefined') {
+ console.error('tc-downloads: MktoForms2 not loaded');
+ return;
+ }
+
+ MktoForms2.setOptions({
+ formXDPath: '/rs/972-GDU-533/images/marketo-xdframe-relative.html',
+ });
+
+ MktoForms2.loadForm(
+ 'https://get.influxdata.com',
+ '972-GDU-533',
+ 3195,
+ function (form) {
+ form.addHiddenFields({ mkto_content_name: 'Telegraf Enterprise Alpha' });
+
+ form.onSuccess(function () {
+ setDownloadKey();
+ toggleModal();
+
+ // Redirect to self with ?ref=tc to trigger downloads on reload
+ const url = new URL(window.location.href);
+ url.searchParams.set(QUERY_PARAM, QUERY_VALUE);
+ window.location.href = url.toString();
+
+ // Prevent Marketo's default redirect
+ return false;
+ });
+ }
+ );
+}
+
+// ─── View state management ──────────────────────────────────────────────────
+
+function showDownloads(area) {
+ const btn = area.querySelector('#tc-download-btn');
+ const linksContainer = area.querySelector('#tc-downloads-links');
+
+ if (!linksContainer) return;
+
+ // Parse download data from the JSON data attribute
+ const rawData = linksContainer.getAttribute('data-downloads');
+ if (!rawData) return;
+
+ let data;
+ try {
+ data = JSON.parse(atob(rawData));
+ } catch (e) {
+ console.error('tc-downloads: failed to parse download data', e);
+ return;
+ }
+
+ // Hide the download button
+ if (btn) btn.style.display = 'none';
+
+ // Render download links and show the container
+ renderDownloadLinks(linksContainer, data);
+ linksContainer.style.display = 'block';
+}
+
+// ─── Initialize ─────────────────────────────────────────────────────────────
+
+function initialize() {
+ // 1. Handle ?ref=tc query param on any page
+ if (hasRefParam()) {
+ setDownloadKey();
+ stripRefParam();
+ }
+
+ const area = document.getElementById('tc-downloads-area');
+ if (!area) return; // No shortcode on this page — no-op
+
+ // 2. Check localStorage and show appropriate view
+ if (hasDownloadKey()) {
+ showDownloads(area);
+ }
+
+ // 3. Initialize Marketo form
+ initMarketoForm();
+
+ // 4. Delegated click handler for SHA copy buttons
+ area.addEventListener('click', function (e) {
+ const copyBtn = e.target.closest('.tc-copy-sha');
+ if (copyBtn) {
+ const sha = copyBtn.getAttribute('data-sha');
+ if (sha) copyToClipboard(sha, copyBtn);
+ }
+ });
+}
+
+export { initialize };
diff --git a/assets/styles/layouts/_article.scss b/assets/styles/layouts/_article.scss
index d3f56bccd..1b8584fd8 100644
--- a/assets/styles/layouts/_article.scss
+++ b/assets/styles/layouts/_article.scss
@@ -216,6 +216,7 @@
"article/tabbed-content",
"article/tables",
"article/tags",
+ "article/tc-downloads",
"article/telegraf-plugins",
"article/title",
"article/truncate",
diff --git a/assets/styles/layouts/_modals.scss b/assets/styles/layouts/_modals.scss
index 2a149c378..fadb181eb 100644
--- a/assets/styles/layouts/_modals.scss
+++ b/assets/styles/layouts/_modals.scss
@@ -135,7 +135,8 @@
@import "modals/url-selector";
@import "modals/page-feedback";
@import "modals/flux-versions";
- @import "modals/_influxdb-gs-datepicker"
+ @import "modals/_influxdb-gs-datepicker";
+ @import "modals/tc-downloads";
}
diff --git a/assets/styles/layouts/article/_tc-downloads.scss b/assets/styles/layouts/article/_tc-downloads.scss
new file mode 100644
index 000000000..a8b54d3d4
--- /dev/null
+++ b/assets/styles/layouts/article/_tc-downloads.scss
@@ -0,0 +1,104 @@
+/////////////////// Styles for inline TC download links ////////////////////////
+
+#tc-downloads-area {
+ margin: 0 0 2rem;
+
+ #tc-download-btn {
+ display: inline-block;
+ }
+
+ .tc-version {
+ font-size: 1rem;
+ color: rgba($article-text, .6);
+ margin-bottom: .5rem;
+ }
+
+ .tc-build-table {
+ margin-bottom: 1rem;
+ }
+
+
+ .tc-build-row {
+ display: flex;
+ align-items: center;
+ border-bottom: 1px solid $article-hr;
+
+ &:first-child {
+ border-top: 1px solid $article-hr;
+ }
+ }
+
+ .tc-build-download {
+ flex: 1 1 auto;
+ margin-right: 1rem;
+ }
+
+ .tc-download-link {
+ font-size: 1rem;
+ padding: .35rem 1rem;
+ white-space: nowrap;
+ }
+
+ .tc-build-sha {
+ flex: 1 1 auto;
+ display: flex;
+ justify-content: flex-end;
+ gap: .1rem;
+ min-width: 0;
+ max-width: 25rem;
+
+ code {
+ font-size: .8rem;
+ padding: .15rem .65rem;
+ color: $article-code;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .tc-copy-sha {
+ flex-shrink: 0;
+ background: $article-code-bg;
+ border: none;
+ border-radius: $radius;
+ padding: .2rem .6rem;
+ font-family: 'icomoon-v4';
+ font-size: .9rem;
+ color: rgba($article-code, .85);
+ cursor: pointer;
+ transition: color .2s;
+
+ &:hover {
+ color: $article-code-link-hover;
+ }
+ }
+ }
+}
+
+//////////////////////////////// MEDIA QUERIES /////////////////////////////////
+
+@include media(small) {
+ #tc-downloads-area {
+ .tc-build-row {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: .5rem;
+ }
+
+ .tc-build-download {
+ margin-right: 0;
+ width: 100%;
+ }
+
+ .tc-download-link {
+ width: 100%;
+ text-align: center;
+ }
+
+ .tc-build-sha {
+ width: 100%;
+ max-width: 100%;
+ margin-bottom: .5rem;
+ }
+ }
+}
diff --git a/assets/styles/layouts/modals/_tc-downloads.scss b/assets/styles/layouts/modals/_tc-downloads.scss
new file mode 100644
index 000000000..a9def5ae8
--- /dev/null
+++ b/assets/styles/layouts/modals/_tc-downloads.scss
@@ -0,0 +1,226 @@
+////////////////////// Styles for the TC downloads modal ////////////////////////
+
+#tc-downloads {
+
+ // ─── Reset Marketo's inline styles and defaults ────────────────────────────
+ .mktoForm {
+ width: 100% !important;
+ font-family: $proxima !important;
+ font-size: 1rem !important;
+ color: $article-text !important;
+ padding: 0 !important;
+ }
+
+ // Hide Marketo's offset/gutter spacers
+ .mktoOffset,
+ .mktoGutter {
+ display: none !important;
+ }
+
+ // ─── Form layout: 2-column grid for first 4 fields ───────────────────────
+ .mktoForm {
+ display: grid !important;
+ grid-template-columns: 1fr 1fr;
+ gap: 0 1.75rem;
+ }
+
+ // Visible field rows (First Name, Last Name, Company, Job Title)
+ // occupy one grid cell each — pairs share a row automatically
+ .mktoFormRow {
+ margin-bottom: .5rem;
+ }
+
+ // Hidden field rows collapse — they don't disrupt the grid
+ .mktoFormRow:has(input[type='hidden']) {
+ display: none;
+ }
+
+ // Email, Privacy, and Submit span full width
+ .mktoFormRow:has(.mktoEmailField),
+ .mktoFormRow:has(.mktoCheckboxList),
+ .mktoButtonRow {
+ grid-column: 1 / -1;
+ }
+
+ .mktoFieldDescriptor,
+ .mktoFieldWrap {
+ width: 100% !important;
+ margin-bottom: 0 !important;
+ }
+
+ // ─── Labels ───────────────────────────────────────────────────────────────
+ .mktoLabel {
+ display: flex !important;
+ align-items: baseline;
+ width: 100% !important;
+ font-family: $proxima !important;
+ font-weight: $medium !important;
+ font-size: .9rem !important;
+ color: $article-bold !important;
+ padding: .5rem 0 .1rem !important;
+ }
+
+ .mktoAsterix {
+ order: 1;
+ color: #e85b5b !important;
+ float: none !important;
+ padding-left: .15rem;
+ }
+
+ // ─── Text inputs ──────────────────────────────────────────────────────────
+ .mktoField.mktoTextField,
+ .mktoField.mktoEmailField {
+ width: 100% !important;
+ font-family: $proxima !important;
+ font-weight: $medium !important;
+ font-size: 1rem !important;
+ background: rgba($article-text, .06) !important;
+ border-radius: $radius !important;
+ border: 1px solid rgba($article-text, .06) !important;
+ padding: .5em !important;
+ color: $article-text !important;
+ transition-property: border;
+ transition-duration: .2s;
+ box-shadow: none !important;
+
+ &:focus {
+ outline: none !important;
+ border-color: $sidebar-search-highlight !important;
+ }
+
+ &::placeholder {
+ color: rgba($sidebar-search-text, .45) !important;
+ font-weight: normal !important;
+ font-style: italic !important;
+ }
+ }
+
+ // ─── Checkbox / privacy consent ───────────────────────────────────────────
+ .mktoFormRow:has(.mktoCheckboxList) .mktoAsterix {
+ display: none !important;
+ }
+
+ .mktoCheckboxList {
+ width: 100% !important;
+
+ label {
+ font-family: $proxima !important;
+ font-size: .85rem !important;
+ line-height: 1.4 !important;
+ color: rgba($article-text, .7) !important;
+
+ &::after {
+ content: '*';
+ color: #e85b5b;
+ font-weight: $medium;
+ font-size: .95rem;
+ font-style: normal;
+ }
+
+ a {
+ color: $article-link !important;
+ font-weight: $medium;
+ text-decoration: none;
+ transition: color .2s;
+
+ &:hover {
+ color: $article-link-hover !important;
+ }
+ }
+ }
+
+ input[type='checkbox'] {
+ margin: .2rem .65rem 0 0;
+ }
+ }
+
+ // ─── Submit button ────────────────────────────────────────────────────────
+ .mktoButtonRow {
+ margin-top: 1rem;
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ .mktoButtonWrap {
+ margin-left: 0 !important;
+ }
+
+ .mktoButton {
+ @include gradient($article-btn-gradient);
+ border: none !important;
+ border-radius: $radius !important;
+ padding: .65rem 1.5rem !important;
+ font-family: $proxima !important;
+ font-weight: $medium !important;
+ font-size: 1rem !important;
+ color: $g20-white !important;
+ cursor: pointer;
+ transition: opacity .2s;
+
+ &:hover {
+ @include gradient($article-btn-gradient-hover);
+ }
+ }
+
+ // ─── Validation errors ────────────────────────────────────────────────────
+ // Marketo positions errors absolutely — make them flow inline instead
+ .mktoFieldWrap {
+ position: relative;
+ }
+
+ .mktoError {
+ position: relative !important;
+ bottom: auto !important;
+ left: auto !important;
+ right: auto !important;
+ pointer-events: none;
+
+ .mktoErrorArrow {
+ display: none !important;
+ }
+
+ .mktoErrorMsg {
+ font-family: $proxima !important;
+ font-size: .8rem !important;
+ max-width: 100% !important;
+ background: none !important;
+ border: none !important;
+ color: #e85b5b !important;
+ padding: .15rem 0 0 !important;
+ box-shadow: none !important;
+ text-shadow: none !important;
+ }
+ }
+
+ // ─── Custom error message ─────────────────────────────────────────────────
+ .tc-form-error {
+ margin: .75rem 0;
+ padding: .5rem .75rem;
+ background: rgba(#e85b5b, .1);
+ border: 1px solid rgba(#e85b5b, .3);
+ border-radius: $radius;
+ color: #e85b5b;
+ font-size: .9rem;
+ }
+
+ // ─── Clear floats ─────────────────────────────────────────────────────────
+ .mktoClear {
+ clear: both;
+ }
+}
+
+//////////////////////////////// MEDIA QUERIES /////////////////////////////////
+
+@include media(small) {
+ #tc-downloads {
+ .mktoForm {
+ grid-template-columns: 1fr;
+ }
+
+ .mktoFormRow:has(.mktoEmailField),
+ .mktoFormRow:has(.mktoCheckboxList),
+ .mktoButtonRow {
+ grid-column: auto;
+ }
+ }
+}
diff --git a/content/telegraf/controller/install/_index.md b/content/telegraf/controller/install/_index.md
index a58650213..908ec8fc3 100644
--- a/content/telegraf/controller/install/_index.md
+++ b/content/telegraf/controller/install/_index.md
@@ -76,15 +76,7 @@ $env:TELEGRAF_CONTROLLER_EULA="accept"
1. **Download the {{% product-name %}} executable.**
- > [!Note]
- > #### Contact InfluxData for download
- >
- > If you are currently participating in the {{% product-name %}} private alpha,
- > send your operating system and architecture to InfluxData and we will
- > provide you with the appropriate {{% product-name %}} executable.
- >
- > If you are not currently in the private alpha and would like to be,
- > [request early access](https://www.influxdata.com/products/telegraf-enterprise).
+ {{< telegraf/tc-downloads >}}
2. **Install {{% product-name %}}**.
diff --git a/cypress/e2e/content/tc-downloads.cy.js b/cypress/e2e/content/tc-downloads.cy.js
new file mode 100644
index 000000000..c7d8045c1
--- /dev/null
+++ b/cypress/e2e/content/tc-downloads.cy.js
@@ -0,0 +1,103 @@
+///
+
+/**
+ * E2E tests for the Telegraf Controller gated downloads module (tc-downloads.js).
+ *
+ * Tests the four key user-facing behaviors:
+ * 1. Gated state — no localStorage key → button visible, links hidden
+ * 2. Ungated state — localStorage key present → links rendered, button hidden
+ * 3. Query param — ?ref=tc visit → key set, downloads shown
+ * 4. SHA copy button — present when downloads are rendered
+ *
+ * Marketo form submission is NOT tested (external dependency).
+ */
+
+const PAGE_URL = '/telegraf/controller/install/';
+const STORAGE_KEY = 'influxdata_docs_tc_dl';
+
+describe('Telegraf Controller gated downloads', () => {
+ describe('Gated state (no localStorage key)', () => {
+ beforeEach(() => {
+ // Clear any existing key so the page starts in the gated state.
+ cy.clearLocalStorage();
+ cy.visit(PAGE_URL);
+ });
+
+ it('shows the download button', () => {
+ cy.get('#tc-download-btn').should('be.visible');
+ });
+
+ it('keeps the download links container hidden', () => {
+ cy.get('#tc-downloads-links').should('not.be.visible');
+ });
+
+ it('does not render download link anchors', () => {
+ cy.get('.tc-download-link').should('not.exist');
+ });
+ });
+
+ describe('Ungated state (localStorage key present)', () => {
+ beforeEach(() => {
+ cy.clearLocalStorage();
+ cy.visit(PAGE_URL, {
+ onBeforeLoad(win) {
+ win.localStorage.setItem(STORAGE_KEY, 'true');
+ },
+ });
+ });
+
+ it('hides the download button', () => {
+ cy.get('#tc-download-btn').should('not.be.visible');
+ });
+
+ it('shows the downloads container', () => {
+ cy.get('#tc-downloads-links').should('be.visible');
+ });
+
+ it('renders at least one download link', () => {
+ cy.get('.tc-download-link').should('have.length.at.least', 1);
+ });
+
+ it('renders SHA copy buttons for each build', () => {
+ cy.get('.tc-copy-sha').should('have.length.at.least', 1);
+ });
+ });
+
+ describe('Query param flow (?ref=tc)', () => {
+ beforeEach(() => {
+ cy.clearLocalStorage();
+ cy.visit(`${PAGE_URL}?ref=tc`);
+ });
+
+ it('sets the localStorage key', () => {
+ cy.window().then((win) => {
+ expect(win.localStorage.getItem(STORAGE_KEY)).to.equal('true');
+ });
+ });
+
+ it('shows download links after the param is processed', () => {
+ cy.get('.tc-download-link').should('have.length.at.least', 1);
+ });
+
+ it('strips the ?ref=tc param from the URL', () => {
+ cy.url().should('not.include', 'ref=tc');
+ });
+ });
+
+ describe('SHA copy button', () => {
+ beforeEach(() => {
+ cy.clearLocalStorage();
+ cy.visit(PAGE_URL, {
+ onBeforeLoad(win) {
+ win.localStorage.setItem(STORAGE_KEY, 'true');
+ },
+ });
+ });
+
+ it('each copy button carries a data-sha attribute', () => {
+ cy.get('.tc-copy-sha').each(($btn) => {
+ expect($btn.attr('data-sha')).to.be.a('string').and.not.be.empty;
+ });
+ });
+ });
+});
diff --git a/data/tc_downloads.yml b/data/tc_downloads.yml
new file mode 100644
index 000000000..834774eb7
--- /dev/null
+++ b/data/tc_downloads.yml
@@ -0,0 +1,24 @@
+version: "0.0.5-beta"
+platforms:
+ - name: Linux
+ builds:
+ - arch: x86_64
+ filename: telegraf-controller-1.0.0_linux_x86_64.tar.gz
+ url: https://dl.influxdata.com/telegraf-controller/releases/telegraf-controller-1.0.0_linux_x86_64.tar.gz
+ sha256: "placeholder"
+ - name: macOS
+ builds:
+ - arch: arm64
+ filename: telegraf-controller-1.0.0_darwin_arm64.tar.gz
+ url: https://dl.influxdata.com/telegraf-controller/releases/telegraf-controller-1.0.0_darwin_arm64.tar.gz
+ sha256: "placeholder"
+ - arch: x86_64
+ filename: telegraf-controller-1.0.0_darwin_x86_64.tar.gz
+ url: https://dl.influxdata.com/telegraf-controller/releases/telegraf-controller-1.0.0_darwin_x86_64.tar.gz
+ sha256: "placeholder"
+ - name: Windows
+ builds:
+ - arch: x86_64
+ filename: telegraf-controller-1.0.0_windows_x86_64.zip
+ url: https://dl.influxdata.com/telegraf-controller/releases/telegraf-controller-1.0.0_windows_x86_64.zip
+ sha256: "placeholder"
diff --git a/layouts/partials/footer/modals.html b/layouts/partials/footer/modals.html
index 9830135dd..56f27291f 100644
--- a/layouts/partials/footer/modals.html
+++ b/layouts/partials/footer/modals.html
@@ -14,6 +14,9 @@
{{ if $inStdlib }}
{{ partial "footer/modals/flux-influxdb-versions.html" . }}
{{ end }}
+ {{ if .Page.HasShortcode "telegraf/tc-downloads" }}
+ {{ partial "footer/modals/tc-downloads.html" . }}
+ {{ end }}
\ No newline at end of file
diff --git a/layouts/partials/footer/modals/tc-downloads.html b/layouts/partials/footer/modals/tc-downloads.html
new file mode 100644
index 000000000..882c25545
--- /dev/null
+++ b/layouts/partials/footer/modals/tc-downloads.html
@@ -0,0 +1,11 @@
+
+
Download Telegraf Controller
+
Provide your information to access Telegraf Controller downloads.
+
+
+
+
+
+ An error occurred. Please try again.
+
+
diff --git a/layouts/shortcodes/telegraf/tc-downloads.html b/layouts/shortcodes/telegraf/tc-downloads.html
new file mode 100644
index 000000000..ceae8efa8
--- /dev/null
+++ b/layouts/shortcodes/telegraf/tc-downloads.html
@@ -0,0 +1,17 @@
+{{/*
+ tc-downloads shortcode
+ Renders a gated download experience for Telegraf Controller.
+ - Shows a "Download" button that opens a contact form modal.
+ - After form submission (or email link with ?ref=tc), JS renders
+ download links from the JSON data attribute.
+ - Data sourced from data/tc_downloads.yml.
+*/}}
+