-
Notifications
You must be signed in to change notification settings - Fork 37
Linter fixes #44
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
base: main
Are you sure you want to change the base?
Linter fixes #44
Conversation
Add getBackendURL to map endpoints Add parsing for CA RA response Update README with CA RAG backend option
Add toggle for data stream display Add environment variable for data stream toggle
Make the theme update cross-tab (local -> session storage)
Toggle background with underlying div
Reword 'transcript' references to 'entries' Minor typo Add pending / ingested toggle in database updates page
WalkthroughAdds Live Data Streaming API, UI components, and history page; introduces ThemeContext and wraps the app; adds CA‑RAG control flow in chat API; updates chat and markdown components, types, and settings storage (sessionStorage → localStorage); Docker and _document script handling adjusted; many minor import/prop hygiene edits. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Home as Home (page)
participant Manager as DataStreamManager
participant Display as DataStreamDisplay
participant API as /api/update-data-stream
participant DBPage as /database-updates
User->>Home: Toggle Data Stream Display
Home->>Manager: mount/update (selectedConversation)
Manager->>Display: render with selectedStream(s)
loop Poll live text (100ms)
Display->>API: GET ?stream={id}
API-->>Display: { text }
Display->>Display: update UI, autoscroll
end
loop Poll streams (2s)
Manager->>API: GET
API-->>Manager: [streams]
Manager->>Home: update dataStreams (if changed)
end
DBPage->>API: GET ?type=finalized
API-->>DBPage: [finalized entries]
DBPage->>API: PATCH / update pending (by uuid)
sequenceDiagram
autonumber
participant Client as Client UI
participant API as /api/chat
participant Backend as CA‑RAG Backend
Client->>API: POST chat (chatCompletionURL = /chat/ca-rag, conversationId)
API->>API: buildContextAwareRAGPayload(conversationId)
API->>Backend: (if not initialized) POST /init { id: ragUuid+conversationId }
Backend-->>API: 200 OK
API->>Backend: POST /call with built payload
Backend-->>API: response (result/content)
API-->>Client: normalized chat response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
pages/_document.tsx (1)
1-26: Do not usenext/scriptin_document.
next/scriptis unsupported inside a custom Document and will trigger Next's@next/next/no-script-in-documenterror (“next/script cannot be used in next/document”). Switch back to a plain<script>tag (or move the script to_appif you need the Script component API) to keep the build from breaking.-import Script from 'next/script'; ... - <Script src="/__ENV.js" strategy="beforeInteractive" /> + <script src="/__ENV.js"></script>components/Chat/ChatInteractionMessage.tsx (1)
3-28: Reset modal state when dismissed
userInputanderrornow live across modal openings. If a user closes after triggering a validation error, the old text and error resurface the next time the modal opens. Reset the local state whenisOpenflips tofalseso each interaction starts clean. This also requires addinguseEffectto the import.-import { useState } from 'react'; +import { useEffect, useState } from 'react'; … const [userInput, setUserInput] = useState(''); const [error, setError] = useState(''); + + useEffect(() => { + if (!isOpen) { + setUserInput(''); + setError(''); + } + }, [isOpen]);utils/app/settings.ts (1)
9-22: Guard localStorage usage against SSR
localStorageis undefined during SSR/build.getSettings()is invoked in contexts/ThemeContext.tsx at module init (Line 19) before the provider mounts, so on the server this will throw and break page rendering. Please gate both reads/writes withtypeof window !== 'undefined', falling back to defaults when not in a browser.Apply this diff:
-export const getSettings = (): Settings => { +export const getSettings = (): Settings => { let settings: Settings = { theme: 'light', }; - const settingsJson = localStorage.getItem(STORAGE_KEY); + if (typeof window === 'undefined') { + return settings; + } + + const settingsJson = window.localStorage.getItem(STORAGE_KEY); if (settingsJson) { try { let savedSettings = JSON.parse(settingsJson) as Settings; settings = Object.assign(settings, savedSettings); } catch (e) { console.error(e); } } return settings; }; export const saveSettings = (settings: Settings) => { - localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); + if (typeof window === 'undefined') { + return; + } + + window.localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); };components/Markdown/Chart.tsx (1)
3-31: Mark Chart and its consumers as client components
Add"use client"as the very first line incomponents/Markdown/Chart.tsxand in any file importing it (e.g.components/Markdown/CustomComponents.tsx).components/Chat/ChatMessage.tsx (1)
15-339: Do not render unsanitized raw HTMLAdding
rehypeRawmeans we now inject raw HTML coming straight frommessage.contentinto the DOM. Any user can paste something like<img src=x onerror=alert(1)>, and React will pass thatonerrorattribute through, triggering an XSS when the message renders. Assistant messages can echo the same payload, so this is exploitable both ways. We need to sanitize before shipping.Please either drop
rehypeRawor pair it with a sanitizer (e.g.,rehype-sanitizeconfigured to allow only the tags/attributes we actually need, such asdetails,summary, and math markup).-import rehypeRaw from 'rehype-raw'; -import remarkGfm from 'remark-gfm'; -import remarkMath from 'remark-math'; +import rehypeRaw from 'rehype-raw'; +import rehypeSanitize from 'rehype-sanitize'; +import remarkGfm from 'remark-gfm'; +import remarkMath from 'remark-math'; … - rehypePlugins={[rehypeRaw] as any} + rehypePlugins={[rehypeRaw, rehypeSanitize] as any} … - rehypePlugins={[rehypeRaw] as any} + rehypePlugins={[rehypeRaw, rehypeSanitize] as any}Be sure to extend the sanitize schema so the components you rely on keep rendering, but event-handler attributes and other dangerous markup stay blocked.
🧹 Nitpick comments (1)
components/DataStreamDisplay/DataStreamDisplay.tsx (1)
98-100: Remove leftover timestamp debug logThis console log fires on every finalized-data fetch and quickly drowns the DevTools console. Please drop it once the debugging session is over.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (45)
DATA_STREAMING.md(1 hunks)Dockerfile(1 hunks)README.md(1 hunks)components/Avatar/SystemAvatar.tsx(1 hunks)components/Avatar/UserAvatar.tsx(0 hunks)components/Chat/Chat.tsx(12 hunks)components/Chat/ChatHeader.tsx(5 hunks)components/Chat/ChatInput.tsx(9 hunks)components/Chat/ChatInteractionMessage.tsx(1 hunks)components/Chat/ChatMessage.tsx(2 hunks)components/Chat/MemoizedChatMessage.tsx(1 hunks)components/Chat/Regenerate.tsx(0 hunks)components/Chatbar/Chatbar.context.tsx(1 hunks)components/Chatbar/Chatbar.tsx(1 hunks)components/Chatbar/components/ChatFolders.tsx(0 hunks)components/Chatbar/components/ChatbarSettings.tsx(1 hunks)components/Chatbar/components/ClearConversations.tsx(0 hunks)components/Chatbar/components/Conversation.tsx(0 hunks)components/DataStreamDisplay/DataStreamDisplay.tsx(1 hunks)components/Folder/Folder.tsx(1 hunks)components/Markdown/Chart.tsx(1 hunks)components/Markdown/CodeBlock.tsx(1 hunks)components/Markdown/CustomComponents.tsx(2 hunks)components/Markdown/CustomDetails.tsx(1 hunks)components/Markdown/CustomSummary.tsx(1 hunks)components/Markdown/Image.tsx(2 hunks)components/Markdown/Loading.tsx(0 hunks)components/Markdown/MemoizedReactMarkdown.tsx(1 hunks)components/Markdown/Video.tsx(2 hunks)components/Search/Search.tsx(1 hunks)components/Settings/Import.tsx(2 hunks)components/Settings/SettingDialog.tsx(3 hunks)components/Sidebar/Sidebar.tsx(2 hunks)components/Spinner/Spinner.tsx(0 hunks)contexts/ThemeContext.tsx(1 hunks)pages/_app.tsx(2 hunks)pages/_document.tsx(2 hunks)pages/api/chat.ts(4 hunks)pages/api/home/home.context.tsx(1 hunks)pages/api/home/home.state.tsx(2 hunks)pages/api/home/home.tsx(8 hunks)pages/api/update-data-stream.ts(1 hunks)pages/database-updates.tsx(1 hunks)types/chat.ts(2 hunks)utils/app/settings.ts(2 hunks)
💤 Files with no reviewable changes (7)
- components/Markdown/Loading.tsx
- components/Chat/Regenerate.tsx
- components/Chatbar/components/Conversation.tsx
- components/Chatbar/components/ClearConversations.tsx
- components/Spinner/Spinner.tsx
- components/Avatar/UserAvatar.tsx
- components/Chatbar/components/ChatFolders.tsx
🧰 Additional context used
🧬 Code graph analysis (14)
contexts/ThemeContext.tsx (1)
utils/app/settings.ts (2)
getSettings(5-19)saveSettings(21-23)
pages/_app.tsx (1)
contexts/ThemeContext.tsx (1)
ThemeProvider(19-61)
components/Chatbar/Chatbar.context.tsx (1)
types/chat.ts (1)
Conversation(21-28)
components/Markdown/MemoizedReactMarkdown.tsx (1)
__mocks__/react-markdown.js (1)
ReactMarkdown(7-9)
pages/api/chat.ts (1)
types/chat.ts (1)
ChatBody(14-19)
pages/database-updates.tsx (1)
contexts/ThemeContext.tsx (1)
useTheme(11-17)
components/Chat/ChatHeader.tsx (1)
contexts/ThemeContext.tsx (1)
useTheme(11-17)
pages/api/home/home.context.tsx (1)
types/chat.ts (1)
Conversation(21-28)
components/Chat/Chat.tsx (2)
types/websocket.ts (1)
WebSocketInbound(59-63)types/chat.ts (1)
Message(1-10)
components/Chat/ChatMessage.tsx (1)
types/chat.ts (1)
Message(1-10)
pages/api/home/home.tsx (5)
pages/api/home/home.state.tsx (1)
initialState(34-82)contexts/ThemeContext.tsx (1)
useTheme(11-17)utils/app/conversation.ts (1)
saveConversation(26-38)components/Chat/ChatHeader.tsx (1)
ChatHeader(20-262)components/Chat/Chat.tsx (1)
Chat(137-1388)
components/Settings/SettingDialog.tsx (1)
contexts/ThemeContext.tsx (1)
useTheme(11-17)
components/Markdown/CustomComponents.tsx (5)
components/Markdown/CodeBlock.tsx (1)
CodeBlock(17-125)components/Markdown/Image.tsx (1)
Image(78-78)components/Markdown/Video.tsx (1)
Video(45-45)components/Markdown/CustomDetails.tsx (1)
CustomDetails(8-141)components/Markdown/CustomSummary.tsx (1)
CustomSummary(15-82)
components/Chat/ChatInput.tsx (1)
types/chat.ts (1)
Message(1-10)
🔇 Additional comments (14)
pages/api/home/home.context.tsx (1)
14-21: Consistent unused-parameter markerRenaming the function signatures in the context props to
_…keeps the contract intact while satisfying the lint rule for unused parameters. Looks good.components/Markdown/CodeBlock.tsx (1)
2-2: Unused import cleanupDropping the unused
MouseEventimport resolves the lint warning without touching runtime behavior. ✅components/Markdown/CustomDetails.tsx (1)
101-101: ClassName formatting tidy-upThanks for trimming the extra whitespace in the class list; keeps the markup lint-happy with no functional change.
components/Markdown/Video.tsx (1)
9-46: Memoized alias exportWrapping the memoized implementation in
VideoComponentand exportingVideoas an alias maintains the public API while appeasing the linter about display names. All good.README.md (1)
88-97: Documentation sync with new endpointsThe additions for
/chat/ca-ragand the live data streaming section line up with the recent feature work—thanks for keeping the README in step.types/chat.ts (1)
17-28: Type surface aligned with new streaming stateAdding
conversationIdandselectedStreamto the chat types captures the new payload/state requirements while remaining optional—nice incremental update.pages/_app.tsx (1)
7-29: ThemeProvider wrapSlotting
ThemeProvideraround the app component keeps the query client setup unchanged and unlocks the new theme context globally. 👍components/Markdown/MemoizedReactMarkdown.tsx (1)
4-11: Named memoized componentIntroducing
MemoizedReactMarkdownComponentwith an explicitdisplayNameaddresses the lint noise while preserving the memo logic. Looks solid.components/Avatar/SystemAvatar.tsx (1)
1-10: LGTMImport cleanup looks good; no behavioral changes.
components/Chat/MemoizedChatMessage.tsx (1)
2-16: LGTMConsolidating the lodash import resolves the lint warning without changing behavior.
components/Markdown/CustomSummary.tsx (1)
38-79: LGTMWhitespace normalization and removal of the unused icon keep the component tidy.
pages/api/home/home.state.tsx (1)
30-82: LGTMThe new data stream fields are wired consistently with existing env-flag patterns.
Dockerfile (1)
21-37: LGTMPropagating NEXT_PUBLIC build args via ENV unblocks linted references during
yarn build.components/Folder/Folder.tsx (1)
24-33: LGTMParameter naming tweak silences the unused-arg lint without affecting behavior.
| const interval = setInterval(async () => { | ||
| try { | ||
| // Get text for selected stream | ||
| const textRes = await fetch(`/api/update-data-stream?stream=${selectedStream}`); | ||
| if (textRes.ok) { | ||
| const textData = await textRes.json(); | ||
| if (typeof textData.text === 'string') { | ||
| setText(textData.text); | ||
| } | ||
| } | ||
| } catch (err) { | ||
| // Optionally handle error | ||
| } | ||
| }, 100); | ||
| return () => clearInterval(interval); |
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.
Dial back the 100 ms polling cadence
We now hit /api/update-data-stream ten times per second for every open tab. That’s a hot loop that will saturate the route and the upstream data source under even modest load, especially once multiple users watch the page. Please stretch the interval (e.g., 1–2 s) or switch to a push mechanism such as SSE/websocket before merging.
- }, 100);
+ }, 1000);📝 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.
| const interval = setInterval(async () => { | |
| try { | |
| // Get text for selected stream | |
| const textRes = await fetch(`/api/update-data-stream?stream=${selectedStream}`); | |
| if (textRes.ok) { | |
| const textData = await textRes.json(); | |
| if (typeof textData.text === 'string') { | |
| setText(textData.text); | |
| } | |
| } | |
| } catch (err) { | |
| // Optionally handle error | |
| } | |
| }, 100); | |
| return () => clearInterval(interval); | |
| const interval = setInterval(async () => { | |
| try { | |
| // Get text for selected stream | |
| const textRes = await fetch(`/api/update-data-stream?stream=${selectedStream}`); | |
| if (textRes.ok) { | |
| const textData = await textRes.json(); | |
| if (typeof textData.text === 'string') { | |
| setText(textData.text); | |
| } | |
| } | |
| } catch (err) { | |
| // Optionally handle error | |
| } | |
| }, 1000); | |
| return () => clearInterval(interval); |
🤖 Prompt for AI Agents
components/DataStreamDisplay/DataStreamDisplay.tsx around lines 30-44: the
component currently polls /api/update-data-stream every 100ms which will
overload the route under real use; change the polling interval to a much lower
frequency (e.g., 1000–2000 ms) or replace the polling with a server push
approach (SSE or websocket) — if staying with polling, update the setInterval
delay to 1000 or 2000 and ensure proper cleanup remains; if switching to
SSE/websocket, open a persistent connection on mount, listen for messages to
setText, and close the connection on unmount.
| const streamTexts: { [streamId: string]: TextData } = {}; | ||
| const finalizedEntries: FinalizedDataEntry[] = []; |
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.
Avoid module-scoped state in API handlers
streamTexts and finalizedEntries live at module scope, so they reset whenever the function spins up on a new worker/lambda (which happens routinely in Next.js production) or when multiple instances serve requests in parallel. As soon as that happens the live/finalized data disappears, making the endpoint unreliable outside a single-process dev server. Please move this state into durable storage (database/Redis/etc.) or another shared backend so the data survives restarts and is consistent across instances.
🤖 Prompt for AI Agents
In pages/api/update-data-stream.ts around lines 21 to 22, the module-scoped
variables streamTexts and finalizedEntries are used to store request state,
which is unsafe because they are reset across process restarts and not shared
across instances; move this state into a durable/shared store (e.g., a database
or Redis) instead: replace reads/writes to streamTexts/finalizedEntries with
async calls to the chosen backend (get/update/append operations), initialize
connections outside hot paths, handle errors and retries, and ensure atomic
operations or transactions where concurrent requests may conflict so data
persists and remains consistent across workers.
| setEntries(data.entries || []); | ||
|
|
||
| // Extract unique stream IDs | ||
| const streamIds = data.entries.map((t: FinalizedDataEntry) => t.stream_id); | ||
| const streams = Array.from(new Set<string>(streamIds)).sort((a: string, b: string) => a.localeCompare(b)); | ||
| setAvailableStreams(streams); | ||
|
|
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.
Guard against missing entries before mapping.
If /api/update-data-stream ever omits the entries array (e.g., on an empty response or transient backend glitch), data.entries.map(...) throws at runtime even though you just defaulted state to []. Please reuse the safeguarded array for both state and the stream-id extraction.
- setEntries(data.entries || []);
-
- // Extract unique stream IDs
- const streamIds = data.entries.map((t: FinalizedDataEntry) => t.stream_id);
+ const fetchedEntries = (data.entries ?? []) as FinalizedDataEntry[];
+ setEntries(fetchedEntries);
+
+ // Extract unique stream IDs
+ const streamIds = fetchedEntries.map((t) => t.stream_id);📝 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.
| setEntries(data.entries || []); | |
| // Extract unique stream IDs | |
| const streamIds = data.entries.map((t: FinalizedDataEntry) => t.stream_id); | |
| const streams = Array.from(new Set<string>(streamIds)).sort((a: string, b: string) => a.localeCompare(b)); | |
| setAvailableStreams(streams); | |
| const fetchedEntries = (data.entries ?? []) as FinalizedDataEntry[]; | |
| setEntries(fetchedEntries); | |
| // Extract unique stream IDs | |
| const streamIds = fetchedEntries.map((t) => t.stream_id); | |
| const streams = Array.from(new Set<string>(streamIds)) | |
| .sort((a: string, b: string) => a.localeCompare(b)); | |
| setAvailableStreams(streams); |
🤖 Prompt for AI Agents
In pages/database-updates.tsx around lines 64 to 70, the code uses
data.entries.map(...) which will throw if data.entries is undefined; instead
create a safeguarded variable (e.g., const entries = data.entries || []), call
setEntries(entries), then derive streamIds from entries (const streamIds =
entries.map(...)), and use that for creating the unique sorted streams before
calling setAvailableStreams; ensure types match (FinalizedDataEntry[]) when
declaring the safeguarded array.
0f4d904 to
d440b02
Compare
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: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
components/Avatar/SystemAvatar.tsx (1)
7-7: Dynamic Tailwind class names won't be included in the CSS bundle.The template literals
w-${width}andh-${height}construct class names at runtime, but Tailwind's static analysis won't detect these dynamic patterns. These classes will be missing from the final CSS, breaking the intended sizing behavior.Apply this diff to use inline styles or a fixed set of Tailwind classes:
Solution 1 (Recommended): Use inline styles for dynamic sizing
- className={`w-${width} h-${height} flex justify-center items-center rounded-full bg-[#004D3C] text-white`} + className="flex justify-center items-center rounded-full bg-[#004D3C] text-white" + style={{ width: `${width * 4}px`, height: `${height * 4}px` }}Solution 2: Use a whitelist of allowed sizes with conditional rendering
+const sizeClasses = { + 7: 'w-7 h-7', + 8: 'w-8 h-8', + // add other sizes as needed +}; + export const SystemAgentAvatar = ({ height = 7, width = 7 }) => { + const sizeClass = height === width ? sizeClasses[height] || 'w-7 h-7' : 'w-7 h-7'; return ( <div - className={`w-${width} h-${height} flex justify-center items-center rounded-full bg-[#004D3C] text-white`} + className={`${sizeClass} flex justify-center items-center rounded-full bg-[#004D3C] text-white`}pages/api/home/home.tsx (1)
39-48: workflow should be stateful; otherwise title/description won’t update after mountMutating a local let in an effect doesn’t re-render. Use state and set it in the effect.
Apply:
- let workflow = APPLICATION_NAME; + const [workflow, setWorkflow] = useState(APPLICATION_NAME);And in the effect:
- workflow = getWorkflowName(); + setWorkflow(getWorkflowName());Update deps:
- }, [dispatch, t, setLightMode]); + }, [dispatch, t, setLightMode, setWorkflow]);Additionally, add useState import:
- import { useEffect, useRef } from 'react'; + import { useEffect, useRef, useState } from 'react';
♻️ Duplicate comments (2)
pages/api/update-data-stream.ts (1)
21-22: Module-scoped state makes the API non-durable across instances/restartsThis was already flagged in a previous review. Move streamTexts/finalizedEntries to durable/shared storage (DB/Redis/etc.) to work in serverless/multi-instance deployments.
pages/api/home/home.tsx (1)
11-13: DataStreamManager still mutates context state via in-place sortThe imported DataStreamManager uses currentStreams.sort() and newStreams.sort(), which mutates context state outside the reducer. Clone before sorting and dispatch a cloned array.
Change in components/DataStreamDisplay/DataStreamManager.tsx:
- const currentStreams = dataStreams || []; - const newStreams = streamsData.streams; - if (JSON.stringify(currentStreams.sort()) !== JSON.stringify(newStreams.sort())) { - dispatch({ field: 'dataStreams', value: newStreams }); - } + const currentStreamsSorted = [...(dataStreams ?? [])].sort(); + const nextStreamsSorted = [...streamsData.streams].sort(); + if (JSON.stringify(currentStreamsSorted) !== JSON.stringify(nextStreamsSorted)) { + dispatch({ field: 'dataStreams', value: nextStreamsSorted }); + }
🧹 Nitpick comments (14)
components/Settings/Import.tsx (2)
10-10: Misleading parameter name change.Prefixing the callback parameter with
_conventionally signals it's unused, but implementers of theonImportcallback will use this parameter. The underscore is misleading in a type definition where the parameter name serves as documentation.Consider either:
- Reverting to
dataand configuring ESLint to ignore parameter names in type definitions (e.g., via@typescript-eslint/no-unused-varswithargs: 'none'for type definitions)- Keeping a descriptive name without the underscore prefix
Apply this diff to revert the parameter name:
- onImport: (_data: SupportedExportFormats) => void; + onImport: (data: SupportedExportFormats) => void;Then configure your ESLint rule to not flag type definition parameters as unused.
28-31: Consider adding error handling for JSON parsing.While beyond the scope of linter fixes,
JSON.parsecan throw if the file contains invalid JSON. Consider wrapping in try-catch to gracefully handle malformed files and provide user feedback.Example enhancement:
reader.onload = (e) => { - const json = JSON.parse(e.target?.result as string); - onImport(json); + try { + const json = JSON.parse(e.target?.result as string); + onImport(json); + } catch (error) { + // Handle error - e.g., show toast notification + console.error('Failed to parse import file:', error); + } };components/Chat/ChatMessage.tsx (1)
269-269: Consider improving type safety by avoidingas anycast.The
rehypePluginsprop uses anas anytype cast (also at lines 302, 327). This bypasses TypeScript's type checking and could mask type errors.If the rehype plugin types are incompatible, consider:
- Installing correct type definitions for rehype-raw
- Creating a properly typed wrapper for the plugins
- Using a more specific type assertion if the actual types are known
Example of a more specific approach:
import { Plugin } from 'unified'; // Then use: rehypePlugins={[rehypeRaw as Plugin]}Or investigate if
@types/rehype-rawprovides the correct types that align with ReactMarkdown's expected plugin types.components/Markdown/CustomComponents.tsx (2)
11-194: Consider if deep equality checks are necessary for all components.All extracted components now use
isEqualfrom lodash for memo comparison. While this provides thorough equality checks, it may be over-optimization for components with simple props:
- Simple cases: Components like
ThComponent,TdComponent,LiComponentreceive onlychildrenprop. React's default shallow comparison or a simpleprevProps.children === nextProps.childrenwould suffice.- Complex cases:
SupComponentwith array filtering andCodeComponentwith multiple props benefit fromisEqual.For simpler components, consider using React's default memo comparison or explicit checks:
-const ThComponent = memo( - ({ children }) => ( - <th className="break-words border border-black bg-gray-500 px-3 py-1 text-white dark:border-white"> - {children} - </th> - ), - (prevProps, nextProps) => - isEqual(prevProps.children, nextProps.children), -); +const ThComponent = memo(({ children }) => ( + <th className="break-words border border-black bg-gray-500 px-3 py-1 text-white dark:border-white"> + {children} + </th> +));This reduces dependency on lodash and improves performance by avoiding deep equality checks where unnecessary.
2-2: Use modular imports for lodash utilitiesLodash is declared in package.json, but
import { isEqual } from 'lodash'pulls in the entire library. Change toimport isEqual from 'lodash/isEqual'or migrate to
lodash-esfor effective tree-shaking and a smaller bundle.components/Chat/DataStreamControls.tsx (1)
44-51: Harden window.open against reverse tabnabbingAdd noopener/noreferrer features when opening a new tab.
- onClick={() => window.open('/database-updates', '_blank')} + onClick={() => + window.open('/database-updates', '_blank', 'noopener,noreferrer') + }pages/api/chat.ts (2)
44-46: Prevent unbounded growth of initializedConversationsModule-scoped Set never clears; long-running edge workers can grow without bound. Add TTL/cleanup or limit entries, or key by a short-lived conversation/session token.
Also applies to: 71-88
77-78: Remove noisy console log in production pathUse debug-level logging or guard with an env flag.
pages/api/update-data-stream.ts (2)
39-41: Replace deprecated substr with slicesubstr is deprecated and triggers linters.
- id: `${streamId}-${currentTimestamp}-${Math.random().toString(36).substr(2, 9)}`, + id: `${streamId}-${currentTimestamp}-${Math.random().toString(36).slice(2, 11)}`,
111-133: Validate pending as boolean in PATCHCurrently accepts any value; add a type check.
if (req.method === 'PATCH') { const { uuid, pending } = req.body; if (!uuid) { return res.status(400).json({ error: 'UUID is required.' }); } + if (typeof pending !== 'boolean') { + return res.status(400).json({ error: 'pending must be a boolean.' }); + } // Find the entry by UUID and update its pending statuscomponents/Chat/Chat.tsx (4)
411-421: Add noopener/noreferrer to OAuth popupPrevents reverse tabnabbing and drops opener reference.
- const popup = window.open( - oauthUrl, - 'oauth-popup', - 'width=600,height=700,scrollbars=yes,resizable=yes' - ); + const popup = window.open( + oauthUrl, + 'oauth-popup', + 'width=600,height=700,scrollbars=yes,resizable=yes,noopener,noreferrer' + );
887-1164: Remove constant condition and unreachable branchif (!false) is a constant truth; the else never runs and will trip linters. Either always stream, or branch on content-type.
- if (!false) { + // Prefer streaming path when body is a ReadableStream (default in Fetch) + if (response.body) { // streaming handling ... - } else { - const { answer } = await response?.json(); - const updatedMessages: Message[] = [ - ...updatedConversation.messages, - { role: 'assistant', content: answer }, - ]; - // ... state updates ... - homeDispatch({ field: 'loading', value: false }); - homeDispatch({ field: 'messageIsStreaming', value: false }); - } + }Optionally branch on content-type:
- text/event-stream or application/x-ndjson → stream
- else → await response.json()
905-907: Remove unused counter and ESLint suppressioncounter isn’t used; drop the variable and increment.
- let counter = 1; + // removed unused counter - // eslint-disable-next-line no-unused-vars - counter++; + // (removed)Also applies to: 974-976
311-315: Drop unused wsUrlObj/isCrossOrigin and ESLint disablesThese vars aren’t used; remove to satisfy linter.
- // eslint-disable-next-line no-unused-vars - const wsUrlObj = new URL(wsUrl); - // eslint-disable-next-line no-unused-vars - const isCrossOrigin = wsUrlObj.origin !== window.location.origin; + // (removed unused URL parsing; add back when needed)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (42)
components/Avatar/SystemAvatar.tsx(1 hunks)components/Avatar/UserAvatar.tsx(0 hunks)components/Chat/Chat.tsx(11 hunks)components/Chat/ChatHeader.tsx(5 hunks)components/Chat/ChatInput.tsx(9 hunks)components/Chat/ChatInteractionMessage.tsx(1 hunks)components/Chat/ChatMessage.tsx(2 hunks)components/Chat/DataStreamControls.tsx(1 hunks)components/Chat/MemoizedChatMessage.tsx(1 hunks)components/Chat/Regenerate.tsx(0 hunks)components/Chatbar/Chatbar.context.tsx(1 hunks)components/Chatbar/Chatbar.tsx(1 hunks)components/Chatbar/components/ChatFolders.tsx(0 hunks)components/Chatbar/components/ChatbarSettings.tsx(1 hunks)components/Chatbar/components/ClearConversations.tsx(0 hunks)components/Chatbar/components/Conversation.tsx(0 hunks)components/DataStreamDisplay/DataStreamDisplay.tsx(1 hunks)components/DataStreamDisplay/DataStreamManager.tsx(1 hunks)components/Folder/Folder.tsx(1 hunks)components/Markdown/Chart.tsx(1 hunks)components/Markdown/CodeBlock.tsx(1 hunks)components/Markdown/CustomComponents.tsx(2 hunks)components/Markdown/CustomDetails.tsx(1 hunks)components/Markdown/CustomSummary.tsx(1 hunks)components/Markdown/Image.tsx(2 hunks)components/Markdown/Loading.tsx(0 hunks)components/Markdown/MemoizedReactMarkdown.tsx(1 hunks)components/Markdown/Video.tsx(2 hunks)components/Search/Search.tsx(1 hunks)components/Settings/Import.tsx(2 hunks)components/Settings/SettingDialog.tsx(3 hunks)components/Sidebar/Sidebar.tsx(2 hunks)components/Spinner/Spinner.tsx(0 hunks)pages/_app.tsx(2 hunks)pages/_document.tsx(2 hunks)pages/api/chat.ts(5 hunks)pages/api/home/home.context.tsx(1 hunks)pages/api/home/home.state.tsx(2 hunks)pages/api/home/home.tsx(7 hunks)pages/api/update-data-stream.ts(1 hunks)pages/database-updates.tsx(1 hunks)types/chat.ts(1 hunks)
💤 Files with no reviewable changes (7)
- components/Spinner/Spinner.tsx
- components/Avatar/UserAvatar.tsx
- components/Chatbar/components/ClearConversations.tsx
- components/Chatbar/components/ChatFolders.tsx
- components/Chatbar/components/Conversation.tsx
- components/Markdown/Loading.tsx
- components/Chat/Regenerate.tsx
🚧 Files skipped from review as they are similar to previous changes (19)
- types/chat.ts
- components/Sidebar/Sidebar.tsx
- components/Chat/ChatHeader.tsx
- pages/api/home/home.context.tsx
- pages/_app.tsx
- components/Settings/SettingDialog.tsx
- components/Markdown/Video.tsx
- components/Markdown/CustomSummary.tsx
- components/Chat/MemoizedChatMessage.tsx
- pages/database-updates.tsx
- components/Chatbar/Chatbar.tsx
- components/DataStreamDisplay/DataStreamDisplay.tsx
- components/Chatbar/components/ChatbarSettings.tsx
- pages/_document.tsx
- components/Search/Search.tsx
- pages/api/home/home.state.tsx
- components/Chatbar/Chatbar.context.tsx
- components/Chat/ChatInteractionMessage.tsx
- components/Chat/ChatInput.tsx
🧰 Additional context used
🧬 Code graph analysis (6)
pages/api/home/home.tsx (4)
pages/api/home/home.state.tsx (1)
initialState(34-82)contexts/ThemeContext.tsx (1)
useTheme(11-17)components/Chat/ChatHeader.tsx (1)
ChatHeader(21-227)components/DataStreamDisplay/DataStreamManager.tsx (1)
DataStreamManager(16-70)
components/Markdown/CustomComponents.tsx (5)
components/Markdown/CodeBlock.tsx (1)
CodeBlock(17-125)components/Markdown/Image.tsx (1)
Image(78-78)components/Markdown/Video.tsx (1)
Video(45-45)components/Markdown/CustomDetails.tsx (1)
CustomDetails(8-141)components/Markdown/CustomSummary.tsx (1)
CustomSummary(15-82)
components/Chat/Chat.tsx (2)
types/websocket.ts (1)
WebSocketInbound(59-63)types/chat.ts (1)
Message(1-10)
components/DataStreamDisplay/DataStreamManager.tsx (3)
types/chat.ts (1)
Conversation(20-27)utils/app/conversation.ts (1)
saveConversation(26-38)components/DataStreamDisplay/DataStreamDisplay.tsx (1)
DataStreamDisplay(170-170)
components/Chat/ChatMessage.tsx (1)
types/chat.ts (1)
Message(1-10)
components/Markdown/MemoizedReactMarkdown.tsx (1)
__mocks__/react-markdown.js (1)
ReactMarkdown(7-9)
🔇 Additional comments (14)
components/Avatar/SystemAvatar.tsx (1)
1-1: LGTM! Unused import removed.The removal of the unused
IconUserPentagonimport correctly addresses the linter error.components/Settings/Import.tsx (1)
29-29: LGTM!Changing
lettoconstis correct since the variable is never reassigned. This properly addresses the prefer-const linter rule.components/Chat/ChatMessage.tsx (3)
15-17: LGTM! Markdown plugin imports are correct.The imports for
rehype-raw,remark-gfm, andremark-mathare properly added and used throughout the component for enhanced Markdown rendering capabilities.
34-34: Verify: Underscore-prefixed parameters in callback interface seem unusual.The underscore prefix on
_editedMessageand_deleteCountin the Props interface definition is unconventional. Typically, underscore prefixes indicate intentionally unused parameters in an implementation, not in an interface definition. These parameters ARE used whenonEditis invoked at line 103:onEdit({ ...message, content: messageContent }, deleteCount);The decision to use/ignore these parameters should be made by the component implementing the callback, not declared in the interface. However, if this is a project-wide linting convention to fix linter errors (as indicated by the PR description), please confirm this is intentional.
Consider verifying if this naming pattern is required by your linter configuration or if the linter rule should be adjusted to not flag callback parameter names in interface definitions.
59-77: LGTM! useEffect hooks correctly placed before conditional returns.All three useEffect hooks are properly positioned before the conditional return at line 81, which is essential for React's Rules of Hooks:
- Lines 60-62: Correctly syncs
message.contentto local state with proper dependency- Lines 64-69: Properly auto-resizes textarea when
isEditingchanges- Lines 71-77: Appropriately cleans up speech synthesis on unmount
components/Markdown/CodeBlock.tsx (1)
2-2: LGTM! Clean import removal.The
MouseEventtype was unused and has been correctly removed.components/Markdown/CustomDetails.tsx (1)
101-101: LGTM! Formatting cleanup.Trailing whitespace removed from className attribute.
components/Markdown/Chart.tsx (1)
3-3: LGTM! Import cleanup.Simplified React import is appropriate for this component's usage.
components/Markdown/Image.tsx (2)
1-1: LGTM! Removed unused icon imports.
IconMaximizeandIconXwere not referenced in the component.
6-78: LGTM! Component aliasing pattern applied.The refactoring introduces an internal
ImageComponentconstant with properdisplayNameand exports it asImage. This pattern:
- Preserves the public API
- Improves debugging with explicit displayName
- Aligns with similar refactorings across the codebase (MemoizedReactMarkdown, CustomComponents)
components/Markdown/CustomComponents.tsx (1)
11-213: LGTM! Excellent refactoring for maintainability.Extracting inline memo definitions into standalone named components significantly improves:
- Code organization and readability
- Debuggability with explicit
displayNameproperties- Testability (each component can be tested independently)
- Consistency across the Markdown rendering ecosystem
The refactoring maintains the same public API while improving the internal structure.
components/Markdown/MemoizedReactMarkdown.tsx (1)
4-10: LGTM! Consistent component aliasing pattern.The refactoring matches the pattern applied in
Image.tsxand aligns with the broader codebase modernization. The internalMemoizedReactMarkdownComponentwith explicitdisplayNameimproves debugging while the publicMemoizedReactMarkdownexport maintains API compatibility.pages/api/home/home.tsx (2)
53-53: Verify ThemeProvider wrapping and dark mode strategyuseTheme throws if no ThemeProvider. Ensure this page is wrapped. Also confirm Tailwind dark mode is applied via a parent with class "dark" (your container appends light/dark classes).
39-39: Confirm file location: pages/api is reserved for API routesThis file exports a React component and getServerSideProps but lives under pages/api/home/. Next.js treats pages/api/* as API routes. Verify routing is intentional; otherwise move to pages/home/ or app/… to avoid build/route conflicts.
| <div className="flex items-center gap-2 whitespace-nowrap"> | ||
| <label className="flex items-center gap-2 cursor-pointer flex-shrink-0"> | ||
| <span className="text-sm font-medium text-black dark:text-white"> | ||
| Data Stream Display | ||
| </span> | ||
| <div | ||
| onClick={() => { | ||
| homeDispatch({ | ||
| field: 'showDataStreamDisplay', | ||
| value: !showDataStreamDisplay, | ||
| }); | ||
| }} | ||
| className={`relative inline-flex h-5 w-10 items-center cursor-pointer rounded-full transition-colors duration-300 ease-in-out ${ | ||
| showDataStreamDisplay ? 'bg-black dark:bg-[#76b900]' : 'bg-gray-200' | ||
| }`} | ||
| > | ||
| <span | ||
| className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-300 ease-in-out ${ | ||
| showDataStreamDisplay ? 'translate-x-6' : 'translate-x-0' | ||
| }`} | ||
| /> | ||
| </div> | ||
| </label> | ||
| </div> |
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 | 🟠 Major
Make the toggle accessible (button/role="switch") instead of clickable div/label
Current markup isn’t keyboard-accessible and misuses label without a form control. Use a button with role="switch" and aria-checked.
Apply:
- <label className="flex items-center gap-2 cursor-pointer flex-shrink-0">
+ <div className="flex items-center gap-2 flex-shrink-0">
<span className="text-sm font-medium text-black dark:text-white">
Data Stream Display
</span>
- <div
- onClick={() => {
+ <button
+ type="button"
+ role="switch"
+ aria-checked={showDataStreamDisplay}
+ aria-label="Toggle Data Stream Display"
+ onClick={() => {
homeDispatch({
field: 'showDataStreamDisplay',
value: !showDataStreamDisplay,
});
}}
- className={`relative inline-flex h-5 w-10 items-center cursor-pointer rounded-full transition-colors duration-300 ease-in-out ${
+ className={`relative inline-flex h-5 w-10 items-center rounded-full transition-colors duration-300 ease-in-out ${
showDataStreamDisplay ? 'bg-black dark:bg-[#76b900]' : 'bg-gray-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-300 ease-in-out ${
showDataStreamDisplay ? 'translate-x-6' : 'translate-x-0'
}`}
/>
- </div>
- </label>
+ </button>
+ </div>🤖 Prompt for AI Agents
In components/Chat/DataStreamControls.tsx around lines 17 to 40, the toggle is
implemented as a clickable div/label which is not keyboard-accessible and
misuses label; replace it with a semantic button element using role="switch" and
aria-checked={showDataStreamDisplay}, move the onClick handler to the button,
ensure the button has an accessible label (either visible text or
aria-label/aria-labelledby), keep the visual styling and transition classes on
the button, and remove the improper label wrapper so keyboard and assistive tech
can toggle state correctly (no extra key handlers needed since button handles
Enter/Space).
| const currentStreams = dataStreams || []; | ||
| const newStreams = streamsData.streams; | ||
| if (JSON.stringify(currentStreams.sort()) !== JSON.stringify(newStreams.sort())) { | ||
| dispatch({ field: 'dataStreams', value: newStreams }); | ||
| } |
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.
Bug: in-place sort mutates state array
currentStreams.sort() mutates the array (dataStreams), causing unintended state changes. Sort copies before comparing.
- const currentStreams = dataStreams || [];
- const newStreams = streamsData.streams;
- if (JSON.stringify(currentStreams.sort()) !== JSON.stringify(newStreams.sort())) {
+ const currentStreams = (dataStreams || []).slice().sort();
+ const newStreams = (streamsData.streams || []).slice().sort();
+ if (JSON.stringify(currentStreams) !== JSON.stringify(newStreams)) {
dispatch({ field: 'dataStreams', value: newStreams });
}📝 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.
| const currentStreams = dataStreams || []; | |
| const newStreams = streamsData.streams; | |
| if (JSON.stringify(currentStreams.sort()) !== JSON.stringify(newStreams.sort())) { | |
| dispatch({ field: 'dataStreams', value: newStreams }); | |
| } | |
| const currentStreams = (dataStreams || []).slice().sort(); | |
| const newStreams = (streamsData.streams || []).slice().sort(); | |
| if (JSON.stringify(currentStreams) !== JSON.stringify(newStreams)) { | |
| dispatch({ field: 'dataStreams', value: newStreams }); | |
| } |
🤖 Prompt for AI Agents
In components/DataStreamDisplay/DataStreamManager.tsx around lines 45 to 49, the
code calls currentStreams.sort() which mutates the state array (dataStreams);
fix this by cloning both arrays before sorting (e.g., use [...currentStreams]
and [...newStreams] or .slice()) and then compare the sorted clones with
JSON.stringify to avoid in-place mutation; ensure you sort the cloned arrays
consistently (use a comparator if items are not primitive strings) and only
dispatch when the serialized clones differ.
| export const getReactMarkDownCustomComponents = ( | ||
| messageIndex = 0, | ||
| messageId = '', | ||
| _messageId = '', |
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 | 🟠 Major
🧩 Analysis chain
Consider removing the unused parameter entirely.
The messageId parameter has been renamed to _messageId to indicate it's unused. If this parameter is truly unused throughout the codebase, consider removing it entirely to simplify the API.
Run this script to verify if any consumers pass this parameter:
If no consumers use the second parameter, apply this diff:
export const getReactMarkDownCustomComponents = (
messageIndex = 0,
- _messageId = '',
) => {🏁 Script executed:
#!/bin/bash
# Search for calls to getReactMarkDownCustomComponents with more than 1 argument
echo "=== Finding calls to getReactMarkDownCustomComponents ==="
rg -nP "getReactMarkDownCustomComponents\s*\([^)]*,[^)]*\)" --type ts --type tsx -C2Length of output: 85
🏁 Script executed:
#!/bin/bash
echo "=== Finding calls to getReactMarkDownCustomComponents with >1 argument ==="
rg -nP "getReactMarkDownCustomComponents\s*\([^)]*,\s*" -g "*.ts" -g "*.tsx" -C2Length of output: 485
Handle the existing second-argument usage before removing _messageId
There’s a consumer in components/Chat/ChatMessage.tsx (line 56):
getReactMarkDownCustomComponents(messageIndex, message?.id)Removing the _messageId parameter will break this call—update it to only pass messageIndex before simplifying the API.
🤖 Prompt for AI Agents
In components/Markdown/CustomComponents.tsx around line 198, the function still
declares a second parameter `_messageId = ''` but callers (e.g.,
components/Chat/ChatMessage.tsx line 56) currently pass messageIndex and
message?.id; before removing `_messageId` update those call sites to stop
passing the second arg (change getReactMarkDownCustomComponents(messageIndex,
message?.id) to getReactMarkDownCustomComponents(messageIndex)) and then safely
remove the unused `_messageId` parameter and its default; ensure TypeScript
signatures and any tests/types are adjusted accordingly.
| const initUrl = chatCompletionURL.replace(/\/chat\/ca-rag$/, '/init'); | ||
|
|
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 brittle path rewrites; preserve query and handle trailing variants
Regex replace anchored to end-of-string misses URLs with query strings or trailing slashes. Use URL API to modify pathname safely.
- const initUrl = chatCompletionURL.replace(/\/chat\/ca-rag$/, '/init');
+ const initUrl = (() => {
+ try {
+ const u = new URL(chatCompletionURL);
+ u.pathname = u.pathname.replace(/\/chat\/ca-rag\/?$/, '/init');
+ return u.toString();
+ } catch {
+ return chatCompletionURL.replace(/\/chat\/ca-rag(?:\/)?(?:\?.*)?$/, '/init');
+ }
+ })();- let backendURL = chatCompletionURL;
- if (chatCompletionURL.includes(chatCaRagEndpoint)) {
- // Replace '/chat/ca-rag' with '/call' to get the backend URL. The Context Aware RAG backend
- // uses '/call' as its endpoint, which is too generic to use as the frontend endpoint here.
- backendURL = chatCompletionURL.replace(/\/chat\/ca-rag$/, '/call');
- }
+ let backendURL = chatCompletionURL;
+ try {
+ const u = new URL(chatCompletionURL);
+ if (u.pathname.endsWith('/chat/ca-rag')) {
+ u.pathname = u.pathname.replace(/\/chat\/ca-rag\/?$/, '/call');
+ }
+ backendURL = u.toString();
+ } catch {
+ backendURL = chatCompletionURL.replace(/\/chat\/ca-rag(?:\/)?(?:\?.*)?$/, '/call');
+ }Also applies to: 325-331
🤖 Prompt for AI Agents
In pages/api/chat.ts around lines 58-59 (and similarly lines 325-331), the
current regex replace anchored to the end-of-string fails for URLs with query
strings or trailing slashes; parse chatCompletionURL with the URL API, preserve
search and hash, and mutate only the pathname: detect and strip a trailing
slash, replace a terminal '/chat/ca-rag' segment (or '/chat/ca-rag/' variant)
with '/init', then reconstruct the full URL via url.toString() so queries and
fragments remain intact.
| const webSocketModeRef = useRef( | ||
| typeof window !== 'undefined' && sessionStorage.getItem('webSocketMode') === 'false' ? false : webSocketMode | ||
| ); |
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.
Persisted WebSocket mode: 'true' value is ignored
The initializer only maps 'false' → false; 'true' falls back to default. Persisted 'true' won’t restore.
Apply:
- const webSocketModeRef = useRef(
- typeof window !== 'undefined' && sessionStorage.getItem('webSocketMode') === 'false' ? false : webSocketMode
- );
+ const storedWsMode = typeof window !== 'undefined' ? sessionStorage.getItem('webSocketMode') : null;
+ const webSocketModeRef = useRef(
+ storedWsMode == null ? webSocketMode : storedWsMode === 'true'
+ );📝 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.
| const webSocketModeRef = useRef( | |
| typeof window !== 'undefined' && sessionStorage.getItem('webSocketMode') === 'false' ? false : webSocketMode | |
| ); | |
| const storedWsMode = typeof window !== 'undefined' | |
| ? sessionStorage.getItem('webSocketMode') | |
| : null; | |
| const webSocketModeRef = useRef( | |
| storedWsMode == null ? webSocketMode : storedWsMode === 'true' | |
| ); |
🤖 Prompt for AI Agents
In pages/api/home/home.tsx around lines 55-57, the useRef initializer only
converts a stored 'false' string to false and ignores a stored 'true' (falling
back to webSocketMode); update the initializer to explicitly handle both 'true'
and 'false' string values from sessionStorage (e.g., check
sessionStorage.getItem('webSocketMode') === 'true' → true, === 'false' → false,
otherwise fallback to webSocketMode) while preserving the typeof window guard.
Description
Fixes
yarn buildlinter errors. Built on top of streaming data branch.By Submitting this PR I confirm:
Summary by CodeRabbit
New Features
Improvements
Documentation
Chores