✨ feat(vscode): 多人协作二期:状态分层/写校验/签名/团队视图
- 本机状态(会话id/worktree/profile/prDiffFile)迁 workspaceState, 共享 state JSON 只留团队字段;读侧本地记录叠加,旧数据兜底 - mergeStateJsonComment 写后读回校验,并发覆盖时在最新状态上重放一次 - webhook 支持 Gitea secret,校验 X-Gitea-Signature(HMAC-SHA256), 不匹配 401;设置面板新增 Webhook Secret 字段 - 看板新增 我的/全部 范围切换(团队视图),按工作区持久化
This commit is contained in:
@@ -8,9 +8,9 @@
|
||||
*/
|
||||
|
||||
import type { ReactElement } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { X } from 'lucide-react'
|
||||
import type { ClaudeProfile } from '../hooks/useIssues'
|
||||
import { X } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
type GroupKey = 'auth' | 'network' | 'youtrack' | 'prompts' | 'hooks'
|
||||
|
||||
@@ -18,6 +18,7 @@ interface SubmitValues {
|
||||
host: string
|
||||
token: string
|
||||
webhookPort: number
|
||||
webhookSecret: string
|
||||
brainstormPrompt: string
|
||||
brainstormContinuePrompt: string
|
||||
implementPlanPrompt: string
|
||||
@@ -63,6 +64,7 @@ export interface SettingsModalProps {
|
||||
canCancel?: boolean
|
||||
initialTokenSaved: boolean
|
||||
initialWebhookPort: number
|
||||
initialWebhookSecret: string
|
||||
initialBrainstormPrompt: string
|
||||
initialBrainstormContinuePrompt: string
|
||||
initialImplementPlanPrompt: string
|
||||
@@ -127,8 +129,10 @@ const GROUPS: Array<{ key: GroupKey, label: string }> = [
|
||||
|
||||
type ErrorKey = 'host' | 'token' | 'webhookPort'
|
||||
|
||||
/** Map a field name to the group it lives in, so we can auto-switch to the
|
||||
* first invalid field's group on save. */
|
||||
/**
|
||||
* Map a field name to the group it lives in, so we can auto-switch to the
|
||||
* first invalid field's group on save.
|
||||
*/
|
||||
const FIELD_TO_GROUP: Record<ErrorKey, GroupKey> = {
|
||||
host: 'auth',
|
||||
token: 'auth',
|
||||
@@ -142,6 +146,7 @@ export function SettingsModal({
|
||||
canCancel,
|
||||
initialTokenSaved,
|
||||
initialWebhookPort,
|
||||
initialWebhookSecret,
|
||||
initialBrainstormPrompt,
|
||||
initialBrainstormContinuePrompt,
|
||||
initialImplementPlanPrompt,
|
||||
@@ -175,6 +180,7 @@ export function SettingsModal({
|
||||
const [host, setHost] = useState(initialHost)
|
||||
const [token, setToken] = useState('')
|
||||
const [webhookPort, setWebhookPort] = useState<string>(String(initialWebhookPort))
|
||||
const [webhookSecret, setWebhookSecret] = useState(initialWebhookSecret)
|
||||
const [brainstormPrompt, setBrainstormPrompt] = useState(initialBrainstormPrompt)
|
||||
const [brainstormContinuePrompt, setBrainstormContinuePrompt] = useState(initialBrainstormContinuePrompt)
|
||||
const [implementPlanPrompt, setImplementPlanPrompt] = useState(initialImplementPlanPrompt)
|
||||
@@ -210,6 +216,7 @@ export function SettingsModal({
|
||||
setHost(initialHost)
|
||||
setToken('')
|
||||
setWebhookPort(String(initialWebhookPort))
|
||||
setWebhookSecret(initialWebhookSecret)
|
||||
setBrainstormPrompt(initialBrainstormPrompt)
|
||||
setBrainstormContinuePrompt(initialBrainstormContinuePrompt)
|
||||
setImplementPlanPrompt(initialImplementPlanPrompt)
|
||||
@@ -294,6 +301,7 @@ export function SettingsModal({
|
||||
// extension side detects empty + existing-saved as "preserve".
|
||||
token: trimmedToken,
|
||||
webhookPort: portNum,
|
||||
webhookSecret: webhookSecret.trim(),
|
||||
brainstormPrompt,
|
||||
brainstormContinuePrompt,
|
||||
implementPlanPrompt,
|
||||
@@ -578,7 +586,13 @@ export function SettingsModal({
|
||||
扩展 HTTP server 绑定的端口。在 gitea 仓库 Webhooks 配置里把目标 URL 指向
|
||||
{' '}
|
||||
<code>{'http://<你的本机/公网域名>:<此端口>/webhook'}</code>
|
||||
,事件需勾选:<b>工单</b>(issue opened/edited)、<b>合并请求</b>(PR opened/synchronize/closed)、<b>工单评论</b>(codex 审查回流)。
|
||||
,事件需勾选:
|
||||
<b>工单</b>
|
||||
(issue opened/edited)、
|
||||
<b>合并请求</b>
|
||||
(PR opened/synchronize/closed)、
|
||||
<b>工单评论</b>
|
||||
(codex 审查回流)。
|
||||
</>
|
||||
)}
|
||||
>
|
||||
@@ -592,6 +606,30 @@ export function SettingsModal({
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="Webhook Secret"
|
||||
hint={(
|
||||
<>
|
||||
与 gitea Webhooks 配置里的
|
||||
{' '}
|
||||
<b>密钥文本</b>
|
||||
{' '}
|
||||
保持一致,用于校验
|
||||
{' '}
|
||||
<code>X-Gitea-Signature</code>
|
||||
。webhook 走公网隧道时必填,否则任何人都能伪造事件;留空 = 不校验。
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
value={webhookSecret}
|
||||
onChange={e => setWebhookSecret(e.target.value)}
|
||||
placeholder="留空表示不校验签名"
|
||||
className={inputClass}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="开启自动审查"
|
||||
hint="PR 创建后自动用 codex exec review 跑审查并把结果灌到实施会话终端"
|
||||
@@ -791,7 +829,12 @@ export function SettingsModal({
|
||||
|
||||
<Field
|
||||
label="审查提示词"
|
||||
hint={<>可用占位符:<code>{'{prNumber}'}</code></>}
|
||||
hint={(
|
||||
<>
|
||||
可用占位符:
|
||||
<code>{'{prNumber}'}</code>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<textarea
|
||||
rows={4}
|
||||
|
||||
Reference in New Issue
Block a user