Skip to content

Conversation

@yujonglee
Copy link
Contributor

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Oct 12, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds an in-app Orama-backed search system (context, types, indexing, multi-entity search), integrates search UI into sidebar and layout, adds search input enhancements and new result components, updates style guidance, adds dependencies, tweaks chat hotkey, adjusts timeline sizing, and removes a duplicate template.

Changes

Cohort / File(s) Summary
Style rules
apps/desktop2/.cursor/rules/style.mdc
Rewrote guidance: prefer avoiding code comments (if present document "Why"), reinstated Tailwind ClassNames guidance recommending cn (import it from @hypr/ui/lib/utils), pass arrays and split by logical grouping; adjusted import wording.
Dependencies
apps/desktop2/package.json
Added dependencies: @orama/highlight, @orama/orama, @orama/plugin-qps, and dompurify.
Search provider & types
apps/desktop2/src/contexts/search/index.tsx
New SearchProvider and useSearch hook: in-browser Orama indexing for sessions/humans/organizations, debounced multi-entity search with scoring/highlighting, grouping, filters/types exported, loading/indexing state and error handling.
Layout wiring
apps/desktop2/src/routes/app/main/_layout.tsx
Wraps main layout content with SearchProvider.
Sidebar integration
apps/desktop2/src/components/main/sidebar/index.tsx
Uses useSearch, derives showSearchResults from query, conditionally renders SearchResults when query exists, otherwise renders TimelineView; minor layout/class adjustments.
Search UI — new components
SearchResults
apps/desktop2/src/components/main/sidebar/search/index.tsx
SearchResultGroup
apps/desktop2/src/components/main/sidebar/search/group.tsx
SearchResultItem
apps/desktop2/src/components/main/sidebar/search/item.tsx
SearchNoResults
apps/desktop2/src/components/main/sidebar/search/empty.tsx
Added grouped search UI: SearchResults aggregates groups, renders headers and counts; SearchResultGroup paginates per-group and shows “Load more”; SearchResultItem sanitizes/highlights title/content, shows confidence indicator and opens target tab; SearchNoResults is empty state UI.
Search input enhancements
apps/desktop2/src/components/main/body/search.tsx
Shows loader when searching/indexing, adds hotkey mod+k to focus (plus arrow/enter handlers), uses context-driven query/focus handlers with forwarded ref, dynamic padding, and clear (X) button.
Chat hotkey
apps/desktop2/src/components/chat/index.tsx
Changes ChatFloatingButton hotkey from meta+j to mod+j.
Sessions templates
apps/desktop2/src/components/main/body/sessions/floating-regenerate-button.tsx
Removed duplicate "Brainstorming" entry from TEMPLATES.
Layout tweak
apps/desktop2/src/components/main/sidebar/timeline.tsx
Changed container class from flex-1 to h-full to adjust height behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Input as SearchInput
  participant Ctx as SearchProvider / useSearch
  participant Index as Orama
  participant Sidebar as SearchResults UI
  participant Tabs as Tabs Store

  User->>Input: Type / Hotkeys (mod+k, arrows, enter)
  Input->>Ctx: setQuery / onFocus / onBlur
  activate Ctx
  Ctx-->>Ctx: Debounce & normalize query
  Ctx->>Index: Search(query, filters, boosts)
  Index-->>Ctx: Hits + scores + highlights
  Ctx-->>Sidebar: grouped results { groups, totalResults, maxScore }
  deactivate Ctx

  Sidebar->>User: Render grouped results
  User->>Sidebar: Click "Load more"
  Sidebar->>Ctx: increase visible count (per-group)
  Ctx-->>Sidebar: updated group view

  User->>Sidebar: Click result item
  Sidebar->>Tabs: openCurrent(target tab)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description is empty and does not convey any information about the changes or objectives of this update, making it impossible to contextualize the modifications during review. Please add a descriptive summary that outlines the purpose of this pull request, including high-level objectives and key changes made to support global search rendering in the left sidebar.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly reflects the primary change of rendering global search results in the left sidebar and is directly related to the main updates introduced by this pull request.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b07b3b and af7e945.

