Merge pull request #6079 from influxdata/chore-js-refactor-footer-scripts-modules

Chore: JavaScript: refactor footer scripts modules
chore-js-refactor-footer-scripts-modules
Jason Stirnaman 2025-06-05 09:08:11 -05:00 committed by Jason Stirnaman
parent 47cb2ce617
commit 4973026adf
51 changed files with 19477 additions and 452 deletions

View File

@ -1,4 +1,4 @@
version: 2 version: 2.1
jobs: jobs:
build: build:
docker: docker:
@ -41,7 +41,7 @@ jobs:
- /home/circleci/bin - /home/circleci/bin
- run: - run:
name: Hugo Build name: Hugo Build
command: npx hugo --logLevel info --minify --destination workspace/public command: npx hugo --config config/production/config.yml --logLevel info --minify --gc --destination workspace/public
- persist_to_workspace: - persist_to_workspace:
root: workspace root: workspace
paths: paths:
@ -68,7 +68,6 @@ jobs:
when: on_success when: on_success
workflows: workflows:
version: 2
build: build:
jobs: jobs:
- build - build

View File

@ -1679,7 +1679,7 @@ The shortcode takes a regular expression for matching placeholder names.
Use the `code-placeholder-key` shortcode to format the placeholder names in Use the `code-placeholder-key` shortcode to format the placeholder names in
text that describes the placeholder--for example: text that describes the placeholder--for example:
``` ```markdown
{{% code-placeholders "DATABASE_NAME|USERNAME|PASSWORD_OR_TOKEN|API_TOKEN|exampleuser@influxdata.com" %}} {{% code-placeholders "DATABASE_NAME|USERNAME|PASSWORD_OR_TOKEN|API_TOKEN|exampleuser@influxdata.com" %}}
```sh ```sh
curl --request POST http://localhost:8086/write?db=DATABASE_NAME \ curl --request POST http://localhost:8086/write?db=DATABASE_NAME \
@ -1703,3 +1703,64 @@ InfluxDB API documentation when documentation is deployed.
Redoc generates HTML documentation using the InfluxDB `swagger.yml`. Redoc generates HTML documentation using the InfluxDB `swagger.yml`.
For more information about generating InfluxDB API documentation, see the For more information about generating InfluxDB API documentation, see the
[API Documentation README](https://github.com/influxdata/docs-v2/tree/master/api-docs#readme). [API Documentation README](https://github.com/influxdata/docs-v2/tree/master/api-docs#readme).
## JavaScript in the documentation UI
The InfluxData documentation UI uses JavaScript with ES6+ syntax and
`assets/js/main.js` as the entry point to import modules from
`assets/js`.
Only `assets/js/main.js` should be imported in HTML files.
`assets/js/main.js` registers components and initializes them on page load.
If you're adding UI functionality that requires JavaScript, follow these steps:
1. In your HTML file, add a `data-component` attribute to the element that
should be initialized by your JavaScript code. For example:
```html
<div data-component="my-component"></div>
```
2. Following the component pattern, create a single-purpose JavaScript module
(`assets/js/components/my-component.js`)
that exports a single function that receives the component element and initializes it.
3. In `assets/js/main.js`, import the module and register the component to ensure
the component is initialized on page load.
### Debugging JavaScript
To debug JavaScript code used in the InfluxData documentation UI:
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
Hugo's lack of source map support in the asset pipeline.
2. Insert debug statements by calling the helper functions in your code--for example:
```js
import { debugLog, debugBreak, debugInspect } from './utils/debug-helpers.js';
const data = debugInspect(someData, 'Data');
debugLog('Processing data', 'myFunction');
function processData() {
// Add a breakpoint that works with DevTools
debugBreak();
// Your existing code...
}
```
3. Start Hugo in development mode--for example:
```bash
yarn hugo server
```
4. In VS Code, go to Run > Start Debugging, and select the "Debug Docs (console-based)" configuration.
Your system uses the configuration in `launch.json` to launch the site in Chrome
and attach the debugger to the Developer Tools console.
Make sure to remove the debug statements before merging your changes.
The debug helpers are designed to be used in development and should not be used in production.

1
.gitignore vendored
View File

@ -21,6 +21,7 @@ node_modules
test-results.xml test-results.xml
/influxdb3cli-build-scripts/content /influxdb3cli-build-scripts/content
.vscode/* .vscode/*
!.vscode/launch.json
.idea .idea
**/config.toml **/config.toml
package-lock.json package-lock.json

View File

@ -3,3 +3,4 @@
**/.svn **/.svn
**/.hg **/.hg
**/node_modules **/node_modules
assets/jsconfig.json

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Docs (console-based)",
"type": "chrome",
"request": "launch",
"url": "http://localhost:1313",
"webRoot": "${workspaceFolder}",
"skipFiles": [
"<node_internals>/**"
],
"sourceMaps": false,
"trace": true,
"smartStep": false
}
]
}

View File

@ -1667,7 +1667,7 @@ The shortcode takes a regular expression for matching placeholder names.
Use the `code-placeholder-key` shortcode to format the placeholder names in Use the `code-placeholder-key` shortcode to format the placeholder names in
text that describes the placeholder--for example: text that describes the placeholder--for example:
``` ```markdown
{{% code-placeholders "DATABASE_NAME|USERNAME|PASSWORD_OR_TOKEN|API_TOKEN|exampleuser@influxdata.com" %}} {{% code-placeholders "DATABASE_NAME|USERNAME|PASSWORD_OR_TOKEN|API_TOKEN|exampleuser@influxdata.com" %}}
```sh ```sh
curl --request POST http://localhost:8086/write?db=DATABASE_NAME \ curl --request POST http://localhost:8086/write?db=DATABASE_NAME \
@ -1691,3 +1691,64 @@ InfluxDB API documentation when documentation is deployed.
Redoc generates HTML documentation using the InfluxDB `swagger.yml`. Redoc generates HTML documentation using the InfluxDB `swagger.yml`.
For more information about generating InfluxDB API documentation, see the For more information about generating InfluxDB API documentation, see the
[API Documentation README](https://github.com/influxdata/docs-v2/tree/master/api-docs#readme). [API Documentation README](https://github.com/influxdata/docs-v2/tree/master/api-docs#readme).
## JavaScript in the documentation UI
The InfluxData documentation UI uses JavaScript with ES6+ syntax and
`assets/js/main.js` as the entry point to import modules from
`assets/js`.
Only `assets/js/main.js` should be imported in HTML files.
`assets/js/main.js` registers components and initializes them on page load.
If you're adding UI functionality that requires JavaScript, follow these steps:
1. In your HTML file, add a `data-component` attribute to the element that
should be initialized by your JavaScript code. For example:
```html
<div data-component="my-component"></div>
```
2. Following the component pattern, create a single-purpose JavaScript module
(`assets/js/components/my-component.js`)
that exports a single function that receives the component element and initializes it.
3. In `assets/js/main.js`, import the module and register the component to ensure
the component is initialized on page load.
### Debugging JavaScript
To debug JavaScript code used in the InfluxData documentation UI:
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
Hugo's lack of source map support in the asset pipeline.
2. Insert debug statements by calling the helper functions in your code--for example:
```js
import { debugLog, debugBreak, debugInspect } from './utils/debug-helpers.js';
const data = debugInspect(someData, 'Data');
debugLog('Processing data', 'myFunction');
function processData() {
// Add a breakpoint that works with DevTools
debugBreak();
// Your existing code...
}
```
3. Start Hugo in development mode--for example:
```bash
yarn hugo server
```
4. In VS Code, go to Run > Start Debugging, and select the "Debug Docs (console-based)" configuration.
Your system uses the configuration in `launch.json` to launch the site in Chrome
and attach the debugger to the Developer Tools console.
Make sure to remove the debug statements before merging your changes.
The debug helpers are designed to be used in development and should not be used in production.

View File

@ -0,0 +1,72 @@
// Memoize the mermaid module import
let mermaidPromise = null;
export default function Diagram({ component }) {
// Import mermaid.js module (memoized)
if (!mermaidPromise) {
mermaidPromise = import('mermaid');
}
mermaidPromise.then(({ default: mermaid }) => {
// Configure mermaid with InfluxData theming
mermaid.initialize({
startOnLoad: false, // We'll manually call run()
theme: document.body.classList.contains('dark-theme') ? 'dark' : 'default',
themeVariables: {
fontFamily: 'Proxima Nova',
fontSize: '16px',
lineColor: '#22ADF6',
primaryColor: '#22ADF6',
primaryTextColor: '#545454',
secondaryColor: '#05CE78',
tertiaryColor: '#f4f5f5',
},
securityLevel: 'loose', // Required for interactive diagrams
logLevel: 'error'
});
// Process the specific diagram component
try {
mermaid.run({ nodes: [component] });
} catch (error) {
console.error('Mermaid diagram rendering error:', error);
}
// Store reference to mermaid for theme switching
if (!window.mermaidInstances) {
window.mermaidInstances = new Map();
}
window.mermaidInstances.set(component, mermaid);
}).catch(error => {
console.error('Failed to load Mermaid library:', error);
});
// Listen for theme changes to refresh diagrams
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === 'class' &&
document.body.classList.contains('dark-theme') !== window.isDarkTheme) {
window.isDarkTheme = document.body.classList.contains('dark-theme');
// Reload this specific diagram with new theme
if (window.mermaidInstances?.has(component)) {
const mermaid = window.mermaidInstances.get(component);
mermaid.initialize({
theme: window.isDarkTheme ? 'dark' : 'default'
});
mermaid.run({ nodes: [component] });
}
}
});
});
// Watch for theme changes on body element
observer.observe(document.body, { attributes: true });
// Return cleanup function to be called when component is destroyed
return () => {
observer.disconnect();
if (window.mermaidInstances?.has(component)) {
window.mermaidInstances.delete(component);
}
};
}

