Skip to content

Allow selecting an app in home chat input#2832

Merged
wwwillchen merged 4 commits intodyad-sh:mainfrom
azizmejri1:select-app-home-chat
Mar 4, 2026
Merged

Allow selecting an app in home chat input#2832
wwwillchen merged 4 commits intodyad-sh:mainfrom
azizmejri1:select-app-home-chat

Conversation

@azizmejri1
Copy link
Copy Markdown
Collaborator

@azizmejri1 azizmejri1 commented Feb 28, 2026

@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience by allowing users to choose an existing application when initiating a new chat from the home screen. This change moves beyond the previous default of always creating a new application, providing greater flexibility and control over where new conversations are housed. It integrates app selection directly into the chat input, streamlining the workflow for users who wish to continue work within an established application.

Highlights

  • App Selection in Home Chat Input: Introduced the ability to select an existing application directly from the home chat input, allowing users to direct new conversations to a specific app instead of always creating a new one.
  • State Management for Selected App: A new Jotai atom, homeSelectedAppAtom, was added to manage the state of the currently selected application in the home chat input.
  • Dynamic Chat Submission Logic: The handleSubmit function in the HomePage was refactored to conditionally create a new application or create a new chat within a pre-selected existing application.
  • Enhanced User Interface: The HomeChatInput component now displays the selected app's name, provides an option to deselect it, and dynamically adjusts its placeholder text based on whether an app is chosen.
  • Improved Loading Feedback: Loading messages displayed during chat submission are now context-aware, differentiating between 'building a new app' and 'starting a new chat in an existing app'.
Changelog
  • src/atoms/chatAtoms.ts
    • Imported ListedApp type from @/ipc/types/app.
    • Added homeSelectedAppAtom to store the currently selected ListedApp or null.
  • src/components/chat/HomeChatInput.tsx
    • Imported FolderOpenIcon and XIcon from lucide-react.
    • Imported homeSelectedAppAtom and useState.
    • Imported useLoadApps hook and AppSearchDialog component.
    • Added state for appSearchOpen and selectedApp using Jotai and React's useState.
    • Implemented handleSelectApp function to update the selectedApp state.
    • Modified the onSubmit call to include selectedApp.
    • Updated the placeholder text to be dynamic based on selectedApp.
    • Added UI elements for displaying the selected app, opening the app search dialog, and deselecting the app.
    • Integrated AppSearchDialog for app selection.
  • src/i18n/locales/en/home.json
    • Added new translation keys: startingChat and creatingNewChat.
  • src/pages/home.tsx
    • Imported ListedApp type.
    • Updated HomeSubmitOptions interface to include an optional selectedApp property.
    • Added loadingMode state to differentiate between new app creation and existing app chat creation.
    • Refactored handleSubmit to check for selectedApp and execute different logic paths for creating a new app or a new chat within an existing app.
    • Updated streamMessage and selectChat calls to use the dynamically determined chatId and appId.
    • Modified loading overlay messages to display startingChat or creatingNewChat based on loadingMode.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with πŸ‘ and πŸ‘Ž on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