📒 Files selected for processing (1)
  • apps/desktop2/src/components/main/sidebar/search/item.tsx (1 hunks)

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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 (2)
apps/desktop2/src/components/main/sidebar/search/empty.tsx (1)

1-14: Consider removing unnecessary cn usage.

Since none of the classNames have conditional logic, using cn adds unnecessary overhead. According to the style guidelines, cn should be used when there are "many classNames and they have conditional logic."

As per coding guidelines.

Apply this diff to simplify:

-import { cn } from "@hypr/ui/lib/utils";
-
 export function SearchNoResults() {
   return (
-    <div className={cn(["h-full flex items-center justify-center"])}>
-      <div className={cn(["text-center px-4"])}>
-        <p className={cn(["text-sm text-gray-600"])}>No results found</p>
-        <p className={cn(["text-xs text-gray-400 mt-1"])}>
+    <div className="h-full flex items-center justify-center">
+      <div className="text-center px-4">
+        <p className="text-sm text-gray-600">No results found</p>
+        <p className="text-xs text-gray-400 mt-1">
           Try a different search term
         </p>
       </div>
     </div>
   );
 }
apps/desktop2/src/components/main/sidebar/search/group.tsx (1)

1-47: Consider removing unnecessary cn usage.

While the component structure is solid (early return, clean layout), none of the classNames have conditional logic. According to the style guidelines, cn should be used when there are "many classNames and they have conditional logic."

As per coding guidelines.

Apply this diff to simplify:

