Skip to content

User Interface Updates#741

Merged
ngoiyaeric merged 10 commits into
mainfrom
fix/reopen-settings-labels
Jul 23, 2026
Merged

User Interface Updates#741
ngoiyaeric merged 10 commits into
mainfrom
fix/reopen-settings-labels

Conversation

@ngoiyaeric

@ngoiyaeric ngoiyaeric commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

…2218-00c8db21"

This reverts commit 696bff5.

Summary by CodeRabbit

  • New Features

    • Added tool selection in Settings, replacing model selection.
    • Improved map-based resolution searches with image and GeoJSON support.
    • Preserved message metadata and streamlined chat history display.
  • Bug Fixes

    • Improved map loading and graceful handling of map configuration errors.
    • Prevented failures when optional backend services are unavailable.
    • Added fallback handling for invalid time zones and malformed search results.
  • UI Improvements

    • Refined mobile map, chat input, empty-state, and Settings layouts.
    • Updated labels and simplified Settings actions.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
qcx Ready Ready Preview, Comment Jul 23, 2026 5:15am

@CLAassistant

CLAassistant commented Jul 16, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
0 out of 3 committers have signed the CLA.

❌ Manus AI
❌ CJWTRUST
❌ google-labs-jules[bot]


Manus AI seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR updates resolution-search file and message handling, adds runtime fallbacks for Supabase and Mapbox initialization, changes settings and mobile layouts, introduces Playwright authentication bypasses, and refreshes service-worker precache entries.

Changes

Chat and runtime behavior

Layer / File(s) Summary
Resolution-search persistence and rehydration
app/actions.tsx, lib/actions/chat.ts, app/search/[id]/page.tsx
Resolution-search inputs and persisted messages now support file validation, sanitized image history, metadata restoration, drawing-context filtering, and guarded assistant JSON parsing.
Service and map initialization fallbacks
lib/supabase/browser-client.ts, components/chat.tsx, components/chat-panel.tsx, components/map-loading-context.tsx, components/map/mapbox-map.tsx
Missing Supabase configuration, unavailable upload clients, delayed map loading, and Mapbox initialization errors now follow explicit fallback paths.
Timezone and model selection
lib/agents/resolution-search.tsx, lib/utils/index.ts
Invalid timezones fall back to UTC, and the named Grok model now selects a vision-capable identifier when required.

Interface updates

Layer / File(s) Summary
Mobile chat and empty state
app/globals.css, components/empty-screen.tsx
Mobile map, icon, and input containers receive inset bordered styling, while example messages use a responsive native-button grid.
Settings tool selection
components/settings/components/tool-selection-form.tsx, components/settings/components/settings.tsx
The model-selection tab and form are replaced with tool-selection labels, options, defaults, and tab wiring.
Settings presentation
components/settings/components/settings-skeleton.tsx, components/settings/components/system-prompt-form.tsx, components/settings/components/user-management-form.tsx, components/settings/components/settings.tsx
Settings tabs, headings, theme spacing, and footer action labels are updated.

Test and build support

Layer / File(s) Summary
Playwright authentication support
lib/auth/use-current-user.ts, middleware.ts
Playwright mode uses a mock current user and bypasses Clerk middleware.
Upload and build support
components/chat-panel.tsx, tests/sidebar.spec.ts, public/sw.js
Upload initialization checks, optional sidebar prompt dismissal, and generated precache entries are updated.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatAction
  participant AIState
  participant ChatStorage
  participant ChatUI
  User->>ChatAction: submit resolution search with image files
  ChatAction->>AIState: create sanitized message history
  AIState->>ChatStorage: persist messages and metadata
  ChatStorage-->>ChatUI: restore chat state
  ChatUI->>ChatUI: filter processed images and invalid payloads
Loading

Possibly related PRs

  • QueueLab/QCX#738: Shares the resolution-search file handling and mobile icon-bar changes.
  • QueueLab/QCX#683: Shares sanitized history persistence in the resolution-search flow.
  • QueueLab/QCX#705: Shares Clerk middleware and authentication plumbing changes.

Suggested labels: Review effort 2/5

Poem

A rabbit hops through maps of blue,
With tidy chats and tools anew.
Images fade, the state stays bright,
Safe fallbacks guide the night.
“Save” and “Reset” — short and sweet,
Spring-cleaned code beneath my feet!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is very generic and doesn't describe the specific UI changes or scope of the patch. Use a more specific title that names the main change, such as mobile UI layout fixes and settings/chat/map updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reopen-settings-labels

Warning

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