gemini-code-assist[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

βœ… Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

chatgpt-codex-connector[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

@github-actions
Copy link
Copy Markdown
Contributor

πŸ” Dyadbot Code Review Summary

Verdict: πŸ€” NOT SURE - Potential issues

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard.

Issues Summary

Severity File Issue
🟑 MEDIUM src/components/AppSearchDialog.tsx:89-98 Ctrl+K shortcut conflict with sidebar AppSearchDialog
🟑 MEDIUM src/pages/home.tsx:232 Misleading error message for existing-app flow
🟒 Low Priority Notes (5 items)
  • "No app selected" microcopy may confuse users - src/components/chat/HomeChatInput.tsx:209 - Phrasing implies user must select an app, but it's optional. Consider "Existing app" or showing only the icon when deselected.
  • span with role="button" instead of semantic button - src/components/chat/HomeChatInput.tsx:211-231 - The "X" deselect control uses <span role="button"> instead of a <button> element. Using a semantic button is more accessible.
  • Duplicated ListedApp-to-AppSearchResult mapping - src/components/chat/HomeChatInput.tsx:253-259 - Same mapping pattern (setting matchedChatTitle: null, matchedChatMessage: null) exists in both AppList.tsx and here. Consider having AppSearchDialog accept ListedApp[] directly.
  • Hardcoded English strings not using i18n - src/components/chat/HomeChatInput.tsx - New strings ("No app selected", "Change selected app", "Select an existing app", "Deselect app") are hardcoded instead of using t().
  • Stale app reference edge case - src/components/chat/HomeChatInput.tsx:75-81 - If user selects an app then deletes it from the sidebar, the global atom still holds the stale reference. Submit would fail with a misleading error.
🚫 Dropped False Positives (4 items)
  • Translation keys missing from non-English locales - Dropped: i18n libraries fall back to the default (English) locale; localization is typically handled in a separate workflow.
  • Apps list re-mapped on every render - Dropped: The dialog is controlled by open prop and likely short-circuits rendering when closed. The mapping overhead is negligible for the expected number of apps.
  • loadingMode initialization concern - Dropped: The code already sets loadingMode immediately before setIsLoading(true) in the same synchronous block, so React batches them correctly.
  • Zero apps empty state in search dialog - Dropped: Users without apps are unlikely to click the app selector. The existing CommandEmpty state is sufficient.

Generated by Dyadbot multi-agent code review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR adds the ability for users to select an existing app from the home chat input before sending a message, so the new chat is created inside that app instead of always creating a brand-new app. The change introduces a homeSelectedAppAtom Jotai atom, wires AppSearchDialog into HomeChatInput, and branches handleSubmit in home.tsx to call ipc.chat.createChat (returning the existing app's chat) versus ipc.app.createApp (original flow).

Key changes:

  • New homeSelectedAppAtom global atom (ListedApp | null) tracks the selected app across the home page session.
  • HomeChatInput renders an app-selector button and a clear button, plus conditionally mounts AppSearchDialog with disableShortcut to avoid conflicting with the global Cmd/Ctrl+K shortcut.
  • AppSearchDialog gains a disableShortcut prop (with corrected useEffect dependency array) to support the embedded use-case.
  • home.tsx's handleSubmit conditionally calls ipc.chat.createChat(selectedApp.id) for the existing-app path, reusing the same downstream streaming and navigation logic.
  • Two E2E tests cover selecting an app, sending a message, and clearing the selection.

The main concern is the nested <button> inside <button> in the app-selector UI, which is invalid HTML and can produce inconsistent cross-browser behavior.

Confidence Score: 3/5

  • Safe to merge after addressing the nested button HTML violation; the core logic is sound.
  • The existing-app flow correctly calls ipc.chat.createChat and reuses the proven streaming/navigation path. The two new E2E tests provide good coverage. The score is docked primarily because of the invalid nested <button> structure in HomeChatInput, which violates the HTML spec and can cause unpredictable behavior when the clear button is clicked in certain browsers. The two style-level concerns (stale-app silent close and atom cleared before error recovery) are minor UX issues that don't block correctness.
  • src/components/chat/HomeChatInput.tsx β€” nested button structure needs to be refactored.

Important Files Changed

Filename Overview
src/components/chat/HomeChatInput.tsx Adds app selector UI with a clear button nested inside the trigger button β€” an invalid HTML structure (button-in-button) that is the main concern in this PR.
src/pages/home.tsx Branches handleSubmit to either create a new app or reuse an existing one via ipc.chat.createChat; logic is sound but selected app atom is cleared before async errors are catchable.
src/atoms/chatAtoms.ts Adds homeSelectedAppAtom holding `ListedApp
src/components/AppSearchDialog.tsx Adds optional disableShortcut prop to skip Cmd/Ctrl+K registration; the dependency array is correctly updated to include the new prop.
src/i18n/locales/en/home.json Adds three new i18n keys (failedCreateChat, startingChat, creatingNewChat) for the new existing-app flow; no issues.
e2e-tests/home_chat_existing_app.spec.ts Adds two E2E tests covering app selection and clear β€” tests are well-structured and use appropriate waitFor timeouts.

Sequence Diagram

sequenceDiagram
    participant User
    participant HomeChatInput
    participant homeSelectedAppAtom
    participant AppSearchDialog
    participant HomePage
    participant IPC

    User->>HomeChatInput: Clicks "No app selected" button
    HomeChatInput->>AppSearchDialog: setAppSearchOpen(true) β†’ mounts dialog
    User->>AppSearchDialog: Selects an app
    AppSearchDialog->>HomeChatInput: onSelectApp(appId)
    HomeChatInput->>homeSelectedAppAtom: setSelectedApp(app)
    HomeChatInput->>AppSearchDialog: setAppSearchOpen(false) β†’ unmounts dialog

    User->>HomeChatInput: Types message and submits
    HomeChatInput->>HomePage: onSubmit({ attachments, selectedApp })
    HomeChatInput->>homeSelectedAppAtom: setSelectedApp(null)

    alt selectedApp is set (existing app flow)
        HomePage->>IPC: ipc.chat.createChat(selectedApp.id)
        IPC-->>HomePage: chatId (number)
    else no selectedApp (new app flow)
        HomePage->>IPC: ipc.app.createApp(...)
        IPC-->>HomePage: { app, chatId }
    end

    HomePage->>IPC: streamMessage({ prompt, chatId, attachments })
    HomePage->>HomePage: refreshApps / invalidateQueries
    HomePage->>HomePage: selectChat({ chatId, appId })
Loading

Last reviewed commit: dfee809

github-actions[bot]

This comment was marked as resolved.

@github-actions github-actions bot added the needs-human:review-issue ai agent flagged an issue that requires human review label Feb 28, 2026
azizmejri1 and others added 3 commits March 1, 2026 01:03
- Replace <span role="button"> with native <button> for accessibility in HomeChatInput
- Add disableShortcut prop to AppSearchDialog to prevent duplicate Cmd/Ctrl+K listeners
- Fix misleading error message when creating a chat in an existing app fails

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@wwwillchen
Copy link
Copy Markdown
Collaborator

@BugBot run

@azizmejri1
Copy link
Copy Markdown
Collaborator Author

πŸ€– Claude Code Review Summary

PR Confidence: 4/5

All review comments addressed with code changes. Minor concerns remain around edge cases with the app selector UX but no blocking issues.

Unresolved Threads

No unresolved threads

Resolved Threads

Issue Rationale Link
Use native <button> instead of <span role="button"> for accessibility Valid accessibility improvement β€” native buttons provide keyboard handling by default View
Duplicate Cmd/Ctrl+K shortcut listeners (2 threads) Added disableShortcut prop to AppSearchDialog, disabled in HomeChatInput to prevent conflict with sidebar instance View, View
Misleading error message for existing-app flow Per Principle #4: Transparent Over Magical, error messages should accurately reflect what happened β€” now shows "Failed to create chat" when selectedApp is truthy View
Product Principle Suggestions

No suggestions β€” principles were clear enough for all decisions.


πŸ€– Generated by Claude Code

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid β€” if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/components/chat/HomeChatInput.tsx">

<violation number="1" location="src/components/chat/HomeChatInput.tsx:242">
P2: Avoid conditionally rendering Radix Dialog components; use only the `open` prop to preserve exit animations.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

</div>
</div>

{appSearchOpen && (
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 1, 2026

Choose a reason for hiding this comment

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

P2: Avoid conditionally rendering Radix Dialog components; use only the open prop to preserve exit animations.

Prompt for AI agents
Check if this issue is valid β€” if so, understand the root cause and fix it. At src/components/chat/HomeChatInput.tsx, line 242:

<comment>Avoid conditionally rendering Radix Dialog components; use only the `open` prop to preserve exit animations.</comment>

<file context>
@@ -246,18 +239,21 @@ export function HomeChatInput({
-          matchedChatMessage: null,
-        }))}
-      />
+      {appSearchOpen && (
+        <AppSearchDialog
+          open={appSearchOpen}
</file context>
Fix with Cubic

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfee809705

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 100 to +101
clearAttachments();
setSelectedApp(null);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retain selected app until submit succeeds

handleCustomSubmit clears homeSelectedAppAtom immediately, before the async submit flow in HomePage.handleSubmit completes. When ipc.chat.createChat(selectedApp.id) fails (for example, if the selected app was removed or IPC returns an error), the catch path in src/pages/home.tsx leaves the user on the home screen with their prompt still present but no selected app, so a retry silently falls back to creating a new app instead of targeting the originally chosen one.

Useful? React with πŸ‘Β / πŸ‘Ž.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 1, 2026

πŸ” Dyadbot Code Review Summary

Verdict: πŸ€” NOT SURE - Potential issues

Reviewed by 3 independent agents: Correctness Expert, Code Health Expert, UX Wizard.

Issues Summary

Severity File Issue
πŸ”΄ HIGH src/components/chat/HomeChatInput.tsx:192-225 Nested <button> elements are invalid HTML (accessibility + interaction)
🟑 MEDIUM src/components/chat/HomeChatInput.tsx:75-81 handleSelectApp does redundant ID round-trip through apps array
🟒 Low Priority Notes (5 items)
  • selectedApp atom cleared before async onSubmit completes - src/components/chat/HomeChatInput.tsx:99-105 β€” Fragile ordering: selectedApp is cleared synchronously while onSubmit is async. Works due to closure capture but is non-obvious.
  • E2E test only checks app name is truthy - e2e-tests/home_chat_existing_app.spec.ts:53 β€” Test should assert currentAppName === appName.trim() to verify the correct app was navigated to.
  • 'No app selected' label implies required selection - src/components/chat/HomeChatInput.tsx:207-210 β€” Label reads like an unfilled required field. Consider "Use existing app" to communicate this is optional.
  • App name truncation without full name in tooltip - src/components/chat/HomeChatInput.tsx:207-210 β€” Long app names are truncated at 150px but tooltip shows "Change selected app" instead of the full name.
  • loadingMode state needs a comment - src/pages/home.tsx:66 β€” Not obvious why this needs to be separate state vs. derived from selectedApp (answer: selectedApp is cleared from atom before overlay renders).
🚫 Dropped False Positives (5 items)
  • isLoading never reset on success path β€” Dropped: Pre-existing pattern; both code paths call selectChat() which navigates away and unmounts HomePage. Not a new issue.
  • loadingMode stale during re-renders β€” Dropped: React 18 automatic batching ensures setLoadingMode and setIsLoading render together. No observable stale state.
  • refreshApps called for existing app flow β€” Dropped: Harmless and arguably useful (may update last-modified times, chat counts). Not a real issue.
  • Typing placeholder animation stops abruptly β€” Dropped: Speculative UX concern that would require testing to confirm. The hook runs in the background regardless.
  • disableShortcut pattern is fragile β€” Dropped: The reviewer themselves noted no actual bug exists. The pattern is correct.

Generated by Dyadbot multi-agent code review

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +193 to +225
<TooltipTrigger
render={
<button
onClick={() => setAppSearchOpen(true)}
className={cn(
"cursor-pointer px-2 py-1 ml-1.5 text-xs font-medium rounded-lg transition-colors flex items-center gap-1",
selectedApp
? "bg-primary/10 text-primary hover:bg-primary/15"
: "text-foreground/80 hover:text-foreground hover:bg-muted/60",
)}
data-testid="home-app-selector"
/>
}
>
<FolderOpenIcon size={14} />
<span className="truncate max-w-[150px]">
{selectedApp ? selectedApp.name : "No app selected"}
</span>
{selectedApp && (
<button
type="button"
onClick={(e) => {
e.stopPropagation();
setSelectedApp(null);
}}
className="hover:bg-primary/20 rounded-sm p-0.5 transition-colors"
aria-label="Deselect app"
data-testid="home-app-selector-clear"
>
<XIcon size={12} />
</button>
)}
</TooltipTrigger>
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.

Nested <button> inside <button> β€” invalid HTML

The clear/deselect button (data-testid="home-app-selector-clear") is a child of <TooltipTrigger render={<button .../>}>. Because @base-ui/react's render prop uses the provided element as the container and injects TooltipTrigger's children into it, the rendered DOM ends up as:

<button data-testid="home-app-selector">   <!-- outer trigger -->
  ...
  <button data-testid="home-app-selector-clear">   <!-- NESTED – invalid HTML -->
    <XIcon />
  </button>
</button>

Nesting interactive elements (<button> inside <button>) is explicitly forbidden by the HTML spec. Browsers handle it inconsistently: some silently break the nesting and move the inner button outside, which means e.stopPropagation() in the clear handler may not behave as expected everywhere.

Fix: Lift the clear button out of TooltipTrigger and position it alongside (not inside) the trigger, e.g. by making the whole row a flex container with the TooltipTrigger button and the clear <button> as siblings. This preserves the same visual layout while producing valid HTML:

<div className="flex items-center gap-1">
  <Tooltip>
    <TooltipTrigger render={<button onClick={() => setAppSearchOpen(true)} ... />}>
      <FolderOpenIcon size={14} />
      <span className="truncate max-w-[150px]">
        {selectedApp ? selectedApp.name : "No app selected"}
      </span>
    </TooltipTrigger>
    <TooltipContent>...</TooltipContent>
  </Tooltip>
  {selectedApp && (
    <button
      type="button"
      onClick={() => setSelectedApp(null)}
      ...
      data-testid="home-app-selector-clear"
    >
      <XIcon size={12} />
    </button>
  )}
</div>
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/HomeChatInput.tsx
Line: 193-225

Comment:
**Nested `<button>` inside `<button>` β€” invalid HTML**

The clear/deselect button (`data-testid="home-app-selector-clear"`) is a child of `<TooltipTrigger render={<button .../>}>`. Because `@base-ui/react`'s `render` prop uses the provided element as the container and injects `TooltipTrigger`'s children into it, the rendered DOM ends up as:

```html
<button data-testid="home-app-selector">   <!-- outer trigger -->
  ...
  <button data-testid="home-app-selector-clear">   <!-- NESTED – invalid HTML -->
    <XIcon />
  </button>
</button>
```

Nesting interactive elements (`<button>` inside `<button>`) is explicitly forbidden by the HTML spec. Browsers handle it inconsistently: some silently break the nesting and move the inner button outside, which means `e.stopPropagation()` in the clear handler may not behave as expected everywhere.

**Fix**: Lift the clear button out of `TooltipTrigger` and position it alongside (not inside) the trigger, e.g. by making the whole row a `flex` container with the `TooltipTrigger` button and the clear `<button>` as siblings. This preserves the same visual layout while producing valid HTML:

```jsx
<div className="flex items-center gap-1">
  <Tooltip>
    <TooltipTrigger render={<button onClick={() => setAppSearchOpen(true)} ... />}>
      <FolderOpenIcon size={14} />
      <span className="truncate max-w-[150px]">
        {selectedApp ? selectedApp.name : "No app selected"}
      </span>
    </TooltipTrigger>
    <TooltipContent>...</TooltipContent>
  </Tooltip>
  {selectedApp && (
    <button
      type="button"
      onClick={() => setSelectedApp(null)}
      ...
      data-testid="home-app-selector-clear"
    >
      <XIcon size={12} />
    </button>
  )}
</div>
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Multi-agent review: 2 issue(s) found (1 HIGH, 1 MEDIUM)

>
<XIcon size={12} />
</button>
)}
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.

πŸ”΄ HIGH | accessibility / interaction

Nested <button> elements are invalid HTML

The clear (X) <button> on line 212 is nested inside the outer <button> rendered by TooltipTrigger (line 193). Nested interactive elements are invalid per the HTML spec and cause:

  • Unpredictable click handling: Clicking the X may fire both the inner click (clear) and the outer click (open dialog) simultaneously in some browsers
  • Broken keyboard navigation: Screen readers and keyboard users cannot reliably interact with the inner button
  • DOM parsing issues: Browsers may restructure the DOM in unexpected ways when encountering nested buttons

Found by 2/3 reviewers (Code Health Expert, UX Wizard).

πŸ’‘ Suggestion: Restructure so the clear button is a sibling of the selector button, not a child. For example, wrap both in a flex <div> β€” the tooltip wraps just the selector button, and the X button sits alongside it:

<div className="flex items-center gap-1">
  <Tooltip>
    <TooltipTrigger render={<button ... />}>
      <FolderOpenIcon size={14} />
      <span className="truncate max-w-[150px]">{...}</span>
    </TooltipTrigger>
    <TooltipContent>{...}</TooltipContent>
  </Tooltip>
  {selectedApp && (
    <button type="button" onClick={() => setSelectedApp(null)} ...>
      <XIcon size={12} />
    </button>
  )}
</div>

setSelectedApp(app);
}
setAppSearchOpen(false);
};
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.