View File

@ -0,0 +1,180 @@
/**
* DocSearch component for InfluxData documentation
* Handles asynchronous loading and initialization of Algolia DocSearch
*/
const debug = false; // Set to true for debugging output
export default function DocSearch({ component }) {
// Store configuration from component data attributes
const config = {
apiKey: component.getAttribute('data-api-key'),
appId: component.getAttribute('data-app-id'),
indexName: component.getAttribute('data-index-name'),
inputSelector: component.getAttribute('data-input-selector'),
searchTag: component.getAttribute('data-search-tag'),
includeFlux: component.getAttribute('data-include-flux') === 'true',
includeResources:
component.getAttribute('data-include-resources') === 'true',
debug: component.getAttribute('data-debug') === 'true',
};
// Initialize global object to track DocSearch state
window.InfluxDocs = window.InfluxDocs || {};
window.InfluxDocs.search = {
initialized: false,
options: config,
};
// Load DocSearch asynchronously
function loadDocSearch() {
if (debug) {
console.log('Loading DocSearch script...');
}
const script = document.createElement('script');
script.src =
'https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js';
script.async = true;
script.onload = initializeDocSearch;
document.body.appendChild(script);
}
// Initialize DocSearch after script loads
function initializeDocSearch() {
if (debug) {
console.log('Initializing DocSearch...');
}
const multiVersion = ['influxdb'];
// Use object-based lookups instead of conditionals for version and product names
// These can be replaced with data from productData in the future
// Version display name mappings
const versionDisplayNames = {
cloud: 'Cloud (TSM)',
core: 'Core',
enterprise: 'Enterprise',
'cloud-serverless': 'Cloud Serverless',
'cloud-dedicated': 'Cloud Dedicated',
clustered: 'Clustered',
explorer: 'Explorer',
};
// Product display name mappings
const productDisplayNames = {
influxdb: 'InfluxDB',
influxdb3: 'InfluxDB 3',
explorer: 'InfluxDB 3 Explorer',
enterprise_influxdb: 'InfluxDB Enterprise',
flux: 'Flux',
telegraf: 'Telegraf',
chronograf: 'Chronograf',
kapacitor: 'Kapacitor',
platform: 'InfluxData Platform',
resources: 'Additional Resources',
};
// Initialize DocSearch with configuration
window.docsearch({
apiKey: config.apiKey,
appId: config.appId,
indexName: config.indexName,
inputSelector: config.inputSelector,
debug: config.debug,
transformData: function (hits) {
// Format version using object lookup instead of if-else chain
function fmtVersion(version, productKey) {
if (version == null) {
return '';
} else if (versionDisplayNames[version]) {
return versionDisplayNames[version];
} else if (multiVersion.includes(productKey)) {
return version;
} else {
return '';
}
}
hits.map((hit) => {
const pathData = new URL(hit.url).pathname
.split('/')
.filter((n) => n);
const product = productDisplayNames[pathData[0]] || pathData[0];
const version = fmtVersion(pathData[1], pathData[0]);
hit.product = product;
hit.version = version;
hit.hierarchy.lvl0 =
hit.hierarchy.lvl0 +
` <span class=\"search-product-version\">${product} ${version}</span>`;
hit._highlightResult.hierarchy.lvl0.value =
hit._highlightResult.hierarchy.lvl0.value +
` <span class=\"search-product-version\">${product} ${version}</span>`;
});
return hits;
},
algoliaOptions: {
hitsPerPage: 10,
facetFilters: buildFacetFilters(config),
},
autocompleteOptions: {
templates: {
header:
'<div class="search-all-content"><a href="https:\/\/support.influxdata.com" target="_blank">Search all InfluxData content <span class="icon-arrow-up-right"></span></a>',
empty:
'<div class="search-no-results"><p>Not finding what you\'re looking for?</p> <a href="https:\/\/support.influxdata.com" target="_blank">Search all InfluxData content <span class="icon-arrow-up-right"></span></a></div>',
},
},
});
// Mark DocSearch as initialized
window.InfluxDocs.search.initialized = true;
// Dispatch event for other components to know DocSearch is ready
window.dispatchEvent(new CustomEvent('docsearch-initialized'));
}
/**
* Helper function to build facet filters based on config
* - Uses nested arrays for AND conditions
* - Includes space after colon in filter expressions
*/
function buildFacetFilters(config) {
if (!config.searchTag) {
return ['latest:true'];
} else if (config.includeFlux) {
// Return a nested array to match original template structure
// Note the space after each colon
return [
[
'searchTag: ' + config.searchTag,
'flux:true',
'resources: ' + config.includeResources,
],
];
} else {
// Return a nested array to match original template structure
// Note the space after each colon
return [
[
'searchTag: ' + config.searchTag,
'resources: ' + config.includeResources,
],
];
}
}
// Load DocSearch when page is idle or after a slight delay
if ('requestIdleCallback' in window) {
requestIdleCallback(loadDocSearch);
} else {
setTimeout(loadDocSearch, 500);
}
// Return cleanup function
return function cleanup() {
// Clean up any event listeners if needed
if (debug) {
console.log('DocSearch component cleanup');
}
};
}

View File

@ -0,0 +1,6 @@
import SearchInteractions from '../utils/search-interactions';
export default function SidebarSearch({ component }) {
const searchInput = component.querySelector('.sidebar--search-field');
SearchInteractions({ searchInput });
}

View File

