✨ feat(vscode): 看板底栏新增工单讨论 Tab 并支持系统气泡与 Gitea 评论同步
This commit is contained in:
1 parent
8ecb40b330
commit
df17821408
14 files changed
+1555
-2
No files matched your search
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`)
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
Reference in new issue
Block a user