⚡ perf(vscode): 开会话去掉多余远程往返,spinner 跟随真实进度
开会话原先要先全量拉工单(含每张工单的评论、依赖、PR)做前置锁检查, 再各读一次 state JSON 给 pre-create 钩子和终端图标,几秒后才 createTerminal。 - 锁检查改用主进程已算好的工单快照,快照里没有该工单才回落全量拉取 - state JSON 一次读两处用,且提前发起与本地准备重叠 - 会话行 spinner 由扩展的 session/tab-settled 消息驱动,不再是固定 1.5s 假动画, 消息丢失时 60s 超时兜底 Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
1 parent
b182e0ac5b
commit
70b826123c
12 files changed
+218
-71
No files matched your search
@@ -184,6 +184,8 @@ export interface UseIssuesResult {
|
||||
dismissToast: (id: string) => void
|
||||
openUrl: (url: string) => void
|
||||
resumeSession: (sessionId: string, kind: 'implement' | 'brainstorm', profilePath?: string, cwd?: string, issueNumber?: number) => void
|
||||
/** 该会话 id 的开 tab 请求还没被扩展处理完 → 行内转 spinner。 */
|
||||
isSessionTabPending: (sessionId: string) => boolean
|
||||
resumeReviewSession: (sessionId: string, issueNumber: number, cwd?: string) => void
|
||||
startTestSession: (issueNumber: number) => void
|
||||
resumeTestSession: (sessionId: string, issueNumber: number, cwd?: string) => void
|
||||
@@ -479,6 +481,50 @@ export function useIssues(): UseIssuesResult {
|
||||
postMessage({ type: 'toast/open-url', url })
|
||||
}, [])
|
||||
|
||||
// 开 tab 是秒级操作(要读 state JSON、跑 pre-create 钩子),行内 spinner 要
|
||||
// 真实反映进度:发请求时标 pending,扩展回 session/tab-settled 时清。消息万一
|
||||
// 丢了就靠 PENDING_TIMEOUT_MS 兜底,spinner 不会永远转下去。
|
||||
const [pendingSessionTabs, setPendingSessionTabs] = useState<Set<string>>(() => new Set())
|
||||
const pendingTimersRef = useRef<Map<string, number>>(new Map())
|
||||
const PENDING_TIMEOUT_MS = 60_000
|
||||
|
||||
const clearSessionTabPending = useCallback((sessionId: string): void => {
|
||||
const timer = pendingTimersRef.current.get(sessionId)
|
||||
if (timer !== undefined) {
|
||||
window.clearTimeout(timer)
|
||||
pendingTimersRef.current.delete(sessionId)
|
||||
}
|
||||
setPendingSessionTabs((prev) => {
|
||||
if (!prev.has(sessionId))
|
||||
return prev
|
||||
const next = new Set(prev)
|
||||
next.delete(sessionId)
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
const markSessionTabPending = useCallback((sessionId: string): void => {
|
||||
const existing = pendingTimersRef.current.get(sessionId)
|
||||
if (existing !== undefined)
|
||||
window.clearTimeout(existing)
|
||||
pendingTimersRef.current.set(
|
||||
sessionId,
|
||||
window.setTimeout(() => clearSessionTabPending(sessionId), PENDING_TIMEOUT_MS),
|
||||
)
|
||||
setPendingSessionTabs(prev => new Set(prev).add(sessionId))
|
||||
}, [clearSessionTabPending])
|
||||
|
||||
const isSessionTabPending = useCallback(
|
||||
(sessionId: string): boolean => pendingSessionTabs.has(sessionId),
|
||||
[pendingSessionTabs],
|
||||
)
|
||||
|
||||
useEffect(() => () => {
|
||||
for (const timer of pendingTimersRef.current.values())
|
||||
window.clearTimeout(timer)
|
||||
pendingTimersRef.current.clear()
|
||||
}, [])
|
||||
|
||||
const resumeSession = useCallback((
|
||||
sessionId: string,
|
||||
kind: 'implement' | 'brainstorm',
|
||||
@@ -486,24 +532,27 @@ export function useIssues(): UseIssuesResult {
|
||||
cwd?: string,
|
||||
issueNumber?: number,
|
||||
): void => {
|
||||
markSessionTabPending(sessionId)
|
||||
postMessage({ type: 'session/resume', sessionId, kind, profilePath, cwd, issueNumber })
|
||||
}, [])
|
||||
}, [markSessionTabPending])
|
||||
|
||||
const focusSession = useCallback((issueNumber: number): void => {
|
||||
postMessage({ type: 'session/focus', issueNumber })
|
||||
}, [])
|
||||
|
||||
const resumeReviewSession = useCallback((sessionId: string, issueNumber: number, cwd?: string): void => {
|
||||
markSessionTabPending(sessionId)
|
||||
postMessage({ type: 'session/resume-review', sessionId, issueNumber, cwd })
|
||||
}, [])
|
||||
}, [markSessionTabPending])
|
||||
|
||||
const startTestSession = useCallback((issueNumber: number): void => {
|
||||
postMessage({ type: 'session/start-test', issueNumber })
|
||||
}, [])
|
||||
|
||||
const resumeTestSession = useCallback((sessionId: string, issueNumber: number, cwd?: string): void => {
|
||||
markSessionTabPending(sessionId)
|
||||
postMessage({ type: 'session/resume-test', sessionId, issueNumber, cwd })
|
||||
}, [])
|
||||
}, [markSessionTabPending])
|
||||
|
||||
const openFile = useCallback((path: string): void => {
|
||||
postMessage({ type: 'editor/open-file', path })
|
||||
@@ -722,6 +771,9 @@ export function useIssues(): UseIssuesResult {
|
||||
useEffect(() => {
|
||||
const cleanup = onMessage((msg) => {
|
||||
switch (msg.type) {
|
||||
case 'session/tab-settled':
|
||||
clearSessionTabPending(msg.sessionId)
|
||||
break
|
||||
case 'issues/loading':
|
||||
setRefreshing(true)
|
||||
setState(prev => prev.status === 'ready' ? prev : { status: 'loading' })
|
||||
@@ -938,5 +990,5 @@ export function useIssues(): UseIssuesResult {
|
||||
return cleanup
|
||||
}, [clearPrDiffSummaryRunning, markHandoffRunning])
|
||||
|
||||
return { state, settings, avatars, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, refreshing, scope, toggleScope, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, continueBrainstorm, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, clearBrainstormSession, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, release, runRelease, cherryPick, dismissCherryPick, confirmCherryPick, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning }
|
||||
return { state, settings, avatars, isSessionTabPending, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, refreshing, scope, toggleScope, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, continueBrainstorm, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, clearBrainstormSession, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, release, runRelease, cherryPick, dismissCherryPick, confirmCherryPick, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning }
|
||||
}
|
||||
Reference in new issue
Block a user