@ -1,30 +1,54 @@
const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; import $ from 'jquery';
var date = new Date()
var currentTimestamp = date.toISOString().replace(/^(.*)(\.\d+)(Z)/, '$1$3') // 2023-01-01T12:34:56Z
var currentTime = date.toISOString().replace(/(^.*T)(.*)(Z)/, '$2') + '084216' // 12:34:56.000084216
function currentDate(offset=0, trimTime=false) { var date = new Date();
outputDate = new Date(date) var currentTimestamp = date.toISOString().replace(/^(.*)(\.\d+)(Z)/, '$1$3'); // 2023-01-01T12:34:56Z
outputDate.setDate(outputDate.getDate() + offset)
// Microsecond offset appended to the current time string for formatting purposes
const MICROSECOND_OFFSET = '084216';
var currentTime =
date.toISOString().replace(/(^.*T)(.*)(Z)/, '$2') + MICROSECOND_OFFSET; // 12:34:56.000084216
function currentDate(offset = 0, trimTime = false) {
let outputDate = new Date(date);
outputDate.setDate(outputDate.getDate() + offset);
if (trimTime) { if (trimTime) {
return outputDate.toISOString().replace(/T.*$/, '') // 2023-01-01 return outputDate.toISOString().replace(/T.*$/, ''); // 2023-01-01
} else { } else {
return outputDate.toISOString().replace(/T.*$/, 'T00:00:00Z') // 2023-01-01T00:00:00Z return outputDate.toISOString().replace(/T.*$/, 'T00:00:00Z'); // 2023-01-01T00:00:00Z
} }
} }
function enterpriseEOLDate() { function enterpriseEOLDate() {
var inTwoYears = date.setFullYear(date.getFullYear() + 2) const monthNames = [
earliestEOL = new Date(inTwoYears) 'January',
return `${monthNames[earliestEOL.getMonth()]} ${earliestEOL.getDate()}, ${earliestEOL.getFullYear()}` 'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
var inTwoYears = new Date(date);
inTwoYears.setFullYear(inTwoYears.getFullYear() + 2);
let earliestEOL = new Date(inTwoYears);
return `${monthNames[earliestEOL.getMonth()]} ${earliestEOL.getDate()}, ${earliestEOL.getFullYear()}`;
} }
$('span.current-timestamp').text(currentTimestamp) function initialize() {
$('span.current-time').text(currentTime) $('span.current-timestamp').text(currentTimestamp);
$('span.enterprise-eol-date').text(enterpriseEOLDate) $('span.current-time').text(currentTime);
$('span.current-date').each(function() { $('span.enterprise-eol-date').text(enterpriseEOLDate);
var dayOffset = parseInt($(this).attr("offset")) $('span.current-date').each(function () {
var trimTime = $(this).attr("trim-time") === "true" var dayOffset = parseInt($(this).attr('offset'));
$(this).text(currentDate(dayOffset, trimTime)) var trimTime = $(this).attr('trim-time') === 'true';
}) $(this).text(currentDate(dayOffset, trimTime));
});
}
export { initialize };

View File

@ -2,37 +2,24 @@
This feature is designed to callout new features added to the documentation This feature is designed to callout new features added to the documentation
CSS is required for the callout bubble to determine look and position, but the CSS is required for the callout bubble to determine look and position, but the
element must have the `callout` class and a unique id. element must have the `callout` class and a unique id.
Callouts are treated as notifications and use the notification cookie API in Callouts are treated as notifications and use the LocalStorage notification API.
assets/js/cookies.js.
*/ */
import $ from 'jquery';
import * as LocalStorageAPI from './local-storage.js';
// Get notification ID // Get notification ID
function getCalloutID (el) { function getCalloutID(el) {
return $(el).attr('id'); return $(el).attr('id');
} }
// Hide a callout and update the cookie with the viewed callout
function hideCallout (calloutID) {
if (!window.LocalStorageAPI.notificationIsRead(calloutID)) {
window.LocalStorageAPI.setNotificationAsRead(calloutID, 'callout');
$(`#${calloutID}`).fadeOut(200);
}
}
// Show the url feature callouts on page load // Show the url feature callouts on page load
$(document).ready(function () { export default function FeatureCallout({ component }) {
$('.feature-callout').each(function () { const calloutID = getCalloutID($(component));
const calloutID = getCalloutID($(this));
if (!window.LocalStorageAPI.notificationIsRead(calloutID, 'callout')) { if (!LocalStorageAPI.notificationIsRead(calloutID, 'callout')) {
$(`#${calloutID}.feature-callout`) $(`#${calloutID}.feature-callout`)
.fadeIn(300) .fadeIn(300)
.removeClass('start-position'); .removeClass('start-position');
} }
}); }
});
// Hide the InfluxDB URL selector callout
// $('button.url-trigger, #influxdb-url-selector .close').click(function () {
// hideCallout('influxdb-url-selector');
// });

View File

@ -1,49 +1,148 @@
var tablesElement = $("#flux-group-keys-demo #grouped-tables") import $ from 'jquery';
// Sample data // Sample data
let data = [ let data = [
[ [
{ _time: "2021-01-01T00:00:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "temp", _value: 110.3 }, {
{ _time: "2021-01-01T00:01:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "temp", _value: 112.5 }, _time: '2021-01-01T00:00:00Z',
{ _time: "2021-01-01T00:02:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "temp", _value: 111.9 } _measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'temp',
_value: 110.3,
},
{
_time: '2021-01-01T00:01:00Z',
_measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'temp',
_value: 112.5,
},
{
_time: '2021-01-01T00:02:00Z',
_measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'temp',
_value: 111.9,
},
], ],
[ [
{ _time: "2021-01-01T00:00:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "hum", _value: 73.4 }, {
{ _time: "2021-01-01T00:01:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "hum", _value: 73.7 }, _time: '2021-01-01T00:00:00Z',
{ _time: "2021-01-01T00:02:00Z", _measurement: "example", loc: "rm1", sensorID: "A123", _field: "hum", _value: 75.1 } _measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'hum',
_value: 73.4,
},
{
_time: '2021-01-01T00:01:00Z',
_measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'hum',
_value: 73.7,
},
{
_time: '2021-01-01T00:02:00Z',
_measurement: 'example',
loc: 'rm1',
sensorID: 'A123',
_field: 'hum',
_value: 75.1,
},
], ],
[ [
{ _time: "2021-01-01T00:00:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "temp", _value: 108.2 }, {
{ _time: "2021-01-01T00:01:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "temp", _value: 108.5 }, _time: '2021-01-01T00:00:00Z',
{ _time: "2021-01-01T00:02:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "temp", _value: 109.6 } _measurement: 'example',
loc: 'rm2',
sensorID: 'B456',
_field: 'temp',
_value: 108.2,
},
{
_time: '2021-01-01T00:01:00Z',
_measurement: 'example',
loc: 'rm2',
sensorID: 'B456',
_field: 'temp',
_value: 108.5,
},
{
_time: '2021-01-01T00:02:00Z',
_measurement: 'example',
loc: 'rm2',
sensorID: 'B456',
_field: 'temp',
_value: 109.6,
},
], ],
[ [
{ _time: "2021-01-01T00:00:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "hum", _value: 71.8 }, {
{ _time: "2021-01-01T00:01:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "hum", _value: 72.3 }, _time: '2021-01-01T00:00:00Z',
{ _time: "2021-01-01T00:02:00Z", _measurement: "example", loc: "rm2", sensorID: "B456", _field: "hum", _value: 72.1 } _measurement: 'example',
] loc: 'rm2',
] sensorID: 'B456',
_field: 'hum',
_value: 71.8,
},
{
_time: '2021-01-01T00:01:00Z',
_measurement: 'example',
loc: 'rm2',
sensorID: 'B456',
_field: 'hum',
_value: 72.3,
},
{
_time: '2021-01-01T00:02:00Z',
_measurement: 'example',
loc: 'rm2',
sensorID: 'B456',
_field: 'hum',
_value: 72.1,
},
],
];
// Default group key // Default group key
let groupKey = ["_measurement", "loc", "sensorID", "_field"] let groupKey = ['_measurement', 'loc', 'sensorID', '_field'];
export default function FluxGroupKeysDemo({ component }) {
$('.column-list label').click(function () {
toggleCheckbox($(this));
groupKey = getChecked(component);
groupData();
buildGroupExample(component);
});
// Group and render tables on load
groupData();
}
// Build a table group (group key and table) using an array of objects // Build a table group (group key and table) using an array of objects
function buildTable(inputData) { function buildTable(inputData) {
// Build the group key string // Build the group key string
function wrapString(column, value) { function wrapString(column, value) {
var stringColumns = ["_measurement", "loc", "sensorID", "_field"] var stringColumns = ['_measurement', 'loc', 'sensorID', '_field'];
if (stringColumns.includes(column)) { if (stringColumns.includes(column)) {
return '"' + value + '"' return '"' + value + '"';
} else { } else {
return value return value;
} }
} }
var groupKeyString = "Group key instance = [" + (groupKey.map(column => column + ": " + wrapString(column, (inputData[0])[column])) ).join(", ") + "]"; var groupKeyString =
var groupKeyLabel = document.createElement("p"); 'Group key instance = [' +
groupKeyLabel.className = "table-group-key" groupKey
groupKeyLabel.innerHTML = groupKeyString .map((column) => column + ': ' + wrapString(column, inputData[0][column]))
.join(', ') +
']';
var groupKeyLabel = document.createElement('p');
groupKeyLabel.className = 'table-group-key';
groupKeyLabel.innerHTML = groupKeyString;
// Extract column headers // Extract column headers
var columns = []; var columns = [];
@ -56,54 +155,55 @@ function buildTable(inputData) {
} }
// Create the table element // Create the table element
var table = document.createElement("table"); const table = document.createElement('table');
// Create the table header // Create the table header
for (let i = 0; i < columns.length; i++) { for (let i = 0; i < columns.length; i++) {
var header = table.createTHead(); var header = table.createTHead();
var th = document.createElement("th"); var th = document.createElement('th');
th.innerHTML = columns[i]; th.innerHTML = columns[i];
if (groupKey.includes(columns[i])) { if (groupKey.includes(columns[i])) {
th.className = "grouped-by"; th.className = 'grouped-by';
} }
header.appendChild(th); header.appendChild(th);
} }
// Add inputData to the HTML table // Add inputData to the HTML table
for (let i = 0; i < inputData.length; i++) { for (let i = 0; i < inputData.length; i++) {
tr = table.insertRow(-1); let tr = table.insertRow(-1);
for (let j = 0; j < columns.length; j++) { for (let j = 0; j < columns.length; j++) {
var td = tr.insertCell(-1); var td = tr.insertCell(-1);
td.innerHTML = inputData[i][columns[j]]; td.innerHTML = inputData[i][columns[j]];
// Highlight the value if column is part of the group key // Highlight the value if column is part of the group key
if (groupKey.includes(columns[j])) { if (groupKey.includes(columns[j])) {
td.className = "grouped-by"; td.className = 'grouped-by';
} }
} }
} }
// Create a table group with group key and table // Create a table group with group key and table
var tableGroup = document.createElement("div"); var tableGroup = document.createElement('div');
tableGroup.innerHTML += groupKeyLabel.outerHTML + table.outerHTML tableGroup.innerHTML += groupKeyLabel.outerHTML + table.outerHTML;
return tableGroup return tableGroup;
} }
// Clear and rebuild all HTML tables // Clear and rebuild all HTML tables
function buildTables(data) { function buildTables(data) {
existingTables = tablesElement[0] let tablesElement = $('#flux-group-keys-demo #grouped-tables');
let existingTables = tablesElement[0];
while (existingTables.firstChild) { while (existingTables.firstChild) {
existingTables.removeChild(existingTables.firstChild); existingTables.removeChild(existingTables.firstChild);
} }
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
var table = buildTable(data[i]) var table = buildTable(data[i]);
tablesElement.append(table); tablesElement.append(table);
} }
} }
// Group data based on the group key and output new tables // Group data based on the group key and output new tables
function groupData() { function groupData() {
let groupedData = data.flat() let groupedData = data.flat();
function groupBy(array, f) { function groupBy(array, f) {
var groups = {}; var groups = {};
@ -114,20 +214,19 @@ function groupData() {
}); });
return Object.keys(groups).map(function (group) { return Object.keys(groups).map(function (group) {
return groups[group]; return groups[group];
}) });
} }
groupedData = groupBy(groupedData, function (r) { groupedData = groupBy(groupedData, function (r) {
return groupKey.map(v => r[v]); return groupKey.map((v) => r[v]);
}); });
buildTables(groupedData); buildTables(groupedData);
} }
// Get selected column names function getChecked(component) {
var checkboxes = $("input[type=checkbox]"); // Get selected column names
var checkboxes = $(component).find('input[type=checkbox]');
function getChecked() {
var checked = []; var checked = [];
for (var i = 0; i < checkboxes.length; i++) { for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i]; var checkbox = checkboxes[i];
@ -141,17 +240,12 @@ function toggleCheckbox(element) {
} }
// Build example group function // Build example group function
function buildGroupExample() { function buildGroupExample(component) {
var columnCollection = getChecked().map(i => '<span class=\"s2\">"' + i + '"</span>').join(", ") var columnCollection = getChecked(component)
$("pre#group-by-example")[0].innerHTML = "data\n <span class='nx'>|></span> group(columns<span class='nx'>:</span> [" + columnCollection + "])"; .map((i) => '<span class=\"s2\">"' + i + '"</span>')
.join(', ');
$('pre#group-by-example')[0].innerHTML =
"data\n <span class='nx'>|></span> group(columns<span class='nx'>:</span> [" +
columnCollection +
'])';
} }
$(".column-list label").click(function () {
toggleCheckbox($(this))
groupKey = getChecked();
groupData();
buildGroupExample();
});
// Group and render tables on load
groupData()

View File

@ -1,22 +0,0 @@
$('.exp-btn').click(function() {
var targetBtnElement = $(this).parent()
$('.exp-btn > p', targetBtnElement).fadeOut(100);
setTimeout(function() {
$('.exp-btn-links', targetBtnElement).fadeIn(200)
$('.exp-btn', targetBtnElement).addClass('open');
$('.close-btn', targetBtnElement).fadeIn(200);
}, 100);
})
$('.close-btn').click(function() {
var targetBtnElement = $(this).parent().parent()
$('.exp-btn-links', targetBtnElement).fadeOut(100)
$('.exp-btn', targetBtnElement).removeClass('open');
$(this).fadeOut(100);
setTimeout(function() {
$('p', targetBtnElement).fadeIn(100);
}, 100);
})
/////////////////////////////// EXPANDING BUTTONS //////////////////////////////

View File

@ -1 +0,0 @@
export * from './main.js';

View File

@ -1,41 +1,58 @@
// Dynamically update keybindings or hotkeys import { getPlatform } from './utils/user-agent-platform.js';
function getPlatform() { import $ from 'jquery';
if (/Mac/.test(navigator.platform)) {
return "osx" /**
} else if (/Win/.test(navigator.platform)) { * Adds OS-specific class to component
return "win" * @param {string} osClass - OS-specific class to add
} else if (/Linux/.test(navigator.platform)) { * @param {Object} options - Component options
return "linux" * @param {jQuery} options.$component - jQuery element reference
} else { */
return "other" function addOSClass(osClass, { $component }) {
} $component.addClass(osClass);
} }
const platform = getPlatform() /**
* Updates keybinding display based on detected platform
* @param {Object} options - Component options
* @param {jQuery} options.$component - jQuery element reference
* @param {string} options.platform - Detected platform
*/
function updateKeyBindings({ $component, platform }) {
const osx = $component.data('osx');
const linux = $component.data('linux');
const win = $component.data('win');
function addOSClass(osClass) { let keybind;
$('.keybinding').addClass(osClass)
}
function updateKeyBindings() { if (platform === 'other') {
$('.keybinding').each(function() { if (win !== linux) {
var osx = $(this).data("osx") keybind =
var linux = $(this).data("linux") `<code class="osx">${osx}</code> for macOS, ` +
var win = $(this).data("win") `<code>${linux}</code> for Linux, ` +
`and <code>${win}</code> for Windows`;
if (platform === "other") {
if (win != linux) {
var keybind = '<code class="osx">' + osx + '</code> for macOS, <code>' + linux + '</code> for Linux, and <code>' + win + '</code> for Windows';
} else { } else {
var keybind = '<code>' + linux + '</code> for Linux and Windows and <code class="osx">' + osx + '</code> for macOS'; keybind =
`<code>${linux}</code> for Linux and Windows and ` +
`<code class="osx">${osx}</code> for macOS`;
} }
} else { } else {
var keybind = '<code>' + $(this).data(platform) + '</code>' keybind = `<code>${$component.data(platform)}</code>`;
} }
$(this).html(keybind) $component.html(keybind);
})
} }
addOSClass(platform) /**
updateKeyBindings() * Initialize and render platform-specific keybindings
* @param {Object} options - Component options
* @param {HTMLElement} options.component - DOM element
* @returns {void}
*/
export default function KeyBinding({ component }) {
// Initialize keybindings
const platform = getPlatform();
const $component = $(component);
addOSClass(platform, { $component });
updateKeyBindings({ $component, platform });
}

View File

@ -3,8 +3,8 @@ function countTag(tag) {
return $(".visible[data-tags*='" + tag + "']").length return $(".visible[data-tags*='" + tag + "']").length
} }
function getFilterCounts() { function getFilterCounts($labels) {
$('#list-filters label').each(function() { $labels.each(function() {
var tagName = $('input', this).attr('name').replace(/[\W/]+/, "-"); var tagName = $('input', this).attr('name').replace(/[\W/]+/, "-");
var tagCount = countTag(tagName); var tagCount = countTag(tagName);
$(this).attr('data-count', '(' + tagCount + ')'); $(this).attr('data-count', '(' + tagCount + ')');
@ -16,18 +16,21 @@ function getFilterCounts() {
}) })
} }
// Get initial filter count on page load export default function ListFilters({ component }) {
getFilterCounts() const $labels = $(component).find('label');
const $inputs = $(component).find('input');
$("#list-filters input").click(function() { getFilterCounts($labels);
$inputs.click(function() {
// List of tags to hide // List of tags to hide
var tagArray = $("#list-filters input:checkbox:checked").map(function(){ var tagArray = $(component).find("input:checkbox:checked").map(function(){
return $(this).attr('name').replace(/[\W]+/, "-"); return $(this).attr('name').replace(/[\W]+/, "-");
}).get(); }).get();
// List of tags to restore // List of tags to restore
var restoreArray = $("#list-filters input:checkbox:not(:checked)").map(function(){ var restoreArray = $(component).find("input:checkbox:not(:checked)").map(function(){
return $(this).attr('name').replace(/[\W]+/, "-"); return $(this).attr('name').replace(/[\W]+/, "-");
}).get(); }).get();
@ -46,5 +49,6 @@ $("#list-filters input").click(function() {
} }
// Refresh filter count // Refresh filter count
getFilterCounts() getFilterCounts($labels);
}); });
}

