Skip to content

Commit 3289052

Browse files
committed
feat(ask-ai): add help in Ask AI widget placeholder
- InfluxDB placeholder recommends specifying product and version - Fix page-context.js to use products.influxdb_cloud instead of products.cloud - Add UI tests verifying version-specific naming in Kapa widget script tags
1 parent 2d3f0e4 commit 3289052

File tree

27 files changed

+2110
-1068
lines changed

27 files changed

+2110
-1068
lines changed

.github/instructions/layouts.instructions.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ applyTo: "layouts/**/*.html"
1111

1212
When creating or modifying Hugo layouts and shortcodes:
1313

14-
1. Use Hugo template syntax and functions
15-
2. Follow existing patterns in `/layouts/shortcodes/`
16-
3. Test in [content/example.md](../../content/example.md)
17-
4. Document new shortcodes in [DOCS-SHORTCODES.md](../../DOCS-SHORTCODES.md)
14+
1. Use test-driven development using `/cypress/`
15+
2. Use Hugo template syntax and functions
16+
3. Follow existing patterns in `/layouts/shortcodes/`
17+
4. Test in [content/example.md](../../content/example.md)
18+
5. Document new shortcodes in [DOCS-SHORTCODES.md](../../DOCS-SHORTCODES.md)
1819

1920
## Shortcode Pattern
2021

@@ -30,9 +31,32 @@ When creating or modifying Hugo layouts and shortcodes:
3031

3132
## Testing
3233

33-
Add usage examples to `content/example.md` to verify:
34+
**IMPORTANT:** Use test-driven development with Cypress.
35+
36+
Add shortcode usage examples to `content/example.md` to verify:
37+
3438
- Rendering in browser
3539
- Hugo build succeeds
3640
- No console errors
41+
- JavaScript functionality works as expected (check browser console for errors)
42+
- Interactive elements behave correctly (click links, buttons, etc.)
43+
44+
### TDD Workflow
45+
46+
1. Add Cypress tests (high-level to start).
47+
2. Run tests and make sure they fail.
48+
3. Implement code changes
49+
4. Run tests and make sure they pass.
50+
5. Add and refine tests.
51+
6. Repeat.
52+
53+
### Manual Testing Workflow
54+
55+
1. Make changes to shortcode/layout files
56+
2. Wait for Hugo to rebuild (check terminal output)
57+
3. Get the server URL from the log
58+
4. Open browser DevTools console (F12)
59+
5. Test the functionality and check for JavaScript errors
60+
6. Verify the feature works as intended before marking complete
3761

3862
See [DOCS-SHORTCODES.md](../../DOCS-SHORTCODES.md) for complete shortcode documentation.

assets/js/ask-ai-trigger.js

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,117 @@
11
import AskAI from './ask-ai.js';
22

3+
/**
4+
* Global state for Ask AI initialization
5+
*/
6+
const state = {
7+
kapaInitialized: false,
8+
linksListenerInitialized: false,
9+
};
10+
11+
/**
12+
* Initialize the Kapa widget
13+
*/
14+
function initializeKapa() {
15+
if (!state.kapaInitialized) {
16+
AskAI();
17+
state.kapaInitialized = true;
18+
19+
// Store in global namespace for debugging
20+
window.influxdatadocs = window.influxdatadocs || {};
21+
window.influxdatadocs.kapaInitialized = true;
22+
}
23+
}
24+
25+
/**
26+
* Show the trigger button by removing inline display: none style
27+
* @param {HTMLElement} element - The trigger button element
28+
*/
329
function showTrigger(element) {
4-
// Remove the inline display: none style
5-
element.removeAttribute('style');
30+
if (element) {
31+
element.removeAttribute('style');
32+
}
633
}
734