-import { cn } from "@hypr/ui/lib/utils";
 import { type SearchResult } from "../../../../contexts/search";
 import { SearchResultItem } from "./item";
 
 export function SearchResultGroup({
   title,
   results,
   icon: Icon,
 }: {
   title: string;
   results: SearchResult[];
   icon: React.ComponentType<{ className?: string }>;
 }) {
   if (results.length === 0) {
     return null;
   }
 
   return (
-    <div className={cn(["mb-6"])}>
+    <div className="mb-6">
       <div
-        className={cn([
-          "sticky top-0 z-10",
-          "px-3 py-2 mb-2",
-          "flex items-center gap-2",
-          "bg-gray-50 rounded-lg",
-          "border-b border-gray-200",
-        ])}
+        className="sticky top-0 z-10 px-3 py-2 mb-2 flex items-center gap-2 bg-gray-50 rounded-lg border-b border-gray-200"
       >
-        <Icon className={cn(["h-4 w-4 text-gray-600"])} />
+        <Icon className="h-4 w-4 text-gray-600" />
         <h3
-          className={cn([
-            "text-xs font-semibold text-gray-700",
-            "uppercase tracking-wider",
-          ])}
+          className="text-xs font-semibold text-gray-700 uppercase tracking-wider"
         >
           {title}
         </h3>
-        <span className={cn(["text-xs text-gray-500 font-medium"])}>
+        <span className="text-xs text-gray-500 font-medium">
           ({results.length})
         </span>
       </div>
-      <div className={cn(["space-y-0.5 px-1"])}>
+      <div className="space-y-0.5 px-1">
         {results.map((result) => <SearchResultItem key={result.id} result={result} />)}
       </div>
     </div>
   );
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9461ec0 and 3ae5e91.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • apps/desktop2/.cursor/rules/style.mdc (1 hunks)
  • apps/desktop2/package.json (1 hunks)
  • apps/desktop2/src/components/chat/index.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/search.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/sessions/floating-regenerate-button.tsx (0 hunks)
  • apps/desktop2/src/components/main/sidebar/index.tsx (2 hunks)
  • apps/desktop2/src/components/main/sidebar/search/empty.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/group.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/index.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/item.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/timeline.tsx (1 hunks)
  • apps/desktop2/src/contexts/search.tsx (1 hunks)
  • apps/desktop2/src/routes/app/main/_layout.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/desktop2/src/components/main/body/sessions/floating-regenerate-button.tsx
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/sidebar/search/empty.tsx
  • apps/desktop2/src/components/chat/index.tsx
  • apps/desktop2/src/components/main/sidebar/timeline.tsx
  • apps/desktop2/src/components/main/sidebar/index.tsx
  • apps/desktop2/src/components/main/sidebar/search/item.tsx
  • apps/desktop2/src/components/main/body/search.tsx
  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/components/main/sidebar/search/index.tsx
  • apps/desktop2/src/contexts/search.tsx
  • apps/desktop2/src/routes/app/main/_layout.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/sidebar/search/empty.tsx
  • apps/desktop2/src/components/chat/index.tsx
  • apps/desktop2/src/components/main/sidebar/timeline.tsx
  • apps/desktop2/src/components/main/sidebar/index.tsx
  • apps/desktop2/src/components/main/sidebar/search/item.tsx
  • apps/desktop2/src/components/main/body/search.tsx
  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/components/main/sidebar/search/index.tsx
  • apps/desktop2/src/contexts/search.tsx
  • apps/desktop2/src/routes/app/main/_layout.tsx
🧠 Learnings (2)
📚 Learning: 2025-10-12T01:18:24.844Z
Learnt from: CR
PR: fastrepl/hyprnote#0
File: apps/desktop2/.cursor/rules/style.mdc:0-0
Timestamp: 2025-10-12T01:18:24.844Z
Learning: Applies to apps/desktop2/**/*.{ts,tsx,js,jsx} : Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "hypr/ui/lib/utils"; avoid using clsx/classnames directly.

Applied to files:

  • apps/desktop2/.cursor/rules/style.mdc
📚 Learning: 2025-10-12T01:18:24.844Z
Learnt from: CR
PR: fastrepl/hyprnote#0
File: apps/desktop2/.cursor/rules/style.mdc:0-0
Timestamp: 2025-10-12T01:18:24.844Z
Learning: Applies to apps/desktop2/**/*.{ts,tsx,js,jsx} : When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Applied to files:

  • apps/desktop2/.cursor/rules/style.mdc
🧬 Code graph analysis (8)
apps/desktop2/src/components/main/sidebar/search/empty.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/index.tsx (4)
apps/desktop2/src/contexts/search.tsx (1)
  • useSearch (312-318)
apps/desktop2/src/components/main/sidebar/new-note-button.tsx (1)
  • NewNoteButton (8-34)
apps/desktop2/src/components/main/sidebar/search/index.tsx (1)
  • SearchResults (8-52)
apps/desktop2/src/components/main/sidebar/timeline.tsx (1)
  • TimelineView (15-35)
apps/desktop2/src/components/main/sidebar/search/item.tsx (3)
apps/desktop2/src/contexts/search.tsx (1)
  • SearchResult (7-14)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/body/search.tsx (2)
apps/desktop2/src/contexts/search.tsx (1)
  • useSearch (312-318)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/group.tsx (3)
apps/desktop2/src/contexts/search.tsx (1)
  • SearchResult (7-14)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)
  • SearchResultItem (8-54)
apps/desktop2/src/components/main/sidebar/search/index.tsx (4)
apps/desktop2/src/contexts/search.tsx (1)
  • useSearch (312-318)
apps/desktop2/src/components/main/sidebar/search/empty.tsx (1)
  • SearchNoResults (3-14)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/group.tsx (1)
  • SearchResultGroup (5-47)
apps/desktop2/src/contexts/search.tsx (1)
crates/db-script/src/lib.rs (1)
  • transcript (10-21)
apps/desktop2/src/routes/app/main/_layout.tsx (1)
apps/desktop2/src/contexts/search.tsx (1)
  • SearchProvider (192-310)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (7)
apps/desktop2/.cursor/rules/style.mdc (1)

5-7: LGTM!

The updated guidance clarifies when to use cn and adds helpful structure about splitting by logical grouping while preserving the array requirement.

apps/desktop2/src/components/chat/index.tsx (1)

16-16: LGTM!

Using mod instead of meta ensures cross-platform compatibility (Cmd on macOS, Ctrl on Windows/Linux).

