chore(js): Extract Hugo params imports to single-purpose modules, fix environment-specific Hugo configs, use Hugo environments instead of specifying the config file, configure source maps and ESM for development and testing

chore-js-refactor-footer-scripts-modules
Jason Stirnaman 2025-06-09 13:59:29 -05:00
parent cd087af85d
commit 717ec5cd1d
28 changed files with 476 additions and 525 deletions

View File

@ -41,7 +41,7 @@ jobs:
- /home/circleci/bin - /home/circleci/bin
- run: - run:
name: Hugo Build name: Hugo Build
command: npx hugo --config config/production/config.yml --logLevel info --minify --gc --destination workspace/public command: yarn hugo --environment production --logLevel info --gc --destination workspace/public
- persist_to_workspace: - persist_to_workspace:
root: workspace root: workspace
paths: paths:

View File

@ -1730,11 +1730,30 @@ If you're adding UI functionality that requires JavaScript, follow these steps:
### Debugging JavaScript ### Debugging JavaScript
To debug JavaScript code used in the InfluxData documentation UI: To debug JavaScript code used in the InfluxData documentation UI, choose one of the following methods:
- Use source maps and the Chrome DevTools debugger.
- Use debug helpers that provide breakpoints and console logging as a workaround or alternative for using source maps and the Chrome DevTools debugger.
#### Using source maps and Chrome DevTools debugger
1. In VS Code, select Run > Start Debugging.
2. Select the "Debug Docs (source maps)" configuration.
3. Click the play button to start the debugger.
5. Set breakpoints in the JavaScript source files--files in the
`assets/js/ns-hugo-imp:` namespace-- in the
VS Code editor or in the Chrome Developer Tools Sources panel:
- In the VS Code Debugger panel > "Loaded Scripts" section, find the
`assets/js/ns-hugo-imp:` namespace.
- In the Chrome Developer Tools Sources panel, expand
`js/ns-hugo-imp:/<YOUR_WORKSPACE_ROOT>/assets/js/`.
#### Using debug helpers
1. In your JavaScript module, import debug helpers from `assets/js/utils/debug-helpers.js`. 1. In your JavaScript module, import debug helpers from `assets/js/utils/debug-helpers.js`.
These helpers provide breakpoints and console logging as a workaround for These helpers provide breakpoints and console logging as a workaround or alternative for
Hugo's lack of source map support in the asset pipeline. using source maps and the Chrome DevTools debugger.
2. Insert debug statements by calling the helper functions in your code--for example: 2. Insert debug statements by calling the helper functions in your code--for example:
```js ```js
@ -1757,7 +1776,7 @@ To debug JavaScript code used in the InfluxData documentation UI:
yarn hugo server yarn hugo server
``` ```
4. In VS Code, go to Run > Start Debugging, and select the "Debug Docs (console-based)" configuration. 4. In VS Code, go to Run > Start Debugging, and select the "Debug JS (debug-helpers)" configuration.
Your system uses the configuration in `launch.json` to launch the site in Chrome Your system uses the configuration in `launch.json` to launch the site in Chrome
and attach the debugger to the Developer Tools console. and attach the debugger to the Developer Tools console.

33
.vscode/launch.json vendored
View File

