feat(ui): shared UI foundation (utilities, source/research primitives, markdown upgrade)#331
Conversation
Foundational frontend utilities for the staged chat UI/UX work: - cn(): clsx + tailwind-merge className composition so conflicting Tailwind utilities resolve deterministically. - titleCaseWords()/ACRONYMS: humanize snake_case and `__`-separated identifiers (tool and function names) into display labels, upper-casing common acronyms. - AppMotionConfig: a Motion provider that honors prefers-reduced-motion. Adds clsx, tailwind-merge, and motion. Covered 100% by unit tests; no UI behavior changes yet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Manush Maheshwari <manushm@nvidia.com>
WalkthroughAdds shared UI primitives, source parsing and display components, enhanced Markdown rendering with citations and math, interactive Mermaid diagrams, research trace helpers, styling tokens, dependencies, and tests. ChangesUI content and research primitives
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant MarkdownRenderer
participant ReactMarkdown
participant MermaidBlock
participant Mermaid
MarkdownRenderer->>ReactMarkdown: render fenced mermaid content
ReactMarkdown->>MermaidBlock: route mermaid code block
MermaidBlock->>Mermaid: initialize theme and render SVG
Mermaid-->>MermaidBlock: return SVG or rendering failure
MermaidBlock-->>MarkdownRenderer: display diagram or fallback
Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. 🔧 Biome (2.5.3)frontends/ui/src/app/globals.cssFile contains syntax errors that prevent linting: Line 155: Tailwind-specific syntax is disabled.; Line 168: Tailwind-specific syntax is disabled.; Line 172: Tailwind-specific syntax is disabled.; Line 176: Tailwind-specific syntax is disabled.; Line 180: Tailwind-specific syntax is disabled.; Line 184: Tailwind-specific syntax is disabled.; Line 188: Tailwind-specific syntax is disabled.; Line 192: Tailwind-specific syntax is disabled.; Line 196: Tailwind-specific syntax is disabled.; Line 200: Tailwind-specific syntax is disabled.; Line 208: Tailwind-specific syntax is disabled.; Line 212: Tailwind-specific syntax is disabled.; Line 216: Tailwind-specific syntax is disabled.; Line 220: Tailwind-specific syntax is disabled.; Line 225: Tailwind-specific syntax is disabled.; Line 231: Tailwind-specific syntax is disabled.; Line 235: Tailwind-specific syntax is disabled.; Line 239: Tailwind-specific syntax is disabled.; Line 247: Tailwind-specific syntax is disabled.; Line 251: Tailwind-specific syntax is disabled.; Line 255: Tailwind-specific syntax is disabled.; Line 259: Tailwind-specific syntax is disabled.; Line 263: Tailwind-specific syntax is disabled.; Line 267: Tailwind-specific syntax is disabled.; Line 271: Tailwind-specific syntax is disabled.; Line 275: Tailwind-specific syntax is disabled.; Line 279: Tailwind-specific syntax is disabled.; Line 283: Tailwind-specific syntax is disabled. Comment |
Adds the UI-only shared component library the chat redesign builds on: - Sources/*: source chips, list, and reference parsing (web + doc kinds). - research/*: StatusDot, ToolCallRow, and a generic tool-label engine for the live research trace. - Surface/Card, Actions/CopyButton, CollapsibleBlock, Mermaid. - MarkdownRenderer upgrade: an answer variant, superscript citations with hover popovers, KaTeX math, and Mermaid diagrams. Prod's artifact-URL handling is preserved verbatim; chart fences fall through unchanged. Adds mermaid, katex, rehype-katex, remark-math, unist-util-visit. No warehouse/predictive features are ported. Covered by unit and render tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Manush Maheshwari <manushm@nvidia.com>
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 15
🤖 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 `@frontends/ui/package.json`:
- Around line 27-43: Align the frontend dependency versions around the Next.js
entry: either upgrade react, react-dom, `@types/react`, and `@types/react-dom`
together to the React 19.2-compatible versions required by next ^16.2.6, or
downgrade next to a 15.x release if React 18 support is intended. Keep the React
runtime and type packages on matching major versions.
In `@frontends/ui/src/app/globals.css`:
- Around line 360-368: Rename the dotBreathe keyframe to a kebab-case identifier
that satisfies stylelint’s keyframes-name-pattern rule, and update every
animation reference to it, including the usages near the additional affected
locations. Run the UI lint, type-check, and build validations.
In `@frontends/ui/src/shared/components/Actions/CopyButton.tsx`:
- Around line 22-33: Update CopyButton’s handleCopy to track the reset timeout
and clear any existing timeout before scheduling a new one, preventing competing
timers on re-click. Add unmount cleanup for the tracked timeout so it cannot
call setCopied after the component is detached, while preserving the current
copied-state behavior.
In `@frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx`:
- Around line 1-90: Add test coverage for the interactive CollapsibleBlock
component, creating CollapsibleBlock.spec.tsx alongside it. Cover the controlled
open/closed rendering, header toggle invoking onOpenChange with the inverse
state, and non-collapsible behavior where the body remains visible and no toggle
affordance is rendered.
- Around line 63-70: Add an aria-controls attribute to the toggle button in
CollapsibleBlock, referencing the unique id assigned to the collapsible
body/content element. Ensure the body uses the same stable id so assistive
technology can associate it with the trigger, while preserving the existing
aria-expanded and toggle behavior.
- Around line 75-87: Update CollapsibleBlock’s motion configuration to respect
prefers-reduced-motion by using a local useReducedMotion branch for the
motion.div transition and animation values. Preserve the existing
expand/collapse behavior while disabling or shortening the height/opacity
animation for reduced-motion users, without relying on AppMotionConfig being
mounted by callers.
In `@frontends/ui/src/shared/components/MarkdownRenderer/Citation.tsx`:
- Around line 32-46: Update the citation chip in the `chip` JSX so citations
without `src?.url` remain keyboard-focusable, allowing the existing `onFocus`
tooltip behavior to work; follow the focusability approach used by
`SourceStrip.tsx` or add the appropriate tab index while preserving link
behavior for URLs.
In `@frontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.ts`:
- Around line 15-46: Update rehypeCitations so its text-node visitor skips nodes
whose parent is a code element, while preserving citation rewriting for prose
text. Add a regression test covering code snippets containing arr[1] and [1],
verifying they remain unchanged and are not converted into cite elements.
In `@frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx`:
- Around line 183-227: Update the fullscreen container rendered by the
MermaidBlock component to expose dialog semantics when fullscreen is active: add
role="dialog" and aria-modal="true" to the fixed overlay, and ensure focus moves
into the overlay on entry and returns to the fullscreen trigger on exit.
Preserve the existing Escape-close behavior and controls.
In `@frontends/ui/src/shared/components/Sources/parse-references.spec.ts`:
- Around line 198-202: The test “renumber + nest-bullets leave fenced content
untouched” is misplaced in the tabularizeEntityLines describe block and does not
exercise that function. Move it to the describe block covering
renumberOrderedLists and nestBulletsUnderOrderedItems, or replace it with a
tabularizeEntityLines assertion that verifies fenced-block handling combined
with renumbering.
In `@frontends/ui/src/shared/components/Sources/source-utils.ts`:
- Around line 43-58: Update mapCitationSource to derive the url field from the
already computed kind value instead of re-testing cs.url with a separate HTTP
regex. Preserve the existing URL value for web sources and undefined behavior
for non-web sources, keeping inferSourceKind as the single source of truth.
In `@frontends/ui/src/shared/components/Sources/SourceList.tsx`:
- Around line 22-57: Add a SourceList.spec.tsx test file covering the
user-visible behavior of SourceList: rendering the title and numbered sources,
displaying source kind icons and domains when applicable, omitting domains that
match labels, and returning no output for an empty sources array. Follow the
existing SourceStrip.spec.tsx testing conventions and reuse established fixtures
or mocks where available.
In `@frontends/ui/src/shared/components/Sources/SourceStrip.tsx`:
- Around line 74-83: Add an aria-expanded attribute to the disclosure button
rendered in SourceStrip’s hasMore and !expanded branch, binding it to the
expanded state so assistive technologies receive the current expansion status.
In `@frontends/ui/src/shared/lib/motion.spec.tsx`:
- Around line 14-32: Strengthen the tests for AppMotionConfig by mocking
motion/react’s MotionConfig and asserting its reducedMotion prop. In the “motion
allowed” case, verify the prop is “never”; in the “reduced motion preferred”
case, verify it is “always”, while retaining the existing child-rendering
assertions.
In `@frontends/ui/src/shared/lib/motion.tsx`:
- Around line 8-17: Update AppMotionConfig to import and use motion/react’s
built-in useReducedMotion instead of the custom `@/hooks/use-reduced-motion` hook.
Remove the now-unused custom import, and verify whether
`@/hooks/use-reduced-motion` has other consumers before deleting it; retain it if
it serves non-Motion use cases.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: f6bb0f6b-2b53-4663-97a2-e8f367f7e44d
⛔ Files ignored due to path filters (1)
frontends/ui/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (38)
frontends/ui/package.jsonfrontends/ui/src/app/globals.cssfrontends/ui/src/shared/components/Actions/CopyButton.spec.tsxfrontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/CollapsibleBlock/index.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/MarkdownRenderer/types.tsfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/Mermaid/index.tsfrontends/ui/src/shared/components/Sources/SourceKindIcon.tsxfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/Sources/parse-references.tsfrontends/ui/src/shared/components/Sources/source-utils.spec.tsfrontends/ui/src/shared/components/Sources/source-utils.tsfrontends/ui/src/shared/components/Sources/types.tsfrontends/ui/src/shared/components/Surface/Card.spec.tsxfrontends/ui/src/shared/components/Surface/Card.tsxfrontends/ui/src/shared/components/research/StatusDot.tsxfrontends/ui/src/shared/components/research/ToolCallRow.tsxfrontends/ui/src/shared/components/research/index.tsfrontends/ui/src/shared/components/research/research-labels.spec.tsfrontends/ui/src/shared/components/research/research-labels.tsfrontends/ui/src/shared/lib/cn.spec.tsfrontends/ui/src/shared/lib/cn.tsfrontends/ui/src/shared/lib/humanize.spec.tsfrontends/ui/src/shared/lib/humanize.tsfrontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/lib/motion.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
frontends/ui/**/*.{js,ts,jsx,tsx,vue}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run npm lint, type-check, and build validation for UI changes in frontends/ui
Files:
frontends/ui/src/shared/lib/cn.spec.tsfrontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/Actions/CopyButton.spec.tsxfrontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/types.tsfrontends/ui/src/shared/components/Mermaid/index.tsfrontends/ui/src/shared/components/research/StatusDot.tsxfrontends/ui/src/shared/components/research/ToolCallRow.tsxfrontends/ui/src/shared/components/Sources/SourceKindIcon.tsxfrontends/ui/src/shared/lib/humanize.spec.tsfrontends/ui/src/shared/lib/humanize.tsfrontends/ui/src/shared/components/research/index.tsfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.spec.tsxfrontends/ui/src/shared/lib/cn.tsfrontends/ui/src/shared/components/CollapsibleBlock/index.tsfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/research/research-labels.spec.tsfrontends/ui/src/shared/lib/motion.tsxfrontends/ui/src/shared/components/Sources/source-utils.tsfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/source-utils.spec.tsfrontends/ui/src/shared/components/Surface/Card.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/Surface/Card.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/types.tsfrontends/ui/src/shared/components/Sources/parse-references.tsfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/research/research-labels.tsfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
frontends/ui/**/*.{ts,tsx,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes
Files:
frontends/ui/src/shared/lib/cn.spec.tsfrontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/Actions/CopyButton.spec.tsxfrontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/types.tsfrontends/ui/src/shared/components/Mermaid/index.tsfrontends/ui/src/shared/components/research/StatusDot.tsxfrontends/ui/src/shared/components/research/ToolCallRow.tsxfrontends/ui/src/shared/components/Sources/SourceKindIcon.tsxfrontends/ui/src/shared/lib/humanize.spec.tsfrontends/ui/src/shared/lib/humanize.tsfrontends/ui/src/shared/components/research/index.tsfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.spec.tsxfrontends/ui/src/shared/lib/cn.tsfrontends/ui/src/shared/components/CollapsibleBlock/index.tsfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/research/research-labels.spec.tsfrontends/ui/src/shared/lib/motion.tsxfrontends/ui/src/shared/components/Sources/source-utils.tsfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/source-utils.spec.tsfrontends/ui/src/shared/components/Surface/Card.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/Surface/Card.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/types.tsfrontends/ui/src/shared/components/Sources/parse-references.tsfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/research/research-labels.tsfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
frontends/ui/**/*
⚙️ CodeRabbit configuration file
frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.
Files:
frontends/ui/src/shared/lib/cn.spec.tsfrontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/Actions/CopyButton.spec.tsxfrontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/types.tsfrontends/ui/src/shared/components/Mermaid/index.tsfrontends/ui/src/shared/components/research/StatusDot.tsxfrontends/ui/src/shared/components/research/ToolCallRow.tsxfrontends/ui/src/shared/components/Sources/SourceKindIcon.tsxfrontends/ui/src/shared/lib/humanize.spec.tsfrontends/ui/src/shared/lib/humanize.tsfrontends/ui/src/shared/components/research/index.tsfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.spec.tsxfrontends/ui/src/shared/lib/cn.tsfrontends/ui/src/shared/components/CollapsibleBlock/index.tsfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/research/research-labels.spec.tsfrontends/ui/src/shared/lib/motion.tsxfrontends/ui/src/shared/components/Sources/source-utils.tsfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/source-utils.spec.tsfrontends/ui/src/shared/components/Surface/Card.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/Surface/Card.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/MarkdownRenderer/Citation.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/package.jsonfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/types.tsfrontends/ui/src/shared/components/Sources/parse-references.tsfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/app/globals.cssfrontends/ui/src/shared/components/research/research-labels.tsfrontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx
🪛 ast-grep (0.44.1)
frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx
[warning] 251-251: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation
(react-unsafe-html-injection)
frontends/ui/src/shared/components/research/research-labels.ts
[warning] 167-167: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(["']${escapedKey}["']\\s*:\\s*"((?:\\\\.|[^"\\\\])*)")
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
[warning] 172-172: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(["']${escapedKey}["']\\s*:\\s*'((?:\\\\.|[^'\\\\])*)')
Note: [CWE-1333] Inefficient Regular Expression Complexity
(regexp-from-variable)
🪛 OpenGrep (1.25.0)
frontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.ts
[ERROR] 24-24: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx
[WARNING] 243-253: dangerouslySetInnerHTML with dynamic content can lead to XSS. Sanitize the input with a library like DOMPurify before rendering.
(coderabbit.xss.react-dangerously-set-innerhtml)
🪛 Stylelint (17.14.0)
frontends/ui/src/app/globals.css
[error] 360-360: Expected keyframe name "dotBreathe" to be kebab-case (keyframes-name-pattern)
(keyframes-name-pattern)
🔇 Additional comments (35)
frontends/ui/src/app/globals.css (1)
320-441: LGTM!frontends/ui/src/shared/lib/cn.spec.ts (1)
1-20: LGTM!frontends/ui/src/shared/lib/cn.ts (1)
1-13: LGTM!frontends/ui/src/shared/components/Surface/Card.spec.tsx (1)
1-46: LGTM!frontends/ui/src/shared/components/Surface/Card.tsx (1)
1-40: LGTM!frontends/ui/src/shared/components/research/research-labels.ts (6)
83-91: 📐 Maintainability & Code QualityRedundant guard after early return.
if (TOOL_LABELS[normalized]) return normalizedalready guarantees the code below only runs whenTOOL_LABELS[normalized]is falsy, so the&& !TOOL_LABELS[normalized]in theif (prefixed && ...)check on Line 87 is dead weight.
165-186: 🔒 Security & PrivacyStatic-analysis ReDoS warning is a false positive.
The hint flags
escapedKeyas "variable input," but it's derived from the hardcodedARG_KEYSlist (Line 135-146), not attacker-controlled text, and is properly regex-escaped. The(?:\\.|[^"\\])*/(?:\\.|[^'\\])*alternations are mutually exclusive on their first character, so there's no catastrophic-backtracking path here.Source: Linters/SAST tools
21-52: LGTM!AGENT_LABELSmapping andgetAgentLabelfallback logic match the tested behavior for known agent names.
108-122: LGTM! Traced all branches (rawexact match,__-prefix collapsing, angle-bracket stripping, agent-title fallback, model-name detection) against everyresearch-labels.spec.tsassertion — all consistent.
195-221: LGTM!getToolArgSummarybranches (structured object, code-fenced JSON/python dumps, marker-prefixed input, dump-signature suppression) all match the spec assertions.
224-244: LGTM!frontends/ui/src/shared/lib/humanize.spec.ts (1)
1-27: LGTM!frontends/ui/src/shared/lib/humanize.ts (1)
16-26: LGTM! Logic matches the documented behavior and all test assertions (acronym upper-casing, separator/whitespace collapsing, empty-string handling).frontends/ui/src/shared/components/research/research-labels.spec.ts (1)
1-114: LGTM! Good coverage of the tool/agent/model label branches, arg-summary extraction, and status mappers; assertions verified consistent with the implementation.frontends/ui/src/shared/components/Actions/CopyButton.spec.tsx (1)
1-35: LGTM!frontends/ui/src/shared/components/CollapsibleBlock/index.ts (1)
1-5: LGTM!frontends/ui/src/shared/components/research/ToolCallRow.tsx (1)
18-50: LGTM!frontends/ui/src/shared/components/research/index.ts (1)
1-19: LGTM!frontends/ui/src/shared/components/research/StatusDot.tsx (1)
12-20: 🎯 Functional CorrectnessNo missing status-dot styles
globals.cssdefinesstatus-dot-*for everyNodeState, includingwaiting.> Likely an incorrect or invalid review comment.frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx (2)
45-58: 🎯 Functional CorrectnessClarify the
metaslot contract
metais rendered inside the trigger<button>, so it should stay text/icon-only. Any interactive control needs to live outside the trigger to avoid invalid nested-interactive markup and broken keyboard/screen-reader behavior.
54-54: 🎯 Functional CorrectnessCheck whether
AnimatedChevronaccepts state props. Infrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx,AnimatedChevronis rendered as<AnimatedChevron />with noopen/isOpenprop, so the rotation only works if the component reads collapse state implicitly.frontends/ui/src/shared/components/Sources/types.ts (1)
1-22: LGTM!frontends/ui/src/shared/components/Sources/source-utils.spec.ts (1)
1-58: LGTM!frontends/ui/src/shared/components/Sources/SourceStrip.spec.tsx (1)
1-44: LGTM!frontends/ui/src/shared/components/Sources/SourceStrip.tsx (1)
23-26: 🎯 Functional Correctness
CardTonealready includeswebanddoc, sotone={source.kind}matches the prop type.> Likely an incorrect or invalid review comment.frontends/ui/src/shared/components/Sources/parse-references.ts (1)
12-13: 🎯 Functional CorrectnessNo production impact from the colon mismatch
splitReferencesandstripTrailingReferencesare only referenced inparse-references.spec.tshere, so this asymmetry doesn’t affect the current render path.> Likely an incorrect or invalid review comment.frontends/ui/src/shared/components/Sources/SourceKindIcon.tsx (1)
1-34: LGTM!frontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.spec.ts (1)
1-43: LGTM!frontends/ui/src/shared/components/MarkdownRenderer/Citation.spec.tsx (1)
9-18: LGTM!Also applies to: 46-50
frontends/ui/src/shared/components/MarkdownRenderer/types.ts (1)
4-5: LGTM!Also applies to: 20-27
frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.tsx (1)
146-177: 🎯 Functional CorrectnessAnswer-mode
p/libypass the KUITextcomponent.For
variant="answer", paragraphs and list items render plain<p>/<li>with ad-hoc Tailwind classes instead of the KUITextcomponent used elsewhere in this file. The doc comment intypes.tsexplains this is intentional (KUI's existingTextkinds don't cover the "answer-prose scale"), but per coding guidelines UI components should reuse existing KUI patterns rather than introducing new ad-hoc styling. Worth confirming there isn't a KUITextvariant/kind that already covers this scale before locking in the bespoke Tailwind classes.As per coding guidelines, "reuse existing KUI components and visual patterns rather than introducing new ones."
Source: Coding guidelines
frontends/ui/src/shared/components/MarkdownRenderer/MarkdownRenderer.spec.tsx (1)
352-429: LGTM!frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx (1)
68-74: 🔒 Security & PrivacySVG injection safety depends entirely on
securityLevel: 'strict'staying set.
dangerouslySetInnerHTMLon the Mermaid-generated SVG (flagged by static analysis) is safe today because Mermaid runs its output through DOMPurify wheneversecurityLevelisn'tloose/sandbox; this component correctly setsstrict. Worth a code comment (or a lint rule / test) pinning this contract so a future refactor towardloose(e.g., to enable click interactivity) doesn't silently reintroduce XSS, since Mermaid diagrams here are LLM/chat-generated content.Please confirm
securityLevel: 'strict'is the intended long-term contract and that no other code path (e.g. a future click-interaction feature) will relax it without adding a secondary sanitizer.Also applies to: 243-253
frontends/ui/src/shared/components/Mermaid/index.ts (1)
1-5: LGTM!frontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsx (1)
1-113: LGTM!
- rehype-citations: skip [n] markers inside code/pre so code samples like arr[1] are not turned into citations. - CopyButton: track the reset timeout in a ref, clearing it on re-click and unmount. - SourceList: always render a clickable link for URL-bearing sources, including when the label equals the domain. - source-utils: reuse the computed kind instead of re-testing the URL regex. - CollapsibleBlock: wire aria-controls to the disclosed region id. - SourceStrip: expose aria-expanded on the "+N more" button. - Citation: keep URL-less citations keyboard-focusable. - Add CollapsibleBlock and SourceList unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Manush Maheshwari <manushm@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@frontends/ui/src/shared/components/Sources/SourceStrip.tsx`:
- Line 78: Update the disclosure control around the expanded rendering condition
in SourceStrip so the trigger remains mounted and keyboard-focusable after
expansion, with aria-expanded reflecting both states; alternatively, explicitly
move focus to the first revealed source when the trigger is unmounted. Preserve
the existing collapsed and expanded source display behavior.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 0273ceab-ea34-4421-9801-c0fba567ef34
📒 Files selected for processing (9)
frontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.spec.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/Sources/SourceList.spec.tsxfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/source-utils.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
frontends/ui/**/*.{js,ts,jsx,tsx,vue}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run npm lint, type-check, and build validation for UI changes in frontends/ui
Files:
frontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/Sources/SourceList.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/Sources/source-utils.ts
frontends/ui/**/*.{ts,tsx,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes
Files:
frontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/Sources/SourceList.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/Sources/source-utils.ts
frontends/ui/**/*
⚙️ CodeRabbit configuration file
frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.
Files:
frontends/ui/src/shared/components/Actions/CopyButton.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/Citation.tsxfrontends/ui/src/shared/components/Sources/SourceList.spec.tsxfrontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.tsfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/SourceList.tsxfrontends/ui/src/shared/components/Sources/source-utils.ts
🔇 Additional comments (10)
frontends/ui/src/shared/components/MarkdownRenderer/rehype-citations.ts (1)
19-20: 📐 Maintainability & Code QualityVerify regression coverage for code-like text.
The
code/preguard now prevents[1]andarr[1]from becoming<cite>, but the supplied cohort does not show that regression test. Confirmrehype-citations.spec.tscovers inline and fenced code; otherwise add it.As per path instructions, require tests for changed user-visible workflows.
Source: Path instructions
frontends/ui/src/shared/components/Sources/source-utils.ts (1)
53-53: LGTM!frontends/ui/src/shared/components/Sources/SourceStrip.tsx (1)
78-78: 📐 Maintainability & Code QualityProvide the required UI validation evidence.
The supplied context reports lint, type-check, and test validation as passing, but no screenshot is included for this visible UI change. Please attach one to the PR or confirm where it is recorded.
As per coding guidelines, “Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes.”
Source: Coding guidelines
frontends/ui/src/shared/components/Sources/SourceList.tsx (1)
40-50: LGTM!frontends/ui/src/shared/components/Sources/SourceList.spec.tsx (1)
24-48: LGTM!frontends/ui/src/shared/components/MarkdownRenderer/Citation.tsx (1)
37-37: LGTM!frontends/ui/src/shared/components/Actions/CopyButton.tsx (1)
6-6: LGTM!Also applies to: 24-38
frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.spec.tsx (1)
1-53: LGTM!frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx (2)
17-17: LGTM!Also applies to: 46-46
69-81: 🎯 Functional CorrectnessNo change needed:
aria-controlscan reference the animated region even though it unmounts when collapsed;aria-expandedalready exposes the toggle state.> Likely an incorrect or invalid review comment.
Signed-off-by: Manush Maheshwari <manushm@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx (1)
184-193: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winDialog semantics fixed, but focus management still missing.
role="dialog"/aria-modaladdresses the earlier finding. However, opening fullscreen never moves focus into the dialog, and closing it (via toggle or Escape at Line 117) never returns focus to the trigger button — screen-reader/keyboard users lose their focus position. The container also has notabIndex={-1}to be a valid focus target.♿️ Suggested minimal focus handling
+ const triggerRef = useRef<HTMLButtonElement>(null) + const dialogRef = useRef<HTMLDivElement>(null) + + useEffect(() => { + if (fullscreen) { + dialogRef.current?.focus() + } else { + triggerRef.current?.focus() + } + }, [fullscreen])And add
ref={dialogRef} tabIndex={-1}on the fullscreen container, andref={triggerRef}on the "Expand to fullscreen"/"Exit fullscreen" button.🤖 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 `@frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx` around lines 184 - 193, Update the Mermaid fullscreen component’s focus management: add refs for the fullscreen container and toggle button, make the dialog container focusable with tabIndex={-1}, move focus to the dialog when fullscreen opens, and restore focus to the trigger when fullscreen closes via the toggle or Escape handler. Anchor the changes in the existing fullscreen container and fullscreen toggle/Escape logic.
🤖 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 `@frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx`:
- Line 87: Add regression coverage in CollapsibleBlock.spec.tsx by forcing
useReducedMotion() to return true and asserting that CollapsibleBlock applies a
zero-duration transition while preserving existing disclosure and ARIA tests.
Run the required UI validation commands and provide the screenshot required for
this visible change.
---
Duplicate comments:
In `@frontends/ui/src/shared/components/Mermaid/MermaidBlock.tsx`:
- Around line 184-193: Update the Mermaid fullscreen component’s focus
management: add refs for the fullscreen container and toggle button, make the
dialog container focusable with tabIndex={-1}, move focus to the dialog when
fullscreen opens, and restore focus to the trigger when fullscreen closes via
the toggle or Escape handler. Anchor the changes in the existing fullscreen
container and fullscreen toggle/Escape logic.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: b7c255c8-2b35-43e1-b719-7b50859831bf
📒 Files selected for processing (8)
frontends/ui/src/app/globals.cssfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/lib/motion.spec.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
frontends/ui/**/*.{js,ts,jsx,tsx,vue}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run npm lint, type-check, and build validation for UI changes in frontends/ui
Files:
frontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx
frontends/ui/**/*.{ts,tsx,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
frontends/ui/**/*.{ts,tsx,jsx,js}: The UI is built with Next.js / React / TypeScript / Tailwind with KUI components; reuse existing KUI components and visual patterns rather than introducing new ones
Validate UI-affecting changes with npm run lint, npm run type-check, and npm run test:ci, and include a screenshot for visible changes
Files:
frontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx
frontends/ui/**/*
⚙️ CodeRabbit configuration file
frontends/ui/**/*: Review UI changes for strict TypeScript behavior, API contract alignment, auth/session handling, accessible controls,
resilient loading and error states, and report/chat state consistency. Prefer existing UI patterns and require tests
for changed user-visible workflows.
Files:
frontends/ui/src/shared/lib/motion.spec.tsxfrontends/ui/src/shared/components/Sources/SourceStrip.spec.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsxfrontends/ui/src/shared/components/Sources/parse-references.spec.tsfrontends/ui/src/shared/components/Sources/SourceStrip.tsxfrontends/ui/src/shared/components/Mermaid/MermaidBlock.tsxfrontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsxfrontends/ui/src/app/globals.css
🔇 Additional comments (8)
frontends/ui/src/shared/components/CollapsibleBlock/CollapsibleBlock.tsx (1)
20-20: LGTM!Also applies to: 48-48
frontends/ui/src/app/globals.css (1)
315-441: LGTM!frontends/ui/src/shared/lib/motion.spec.tsx (1)
1-47: LGTM!frontends/ui/src/shared/components/Sources/parse-references.spec.ts (1)
100-204: LGTM!frontends/ui/src/shared/components/Sources/SourceStrip.spec.tsx (1)
40-52: LGTM!frontends/ui/src/shared/components/Sources/SourceStrip.tsx (2)
58-89: LGTM!
21-45: 🔒 Security & PrivacyNo scheme-filter fix needed here.
parse-references.tsonly captureshttps://URLs, andmapCitationSource()only forwardscs.urlwheninferSourceKind()classifies it as web, soSourceCarddoes not exposejavascript:/data:anchors.> Likely an incorrect or invalid review comment.frontends/ui/src/shared/components/Mermaid/MermaidBlock.spec.tsx (1)
84-89: LGTM!
What this does
PR 1 of a UI-only chat redesign. Adds the foundational utilities and shared component library that later PRs build on. No user-visible change yet and no predictive/analytical/warehouse features — this is purely additive UI plumbing.
Utilities (
shared/lib)cn()— clsx + tailwind-merge className composition.titleCaseWords()/ACRONYMS— humanize snake_case identifiers into labels.AppMotionConfig— Motion provider that honorsprefers-reduced-motion.Shared components (
shared/components)Sources/*— source chips, list, and reference parsing (web + doc kinds).research/*—StatusDot,ToolCallRow, and a generic tool-label engine for the live research trace.Surface/Card,Actions/CopyButton,CollapsibleBlock,Mermaid.MarkdownRendererupgrade: ananswervariant, superscript citations with hover popovers, KaTeX math, and Mermaid diagrams. Prod's artifact-URL handling is preserved verbatim; chart fences fall through unchanged.Adds
clsx,tailwind-merge,motion,mermaid,katex,rehype-katex,remark-math,unist-util-visit.Testing
cn,humanize,parse-references,source-utils,research-labels,rehype-citations) is covered thoroughly.npm run type-checkandnpm run lintclean; full frontend suite green (1420 tests).Scope
Deliberately additive so it reviews in isolation. Follow-ups add the chat state/streaming plumbing, then the visual chat components that consume these primitives.
Screenshots
This PR adds the shared rendering primitives; they have no page of their own, so they are shown here rendering an answer in the chat (the surrounding shell/layout is added in #333):
🤖 Generated with Claude Code
Summary by CodeRabbit