✨ feat(vscode): 工具栏发布按钮与下拉菜单
Claude-Session: https://claude.ai/code/session_01HTMgwaE3woqM5yvsHiuSAa
This commit is contained in:
1 parent
b363e08ef9
commit
d04048148a
6 files changed
+120
-121
No files matched your search
@@ -28,6 +28,8 @@ export async function handleReleaseStatus(panel: KanbanWebviewPanel): Promise<vo
|
|||||||
devBranch: s.devBranch,
|
devBranch: s.devBranch,
|
||||||
nextBranch: todayReleaseBranch(s.releaseBranchPrefix),
|
nextBranch: todayReleaseBranch(s.releaseBranchPrefix),
|
||||||
running: panel.releaseRunning,
|
running: panel.releaseRunning,
|
||||||
|
// webview 只在设置弹窗打开时才有设置快照,「部署」菜单项是否显示由这里告诉它
|
||||||
|
jenkinsConfigured: s.jenkinsJob.length > 0,
|
||||||
}
|
}
|
||||||
if (!root) {
|
if (!root) {
|
||||||
panel.postMessage({ ...base, unreleased: 0, unavailable: '请先打开一个工作区文件夹' })
|
panel.postMessage({ ...base, unreleased: 0, unavailable: '请先打开一个工作区文件夹' })
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ export type ExtensionToWebview
|
|||||||
unreleased: number
|
unreleased: number
|
||||||
unavailable?: string
|
unavailable?: string
|
||||||
running: boolean
|
running: boolean
|
||||||
|
jenkinsConfigured: boolean
|
||||||
}
|
}
|
||||||
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
|
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
|
||||||
| { type: 'issue/remove', issueNumber: number }
|
| { type: 'issue/remove', issueNumber: number }
|
||||||
|
|||||||
@@ -67,11 +67,8 @@ export function App() {
|
|||||||
commitRunning,
|
commitRunning,
|
||||||
runCommit,
|
runCommit,
|
||||||
hasChanges,
|
hasChanges,
|
||||||
branchSyncBehind,
|
release,
|
||||||
branchSyncRunning,
|
runRelease,
|
||||||
branchSyncDisabled,
|
|
||||||
branchSyncTitle,
|
|
||||||
runBranchSync,
|
|
||||||
envLocked,
|
envLocked,
|
||||||
envFileCount,
|
envFileCount,
|
||||||
envLockRunning,
|
envLockRunning,
|
||||||
@@ -307,16 +304,13 @@ export function App() {
|
|||||||
commitRunning={commitRunning}
|
commitRunning={commitRunning}
|
||||||
hasChanges={hasChanges}
|
hasChanges={hasChanges}
|
||||||
onCommit={runCommit}
|
onCommit={runCommit}
|
||||||
branchSyncBehind={branchSyncBehind}
|
release={release}
|
||||||
branchSyncRunning={branchSyncRunning}
|
onRelease={runRelease}
|
||||||
branchSyncDisabled={branchSyncDisabled}
|
|
||||||
branchSyncTitle={branchSyncTitle}
|
|
||||||
envLocked={envLocked}
|
envLocked={envLocked}
|
||||||
envFileCount={envFileCount}
|
envFileCount={envFileCount}
|
||||||
envLockRunning={envLockRunning}
|
envLockRunning={envLockRunning}
|
||||||
envLockTitle={envLockTitle}
|
envLockTitle={envLockTitle}
|
||||||
onToggleEnvLock={toggleEnvLock}
|
onToggleEnvLock={toggleEnvLock}
|
||||||
onSyncBranch={runBranchSync}
|
|
||||||
youtrackConfigured={youtrackConfigured}
|
youtrackConfigured={youtrackConfigured}
|
||||||
onImportYouTrack={importYouTrack}
|
onImportYouTrack={importYouTrack}
|
||||||
/>
|
/>
|
||||||
@@ -336,16 +330,13 @@ export function App() {
|
|||||||
commitRunning={commitRunning}
|
commitRunning={commitRunning}
|
||||||
hasChanges={hasChanges}
|
hasChanges={hasChanges}
|
||||||
onCommit={runCommit}
|
onCommit={runCommit}
|
||||||
branchSyncBehind={branchSyncBehind}
|
release={release}
|
||||||
branchSyncRunning={branchSyncRunning}
|
onRelease={runRelease}
|
||||||
branchSyncDisabled={branchSyncDisabled}
|
|
||||||
branchSyncTitle={branchSyncTitle}
|
|
||||||
envLocked={envLocked}
|
envLocked={envLocked}
|
||||||
envFileCount={envFileCount}
|
envFileCount={envFileCount}
|
||||||
envLockRunning={envLockRunning}
|
envLockRunning={envLockRunning}
|
||||||
envLockTitle={envLockTitle}
|
envLockTitle={envLockTitle}
|
||||||
onToggleEnvLock={toggleEnvLock}
|
onToggleEnvLock={toggleEnvLock}
|
||||||
onSyncBranch={runBranchSync}
|
|
||||||
youtrackConfigured={youtrackConfigured}
|
youtrackConfigured={youtrackConfigured}
|
||||||
onImportYouTrack={importYouTrack}
|
onImportYouTrack={importYouTrack}
|
||||||
/>
|
/>
|
||||||
@@ -434,16 +425,13 @@ export function App() {
|
|||||||
commitRunning={commitRunning}
|
commitRunning={commitRunning}
|
||||||
hasChanges={hasChanges}
|
hasChanges={hasChanges}
|
||||||
onCommit={runCommit}
|
onCommit={runCommit}
|
||||||
branchSyncBehind={branchSyncBehind}
|
release={release}
|
||||||
branchSyncRunning={branchSyncRunning}
|
onRelease={runRelease}
|
||||||
branchSyncDisabled={branchSyncDisabled}
|
|
||||||
branchSyncTitle={branchSyncTitle}
|
|
||||||
envLocked={envLocked}
|
envLocked={envLocked}
|
||||||
envFileCount={envFileCount}
|
envFileCount={envFileCount}
|
||||||
envLockRunning={envLockRunning}
|
envLockRunning={envLockRunning}
|
||||||
envLockTitle={envLockTitle}
|
envLockTitle={envLockTitle}
|
||||||
onToggleEnvLock={toggleEnvLock}
|
onToggleEnvLock={toggleEnvLock}
|
||||||
onSyncBranch={runBranchSync}
|
|
||||||
youtrackConfigured={youtrackConfigured}
|
youtrackConfigured={youtrackConfigured}
|
||||||
onImportYouTrack={importYouTrack}
|
onImportYouTrack={importYouTrack}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { GitCommit, GitMerge, ListPlus, Loader2, Lock, RefreshCw, Settings, Unlock, User, Users } from 'lucide-react'
|
import type { ReleaseAction, ReleaseStatus } from '../hooks/useIssues'
|
||||||
|
import { GitCommit, ListPlus, Loader2, Lock, RefreshCw, Rocket, Settings, Unlock, User, Users } from 'lucide-react'
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onRefresh: () => void
|
onRefresh: () => void
|
||||||
@@ -15,24 +17,9 @@ interface Props {
|
|||||||
*/
|
*/
|
||||||
hasChanges: boolean
|
hasChanges: boolean
|
||||||
onCommit: () => void
|
onCommit: () => void
|
||||||
/**
|
/** 最近一次发布状态;首次消息到达前为 undefined,按钮显示「正在检查」并禁用。 */
|
||||||
* Commits the remote auto-build branch is behind the remote dev branch.
|
release: ReleaseStatus | undefined
|
||||||
* Combined with `branchSyncDisabled` to compute the button's disabled
|
onRelease: (action: ReleaseAction) => void
|
||||||
* state.
|
|
||||||
*/
|
|
||||||
branchSyncBehind: number
|
|
||||||
branchSyncRunning: boolean
|
|
||||||
/**
|
|
||||||
* True when sync is structurally unavailable (same-branch / fetch fail
|
|
||||||
* / not a repo / …). Disables the button regardless of `branchSyncBehind`.
|
|
||||||
*/
|
|
||||||
branchSyncDisabled: boolean
|
|
||||||
/**
|
|
||||||
* Hover tooltip, already includes branch names + behind count or the
|
|
||||||
* unavailable reason.
|
|
||||||
*/
|
|
||||||
branchSyncTitle: string
|
|
||||||
onSyncBranch: () => void
|
|
||||||
/**
|
/**
|
||||||
* Whether the workspace's `.env*` files are currently chmod-locked (444).
|
* Whether the workspace's `.env*` files are currently chmod-locked (444).
|
||||||
* Icon flips between Lock and Unlock based on this.
|
* Icon flips between Lock and Unlock based on this.
|
||||||
@@ -63,6 +50,19 @@ interface Props {
|
|||||||
onImportYouTrack: () => void
|
onImportYouTrack: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MENU_ITEM_CLASS = 'w-full px-3 py-1 text-left hover:bg-[var(--vscode-menu-selectionBackground)] hover:text-[var(--vscode-menu-selectionForeground)] disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent disabled:hover:text-inherit'
|
||||||
|
|
||||||
|
function releaseTitle(release: ReleaseStatus | undefined): string {
|
||||||
|
if (!release)
|
||||||
|
return '正在检查发布状态…'
|
||||||
|
if (release.unavailable)
|
||||||
|
return release.unavailable
|
||||||
|
if (!release.current)
|
||||||
|
return '尚无发布点 · 点击切第一个发布分支'
|
||||||
|
const lead = release.unreleased > 0 ? `${release.devBranch} 领先 ${release.unreleased} 个提交` : '已全部发布'
|
||||||
|
return `正式服发布点 ${release.current} · ${lead}`
|
||||||
|
}
|
||||||
|
|
||||||
export function PanelHeader({
|
export function PanelHeader({
|
||||||
onRefresh,
|
onRefresh,
|
||||||
scope,
|
scope,
|
||||||
@@ -71,11 +71,8 @@ export function PanelHeader({
|
|||||||
commitRunning,
|
commitRunning,
|
||||||
hasChanges,
|
hasChanges,
|
||||||
onCommit,
|
onCommit,
|
||||||
branchSyncBehind,
|
release,
|
||||||
branchSyncRunning,
|
onRelease,
|
||||||
branchSyncDisabled,
|
|
||||||
branchSyncTitle,
|
|
||||||
onSyncBranch,
|
|
||||||
envLocked,
|
envLocked,
|
||||||
envFileCount,
|
envFileCount,
|
||||||
envLockRunning,
|
envLockRunning,
|
||||||
@@ -85,27 +82,80 @@ export function PanelHeader({
|
|||||||
onImportYouTrack,
|
onImportYouTrack,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const showCommit = hasChanges || commitRunning
|
const showCommit = hasChanges || commitRunning
|
||||||
// Sync button is *always* rendered so the user can see status (vs the
|
|
||||||
// commit button which auto-hides on a clean tree). Disabled when nothing
|
|
||||||
// to push, unavailable, or already syncing.
|
|
||||||
const syncDisabled = branchSyncRunning || branchSyncDisabled || branchSyncBehind <= 0
|
|
||||||
// Env-lock button is always visible; disabled while a chmod batch is in
|
// Env-lock button is always visible; disabled while a chmod batch is in
|
||||||
// flight or when the workspace has no .env files to act on.
|
// flight or when the workspace has no .env files to act on.
|
||||||
const envLockDisabled = envLockRunning || envFileCount === 0
|
const envLockDisabled = envLockRunning || envFileCount === 0
|
||||||
|
|
||||||
|
const [releaseMenuOpen, setReleaseMenuOpen] = useState(false)
|
||||||
|
const menuRef = useRef<HTMLDivElement>(null)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!releaseMenuOpen)
|
||||||
|
return
|
||||||
|
const onDown = (e: MouseEvent): void => {
|
||||||
|
if (!menuRef.current?.contains(e.target as Node))
|
||||||
|
setReleaseMenuOpen(false)
|
||||||
|
}
|
||||||
|
document.addEventListener('mousedown', onDown)
|
||||||
|
return () => document.removeEventListener('mousedown', onDown)
|
||||||
|
}, [releaseMenuOpen])
|
||||||
|
|
||||||
|
const title = releaseTitle(release)
|
||||||
|
// 发布按钮常驻,让用户随时看到发布点状态;结构性不可用或动作进行中禁用。
|
||||||
|
const releaseDisabled = !release || !!release.unavailable || release.running
|
||||||
|
const unreleased = release?.unreleased ?? 0
|
||||||
|
|
||||||
|
function pickRelease(action: ReleaseAction): void {
|
||||||
|
setReleaseMenuOpen(false)
|
||||||
|
onRelease(action)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-8 shrink-0 items-center justify-end gap-1 border-b border-[var(--vscode-panel-border)] px-2">
|
<div className="flex h-8 shrink-0 items-center justify-end gap-1 border-b border-[var(--vscode-panel-border)] px-2">
|
||||||
<button
|
<div ref={menuRef} className="relative">
|
||||||
type="button"
|
<button
|
||||||
onClick={onSyncBranch}
|
type="button"
|
||||||
disabled={syncDisabled}
|
onClick={() => setReleaseMenuOpen(open => !open)}
|
||||||
title={branchSyncTitle}
|
disabled={releaseDisabled}
|
||||||
aria-label={branchSyncTitle}
|
title={title}
|
||||||
className="flex h-6 w-6 items-center justify-center rounded hover:bg-[var(--vscode-toolbar-hoverBackground)] disabled:cursor-not-allowed disabled:opacity-50"
|
aria-label={title}
|
||||||
>
|
aria-haspopup="menu"
|
||||||
{branchSyncRunning
|
aria-expanded={releaseMenuOpen}
|
||||||
? <Loader2 size={14} className="animate-spin" />
|
className="relative flex h-6 w-6 items-center justify-center rounded hover:bg-[var(--vscode-toolbar-hoverBackground)] disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
: <GitMerge size={14} />}
|
>
|
||||||
</button>
|
{release?.running
|
||||||
|
? <Loader2 size={14} className="animate-spin" />
|
||||||
|
: <Rocket size={14} />}
|
||||||
|
{unreleased > 0 && (
|
||||||
|
<span className="absolute -right-1 -top-1 rounded-full bg-[var(--vscode-badge-background)] px-1 text-[9px] leading-3 text-[var(--vscode-badge-foreground)]">
|
||||||
|
{unreleased > 99 ? '99+' : unreleased}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
{releaseMenuOpen && release && (
|
||||||
|
<div
|
||||||
|
role="menu"
|
||||||
|
className="absolute right-0 top-7 z-20 min-w-44 rounded border border-[var(--vscode-menu-border)] bg-[var(--vscode-menu-background)] py-1 text-xs text-[var(--vscode-menu-foreground)] shadow"
|
||||||
|
>
|
||||||
|
<button type="button" role="menuitem" className={MENU_ITEM_CLASS} onClick={() => pickRelease('cut')}>
|
||||||
|
{`切新发布(${release.nextBranch})`}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
role="menuitem"
|
||||||
|
className={MENU_ITEM_CLASS}
|
||||||
|
disabled={!release.current}
|
||||||
|
onClick={() => pickRelease('cherry-pick')}
|
||||||
|
>
|
||||||
|
{release.current ? `摘修复到 ${release.current}` : '摘修复(尚无发布分支)'}
|
||||||
|
</button>
|
||||||
|
{release.jenkinsConfigured && (
|
||||||
|
<button type="button" role="menuitem" className={MENU_ITEM_CLASS} onClick={() => pickRelease('deploy')}>
|
||||||
|
部署到正式服…
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onToggleEnvLock}
|
onClick={onToggleEnvLock}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ToastItem } from '../components/ToastStack'
|
import type { ToastItem } from '../components/ToastStack'
|
||||||
import type { LogEntry } from '../lib/messages'
|
import type { ExtensionToWebview, LogEntry } from '../lib/messages'
|
||||||
import type { Issue, IssueColumn } from '../types'
|
import type { Issue, IssueColumn } from '../types'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { compareIssuesInColumn } from '../lib/issueSort'
|
import { compareIssuesInColumn } from '../lib/issueSort'
|
||||||
@@ -126,6 +126,9 @@ export interface ClaudeProfile {
|
|||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ReleaseStatus = Extract<ExtensionToWebview, { type: 'release/status' }>
|
||||||
|
export type ReleaseAction = 'cut' | 'cherry-pick' | 'deploy'
|
||||||
|
|
||||||
export interface UseIssuesResult {
|
export interface UseIssuesResult {
|
||||||
state: UseIssuesState
|
state: UseIssuesState
|
||||||
settings: SettingsOverlayState | null
|
settings: SettingsOverlayState | null
|
||||||
@@ -239,29 +242,10 @@ export interface UseIssuesResult {
|
|||||||
* extension reports its first observation.
|
* extension reports its first observation.
|
||||||
*/
|
*/
|
||||||
hasChanges: boolean
|
hasChanges: boolean
|
||||||
/**
|
/** 最近一次 `release/status`;首次消息到达前为 undefined(按钮显示「正在检查」并禁用)。 */
|
||||||
* Commits the remote auto-build branch is behind the remote dev branch
|
release: ReleaseStatus | undefined
|
||||||
* (per latest `branch-sync/status`). 0 ⇒ in sync ⇒ disable button.
|
/** 发布按钮三个动作;running 由扩展侧状态决定,webview 不自置。 */
|
||||||
*/
|
runRelease: (action: ReleaseAction) => void
|
||||||
branchSyncBehind: number
|
|
||||||
/**
|
|
||||||
* True while a `branch-sync/run` request is in flight. The extension
|
|
||||||
* doesn't echo a "running" state itself — we set this on click and clear
|
|
||||||
* it when the next `branch-sync/status` arrives.
|
|
||||||
*/
|
|
||||||
branchSyncRunning: boolean
|
|
||||||
/**
|
|
||||||
* True when sync is structurally unavailable (same branch, missing
|
|
||||||
* remote, fetch error, …). Disables the button regardless of behind.
|
|
||||||
*/
|
|
||||||
branchSyncDisabled: boolean
|
|
||||||
/**
|
|
||||||
* Tooltip text for the sync button (already includes branch names /
|
|
||||||
* behind count / unavailable reason).
|
|
||||||
*/
|
|
||||||
branchSyncTitle: string
|
|
||||||
/** Trigger a fast-forward push from remote dev to remote auto-build. */
|
|
||||||
runBranchSync: () => void
|
|
||||||
/**
|
/**
|
||||||
* Whether the workspace's `.env*` files are currently chmod-locked
|
* Whether the workspace's `.env*` files are currently chmod-locked
|
||||||
* according to `workspaceState`. Persisted per-workspace.
|
* according to `workspaceState`. Persisted per-workspace.
|
||||||
@@ -316,10 +300,7 @@ export function useIssues(): UseIssuesResult {
|
|||||||
const [pendingSelectId, setPendingSelectId] = useState<string | null>(null)
|
const [pendingSelectId, setPendingSelectId] = useState<string | null>(null)
|
||||||
const [commitRunning, setCommitRunning] = useState<boolean>(false)
|
const [commitRunning, setCommitRunning] = useState<boolean>(false)
|
||||||
const [hasChanges, setHasChanges] = useState<boolean>(false)
|
const [hasChanges, setHasChanges] = useState<boolean>(false)
|
||||||
const [branchSyncBehind, setBranchSyncBehind] = useState<number>(0)
|
const [release, setRelease] = useState<ReleaseStatus>()
|
||||||
const [branchSyncRunning, setBranchSyncRunning] = useState<boolean>(false)
|
|
||||||
const [branchSyncDisabled, setBranchSyncDisabled] = useState<boolean>(true)
|
|
||||||
const [branchSyncTitle, setBranchSyncTitle] = useState<string>('正在检查分支同步状态…')
|
|
||||||
const [envLocked, setEnvLocked] = useState<boolean>(false)
|
const [envLocked, setEnvLocked] = useState<boolean>(false)
|
||||||
const [envFileCount, setEnvFileCount] = useState<number>(0)
|
const [envFileCount, setEnvFileCount] = useState<number>(0)
|
||||||
const [envLockRunning, setEnvLockRunning] = useState<boolean>(false)
|
const [envLockRunning, setEnvLockRunning] = useState<boolean>(false)
|
||||||
@@ -350,9 +331,8 @@ export function useIssues(): UseIssuesResult {
|
|||||||
const refresh = useCallback((): void => {
|
const refresh = useCallback((): void => {
|
||||||
setState({ status: 'loading' })
|
setState({ status: 'loading' })
|
||||||
postMessage({ type: 'issues/refresh' })
|
postMessage({ type: 'issues/refresh' })
|
||||||
// Re-poll branch-sync state on user refresh — branches may have moved
|
// 用户刷新时重查发布状态:远端分支可能已经动了。
|
||||||
// on the remote since the last check.
|
postMessage({ type: 'release/check' })
|
||||||
postMessage({ type: 'branch-sync/check' })
|
|
||||||
// Re-poll env-lock state so newly added .env files surface in the count.
|
// Re-poll env-lock state so newly added .env files surface in the count.
|
||||||
postMessage({ type: 'env-lock/check' })
|
postMessage({ type: 'env-lock/check' })
|
||||||
}, [])
|
}, [])
|
||||||
@@ -637,14 +617,9 @@ export function useIssues(): UseIssuesResult {
|
|||||||
postMessage({ type: 'commit/run' })
|
postMessage({ type: 'commit/run' })
|
||||||
}, [commitRunning])
|
}, [commitRunning])
|
||||||
|
|
||||||
const runBranchSync = useCallback((): void => {
|
const runRelease = useCallback((action: ReleaseAction): void => {
|
||||||
// Double-click guard. The next `branch-sync/status` message clears the
|
postMessage({ type: `release/${action}` })
|
||||||
// running flag — both on success and on failure.
|
}, [])
|
||||||
if (branchSyncRunning)
|
|
||||||
return
|
|
||||||
setBranchSyncRunning(true)
|
|
||||||
postMessage({ type: 'branch-sync/run' })
|
|
||||||
}, [branchSyncRunning])
|
|
||||||
|
|
||||||
const toggleEnvLock = useCallback((): void => {
|
const toggleEnvLock = useCallback((): void => {
|
||||||
// Double-click guard — the next `env-lock/status` clears the running flag.
|
// Double-click guard — the next `env-lock/status` clears the running flag.
|
||||||
@@ -832,27 +807,9 @@ export function useIssues(): UseIssuesResult {
|
|||||||
case 'commit/has-changes':
|
case 'commit/has-changes':
|
||||||
setHasChanges(msg.value)
|
setHasChanges(msg.value)
|
||||||
break
|
break
|
||||||
case 'branch-sync/status': {
|
case 'release/status':
|
||||||
setBranchSyncBehind(msg.behind)
|
setRelease(msg)
|
||||||
setBranchSyncRunning(false)
|
|
||||||
// Title + disabled derive purely from the status payload, so we
|
|
||||||
// resolve them here once instead of recomputing in each render.
|
|
||||||
if (msg.unavailable) {
|
|
||||||
setBranchSyncDisabled(true)
|
|
||||||
setBranchSyncTitle(msg.reason ?? '分支同步不可用')
|
|
||||||
}
|
|
||||||
else if (msg.behind <= 0) {
|
|
||||||
setBranchSyncDisabled(true)
|
|
||||||
setBranchSyncTitle(`${msg.devBranch} → ${msg.autoBuildBranch} 已同步`)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setBranchSyncDisabled(false)
|
|
||||||
setBranchSyncTitle(
|
|
||||||
`同步 ${msg.devBranch} → ${msg.autoBuildBranch}(落后 ${msg.behind} 个提交)`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
|
||||||
case 'env-lock/status': {
|
case 'env-lock/status': {
|
||||||
setEnvLocked(msg.locked)
|
setEnvLocked(msg.locked)
|
||||||
setEnvFileCount(msg.fileCount)
|
setEnvFileCount(msg.fileCount)
|
||||||
@@ -876,10 +833,10 @@ export function useIssues(): UseIssuesResult {
|
|||||||
postMessage({ type: 'issues/refresh' })
|
postMessage({ type: 'issues/refresh' })
|
||||||
postMessage({ type: 'profiles/list' })
|
postMessage({ type: 'profiles/list' })
|
||||||
postMessage({ type: 'logs/fetch' })
|
postMessage({ type: 'logs/fetch' })
|
||||||
postMessage({ type: 'branch-sync/check' })
|
postMessage({ type: 'release/check' })
|
||||||
postMessage({ type: 'env-lock/check' })
|
postMessage({ type: 'env-lock/check' })
|
||||||
return cleanup
|
return cleanup
|
||||||
}, [clearPrDiffSummaryRunning, markHandoffRunning])
|
}, [clearPrDiffSummaryRunning, markHandoffRunning])
|
||||||
|
|
||||||
return { state, settings, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, scope, toggleScope, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, startBrainstormSession, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, branchSyncBehind, branchSyncRunning, branchSyncDisabled, branchSyncTitle, runBranchSync, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning }
|
return { state, settings, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, scope, toggleScope, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, startBrainstormSession, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, release, runRelease, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock, me, handoffUsers, requestHandoffUsers, startHandoff, acceptHandoff, isHandoffRunning }
|
||||||
}
|
}
|
||||||
@@ -135,6 +135,7 @@ export type ExtensionToWebview
|
|||||||
unreleased: number
|
unreleased: number
|
||||||
unavailable?: string
|
unavailable?: string
|
||||||
running: boolean
|
running: boolean
|
||||||
|
jenkinsConfigured: boolean
|
||||||
}
|
}
|
||||||
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
|
| { type: 'env-lock/status', locked: boolean, fileCount: number, failedCount?: number }
|
||||||
| { type: 'issue/remove', issueNumber: number }
|
| { type: 'issue/remove', issueNumber: number }
|
||||||
|
|||||||
Reference in new issue
Block a user