🐛 fix(vscode): 修复看板缓存并增加问答默认模型
This commit is contained in:
1 parent
c38f1dc468
commit
012daf95b5
25 files changed
+1753
-164
No files matched your search
@@ -605,6 +605,7 @@ export function App() {
|
||||
initialDefaultImplementProfilePath={settings?.defaultImplementProfilePath ?? ''}
|
||||
initialDefaultTestProfilePath={settings?.defaultTestProfilePath ?? ''}
|
||||
initialDefaultPrototypeProfilePath={settings?.defaultPrototypeProfilePath ?? ''}
|
||||
initialDefaultAskProfilePath={settings?.defaultAskProfilePath ?? ''}
|
||||
initialConflictResolutionProfilePath={settings?.conflictResolutionProfilePath ?? ''}
|
||||
initialCommitProfilePath={settings?.commitProfilePath ?? ''}
|
||||
initialPrDiffSummaryProfilePath={settings?.prDiffSummaryProfilePath ?? ''}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import type { SettingsModalProps } from './SettingsModal'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { SettingsModal } from './SettingsModal'
|
||||
|
||||
const PROPS: SettingsModalProps = {
|
||||
open: true,
|
||||
host: 'gitea.example.com',
|
||||
initialTokenSaved: true,
|
||||
initialWebhookPort: 8080,
|
||||
initialWebhookSecret: '',
|
||||
initialBrainstormPrompt: '',
|
||||
initialImplementPlanPrompt: '',
|
||||
initialAutoReview: false,
|
||||
initialReviewPrompt: '',
|
||||
initialTestPrompt: '',
|
||||
initialPrototypePrompt: '',
|
||||
initialDevBranch: 'main',
|
||||
initialReleaseBranchPrefix: 'release/',
|
||||
initialJenkinsJob: '',
|
||||
initialJenkinsProdHost: '',
|
||||
initialWorktreeDirectory: '',
|
||||
initialWorktreeOpenWith: 'vscode',
|
||||
initialPycharmCommand: '',
|
||||
initialWorktreePostCreateScript: '',
|
||||
initialWorktreePreRemoveScript: '',
|
||||
initialImplTabPreCreateScript: '',
|
||||
initialImplTabPostCloseScript: '',
|
||||
initialSplitNewTerminals: false,
|
||||
initialDefaultBrainstormProfilePath: '',
|
||||
initialDefaultImplementProfilePath: '',
|
||||
initialDefaultTestProfilePath: '',
|
||||
initialDefaultPrototypeProfilePath: '',
|
||||
initialDefaultAskProfilePath: '/p/sonnet.json',
|
||||
initialConflictResolutionProfilePath: '',
|
||||
initialCommitProfilePath: '',
|
||||
initialPrDiffSummaryProfilePath: '',
|
||||
initialCodexModel: '',
|
||||
initialCodexReasoningEffort: '',
|
||||
initialProfilesDirectory: '',
|
||||
initialYoutrackBaseUrl: '',
|
||||
initialYoutrackProjectShortName: '',
|
||||
initialYoutrackCloseCommand: '',
|
||||
initialYoutrackTokenSaved: false,
|
||||
profiles: [{ name: 'sonnet', path: '/p/sonnet.json' }],
|
||||
youtrackProjects: { status: 'idle', projects: [] },
|
||||
onListYouTrackProjects: () => {},
|
||||
onSubmit: () => {},
|
||||
}
|
||||
|
||||
function field(props: Partial<SettingsModalProps> = {}): string {
|
||||
const html = renderToStaticMarkup(<SettingsModal {...PROPS} {...props} />)
|
||||
expect(html).toContain('文件问答默认模型')
|
||||
return html.slice(html.indexOf('文件问答默认模型'), html.indexOf('冲突解决配置文件'))
|
||||
}
|
||||
|
||||
describe('设置面板的文件问答默认模型', () => {
|
||||
it('与其他默认配置在同一区域,显示保存的名称并说明临时切换不会改默认', () => {
|
||||
const html = field()
|
||||
expect(html).toContain('sonnet')
|
||||
expect(html).toContain('问这个文件')
|
||||
expect(html).toContain('临时切换')
|
||||
expect(html).toContain('不会修改这里的默认值')
|
||||
expect(html).toContain('aria-haspopup="listbox"')
|
||||
})
|
||||
|
||||
it('未配置时显示官方默认,失效路径不能伪装成默认', () => {
|
||||
expect(field({ initialDefaultAskProfilePath: '' })).toContain('(默认)')
|
||||
expect(field({ initialDefaultAskProfilePath: '/p/deleted.json' })).toContain('不可用:/p/deleted.json')
|
||||
})
|
||||
})
|
||||
@@ -42,6 +42,7 @@ interface SubmitValues {
|
||||
defaultImplementProfilePath: string
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -97,6 +98,7 @@ export interface SettingsModalProps {
|
||||
initialDefaultImplementProfilePath: string
|
||||
initialDefaultTestProfilePath: string
|
||||
initialDefaultPrototypeProfilePath: string
|
||||
initialDefaultAskProfilePath: string
|
||||
initialConflictResolutionProfilePath: string
|
||||
initialCommitProfilePath: string
|
||||
initialPrDiffSummaryProfilePath: string
|
||||
@@ -189,6 +191,7 @@ export function SettingsModal({
|
||||
initialDefaultImplementProfilePath,
|
||||
initialDefaultTestProfilePath,
|
||||
initialDefaultPrototypeProfilePath,
|
||||
initialDefaultAskProfilePath,
|
||||
initialConflictResolutionProfilePath,
|
||||
initialCommitProfilePath,
|
||||
initialPrDiffSummaryProfilePath,
|
||||
@@ -232,6 +235,7 @@ export function SettingsModal({
|
||||
const [defaultImplementProfilePath, setDefaultImplementProfilePath] = useState(initialDefaultImplementProfilePath)
|
||||
const [defaultTestProfilePath, setDefaultTestProfilePath] = useState(initialDefaultTestProfilePath)
|
||||
const [defaultPrototypeProfilePath, setDefaultPrototypeProfilePath] = useState(initialDefaultPrototypeProfilePath)
|
||||
const [defaultAskProfilePath, setDefaultAskProfilePath] = useState(initialDefaultAskProfilePath)
|
||||
const [conflictResolutionProfilePath, setConflictResolutionProfilePath] = useState(initialConflictResolutionProfilePath)
|
||||
const [commitProfilePath, setCommitProfilePath] = useState(initialCommitProfilePath)
|
||||
const [prDiffSummaryProfilePath, setPrDiffSummaryProfilePath] = useState(initialPrDiffSummaryProfilePath)
|
||||
@@ -277,6 +281,7 @@ export function SettingsModal({
|
||||
setDefaultImplementProfilePath(initialDefaultImplementProfilePath)
|
||||
setDefaultTestProfilePath(initialDefaultTestProfilePath)
|
||||
setDefaultPrototypeProfilePath(initialDefaultPrototypeProfilePath)
|
||||
setDefaultAskProfilePath(initialDefaultAskProfilePath)
|
||||
setConflictResolutionProfilePath(initialConflictResolutionProfilePath)
|
||||
setCommitProfilePath(initialCommitProfilePath)
|
||||
setPrDiffSummaryProfilePath(initialPrDiffSummaryProfilePath)
|
||||
@@ -374,6 +379,7 @@ export function SettingsModal({
|
||||
defaultImplementProfilePath: defaultImplementProfilePath.trim(),
|
||||
defaultTestProfilePath: defaultTestProfilePath.trim(),
|
||||
defaultPrototypeProfilePath: defaultPrototypeProfilePath.trim(),
|
||||
defaultAskProfilePath: defaultAskProfilePath.trim(),
|
||||
// 冲突解决 profile:空串 = 用 DEFAULT_PROFILE_PATH
|
||||
conflictResolutionProfilePath: conflictResolutionProfilePath.trim(),
|
||||
// 提交代码 profile:空串 = 未配置 → 提交严格失败
|
||||
@@ -656,6 +662,26 @@ export function SettingsModal({
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="文件问答默认模型"
|
||||
hint="代码阅读底部「问这个文件」默认使用此模型,也用于代码块和文件夹问答;留空沿用官方默认。输入框旁可临时切换,不会修改这里的默认值;重启或修改此设置后恢复默认。"
|
||||
>
|
||||
<SelectMenu
|
||||
value={defaultAskProfilePath}
|
||||
onChange={setDefaultAskProfilePath}
|
||||
variant="input"
|
||||
className={inputClass}
|
||||
options={[
|
||||
{ value: '', label: '(默认)' },
|
||||
...profiles.map(p => ({ value: p.path, label: p.name })),
|
||||
...(defaultAskProfilePath
|
||||
&& !profiles.some(p => p.path === defaultAskProfilePath)
|
||||
? [{ value: defaultAskProfilePath, label: `不可用:${defaultAskProfilePath}` }]
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="冲突解决配置文件"
|
||||
hint={(
|
||||
|
||||
@@ -21,19 +21,10 @@ import type { ExtensionToWebview, LogEntry, ReleaseCommitGroup } from '../lib/me
|
||||
import type { Issue, IssueColumn } from '../types'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { handoffRequestNotices } from '../../../src/panel/handlers/handoffRequest'
|
||||
import { applyIssueUpdate } from '../../../src/shared/kanbanUpdates'
|
||||
import { compareIssuesInColumn } from '../lib/issueSort'
|
||||
import { onMessage, postMessage } from '../lib/vscode'
|
||||
|
||||
/** postMessage 用 null 清空 optional 字段;合并时 delete 还原 optional,避免残留 null */
|
||||
function applyIssuePatch(issue: Issue, patch: Record<string, unknown>): Issue {
|
||||
const next = { ...issue, ...patch } as Issue & Record<string, unknown>
|
||||
for (const [k, v] of Object.entries(patch)) {
|
||||
if (v === null)
|
||||
delete next[k]
|
||||
}
|
||||
return next as Issue
|
||||
}
|
||||
|
||||
export interface SettingsValues {
|
||||
host: string
|
||||
token: string
|
||||
@@ -61,6 +52,7 @@ export interface SettingsValues {
|
||||
defaultImplementProfilePath: string
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -102,6 +94,7 @@ export interface SettingsOverlayState {
|
||||
defaultImplementProfilePath: string
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -465,6 +458,7 @@ export function useIssues(): UseIssuesResult {
|
||||
defaultImplementProfilePath: values.defaultImplementProfilePath,
|
||||
defaultTestProfilePath: values.defaultTestProfilePath,
|
||||
defaultPrototypeProfilePath: values.defaultPrototypeProfilePath,
|
||||
defaultAskProfilePath: values.defaultAskProfilePath,
|
||||
conflictResolutionProfilePath: values.conflictResolutionProfilePath,
|
||||
commitProfilePath: values.commitProfilePath,
|
||||
prDiffSummaryProfilePath: values.prDiffSummaryProfilePath,
|
||||
@@ -890,9 +884,7 @@ export function useIssues(): UseIssuesResult {
|
||||
return prev
|
||||
return {
|
||||
status: 'ready',
|
||||
issues: prev.issues.map(i =>
|
||||
i.number === msg.issueNumber ? applyIssuePatch(i, msg.patch) : i,
|
||||
),
|
||||
issues: applyIssueUpdate(prev.issues, msg),
|
||||
}
|
||||
})
|
||||
if (msg.patch.prDiffFile)
|
||||
@@ -915,7 +907,7 @@ export function useIssues(): UseIssuesResult {
|
||||
if (prev.status !== 'ready')
|
||||
return prev
|
||||
const removed = prev.issues.find(i => i.number === msg.issueNumber)
|
||||
const remaining = prev.issues.filter(i => i.number !== msg.issueNumber)
|
||||
const remaining = applyIssueUpdate(prev.issues, msg)
|
||||
if (removed) {
|
||||
const sameCol = remaining
|
||||
.filter(i => i.column === removed.column)
|
||||
@@ -931,12 +923,9 @@ export function useIssues(): UseIssuesResult {
|
||||
setState((prev) => {
|
||||
if (prev.status !== 'ready')
|
||||
return prev
|
||||
const exists = prev.issues.some(i => i.number === msg.issue.number)
|
||||
return {
|
||||
status: 'ready',
|
||||
issues: exists
|
||||
? prev.issues.map(i => i.number === msg.issue.number ? msg.issue : i)
|
||||
: [...prev.issues, msg.issue],
|
||||
issues: applyIssueUpdate(prev.issues, msg),
|
||||
}
|
||||
})
|
||||
if (msg.select)
|
||||
@@ -991,6 +980,7 @@ export function useIssues(): UseIssuesResult {
|
||||
defaultImplementProfilePath: msg.defaultImplementProfilePath,
|
||||
defaultTestProfilePath: msg.defaultTestProfilePath,
|
||||
defaultPrototypeProfilePath: msg.defaultPrototypeProfilePath,
|
||||
defaultAskProfilePath: msg.defaultAskProfilePath,
|
||||
conflictResolutionProfilePath: msg.conflictResolutionProfilePath,
|
||||
commitProfilePath: msg.commitProfilePath,
|
||||
prDiffSummaryProfilePath: msg.prDiffSummaryProfilePath,
|
||||
|
||||
@@ -134,6 +134,7 @@ export type ExtensionToWebview
|
||||
defaultImplementProfilePath: string
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
@@ -219,6 +220,7 @@ export type WebviewToExtension
|
||||
defaultImplementProfilePath: string
|
||||
defaultTestProfilePath: string
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
conflictResolutionProfilePath: string
|
||||
commitProfilePath: string
|
||||
prDiffSummaryProfilePath: string
|
||||
|
||||
Reference in new issue
Block a user