🔧 ESLint

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

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@app/actions.tsx`:
- Line 212: Update the history sanitization flow producing sanitizedHistory so
IMAGE_PROCESSED is not persisted as an image part or URL. Convert it to a text
placeholder such as “[Image processed]”, omit that image part, or add matching
sentinel handling in components/user-message.tsx before it reaches Image
rendering; preserve normal image parts unchanged.

In `@components/chat-panel.tsx`:
- Around line 130-133: Update the upload flow around the optimistic message
creation and Supabase initialization guard to roll back the optimistic message
when initialization fails. In the catch path, remove the fake attachment message
and clear the selected file state before returning, while preserving the
existing optimistic behavior when upload initialization succeeds.

In `@components/empty-screen.tsx`:
- Around line 40-44: Update the button rendered in the example-message loop by
adding an explicit type="button" and simplify its onClick handler to a non-async
callback since submitMessage is not awaited; preserve the existing
submitMessage(item.message) behavior.

In `@components/map/mapbox-map.tsx`:
- Around line 445-453: Remove the unused initializedRef declaration and all
assignments to initializedRef.current in the Mapbox initialization success and
failure paths. Keep the existing !map.current initialization guard unchanged; do
not add initializedRef to it, preserving React 18 Strict Mode re-initialization
behavior.

In `@lib/agents/resolution-search.tsx`:
- Around line 69-93: Update the timezone formatting flow around the localTime
calculation to track an effectiveTimezone initialized from timezone, set it to
UTC in the catch fallback, and use effectiveTimezone when constructing the
prompt so the displayed label matches the formatted timestamp.

In `@tests/sidebar.spec.ts`:
- Around line 6-8: Update the Later-dismissal try/catch around
page.locator('text=Later').click so it ignores only the expected timeout when
the control is absent. Re-throw any other click or actionability error instead
of allowing setup to continue with the dialog open.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5005f2f8-d49f-4e03-9606-14eaa832b949

📥 Commits

Reviewing files that changed from the base of the PR and between 696bff5 and b7c8d65.

📒 Files selected for processing (17)
  • .gitignore
  • app/actions.tsx
  • app/globals.css
  • components/chat-panel.tsx
  • components/chat.tsx
  • components/empty-screen.tsx
  • components/map-loading-context.tsx
  • components/map/mapbox-map.tsx
  • components/settings/components/settings-skeleton.tsx
  • components/settings/components/settings.tsx
  • components/settings/components/system-prompt-form.tsx
  • components/settings/components/user-management-form.tsx
  • lib/agents/resolution-search.tsx
  • lib/supabase/browser-client.ts
  • lib/utils/index.ts
  • public/sw.js
  • tests/sidebar.spec.ts
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.44.1)
public/sw.js

[warning] Avoid using the initial state variable in setState
Context: setTimeout(t,e)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

🪛 React Doctor (0.7.6)
components/empty-screen.tsx

[warning] 40-40: Your users can submit the form by accident because a <button> with no type defaults to submit.

Set an explicit button type so plain buttons do not submit forms by accident: type="button", "submit", or "reset".

(button-has-type)

🔇 Additional comments (11)
app/globals.css (1)

121-136: LGTM!

Also applies to: 152-155, 183-194

lib/supabase/browser-client.ts (1)

5-8: LGTM!

components/chat.tsx (1)

98-99: LGTM!

components/settings/components/settings-skeleton.tsx (1)

9-13: LGTM!

components/settings/components/settings.tsx (1)

197-203: LGTM!

Also applies to: 214-216, 230-230, 242-242, 288-288, 299-299

components/settings/components/system-prompt-form.tsx (1)

148-148: LGTM!

components/settings/components/user-management-form.tsx (1)

76-76: LGTM!

.gitignore (1)

62-64: LGTM!

public/sw.js (1)

2-2: LGTM!

components/map-loading-context.tsx (1)

14-20: LGTM!

lib/utils/index.ts (1)

44-45: 🩺 Stability & Availability

Drop this warning. grok-vision-beta is a valid xAI vision model identifier, so these branches don’t need to change.

			> Likely an incorrect or invalid review comment.

Comment thread app/actions.tsx Outdated
Comment thread components/chat-panel.tsx
Comment on lines 130 to +133
const supabase = getSupabaseBrowserClient()
if (!supabase) {
throw new Error('Supabase client is not initialized.')
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Rollback the optimistic message when upload initialization fails.

The optimistic message is added before this guard. When the guard throws, the catch returns while the fake attachment remains in chat history and the selected file remains attached, so retrying can duplicate the message. Either defer setMessages until the upload succeeds or remove the optimistic entry in the catch path.

🤖 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 `@components/chat-panel.tsx` around lines 130 - 133, Update the upload flow
around the optimistic message creation and Supabase initialization guard to roll
back the optimistic message when initialization fails. In the catch path, remove
the fake attachment message and clear the selected file state before returning,
while preserving the existing optimistic behavior when upload initialization
succeeds.

Comment on lines +40 to 44
<button
key={item.message}
onClick={async () => {
submitMessage(item.message);
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add an explicit button type to prevent unintended form submissions.

A plain <button> element defaults to type="submit". If this component is placed within a <form> context in the future, clicking the example message will trigger a form submission. Explicitly set type="button".

Also, the onClick handler is currently marked as async but doesn't await anything, which can be safely simplified.

💡 Proposed fix
-              <button
-                key={item.message}
-                onClick={async () => {
-                  submitMessage(item.message);
-                }}
+              <button
+                key={item.message}
+                type="button"
+                onClick={() => {
+                  submitMessage(item.message);
+                }}
📝 Committable suggestion

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

Suggested change
<button
key={item.message}
onClick={async () => {
submitMessage(item.message);
}}
<button
key={item.message}
type="button"
onClick={() => {
submitMessage(item.message);
}}
🧰 Tools
🪛 React Doctor (0.7.6)

[warning] 40-40: Your users can submit the form by accident because a <button> with no type defaults to submit.

Set an explicit button type so plain buttons do not submit forms by accident: type="button", "submit", or "reset".

(button-has-type)

🤖 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 `@components/empty-screen.tsx` around lines 40 - 44, Update the button rendered
in the example-message loop by adding an explicit type="button" and simplify its
onClick handler to a non-async callback since submitMessage is not awaited;
preserve the existing submitMessage(item.message) behavior.

Source: Linters/SAST tools

Comment on lines +445 to +453
initializedRef.current = true
setIsMapReady(true)
setIsMapLoaded(true) // Set map loaded state to true
})
} catch (error) {
console.error('Failed to initialize Mapbox Map:', error)
initializedRef.current = true
setIsMapReady(true)
setIsMapLoaded(true) // Set map loaded state to true
})
setIsMapLoaded(true) // Set loaded/ready so overlay disappears and app remains functional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused initializedRef.

The initializedRef is assigned here but never read, making it dead code.

While it might seem tempting to add this ref to the initialization guard (if (!map.current && !initializedRef.current)) to prevent multiple failure logs, doing so would actually break React 18 Strict Mode. In Strict Mode, refs persist across the simulated unmount and remount cycle, so checking the ref would permanently prevent the map from re-initializing after the simulated unmount. The current !map.current guard works correctly on its own, so it is best to remove this ref entirely.

🧹 Proposed cleanup
-          initializedRef.current = true
           setIsMapReady(true)
           setIsMapLoaded(true) // Set map loaded state to true
         })
       } catch (error) {
         console.error('Failed to initialize Mapbox Map:', error)
-        initializedRef.current = true
         setIsMapReady(true)
         setIsMapLoaded(true) // Set loaded/ready so overlay disappears and app remains functional
       }

(You can also safely remove its declaration const initializedRef = useRef<boolean>(false) around line 33).

🤖 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 `@components/map/mapbox-map.tsx` around lines 445 - 453, Remove the unused
initializedRef declaration and all assignments to initializedRef.current in the
Mapbox initialization success and failure paths. Keep the existing !map.current
initialization guard unchanged; do not add initializedRef to it, preserving
React 18 Strict Mode re-initialization behavior.

Comment on lines +69 to +93
let localTime = '';
try {
localTime = now.toLocaleString('en-US', {
timeZone: timezone,
hour: '2-digit',
minute: '2-digit',
hour12: true,
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
} catch (e) {
console.error(`Invalid timezone specified: ${timezone}, falling back to UTC`, e);
localTime = now.toLocaleString('en-US', {
timeZone: 'UTC',
hour: '2-digit',
minute: '2-digit',
hour12: true,
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

rg -n -C 5 '\bfetchLocationNews\s*\(' lib

Repository: QueueLab/QCX

Length of output: 1799


🏁 Script executed:

sed -n '1,180p' lib/agents/resolution-search.tsx

Repository: QueueLab/QCX

Length of output: 6636


Use the fallback timezone in the prompt too. When toLocaleString falls back to UTC, the prompt still labels the time with the original invalid timezone, so the timestamp and timezone can disagree. Store an effectiveTimezone and use it in the prompt.

🤖 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 `@lib/agents/resolution-search.tsx` around lines 69 - 93, Update the timezone
formatting flow around the localTime calculation to track an effectiveTimezone
initialized from timezone, set it to UTC in the catch fallback, and use
effectiveTimezone when constructing the prompt so the displayed label matches
the formatted timestamp.

Comment thread tests/sidebar.spec.ts
Comment on lines +6 to +8
try {
await page.locator('text=Later').click({ timeout: 3000 });
} catch (e) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== tests/sidebar.spec.ts ==\n'
nl -ba tests/sidebar.spec.ts | sed -n '1,80p'

printf '\n== components/purchase-credits-popup.tsx ==\n'
nl -ba components/purchase-credits-popup.tsx | sed -n '1,220p'

Repository: QueueLab/QCX

Length of output: 219


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== tests/sidebar.spec.ts ==\n'
awk 'NR>=1 && NR<=120 { printf "%4d  %s\n", NR, $0 }' tests/sidebar.spec.ts

printf '\n== components/purchase-credits-popup.tsx ==\n'
awk 'NR>=1 && NR<=260 { printf "%4d  %s\n", NR, $0 }' components/purchase-credits-popup.tsx

Repository: QueueLab/QCX

Length of output: 4811


Do not swallow all dismissal errors.
Catch only the expected timeout when Later is absent; rethrow other click/actionability errors so setup fails instead of continuing with the dialog still open.

🤖 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 `@tests/sidebar.spec.ts` around lines 6 - 8, Update the Later-dismissal
try/catch around page.locator('text=Later').click so it ignores only the
expected timeout when the control is absent. Re-throw any other click or
actionability error instead of allowing setup to continue with the dialog open.

@charliecreates charliecreates Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: Request changes

I found two blocking regressions.

  1. lib/utils/index.ts:44 and :90 — invalid xAI image model selection. getModel(true) now hard-codes the legacy grok-vision-beta model ID for both the selected Grok and default xAI paths. resolutionSearch and researcher call getModel(hasImage), so every xAI-backed image request can fail before analysis; the surrounding try/catch only wraps provider/model construction, not the request. Please use an image-capable model ID actually supported by the configured xAI API and preserve a request-level fallback if xAI rejects it.

  2. app/actions.tsx:194 — invalid persisted image URL. This keeps the part as type: "image" but replaces its URL with the literal IMAGE_PROCESSED. aiState.done persists this history, and getUIStateFromAIState later passes the array to UserMessage, which renders every image part through next/image; revisiting a chat after a resolution search can therefore break rendering with an invalid image src. Drop the image part or render a valid explicit placeholder instead of persisting an invalid image URL.

Validation: inspected the complete 17-file diff, relevant call sites and persistence/rendering paths, PR discussion and prior formal reviews, and the existing checks for head b7c8d653e5931a9f4ab77a34f6fda1fcdf43e4f3. No tests, lint, build, or other CI-style commands were run.

@ngoiyaeric ngoiyaeric changed the title Reapply "Merge pull request #735 from QueueLab/jules-1637146196022344… User Interface Updates Jul 16, 2026
@ngoiyaeric

Copy link
Copy Markdown
Collaborator Author

Screenshot_20260722_195147_Chrome can you fix the overflowing ui on mobile

google-labs-jules Bot and others added 3 commits July 22, 2026 17:28
- Rename `model-selection-form` to `tool-selection-form`.
- Replace existing models (Grok, Gemini, GPT) with "SkyFi" and "QCX-Terra".
- Fix the layout to use a responsive, column-wrapping flex container on narrow viewports to completely prevent word wrapping and element overlap.
- Change tab triggers, values, form validation schemas, and descriptions from "model" to "tool".
- Update the default value of the selected tool to "QCX-Terra".

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Rename `model-selection-form` to `tool-selection-form`.
- Replace existing models (Grok, Gemini, GPT) with "SkyFi" and "QCX-Terra".
- Fix layout overflow by applying a responsive, column-wrapping flex container on narrow viewports.
- Change tab triggers, values, form validation schemas, and descriptions from "model" to "tool".
- Update the default value of the selected tool to "QCX-Terra".
- Unconditionally invoke `useUser` hook in `useCurrentUser` to fix React rules-of-hooks violation.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…2612169477250952

Settings tools select renaming and layout overflow fix

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@lib/actions/chat.ts`:
- Around line 213-241: Use a lossless metadata envelope in lib/actions/chat.ts
lines 213-241: update the message-content transformation to store the original
payload in a dedicated field instead of spreading parsed content, preserving
strings and arrays without reshaping them. In app/search/[id]/page.tsx lines
53-74, update the rehydration logic to restore that field verbatim for original
strings and JSON-stringify it only for originally structured payloads, so
BotMessage receives the original response type and content.