View File

@ -82,13 +82,16 @@ function getPreferences() {
//////////// MANAGE INFLUXDATA DOCS URLS IN LOCAL STORAGE ////////////////////// //////////// MANAGE INFLUXDATA DOCS URLS IN LOCAL STORAGE //////////////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const defaultUrls = {}; const defaultUrls = {};
// Guard against pageParams being null/undefined and safely access nested properties // Guard against pageParams being null/undefined and safely access nested properties
if (pageParams && pageParams.influxdb_urls) { if (pageParams && pageParams.influxdb_urls) {
Object.entries(pageParams.influxdb_urls).forEach(([product, {providers}]) => { Object.entries(pageParams.influxdb_urls).forEach(
defaultUrls[product] = providers.filter(provider => provider.name === 'Default')[0]?.regions[0]?.url; ([product, { providers }]) => {
}); 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 = {
@ -177,7 +180,10 @@ const defaultNotificationsObj = {
function getNotifications() { function getNotifications() {
// Initialize notifications data if it doesn't already exist // Initialize notifications data if it doesn't already exist
if (localStorage.getItem(notificationStorageKey) === null) { if (localStorage.getItem(notificationStorageKey) === null) {
initializeStorageItem('notifications', JSON.stringify(defaultNotificationsObj)); initializeStorageItem(
'notifications',
JSON.stringify(defaultNotificationsObj)
);
} }
// Retrieve and parse the notifications data as JSON // Retrieve and parse the notifications data as JSON
@ -221,7 +227,10 @@ function setNotificationAsRead(notificationID, notificationType) {
readNotifications.push(notificationID); readNotifications.push(notificationID);
notificationsObj[notificationType + 's'] = readNotifications; notificationsObj[notificationType + 's'] = readNotifications;
localStorage.setItem(notificationStorageKey, JSON.stringify(notificationsObj)); localStorage.setItem(
notificationStorageKey,
JSON.stringify(notificationsObj)
);
} }
// Export functions as a module and make the file backwards compatible for non-module environments until all remaining dependent scripts are ported to modules // Export functions as a module and make the file backwards compatible for non-module environments until all remaining dependent scripts are ported to modules

View File

@ -3,12 +3,16 @@
// If you need to pass parameters from the calling Hugo page, you can import them here like so: // If you need to pass parameters from the calling Hugo page, you can import them here like so:
// import * as pageParams from '@params'; // import * as pageParams from '@params';
// Import dependencies that we still need to load in the global scope
import $ from 'jquery';
/** Import modules that are not components. /** Import modules that are not components.
* TODO: Refactor these into single-purpose component modules. * TODO: Refactor these into single-purpose component modules.
*/ */
import * as apiLibs from './api-libs.js'; import * as apiLibs from './api-libs.js';
import * as codeControls from './code-controls.js'; import * as codeControls from './code-controls.js';
import * as contentInteractions from './content-interactions.js'; import * as contentInteractions from './content-interactions.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 './local-storage.js';
@ -29,8 +33,17 @@ import * as v3Wayfinding from './v3-wayfinding.js';
import AskAITrigger from './ask-ai-trigger.js'; import AskAITrigger from './ask-ai-trigger.js';
import CodePlaceholder from './code-placeholders.js'; import CodePlaceholder from './code-placeholders.js';
import { CustomTimeTrigger } from './custom-timestamps.js'; import { CustomTimeTrigger } from './custom-timestamps.js';
import Diagram from './components/diagram.js';
import DocSearch from './components/doc-search.js';
import FeatureCallout from './feature-callouts.js';
import FluxGroupKeysDemo from './flux-group-keys.js';
import FluxInfluxDBVersionsTrigger from './flux-influxdb-versions.js'; import FluxInfluxDBVersionsTrigger from './flux-influxdb-versions.js';
import KeyBinding from './keybindings.js';
import ListFilters from './list-filters.js';
import ProductSelector from './version-selector.js';
import ReleaseToc from './release-toc.js';
import { SearchButton } from './search-button.js'; import { SearchButton } from './search-button.js';
import SidebarSearch from './components/sidebar-search.js';
import { SidebarToggle } from './sidebar-toggle.js'; import { SidebarToggle } from './sidebar-toggle.js';
import Theme from './theme.js'; import Theme from './theme.js';
import ThemeSwitch from './theme-switch.js'; import ThemeSwitch from './theme-switch.js';
@ -49,8 +62,17 @@ const componentRegistry = {
'ask-ai-trigger': AskAITrigger, 'ask-ai-trigger': AskAITrigger,
'code-placeholder': CodePlaceholder, 'code-placeholder': CodePlaceholder,
'custom-time-trigger': CustomTimeTrigger, 'custom-time-trigger': CustomTimeTrigger,
'diagram': Diagram,
'doc-search': DocSearch,
'feature-callout': FeatureCallout,
'flux-group-keys-demo': FluxGroupKeysDemo,
'flux-influxdb-versions-trigger': FluxInfluxDBVersionsTrigger, 'flux-influxdb-versions-trigger': FluxInfluxDBVersionsTrigger,
'keybinding': KeyBinding,
'list-filters': ListFilters,
'product-selector': ProductSelector,
'release-toc': ReleaseToc,
'search-button': SearchButton, 'search-button': SearchButton,
'sidebar-search': SidebarSearch,
'sidebar-toggle': SidebarToggle, 'sidebar-toggle': SidebarToggle,
'theme': Theme, 'theme': Theme,
'theme-switch': ThemeSwitch 'theme-switch': ThemeSwitch
@ -72,6 +94,11 @@ function initGlobals() {
window.influxdatadocs.toggleModal = modals.toggleModal; window.influxdatadocs.toggleModal = modals.toggleModal;
window.influxdatadocs.componentRegistry = componentRegistry; window.influxdatadocs.componentRegistry = componentRegistry;
// Re-export jQuery to global namespace for legacy scripts
if (typeof window.jQuery === 'undefined') {
window.jQuery = window.$ = $;
}
return window.influxdatadocs; return window.influxdatadocs;
} }
@ -122,6 +149,7 @@ function initModules() {
apiLibs.initialize(); apiLibs.initialize();
codeControls.initialize(); codeControls.initialize();
contentInteractions.initialize(); contentInteractions.initialize();
datetime.initialize();
InfluxDBUrl(); InfluxDBUrl();
notifications.initialize(); notifications.initialize();
pageFeedback.initialize(); pageFeedback.initialize();

View File

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

View File

@ -1,10 +0,0 @@
// Fade content wrapper when focusing on search input
$('#algolia-search-input').focus(function() {
$('.content-wrapper').fadeTo(300, .35);
})
// Hide search dropdown when leaving search input
$('#algolia-search-input').blur(function() {
$('.content-wrapper').fadeTo(200, 1);
$('.ds-dropdown-menu').hide();
})

View File

@ -1,20 +1,21 @@
import Theme from './theme.js'; import Theme from './theme.js';
export default function ThemeSwitch({ component }) { export default function ThemeSwitch({ component }) {
if ( component == undefined) { if (component === undefined) {
component = document; component = document;
} }
component.querySelectorAll(`.theme-switch-light`).forEach((button) => {
button.addEventListener('click', function(event) { component.querySelectorAll('.theme-switch-light').forEach((button) => {
button.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
Theme({ style: 'light-theme' }); Theme({ component, style: 'light-theme' });
}); });
}); });
component.querySelectorAll(`.theme-switch-dark`).forEach((button) => { component.querySelectorAll('.theme-switch-dark').forEach((button) => {
button.addEventListener('click', function(event) { button.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
Theme({ style: 'dark-theme' }); Theme({ component, style: 'dark-theme' });
}); });
}); });
} }

View File

@ -0,0 +1,38 @@
/**
* Helper functions for debugging without source maps
* Example usage:
* In your code, you can use these functions like this:
* ```javascript
* import { debugLog, debugBreak, debugInspect } from './debug-helpers.js';
*
* const data = debugInspect(someData, 'Data');
* debugLog('Processing data', 'myFunction');
*
* function processData() {
* // Add a breakpoint that works with DevTools
* debugBreak();
*
* // Your existing code...
* }
* ```
*
* @fileoverview DEVELOPMENT USE ONLY - Functions should not be committed to production
*/
/* eslint-disable no-debugger */
/* eslint-disable-next-line */
// NOTE: These functions are detected by ESLint rules to prevent committing debug code
export function debugLog(message, context = '') {
const contextStr = context ? `[${context}]` : '';
console.log(`DEBUG${contextStr}: ${message}`);
}
export function debugBreak() {
debugger;
}
export function debugInspect(value, label = 'Inspect') {
console.log(`DEBUG[${label}]:`, value);
return value;
}

View File

@ -0,0 +1,107 @@
/**
* Manages search interactions for DocSearch integration
* Uses MutationObserver to watch for dropdown creation
*/
export default function SearchInteractions({ searchInput }) {
const contentWrapper = document.querySelector('.content-wrapper');
let observer = null;
let dropdownObserver = null;
let dropdownMenu = null;
const debug = false; // Set to true for debugging logs
// Fade content wrapper when focusing on search input
function handleFocus() {
contentWrapper.style.opacity = '0.35';
contentWrapper.style.transition = 'opacity 300ms';
}
// Hide search dropdown when leaving search input
function handleBlur(event) {
// Only process blur if not clicking within dropdown
const relatedTarget = event.relatedTarget;
if (
relatedTarget &&
(relatedTarget.closest('.algolia-autocomplete') ||
relatedTarget.closest('.ds-dropdown-menu'))
) {
return;
}
contentWrapper.style.opacity = '1';
contentWrapper.style.transition = 'opacity 200ms';
// Hide dropdown if it exists
if (dropdownMenu) {
dropdownMenu.style.display = 'none';
}
}
// Add event listeners
searchInput.addEventListener('focus', handleFocus);
searchInput.addEventListener('blur', handleBlur);
// Use MutationObserver to detect when dropdown is added to the DOM
observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
const newDropdown = document.querySelector(
'.ds-dropdown-menu:not([data-monitored])'
);
if (newDropdown) {
// Save reference to dropdown
dropdownMenu = newDropdown;
newDropdown.setAttribute('data-monitored', 'true');
// Monitor dropdown removal/display changes
dropdownObserver = new MutationObserver((dropdownMutations) => {
for (const dropdownMutation of dropdownMutations) {
if (debug) {
if (
dropdownMutation.type === 'attributes' &&
dropdownMutation.attributeName === 'style'
) {
console.log(
'Dropdown style changed:',
dropdownMenu.style.display
);
}
}
}
});
// Observe changes to dropdown attributes (like style)
dropdownObserver.observe(dropdownMenu, {
attributes: true,
attributeFilter: ['style'],
});
// Add event listeners to keep dropdown open when interacted with
dropdownMenu.addEventListener('mousedown', (e) => {
// Prevent blur on searchInput when clicking in dropdown
e.preventDefault();
});
}
}
}
});
// Start observing the document body for dropdown creation
observer.observe(document.body, {
childList: true,
subtree: true,
});
// Return cleanup function
return function cleanup() {
searchInput.removeEventListener('focus', handleFocus);
searchInput.removeEventListener('blur', handleBlur);
if (observer) {
observer.disconnect();
}
if (dropdownObserver) {
dropdownObserver.disconnect();
}
};
}

View File

@ -0,0 +1,29 @@
/**
* Platform detection utility functions
* Provides methods for detecting user's operating system
*/
/**
* Detects user's operating system using modern techniques
* Falls back to userAgent parsing when newer APIs aren't available
* @returns {string} Operating system identifier ("osx", "win", "linux", or "other")
*/
export function getPlatform() {
// Try to use modern User-Agent Client Hints API first (Chrome 89+, Edge 89+)
if (navigator.userAgentData && navigator.userAgentData.platform) {
const platform = navigator.userAgentData.platform.toLowerCase();
if (platform.includes('mac')) return 'osx';
if (platform.includes('win')) return 'win';
if (platform.includes('linux')) return 'linux';
}
// Fall back to userAgent string parsing
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.includes('mac') || userAgent.includes('iphone') || userAgent.includes('ipad')) return 'osx';
if (userAgent.includes('win')) return 'win';
if (userAgent.includes('linux') || userAgent.includes('android')) return 'linux';
return 'other';
}

