-
-
Notifications
You must be signed in to change notification settings - Fork 725
Use the Kapa AI SDK instead of the Kapa AI widget #2113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
WalkthroughA new AI chat system named "AskAI" was integrated into the web application, replacing the previous Kapa AI widget implementation. This involved adding a comprehensive React-based chat interface with context management, modal dialog UI, chat history, feedback mechanisms, and bot protection via hCaptcha. Supporting components and hooks for AskAI were introduced, while the old Kapa widget integration and its related hooks were removed. The navigation and provider structure were updated to use the new AskAI context. Additionally, a new SVG icon component and animated gradient-glow CSS utility were added, and relevant dependencies such as 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms (25)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/webapp/app/components/AskAI.tsx (3)
91-93
: Consider making the hCaptcha delay configurable.The 1000ms delay is hardcoded. Consider making this configurable through props or environment variables to allow for adjustment based on different environments or testing needs.
+const HCAPTCHA_DELAY_MS = process.env.HCAPTCHA_DELAY_MS || 1000; // Add a delay to avoid triggering hCaptcha bot detection setTimeout(() => { openAskAI(decodedAiHelp); - }, 1000); + }, HCAPTCHA_DELAY_MS);
306-310
: Extract duplicate feedback logic into a helper function.The feedback handling logic is duplicated for upvote and downvote actions.
+ const handleFeedback = (reaction: "upvote" | "downvote") => { + const latestQA = conversation[conversation.length - 1]; + if (latestQA?.id) { + addFeedback(latestQA.id, reaction); + setFeedbackGivenForQAs((prev) => new Set(prev).add(latestQA.id)); + } + }; + <div className="flex items-center"> <Button variant="minimal/small" - onClick={() => { - const latestQA = conversation[conversation.length - 1]; - if (latestQA?.id) { - addFeedback(latestQA.id, "upvote"); - setFeedbackGivenForQAs((prev) => new Set(prev).add(latestQA.id)); - } - }} + onClick={() => handleFeedback("upvote")} className="size-8 px-1.5" > <HandThumbUpIcon className="size-4 text-text-dimmed transition group-hover/button:text-success" /> </Button> <Button variant="minimal/small" - onClick={() => { - const latestQA = conversation[conversation.length - 1]; - if (latestQA?.id) { - addFeedback(latestQA.id, "downvote"); - setFeedbackGivenForQAs((prev) => new Set(prev).add(latestQA.id)); - } - }} + onClick={() => handleFeedback("downvote")} className="size-8 px-1.5" >Also applies to: 319-323
539-539
: Remove the extra empty line at the end of the file.-
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (10)
apps/webapp/app/assets/icons/SparkleListIcon.tsx
(1 hunks)apps/webapp/app/components/AskAI.tsx
(1 hunks)apps/webapp/app/components/navigation/SideMenu.tsx
(4 hunks)apps/webapp/app/components/primitives/Dialog.tsx
(1 hunks)apps/webapp/app/components/primitives/SheetV3.tsx
(1 hunks)apps/webapp/app/components/primitives/ShortcutKey.tsx
(1 hunks)apps/webapp/app/hooks/useKapaWidget.tsx
(0 hunks)apps/webapp/app/root.tsx
(2 hunks)apps/webapp/app/tailwind.css
(2 hunks)apps/webapp/package.json
(4 hunks)
💤 Files with no reviewable changes (1)
- apps/webapp/app/hooks/useKapaWidget.tsx
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/webapp/app/components/primitives/SheetV3.tsx (1)
apps/webapp/app/components/primitives/ShortcutKey.tsx (1)
ShortcutKey
(38-55)
apps/webapp/app/components/primitives/ShortcutKey.tsx (1)
apps/webapp/app/utils/cn.ts (1)
cn
(30-32)
apps/webapp/app/root.tsx (1)
apps/webapp/app/components/AskAI.tsx (1)
AskAIProvider
(60-125)
apps/webapp/app/components/primitives/Dialog.tsx (1)
apps/webapp/app/components/primitives/ShortcutKey.tsx (1)
ShortcutKey
(38-55)
apps/webapp/app/components/navigation/SideMenu.tsx (4)
apps/webapp/app/hooks/useFeatures.ts (1)
useFeatures
(5-9)apps/webapp/app/root.tsx (1)
loader
(42-64)apps/webapp/app/components/AskAI.tsx (1)
useAskAI
(47-53)apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx (1)
HelpAndFeedback
(26-191)
🪛 Biome (1.9.4)
apps/webapp/app/components/AskAI.tsx
[error] 256-256: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (23)
apps/webapp/app/assets/icons/SparkleListIcon.tsx (1)
1-14
: LGTM! Clean and well-structured icon component.The implementation follows React best practices with proper TypeScript typing, optional className prop for styling flexibility, and uses
currentColor
for theme compatibility. The SVG structure is well-formed with appropriate paths and rectangles.apps/webapp/app/tailwind.css (2)
8-12
: LGTM! Proper CSS custom property definition.The
@property
syntax is correctly used to define the--gradient-angle
custom property with appropriate syntax, initial value, and inheritance behavior.
49-83
: LGTM! Well-implemented animated gradient utility.The animated gradient glow utility is well-structured with:
- Proper positioning and overflow handling
- Efficient pseudo-element approach for the background effect
- Smooth conic-gradient animation with reasonable performance characteristics
- Appropriate use of
pointer-events: none
to prevent interaction issues- Good balance of blur and opacity for the glow effect
apps/webapp/app/components/primitives/SheetV3.tsx (1)
94-104
: LGTM! Platform-specific shortcut structure improves consistency.The update to use explicit
windows
andmac
shortcut definitions enhances consistency with the ShortcutKey component's capabilities, even though both platforms use the same "esc" key in this case. This provides better clarity and maintains consistency with other shortcut usage patterns.apps/webapp/app/components/primitives/ShortcutKey.tsx (2)
16-16
: LGTM! Improved semantic color naming for small variant.The change from
border-dimmed/40
toborder-text-dimmed/40
(and corresponding hover effects) improves semantic naming and maintains visual consistency.
17-17
: LGTM! Proper use of utility function for class composition.Using the
cn
utility to combine the basemedium
styles with the additional hover effect (group-hover:border-charcoal-550
) is the correct approach for composing Tailwind CSS classes while handling potential conflicts.apps/webapp/app/root.tsx (3)
3-3
: Clean import optimization.Good removal of unused imports (
useMatches
,useTypedMatchesData
,KapaScripts
) as part of the migration from the old Kapa widget to the new AskAI system.
9-9
: Proper integration of AskAIProvider.The import aligns with the new AI chat system implementation.
111-116
: Well-structured provider integration.The
AskAIProvider
is properly positioned at the root level and correctly receives thewebsiteId
from the loader data. The conditional|| null
ensures type safety whenkapa.websiteId
is undefined. The nested component structure maintains the existing hierarchy while providing the new AI context.apps/webapp/app/components/primitives/Dialog.tsx (1)
53-67
: Excellent UI improvements to the dialog close button.The refactoring brings several enhancements:
- Simplified structure by removing unnecessary wrapper div
- Better hover coordination using
group
andgroup-hover:
classes- More explicit shortcut key definition with platform-specific variants
- Improved positioning and spacing with
right-2 top-[0.5625rem]
- Enhanced visual feedback with transition effects on the icon
The change from
variant="small"
tovariant="medium"
forShortcutKey
aligns with the broader UI consistency improvements mentioned in the AI summary.apps/webapp/package.json (2)
58-58
: Essential dependency for AskAI integration.The addition of
@kapaai/react-sdk
is necessary for the new AI chat interface that replaces the previous Kapa widget integration. The version^0.1.2
appears reasonable for this new integration.
49-61
: Good dependency organization.The reordering of dependencies like
@internal/redis
,@internal/tracing
,@trigger.dev/redis-worker
, and@opentelemetry/api-logs
improves maintainability without changing functionality.Also applies to: 108-108
apps/webapp/app/components/navigation/SideMenu.tsx (4)
21-21
: Clean migration from useKapaWidget to useAskAI.The import changes properly reflect the transition from the old Kapa widget integration to the new AskAI system. The addition of
useMatches
,useFeatures
,useTypedMatchesData
, anduseAskAI
provides the necessary hooks for the refactored component logic.Also applies to: 27-27, 30-30, 33-33, 36-36, 84-84
576-583
: Well-structured data fetching for AI feature detection.The refactored approach properly:
- Uses
useMatches
anduseTypedMatchesData
to access root loader data- Leverages
useFeatures
for feature flag detection- Extracts
websiteId
andopenAskAI
from the newuseAskAI
hook- Maintains the same
isKapaEnabled
logic usingfeatures.isManagedCloud && websiteId
This approach is more explicit and maintainable than the previous implementation.
588-588
: Simplified HelpAndFeedback usage.The removal of the
disableShortcut
prop suggests that shortcut handling is now managed at a higher level or within the component itself, which aligns with the overall UI improvements in this PR.
600-600
: Streamlined onClick handler.The simplification from a block function calling
openKapa()
to a direct call toopenAskAI()
reflects the cleaner API of the new AskAI system.apps/webapp/app/components/AskAI.tsx (7)
1-36
: LGTM!The imports are well-organized and appropriate for the functionality implemented.
38-53
: LGTM!The context setup follows React best practices with proper typing and error handling.
113-116
: Verify the KapaProvider callback implementation.The callbacks
onQuerySubmit
andonAnswerGenerationCompleted
both callopenAskAI()
without parameters, which only setsinitialQuery
toundefined
. This seems redundant since the dialog is already open when these callbacks fire.Please verify if these callbacks are intended to perform specific actions or if they can be removed.
127-157
: LGTM!The dialog component is well-structured with proper state management and styling.
380-488
: LGTM!The ChatInterface component is well-implemented with proper state management, form handling, and animation effects.
490-512
: LGTM!The GradientSpinnerBackground component provides a nice visual effect for the loading states.
514-538
: LGTM!The AskAIButton component is simple and effective, with proper tooltip integration.
# Conflicts: # apps/webapp/package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/webapp/app/components/AskAI.tsx (2)
255-260
: Potentially unstable React keys whenqa.id
is undefined
key={qa.id || \
temp-${qa.question}`}may collide if a user submits the same question twice before IDs are returned, leading to incorrect list reconciliation. Generate a truly unique fallback (e.g.
crypto.randomUUID()` or an incrementing ref).-<div key={qa.id || `temp-${qa.question}`} className="mb-4"> +<div key={qa.id ?? crypto.randomUUID()} className="mb-4">🧰 Tools
🪛 Biome (1.9.4)
[error] 260-260: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
259-261
: Repeated re-parsing/ sanitising of markdown can be expensive
marked
+DOMPurify.sanitize
runs on every render.
For long conversations this can become costly. Memoise the HTML per QA item:const html = useMemo( () => DOMPurify.sanitize(marked(qa.answer)), [qa.answer] );Wrap it in a component or compute once before
map
.🧰 Tools
🪛 Biome (1.9.4)
[error] 260-260: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
apps/webapp/app/components/AskAI.tsx
(1 hunks)apps/webapp/package.json
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/webapp/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/webapp/app/components/AskAI.tsx (5)
apps/webapp/app/components/primitives/Dialog.tsx (4)
Dialog
(114-114)DialogContent
(116-116)DialogHeader
(117-117)DialogTitle
(119-119)apps/webapp/app/assets/icons/AISparkleIcon.tsx (1)
AISparkleIcon
(1-31)apps/webapp/app/components/primitives/Buttons.tsx (1)
Button
(294-329)apps/webapp/app/components/primitives/Spinner.tsx (1)
Spinner
(8-62)apps/webapp/app/components/primitives/Tooltip.tsx (5)
SimpleTooltip
(118-118)TooltipProvider
(118-118)Tooltip
(118-118)TooltipTrigger
(118-118)TooltipContent
(118-118)
🪛 Biome (1.9.4)
apps/webapp/app/components/AskAI.tsx
[error] 260-260: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/webapp/app/components/AskAI.tsx (1)
104-107
:openAskAI()
becomes a no-op whenwebsiteId
isnull
When
websiteId
is absent you short-circuit the JSX and don’t renderAskAIDialog
, yetopenAskAI
will still setisOpen
totrue
.
Call sites might assume a dialog will appear and wait for callbacks that never come. Consider either:
- Throwing early in
openAskAI
whenwebsiteId
isnull
, or- Always rendering the dialog but displaying a “feature unavailable” state.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/webapp/app/components/AskAI.tsx (2)
256-259
: Consider replacingdangerouslySetInnerHTML
or silencing the linterEven though the HTML is being sanitised with DOMPurify,
dangerouslySetInnerHTML
still triggerslint/security/noDangerouslySetInnerHtml
. If keeping the current approach:
- Explicitly disable the rule for this line with an inline comment, or
- Switch to
react-markdown
/markdown-to-jsx
to avoiddangerouslySetInnerHTML
altogether.Either way you get rid of the noisy Biome warning.
🧰 Tools
🪛 Biome (1.9.4)
[error] 258-258: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
191-196
: HoistexampleQuestions
outside the component
exampleQuestions
is recreated on every re-render even though it is static. Move it to file scope (or wrap inuseMemo
) to avoid needless allocations.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/webapp/app/components/AskAI.tsx
(1 hunks)apps/webapp/app/components/navigation/SideMenu.tsx
(4 hunks)apps/webapp/app/components/primitives/Dialog.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/webapp/app/components/navigation/SideMenu.tsx
- apps/webapp/app/components/primitives/Dialog.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/webapp/app/components/AskAI.tsx
[error] 100-100: Expected an expression but instead found '}'.
Expected an expression here.
(parse)
[error] 103-103: Illegal return statement outside of a function
(parse)
[error] 106-122: Illegal return statement outside of a function
(parse)
[error] 122-123: Expected a statement but instead found '}'.
Expected a statement here.
(parse)
[error] 258-258: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🪛 GitHub Actions: 🤖 PR Checks
apps/webapp/app/components/AskAI.tsx
[error] 100-100: TypeScript error TS1109: Expression expected.
isOpen, | ||
openAskAI, | ||
closeAskAI, | ||
websiteId, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix missing contextValue
declaration – the file does not compile
contextValue
is referenced twice below but never declared. This leaves five stray identifiers in the top-level scope and is the root cause of the TS/parse errors reported by the pipeline.
- isOpen,
- openAskAI,
- closeAskAI,
- websiteId,
- };
+ const contextValue: AskAIContextType = {
+ isOpen,
+ openAskAI,
+ closeAskAI,
+ websiteId,
+ };
Without this object the component fails to build and every downstream reference to contextValue
is invalid.
📝 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.
isOpen, | |
openAskAI, | |
closeAskAI, | |
websiteId, | |
}; | |
const contextValue: AskAIContextType = { | |
isOpen, | |
openAskAI, | |
closeAskAI, | |
websiteId, | |
}; |
🧰 Tools
🪛 Biome (1.9.4)
[error] 100-100: Expected an expression but instead found '}'.
Expected an expression here.
(parse)
🪛 GitHub Actions: 🤖 PR Checks
[error] 100-100: TypeScript error TS1109: Expression expected.
🤖 Prompt for AI Agents
In apps/webapp/app/components/AskAI.tsx around lines 96 to 100, the variable
contextValue is used but not declared, causing TypeScript and parsing errors. To
fix this, declare contextValue as an object that includes the relevant
properties such as isOpen, openAskAI, closeAskAI, and websiteId before it is
referenced. This will ensure the component compiles correctly and all references
to contextValue are valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/webapp/app/components/AskAI.tsx (4)
80-95
:useEffect
dependency can still trigger unnecessary re-renders
searchParams.toString()
is recalculated on every render even when the query
string hasn’t actually changed, so the effect may re-run more often than
needed. A cheaper and more explicit option is to watch the specific parameter
you care about:-useEffect(() => { - const aiHelp = searchParams.get("aiHelp"); - ... -}, [searchParams.toString(), openAskAI]); +useEffect(() => { + const aiHelp = searchParams.get("aiHelp"); + ... +// Only re-run when the *value* of the param changes +}, [searchParams.get("aiHelp"), openAskAI]);This avoids the stringification cost and prevents the effect from firing when
unrelated query-string keys change.
259-261
: Sanitisation looks good, but tighten the allowed tags to silence the linterDOMPurify is already in place – nice!
To satisfy the security linter and further reduce attack-surface you can pass a
minimal allowed-tags list:- dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(marked(qa.answer)) }} + dangerouslySetInnerHTML={{ + __html: DOMPurify.sanitize(marked(qa.answer), { ALLOWED_TAGS: ["p","ul","ol","li","a","code","pre","strong","em"] }) + }}Keeps flexibility while nullifying most XSS vectors and removes the Biome
warning.🧰 Tools
🪛 Biome (1.9.4)
[error] 260-260: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
221-252
: Make example buttons non-submit & prevent potential form side-effectsThese
<motion.button>
elements live outside a<form>
now, but future
refactors could nest them unintentionally. Adding an explicittype="button"
guards against accidental form submission:-<motion.button +<motion.button + type="button"
308-329
: Set-state helper mutates the newSet
unnecessarily
new Set(prev).add(id)
mutates the newly created set inline. While harmless,
it’s clearer to mutate in a separate step:-setFeedbackGivenForQAs((prev) => new Set(prev).add(latestQA.id)); +setFeedbackGivenForQAs((prev) => { + const next = new Set(prev); + next.add(latestQA.id); + return next; +});Improves readability and prevents accidental reliance on
Set.add
’s return
value.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/webapp/app/components/AskAI.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/webapp/app/components/AskAI.tsx
[error] 260-260: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
⏰ Context from checks skipped due to timeout of 90000ms (16)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: typecheck / typecheck
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: Analyze (javascript-typescript)
<span | ||
onClick={() => stopGeneration()} | ||
className="group relative z-10 flex size-10 min-w-10 cursor-pointer items-center justify-center" | ||
> | ||
<StopIcon className="z-10 size-5 text-indigo-500 transition group-hover:text-indigo-400" /> | ||
<GradientSpinnerBackground | ||
className="absolute inset-0 animate-spin" | ||
hoverEffect | ||
/> | ||
</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace non-semantic <span>
with an accessible button
The “stop generating” control is currently a clickable <span>
which is not
keyboard-focusable and fails accessibility guidelines. Swapping to a <button>
restores correct semantics, keyboard support and native focus styling:
-<span
- onClick={() => stopGeneration()}
- className="group relative z-10 flex size-10 min-w-10 cursor-pointer items-center justify-center"
->
+<button
+ type="button"
+ onClick={stopGeneration}
+ aria-label="Stop generating"
+ className="group relative z-10 flex size-10 min-w-10 items-center justify-center rounded-full focus-visible:focus-custom"
+>
<StopIcon className="z-10 size-5 text-indigo-500 transition group-hover:text-indigo-400" />
<GradientSpinnerBackground
className="absolute inset-0 animate-spin"
hoverEffect
/>
-</span>
+</button>
📝 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.
<span | |
onClick={() => stopGeneration()} | |
className="group relative z-10 flex size-10 min-w-10 cursor-pointer items-center justify-center" | |
> | |
<StopIcon className="z-10 size-5 text-indigo-500 transition group-hover:text-indigo-400" /> | |
<GradientSpinnerBackground | |
className="absolute inset-0 animate-spin" | |
hoverEffect | |
/> | |
</span> | |
<button | |
type="button" | |
onClick={stopGeneration} | |
aria-label="Stop generating" | |
className="group relative z-10 flex size-10 min-w-10 items-center justify-center rounded-full focus-visible:focus-custom" | |
> | |
<StopIcon className="z-10 size-5 text-indigo-500 transition group-hover:text-indigo-400" /> | |
<GradientSpinnerBackground | |
className="absolute inset-0 animate-spin" | |
hoverEffect | |
/> | |
</button> |
🤖 Prompt for AI Agents
In apps/webapp/app/components/AskAI.tsx around lines 456 to 465, replace the
non-semantic clickable <span> element used for the "stop generating" control
with a <button> element to improve accessibility. This change will make the
control keyboard-focusable, provide correct semantic meaning, and restore native
focus styling. Ensure the onClick handler and all class names are preserved on
the new <button> element.
# Conflicts: # apps/webapp/app/components/navigation/SideMenu.tsx
This replaces the Kapa AI Javascript widget with their React SDK. This means:
useAskAI
hook to trigger it from anywhere in the app and pass it a payload 'answer'Testing for Test Cloud
askai.mp4