Skip to content

feat: implement comprehensive tooltip and help system (#165)#269

Open
CodeMayor wants to merge 1 commit into
nexoraorg:mainfrom
CodeMayor:feat/tooltip-help-system
Open

feat: implement comprehensive tooltip and help system (#165)#269
CodeMayor wants to merge 1 commit into
nexoraorg:mainfrom
CodeMayor:feat/tooltip-help-system

Conversation

@CodeMayor

@CodeMayor CodeMayor commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Overview

Implements a complete tooltip and help system for the ChenaiKit frontend dashboard.

Changes

  • ✅ Tooltip component with 5 variants (simple text, rich content, icon, follow-cursor, persistent)
  • ✅ HelpButton integrated into dashboard header
  • ✅ HelpPanel drawer with searchable help topics and video support
  • ✅ FeatureTour with step-by-step guided onboarding
  • ✅ Centralized help content management (5 topics + FAQ)
  • ✅ Tour target IDs on dashboard elements for highlighting
  • ✅ Full Material-UI integration
  • ✅ Accessibility (ARIA labels, semantic HTML)

Acceptance Criteria Met

  • ✅ Tooltips display correctly
  • ✅ Help buttons are present
  • ✅ Help content is comprehensive
  • ✅ Feature tour works smoothly
  • ✅ Search in help works
  • ✅ Help is context-sensitive
  • ✅ Tour can be skipped
  • ✅ Content is maintainable

Test Results

  • ✅ 610 tests passed
  • ✅ Build successful
  • ✅ No TypeScript errors

Closes #165

Summary by CodeRabbit

  • New Features

    • Added an in-app Help Center with searchable topics, suggestions, FAQs, and optional video guidance.
    • Added a guided product tour with step-by-step navigation and skip/finish controls.
    • Added contextual help buttons, tooltips, and improved dashboard assistance.
    • Added dedicated login, signup, password recovery, terms, and privacy pages.
    • Added Profile and Settings navigation options.
  • Improvements

    • Enhanced account, notification, security, session, and API-key settings experiences.
    • Refined dashboard navigation, layout, and loading behavior.

- Add Tooltip component with 5 variants
- Add HelpButton, HelpPanel, FeatureTour
- Add help content management
- Wire help system into dashboard
- All acceptance criteria met
- 610 tests passed
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The frontend adds reusable tooltips, searchable help content, a help drawer, and a step-based feature tour. The dashboard integrates these controls, while routing and settings handling are expanded with additional pages, error boundaries, security data, and API-key response validation.

Changes

Help system and application updates

Layer / File(s) Summary
Help contracts and tooltip primitives
frontend/package.json, frontend/src/help/content.tsx, frontend/src/components/Tooltip.tsx, frontend/src/components/HelpButton.tsx, frontend/src/components/index.ts
Adds structured help topics, configurable tooltip behavior, a help button, component exports, and the MUI icons dependency update.
Help panel and feature tour
frontend/src/components/HelpPanel.tsx, frontend/src/components/FeatureTour.tsx
Adds searchable contextual help in a drawer and a step-based tour with progress, skip, and finish actions.
Dashboard help integration
frontend/src/App.tsx
Connects help and tour state to the dashboard, adds navigation controls, updates dashboard presentation, and renders help components alongside lazy-loaded content.
Routing and settings integration
frontend/src/App.tsx
Adds auth and policy routes, updates error-boundary metadata, and expands settings request handling, security data, and API-key extraction.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DashboardShell
  participant HelpButton
  participant HelpPanel
  participant FeatureTour
  DashboardShell->>HelpButton: render help trigger
  HelpButton->>HelpPanel: open help panel
  HelpPanel->>HelpPanel: filter helpTopics by query and context
  HelpPanel->>FeatureTour: start product tour
  FeatureTour->>DashboardShell: close tour
Loading

Possibly related PRs

Suggested reviewers: jaynomyaro

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Help-system basics are present, but the tour lacks evidenced progress/highlight features and the docs don't show screenshots, diagrams, or code examples. Add the missing tour UX and richer help content, or document that screenshots/diagrams/code examples are intentionally out of scope.
Out of Scope Changes check ⚠️ Warning App.tsx adds login/signup/terms/privacy routes and expanded settings logic that are unrelated to the tooltip/help-system scope. Remove the unrelated routing/settings changes or split them into a separate PR focused on the help and tooltip system.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: implementing a tooltip and help system for the frontend.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/App.tsx (1)

512-533: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Profile page shows a hardcoded fake identity instead of the signed-in user.

Unlike settingsUser (lines 423-439), which correctly derives from authUser, the /profile route always passes { id: 1, email: "user@example.com", name: "Demo User", role: "user" }. A real signed-in user will see demo identity data on their own profile page.

🪪 Suggested fix
                   <Profile
                     user={{
-                      id: 1,
-                      email: "user@example.com",
-                      name: "Demo User",
-                      role: "user",
+                      id: settingsUser.id,
+                      email: settingsUser.email,
+                      name: settingsUser.name,
+                      role: settingsUser.role,
                     }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.tsx` around lines 512 - 533, Update the Profile element in
the /profile route to pass the authenticated user data derived from authUser,
following the existing settingsUser mapping instead of the hardcoded demo
identity. Preserve the Profile component’s expected user shape and retain the
surrounding route behavior.
🧹 Nitpick comments (1)
frontend/src/App.tsx (1)

555-575: 🔒 Security & Privacy | 🔵 Trivial

Security settings show static, fabricated session/login data for every user.

sessions and loginHistory are hardcoded literals ("Chrome on macOS", "San Francisco, CA", etc.) rendered identically regardless of the actual signed-in user. Displaying fabricated security telemetry on an account security page risks giving users a false sense of their real session/login state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.tsx` around lines 555 - 575, Replace the hardcoded
securitySettings sessions and loginHistory literals in App with data sourced
from the authenticated user’s actual security/session telemetry, or render an
empty/loading state when that data is unavailable; do not display fabricated
device, location, activity, or login status values. Preserve the existing
twoFactorEnabled behavior and security settings structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/App.tsx`:
- Around line 660-677: Defer success toasts until API key validation succeeds in
both handlers: in frontend/src/App.tsx lines 660-677, remove the success message
from runSettingsRequest in onCreateApiKey and call toast.success after
extractApiKey confirms a key; apply the same change in lines 688-704 for
onRegenerateApiKey, using the regenerated message. Keep the existing error
thrown when no usable key is returned.

In `@frontend/src/components/FeatureTour.tsx`:
- Around line 1-84: Update FeatureTour to spotlight the dashboard elements
described by each tour step instead of rendering only a centered Dialog:
associate the relevant steps with the existing tour-header,
tour-dashboard-range, and tour-tabs target ids, locate the active target, scroll
it into view, and render a visual highlight/overlay anchored to it while the
step is active. Preserve the current navigation, skip, finish, and dialog
content behavior, and handle steps without a target such as the welcome and
completion screens.
- Around line 48-61: Reset currentStep to the initial step whenever the open
prop transitions to true by adding a useEffect in FeatureTour and importing it
from React. Preserve the existing handleNext and handleSkip behavior while
ensuring every reopening starts at the first tour step.

In `@frontend/src/components/HelpPanel.tsx`:
- Around line 28-33: Update the suggestion chip handling around suggestionLabels
and filterTopics so chips use searchable topic keywords or contexts rather than
literal labels that do not occur in helpTopics. Map each chip to a query
matching its intended topics, while preserving the displayed labels and ensuring
clicking every chip produces relevant results instead of an empty list.

In `@frontend/src/components/Tooltip.tsx`:
- Around line 47-79: Update the StyledTooltip listener configuration in Tooltip
so focus and touch listeners remain enabled for the default non-persistent
tooltips; do not set disableFocusListener or disableTouchListener based on
!persistent. Preserve the existing persistent open-state and delay behavior.

In `@frontend/src/help/content.tsx`:
- Line 36: Replace the placeholder videoUrl for the “Getting Started” help topic
with the correct product tutorial video URL, ensuring HelpPanel embeds real
instructional content instead of the rickroll video.

---

Outside diff comments:
In `@frontend/src/App.tsx`:
- Around line 512-533: Update the Profile element in the /profile route to pass
the authenticated user data derived from authUser, following the existing
settingsUser mapping instead of the hardcoded demo identity. Preserve the
Profile component’s expected user shape and retain the surrounding route
behavior.

---

Nitpick comments:
In `@frontend/src/App.tsx`:
- Around line 555-575: Replace the hardcoded securitySettings sessions and
loginHistory literals in App with data sourced from the authenticated user’s
actual security/session telemetry, or render an empty/loading state when that
data is unavailable; do not display fabricated device, location, activity, or
login status values. Preserve the existing twoFactorEnabled behavior and
security settings structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b93648ff-76b3-4c9b-a23c-097880162876

📥 Commits

Reviewing files that changed from the base of the PR and between 602b6f7 and 8a3e921.

📒 Files selected for processing (8)
  • frontend/package.json
  • frontend/src/App.tsx
  • frontend/src/components/FeatureTour.tsx
  • frontend/src/components/HelpButton.tsx
  • frontend/src/components/HelpPanel.tsx
  • frontend/src/components/Tooltip.tsx
  • frontend/src/components/index.ts
  • frontend/src/help/content.tsx

Comment thread frontend/src/App.tsx
Comment on lines 660 to 677
onCreateApiKey={async (name, permissions) => {
const response = await runSettingsRequest(
() => requestSettingsApi({ method: 'post', url: '/api/v2/account/api-keys', data: { name, permissions } }),
'API key created.'
() =>
requestSettingsApi({
method: "post",
url: "/api/v2/account/api-keys",
data: { name, permissions },
}),
"API key created.",
);
const key = extractApiKey(response);
if (!key) {
throw new Error('The server did not return a new API key.');
throw new Error(
"The server did not return a new API key.",
);
}
return { key };
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Success toast fires before the API key is validated, in both key-creation flows.

runSettingsRequest shows the successMessage toast as soon as the HTTP call resolves (lines 406-409), but onCreateApiKey and onRegenerateApiKey only validate the returned key after that call returns. If the request succeeds with a 200 but the response body lacks a usable key, the user sees "API key created."/"API key regenerated." immediately followed by a thrown error — a misleading, contradictory sequence for a security-sensitive flow.

  • frontend/src/App.tsx#L660-L677: don't pass "API key created." into runSettingsRequest; call toast.success manually only after extractApiKey confirms a key was returned.
  • frontend/src/App.tsx#L688-L704: apply the same fix to onRegenerateApiKey's "API key regenerated." message.
✅ Suggested fix (applies to both handlers)
                     onCreateApiKey={async (name, permissions) => {
                       const response = await runSettingsRequest(
                         () =>
                           requestSettingsApi({
                             method: "post",
                             url: "/api/v2/account/api-keys",
                             data: { name, permissions },
                           }),
-                        "API key created.",
                       );
                       const key = extractApiKey(response);
                       if (!key) {
                         throw new Error(
                           "The server did not return a new API key.",
                         );
                       }
+                      toast.success("API key created.");
                       return { key };
                     }}

(mirror the same change for onRegenerateApiKey)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onCreateApiKey={async (name, permissions) => {
const response = await runSettingsRequest(
() => requestSettingsApi({ method: 'post', url: '/api/v2/account/api-keys', data: { name, permissions } }),
'API key created.'
() =>
requestSettingsApi({
method: "post",
url: "/api/v2/account/api-keys",
data: { name, permissions },
}),
"API key created.",
);
const key = extractApiKey(response);
if (!key) {
throw new Error('The server did not return a new API key.');
throw new Error(
"The server did not return a new API key.",
);
}
return { key };
}}
onCreateApiKey={async (name, permissions) => {
const response = await runSettingsRequest(
() =>
requestSettingsApi({
method: "post",
url: "/api/v2/account/api-keys",
data: { name, permissions },
}),
);
const key = extractApiKey(response);
if (!key) {
throw new Error(
"The server did not return a new API key.",
);
}
toast.success("API key created.");
return { key };
}}
📍 Affects 1 file
  • frontend/src/App.tsx#L660-L677 (this comment)
  • frontend/src/App.tsx#L688-L704
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/App.tsx` around lines 660 - 677, Defer success toasts until API
key validation succeeds in both handlers: in frontend/src/App.tsx lines 660-677,
remove the success message from runSettingsRequest in onCreateApiKey and call
toast.success after extractApiKey confirms a key; apply the same change in lines
688-704 for onRegenerateApiKey, using the regenerated message. Keep the existing
error thrown when no usable key is returned.

Comment on lines +1 to +84
import React, { useState } from "react";
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Box,
Typography,
} from "@mui/material";

interface FeatureTourProps {
open: boolean;
onClose: () => void;
}

const tourSteps = [
{
title: "Welcome to ChenaiKit",
content:
"This quick tour will guide you through the main dashboard controls, reporting panels, and help resources.",
},
{
title: "Dashboard Header",
content:
"The dashboard header gives you quick access to theme controls, help, and account settings.",
},
{
title: "Time Range Selector",
content: "Use this range selector to filter analytics and reports by time window.",
},
{
title: "Export Actions",
content: "Export charts, CSV files, and reports from the action bar here.",
},
{
title: "Visualization Tabs",
content:
"Switch between data visualization modules and explore charts, heatmaps, and topology views.",
},
{
title: "Tour Complete",
content:
"You are now familiar with the main features. Use the Help button anytime for more information.",
},
];

const FeatureTour: React.FC<FeatureTourProps> = ({ open, onClose }) => {
const [currentStep, setCurrentStep] = useState(0);

const handleNext = () => {
if (currentStep < tourSteps.length - 1) {
setCurrentStep(currentStep + 1);
} else {
onClose();
}
};

const handleSkip = () => {
onClose();
};

const step = tourSteps[currentStep];

return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
<DialogTitle>{step.title}</DialogTitle>
<DialogContent>
<Box sx={{ pt: 2 }}>
<Typography variant="body1">{step.content}</Typography>
<Typography variant="caption" color="textSecondary" sx={{ mt: 2, display: "block" }}>
Step {currentStep + 1} of {tourSteps.length}
</Typography>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleSkip}>Skip</Button>
<Button onClick={handleNext} variant="contained" color="primary">
{currentStep === tourSteps.length - 1 ? "Finish" : "Next"}
</Button>
</DialogActions>
</Dialog>
);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Tour never highlights target elements — tour-header/tour-tabs/tour-dashboard-range ids are unused.

App.tsx wires up dashboard elements with ids (tour-header at line 166, tour-tabs at line 248, tour-dashboard-range at line 352) presumably for the tour to spotlight, but FeatureTour renders a plain centered Dialog with no reference to any target id, no scroll-into-view, and no visual highlight/overlay on the underlying element. This leaves the "highlighted elements" requirement from the linked issue unimplemented — the tour currently can't actually point at what it's describing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/FeatureTour.tsx` around lines 1 - 84, Update
FeatureTour to spotlight the dashboard elements described by each tour step
instead of rendering only a centered Dialog: associate the relevant steps with
the existing tour-header, tour-dashboard-range, and tour-tabs target ids, locate
the active target, scroll it into view, and render a visual highlight/overlay
anchored to it while the step is active. Preserve the current navigation, skip,
finish, and dialog content behavior, and handle steps without a target such as
the welcome and completion screens.

Comment on lines +48 to +61
const FeatureTour: React.FC<FeatureTourProps> = ({ open, onClose }) => {
const [currentStep, setCurrentStep] = useState(0);

const handleNext = () => {
if (currentStep < tourSteps.length - 1) {
setCurrentStep(currentStep + 1);
} else {
onClose();
}
};

const handleSkip = () => {
onClose();
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Tour resumes at the last step instead of restarting when reopened.

currentStep is component-local state that's never reset on open transitions. Since FeatureTour stays mounted for the lifetime of the dashboard, skipping/finishing at step N and later reopening the tour (e.g. from the Help Panel) resumes at step N instead of starting over at step 1.

🔁 Suggested fix
 const FeatureTour: React.FC<FeatureTourProps> = ({ open, onClose }) => {
   const [currentStep, setCurrentStep] = useState(0);

+  useEffect(() => {
+    if (open) {
+      setCurrentStep(0);
+    }
+  }, [open]);
+
   const handleNext = () => {

(requires importing useEffect from react)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const FeatureTour: React.FC<FeatureTourProps> = ({ open, onClose }) => {
const [currentStep, setCurrentStep] = useState(0);
const handleNext = () => {
if (currentStep < tourSteps.length - 1) {
setCurrentStep(currentStep + 1);
} else {
onClose();
}
};
const handleSkip = () => {
onClose();
};
const FeatureTour: React.FC<FeatureTourProps> = ({ open, onClose }) => {
const [currentStep, setCurrentStep] = useState(0);
useEffect(() => {
if (open) {
setCurrentStep(0);
}
}, [open]);
const handleNext = () => {
if (currentStep < tourSteps.length - 1) {
setCurrentStep(currentStep + 1);
} else {
onClose();
}
};
const handleSkip = () => {
onClose();
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/FeatureTour.tsx` around lines 48 - 61, Reset
currentStep to the initial step whenever the open prop transitions to true by
adding a useEffect in FeatureTour and importing it from React. Preserve the
existing handleNext and handleSkip behavior while ensuring every reopening
starts at the first tour step.

Comment on lines +28 to +33
const suggestionLabels: Record<string, string> = {
analytics: 'Analytics help',
visualization: 'Visualizations',
dashboard: 'Dashboard guidance',
general: 'General help',
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Most suggestion chips return zero search results.

filterTopics does a substring match of the entire query against topic title/summary/section/keywords. The chip labels ('Analytics help', 'Dashboard guidance', 'General help') don't appear as contiguous substrings anywhere in helpTopics (see frontend/src/help/content.tsx), so clicking those chips will filter the topic list down to empty while the detail pane still shows an unrelated fallback topic.

🔍 Suggested fix — match against keywords/contexts instead of literal phrase
 const filterTopics = (topics: HelpTopic[], query: string, context?: string) => {
   const normalizedQuery = query.trim().toLowerCase();

   return topics.filter((topic) => {
     const contextMatch =
       !context ||
       topic.contexts.includes(context) ||
       topic.keywords.some((keyword) => keyword === context);

     if (!contextMatch) {
       return false;
     }

     if (!normalizedQuery) {
       return true;
     }

-    const searchable = [topic.title, topic.summary, topic.section, ...topic.keywords].join(' ').toLowerCase();
-    return searchable.includes(normalizedQuery);
+    const searchTerms = normalizedQuery.split(/\s+/).filter(Boolean);
+    const searchable = [topic.title, topic.summary, topic.section, ...topic.keywords].join(' ').toLowerCase();
+    return searchTerms.some((term) => searchable.includes(term));
   });
 };

Also applies to: 35-55, 116-126

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/HelpPanel.tsx` around lines 28 - 33, Update the
suggestion chip handling around suggestionLabels and filterTopics so chips use
searchable topic keywords or contexts rather than literal labels that do not
occur in helpTopics. Map each chip to a query matching its intended topics,
while preserving the displayed labels and ensuring clicking every chip produces
relevant results instead of an empty list.

Comment on lines +47 to +79
export const Tooltip: React.FC<TooltipProps> = ({
title,
children,
placement = "top",
followCursor = false,
persistent = false,
icon,
className,
enterDelay,
leaveDelay,
arrow = true,
}) => {
const [open, setOpen] = useState(false);

const trigger = (
<Box component="span" className={className} sx={{ display: "inline-flex" }}>
{children ?? icon ?? <HelpOutlineIcon fontSize="small" />}
</Box>
);

return (
<StyledTooltip
title={title}
placement={placement}
followCursor={followCursor}
disableTouchListener={!persistent}
disableFocusListener={!persistent}
enterDelay={enterDelay ?? (persistent ? 0 : 250)}
leaveDelay={leaveDelay ?? (persistent ? 5000 : 100)}
open={persistent ? open : undefined}
onOpen={() => persistent && setOpen(true)}
onClose={() => persistent && setOpen(false)}
arrow={arrow}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What are the default values of disableFocusListener and disableTouchListener on the MUI v5 Tooltip component?

💡 Result:

On the MUI v5 Tooltip component, the default values for both disableFocusListener and disableTouchListener are false [1][2][3]. This means that by default, the Tooltip is configured to respond to both focus-visible events and long-press touch events [1][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euopipefail

printf 'Package files:\n'
fd -a 'package.json$' . | sed 's#^\./##' | sort

printf '\nMUI versions in package manifests:\n'
python3 - <<'PY'
import json, pathlib
for p in pathlib.Path('.').rglob('package.json'):
    try:
        data=json.loads(p.read_text())
    except Exception:
        continue
    keys=[]
    for sec in ('dependencies','devDependencies','peerDependencies','optionalDependencies'):
        for k,v in data.get(sec, {}).items():
            if k.startswith('`@mui/`'):
                keys.append((sec,k,v))
    if keys:
        print(p)
        for sec,k,v in keys:
            print(f'  {sec}: {k}@{v}')
PY

printf '\nTooltip component excerpt:\n'
fd -a 'Tooltip.tsx$' . | while read -r f; do
  echo "--- ${f#"$PWD/"}"
  wc -l "$f"
  sed -n '1,140p' "$f"
done

printf '\nTooltip usages:\n'
rg -n "Tooltip|<Tooltip|tooltip|<StyledTooltip" -S --glob '!node_modules' --glob '!dist' --glob '!build' .

Repository: nexoraorg/chenaikit

Length of output: 810


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Package files:\n'
find . -type f -name 'package.json' -print | sed 's#^\./##' | sort

printf '\nMUI version references:\n'
grep -RInE '"`@mui/`[^"]+":\s*"[^"]*"' --include='package.json' . || true

printf '\nTooltip.tsx files:\n'
find . -type f -name 'Tooltip.tsx' -print | sed 's#^\./##' | sort

printf '\nTooltip component excerpts:\n'
while IFS= read -r f; do
  echo "--- ${f#"$PWD/"}"
  wc -l "$f"
  sed -n '1,140p' "$f"
done < <(find . -type f -name 'Tooltip.tsx' -print | sort)

printf '\nTooltip usages (first 120 matches):\n'
grep -RInE 'useTooltip|Tooltip|<Tooltip|<StyledTooltip' --include='*.tsx' --include='*.ts' . | head -n 120 || true

printf '\nHelpButton references:\n'
find . -type f \( -name '*Help*Button*.tsx' -o -name '*Help*Button*.ts' \) -print | sed 's#^\./##' | sort | while read -r f; do
  echo "-- ${f#"$PWD/"}"
  sed -n '1,180p' "$f"
done

Repository: nexoraorg/chenaikit

Length of output: 770


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- frontend/src/components/Tooltip.tsx"
wc -l frontend/src/components/Tooltip.tsx
cat -n frontend/src/components/Tooltip.tsx | sed -n '1,140p'

echo
echo "--- Tooltip usages"
grep -RInE 'Tooltip|<Tooltip|<StyledTooltip' --include='*.tsx' --include='*.ts' frontend src packages examples tests 2>/dev/null | head -n 160 || true

echo
echo "--- package manager / lockfile snippets"
for f in package.json frontend/package.json package-lock.json frontend/package-lock.json pnpm-lock.yaml yarn.lock .yarnrc.yml; do
  if [ -f "$f" ]; then
    echo "--- $f"
    sed -n '1,80p' "$f"
  fi
done

Repository: nexoraorg/chenaikit

Length of output: 20943


Keep focus/touch listeners enabled by default.

disableFocusListener={!persistent} disables keyboard focus triggering for every non-persistent tooltip, which is the default here. MUI Tooltip enables focus/touch listeners by default, so this component makes the common HelpButton/MFASetupWizard cases inaccessible without persistent. Do not disable listeners unless the tooltip is explicitly persistent.

♿ Suggested fix
-      disableTouchListener={!persistent}
-      disableFocusListener={!persistent}
+      disableTouchListener={false}
+      disableFocusListener={false}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const Tooltip: React.FC<TooltipProps> = ({
title,
children,
placement = "top",
followCursor = false,
persistent = false,
icon,
className,
enterDelay,
leaveDelay,
arrow = true,
}) => {
const [open, setOpen] = useState(false);
const trigger = (
<Box component="span" className={className} sx={{ display: "inline-flex" }}>
{children ?? icon ?? <HelpOutlineIcon fontSize="small" />}
</Box>
);
return (
<StyledTooltip
title={title}
placement={placement}
followCursor={followCursor}
disableTouchListener={!persistent}
disableFocusListener={!persistent}
enterDelay={enterDelay ?? (persistent ? 0 : 250)}
leaveDelay={leaveDelay ?? (persistent ? 5000 : 100)}
open={persistent ? open : undefined}
onOpen={() => persistent && setOpen(true)}
onClose={() => persistent && setOpen(false)}
arrow={arrow}
export const Tooltip: React.FC<TooltipProps> = ({
title,
children,
placement = "top",
followCursor = false,
persistent = false,
icon,
className,
enterDelay,
leaveDelay,
arrow = true,
}) => {
const [open, setOpen] = useState(false);
const trigger = (
<Box component="span" className={className} sx={{ display: "inline-flex" }}>
{children ?? icon ?? <HelpOutlineIcon fontSize="small" />}
</Box>
);
return (
<StyledTooltip
title={title}
placement={placement}
followCursor={followCursor}
disableTouchListener={false}
disableFocusListener={false}
enterDelay={enterDelay ?? (persistent ? 0 : 250)}
leaveDelay={leaveDelay ?? (persistent ? 5000 : 100)}
open={persistent ? open : undefined}
onOpen={() => persistent && setOpen(true)}
onClose={() => persistent && setOpen(false)}
arrow={arrow}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/Tooltip.tsx` around lines 47 - 79, Update the
StyledTooltip listener configuration in Tooltip so focus and touch listeners
remain enabled for the default non-persistent tooltips; do not set
disableFocusListener or disableTouchListener based on !persistent. Preserve the
existing persistent open-state and delay behavior.

contexts: ['general', 'dashboard'],
keywords: ['getting started', 'tour', 'overview', 'dashboard'],
section: 'Overview',
videoUrl: 'https://www.youtube.com/embed/dQw4w9WgXcQ',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Placeholder rickroll video URL shipped as real content.

videoUrl for the "Getting Started" topic points to the well-known "Never Gonna Give You Up" video ID (dQw4w9WgXcQ), not an actual product tutorial. This will render inside the HelpPanel's embedded iframe for real users.

🎬 Suggested fix
-    videoUrl: 'https://www.youtube.com/embed/dQw4w9WgXcQ',
+    videoUrl: 'https://www.youtube.com/embed/<REAL_TUTORIAL_VIDEO_ID>',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/help/content.tsx` at line 36, Replace the placeholder videoUrl
for the “Getting Started” help topic with the correct product tutorial video
URL, ensuring HelpPanel embeds real instructional content instead of the
rickroll video.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Frontend] Add Tooltip and Help System

1 participant