apps/desktop2/src/components/main/sidebar/timeline.tsx (1)

19-19: LGTM!

The change to h-full aligns with SearchResults component styling for consistent height behavior in the sidebar's conditional rendering.

apps/desktop2/src/routes/app/main/_layout.tsx (1)

4-5: LGTM!

The SearchProvider is properly integrated into the provider hierarchy, enabling search context for all child components while maintaining the existing layout structure.

Also applies to: 17-20

apps/desktop2/src/components/main/sidebar/index.tsx (2)

5-5: LGTM!

The search integration is clean and straightforward. Conditional rendering based on query.trim() appropriately switches between search results and timeline view.

Also applies to: 8-8, 13-15


37-44: LGTM!

The layout structure correctly accommodates both SearchResults and TimelineView with proper overflow handling. The added gap-1 improves spacing between sidebar sections.

apps/desktop2/package.json (1)

25-25: @orama/orama is up-to-date (v3.1.15) with no known security advisories.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
apps/desktop2/src/contexts/search/index.tsx (1)

221-226: Rename helper to avoid shadowing toString.

Naming this helper toString shadows the global and is flagged by Biome. Rename it (e.g., toNonEmptyString) and update the callers.

Apply this diff:

-function toString(value: unknown): string | null {
+function toNonEmptyString(value: unknown): string | null {
   if (typeof value === "string" && value.length > 0) {
     return value;
   }
   return null;
 }
-      folder_id: toString(row.folder_id),
-      event_id: toString(row.event_id),
+      folder_id: toNonEmptyString(row.folder_id),
+      event_id: toNonEmptyString(row.event_id),
-      org_id: toString(row.org_id),
+      org_id: toNonEmptyString(row.org_id),

Also applies to: 257-260, 289-290

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ae5e91 and 98827ba.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • apps/desktop2/.cursor/rules/style.mdc (1 hunks)
  • apps/desktop2/package.json (1 hunks)
  • apps/desktop2/src/components/main/body/search.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/empty.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/group.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/index.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/search/item.tsx (1 hunks)
  • apps/desktop2/src/contexts/search/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop2/src/components/main/sidebar/search/index.tsx
  • apps/desktop2/package.json
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/contexts/search/index.tsx
  • apps/desktop2/src/components/main/sidebar/search/item.tsx
  • apps/desktop2/src/components/main/body/search.tsx
  • apps/desktop2/src/components/main/sidebar/search/empty.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/contexts/search/index.tsx
  • apps/desktop2/src/components/main/sidebar/search/item.tsx
  • apps/desktop2/src/components/main/body/search.tsx
  • apps/desktop2/src/components/main/sidebar/search/empty.tsx
🧠 Learnings (2)
📚 Learning: 2025-10-12T01:18:24.844Z
Learnt from: CR
PR: fastrepl/hyprnote#0
File: apps/desktop2/.cursor/rules/style.mdc:0-0
Timestamp: 2025-10-12T01:18:24.844Z
Learning: Applies to apps/desktop2/**/*.{ts,tsx,js,jsx} : Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "hypr/ui/lib/utils"; avoid using clsx/classnames directly.

Applied to files:

  • apps/desktop2/.cursor/rules/style.mdc
📚 Learning: 2025-10-12T01:18:24.844Z
Learnt from: CR
PR: fastrepl/hyprnote#0
File: apps/desktop2/.cursor/rules/style.mdc:0-0
Timestamp: 2025-10-12T01:18:24.844Z
Learning: Applies to apps/desktop2/**/*.{ts,tsx,js,jsx} : When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Applied to files:

  • apps/desktop2/.cursor/rules/style.mdc
🧬 Code graph analysis (5)
apps/desktop2/src/components/main/sidebar/search/group.tsx (3)
apps/desktop2/src/contexts/search/index.tsx (2)
  • SearchGroup (36-45)
  • useSearch (619-625)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)
  • SearchResultItem (8-69)
apps/desktop2/src/contexts/search/index.tsx (1)
crates/db-script/src/lib.rs (1)
  • transcript (10-21)