🟑 MEDIUM | unnecessary complexity

handleSelectApp does a redundant ID round-trip through apps array

AppSearchDialog calls onSelectApp(appId) with just the numeric ID, then handleSelectApp immediately does apps.find(a => a.id === appId) to recover the full app object. The dialog already has the full AppSearchResult (id, name, createdAt) available at the call site.

This pattern has two issues:

  1. If apps hasn't finished loading or is stale, find() returns undefined and the selection is silently dropped β€” no feedback to the user
  2. It requires HomeChatInput to call useLoadApps() solely to support this lookup, creating an unnecessary dependency

Found by 2/3 reviewers (Correctness Expert, Code Health Expert).

πŸ’‘ Suggestion: Change onSelectApp to accept the full app object (or { id, name }) instead of just the ID. This eliminates the lookup and the need for useLoadApps() in this component.

Copy link
Copy Markdown
Collaborator

@wwwillchen wwwillchen left a comment

Choose a reason for hiding this comment

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

thanks! merging

@wwwillchen wwwillchen merged commit c4cdf7b into dyad-sh:main Mar 4, 2026
9 of 10 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 5, 2026

🎭 Playwright Test Results

❌ Some tests failed

OS Passed Failed Flaky Skipped
🍎 macOS 369 0 5 120
πŸͺŸ Windows 372 1 8 120

