✨ feat(vscode): 看板底栏新增工单讨论 Tab 并支持系统气泡与 Gitea 评论同步

This commit is contained in:
cruldra committed 2026-09-29 04:23:57 +08:00
1 parent 8ecb40b330
commit df17821408
14 files changed
+1555 -2

No files matched your search

+9
View File
@@ -29,6 +29,7 @@ import { webhookCoordinator } from '../webhook/coordinator'
import { makeNonce, webviewHtml, webviewUiRoot } from '../webview/html'
import { loadYouTrackIssues } from '../youtrack/issueLoader'
import * as handoffFlow from './handlers/handoffFlow'
import * as issueChat from './handlers/issueChat'
import * as issues from './handlers/issues'
import * as managedSessions from './handlers/managedSessions'
import * as prFiles from './handlers/prFiles'
@@ -728,6 +729,14 @@ export class KanbanWebviewPanel {
}
if (msg.type === 'pr-diff-mode/set') {
void prFiles.handleSetPrDiffMode(this, msg.mode)
return
}
if (msg.type === 'issue/comments-query') {
void issueChat.handleIssueComments(this, msg.issueNumber)
return
}
if (msg.type === 'issue/comment-post') {
void issueChat.handleIssueCommentPost(this, msg.issueNumber, msg.body)
}
}
+83
View File
@@ -0,0 +1,83 @@
import type { GiteaComment } from '../../gitea/api'
import type { KanbanWebviewPanel } from '../KanbanPanel'
import { listIssueComments, postIssueComment } from '../../gitea/api'
import { systemCommentText } from '../../gitea/issueComment'
import { logger } from '../../logging/logger'
import { resolveRepoCtx, toast } from './handoffFlow'
export interface IssueChatComment {
id: number
author: string
authorName?: string
avatarUrl?: string
createdAt: string
body: string
systemText?: string
}
function toChat(comment: GiteaComment): IssueChatComment {
const systemText = systemCommentText(comment.body)
return {
id: comment.id,
author: comment.user?.login ?? '未知',
authorName: comment.user?.full_name || undefined,
avatarUrl: comment.user?.avatar_url || undefined,
createdAt: comment.created_at,
body: comment.body,
...(systemText ? { systemText } : {}),
}
}
async function pushComments(panel: KanbanWebviewPanel, issueNumber: number): Promise<void> {
const ctx = await resolveRepoCtx(panel)
if (!ctx)
return
const comments = await listIssueComments({
host: ctx.host,
token: ctx.token,
owner: ctx.owner,
repo: ctx.repo,
index: issueNumber,
})
panel.postMessage({
type: 'issue/comments-result',
issueNumber,
comments: comments.map(toChat),
})
}
export async function handleIssueComments(panel: KanbanWebviewPanel, issueNumber: number): Promise<void> {
try {
await pushComments(panel, issueNumber)
}
catch (err) {
const message = err instanceof Error ? err.message : String(err)
logger.add({ level: 'error', source: 'panel', message: `读取工单 #${issueNumber} 评论失败`, details: message })
panel.postMessage({ type: 'issue/comments-result', issueNumber, comments: [], error: message })
}
}
export async function handleIssueCommentPost(panel: KanbanWebviewPanel, issueNumber: number, body: string): Promise<void> {
const text = body.trim()
if (!text)
return
const ctx = await resolveRepoCtx(panel)
if (!ctx)
return
try {
await postIssueComment({
host: ctx.host,
token: ctx.token,
owner: ctx.owner,
repo: ctx.repo,
index: issueNumber,
body: text,
})
await pushComments(panel, issueNumber)
}
catch (err) {
const message = err instanceof Error ? err.message : String(err)
logger.add({ level: 'error', source: 'panel', message: `发表工单 #${issueNumber} 评论失败`, details: message })
toast(panel, 'error', `评论没发出去:${message}`)
}
}
+5
View File
@@ -3,9 +3,11 @@ import type { Issue, IssueColumn } from '../gitea/types'
import type { LogEntry } from '../logging/logger'
import type { ProfilesData } from '../profiles/store'
import type { ManagedSession } from '../sessions/managedStore'
import type { IssueChatComment } from './handlers/issueChat'
export type { LogEntry } from '../logging/logger'
export type { ProfileRow, ProfilesData } from '../profiles/store'
export type { IssueChatComment } from './handlers/issueChat'
/**
* `managed-sessions/show` 的 payload 类型:在持久化的 ManagedSession 基础上
@@ -145,6 +147,7 @@ export type ExtensionToWebview
// profile 值编辑器粘贴的图片:存盘/读盘的回执,requestId 关联并发请求。
| { type: 'profile-asset/saved', requestId: string, assetPath?: string, error?: string }
| { type: 'profile-asset/loaded', requestId: string, dataUrl?: string, error?: string }
| { type: 'issue/comments-result', issueNumber: number, comments: IssueChatComment[], error?: string }
export type WebviewToExtension
= | { type: 'issues/refresh' }
@@ -264,3 +267,5 @@ export type WebviewToExtension
// profile 值编辑器:图片存盘(base64→磁盘)与读盘(磁盘→dataUrl)请求。
| { type: 'profile-asset/save', requestId: string, base64: string, mediaType: string }
| { type: 'profile-asset/load', requestId: string, assetPath: string }
| { type: 'issue/comments-query', issueNumber: number }
| { type: 'issue/comment-post', issueNumber: number, body: string }