⚡ 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
@@ -29,6 +29,7 @@ interface BottomTabsProps {
|
||||
globalAutoReview: boolean
|
||||
onOpenInBrowser: (url: string) => void
|
||||
onResumeSession: (sessionId: string, kind: 'implement' | 'brainstorm', profilePath?: string, cwd?: string, issueNumber?: number) => void
|
||||
isSessionTabPending: (sessionId: string) => boolean
|
||||
onResumeReviewSession: (sessionId: string, issueNumber: number, cwd?: string) => void
|
||||
onStartTestSession: (issueNumber: number) => void
|
||||
onResumeTestSession: (sessionId: string, issueNumber: number, cwd?: string) => void
|
||||
@@ -127,6 +128,7 @@ export function BottomTabs(props: BottomTabsProps) {
|
||||
globalAutoReview={props.globalAutoReview}
|
||||
onOpenInBrowser={props.onOpenInBrowser}
|
||||
onResumeSession={props.onResumeSession}
|
||||
isSessionTabPending={props.isSessionTabPending}
|
||||
onResumeReviewSession={props.onResumeReviewSession}
|
||||
onStartTestSession={props.onStartTestSession}
|
||||
onResumeTestSession={props.onResumeTestSession}
|
||||
|
||||
@@ -39,6 +39,8 @@ interface IssueDetailPanelProps {
|
||||
globalAutoReview: boolean
|
||||
onOpenInBrowser: (url: string) => void
|
||||
onResumeSession: (sessionId: string, kind: 'implement' | 'brainstorm', profilePath?: string, cwd?: string, issueNumber?: number) => void
|
||||
/** 会话 id 行的 spinner:该会话的开 tab 请求还没被扩展处理完就为 true。 */
|
||||
isSessionTabPending: (sessionId: string) => boolean
|
||||
/**
|
||||
* Open a new terminal that runs `codex resume <id>` for the auto-review
|
||||
* conversation associated with this issue.
|
||||
@@ -153,6 +155,7 @@ export function IssueDetailPanel({
|
||||
onUpdateTestProfilePath,
|
||||
onOpenLogs,
|
||||
me,
|
||||
isSessionTabPending,
|
||||
onStartHandoff,
|
||||
onAcceptHandoff,
|
||||
isHandoffRunning,
|
||||
@@ -252,6 +255,7 @@ export function IssueDetailPanel({
|
||||
key: 'sessionId',
|
||||
label: '头脑风暴会话id',
|
||||
type: 'action' as const,
|
||||
pending: hasSession ? isSessionTabPending(issue!.sessionId!) : false,
|
||||
description: hasSession
|
||||
? '双击在新终端运行 claude --resume <id> 恢复对话;点 ▶ 续聊'
|
||||
: '工单尚未关联 cc 会话;点 ▶ 新开一个规划会话并续聊',
|
||||
@@ -274,6 +278,7 @@ export function IssueDetailPanel({
|
||||
key: 'implementSessionId',
|
||||
label: '实施会话id',
|
||||
type: 'action',
|
||||
pending: issue?.implementSessionId ? isSessionTabPending(issue.implementSessionId) : false,
|
||||
description: issue?.worktreeExists
|
||||
? '双击在新终端运行 claude --resume <id> 恢复实施对话(cwd 为 worktree)'
|
||||
: 'worktree 已清理,将在工作区根目录恢复(cc 可能提示原 cwd 不存在)',
|
||||
@@ -298,6 +303,7 @@ export function IssueDetailPanel({
|
||||
key: 'reviewSessionId',
|
||||
label: '审查会话id',
|
||||
type: 'action',
|
||||
pending: issue.reviewSessionId ? isSessionTabPending(issue.reviewSessionId) : false,
|
||||
description: '双击在新终端运行 codex resume <id> 查看审查会话(worktree 在则用之,否则工作区根目录)',
|
||||
actionIcon: <Terminal className="size-3.5" />,
|
||||
onAction: (v) => {
|
||||
@@ -355,6 +361,7 @@ export function IssueDetailPanel({
|
||||
key: 'testSessionId',
|
||||
label: '测试会话id',
|
||||
type: 'action' as const,
|
||||
pending: hasSession ? isSessionTabPending(issue!.testSessionId!) : false,
|
||||
description: hasSession
|
||||
? '双击在新终端运行 claude --resume <id> 在工作区根(main)恢复测试对话'
|
||||
: '工单 PR 合并后点击右侧 ▶ 在工作区根(main)启动一个测试 cc tab(让 cc 了解代码后告诉你怎么测试)',
|
||||
@@ -535,7 +542,7 @@ export function IssueDetailPanel({
|
||||
],
|
||||
},
|
||||
],
|
||||
[onResumeSession, onResumeReviewSession, onResumeTestSession, onStartTestSession, onOpenFile, onImplement, onOpenPr, onGeneratePrDiffSummary, onOpenWorktree, onDeleteWorktree, onMergeBranch, onCloseSessionTab, onContinueBrainstorm, onClearBrainstormSession, onOpenLogs, issue, locked, lockTitle, globalAutoReview, prDiffSummaryRunning, profiles],
|
||||
[onResumeSession, onResumeReviewSession, onResumeTestSession, onStartTestSession, onOpenFile, onImplement, onOpenPr, onGeneratePrDiffSummary, onOpenWorktree, onDeleteWorktree, onMergeBranch, onCloseSessionTab, onContinueBrainstorm, onClearBrainstormSession, onOpenLogs, issue, locked, lockTitle, globalAutoReview, prDiffSummaryRunning, profiles, isSessionTabPending],
|
||||
)
|
||||
|
||||
// 同事的工单只读:属性表统一消毒,顶部只留查看类按钮。
|
||||
|
||||
@@ -60,6 +60,11 @@ export interface PropertyDef {
|
||||
onAction?: (value: unknown) => void
|
||||
/** type='action' 专用:值前的图标 */
|
||||
actionIcon?: ReactNode
|
||||
/**
|
||||
* 主动作是否还在进行中。给了就由外部决定 spinner 何时收(真实进度),
|
||||
* 不给则沿用点击后固定 1.5s 的即时反馈。
|
||||
*/
|
||||
pending?: boolean
|
||||
/** type='file-link' 专用:双击文件名时调用,参数为 value(workspace 相对路径) */
|
||||
onOpen?: (path: string) => void
|
||||
/** type='file-link' 专用:点击右侧图标按钮时调用,用于重新扫描/加载 */
|
||||
@@ -174,7 +179,8 @@ function PropertyRow({
|
||||
registerCellRef: (fullKey: string, el: HTMLDivElement | null) => void
|
||||
}) {
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const [actionPending, setActionPending] = useState(false)
|
||||
const [localActionPending, setLocalActionPending] = useState(false)
|
||||
const actionPending = propDef.pending ?? localActionPending
|
||||
const pendingTimerRef = useRef<number | null>(null)
|
||||
const ro = propDef.readOnly
|
||||
|
||||
@@ -183,14 +189,16 @@ function PropertyRow({
|
||||
window.clearTimeout(pendingTimerRef.current)
|
||||
}, [])
|
||||
|
||||
/** 触发主动作并给出即时反馈:行内图标临时切换为 spinner,约 1.5s 后恢复 */
|
||||
/** 触发主动作:外部受控时 spinner 交给 propDef.pending,否则本地转约 1.5s */
|
||||
function firePrimaryAction(fire: () => void): void {
|
||||
fire()
|
||||
setActionPending(true)
|
||||
if (propDef.pending !== undefined)
|
||||
return
|
||||
setLocalActionPending(true)
|
||||
if (pendingTimerRef.current != null)
|
||||
window.clearTimeout(pendingTimerRef.current)
|
||||
pendingTimerRef.current = window.setTimeout(() => {
|
||||
setActionPending(false)
|
||||
setLocalActionPending(false)
|
||||
pendingTimerRef.current = null
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user