In `@middleware.ts`:
- Around line 4-9: Update the default middleware function to accept NextRequest
and NextFetchEvent instead of any, and initialize clerkMiddleware() once at
module scope. Reuse that module-scoped Clerk handler for non-Playwright requests
while preserving the existing NextResponse.next() test bypass and middleware
contract.
- Around line 5-6: Restrict the Playwright authentication bypass in
middleware.ts to a server-only, non-production test guard rather than the public
NEXT_PUBLIC flag alone. In lib/auth/use-current-user.ts, provide the mock
identity only through a matching test-only guarded provider or equivalent
mechanism, and ensure both paths cannot activate in production or outside
isolated tests.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d5d26ce6-0825-4839-866c-7e7597b9f64a

📥 Commits

Reviewing files that changed from the base of the PR and between b7c8d65 and 4a9185d.

📒 Files selected for processing (9)
  • app/actions.tsx
  • app/search/[id]/page.tsx
  • components/settings/components/settings-skeleton.tsx
  • components/settings/components/settings.tsx
  • components/settings/components/tool-selection-form.tsx
  • lib/actions/chat.ts
  • lib/auth/use-current-user.ts
  • middleware.ts
  • public/sw.js
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.44.1)
public/sw.js

[warning] Avoid using the initial state variable in setState
Context: setTimeout(t,e)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

