Skip to content

feat(wework): improve mobile project controls - #1312

Merged
qdaxb merged 1 commit into
wecode-ai:mainfrom
Micro66:human/finch-20260608-050919
Jun 8, 2026
Merged

qdaxb merged 1 commit into
wecode-ai:mainfrom
Micro66:human/finch-20260608-050919

Conversation

@Micro66

@Micro66 Micro66 commented Jun 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added branch selection and switching functionality to project work controls, with searchable branch dropdown UI.
    • Introduced searchable select components for Git repository and branch picking, replacing standard dropdowns.
    • Added mobile-responsive branch management interface with bottom-sheet styling on mobile devices.
    • Enabled branch refresh and creation workflows in project environments.
  • Tests

    • Added comprehensive test coverage for branch switching, creation, and UI state handling.
  • Localization

    • Added English and Chinese translations for branch and repository search interfaces.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a new searchable dropdown component (SearchableSelect) and a branch-management component (BranchSelector) that integrates branch selection/creation UI into project work contexts. It refactors project creation and environment info popovers to use the new patterns, wires branch operations through the desktop and mobile workbench layouts with full mobile-responsive support, and adds comprehensive test coverage with i18n support.

Changes

Branch Selection and Management Feature

Layer / File(s) Summary
SearchableSelect reusable component
wework/src/components/common/SearchableSelect.tsx
New dropdown component with client-side fuzzy search, dynamic above/below placement, outside-click and Escape closing; provides foundation for branch and repository selection.
BranchSelector component
wework/src/components/common/BranchSelector.tsx, wework/src/components/chat/ChatInput.test.tsx
Branch-specific UI wrapping async operations (refresh, list, checkout, create) with responsive popover/bottom-sheet rendering, error handling, subsequence filtering, and create-branch form; includes tests for branch switching, creation, and execution-mode-locked hiding.
ProjectWorkBar branch support and mobile UI
wework/src/components/chat/composer/ProjectWorkBar.tsx
Extends props with optional branch fields and conditionally renders BranchSelector for workspace execution mode; adds comprehensive mobile responsive behavior with sheet headers, backdrops, data-mobile attributes, and mobile-aware spacing/sizing for menus and buttons.
ChatInput and ProjectChatComposer branch props
wework/src/components/chat/ChatInput.tsx, wework/src/components/chat/composer/ProjectChatComposer.tsx
Extends ProjectWorkControls interface with optional branch-related fields and passes them through the composer to ProjectWorkBar.
DesktopWorkbenchLayout branch operations wiring
wework/src/components/layout/DesktopWorkbenchLayout.tsx
Refactors projectWorkWithCreation to wire environment branch state (branchName, branchLoading) and route branch list/checkout/create callbacks to environment handlers; adds effect to refresh environment info on project changes without active task.
MobileWorkbenchLayout branch operations wiring
wework/src/components/layout/MobileWorkbenchLayout.tsx
Adds optional branch callback props, introduces environmentInfo state with async refresh callback, extends effectiveProjectWork to expose branch operations that call environment handlers then refresh, and adds effect for project-change-triggered refresh.
EnvironmentInfoPopover: migrate to BranchSelector
wework/src/components/layout/EnvironmentInfoPopover.tsx
Removes inline branch dropdown implementation and replaces with BranchSelector component; simplifies state and open/close handling.
ProjectCreateDialog: SearchableSelect for repos/branches
wework/src/components/projects/ProjectCreateDialog.tsx
Replaces native <select> controls with SearchableSelect for Git repositories and branches; adds uniqueRepositories() deduplication helper and memoized option lists with localized default-branch labeling.
Test coverage and i18n
wework/src/components/layout/DesktopWorkbenchLayout.test.tsx, wework/src/components/projects/ProjectCreateDialog.test.tsx, wework/src/components/layout/MobileWorkbenchLayout.test.tsx, wework/src/i18n/locales/*/common.json
Updates existing tests to interact with new select components via clicks and search flows, adds new mobile branch selection test, and adds English/Chinese translation keys for search labels, no-results messages, and default-branch suffix.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • wecode-ai/Wegent#1301: Overlaps at the ProjectWorkControls → ProjectChatComposer → ProjectWorkBar prop surface where branch fields are added alongside project-work menu wiring.
  • wecode-ai/Wegent#1256: Provides the backend/frontend branch operation implementations (listProjectBranches, checkoutProjectBranch, createAndCheckoutProjectBranch) that this PR's new UI components call via callbacks.
  • wecode-ai/Wegent#1177: Introduces the base ProjectWorkBar/ChatInput wiring that this PR extends with branch-selection UI and new branch-related props.

Suggested reviewers

  • qdaxb

Poem

🐰 A dropdown so wise, with search in its eyes,
Branches flip-flop with responsive surprise—
On mobile, a sheet; on desktop, a hover,
Where rabbits once hopped, now users discover!
New selects bloom bright, in English and Chinese,
Making project creation perfectly at ease. ✨

🚥 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 partially related but overly broad—it mentions "mobile project controls" improvements, yet the changeset also adds branch selector functionality across desktop and mobile components, introduces SearchableSelect, and extends the ProjectWorkControls interface significantly beyond mobile-specific changes. Consider a more specific title that reflects the primary change, such as 'feat(wework): add branch selection and SearchableSelect components' or explicitly clarify that this includes both mobile and desktop improvements.
✅ 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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@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.

🧹 Nitpick comments (3)
wework/src/components/common/SearchableSelect.tsx (1)

117-127: ⚖️ Poor tradeoff

Consider adding keyboard navigation for better accessibility.

The search input has autoFocus (good), but the component lacks arrow key navigation and Enter-to-select functionality for options. Users must click to select filtered options.

Consider adding:

  • Arrow Up/Down to navigate filtered options
  • Enter to select highlighted option
  • Visual highlight for keyboard-focused option

This would improve accessibility and keyboard-only user experience.

🤖 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 `@wework/src/components/common/SearchableSelect.tsx` around lines 117 - 127,
The SearchableSelect component currently focuses the input but lacks keyboard
navigation; add a highlightedIndex state (e.g., const [highlightedIndex,
setHighlightedIndex]) and a handleKeyDown on the search input to: 1) on
ArrowDown/ArrowUp increment/decrement highlightedIndex constrained to
filteredOptions.length, 2) on Enter call the existing select handler (e.g.,
selectOption or onSelect) with filteredOptions[highlightedIndex], and 3) on
Escape clear the query/close the list. Update the options rendering (where
filteredOptions is mapped) to apply a visible highlight class and aria-selected
for the item at highlightedIndex, and ensure the input uses that handleKeyDown
instead of only onChange (preserving setQuery and autoFocus).
wework/src/components/layout/MobileWorkbenchLayout.tsx (1)

179-202: 💤 Low value

Consider memoizing branch callback wrappers for performance.

The inline arrow functions for onListBranches, onCheckoutBranch, and onCreateBranch are recreated on every render, which could cause unnecessary re-renders in ProjectWorkBar or BranchSelector. Consider extracting them to useCallback:

♻️ Optional refactor
+  const handleListBranches = useCallback(async () => {
+    if (!state.currentProject || !onListEnvironmentBranches) return []
+    return onListEnvironmentBranches(state.currentProject)
+  }, [state.currentProject, onListEnvironmentBranches])
+
+  const handleCheckoutBranch = useCallback(
+    async (branchName: string) => {
+      if (!state.currentProject || !onCheckoutEnvironmentBranch) return
+      await onCheckoutEnvironmentBranch(state.currentProject, branchName)
+      await refreshEnvironmentInfo()
+    },
+    [state.currentProject, onCheckoutEnvironmentBranch, refreshEnvironmentInfo],
+  )
+
+  const handleCreateBranch = useCallback(
+    async (branchName: string) => {
+      if (!state.currentProject || !onCreateEnvironmentBranch) return
+      await onCreateEnvironmentBranch(state.currentProject, branchName)
+      await refreshEnvironmentInfo()
+    },
+    [state.currentProject, onCreateEnvironmentBranch, refreshEnvironmentInfo],
+  )
+
   const effectiveProjectWork: ProjectWorkControls = {
     ...baseProjectWork,
     branchName: environmentInfo.branchName,
     branchLoading: environmentInfo.loading,
     onRefreshBranch: refreshEnvironmentInfo,
-    onListBranches:
-      state.currentProject && onListEnvironmentBranches
-        ? () => onListEnvironmentBranches(state.currentProject)
-        : undefined,
-    onCheckoutBranch:
-      state.currentProject && onCheckoutEnvironmentBranch
-        ? async branchName => {
-            await onCheckoutEnvironmentBranch(state.currentProject, branchName)
-            await refreshEnvironmentInfo()
-          }
-        : undefined,
-    onCreateBranch:
-      state.currentProject && onCreateEnvironmentBranch
-        ? async branchName => {
-            await onCreateEnvironmentBranch(state.currentProject, branchName)
-            await refreshEnvironmentInfo()
-          }
-        : undefined,
+    onListBranches: state.currentProject && onListEnvironmentBranches ? handleListBranches : undefined,
+    onCheckoutBranch: state.currentProject && onCheckoutEnvironmentBranch ? handleCheckoutBranch : undefined,
+    onCreateBranch: state.currentProject && onCreateEnvironmentBranch ? handleCreateBranch : undefined,
   }
🤖 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 `@wework/src/components/layout/MobileWorkbenchLayout.tsx` around lines 179 -
202, The inline callback wrappers assigned into effectiveProjectWork
(onListBranches, onCheckoutBranch, onCreateBranch) are recreated each render;
wrap each wrapper with React.useCallback so they are stable and only change when
their dependencies change (e.g., state.currentProject,
onListEnvironmentBranches, onCheckoutEnvironmentBranch,
onCreateEnvironmentBranch, refreshEnvironmentInfo), then reference those
memoized callbacks in effectiveProjectWork instead of creating new arrow
functions inline.
wework/src/components/layout/DesktopWorkbenchLayout.tsx (1)

244-253: 💤 Low value

Consider memoizing projectWorkWithCreation for performance.

The object literal is recreated on every render, and onListBranches creates a new arrow function each time. While the impact is likely minimal, consider using useMemo if you observe unnecessary re-renders in ProjectWorkBar or BranchSelector:

♻️ Optional refactor
-  const projectWorkWithCreation: ProjectWorkControls = {
-    ...projectWork,
-    onCreateProjectMode: openProjectFromWorkMenu,
-    branchName: environmentInfo.branchName,
-    branchLoading: environmentInfo.loading,
-    onRefreshBranch: refreshEnvironmentInfo,
-    onListBranches: () => onListEnvironmentBranches(environmentProject),
-    onCheckoutBranch: handleCheckoutEnvironmentBranch,
-    onCreateBranch: handleCreateEnvironmentBranch,
-  }
+  const projectWorkWithCreation: ProjectWorkControls = useMemo(
+    () => ({
+      ...projectWork,
+      onCreateProjectMode: openProjectFromWorkMenu,
+      branchName: environmentInfo.branchName,
+      branchLoading: environmentInfo.loading,
+      onRefreshBranch: refreshEnvironmentInfo,
+      onListBranches: () => onListEnvironmentBranches(environmentProject),
+      onCheckoutBranch: handleCheckoutEnvironmentBranch,
+      onCreateBranch: handleCreateEnvironmentBranch,
+    }),
+    [
+      projectWork,
+      openProjectFromWorkMenu,
+      environmentInfo.branchName,
+      environmentInfo.loading,
+      refreshEnvironmentInfo,
+      onListEnvironmentBranches,
+      environmentProject,
+      handleCheckoutEnvironmentBranch,
+      handleCreateEnvironmentBranch,
+    ],
+  )
🤖 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 `@wework/src/components/layout/DesktopWorkbenchLayout.tsx` around lines 244 -
253, The object literal projectWorkWithCreation is recreated each render (and
onListBranches creates a new closure), so wrap its creation in useMemo to avoid
unnecessary re-renders of consumers like ProjectWorkBar or BranchSelector;
compute projectWorkWithCreation = useMemo(() => ({ ...projectWork,
onCreateProjectMode: openProjectFromWorkMenu, branchName:
environmentInfo.branchName, branchLoading: environmentInfo.loading,
onRefreshBranch: refreshEnvironmentInfo, onListBranches: () =>
onListEnvironmentBranches(environmentProject), onCheckoutBranch:
handleCheckoutEnvironmentBranch, onCreateBranch: handleCreateEnvironmentBranch
}), [projectWork, openProjectFromWorkMenu, environmentInfo.branchName,
environmentInfo.loading, refreshEnvironmentInfo, onListEnvironmentBranches,
environmentProject, handleCheckoutEnvironmentBranch,
handleCreateEnvironmentBranch]) so the object and the onListBranches closure
only change when their inputs change.
🤖 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.

Nitpick comments:
In `@wework/src/components/common/SearchableSelect.tsx`:
- Around line 117-127: The SearchableSelect component currently focuses the
input but lacks keyboard navigation; add a highlightedIndex state (e.g., const
[highlightedIndex, setHighlightedIndex]) and a handleKeyDown on the search input
to: 1) on ArrowDown/ArrowUp increment/decrement highlightedIndex constrained to
filteredOptions.length, 2) on Enter call the existing select handler (e.g.,
selectOption or onSelect) with filteredOptions[highlightedIndex], and 3) on
Escape clear the query/close the list. Update the options rendering (where
filteredOptions is mapped) to apply a visible highlight class and aria-selected
for the item at highlightedIndex, and ensure the input uses that handleKeyDown
instead of only onChange (preserving setQuery and autoFocus).

In `@wework/src/components/layout/DesktopWorkbenchLayout.tsx`:
- Around line 244-253: The object literal projectWorkWithCreation is recreated
each render (and onListBranches creates a new closure), so wrap its creation in
useMemo to avoid unnecessary re-renders of consumers like ProjectWorkBar or
BranchSelector; compute projectWorkWithCreation = useMemo(() => ({
...projectWork, onCreateProjectMode: openProjectFromWorkMenu, branchName:
environmentInfo.branchName, branchLoading: environmentInfo.loading,
onRefreshBranch: refreshEnvironmentInfo, onListBranches: () =>
onListEnvironmentBranches(environmentProject), onCheckoutBranch:
handleCheckoutEnvironmentBranch, onCreateBranch: handleCreateEnvironmentBranch
}), [projectWork, openProjectFromWorkMenu, environmentInfo.branchName,
environmentInfo.loading, refreshEnvironmentInfo, onListEnvironmentBranches,
environmentProject, handleCheckoutEnvironmentBranch,
handleCreateEnvironmentBranch]) so the object and the onListBranches closure
only change when their inputs change.

In `@wework/src/components/layout/MobileWorkbenchLayout.tsx`:
- Around line 179-202: The inline callback wrappers assigned into
effectiveProjectWork (onListBranches, onCheckoutBranch, onCreateBranch) are
recreated each render; wrap each wrapper with React.useCallback so they are
stable and only change when their dependencies change (e.g.,
state.currentProject, onListEnvironmentBranches, onCheckoutEnvironmentBranch,
onCreateEnvironmentBranch, refreshEnvironmentInfo), then reference those
memoized callbacks in effectiveProjectWork instead of creating new arrow
functions inline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf120a30-93c4-461f-81d4-d6bffbaecff6

📥 Commits

Reviewing files that changed from the base of the PR and between 97136a7 and ee33c8d.

📒 Files selected for processing (15)
  • wework/src/components/chat/ChatInput.test.tsx
  • wework/src/components/chat/ChatInput.tsx
  • wework/src/components/chat/composer/ProjectChatComposer.tsx
  • wework/src/components/chat/composer/ProjectWorkBar.tsx
  • wework/src/components/common/BranchSelector.tsx
  • wework/src/components/common/SearchableSelect.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.test.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/projects/ProjectCreateDialog.test.tsx
  • wework/src/components/projects/ProjectCreateDialog.tsx
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json

@qdaxb
qdaxb merged commit 7ed6551 into wecode-ai:main Jun 8, 2026
27 of 28 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.

2 participants