@ -2,7 +2,7 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Debug Docs (console-based)", "name": "Debug JS (debug-helpers)",
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
"url": "http://localhost:1313", "url": "http://localhost:1313",
@ -13,6 +13,35 @@
"sourceMaps": false, "sourceMaps": false,
"trace": true, "trace": true,
"smartStep": false "smartStep": false
} },
{
"name": "Debug JS (source maps)",
"type": "chrome",
"request": "launch",
"url": "http://localhost:1313",
"webRoot": "${workspaceFolder}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"*": "${webRoot}/assets/js/*",
"main.js": "${webRoot}/assets/js/main.js",
"page-context.js": "${webRoot}/assets/js/page-context.js",
"ask-ai-trigger.js": "${webRoot}/assets/js/ask-ai-trigger.js",
"ask-ai.js": "${webRoot}/assets/js/ask-ai.js",
"utils/*": "${webRoot}/assets/js/utils/*",
"services/*": "${webRoot}/assets/js/services/*"
},
"skipFiles": [
"<node_internals>/**",
"node_modules/**",
"chrome-extension://**"
],
"trace": true,
"smartStep": true,
"disableNetworkCache": true,
"userDataDir": "${workspaceFolder}/.vscode/chrome-user-data",
"runtimeArgs": [
"--disable-features=VizDisplayCompositor"
]
},
] ]
} }

View File

@ -1718,11 +1718,30 @@ If you're adding UI functionality that requires JavaScript, follow these steps:
### Debugging JavaScript ### Debugging JavaScript
To debug JavaScript code used in the InfluxData documentation UI: To debug JavaScript code used in the InfluxData documentation UI, choose one of the following methods:
- Use source maps and the Chrome DevTools debugger.
- Use debug helpers that provide breakpoints and console logging as a workaround or alternative for using source maps and the Chrome DevTools debugger.
#### Using source maps and Chrome DevTools debugger
1. In VS Code, select Run > Start Debugging.
2. Select the "Debug Docs (source maps)" configuration.
3. Click the play button to start the debugger.
5. Set breakpoints in the JavaScript source files--files in the
`assets/js/ns-hugo-imp:` namespace-- in the
VS Code editor or in the Chrome Developer Tools Sources panel:
- In the VS Code Debugger panel > "Loaded Scripts" section, find the
`assets/js/ns-hugo-imp:` namespace.
- In the Chrome Developer Tools Sources panel, expand
`js/ns-hugo-imp:/<YOUR_WORKSPACE_ROOT>/assets/js/`.
#### Using debug helpers
1. In your JavaScript module, import debug helpers from `assets/js/utils/debug-helpers.js`. 1. In your JavaScript module, import debug helpers from `assets/js/utils/debug-helpers.js`.
These helpers provide breakpoints and console logging as a workaround for These helpers provide breakpoints and console logging as a workaround or alternative for
Hugo's lack of source map support in the asset pipeline. using source maps and the Chrome DevTools debugger.
2. Insert debug statements by calling the helper functions in your code--for example: 2. Insert debug statements by calling the helper functions in your code--for example:
```js ```js
@ -1745,7 +1764,7 @@ To debug JavaScript code used in the InfluxData documentation UI:
yarn hugo server yarn hugo server
``` ```
4. In VS Code, go to Run > Start Debugging, and select the "Debug Docs (console-based)" configuration. 4. In VS Code, go to Run > Start Debugging, and select the "Debug JS (debug-helpers)" configuration.
Your system uses the configuration in `launch.json` to launch the site in Chrome Your system uses the configuration in `launch.json` to launch the site in Chrome
and attach the debugger to the Developer Tools console. and attach the debugger to the Developer Tools console.

View File

@ -2,7 +2,7 @@
///////////////// Preferred Client Library programming language /////////////// ///////////////// Preferred Client Library programming language ///////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
import { activateTabs, updateBtnURLs } from './tabbed-content.js'; import { activateTabs, updateBtnURLs } from './tabbed-content.js';
import { getPreference, setPreference } from './local-storage.js'; import { getPreference, setPreference } from './services/local-storage.js';
function getVisitedApiLib() { function getVisitedApiLib() {
const path = window.location.pathname.match( const path = window.location.pathname.match(

View File

@ -8,29 +8,31 @@ function setUser(userid, email) {
window[NAMESPACE] = { window[NAMESPACE] = {
user: { user: {
uniqueClientId: userid, uniqueClientId: userid,
email: email, email: email,
} },
} };
} }
// Initialize the chat widget // Initialize the chat widget
function initializeChat({onChatLoad, chatAttributes}) { function initializeChat({ onChatLoad, chatAttributes }) {
/* See https://docs.kapa.ai/integrations/website-widget/configuration for /* See https://docs.kapa.ai/integrations/website-widget/configuration for
* available configuration options. * available configuration options.
* All values are strings. * All values are strings.
*/ */
// If you make changes to data attributes here, you also need to port the changes to the api-docs/template.hbs API reference template. // If you make changes to data attributes here, you also need to
// port the changes to the api-docs/template.hbs API reference template.
const requiredAttributes = { const requiredAttributes = {
websiteId: 'a02bca75-1dd3-411e-95c0-79ee1139be4d', websiteId: 'a02bca75-1dd3-411e-95c0-79ee1139be4d',
projectName: 'InfluxDB', projectName: 'InfluxDB',
projectColor: '#020a47', projectColor: '#020a47',
projectLogo: '/img/influx-logo-cubo-white.png', projectLogo: '/img/influx-logo-cubo-white.png',
} };
const optionalAttributes = { const optionalAttributes = {
modalDisclaimer:
modalDisclaimer: 'This AI can access [documentation for InfluxDB, clients, and related tools](https://docs.influxdata.com). Information you submit is used in accordance with our [Privacy Policy](https://www.influxdata.com/legal/privacy-policy/).', 'This AI can access [documentation for InfluxDB, clients, and related tools](https://docs.influxdata.com). Information you submit is used in accordance with our [Privacy Policy](https://www.influxdata.com/legal/privacy-policy/).',
modalExampleQuestions: 'Use Python to write data to InfluxDB 3,How do I query using SQL?,How do I use MQTT with Telegraf?', modalExampleQuestions:
'Use Python to write data to InfluxDB 3,How do I query using SQL?,How do I use MQTT with Telegraf?',
buttonHide: 'true', buttonHide: 'true',
exampleQuestionButtonWidth: 'auto', exampleQuestionButtonWidth: 'auto',
modalOpenOnCommandK: 'true', modalOpenOnCommandK: 'true',
@ -52,28 +54,32 @@ function initializeChat({onChatLoad, chatAttributes}) {
modalHeaderBorderBottom: 'none', modalHeaderBorderBottom: 'none',
modalTitleColor: '#fff', modalTitleColor: '#fff',
modalTitleFontSize: '1.25rem', modalTitleFontSize: '1.25rem',
} };
const scriptUrl = 'https://widget.kapa.ai/kapa-widget.bundle.js'; const scriptUrl = 'https://widget.kapa.ai/kapa-widget.bundle.js';
const script = document.createElement('script'); const script = document.createElement('script');
script.async = true; script.async = true;
script.src = scriptUrl; script.src = scriptUrl;
script.onload = function() { script.onload = function () {
onChatLoad(); onChatLoad();
window.influxdatadocs.AskAI = AskAI; window.influxdatadocs.AskAI = AskAI;
}; };
script.onerror = function() { script.onerror = function () {
console.error('Error loading AI chat widget script'); console.error('Error loading AI chat widget script');
}; };
const dataset = {...requiredAttributes, ...optionalAttributes, ...chatAttributes}; const dataset = {
Object.keys(dataset).forEach(key => { ...requiredAttributes,
// Assign dataset attributes from the object ...optionalAttributes,
...chatAttributes,
};
Object.keys(dataset).forEach((key) => {
// Assign dataset attributes from the object
script.dataset[key] = dataset[key]; script.dataset[key] = dataset[key];
}); });
// Check for an existing script element to remove // Check for an existing script element to remove
const oldScript= document.querySelector(`script[src="${scriptUrl}"]`); const oldScript = document.querySelector(`script[src="${scriptUrl}"]`);
if (oldScript) { if (oldScript) {
oldScript.remove(); oldScript.remove();
} }
@ -82,22 +88,21 @@ function initializeChat({onChatLoad, chatAttributes}) {
function getProductExampleQuestions() { function getProductExampleQuestions() {
const questions = productData?.product?.ai_sample_questions; const questions = productData?.product?.ai_sample_questions;
return questions?.join(',') || ''; return questions?.join(',') || '';
} }
/** /**
* chatParams: specify custom (for example, page-specific) attribute values for the chat, pass the dataset key-values (collected in ...chatParams). See https://docs.kapa.ai/integrations/website-widget/configuration for available configuration options. * chatParams: specify custom (for example, page-specific) attribute values for the chat, pass the dataset key-values (collected in ...chatParams). See https://docs.kapa.ai/integrations/website-widget/configuration for available configuration options.
* onChatLoad: function to call when the chat widget has loaded * onChatLoad: function to call when the chat widget has loaded
* userid: optional, a unique user ID for the user (not currently used for public docs) * userid: optional, a unique user ID for the user (not currently used for public docs)
*/ */
export default function AskAI({ userid, email, onChatLoad, ...chatParams }) { export default function AskAI({ userid, email, onChatLoad, ...chatParams }) {
const modalExampleQuestions = getProductExampleQuestions(); const modalExampleQuestions = getProductExampleQuestions();
const chatAttributes = { const chatAttributes = {
...(modalExampleQuestions && { modalExampleQuestions }), ...(modalExampleQuestions && { modalExampleQuestions }),
...chatParams, ...chatParams,
} };
initializeChat({onChatLoad, chatAttributes}); initializeChat({ onChatLoad, chatAttributes });
if (userid) { if (userid) {
setUser(userid, email); setUser(userid, email);

View File

@ -1,8 +1,9 @@
import $ from 'jquery'; import $ from 'jquery';
import { debugBreak } from './utils/debug-helpers.js';
function initialize() { function initialize() {
var codeBlockSelector = '.article--content pre'; var codeBlockSelector = '.article--content pre';
var codeBlocks = $(codeBlockSelector); var $codeBlocks = $(codeBlockSelector);
var appendHTML = ` var appendHTML = `
<div class="code-controls"> <div class="code-controls">
@ -15,7 +16,7 @@ function initialize() {
`; `;
// Wrap all codeblocks with a new 'codeblock' div // Wrap all codeblocks with a new 'codeblock' div
$(codeBlocks).each(function () { $codeBlocks.each(function () {
$(this).wrap("<div class='codeblock'></div>"); $(this).wrap("<div class='codeblock'></div>");
}); });
@ -68,7 +69,9 @@ function initialize() {
// Trigger copy failure state lifecycle // Trigger copy failure state lifecycle
$('.copy-code').click(function () { $('.copy-code').click(function () {
let text = $(this).closest('.code-controls').prevAll('pre:has(code)')[0].innerText; let text = $(this)
.closest('.code-controls')
.prevAll('pre:has(code)')[0].innerText;
const copyContent = async () => { const copyContent = async () => {
try { try {
@ -90,7 +93,10 @@ Disable scrolling on the body.
Disable user selection on everything but the fullscreen codeblock. Disable user selection on everything but the fullscreen codeblock.
*/ */
$('.fullscreen-toggle').click(function () { $('.fullscreen-toggle').click(function () {
var code = $(this).closest('.code-controls').prevAll('pre:has(code)').clone(); var code = $(this)
.closest('.code-controls')
.prevAll('pre:has(code)')
.clone();
$('#fullscreen-code-placeholder').replaceWith(code[0]); $('#fullscreen-code-placeholder').replaceWith(code[0]);
$('body').css('overflow', 'hidden'); $('body').css('overflow', 'hidden');

View File

@ -1,7 +1,7 @@
import $ from 'jquery'; import $ from 'jquery';
import { Datepicker } from 'vanillajs-datepicker'; import { Datepicker } from 'vanillajs-datepicker';
import { toggleModal } from './modals.js'; import { toggleModal } from './modals.js';
import * as localStorage from './local-storage.js'; import * as localStorage from './services/local-storage.js';
// Placeholder start date used in InfluxDB custom timestamps // Placeholder start date used in InfluxDB custom timestamps
const defaultStartDate = '2022-01-01'; const defaultStartDate = '2022-01-01';
@ -53,65 +53,65 @@ function timeToUnixSeconds(time) {
return unixSeconds; return unixSeconds;
} }
// Default time values in getting started sample data // Default time values in getting started sample data
const defaultTimes = [ const defaultTimes = [
{ {
rfc3339: `${defaultStartDate}T08:00:00Z`, rfc3339: `${defaultStartDate}T08:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T08:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T08:00:00Z`),
}, // 1641024000 }, // 1641024000
{ {
rfc3339: `${defaultStartDate}T09:00:00Z`, rfc3339: `${defaultStartDate}T09:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T09:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T09:00:00Z`),
}, // 1641027600 }, // 1641027600
{ {
rfc3339: `${defaultStartDate}T10:00:00Z`, rfc3339: `${defaultStartDate}T10:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T10:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T10:00:00Z`),
}, // 1641031200 }, // 1641031200
{ {
rfc3339: `${defaultStartDate}T11:00:00Z`, rfc3339: `${defaultStartDate}T11:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T11:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T11:00:00Z`),
}, // 1641034800 }, // 1641034800
{ {
rfc3339: `${defaultStartDate}T12:00:00Z`, rfc3339: `${defaultStartDate}T12:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T12:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T12:00:00Z`),
}, // 1641038400 }, // 1641038400
{ {
rfc3339: `${defaultStartDate}T13:00:00Z`, rfc3339: `${defaultStartDate}T13:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T13:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T13:00:00Z`),
}, // 1641042000 }, // 1641042000
{ {
rfc3339: `${defaultStartDate}T14:00:00Z`, rfc3339: `${defaultStartDate}T14:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T14:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T14:00:00Z`),
}, // 1641045600 }, // 1641045600
{ {
rfc3339: `${defaultStartDate}T15:00:00Z`, rfc3339: `${defaultStartDate}T15:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T15:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T15:00:00Z`),
}, // 1641049200 }, // 1641049200
{ {
rfc3339: `${defaultStartDate}T16:00:00Z`, rfc3339: `${defaultStartDate}T16:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T16:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T16:00:00Z`),
}, // 1641052800 }, // 1641052800
{ {
rfc3339: `${defaultStartDate}T17:00:00Z`, rfc3339: `${defaultStartDate}T17:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T17:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T17:00:00Z`),
}, // 1641056400 }, // 1641056400
{ {
rfc3339: `${defaultStartDate}T18:00:00Z`, rfc3339: `${defaultStartDate}T18:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T18:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T18:00:00Z`),
}, // 1641060000 }, // 1641060000
{ {
rfc3339: `${defaultStartDate}T19:00:00Z`, rfc3339: `${defaultStartDate}T19:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T19:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T19:00:00Z`),
}, // 1641063600 }, // 1641063600
{ {
rfc3339: `${defaultStartDate}T20:00:00Z`, rfc3339: `${defaultStartDate}T20:00:00Z`,
unix: timeToUnixSeconds(`${defaultStartDate}T20:00:00Z`), unix: timeToUnixSeconds(`${defaultStartDate}T20:00:00Z`),
}, // 1641067200 }, // 1641067200
]; ];
function updateTimestamps (newStartDate, seedTimes=defaultTimes) { function updateTimestamps(newStartDate, seedTimes = defaultTimes) {
// Update the times array with replacement times // Update the times array with replacement times
const times = seedTimes.map(x => { const times = seedTimes.map((x) => {
var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + 'T'); var newStartTimestamp = x.rfc3339.replace(/^.*T/, newStartDate + 'T');
return { return {
@ -178,7 +178,7 @@ function updateTimestamps (newStartDate, seedTimes=defaultTimes) {
/////////////////////// MODAL INTERACTIONS / DATE PICKER /////////////////////// /////////////////////// MODAL INTERACTIONS / DATE PICKER ///////////////////////
function CustomTimeTrigger({component}) { function CustomTimeTrigger({ component }) {
const $component = $(component); const $component = $(component);
$component $component
.find('a[data-action="open"]:first') .find('a[data-action="open"]:first')
@ -212,7 +212,7 @@ function CustomTimeTrigger({component}) {
if (newDate != undefined) { if (newDate != undefined) {
newDate = formatDate(newDate); newDate = formatDate(newDate);
// Update the last updated timestamps with the new date // Update the last updated timestamps with the new date
// and reassign the updated times. // and reassign the updated times.
updatedTimes = updateTimestamps(newDate, updatedTimes); updatedTimes = updateTimestamps(newDate, updatedTimes);

View File

@ -6,7 +6,7 @@
*/ */
import $ from 'jquery'; import $ from 'jquery';
import * as LocalStorageAPI from './local-storage.js'; import * as LocalStorageAPI from './services/local-storage.js';
// Get notification ID // Get notification ID
function getCalloutID(el) { function getCalloutID(el) {

View File

@ -3,7 +3,6 @@
///////////////////////// INFLUXDB URL PREFERENCE ///////////////////////////// ///////////////////////// INFLUXDB URL PREFERENCE /////////////////////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
*/ */
import * as pageParams from '@params';
import { import {
DEFAULT_STORAGE_URLS, DEFAULT_STORAGE_URLS,
getPreference, getPreference,
@ -12,15 +11,18 @@ import {
removeInfluxDBUrl, removeInfluxDBUrl,
getInfluxDBUrl, getInfluxDBUrl,
getInfluxDBUrls, getInfluxDBUrls,
} from './local-storage.js'; } from './services/local-storage.js';
import $ from 'jquery'; import $ from 'jquery';
import { context as PRODUCT_CONTEXT, referrerHost } from './page-context.js'; import { context as PRODUCT_CONTEXT, referrerHost } from './page-context.js';
import { influxdbUrls } from './services/influxdb-urls.js';
import { delay } from './helpers.js'; import { delay } from './helpers.js';
import { toggleModal } from './modals.js'; import { toggleModal } from './modals.js';
let CLOUD_URLS = []; let CLOUD_URLS = [];
if (pageParams && pageParams.influxdb_urls) { if (influxdbUrls?.cloud) {
CLOUD_URLS = Object.values(pageParams.influxdb_urls.cloud.providers).flatMap((provider) => provider.regions?.map((region) => region.url)); CLOUD_URLS = Object.values(influxdbUrls.cloud.providers).flatMap((provider) =>
provider.regions?.map((region) => region.url)
);
} }
export { CLOUD_URLS }; export { CLOUD_URLS };
@ -28,7 +30,7 @@ export function InfluxDBUrl() {
const UNIQUE_URL_PRODUCTS = ['dedicated', 'clustered']; const UNIQUE_URL_PRODUCTS = ['dedicated', 'clustered'];
const IS_UNIQUE_URL_PRODUCT = UNIQUE_URL_PRODUCTS.includes(PRODUCT_CONTEXT); const IS_UNIQUE_URL_PRODUCT = UNIQUE_URL_PRODUCTS.includes(PRODUCT_CONTEXT);
// Add actual cloud URLs as needed // Add actual cloud URLs as needed
const elementSelector = '.article--content pre:not(.preserve)'; const elementSelector = '.article--content pre:not(.preserve)';
///////////////////// Stored preference management /////////////////////// ///////////////////// Stored preference management ///////////////////////
@ -118,11 +120,12 @@ export function InfluxDBUrl() {
}); });
} }
// Retrieve the currently selected URLs from the urls local storage object. // Retrieve the currently selected URLs from the urls local storage object.
function getUrls() { function getUrls() {
const { cloud, oss, core, enterprise, serverless, dedicated, clustered } = getInfluxDBUrls(); const { cloud, oss, core, enterprise, serverless, dedicated, clustered } =
return { oss, cloud, core, enterprise, serverless, dedicated, clustered }; getInfluxDBUrls();
} return { oss, cloud, core, enterprise, serverless, dedicated, clustered };
}
// Retrieve the previously selected URLs from the from the urls local storage object. // Retrieve the previously selected URLs from the from the urls local storage object.
// This is used to update URLs whenever you switch between browser tabs. // This is used to update URLs whenever you switch between browser tabs.
@ -289,15 +292,17 @@ export function InfluxDBUrl() {
} }
// Append the URL selector button to each codeblock containing a placeholder URL // Append the URL selector button to each codeblock containing a placeholder URL
function appendUrlSelector(urls={ function appendUrlSelector(
cloud: '', urls = {
oss: '', cloud: '',
core: '', oss: '',
enterprise: '', core: '',
serverless: '', enterprise: '',
dedicated: '', serverless: '',
clustered: '', dedicated: '',
}) { clustered: '',
}
) {
const appendToUrls = Object.values(urls); const appendToUrls = Object.values(urls);
const getBtnText = (context) => { const getBtnText = (context) => {
@ -315,7 +320,7 @@ export function InfluxDBUrl() {
return contextText[context]; return contextText[context];
}; };
appendToUrls.forEach(function (url) { appendToUrls.forEach(function (url) {
$(elementSelector).each(function () { $(elementSelector).each(function () {
var code = $(this).html(); var code = $(this).html();
if (code.includes(url)) { if (code.includes(url)) {
@ -330,20 +335,32 @@ export function InfluxDBUrl() {
}); });
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
////////////////// Initialize InfluxDB URL interactions //////////////////// ////////////////// Initialize InfluxDB URL interactions ////////////////////
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Add the preserve tag to code blocks that shouldn't be updated // Add the preserve tag to code blocks that shouldn't be updated
addPreserve(); addPreserve();
const { cloud, oss, core, enterprise, serverless, dedicated, clustered } = DEFAULT_STORAGE_URLS; const { cloud, oss, core, enterprise, serverless, dedicated, clustered } =
DEFAULT_STORAGE_URLS;
// Append URL selector buttons to code blocks // Append URL selector buttons to code blocks
appendUrlSelector({ cloud, oss, core, enterprise, serverless, dedicated, clustered }); appendUrlSelector({
cloud,
oss,
core,
enterprise,
serverless,
dedicated,
clustered,
});
// Update URLs on load // Update URLs on load
updateUrls({ cloud, oss, core, enterprise, serverless, dedicated, clustered }, getUrls()); updateUrls(
{ cloud, oss, core, enterprise, serverless, dedicated, clustered },
getUrls()
);
// Set active radio button on page load // Set active radio button on page load
setRadioButtons(getUrls()); setRadioButtons(getUrls());

View File

@ -1,8 +1,5 @@
// assets/js/main.js // assets/js/main.js
// If you need to pass parameters from the calling Hugo page, you can import them here like so:
// import * as pageParams from '@params';
// Import dependencies that we still need to load in the global scope // Import dependencies that we still need to load in the global scope
import $ from 'jquery'; import $ from 'jquery';
@ -15,7 +12,7 @@ import * as contentInteractions from './content-interactions.js';
import * as datetime from './datetime.js'; import * as datetime from './datetime.js';
import { delay } from './helpers.js'; import { delay } from './helpers.js';
import { InfluxDBUrl } from './influxdb-url.js'; import { InfluxDBUrl } from './influxdb-url.js';
import * as localStorage from './local-storage.js'; import * as localStorage from './services/local-storage.js';
import * as modals from './modals.js'; import * as modals from './modals.js';
import * as notifications from './notifications.js'; import * as notifications from './notifications.js';
import * as pageContext from './page-context.js'; import * as pageContext from './page-context.js';

View File

@ -1,34 +1,80 @@
/** This module retrieves browser context information and site data for the /** This module retrieves browser context information and site data for the
* current page, version, and product. * current page, version, and product.
*/ */
import { products, influxdb_urls } from '@params'; import { products } from './services/influxdata-products.js';
import { influxdbUrls } from './services/influxdb-urls.js';
const safeProducts = products || {};
const safeUrls = influxdb_urls || {};
function getCurrentProductData() { function getCurrentProductData() {
const path = window.location.pathname; const path = window.location.pathname;
const mappings = [ const mappings = [
{ pattern: /\/influxdb\/cloud\//, product: safeProducts.cloud, urls: safeUrls.influxdb_cloud }, {
{ pattern: /\/influxdb3\/core/, product: safeProducts.influxdb3_core, urls: safeUrls.core }, pattern: /\/influxdb\/cloud\//,
{ pattern: /\/influxdb3\/enterprise/, product: safeProducts.influxdb3_enterprise, urls: safeUrls.enterprise }, product: products.cloud,
{ pattern: /\/influxdb3\/cloud-serverless/, product: safeProducts.influxdb3_cloud_serverless, urls: safeUrls.cloud }, urls: influxdbUrls.influxdb_cloud,
{ pattern: /\/influxdb3\/cloud-dedicated/, product: safeProducts.influxdb3_cloud_dedicated, urls: safeUrls.dedicated }, },
{ pattern: /\/influxdb3\/clustered/, product: safeProducts.influxdb3_clustered, urls: safeUrls.clustered }, {
{ pattern: /\/enterprise_v1\//, product: safeProducts.enterprise_influxdb, urls: safeUrls.oss }, pattern: /\/influxdb3\/core/,
{ pattern: /\/influxdb.*v1\//, product: safeProducts.influxdb, urls: safeUrls.oss }, product: products.influxdb3_core,
{ pattern: /\/influxdb.*v2\//, product: safeProducts.influxdb, urls: safeUrls.oss }, urls: influxdbUrls.core,
{ pattern: /\/kapacitor\//, product: safeProducts.kapacitor, urls: safeUrls.oss }, },
{ pattern: /\/telegraf\//, product: safeProducts.telegraf, urls: safeUrls.oss }, {
{ pattern: /\/chronograf\//, product: safeProducts.chronograf, urls: safeUrls.oss }, pattern: /\/influxdb3\/enterprise/,
{ pattern: /\/flux\//, product: safeProducts.flux, urls: safeUrls.oss }, product: products.influxdb3_enterprise,
urls: influxdbUrls.enterprise,
},
{
pattern: /\/influxdb3\/cloud-serverless/,
product: products.influxdb3_cloud_serverless,
urls: influxdbUrls.cloud,
},
{
pattern: /\/influxdb3\/cloud-dedicated/,
product: products.influxdb3_cloud_dedicated,
urls: influxdbUrls.dedicated,
},
{
pattern: /\/influxdb3\/clustered/,
product: products.influxdb3_clustered,
urls: influxdbUrls.clustered,
},
{
pattern: /\/enterprise_v1\//,
product: products.enterprise_influxdb,
urls: influxdbUrls.oss,
},
{
pattern: /\/influxdb.*v1\//,
product: products.influxdb,
urls: influxdbUrls.oss,
},
{
pattern: /\/influxdb.*v2\//,
product: products.influxdb,
urls: influxdbUrls.oss,
},
{
pattern: /\/kapacitor\//,
product: products.kapacitor,
urls: influxdbUrls.oss,
},
{
pattern: /\/telegraf\//,
product: products.telegraf,
urls: influxdbUrls.oss,
},
{
pattern: /\/chronograf\//,
product: products.chronograf,
urls: influxdbUrls.oss,
},
{ pattern: /\/flux\//, product: products.flux, urls: influxdbUrls.oss },
]; ];
for (const { pattern, product, urls } of mappings) { for (const { pattern, product, urls } of mappings) {
if (pattern.test(path)) { if (pattern.test(path)) {
return { return {
product: product || 'unknown', product: product || 'unknown',
urls: urls || {} urls: urls || {},
}; };
} }
} }
@ -36,7 +82,8 @@ function getCurrentProductData() {
return { product: 'other', urls: {} }; return { product: 'other', urls: {} };
} }
// Return the page context (cloud, serverless, oss/enterprise, dedicated, clustered, other) // Return the page context
// (cloud, serverless, oss/enterprise, dedicated, clustered, other)
function getContext() { function getContext() {
if (/\/influxdb\/cloud\//.test(window.location.pathname)) { if (/\/influxdb\/cloud\//.test(window.location.pathname)) {
return 'cloud'; return 'cloud';
@ -78,8 +125,12 @@ const context = getContext(),
protocol = location.protocol, protocol = location.protocol,
referrer = document.referrer === '' ? 'direct' : document.referrer, referrer = document.referrer === '' ? 'direct' : document.referrer,
referrerHost = getReferrerHost(), referrerHost = getReferrerHost(),
// TODO: Verify this still does what we want since the addition of InfluxDB 3 naming and the Core and Enterprise versions. // TODO: Verify this works since the addition of InfluxDB 3 naming
version = (/^v\d/.test(pathArr[1]) || pathArr[1]?.includes('cloud') ? pathArr[1].replace(/^v/, '') : "n/a") // and the Core and Enterprise versions.
version =
/^v\d/.test(pathArr[1]) || pathArr[1]?.includes('cloud')
? pathArr[1].replace(/^v/, '')
: 'n/a';
export { export {
context, context,
@ -92,4 +143,4 @@ export {
referrer, referrer,
referrerHost, referrerHost,
version, version,
}; };

View File

@ -5,33 +5,23 @@
* release notes pages. * release notes pages.
*/ */
export default function ReleaseToc({ component }) { export default function ReleaseToc({ component }) {
// Use jQuery filter to get an array of all the *release* h2 elements // Get all h2 elements that are not checkpoint-releases
const releases = $('h2').filter( const releases = Array.from(document.querySelectorAll('h2')).filter(
(_i, el) => !el.id.match(/checkpoint-releases/) (el) => !el.id.match(/checkpoint-releases/)
); );
// Extract data about each release from the array of releases // Extract data about each release from the array of releases
const releaseData = releases.map((_i, el) => ({ const releaseData = releases.map((el) => ({
name: el.textContent, name: el.textContent,
id: el.id, id: el.id,
class: el.getAttribute('class'), class: el.getAttribute('class'),
date: el.getAttribute('date'), date: el.getAttribute('date'),
})); }));
// Use release data to generate a list item for each release // Build the release table of contents
getReleaseItem = (releaseData) => { const releaseTocUl = component.querySelector('#release-toc ul');
var li = document.createElement('li'); releaseData.forEach((release) => {
if (releaseData.class !== null) { releaseTocUl.appendChild(getReleaseItem(release));
li.className = releaseData.class;
}
li.innerHTML = `<a href="#${releaseData.id}">${releaseData.name}</a>`;
li.setAttribute('date', releaseData.date);
return li;
};
// Use jQuery each to build the release table of contents
releaseData.each((_i, release) => {
$('#release-toc ul')[0].appendChild(getReleaseItem(release));
}); });
/* /*
@ -39,21 +29,43 @@ export default function ReleaseToc({ component }) {
* number specified in the `show` attribute of `ul.release-list`. * number specified in the `show` attribute of `ul.release-list`.
* Once all the release items are visible, the "Show More" button is hidden. * Once all the release items are visible, the "Show More" button is hidden.
*/ */
$('#release-toc .show-more').click(function () { const showMoreBtn = component.querySelector('.show-more');
const itemHeight = 1.885; // Item height in rem if (showMoreBtn) {
const releaseNum = releaseData.length; showMoreBtn.addEventListener('click', function () {
const maxHeight = releaseNum * itemHeight; const itemHeight = 1.885; // Item height in rem
const releaseIncrement = Number($('#release-list')[0].getAttribute('show')); const releaseNum = releaseData.length;
const currentHeight = Number( const maxHeight = releaseNum * itemHeight;
$('#release-list')[0].style.height.match(/\d+\.?\d+/)[0] const releaseList = document.getElementById('release-list');
); const releaseIncrement = Number(releaseList.getAttribute('show'));
const potentialHeight = currentHeight + releaseIncrement * itemHeight; const currentHeightMatch = releaseList.style.height.match(/\d+\.?\d+/);
const newHeight = potentialHeight > maxHeight ? maxHeight : potentialHeight; const currentHeight = currentHeightMatch
? Number(currentHeightMatch[0])
: 0;
const potentialHeight = currentHeight + releaseIncrement * itemHeight;
const newHeight =
potentialHeight > maxHeight ? maxHeight : potentialHeight;
$('#release-list')[0].style.height = `${newHeight}rem`; releaseList.style.height = `${newHeight}rem`;
if (newHeight >= maxHeight) { if (newHeight >= maxHeight) {
$('#release-toc .show-more').fadeOut(100); // Simple fade out
} showMoreBtn.style.transition = 'opacity 0.1s';
}); showMoreBtn.style.opacity = 0;
setTimeout(() => {
showMoreBtn.style.display = 'none';
}, 100);
}
});
}
}
// Use release data to generate a list item for each release
function getReleaseItem(releaseData) {
const li = document.createElement('li');
if (releaseData.class !== null) {
li.className = releaseData.class;
}
li.innerHTML = `<a href="#${releaseData.id}">${releaseData.name}</a>`;
li.setAttribute('date', releaseData.date);
return li;
} }

View File

@ -0,0 +1,3 @@
import { products as productsParam } from '@params';
export const products = productsParam || {};

View File

@ -0,0 +1,3 @@
import { influxdb_urls as influxdbUrlsParam } from '@params';
export const influxdbUrls = influxdbUrlsParam || {};

View File

@ -10,7 +10,8 @@
- messages: Messages (data/notifications.yaml) that have been seen (array) - messages: Messages (data/notifications.yaml) that have been seen (array)
- callouts: Feature callouts that have been seen (array) - callouts: Feature callouts that have been seen (array)
*/ */
import * as pageParams from '@params';
import { influxdbUrls } from './influxdb-urls.js';
// Prefix for all InfluxData docs local storage // Prefix for all InfluxData docs local storage
const storagePrefix = 'influxdata_docs_'; const storagePrefix = 'influxdata_docs_';
@ -83,16 +84,11 @@ function getPreferences() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const defaultUrls = {}; const defaultUrls = {};
// Guard against pageParams being null/undefined and safely access nested properties Object.entries(influxdbUrls).forEach(([product, { providers }]) => {
if (pageParams && pageParams.influxdb_urls) { defaultUrls[product] =
Object.entries(pageParams.influxdb_urls).forEach( providers.filter((provider) => provider.name === 'Default')[0]?.regions[0]
([product, { providers }]) => { ?.url || 'https://cloud2.influxdata.com';
defaultUrls[product] = });
providers.filter((provider) => provider.name === 'Default')[0]
?.regions[0]?.url || 'https://cloud2.influxdata.com';
}
);
}
export const DEFAULT_STORAGE_URLS = { export const DEFAULT_STORAGE_URLS = {
oss: defaultUrls.oss, oss: defaultUrls.oss,

View File

@ -3,7 +3,7 @@
http://www.thesitewizard.com/javascripts/change-style-sheets.shtml http://www.thesitewizard.com/javascripts/change-style-sheets.shtml
*/ */
import * as localStorage from './local-storage.js'; import * as localStorage from './services/local-storage.js';
// *** TO BE CUSTOMISED *** // *** TO BE CUSTOMISED ***
var sidebar_state_preference_name = 'sidebar_state'; var sidebar_state_preference_name = 'sidebar_state';

View File

@ -1,4 +1,4 @@
import { getPreference, setPreference } from './local-storage.js'; import { getPreference, setPreference } from './services/local-storage.js';
const PROPS = { const PROPS = {
style_preference_name: 'theme', style_preference_name: 'theme',
@ -6,19 +6,22 @@ const PROPS = {
style_domain: 'docs.influxdata.com', style_domain: 'docs.influxdata.com',
}; };
function getPreferredTheme () { function getPreferredTheme() {
return `${getPreference(PROPS.style_preference_name)}-theme`; return `${getPreference(PROPS.style_preference_name)}-theme`;
} }
function switchStyle({ styles_element, css_title }) { function switchStyle({ styles_element, css_title }) {
// Disable all other theme stylesheets // Disable all other theme stylesheets
styles_element.querySelectorAll('link[rel*="stylesheet"][title*="theme"]') styles_element
.forEach(function (link) { .querySelectorAll('link[rel*="stylesheet"][title*="theme"]')
link.disabled = true; .forEach(function (link) {
}); link.disabled = true;
});
// Enable the stylesheet with the specified title // Enable the stylesheet with the specified title
const link = styles_element.querySelector(`link[rel*="stylesheet"][title="${css_title}"]`); const link = styles_element.querySelector(
`link[rel*="stylesheet"][title="${css_title}"]`
);
link && (link.disabled = false); link && (link.disabled = false);
setPreference(PROPS.style_preference_name, css_title.replace(/-theme/, '')); setPreference(PROPS.style_preference_name, css_title.replace(/-theme/, ''));
@ -38,5 +41,4 @@ export default function Theme({ component, style }) {
if (component.dataset?.themeCallback === 'setVisibility') { if (component.dataset?.themeCallback === 'setVisibility') {
setVisibility(component); setVisibility(component);
} }
} }

View File

@ -1,6 +1,14 @@
import { CLOUD_URLS } from './influxdb-url.js'; import { CLOUD_URLS } from './influxdb-url.js';
import * as localStorage from './local-storage.js'; import * as localStorage from './services/local-storage.js';
import { context, host, hostname, path, protocol, referrer, referrerHost } from './page-context.js'; import {
context,
host,
hostname,
path,
protocol,
referrer,
referrerHost,
} from './page-context.js';
/** /**
* Builds a referrer whitelist array that includes the current page host and all * Builds a referrer whitelist array that includes the current page host and all
@ -69,8 +77,6 @@ function setWayfindingInputState() {
} }
function submitWayfindingData(engine, action) { function submitWayfindingData(engine, action) {
// Build lp using page data and engine data // Build lp using page data and engine data
const lp = `ioxwayfinding,host=${hostname},path=${path},referrer=${referrer},engine=${engine} action="${action}"`; const lp = `ioxwayfinding,host=${hostname},path=${path},referrer=${referrer},engine=${engine} action="${action}"`;
@ -81,10 +87,7 @@ function submitWayfindingData(engine, action) {
'https://j32dswat7l.execute-api.us-east-1.amazonaws.com/prod/wayfinding' 'https://j32dswat7l.execute-api.us-east-1.amazonaws.com/prod/wayfinding'
); );
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader( xhr.setRequestHeader('Access-Control-Allow-Origin', `${protocol}//${host}`);
'Access-Control-Allow-Origin',
`${protocol}//${host}`
);
xhr.setRequestHeader('Content-Type', 'text/plain; charset=utf-8'); xhr.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');
xhr.setRequestHeader('Accept', 'application/json'); xhr.setRequestHeader('Accept', 'application/json');
xhr.send(lp); xhr.send(lp);

View File

@ -1,2 +0,0 @@
import:
- hugo.yml

View File

@ -1,4 +1,4 @@
baseURL: 'https://docs.influxdata.com/' baseURL: https://docs.influxdata.com/
languageCode: en-us languageCode: en-us
title: InfluxDB Documentation title: InfluxDB Documentation
@ -58,7 +58,11 @@ outputFormats:
# Asset processing configuration for development # Asset processing configuration for development
build: build:
writeStats: false # Ensure Hugo correctly processes JavaScript modules
jsConfig:
nodeEnv: "development"
# Development asset processing
writeStats: false
useResourceCacheWhen: "fallback" useResourceCacheWhen: "fallback"
noJSConfigInAssets: false noJSConfigInAssets: false
@ -72,7 +76,7 @@ module:
- source: node_modules - source: node_modules
target: assets/node_modules target: assets/node_modules
# Development settings # Environment parameters
params: params:
env: development env: development
environment: development environment: development

View File

@ -0,0 +1,17 @@
build:
writeStats: false
useResourceCacheWhen: "fallback"
buildOptions:
sourcemap: false
target: "es2015"
minify:
disableJS: false
disableCSS: false
disableHTML: false
minifyOutput: true
params:
env: production
environment: production
server: {
disableLiveReload: true
}

18
config/staging/hugo.yml Normal file
View File

@ -0,0 +1,18 @@
baseURL: https://test2.docs.influxdata.com/
build:
writeStats: false
useResourceCacheWhen: "fallback"
buildOptions:
sourcemap: false
target: "es2015"
minify:
disableJS: false
disableCSS: false
disableHTML: false
minifyOutput: true
params:
env: staging
environment: staging
server:
disableLiveReload: true

View File

@ -1,106 +0,0 @@
baseURL: 'http://localhost:1315/'
languageCode: en-us
title: InfluxDB Documentation
# Git history information for lastMod-type functionality
enableGitInfo: true
# Syntax Highlighting
pygmentsCodefences: true
pygmentsUseClasses: true
# Preserve case in article tags
preserveTaxonomyNames: true
# Generate a robots.txt
enableRobotsTXT: true
# Markdown rendering options
blackfriday:
hrefTargetBlank: true
smartDashes: false
# Copy taxonomies from main config
taxonomies:
influxdb/v2/tag: influxdb/v2/tags
influxdb/cloud/tag: influxdb/cloud/tags
influxdb3/cloud-serverless/tag: influxdb/cloud-serverless/tags
influxdb3/cloud-dedicated/tag: influxdb/cloud-dedicated/tags
influxdb3/clustered/tag: influxdb3/clustered/tags
influxdb3/core/tag: influxdb3/core/tags
influxdb3/enterprise/tag: influxdb3/enterprise/tags
flux/v0/tag: flux/v0/tags
markup:
goldmark:
renderer:
unsafe: true
extensions:
linkify: false
parser:
attribute:
block: true
privacy:
googleAnalytics:
anonymizeIP: false
disable: false
respectDoNotTrack: true
useSessionStorage: false
youtube:
disable: false
privacyEnhanced: true
outputFormats:
json:
mediaType: application/json
baseName: pages
isPlainText: true
# Asset processing for testing (disable minification)
build:
writeStats: false
useResourceCacheWhen: "fallback"
noJSConfigInAssets: false
# Asset processing configuration
assetDir: "assets"
module:
mounts:
- source: assets
target: assets
- source: node_modules
target: assets/node_modules
# Override settings for testing
buildFuture: true
# Configure what content is built in testing env
params:
env: testing
environment: testing
buildTestContent: true
# Configure the server for testing
server:
port: 1315
baseURL: 'http://localhost:1315/'
watchChanges: true
disableLiveReload: false
# Keep your shared content exclusions
ignoreFiles:
- "content/shared/.*"
# Ignore specific warning logs
ignoreLogs:
- warning-goldmark-raw-html
# Disable minification for testing
minify:
disableJS: true
disableCSS: true
disableHTML: true
minifyOutput: false

View File

@ -2,8 +2,10 @@ import { spawn } from 'child_process';
import fs from 'fs'; import fs from 'fs';
import http from 'http'; import http from 'http';
import net from 'net'; import net from 'net';
import process from 'process';
// Hugo server constants // Hugo server constants
export const HUGO_ENVIRONMENT = 'testing';
export const HUGO_PORT = 1315; export const HUGO_PORT = 1315;
export const HUGO_LOG_FILE = '/tmp/hugo_server.log'; export const HUGO_LOG_FILE = '/tmp/hugo_server.log';
@ -28,7 +30,8 @@ export async function isPortInUse(port) {
/** /**
* Start the Hugo server with the specified options * Start the Hugo server with the specified options
* @param {Object} options - Configuration options for Hugo * @param {Object} options - Configuration options for Hugo
* @param {string} options.configFile - Path to Hugo config file (e.g., 'config/testing/config.yml') * @param {string} options.configFile - Path to Hugo config file
* @param {string} options.environment - Environment to run Hugo in
* @param {number} options.port - Port number for Hugo server * @param {number} options.port - Port number for Hugo server
* @param {boolean} options.buildDrafts - Whether to build draft content * @param {boolean} options.buildDrafts - Whether to build draft content
* @param {boolean} options.noHTTPCache - Whether to disable HTTP caching * @param {boolean} options.noHTTPCache - Whether to disable HTTP caching
@ -36,9 +39,10 @@ export async function isPortInUse(port) {
* @returns {Promise<Object>} Child process object * @returns {Promise<Object>} Child process object
*/ */
export async function startHugoServer({ export async function startHugoServer({
configFile = 'config/testing/config.yml', configFile = 'config/_default/hugo.yml',
port = HUGO_PORT, port = HUGO_PORT,
buildDrafts = true, environment = 'testing',
buildDrafts = false,
noHTTPCache = true, noHTTPCache = true,
logFile = HUGO_LOG_FILE, logFile = HUGO_LOG_FILE,
} = {}) { } = {}) {
@ -48,6 +52,8 @@ export async function startHugoServer({
const hugoArgs = [ const hugoArgs = [
'hugo', 'hugo',
'server', 'server',
'--environment',
environment,
'--config', '--config',
configFile, configFile,
'--port', '--port',
@ -64,16 +70,16 @@ export async function startHugoServer({
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
// Use npx to find and execute Hugo, which will work regardless of installation method // Use yarn to find and execute Hugo, which will work regardless of installation method
console.log(`Running Hugo with npx: npx ${hugoArgs.join(' ')}`); console.log(`Running Hugo with yarn: yarn ${hugoArgs.join(' ')}`);
const hugoProc = spawn('npx', hugoArgs, { const hugoProc = spawn('yarn', hugoArgs, {
stdio: ['ignore', 'pipe', 'pipe'], stdio: ['ignore', 'pipe', 'pipe'],
shell: true, shell: true,
}); });
// Check if the process started successfully // Check if the process started successfully
if (!hugoProc || !hugoProc.pid) { if (!hugoProc || !hugoProc.pid) {
return reject(new Error('Failed to start Hugo server via npx')); return reject(new Error('Failed to start Hugo server via yarn'));
} }
// Set up logging // Set up logging

View File

@ -38,9 +38,10 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import cypress from 'cypress'; import cypress from 'cypress';
import net from 'net'; import net from 'net';
import matter from 'gray-matter'; import { Buffer } from 'buffer';
import { displayBrokenLinksReport, initializeReport } from './link-reporter.js'; import { displayBrokenLinksReport, initializeReport } from './link-reporter.js';
import { import {
HUGO_ENVIRONMENT,
HUGO_PORT, HUGO_PORT,
HUGO_LOG_FILE, HUGO_LOG_FILE,
startHugoServer, startHugoServer,
@ -90,28 +91,6 @@ async function isPortInUse(port) {
}); });
} }
/**
* Extract source information from frontmatter
* @param {string} filePath - Path to the markdown file
* @returns {string|null} Source information if present
*/
function getSourceFromFrontmatter(filePath) {
if (!fs.existsSync(filePath)) {
return null;
}
try {
const fileContent = fs.readFileSync(filePath, 'utf8');
const { data } = matter(fileContent);
return data.source || null;
} catch (err) {
console.warn(
`Warning: Could not extract frontmatter from ${filePath}: ${err.message}`
);
return null;
}
}
/** /**
* Ensures a directory exists, creating it if necessary * Ensures a directory exists, creating it if necessary
* Also creates an empty file to ensure the directory is not empty * Also creates an empty file to ensure the directory is not empty
@ -296,7 +275,7 @@ async function main() {
}); });
console.log('Hugo is available on the system'); console.log('Hugo is available on the system');
} catch (checkErr) { } catch {
console.log( console.log(
'Hugo not found on PATH, will use project-local Hugo via yarn' 'Hugo not found on PATH, will use project-local Hugo via yarn'
); );
@ -304,9 +283,8 @@ async function main() {
// Use the startHugoServer function from hugo-server.js // Use the startHugoServer function from hugo-server.js
hugoProc = await startHugoServer({ hugoProc = await startHugoServer({
configFile: 'config/testing/config.yml', environment: HUGO_ENVIRONMENT,
port: HUGO_PORT, port: HUGO_PORT,
buildDrafts: true,
noHTTPCache: true, noHTTPCache: true,
logFile: HUGO_LOG_FILE, logFile: HUGO_LOG_FILE,
}); });
@ -412,7 +390,7 @@ async function main() {
` Note: ${testFailureCount} test(s) failed but no broken links were detected in the report.` ` Note: ${testFailureCount} test(s) failed but no broken links were detected in the report.`
); );
console.warn( console.warn(
` This usually indicates test errors unrelated to link validation.` ' This usually indicates test errors unrelated to link validation.'
); );
// We should not consider special case domains (those with expected errors) as failures // We should not consider special case domains (those with expected errors) as failures

View File

@ -1,79 +0,0 @@
baseURL: https://test2.docs.influxdata.com/
languageCode: en-us
title: InfluxDB Documentation
# Git history information for lastMod-type functionality
enableGitInfo: true
# Syntax Highlighting
pygmentsCodefences: true
pygmentsUseClasses: true
# Preserve case in article tags
preserveTaxonomyNames: true
# Generate a robots.txt
enableRobotsTXT: true
# Custom staging params
params:
env: staging
environment: staging
server:
disableLiveReload: true
# Staging uses the same asset processing as production
# Enable minification for staging
minify:
disableJS: false
disableCSS: false
disableHTML: false
minifyOutput: true
# Staging asset processing
build:
writeStats: false
useResourceCacheWhen: "always"
buildOptions:
sourcemap: false
target: "es2015"
# Markdown rendering options
blackfriday:
hrefTargetBlank: true
smartDashes: false
taxonomies:
influxdb/v2/tag: influxdb/v2/tags
influxdb/cloud/tag: influxdb/cloud/tags
influxdb3/cloud-serverless/tag: influxdb/cloud-serverless/tags
influxdb/cloud-dedicated/tag: influxdb/cloud-dedicated/tags
influxdb/clustered/tag: influxdb/clustered/tags
influxdb3/core/tag: influxdb3/core/tags
influxdb3/enterprise/tag: influxdb3/enterprise/tags
flux/v0/tag: flux/v0/tags
markup:
goldmark:
renderer:
unsafe: true
extensions:
linkify: false
parser:
attribute:
block: true
privacy:
googleAnalytics:
anonymizeIP: false
disable: false
respectDoNotTrack: true
useSessionStorage: false
youtube:
disable: false
privacyEnhanced: true
outputFormats:
json:
mediaType: application/json
baseName: pages
isPlainText: true

View File

@ -13,96 +13,49 @@
{{ $products := .Site.Data.products }} {{ $products := .Site.Data.products }}
{{ $influxdb_urls := .Site.Data.influxdb_urls }} {{ $influxdb_urls := .Site.Data.influxdb_urls }}
{{ $isDevelopmentOrTesting := or (eq .Site.Params.environment "development") (eq .Site.Params.environment "testing") (eq (getenv "HUGO_ENV") "development") (eq (getenv "HUGO_ENV") "testing") (not hugo.IsProduction) }} <!-- Build main.js -->
{{ $isDevelopment := false }}
{{ $isTesting := false }}
{{ if $isDevelopmentOrTesting }} {{ with hugo }}
{{/* Load individual JS files for debugging with ESM format */}} {{ if .IsDevelopment }}
{{ $sharedParams := dict "product" $product "currentVersion" $currentVersion "isServer" hugo.IsServer "products" $products "influxdb_urls" $influxdb_urls "cloudUrls" $cloudUrls }} {{ $isDevelopment = .IsDevelopment }}
{{/* Load main.js first to ensure proper initialization */}}
{{ $mainJS := resources.Get "js/main.js" }}
{{ if $mainJS }}
{{ $opts := dict
"sourceMap" "external"
"sourcesContent" true
"targetPath" "js/main.js"
"format" "esm"
"bundle" false
"minify" false
"target" "es2017"
"write" true
"params" $sharedParams
}}
{{ $processed := $mainJS | js.Build $opts }}
{{ if $processed }}
<script type="module" src="{{ $processed.RelPermalink }}"></script>
{{ end }}
{{ end }} {{ end }}
{{ end }}
{{/* Load other individual JS files for debugging with error handling */}}
{{ $jsDir := "assets/js" }}
{{ if fileExists $jsDir }}
{{ range $file := (readDir $jsDir) }}
{{ if and (strings.HasSuffix $file.Name ".js") (ne $file.Name "main.js") }}
{{ $jsPath := printf "js/%s" $file.Name }}
{{ $jsRes := resources.Get $jsPath }}
{{ with $jsRes }}
{{ $opts := dict
"sourceMap" ""
"targetPath" $jsPath
"format" "esm"
"bundle" false
"minify" false
"target" "es2015"
"write" true
"params" $sharedParams
}}
{{ $out := . | js.Build $opts }}
{{/* Add descriptive debug comments at the beginning of each file */}}
{{ $debugHeader := printf "// DEBUG MODE: %s\n// Original file: assets/js/%s\n\n" $file.Name $file.Name }}
{{ $modifiedContent := printf "%s%s" $debugHeader $out.Content }}
{{ $out = resources.FromString $jsPath $modifiedContent }}
<script type="module" src="{{ $out.RelPermalink }}"></script> {{ if eq .Site.Params.env "testing" }}
{{ end }} {{ $isTesting = true }}
{{ end }} {{ end }}
{{ end }} {{ if eq .Site.Params.environment "testing" }}
{{ end }} {{ $isTesting = true }}
{{ else }} {{ end }}
{{/* Production environment: Use IIFE for better compatibility */}}
{{ $mainJS := resources.Get "js/main.js" }} {{ $isDevelopmentOrTesting := or $isDevelopment $isTesting }}
{{ if $mainJS }}
{{ $sharedParams := dict "product" $product "currentVersion" $currentVersion "isServer" hugo.IsServer "products" $products "influxdb_urls" $influxdb_urls "cloudUrls" $cloudUrls }} {{ with resources.Get "js/main.js" }}
{{ $opts := dict
{{ $opts := dict "minify" hugo.IsProduction
"minify" hugo.IsProduction "sourceMap" (cond $isDevelopmentOrTesting "inline" "")
"sourceMap" "" "format" (cond $isDevelopmentOrTesting "esm" "iife")
"targetPath" "js/main.js" "bundle" true
"params" $sharedParams "targetPath" "js/main.js"
"format" "iife" "params" (dict
"target" "es2019" "product" $product
"splitting" false "currentVersion" $currentVersion
"external" (slice "*") "isServer" hugo.IsServer
"define" (dict "products" $products
"process.env.NODE_ENV" "\"production\"" "influxdb_urls" $influxdb_urls
) "cloudUrls" $cloudUrls
}} "isDevelopment" $isDevelopmentOrTesting
)
{{ $processed := "" }} }}
{{ with $mainJS }} {{ with . | js.Build $opts }}
{{ $processed = . | js.Build $opts }} {{ if hugo.IsProduction }}
{{ end }} {{ with . | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script>
{{ if $processed }}
{{ if hugo.IsProduction }}
{{ $fingerprinted := $processed | fingerprint }}
{{ if $fingerprinted }}
<script defer src="{{ $fingerprinted.RelPermalink }}" integrity="{{ $fingerprinted.Data.Integrity }}" crossorigin="anonymous"></script>
{{ end }}
{{ else }}
<script defer src="{{ $processed.RelPermalink }}"></script>
{{ end }} {{ end }}
{{ else }}
<script type="module" src="{{ .RelPermalink }}"></script>
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ end }} {{ end }}