35+
/**
36+
* Initialize Ask AI trigger button component
37+
* @param {Object} options - Component options
38+
* @param {HTMLElement} options.component - The trigger button element
39+
*/
840
export default function AskAITrigger({ component }) {
941
const kapaContainer = document.querySelector('#kapa-widget-container');
42+
1043
if (!component && !kapaContainer) {
1144
return;
1245
}
46+
1347
if (!kapaContainer) {
1448
// Initialize the chat widget
1549
AskAI({ onChatLoad: () => showTrigger(component) });
50+
state.kapaInitialized = true;
51+
window.influxdatadocs = window.influxdatadocs || {};
52+
window.influxdatadocs.kapaInitialized = true;
1653
} else {
1754
showTrigger(component);
1855
}
19-
}
56+
}
57+
58+
/**
59+
* Handle ask-ai-link clicks globally
60+
* This ensures ask-ai-link shortcodes work even without the trigger button
61+
*/
62+
function handleAskAILinks() {
63+
if (state.linksListenerInitialized) {
64+
return;
65+
}
66+
67+
state.linksListenerInitialized = true;
68+
69+
// Store in global namespace for debugging
70+
window.influxdatadocs = window.influxdatadocs || {};
71+
window.influxdatadocs.askAILinksInitialized = true;
72+
73+
// Listen for clicks on ask-ai-link elements
74+
document.addEventListener(
75+
'click',
76+
(event) => {
77+
const link = event.target.closest('.ask-ai-open');
78+
if (!link) return;
79+
80+
const query = link.getAttribute('data-query');
81+
82+
// Initialize Kapa if not already done
83+
if (!state.kapaInitialized) {
84+
initializeKapa();
85+
86+
// Wait for Kapa to be ready, then open with query
87+
if (query && window.Kapa?.open) {
88+
// Give Kapa a moment to initialize
89+
setTimeout(() => {
90+
if (window.Kapa?.open) {
91+
window.Kapa.open({
92+
mode: 'ai',
93+
query: query,
94+
});
95+
}
96+
}, 100);
97+
}
98+
} else {
99+
// Kapa is already initialized - open with query if provided
100+
if (query && window.Kapa?.open) {
101+
window.Kapa.open({
102+
mode: 'ai',
103+
query: query,
104+
});
105+
}
106+
}
107+
},
108+
{ passive: true }
109+
);
110+
}
111+
112+
// Initialize ask-ai-link handling when DOM is ready
113+
if (document.readyState === 'loading') {
114+
document.addEventListener('DOMContentLoaded', handleAskAILinks);
115+
} else {
116+
handleAskAILinks();
117+
}

assets/js/ask-ai.ts

Lines changed: 33 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ type KapaFunction = (command: string, options?: unknown) => void;
4747

4848
interface ChatAttributes extends Record<string, string | undefined> {
4949
modalExampleQuestions?: string;
50+
modalAskAiInputPlaceholder?: string;
51+
modalDisclaimer?: string;
5052
sourceGroupIdsInclude?: string;
5153
}
5254

