(
)
: null}
-
{issue.source === 'youtrack' ? issue.externalId : `#${issue.number}`}
diff --git a/vscode/webview-ui/src/components/IssueDetailPanel.tsx b/vscode/webview-ui/src/components/IssueDetailPanel.tsx
index 947f016..5dc2a5b 100644
--- a/vscode/webview-ui/src/components/IssueDetailPanel.tsx
+++ b/vscode/webview-ui/src/components/IssueDetailPanel.tsx
@@ -3,6 +3,7 @@ import type { Issue, IssueColumn } from '../types'
import type { PropertyGroup, RowAction } from './property-grid'
import { ArrowRightLeft, CircleSlash, Download, Eraser, ExternalLink, GitMerge, Loader2, Play, RotateCcw, Terminal, Trash2, X } from 'lucide-react'
import { useMemo, useRef } from 'react'
+import { canAnswerHandoffRequest, canAskHandoff, canCancelHandoffRequest } from '../../../src/panel/handlers/handoffRequest'
import { isIssueLocked } from '../lib/dependencies'
import { isIssueMine, issueOwnerLogin } from '../lib/issueOwnership'
import { isSessionMissing } from '../lib/missingSession'
@@ -134,6 +135,10 @@ interface IssueDetailPanelProps {
me?: string
onStartHandoff: (issueNumber: number) => void
onAcceptHandoff: (issueNumber: number) => void
+ onAskHandoff: (issueNumber: number) => void
+ onCancelHandoffRequest: (issueNumber: number) => void
+ onAcceptHandoffRequest: (issueNumber: number) => void
+ onRejectHandoffRequest: (issueNumber: number) => void
isHandoffRunning: (issueNumber: number) => boolean
/** Gitea login → 头像 data URI;只读工单在标题旁贴归属人头像。 */
avatars?: Record
@@ -185,6 +190,10 @@ export function IssueDetailPanel({
isSessionTabPending,
onStartHandoff,
onAcceptHandoff,
+ onAskHandoff,
+ onCancelHandoffRequest,
+ onAcceptHandoffRequest,
+ onRejectHandoffRequest,
isHandoffRunning,
avatars,
}: IssueDetailPanelProps) {
@@ -847,6 +856,68 @@ export function IssueDetailPanel({
{issue.source === 'youtrack' ? '在 YouTrack 打开' : '在 Gitea 打开'}
+ {canAskHandoff(issue, me) && (
+
+ )}
+ {canCancelHandoffRequest(issue, me) && (
+ <>
+
+ {issue.handoffRequestError && issue.handoffRequestError !== 'rejected' ? issue.handoffRequestError : '已申请'}
+
+
+ >
+ )}
+ {canAnswerHandoffRequest(issue, me) && (
+ <>
+
+ {issue.handoffRequestFrom}
+ {' '}
+ 想要这个工单
+
+ {issue.handoffRequestError && issue.handoffRequestError !== 'rejected'
+ ? (
+
+ {issue.handoffRequestError}
+
+ )
+ : null}
+
+
+ >
+ )}
{/* Close/delete write to gitea by number — hide for youtrack cards to
avoid acting on a gitea issue of the same number. */}
{issue.source !== 'youtrack' && !readOnly && (
diff --git a/vscode/webview-ui/src/components/KanbanBoard.tsx b/vscode/webview-ui/src/components/KanbanBoard.tsx
index a50c356..d0ef0f5 100644
--- a/vscode/webview-ui/src/components/KanbanBoard.tsx
+++ b/vscode/webview-ui/src/components/KanbanBoard.tsx
@@ -45,10 +45,6 @@ interface KanbanBoardProps {
me?: string
/** Gitea login → 头像 data URI。 */
avatars?: Record
- onAskHandoff?: (issueNumber: number) => void
- onCancelHandoffRequest?: (issueNumber: number) => void
- onAcceptHandoffRequest?: (issueNumber: number) => void
- onRejectHandoffRequest?: (issueNumber: number) => void
}
const kanbanCollisionDetection: CollisionDetection = (args) => {
@@ -123,10 +119,6 @@ export function KanbanBoard({
onDependencyClear,
me,
avatars,
- onAskHandoff,
- onCancelHandoffRequest,
- onAcceptHandoffRequest,
- onRejectHandoffRequest,
}: KanbanBoardProps) {
const [activeId, setActiveId] = useState(null)
@@ -289,11 +281,6 @@ export function KanbanBoard({
readOnly={readOnly}
ownerLogin={ownerLogin}
ownerAvatar={ownerLogin ? avatars?.[ownerLogin] : undefined}
- me={me}
- onAskHandoff={onAskHandoff}
- onCancelHandoffRequest={onCancelHandoffRequest}
- onAcceptHandoffRequest={onAcceptHandoffRequest}
- onRejectHandoffRequest={onRejectHandoffRequest}
/>
)
})}