🔇 Additional comments (7)
app/actions.tsx (2)

188-212: LGTM!


698-718: LGTM!

middleware.ts (1)

2-2: LGTM!

public/sw.js (1)

2-2: 🩺 Stability & Availability

Validate the regenerated precache inventory against the build output.

Confirm every precacheEntries URL exists in the corresponding .next or public output and that the worker is generated from the same build; a stale or missing asset can break installation and offline navigation.

components/settings/components/tool-selection-form.tsx (1)

22-122: LGTM!

components/settings/components/settings.tsx (1)

17-17: LGTM!

Also applies to: 40-40, 60-60, 73-85, 197-203, 214-246, 288-299

components/settings/components/settings-skeleton.tsx (1)

9-13: LGTM!

Comment thread lib/actions/chat.ts
Comment on lines +213 to +241
const newMessagesData: Omit<DbNewMessage, 'chatId'>[] = chat.messages.map(msg => {
let content = typeof msg.content === 'object' ? JSON.stringify(msg.content) : msg.content;

// If the message has a type or name, embed them as metadata in the content
// since the DB schema doesn't have dedicated columns for them yet.
if (msg.type || msg.name) {
try {
let parsedContent;
if (typeof msg.content === 'object') {
parsedContent = msg.content;
} else {
try {
parsedContent = JSON.parse(msg.content);
} catch (e) {
// If it's not JSON, we wrap it
parsedContent = { text: msg.content };
}
}

content = JSON.stringify({
...parsedContent,
__metadata: {
type: msg.type,
name: msg.name
}
});
} catch (e) {
console.error('Failed to embed metadata in message content:', e);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use a lossless metadata envelope.

A typed plaintext response such as "Hello" is stored as {"text":"Hello","__metadata":...} and rehydrates as {"text":"Hello"}. BotMessage then renders that JSON instead of the response. Arrays are also converted into numeric-keyed objects by { ...parsedContent }.

  • lib/actions/chat.ts#L213-L241: store the original payload under a dedicated field instead of spreading it.
  • app/search/[id]/page.tsx#L53-L74: restore that payload verbatim (string) or JSON-stringify it only when it was originally structured.
Proposed protocol
- content = JSON.stringify({
-   ...parsedContent,
-   __metadata: { type: msg.type, name: msg.name }
- });
+ content = JSON.stringify({
+   __metadata: { type: msg.type, name: msg.name },
+   __content: msg.content
+ });
- const { __metadata, ...rest } = parsed;
- content = JSON.stringify(rest);
+ const { __metadata, __content } = parsed;
+ content =
+   typeof __content === 'string'
+     ? __content
+     : JSON.stringify(__content);
📝 Committable suggestion

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

Suggested change
const newMessagesData: Omit<DbNewMessage, 'chatId'>[] = chat.messages.map(msg => {
let content = typeof msg.content === 'object' ? JSON.stringify(msg.content) : msg.content;
// If the message has a type or name, embed them as metadata in the content
// since the DB schema doesn't have dedicated columns for them yet.
if (msg.type || msg.name) {
try {
let parsedContent;
if (typeof msg.content === 'object') {
parsedContent = msg.content;
} else {
try {
parsedContent = JSON.parse(msg.content);
} catch (e) {
// If it's not JSON, we wrap it
parsedContent = { text: msg.content };
}
}
content = JSON.stringify({
...parsedContent,
__metadata: {
type: msg.type,
name: msg.name
}
});
} catch (e) {
console.error('Failed to embed metadata in message content:', e);
}
const newMessagesData: Omit<DbNewMessage, 'chatId'>[] = chat.messages.map(msg => {
let content = typeof msg.content === 'object' ? JSON.stringify(msg.content) : msg.content;
// If the message has a type or name, embed them as metadata in the content
// since the DB schema doesn't have dedicated columns for them yet.
if (msg.type || msg.name) {
try {
content = JSON.stringify({
__metadata: {
type: msg.type,
name: msg.name
},
__content: msg.content
});
} catch (e) {
console.error('Failed to embed metadata in message content:', e);
}
📍 Affects 2 files
  • lib/actions/chat.ts#L213-L241 (this comment)
  • app/search/[id]/page.tsx#L53-L74
🤖 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 `@lib/actions/chat.ts` around lines 213 - 241, Use a lossless metadata envelope
in lib/actions/chat.ts lines 213-241: update the message-content transformation
to store the original payload in a dedicated field instead of spreading parsed
content, preserving strings and arrays without reshaping them. In
app/search/[id]/page.tsx lines 53-74, update the rehydration logic to restore
that field verbatim for original strings and JSON-stringify it only for
originally structured payloads, so BotMessage receives the original response
type and content.

Comment thread middleware.ts
Comment on lines +4 to +9
export default function middleware(request: any, event: any) {
if (process.env.NEXT_PUBLIC_PLAYWRIGHT_TEST === "true") {
return NextResponse.next();
}
return clerkMiddleware()(request, event);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve the middleware contract and reuse the Clerk handler.

The new wrapper erases Next/Clerk type checking with any and reconstructs clerkMiddleware() for every request. Use NextRequest/NextFetchEvent and initialize the Clerk handler once at module scope.

🤖 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 `@middleware.ts` around lines 4 - 9, Update the default middleware function to
accept NextRequest and NextFetchEvent instead of any, and initialize
clerkMiddleware() once at module scope. Reuse that module-scoped Clerk handler
for non-Playwright requests while preserving the existing NextResponse.next()
test bypass and middleware contract.

Comment thread middleware.ts
Comment on lines +5 to +6
if (process.env.NEXT_PUBLIC_PLAYWRIGHT_TEST === "true") {
return NextResponse.next();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

The Playwright switch is a shared fail-open authentication control. A public flag changes both server request enforcement and client identity; if enabled outside isolated tests, the application can bypass Clerk and expose a shared mock user.

  • middleware.ts#L5-L6: require a server-only, non-production guard before skipping Clerk.
  • lib/auth/use-current-user.ts#L6-L18: provide the mock identity through a test-only provider or equivalent guarded mechanism.
📍 Affects 2 files
  • middleware.ts#L5-L6 (this comment)
  • lib/auth/use-current-user.ts#L6-L18
🤖 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 `@middleware.ts` around lines 5 - 6, Restrict the Playwright authentication
bypass in middleware.ts to a server-only, non-production test guard rather than
the public NEXT_PUBLIC flag alone. In lib/auth/use-current-user.ts, provide the
mock identity only through a matching test-only guarded provider or equivalent
mechanism, and ensure both paths cannot activate in production or outside
isolated tests.

google-labs-jules Bot and others added 4 commits July 22, 2026 18:42
…ent 500 errors

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…okens

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…2612169477250952-12186543232757801618

Fix Resolution Search unhandled 500 crashes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@app/actions.tsx`:
- Around line 224-235: Update the resolution_search_result persistence in
app/actions.tsx to avoid storing full base64 data URLs in messages.content.
Upload the generated image data through the existing Supabase/object-storage
flow, persist only the resulting storage paths or URLs for image, mapboxImage,
and googleImage, and ensure ResolutionCarousel rehydrates using those references
on reload. Preserve the existing IMAGE_PROCESSED sanitization behavior.

In `@lib/utils/index.ts`:
- Around line 90-91: In the model selection flow returning xai(), remove the
no-op requireVision ternary and assign the model ID directly to 'grok-latest'.
Keep the existing model choice unchanged for both vision-required and non-vision
paths.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 267f9ee5-5bc5-4124-adcd-6e91dc05c53d

📥 Commits

Reviewing files that changed from the base of the PR and between 4a9185d and a7bd3ee.

📒 Files selected for processing (3)
  • app/actions.tsx
  • lib/utils/index.ts
  • public/sw.js
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.44.1)
public/sw.js

[warning] Avoid using the initial state variable in setState
Context: setTimeout(t,e)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

🔇 Additional comments (6)
public/sw.js (1)

2-2: LGTM!

app/actions.tsx (4)

43-45: LGTM!


722-727: LGTM!


739-740: LGTM!


762-780: LGTM!

Also applies to: 790-816

lib/utils/index.ts (1)

44-45: LGTM!

Comment thread app/actions.tsx
Comment on lines +224 to +235
{
id: groupeId,
role: 'assistant',
content: JSON.stringify({
...analysisResult,
geoJson: geoJson, // Use reconstructed GeoJSON for storage/UI
image: dataUrl,
mapboxImage: mapboxDataUrl,
googleImage: googleDataUrl
}),
type: 'resolution_search_result'
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Persisting full base64 data URLs in messages.content will bloat chat storage.

image, mapboxImage, and googleImage embed complete base64 data URLs into the resolution_search_result content, which is serialized into the messages.content text column (lib/db/schema.ts). This is at odds with the sanitization just above (rewriting the user image to IMAGE_PROCESSED to avoid persisting images), and each row can grow to hundreds of KB–MBs, slowing every rehydration/read and inflating the DB.

Since these are only needed to re-render ResolutionCarousel on reload, consider persisting object-storage paths/URLs (e.g. upload to Supabase storage like the document flow does) and rehydrating from those instead of inlining base64.

🤖 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 `@app/actions.tsx` around lines 224 - 235, Update the resolution_search_result
persistence in app/actions.tsx to avoid storing full base64 data URLs in
messages.content. Upload the generated image data through the existing
Supabase/object-storage flow, persist only the resulting storage paths or URLs
for image, mapboxImage, and googleImage, and ensure ResolutionCarousel
rehydrates using those references on reload. Preserve the existing
IMAGE_PROCESSED sanitization behavior.

Comment thread lib/utils/index.ts
Comment on lines +90 to +91
const modelId = requireVision ? 'grok-latest' : 'grok-latest';
return xai(modelId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

No-op ternary — both branches return 'grok-latest'.

requireVision ? 'grok-latest' : 'grok-latest' has no effect and reads as leftover/incomplete logic (contrast with line 44, which differentiates). Collapse it to a direct assignment.

I verified the identifiers against the current xAI catalog: the grok-latest alias resolves to a model with input modalities ["text", "image"], so it is vision-capable and correct for both paths — but note it's a moving alias that silently upgrades, so pin an explicit version if you need reproducibility.

♻️ Proposed cleanup
-      const modelId = requireVision ? 'grok-latest' : 'grok-latest';
-      return xai(modelId);
+      return xai('grok-latest');
📝 Committable suggestion

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

Suggested change
const modelId = requireVision ? 'grok-latest' : 'grok-latest';
return xai(modelId);
return xai('grok-latest');
🤖 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 `@lib/utils/index.ts` around lines 90 - 91, In the model selection flow
returning xai(), remove the no-op requireVision ternary and assign the model ID
directly to 'grok-latest'. Keep the existing model choice unchanged for both
vision-required and non-vision paths.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
components/settings/components/settings.tsx (1)

294-304: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Prevent the connected Discord row from overflowing on mobile.

The single-line flex row contains a long provider ID, avatar, and button, but the text container has no min-w-0 or wrapping behavior. Long usernames/IDs can force horizontal overflow and make the Disconnect action difficult to reach on narrow screens.

Proposed responsive fix
- <div className="flex items-center gap-4 p-4 border rounded-xl bg-accent/20 border-primary/50">
+ <div className="flex flex-col gap-3 p-4 border rounded-xl bg-accent/20 border-primary/50 sm:flex-row sm:items-center">
...
- <div className="flex-1">
+ <div className="min-w-0 flex-1">
...
- <p className="text-xs text-muted-foreground">ID: {discordAccount.providerUserId}</p>
+ <p className="break-all text-xs text-muted-foreground">ID: {discordAccount.providerUserId}</p>
🤖 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 `@components/settings/components/settings.tsx` around lines 294 - 304, Update
the connected Discord row around the flex container holding the avatar, account
text, and Disconnect action so the text section can shrink on narrow screens and
long usernames/provider IDs wrap or truncate within its bounds. Preserve the
existing avatar and action layout while ensuring long values do not cause
horizontal overflow or push the Disconnect control off-screen.
🤖 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 `@components/settings/components/settings.tsx`:
- Around line 216-220: Update the className styling on the Tabs.Trigger elements
for System, Tools, Users, Map, and Account to use muted styling by default, then
apply the primary background and foreground styling through the
data-[state=active] variant so the selected tab is visually prominent.
- Line 77: Update the settings component around useUser and the Discord
linked-account UI to await Clerk readiness before rendering Discord controls;
disable the link button while clerkUser is unavailable, and guard the disconnect
handler so destroy/reload only run when an existing external account is present.

---

Outside diff comments:
In `@components/settings/components/settings.tsx`:
- Around line 294-304: Update the connected Discord row around the flex
container holding the avatar, account text, and Disconnect action so the text
section can shrink on narrow screens and long usernames/provider IDs wrap or
truncate within its bounds. Preserve the existing avatar and action layout while
ensuring long values do not cause horizontal overflow or push the Disconnect
control off-screen.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 24c14894-ea62-4e0c-bd2b-64729f97c229

📥 Commits

Reviewing files that changed from the base of the PR and between a7bd3ee and 66562c9.

📒 Files selected for processing (1)
  • components/settings/components/settings.tsx
📜 Review details
🔇 Additional comments (2)
components/settings/components/settings.tsx (2)

61-61: 🎯 Functional Correctness

Verify legacy selectedModel values are compatible with tool IDs.

ToolSelectionForm emits tool.id, but settings still hydrates the raw persisted selectedModel value. Existing model identifiers—or a default that is not present in tools—will leave no option selected and can be resubmitted unchanged. Add a migration/normalization or server-side allowlist, and verify QCX-Terra is an actual tool ID.

Also applies to: 242-249


28-28: LGTM!

Also applies to: 40-40, 74-75, 78-87, 199-205, 233-233, 305-336, 358-362, 368-368, 376-387

const [currentTab, setCurrentTab] = useState(initialTab === "model" ? "tool" : initialTab);
const { mapProvider, setMapProvider } = useSettingsStore();
const { user, loading: authLoading } = useCurrentUser();
const { user: clerkUser } = useUser();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the settings component around the mentioned lines.
fd -a 'settings.tsx$' . | sed 's#^\./##'
printf '\n--- relevant file sizes ---\n'
wc -l components/settings/components/settings.tsx 2>/dev/null || true

printf '\n--- outlines relevant symbols ---\n'
ast-grep outline components/settings/components/settings.tsx --view compact 2>/dev/null | sed -n '1,220p' || true

printf '\n--- context lines 55-360 ---\n'
cat -n components/settings/components/settings.tsx | sed -n '55,360p'

printf '\n--- Clerk usage summary ---\n'
rg -n "useUser|createExternalAccount|loaded|status|isLoaded|externalAccount|Discord|discord" components/settings/components/settings.tsx

Repository: QueueLab/QCX

Length of output: 20037


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- files for useCurrentUser ---\n'
rg -n "function useCurrentUser|const useCurrentUser|export .*useCurrentUser|useCurrentUser" components lib src 2>/dev/null || true

printf '\n--- package deps relevant to Clerk ---\n'
if [ -f package.json ]; then cat package.json | jq '.dependencies, .devDependencies' 2>/dev/null || cat package.json; fi
fd -a 'package.json$' . | xargs -r -n1 sh -c 'echo "--- $0 ---"; jq "{dependencies, devDependencies}" "$0" 2>/dev/null | grep -i clerk || true'

Repository: QueueLab/QCX

Length of output: 3873


Prevent Discord linking from silently no-oping while Clerk loads.

clerkUser can be temporarily unavailable while @clerk/nextjs loads: both the linked-account render path and the connect/disconnect handlers will evaluate to no-ops or throw UndefinedValueError, while the auth check is still waiting on useCurrentUser. Await Clerk readiness before rendering the Discord UI, disable the link button until clerkUser exists, and guard the disconnect handler with an existing external account before calling destroy/reload.

🤖 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 `@components/settings/components/settings.tsx` at line 77, Update the settings
component around useUser and the Discord linked-account UI to await Clerk
readiness before rendering Discord controls; disable the link button while
clerkUser is unavailable, and guard the disconnect handler so destroy/reload
only run when an existing external account is present.

Comment on lines +216 to 220
<Tabs.Trigger value="system-prompt" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">System</Tabs.Trigger>
<Tabs.Trigger value="tool" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Tools</Tabs.Trigger>
<Tabs.Trigger value="user-management" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Users</Tabs.Trigger>
<Tabs.Trigger value="map" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Map</Tabs.Trigger>
<Tabs.Trigger value="account" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Account</Tabs.Trigger>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the active tab visually distinct.

Every trigger uses bg-primary, while the active state changes it to bg-primary/80; consequently, inactive tabs are more prominent than the selected tab. Use muted styling by default and apply the primary styling in the active-state variant.

Proposed styling adjustment
- bg-primary text-primary-foreground ... data-[state=active]:bg-primary/80
+ bg-muted text-muted-foreground ... data-[state=active]:bg-primary data-[state=active]:text-primary-foreground
📝 Committable suggestion

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

Suggested change
<Tabs.Trigger value="system-prompt" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">System</Tabs.Trigger>
<Tabs.Trigger value="tool" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Tools</Tabs.Trigger>
<Tabs.Trigger value="user-management" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Users</Tabs.Trigger>
<Tabs.Trigger value="map" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Map</Tabs.Trigger>
<Tabs.Trigger value="account" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary/80">Account</Tabs.Trigger>
<Tabs.Trigger value="system-prompt" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-muted text-muted-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground">System</Tabs.Trigger>
<Tabs.Trigger value="tool" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-muted text-muted-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground">Tools</Tabs.Trigger>
<Tabs.Trigger value="user-management" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-muted text-muted-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground">Users</Tabs.Trigger>
<Tabs.Trigger value="map" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-muted text-muted-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground">Map</Tabs.Trigger>
<Tabs.Trigger value="account" className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-muted text-muted-foreground hover:bg-primary/90 h-10 px-4 py-2 data-[state=active]:bg-primary data-[state=active]:text-primary-foreground">Account</Tabs.Trigger>
🤖 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 `@components/settings/components/settings.tsx` around lines 216 - 220, Update
the className styling on the Tabs.Trigger elements for System, Tools, Users,
Map, and Account to use muted styling by default, then apply the primary
background and foreground styling through the data-[state=active] variant so the
selected tab is visually prominent.

@ngoiyaeric
ngoiyaeric merged commit 8c28540 into main Jul 23, 2026
3 of 4 checks passed
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.

3 participants