@@ -96,6 +98,7 @@ function initializeChat({
9698

9799
const optionalAttributes = {
98100
modalDisclaimer:
101+
chatAttributes.modalDisclaimer ||
99102
'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/).',
100103
modalExampleQuestions:
101104
'Use Python to write data to InfluxDB 3,How do I query using SQL?,How do I use MQTT with Telegraf?',
@@ -175,27 +178,7 @@ function getProductExampleQuestions(): string {
175178
return '';
176179
}
177180

178-
// Only add version hints for InfluxDB database products
179-
// Other tools like Explorer, Telegraf, Chronograf, Kapacitor,
180-
// Flux don't need version hints
181-
const productNamespace = productData?.product?.namespace;
182-
const shouldAddVersionHint =
183-
productNamespace === 'influxdb' ||
184-
productNamespace === 'influxdb3' ||
185-
productNamespace === 'enterprise_influxdb';
186-
187-
if (!shouldAddVersionHint) {
188-
return questions.join(',');
189-
}
190-
191-
const productName = productData?.product?.name || 'InfluxDB';
192-
193-
// Append version hint to each question
194-
const questionsWithHint = questions.map((question) => {
195-
return `${question} My version: ${productName}`;
196-
});
197-
198-
return questionsWithHint.join(',');
181+
return questions.join(',');
199182
}
200183

201184
function getProductSourceGroupIds(): string {
@@ -205,60 +188,37 @@ function getProductSourceGroupIds(): string {
205188
return sourceGroupIds || '';
206189
}
207190

208-
function getVersionContext(): string {
209-
// Only add version context for InfluxDB database products
210-
const productNamespace = productData?.product?.namespace;
211-
const shouldAddVersionContext =
212-
productNamespace === 'influxdb' ||
213-
productNamespace === 'influxdb3' ||
214-
productNamespace === 'enterprise_influxdb';
215-
216-
if (!shouldAddVersionContext) {
217-
return '';
218-
}
219-
220-
const productName = productData?.product?.name || 'InfluxDB';
191+
function getProductInputPlaceholder(): string {
192+
const placeholder = getVersionSpecificConfig('ai_input_placeholder') as
193+
| string
194+
| undefined;
221195

222-
return `My version: ${productName}`;
196+
// Return product-specific placeholder or default
197+
return (
198+
placeholder ||
199+
'Ask questions about InfluxDB. Specify your product and version ' +
200+
'for better results'
201+
);
223202
}
224203

225-
function setupVersionPrefill(): void {
226-
const versionContext = getVersionContext();
227-
if (!versionContext) {
228-
return;
229-
}
230-
231-
// Wait for Kapa to be available
232-
const checkKapa = (): void => {
233-
if (!window.Kapa || typeof window.Kapa !== 'function') {
234-
setTimeout(checkKapa, 100);
235-
return;
236-
}
204+
function getProductDisclaimer(): string {
205+
// Build version-specific note if version is available
206+
const versionNote =
207+
version && version !== 'n/a' && productData?.product?.name
208+
? `**Viewing documentation for ${productData.product.name}**\n\n`
209+
: '';
237210

238-
// Find the Ask AI button and add click handler to prefill version
239-
const askAIButton = document.querySelector('.ask-ai-open');
240-
if (askAIButton) {
241-
askAIButton.addEventListener(
242-
'click',
243-
(e) => {
244-
e.preventDefault();
245-
e.stopPropagation();
246-
window.Kapa('open', { query: versionContext });
247-
},
248-
true
249-
); // Use capture phase to run before Kapa's handler
250-
}
211+
// Check for product-specific custom disclaimer note
212+
const customNote = getVersionSpecificConfig('ai_disclaimer_note') as
213+
| string
214+
| undefined;
215+
const noteContent = customNote ? `${customNote}\n\n` : '';
251216

252-
// Listen for conversation reset to re-fill version context
253-
window.Kapa('onAskAIConversationReset', () => {
254-
// Small delay to ensure the reset is complete
255-
setTimeout(() => {
256-
window.Kapa('open', { query: versionContext });
257-
}, 100);
258-
});
259-
};
217+
// Base disclaimer with privacy policy link
218+
const baseDisclaimer =
219+
'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/).';
260220

261-
checkKapa();
221+
return `${versionNote}${noteContent}${baseDisclaimer}`;
262222
}
263223

264224
/**
@@ -277,16 +237,18 @@ export default function AskAI({
277237
...chatParams
278238
}: AskAIParams): void {
279239
const modalExampleQuestions = getProductExampleQuestions();
240+
const modalAskAiInputPlaceholder = getProductInputPlaceholder();
241+
const modalDisclaimer = getProductDisclaimer();
280242
const sourceGroupIds = getProductSourceGroupIds();
281243
const chatAttributes: ChatAttributes = {
282244
...(modalExampleQuestions && { modalExampleQuestions }),
245+
...(modalAskAiInputPlaceholder && { modalAskAiInputPlaceholder }),
246+
...(modalDisclaimer && { modalDisclaimer }),
283247
...(sourceGroupIds && { sourceGroupIdsInclude: sourceGroupIds }),
284248
...(chatParams as Record<string, string>),
285249
};
286250

287251
const wrappedOnChatLoad = (): void => {
288-
// Setup version pre-fill after widget loads
289-
setupVersionPrefill();
290252
// Call original onChatLoad if provided
291253
if (onChatLoad) {
292254
onChatLoad();

assets/js/page-context.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function getCurrentProductData() {
99
const mappings = [
1010
{
1111
pattern: /\/influxdb\/cloud\//,
12-
product: products.cloud,
12+
product: products.influxdb_cloud,
1313
urls: influxdbUrls.influxdb_cloud,
1414
},
1515
{
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: Identify InfluxDB Enterprise v1 version
3+
description: Learn how to identify your InfluxDB Enterprise v1 version using command-line tools, HTTP endpoints, and other methods.
4+
menu:
5+
enterprise_influxdb_v1:
6+
name: Identify version
7+
parent: Administration
8+
weight: 10
9+
source: /shared/identify-version.md
10+
related:
11+
- /enterprise_influxdb/v1/install-and-deploy/
12+
alt_links:
13+
v1: /influxdb/v1/administration/identify-version/
14+
v2: /influxdb/v2/admin/identify-version/
15+
cloud: /influxdb/cloud/admin/identify-version/
16+
cloud-serverless: /influxdb3/cloud-serverless/admin/identify-version/
17+
cloud-dedicated: /influxdb3/cloud-dedicated/admin/identify-version/
18+
clustered: /influxdb3/clustered/admin/identify-version/
19+
core: /influxdb3/core/admin/identify-version/
20+
enterprise: /influxdb3/enterprise/admin/identify-version/
21+
---

0 commit comments

Comments
 (0)