View File

@ -1,19 +1,21 @@
// Select the product dropdown and dropdown items export default function ProductSelector({ component }) {
const productDropdown = document.querySelector("#product-dropdown"); // Select the product dropdown and dropdown items
const dropdownItems = document.querySelector("#dropdown-items"); const productDropdown = component.querySelector("#product-dropdown");
const dropdownItems = component.querySelector("#dropdown-items");
// Expand the menu on click // Expand the menu on click
if (productDropdown) { if (productDropdown) {
productDropdown.addEventListener("click", function() { productDropdown.addEventListener("click", function() {
productDropdown.classList.toggle("open"); productDropdown.classList.toggle("open");
dropdownItems.classList.toggle("open"); dropdownItems.classList.toggle("open");
}); });
} }
// Close the dropdown by clicking anywhere else // Close the dropdown by clicking anywhere else
document.addEventListener("click", function(e) { document.addEventListener("click", function(e) {
// Check if the click was outside of the '.product-list' container // Check if the click was outside of the '.product-list' container
if (!e.target.closest('.product-list')) { if (!e.target.closest('.product-list')) {
dropdownItems.classList.remove("open"); dropdownItems.classList.remove("open");
} }
}); });
}

View File

@ -0,0 +1,18 @@
/*
Datetime Components
----------------------------------------------
*/
.current-timestamp,
.current-date,
.current-time,
.enterprise-eol-date {
color: $current-timestamp-color;
display: inline-block;
font-family: $proxima;
white-space: nowrap;
}
.nowrap {
white-space: nowrap;
}

