diff --git a/wework/src/components/layout/EnvironmentInfoPopover.tsx b/wework/src/components/layout/EnvironmentInfoPopover.tsx
index d756df44f94..f25f990a7a1 100644
--- a/wework/src/components/layout/EnvironmentInfoPopover.tsx
+++ b/wework/src/components/layout/EnvironmentInfoPopover.tsx
@@ -1,17 +1,13 @@
import {
- Check,
- ChevronDown,
CircleDot,
- GitBranch,
GitCommit,
GitPullRequest,
Info,
Laptop,
- Plus,
- Search,
Settings,
} from 'lucide-react'
-import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent, type ReactNode } from 'react'
+import { useEffect, useRef, useState, type FormEvent, type ReactNode } from 'react'
+import { BranchSelector } from '@/components/common/BranchSelector'
import { useTranslation } from '@/hooks/useTranslation'
import { cn } from '@/lib/utils'
import type { EnvironmentInfo } from '@/types/environment'
@@ -59,22 +55,6 @@ function formatDeviceId(deviceId?: string) {
return `${deviceId.slice(0, 8)}...${deviceId.slice(-4)}`
}
-function branchMatchesQuery(branch: string, query: string): boolean {
- const normalizedBranch = branch.toLowerCase()
- const normalizedQuery = query.trim().toLowerCase()
- if (!normalizedQuery) return true
- if (normalizedBranch.includes(normalizedQuery)) return true
-
- let queryIndex = 0
- for (const character of normalizedBranch) {
- if (character === normalizedQuery[queryIndex]) {
- queryIndex += 1
- if (queryIndex === normalizedQuery.length) return true
- }
- }
- return false
-}
-
export function EnvironmentInfoPopover({
info,
onRefresh,
@@ -86,14 +66,6 @@ export function EnvironmentInfoPopover({
const { t } = useTranslation('common')
const [open, setOpen] = useState(false)
const [deviceCopied, setDeviceCopied] = useState(false)
- const [branchMenuOpen, setBranchMenuOpen] = useState(false)
- const [branches, setBranches] = useState
([])
- const [branchQuery, setBranchQuery] = useState('')
- const [branchesLoading, setBranchesLoading] = useState(false)
- const [branchActionStatus, setBranchActionStatus] = useState<'idle' | 'switching' | 'creating'>('idle')
- const [branchError, setBranchError] = useState(null)
- const [newBranchFormOpen, setNewBranchFormOpen] = useState(false)
- const [newBranchName, setNewBranchName] = useState('')
const [commitFormOpen, setCommitFormOpen] = useState(false)
const [commitMessage, setCommitMessage] = useState('')
const [commitStatus, setCommitStatus] = useState<'idle' | 'committing' | 'success'>('idle')
@@ -101,41 +73,12 @@ export function EnvironmentInfoPopover({
const rootRef = useRef(null)
const additions = info.additions || '+0'
const deletions = info.deletions || '-0'
- const branchName = info.branchName || t('workbench.environment_branch_empty', '暂无分支')
const executionLabel =
info.executionTarget === 'cloud'
? t('workbench.environment_cloud', '云端')
: t('workbench.environment_local', '本地')
const shortDeviceId = formatDeviceId(info.deviceId)
const deviceTitle = info.deviceId ? `${executionLabel} · ${info.deviceId}` : executionLabel
- const filteredBranches = useMemo(
- () => branches.filter(branch => branchMatchesQuery(branch, branchQuery)),
- [branchQuery, branches],
- )
-
- const closeBranchMenu = useCallback(() => {
- setBranchMenuOpen(false)
- setBranchQuery('')
- setBranchError(null)
- setNewBranchFormOpen(false)
- setNewBranchName('')
- }, [])
-
- useEffect(() => {
- if (!branchMenuOpen) {
- return
- }
-
- function handleBranchMenuKeyDown(event: KeyboardEvent) {
- if (event.key === 'Escape') {
- closeBranchMenu()
- }
- }
-
- window.addEventListener('keydown', handleBranchMenuKeyDown)
- return () => window.removeEventListener('keydown', handleBranchMenuKeyDown)
- }, [branchMenuOpen, closeBranchMenu])
-
function handleCreatePullRequest() {
if (!info.createPullRequestUrl) {
return
@@ -174,79 +117,12 @@ export function EnvironmentInfoPopover({
}
}
- async function handleToggleBranchMenu() {
- const nextOpen = !branchMenuOpen
- if (!nextOpen) {
- closeBranchMenu()
- return
- }
- setBranchMenuOpen(true)
- setBranchError(null)
-
- if (!onListBranches) {
- return
- }
-
- setBranchesLoading(true)
- try {
- const nextBranches = await onListBranches()
- setBranches(nextBranches)
- } catch (error) {
- setBranches([])
- setBranchError(error instanceof Error ? error.message : t('workbench.environment_branch_load_failed', '分支加载失败'))
- } finally {
- setBranchesLoading(false)
- }
- }
-
- async function handleCheckoutBranch(nextBranchName: string) {
- if (!onCheckoutBranch || nextBranchName === info.branchName) {
- closeBranchMenu()
- return
- }
-
- setBranchError(null)
- setBranchActionStatus('switching')
- try {
- await onCheckoutBranch(nextBranchName)
- closeBranchMenu()
- } catch (error) {
- setBranchError(error instanceof Error ? error.message : t('workbench.environment_branch_checkout_failed', '切换分支失败'))
- } finally {
- setBranchActionStatus('idle')
- }
- }
-
- async function handleCreateBranch(event: FormEvent) {
- event.preventDefault()
- const trimmedName = newBranchName.trim()
- if (!trimmedName || !onCreateBranch) {
- return
- }
-
- setBranchError(null)
- setBranchActionStatus('creating')
- try {
- await onCreateBranch(trimmedName)
- setNewBranchName('')
- setNewBranchFormOpen(false)
- setBranchMenuOpen(false)
- setBranchQuery('')
- } catch (error) {
- setBranchError(error instanceof Error ? error.message : t('workbench.environment_branch_create_failed', '创建分支失败'))
- } finally {
- setBranchActionStatus('idle')
- }
- }
-
function handleToggleOpen() {
const nextOpen = !open
setOpen(nextOpen)
if (nextOpen) {
void onRefresh?.()
- } else {
- closeBranchMenu()
}
}
@@ -258,13 +134,12 @@ export function EnvironmentInfoPopover({
function handlePointerDown(event: PointerEvent) {
if (!rootRef.current?.contains(event.target as Node)) {
setOpen(false)
- closeBranchMenu()
}
}
document.addEventListener('pointerdown', handlePointerDown)
return () => document.removeEventListener('pointerdown', handlePointerDown)
- }, [closeBranchMenu, open])
+ }, [open])
return (
@@ -338,114 +213,16 @@ export function EnvironmentInfoPopover({
)}
-
- {branchMenuOpen && (
-
-
-
- {t('workbench.environment_branches', '分支')}
-
-
- {branchesLoading && (
-
- {t('common.loading', '加载中...')}
-
- )}
- {!branchesLoading && branchError && (
-
{branchError}
- )}
- {!branchesLoading && !branchError && filteredBranches.map(branch => {
- const current = branch === info.branchName
- return (
-
- )
- })}
- {!branchesLoading && !branchError && filteredBranches.length === 0 && (
-
- {t('workbench.environment_branch_empty_results', '没有匹配的分支')}
-
- )}
-
-
- {newBranchFormOpen ? (
-
- ) : (
-
- )}
-
-
+ {onListBranches && onCheckoutBranch && (
+
)}