apps/desktop2/src/components/main/sidebar/search/item.tsx (3)
apps/desktop2/src/contexts/search/index.tsx (1)
  • SearchResult (20-34)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/body/search.tsx (2)
apps/desktop2/src/contexts/search/index.tsx (1)
  • useSearch (619-625)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/empty.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
🪛 ast-grep (0.39.6)
apps/desktop2/src/components/main/sidebar/search/item.tsx

[warning] 48-48: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)


[warning] 62-62: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
apps/desktop2/src/contexts/search/index.tsx

[error] 221-221: Do not shadow the global "toString" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

apps/desktop2/src/components/main/sidebar/search/item.tsx

[error] 49-49: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 63-63: 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. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/desktop2/src/contexts/search/index.tsx (1)

466-486: Critical issue already flagged: Await the create() call.

This issue was previously identified in past review comments. The create() function returns a Promise<Orama>, but it's not awaited here. This means db (and subsequently oramaInstance.current) will be a Promise object, causing insert() and search() calls to fail when they attempt to access Orama internals.

The createIndex callback should be async and await the create call:

-  const createIndex = useCallback(async () => {
+  const createIndex = useCallback(async () => {
     if (!persistedStore || isIndexing) {
       return;
     }
 
     setIsIndexing(true);
 
     try {
-      const db = create({
+      const db = await create({
         schema: {
🧹 Nitpick comments (2)
apps/desktop2/src/components/main/sidebar/search/group.tsx (1)

83-83: Use LOAD_MORE_STEP constant in button text.

The button displays "Load 5 more" as hardcoded text while the onClick handler increments by LOAD_MORE_STEP. If LOAD_MORE_STEP changes, the text will be stale.

Apply this diff:

-          <span>Load 5 more</span>
+          <span>Load {LOAD_MORE_STEP} more</span>
apps/desktop2/src/contexts/search/index.tsx (1)

216-221: Rename toString to avoid shadowing the global property.

The function name toString shadows the global toString property, which can cause confusion about variable origin and potential issues with tooling.

Apply this diff:

-function toString(value: unknown): string {
+function toStringValue(value: unknown): string {
   if (typeof value === "string" && value.length > 0) {
     return value;
   }
   return "";
 }

Then update all call sites at lines 252, 253, 284, and 308:

-      folder_id: toString(row.folder_id),
-      event_id: toString(row.event_id),
+      folder_id: toStringValue(row.folder_id),
+      event_id: toStringValue(row.event_id),
-      org_id: toString(row.org_id),
+      org_id: toStringValue(row.org_id),

Based on static analysis hints.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98827ba and cbc3c96.

📒 Files selected for processing (2)
  • apps/desktop2/src/components/main/sidebar/search/group.tsx (1 hunks)
  • apps/desktop2/src/contexts/search/index.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/contexts/search/index.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/sidebar/search/group.tsx
  • apps/desktop2/src/contexts/search/index.tsx
🧬 Code graph analysis (2)
apps/desktop2/src/components/main/sidebar/search/group.tsx (3)
apps/desktop2/src/contexts/search/index.tsx (1)
  • SearchGroup (36-43)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)
  • SearchResultItem (8-69)
apps/desktop2/src/contexts/search/index.tsx (1)
crates/db-script/src/lib.rs (1)
  • transcript (10-21)
🪛 Biome (2.1.2)
apps/desktop2/src/contexts/search/index.tsx

[error] 216-216: Do not shadow the global "toString" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)

Copy link

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbc3c96 and 066b7d5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • apps/desktop2/package.json (2 hunks)
  • apps/desktop2/src/components/main/sidebar/search/item.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop2/package.json
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/sidebar/search/item.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/sidebar/search/item.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/sidebar/search/item.tsx (3)
apps/desktop2/src/contexts/search/index.tsx (1)
  • SearchResult (20-34)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
🪛 ast-grep (0.39.6)
apps/desktop2/src/components/main/sidebar/search/item.tsx

[warning] 59-59: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)


[warning] 73-73: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
apps/desktop2/src/components/main/sidebar/search/item.tsx

[error] 60-60: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 74-74: 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. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (1)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)

9-80: XSS mitigation implemented—good work!

The component correctly sanitizes result.titleHighlighted and result.contentHighlighted before rendering with dangerouslySetInnerHTML, addressing the XSS concerns from previous reviews. The use of useMemo to cache sanitized values is appropriate, and the overall component structure (event handling, icon selection, confidence display) is clean and follows React best practices.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a 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 (1)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)

29-31: Consider truncating text content instead of raw HTML.

Slicing the HTML string at position 200 before sanitization can break tags mid-stream (e.g., cutting </mark> to </mar). While DOMPurify safely cleans up broken tags, the visual result may truncate highlights unexpectedly or include fewer than 200 characters of visible text due to HTML overhead.

A more display-friendly approach:

 const sanitizedContent = useMemo(
-  () => DOMPurify.sanitize(result.contentHighlighted.slice(0, 200), { ALLOWED_TAGS: ['mark'], ALLOWED_ATTR: [] }),
+  () => {
+    const full = DOMPurify.sanitize(result.contentHighlighted, { ALLOWED_TAGS: ['mark'], ALLOWED_ATTR: [] });
+    const temp = document.createElement('div');
+    temp.innerHTML = full;
+    const text = temp.textContent || '';
+    if (text.length <= 200) return full;
+    // Fallback: slice and re-sanitize
+    return DOMPurify.sanitize(result.contentHighlighted.slice(0, 200), { ALLOWED_TAGS: ['mark'], ALLOWED_ATTR: [] });
+  },
   [result.contentHighlighted],
 );

Alternatively, use CSS text-overflow: ellipsis with a fixed height container instead of pre-truncating.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 066b7d5 and 4b07b3b.

📒 Files selected for processing (1)
  • apps/desktop2/src/components/main/sidebar/search/item.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/desktop2/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop2/.cursor/rules/style.mdc)

apps/desktop2/**/*.{ts,tsx,js,jsx}: Use the cn utility for conditional Tailwind classNames, importing it as: import { cn } from "@hypr/ui/lib/utils"; avoid using clsx/classnames directly.
When calling cn, always pass an array of class segments (e.g., cn(["base", condition && "modifier"]))

Files:

  • apps/desktop2/src/components/main/sidebar/search/item.tsx
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/sidebar/search/item.tsx
🧬 Code graph analysis (1)
apps/desktop2/src/components/main/sidebar/search/item.tsx (3)
apps/desktop2/src/contexts/search/index.tsx (1)
  • SearchResult (20-34)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (31-121)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
🪛 ast-grep (0.39.6)
apps/desktop2/src/components/main/sidebar/search/item.tsx

[warning] 59-59: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)


[warning] 73-73: 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 [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
apps/desktop2/src/components/main/sidebar/search/item.tsx

[error] 60-60: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 74-74: 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: .github/workflows/fmt.yaml
apps/desktop2/src/components/main/sidebar/search/item.tsx

[error] 1-1: dprint formatting check failed. Found 1 not formatted file. Run '~/.dprint/bin/dprint check --config dprint.json' to fix formatting.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-14)
🔇 Additional comments (1)
apps/desktop2/src/components/main/sidebar/search/item.tsx (1)

24-32: LGTM! Previous XSS concerns addressed.

The sanitization implementation correctly addresses the previous security concerns by:

  • Using DOMPurify with a restrictive allowlist (ALLOWED_TAGS: ['mark'], ALLOWED_ATTR: [])
  • Sanitizing both title and content before rendering
  • Memoizing sanitized values for performance

The configuration properly restricts allowed HTML to only <mark> tags, minimizing XSS attack surface while preserving search highlights.

Based on learnings

@yujonglee yujonglee merged commit 79bdf28 into main Oct 12, 2025
4 checks passed
@yujonglee yujonglee deleted the global-search-rendering branch October 12, 2025 11:13
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.

2 participants