View File

@ -16,6 +16,10 @@
background: $article-code-bg !important; background: $article-code-bg !important;
font-size: .85em; font-size: .85em;
font-weight: $medium; font-weight: $medium;
p {
background: $article-bg !important;
}
} }
.node { .node {

View File

@ -23,6 +23,7 @@
"layouts/syntax-highlighting", "layouts/syntax-highlighting",
"layouts/algolia-search-overrides", "layouts/algolia-search-overrides",
"layouts/landing", "layouts/landing",
"layouts/datetime",
"layouts/error-page", "layouts/error-page",
"layouts/footer-widgets", "layouts/footer-widgets",
"layouts/modals", "layouts/modals",

View File

@ -203,6 +203,12 @@ $article-btn-text-hover: $g20-white;
$article-nav-icon-bg: $g5-pepper; $article-nav-icon-bg: $g5-pepper;
$article-nav-acct-bg: $g3-castle; $article-nav-acct-bg: $g3-castle;
// Datetime shortcode colors
$current-timestamp-color: $g15-platinum;
$current-date-color: $g15-platinum;
$current-time-color: $g15-platinum;
$enterprise-eol-date-color: $g15-platinum;
// Error Page Colors // Error Page Colors
$error-page-btn: $b-pool; $error-page-btn: $b-pool;
$error-page-btn-text: $g20-white; $error-page-btn-text: $g20-white;

View File

@ -203,6 +203,12 @@ $article-btn-text-hover: $g20-white !default;
$article-nav-icon-bg: $g6-smoke !default; $article-nav-icon-bg: $g6-smoke !default;
$article-nav-acct-bg: $g5-pepper !default; $article-nav-acct-bg: $g5-pepper !default;
// Datetime Colors
$current-timestamp-color: $article-text !default;
$current-date-color: $article-text !default;
$current-time-color: $article-text !default;
$enterprise-eol-date-color: $article-text !default;
// Error Page Colors // Error Page Colors
$error-page-btn: $b-pool !default; $error-page-btn: $b-pool !default;
$error-page-btn-text: $g20-white !default; $error-page-btn-text: $g20-white !default;

View File

@ -0,0 +1,40 @@
# Production overrides for CI/CD builds
baseURL: 'https://docs.influxdata.com/'
# Production environment parameters
params:
env: production
environment: production
# Enable minification for production
minify:
disableJS: false
disableCSS: false
disableHTML: false
minifyOutput: true
# Production asset processing
build:
writeStats: false
useResourceCacheWhen: "fallback"
buildOptions:
sourcemap: false
target: "es2015"
# Asset processing configuration
assetDir: "assets"
# Mount assets for production
module:
mounts:
- source: assets
target: assets
- source: node_modules
target: assets/node_modules
# Disable development server settings
server: {}
# Suppress the warning mentioned in the error
ignoreLogs:
- 'warning-goldmark-raw-html'

View File

@ -1,16 +1,95 @@
baseURL: 'http://localhost:1315/' baseURL: 'http://localhost:1315/'
languageCode: en-us
title: InfluxDB Documentation
server: # Git history information for lastMod-type functionality
port: 1315 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 # Override settings for testing
buildFuture: true buildFuture: true
# Configure what content is built in testing env # Configure what content is built in testing env
params: params:
env: testing
environment: testing environment: testing
buildTestContent: true buildTestContent: true
# Configure the server for testing
server:
port: 1315
baseURL: 'http://localhost:1315/'
watchChanges: true
disableLiveReload: false
# Keep your shared content exclusions # Keep your shared content exclusions
ignoreFiles: ignoreFiles:
- "content/shared/.*" - "content/shared/.*"
@ -18,3 +97,10 @@ ignoreFiles:
# Ignore specific warning logs # Ignore specific warning logs
ignoreLogs: ignoreLogs:
- warning-goldmark-raw-html - warning-goldmark-raw-html
# Disable minification for testing
minify:
disableJS: true
disableCSS: true
disableHTML: true
minifyOutput: false

View File

@ -1267,3 +1267,106 @@ This is small tab 2.4 content.
{{% /tab-content %}} {{% /tab-content %}}
{{< /tabs-wrapper >}} {{< /tabs-wrapper >}}
## Group key demo
Used to demonstrate Flux group keys
{{< tabs-wrapper >}}
{{% tabs "small" %}}
[Input](#)
[Output](#)
<span class="tab-view-output">Click to view output</span>
{{% /tabs %}}
{{% tab-content %}}
The following data is output from the last `filter()` and piped forward into `group()`:
> [!Note]
> `_start` and `_stop` columns have been omitted.
{{% flux/group-key "[_measurement=home, room=Kitchen, _field=hum]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Kitchen | hum | 35.9 |
| 2022-01-01T09:00:00Z | home | Kitchen | hum | 36.2 |
| 2022-01-01T10:00:00Z | home | Kitchen | hum | 36.1 |
{{% flux/group-key "[_measurement=home, room=Living Room, _field=hum]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Living Room | hum | 35.9 |
| 2022-01-01T09:00:00Z | home | Living Room | hum | 35.9 |
| 2022-01-01T10:00:00Z | home | Living Room | hum | 36 |
{{% flux/group-key "[_measurement=home, room=Kitchen, _field=temp]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Kitchen | temp | 21 |
| 2022-01-01T09:00:00Z | home | Kitchen | temp | 23 |
| 2022-01-01T10:00:00Z | home | Kitchen | temp | 22.7 |
{{% flux/group-key "[_measurement=home, room=Living Room, _field=temp]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Living Room | temp | 21.1 |
| 2022-01-01T09:00:00Z | home | Living Room | temp | 21.4 |
| 2022-01-01T10:00:00Z | home | Living Room | temp | 21.8 |
{{% /tab-content %}}
{{% tab-content %}}
When grouped by `_field`, all rows with the `temp` field will be in one table
and all the rows with the `hum` field will be in another.
`_measurement` and `room` columns no longer affect how rows are grouped.
{{% note %}}
`_start` and `_stop` columns have been omitted.
{{% /note %}}
{{% flux/group-key "[_field=hum]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Kitchen | hum | 35.9 |
| 2022-01-01T09:00:00Z | home | Kitchen | hum | 36.2 |
| 2022-01-01T10:00:00Z | home | Kitchen | hum | 36.1 |
| 2022-01-01T08:00:00Z | home | Living Room | hum | 35.9 |
| 2022-01-01T09:00:00Z | home | Living Room | hum | 35.9 |
| 2022-01-01T10:00:00Z | home | Living Room | hum | 36 |
{{% flux/group-key "[_field=temp]" true %}}
| _time | _measurement | room | _field | _value |
| :------------------- | :----------- | :---------- | :----- | :----- |
| 2022-01-01T08:00:00Z | home | Kitchen | temp | 21 |
| 2022-01-01T09:00:00Z | home | Kitchen | temp | 23 |
| 2022-01-01T10:00:00Z | home | Kitchen | temp | 22.7 |
| 2022-01-01T08:00:00Z | home | Living Room | temp | 21.1 |
| 2022-01-01T09:00:00Z | home | Living Room | temp | 21.4 |
| 2022-01-01T10:00:00Z | home | Living Room | temp | 21.8 |
{{% /tab-content %}}
{{< /tabs-wrapper >}}
## datetime/current-timestamp shortcode
### Default usage
{{< datetime/current-timestamp >}}
### Format YYYY-MM-DD HH:mm:ss
{{< datetime/current-timestamp format="YYYY-MM-DD HH:mm:ss" >}}
### Format with UTC timezone
{{< datetime/current-timestamp format="YYYY-MM-DD HH:mm:ss" timezone="UTC" >}}
### Format with America/New_York timezone
{{< datetime/current-timestamp format="YYYY-MM-DD HH:mm:ss" timezone="America/New_York" >}}

View File

@ -66,6 +66,23 @@ cloud:
- name: East US (Virginia) - name: East US (Virginia)
location: Virginia, USA location: Virginia, USA
url: https://eastus-1.azure.cloud2.influxdata.com url: https://eastus-1.azure.cloud2.influxdata.com
serverless:
product: InfluxDB Cloud
providers:
- name: Amazon Web Services
short_name: AWS
iox: true
regions:
- name: US East (Virginia)
location: Virginia, USA
url: https://us-east-1-1.aws.cloud2.influxdata.com
iox: true
- name: EU Frankfurt
location: Frankfurt, Germany
url: https://eu-central-1-1.aws.cloud2.influxdata.com
iox: true
cloud_dedicated: cloud_dedicated:
providers: providers:
- name: Default - name: Default

View File

@ -106,6 +106,33 @@ export default [
files: ['assets/js/**/*.js'], files: ['assets/js/**/*.js'],
rules: { rules: {
// Rules specific to JavaScript in Hugo assets // Rules specific to JavaScript in Hugo assets
// Prevent imports from debug-helpers.js
'no-restricted-imports': [
'error',
{
paths: [
{
name: './utils/debug-helpers.js',
message:
'Remove debugging functions before committing. Debug helpers should not be used in production code.',
},
{
name: '/utils/debug-helpers.js',
message:
'Remove debugging functions before committing. Debug helpers should not be used in production code.',
},
],
},
],
// Prevent use of debug functions in production code
'no-restricted-syntax': [
'error',
{
selector: 'CallExpression[callee.name=/^debug(Log|Break|Inspect)$/]',
message:
'Remove debugging functions before committing. Debug helpers should not be used in production code.',
},
],
}, },
}, },
{ {

View File

@ -17,7 +17,26 @@ enableRobotsTXT: true
# Custom staging params # Custom staging params
params: params:
env: staging
environment: 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 # Markdown rendering options
blackfriday: blackfriday:

View File

@ -49,21 +49,48 @@ privacy:
youtube: youtube:
disable: false disable: false
privacyEnhanced: true privacyEnhanced: true
outputFormats: outputFormats:
json: json:
mediaType: application/json mediaType: application/json
baseName: pages baseName: pages
isPlainText: true isPlainText: true
# Asset processing configuration for development
build: build:
# Ensure Hugo correctly processes JavaScript modules writeStats: false
jsConfig: useResourceCacheWhen: "fallback"
nodeEnv: "development" noJSConfigInAssets: false
# Asset processing configuration
assetDir: "assets"
module: module:
mounts: mounts:
- source: assets - source: assets
target: assets target: assets
- source: node_modules - source: node_modules
target: assets/node_modules target: assets/node_modules
# Development settings
params:
env: development
environment: development
# Configure the server for development
server:
port: 1313
baseURL: 'http://localhost:1313/'
watchChanges: true
disableLiveReload: false
# Ignore specific warning logs
ignoreLogs:
- warning-goldmark-raw-html
# Disable minification for development
minify:
disableJS: true
disableCSS: true
disableHTML: true
minifyOutput: false

18019
hugo_stats.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@
<div class="home-content"> <div class="home-content">
<div class="section search"> <div class="section search">
<div class="sidebar--search"> <div class="sidebar--search" data-component="sidebar-search">
<input class="sidebar--search-field" <input class="sidebar--search-field"
id="algolia-search-input" id="algolia-search-input"
type="text" type="text"

View File

@ -13,7 +13,7 @@
{{ $urlCalloutText := $scratch.Get "urlCalloutText" }} {{ $urlCalloutText := $scratch.Get "urlCalloutText" }}
<!-- {{ if or $isOSS $isCloud $isHome }} <!-- {{ if or $isOSS $isCloud $isHome }}
<div class="feature-callout start-position" id="callout-url-selector"> <div class="feature-callout start-position" id="callout-url-selector" data-component="feature-callout">
<p>{{ $urlCalloutText }} <a href="#" class="close"><span class="icon-remove"></span></a></p> <p>{{ $urlCalloutText }} <a href="#" class="close"><span class="icon-remove"></span></a></p>
</div> </div>
{{ end }} --> {{ end }} -->

View File

@ -1,18 +1,3 @@
{{ $jquery := resources.Get "js/jquery-3.5.0.min.js" }}
{{ $versionSelector := resources.Get "js/version-selector.js" }}
{{ $searchInteractions := resources.Get "js/search-interactions.js" }}
{{ $listFilters := resources.Get "js/list-filters.js" }}
{{ $featureCallouts := resources.Get "js/feature-callouts.js" }}
{{ $keybindings := resources.Get "js/keybindings.js" }}
{{ $fluxGroupKeys := resources.Get "js/flux-group-keys.js" }}
{{ $dateTime := resources.Get "js/datetime.js" }}
{{ $homepageInteractions := resources.Get "js/home-interactions.js" }}
{{ $releaseTOC := resources.Get "/js/release-toc.js" }}
{{ $footerjs := slice $jquery $versionSelector $searchInteractions $listFilters $featureCallouts $keybindings $homepageInteractions | resources.Concat "js/footer.bundle.js" | resources.Fingerprint }}
{{ $fluxGroupKeyjs := $fluxGroupKeys | resources.Fingerprint }}
{{ $dateTimejs := $dateTime | resources.Fingerprint }}
{{ $releaseTOCjs := $releaseTOC | resources.Fingerprint }}
<!-- Load cloudUrls array --> <!-- Load cloudUrls array -->
<script type="text/javascript"> <script type="text/javascript">
cloudUrls = [ cloudUrls = [
@ -21,37 +6,3 @@
{{ end -}} {{ end -}}
] ]
</script> </script>
{{ if .Page.HasShortcode "diagram" }}
<!-- Load mermaid.js for diagrams -->
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true,
themeVariables: {
fontFamily: "Proxima Nova",
fontSize: '18px',
}
})
</script>
{{ end }}
<!-- Load group key demo JS if when the group key demo shortcode is present -->
{{ if .Page.HasShortcode "flux/group-key-demo" }}
<script type="text/javascript" src="{{ $fluxGroupKeyjs.RelPermalink }}"></script>
{{ end }}
<!-- Load datetime js if when datetime shortcodes are present -->
{{ if or (.Page.HasShortcode "datetime/current-time") (.Page.HasShortcode "datetime/current-timestamp")
(.Page.HasShortcode "datetime/current-date") (.Page.HasShortcode "datetime/enterprise-eol-date") }}
<script type="text/javascript" src="{{ $dateTimejs.RelPermalink }}"></script>
{{ end }}
<!-- Load code release-toc js when release-toc shortcode is present -->
{{ if .Page.HasShortcode "release-toc" }}
<script type="text/javascript" src="{{ $releaseTOCjs.RelPermalink }}"></script>
{{ end }}
<!-- Load footer.js -->
<script type="text/javascript" src="{{ $footerjs.RelPermalink }}"></script>

View File

@ -7,84 +7,15 @@
{{ $includeFlux := and (in $fluxSupported $product) (in $influxdbFluxSupport $version) }} {{ $includeFlux := and (in $fluxSupported $product) (in $influxdbFluxSupport $version) }}
{{ $includeResources := not (in (slice "cloud-serverless" "cloud-dedicated" "clustered" "core" "enterprise" "explorer") $version) }} {{ $includeResources := not (in (slice "cloud-serverless" "cloud-dedicated" "clustered" "core" "enterprise" "explorer") $version) }}
<script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script> <!-- DocSearch Component Container -->
<script> <div
var multiVersion = ['influxdb'] data-component="doc-search"
docsearch({ data-api-key="501434b53a46a92a7931aecc7c9672e2"
apiKey: '501434b53a46a92a7931aecc7c9672e2', data-app-id="WHM9UWMP6M"
appId: 'WHM9UWMP6M', data-index-name="influxdata"
indexName: 'influxdata', data-input-selector="#algolia-search-input"
inputSelector: '#algolia-search-input', data-search-tag="{{ $product }}-{{ $version }}"
// Set debug to true if you want to inspect the dropdown data-include-flux="{{ $includeFlux }}"
debug: true, data-include-resources="{{ $includeResources }}"
transformData: function (hits) { data-debug="{{ if hugo.IsProduction }}false{{ else }}true{{ end }}"
function fmtVersion (version, productKey) { ></div>
if (version == null) {
return '';
} else if (version === 'cloud') {
return 'Cloud (TSM)';
} else if (version === 'core') {
return 'Core';
} else if (version === 'enterprise') {
return 'Enterprise';
} else if (version === 'explorer') {
return 'Explorer';
} else if (version === 'cloud-serverless') {
return 'Cloud Serverless';
} else if (version === 'cloud-dedicated') {
return 'Cloud Dedicated';
} else if (version === 'clustered') {
return 'Clustered';
} else if (multiVersion.includes(productKey)) {
return version;
} else {
return '';
}
};
productNames = {
influxdb: 'InfluxDB',
influxdb3: 'InfluxDB 3',
enterprise_influxdb: 'InfluxDB Enterprise',
flux: 'Flux',
telegraf: 'Telegraf',
chronograf: 'Chronograf',
kapacitor: 'Kapacitor',
platform: 'InfluxData Platform',
resources: 'Additional Resources',
};
hits.map(hit => {
pathData = new URL(hit.url).pathname.split('/').filter(n => n);
product = productNames[pathData[0]];
version = fmtVersion(pathData[1], pathData[0]);
hit.product = product;
hit.version = version;
hit.hierarchy.lvl0 =
hit.hierarchy.lvl0 +
` <span class=\"search-product-version\">${product} ${version}</span>`;
hit._highlightResult.hierarchy.lvl0.value =
hit._highlightResult.hierarchy.lvl0.value +
` <span class=\"search-product-version\">${product} ${version}</span>`;
});
return hits;
},
algoliaOptions: {
hitsPerPage: 10,
'facetFilters': [
{{ if or (eq $product "platform") (eq $product "resources") (le (len $productPathData) 1) }}
'latest:true'
{{ else if $includeFlux }}
['searchTag: {{ $product }}-{{ $version }}', 'flux:true', 'resources:{{ $includeResources }}']
{{ else }}
['searchTag: {{ $product }}-{{ $version }}', 'resources:{{ $includeResources }}']
{{ end }}
]
},
autocompleteOptions: {
templates: {
header: '<div class="search-all-content"><a href="https:\/\/support.influxdata.com" target="_blank">Search all InfluxData content <span class="icon-arrow-up-right"></span></a>',
empty: '<div class="search-no-results"><p>Not finding what you\'re looking for?</p> <a href="https:\/\/support.influxdata.com" target="_blank">Search all InfluxData content <span class="icon-arrow-up-right"></span></a></div>'
}
}
});
</script>

View File

@ -5,28 +5,104 @@
<!-- Get site data --> <!-- Get site data -->
<!-- Load cloudUrls array --> <!-- Load cloudUrls array -->
{{ $cloudUrls := slice }} {{ $cloudUrls := slice }}
{{- range.Site.Data.influxdb_urls.cloud.providers }} {{- range .Site.Data.influxdb_urls.cloud.providers }}
{{- range.regions }} {{- range .regions }}
{{ $cloudUrls = $cloudUrls | append "{{ safeHTML .url }}" }} {{ $cloudUrls = $cloudUrls | append (safeHTML .url) }}
{{ end -}} {{ end -}}
{{ end -}} {{ end -}}
{{ $products := .Site.Data.products }} {{ $products := .Site.Data.products }}
{{ $influxdb_urls := .Site.Data.influxdb_urls }} {{ $influxdb_urls := .Site.Data.influxdb_urls }}
<!-- Build main.js -->
{{ with resources.Get "js/index.js" }} {{ $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) }}
{{ if $isDevelopmentOrTesting }}
{{/* Load individual JS files for debugging with ESM format */}}
{{ $sharedParams := dict "product" $product "currentVersion" $currentVersion "isServer" hugo.IsServer "products" $products "influxdb_urls" $influxdb_urls "cloudUrls" $cloudUrls }}
{{/* 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 }}
{{/* 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>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ else }}
{{/* Production environment: Use IIFE for better compatibility */}}
{{ $mainJS := resources.Get "js/main.js" }}
{{ if $mainJS }}
{{ $sharedParams := dict "product" $product "currentVersion" $currentVersion "isServer" hugo.IsServer "products" $products "influxdb_urls" $influxdb_urls "cloudUrls" $cloudUrls }}
{{ $opts := dict {{ $opts := dict
"minify" hugo.IsProduction "minify" hugo.IsProduction
"sourceMap" (cond hugo.IsProduction "" "external") "sourceMap" ""
"targetPath" "js/main.js" "targetPath" "js/main.js"
"params" (dict "product" $product "currentVersion" $currentVersion "isServer" hugo.IsServer "products" $products "influxdb_urls" $influxdb_urls "cloudUrls" $cloudUrls) "params" $sharedParams
"format" "iife"
"target" "es2019"
"splitting" false
"external" (slice "*")
"define" (dict
"process.env.NODE_ENV" "\"production\""
)
}} }}
{{ with . | js.Build $opts }}
{{ $processed := "" }}
{{ with $mainJS }}
{{ $processed = . | js.Build $opts }}
{{ end }}
{{ if $processed }}
{{ if hugo.IsProduction }} {{ if hugo.IsProduction }}
{{ with . | fingerprint }} {{ $fingerprinted := $processed | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script> {{ if $fingerprinted }}
<script defer src="{{ $fingerprinted.RelPermalink }}" integrity="{{ $fingerprinted.Data.Integrity }}" crossorigin="anonymous"></script>
{{ end }} {{ end }}
{{ else }} {{ else }}
<script src="{{ .RelPermalink }}"></script> <script defer src="{{ $processed.RelPermalink }}"></script>
{{ end }}
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ end }} {{ end }}

View File

@ -49,7 +49,7 @@
<aside class="sidebar"> <aside class="sidebar">
{{ partial "sidebar/sidebar-toggle.html" (dict "state" "Close") }} {{ partial "sidebar/sidebar-toggle.html" (dict "state" "Close") }}
<div class="search-and-nav-toggle"> <div class="search-and-nav-toggle">
<div class="sidebar--search"> <div class="sidebar--search" data-component="sidebar-search">
<input class="sidebar--search-field" <input class="sidebar--search-field"
id="algolia-search-input" id="algolia-search-input"
type="text" type="text"

View File

@ -43,7 +43,7 @@ Identify products by their product path. Dictionary schema:
{{ $templateDefaults := dict "context" . "productInfo" $productInfo "altLinks" $altLinks "pageRoot" $pageRoot "useRootProductLink" $useRootProductLink }} {{ $templateDefaults := dict "context" . "productInfo" $productInfo "altLinks" $altLinks "pageRoot" $pageRoot "useRootProductLink" $useRootProductLink }}
<div class="product-list"> <div class="product-list" data-component="product-selector">
<div id="product-dropdown"> <div id="product-dropdown">
<p class="selected">{{ index (index $productInfo $pageRoot) 0 | default "Select product" }}</p> <p class="selected">{{ index (index $productInfo $pageRoot) 0 | default "Select product" }}</p>
</div> </div>

View File

@ -1,3 +1,3 @@
<div class="mermaid"> <div class="mermaid" data-component="diagram">
{{.Inner}} {{.Inner}}
</div> </div>

View File

@ -1,4 +1,4 @@
<div id="flux-group-keys-demo"> <div id="flux-group-keys-demo" data-component="flux-group-keys-demo">
<div id="group-by-columns"> <div id="group-by-columns">
<ul class="column-list"> <ul class="column-list">
<li> <li>

View File

@ -5,4 +5,4 @@
{{- $mac := .Get "mac" | default $default -}} {{- $mac := .Get "mac" | default $default -}}
{{- $win := .Get "win" | default $default -}} {{- $win := .Get "win" | default $default -}}
{{- $linux := .Get "linux" | default $default -}} {{- $linux := .Get "linux" | default $default -}}
<span class="keybinding" data-osx="{{ $mac }}" data-win="{{ $win }}" data-linux="{{ $linux }}"><code>{{ $default }}</code></span> <span class="keybinding" data-osx="{{ $mac }}" data-win="{{ $win }}" data-linux="{{ $linux }}" data-component="keybinding"><code>{{ $default }}</code></span>

View File

@ -1,6 +1,6 @@
{{ $source := .Get 0 | default "telegraf"}} {{ $source := .Get 0 | default "telegraf"}}
<div id="list-filters"> <div id="list-filters" data-component="list-filters">
{{ range ( index .Site.Data.list_filters $source) }} {{ range ( index .Site.Data.list_filters $source) }}
{{ $numValues := len .values }} {{ $numValues := len .values }}

View File

@ -2,7 +2,7 @@
{{- $currentVersion := index $productPathData 1 -}} {{- $currentVersion := index $productPathData 1 -}}
{{- $show := .Get "show" | default 12 -}} {{- $show := .Get "show" | default 12 -}}
<div id="release-toc" class="{{ $currentVersion }}"> <div id="release-toc" class="{{ $currentVersion }}" data-component="release-toc">
<ul id="release-list" style="height: calc({{ $show }} * 1.885rem);" show="{{ $show }}"> <ul id="release-list" style="height: calc({{ $show }} * 1.885rem);" show="{{ $show }}">
<!-- PLACEHOLDER FOR JS-GENERATED LIST ITEMS --> <!-- PLACEHOLDER FOR JS-GENERATED LIST ITEMS -->
</ul> </ul>

View File

@ -66,8 +66,6 @@
"test:links:api-docs": "node cypress/support/run-e2e-specs.js --spec \"cypress/e2e/content/article-links.cy.js\" /influxdb3/core/api/,/influxdb3/enterprise/api/,/influxdb3/cloud-dedicated/api/,/influxdb3/cloud-dedicated/api/v1/,/influxdb/cloud-dedicated/api/v1/,/influxdb/cloud-dedicated/api/management/,/influxdb3/cloud-dedicated/api/management/", "test:links:api-docs": "node cypress/support/run-e2e-specs.js --spec \"cypress/e2e/content/article-links.cy.js\" /influxdb3/core/api/,/influxdb3/enterprise/api/,/influxdb3/cloud-dedicated/api/,/influxdb3/cloud-dedicated/api/v1/,/influxdb/cloud-dedicated/api/v1/,/influxdb/cloud-dedicated/api/management/,/influxdb3/cloud-dedicated/api/management/",
"test:shortcode-examples": "node cypress/support/run-e2e-specs.js --spec \"cypress/e2e/content/article-links.cy.js\" content/example.md" "test:shortcode-examples": "node cypress/support/run-e2e-specs.js --spec \"cypress/e2e/content/article-links.cy.js\" content/example.md"
}, },
"main": "assets/js/main.js",
"module": "assets/js/main.js",
"type": "module", "type": "module",
"browserslist": [ "browserslist": [
"last 2 versions", "last 2 versions",