Summary: 741 passed, 1 failed, 13 flaky, 240 skipped

Failed Tests

πŸͺŸ Windows

  • reject.spec.ts > reject
    • TimeoutError: locator.click: Timeout 30000ms exceeded.

⚠️ Flaky Tests

🍎 macOS

  • capacitor.spec.ts > capacitor upgrade and sync works (passed after 1 retry)
  • logs_server.spec.ts > system messages UI shows server logs with correct type (passed after 1 retry)
  • setup_flow.spec.ts > Setup Flow > setup banner shows correct state when node.js is installed (passed after 1 retry)
  • smart_context_balanced.spec.ts > smart context balanced - simple (passed after 2 retries)
  • smart_context_options.spec.ts > switching smart context mode saves the right setting (passed after 1 retry)

πŸͺŸ Windows

  • chat_input.spec.ts > send button disabled during pending proposal (passed after 1 retry)
  • chat_tabs.spec.ts > closing a tab removes it and selects adjacent tab (passed after 1 retry)
  • context_manage.spec.ts > manage context - exclude paths with smart context (passed after 1 retry)
  • edit_code.spec.ts > edit code (passed after 1 retry)
  • git_collaboration.spec.ts > Git Collaboration > should create, switch, rename, merge, and delete branches (passed after 1 retry)
  • security_review.spec.ts > security review - multi-select and fix issues (passed after 1 retry)
  • setup_flow.spec.ts > Setup Flow > setup banner shows correct state when node.js is installed (passed after 1 retry)
  • template-create-nextjs.spec.ts > create next.js app (passed after 2 retries)

πŸ“Š View full report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-human:review-issue ai agent flagged an issue that requires human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants