✨ feat(vscode): 审查列可以申请同事移交工单

This commit is contained in:
cruldra committed 2026-09-28 00:17:09 +08:00
1 parent 65583a001c
commit 6342f39de0
22 files changed
+450 -31

No files matched your search

+46 -1
View File
@@ -20,6 +20,7 @@ import type { ToastItem } from '../components/ToastStack'
import type { ExtensionToWebview, LogEntry, ReleaseCommitGroup } from '../lib/messages'
import type { Issue, IssueColumn } from '../types'
import { useCallback, useEffect, useRef, useState } from 'react'
import { handoffRequestNotices } from '../../../src/panel/handlers/handoffRequest'
import { compareIssuesInColumn } from '../lib/issueSort'
import { onMessage, postMessage } from '../lib/vscode'
@@ -320,6 +321,11 @@ export interface UseIssuesResult {
startHandoff: (issueNumber: number, to: string) => void
/** 接管一个待接管工单:拉取移交附件、恢复会话与 worktree。 */
acceptHandoff: (issueNumber: number) => void
/** 审查列里向同事申请把工单移交给自己。 */
askHandoff: (issueNumber: number) => void
cancelHandoffRequest: (issueNumber: number) => void
acceptHandoffRequest: (issueNumber: number) => void
rejectHandoffRequest: (issueNumber: number) => void
/** 是否有移交/接管流程正在该工单上跑,直到扩展端回 `handoff/done` 才清除。 */
isHandoffRunning: (issueNumber: number) => boolean
}
@@ -632,6 +638,18 @@ export function useIssues(): UseIssuesResult {
postMessage({ type: 'handoff/start', issueNumber, to })
}, [markHandoffRunning])
const askHandoff = useCallback((issueNumber: number): void => {
postMessage({ type: 'handoff/request', issueNumber })
}, [])
const cancelHandoffRequest = useCallback((issueNumber: number): void => {
postMessage({ type: 'handoff/request-cancel', issueNumber })
}, [])
const acceptHandoffRequest = useCallback((issueNumber: number): void => {
postMessage({ type: 'handoff/request-accept', issueNumber })
}, [])
const rejectHandoffRequest = useCallback((issueNumber: number): void => {
postMessage({ type: 'handoff/request-reject', issueNumber })
}, [])
const acceptHandoff = useCallback((issueNumber: number): void => {
if (handoffRunningRef.current.has(issueNumber))
return
@@ -1042,5 +1060,32 @@ export function useIssues(): UseIssuesResult {
return cleanup
}, [clearPrDiffSummaryRunning, markHandoffRunning])
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, startReviewSession, startTestSession, resumeTestSession, startPrototypeSession, resumePrototypeSession, focusSession, openFile, openPrototypeInFigma, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, continueBrainstorm, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, clearSession, updateIssueTestProfilePath, updateIssuePrototypeProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, release, runRelease, cherryPick, dismissCherryPick, confirmCherryPick, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning }
const seenIssues = useRef<Issue[] | null>(null)
useEffect(() => {
if (state.status !== 'ready')
return
const prev = seenIssues.current
seenIssues.current = state.issues
if (!prev || !me)
return
const messages: string[] = []
for (const next of state.issues) {
const before = prev.find(issue => issue.number === next.number)
if (before)
messages.push(...handoffRequestNotices(before, next, me))
}
if (messages.length === 0)
return
setToasts(current => [
...current,
...messages.map(message => ({
id: `handoff-request-${message}`,
level: 'info' as const,
message,
dismissOnTimer: 8000,
})),
])
}, [state, me])
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, startReviewSession, startTestSession, resumeTestSession, startPrototypeSession, resumePrototypeSession, focusSession, openFile, openPrototypeInFigma, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, continueBrainstorm, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, clearSession, updateIssueTestProfilePath, updateIssuePrototypeProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, release, runRelease, cherryPick, dismissCherryPick, confirmCherryPick, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning, askHandoff, cancelHandoffRequest, acceptHandoffRequest, rejectHandoffRequest }
}