dsh-vscode-mode 0.20.2 → 0.20.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,154 @@
1
+ import React from 'react'
2
+ import { Button, Menu } from '@deepseek-ai/dsh-client-ui-primitives'
3
+ import { callIdAttr } from '../state/records.js'
4
+ import { SIDECAR_KEEP_TITLE, SIDECAR_LABEL, SIDECAR_LABEL_TITLE, SIDECAR_UNDO_TITLE, reviewBarView } from '../reviewBar.js'
5
+ import type { OfficialDownView } from '../reviewBar.js'
6
+ import { barIcon } from './OfficialDiffBar.js'
7
+ import { ReviewAllRow } from './reviewAllRow.js'
8
+ import { badgeOf } from './shared.js'
9
+
10
+ /** 侧车差异区域:由 records 派生的行范围,不含官方块元数据。 */
11
+ export interface SidecarRegion {
12
+ callId: string
13
+ idx: number
14
+ start?: number
15
+ end?: number
16
+ oldLines?: string[]
17
+ newLines?: string[]
18
+ create?: boolean
19
+ status?: string
20
+ }
21
+
22
+ /** 侧车栏输入:字段与官方栏对齐,缺的是官方记录元数据,多的是侧车区域的 keep/undo 能力。 */
23
+ export interface SidecarBarProps {
24
+ activePath?: string
25
+ pendingRegions?: SidecarRegion[]
26
+ staleRegions?: SidecarRegion[]
27
+ diffIdx?: number
28
+ /** 编辑器内容是否就绪;未就绪时不得断言差异失效 */
29
+ contentReady?: boolean
30
+ fileIdx?: number
31
+ fileTotal?: number
32
+ allPendingCount?: number
33
+ reviewBatchBusy?: boolean
34
+ /** 官方元数据通道失败时的可操作提示 */
35
+ officialDown?: OfficialDownView
36
+ onRetryOfficial?: () => void
37
+ onAcceptFile: () => void
38
+ onUndoFile: () => void
39
+ onAcceptAllFiles: () => void
40
+ onUndoAllFiles: () => void
41
+ onPrevFile: () => void
42
+ onNextFile: () => void
43
+ onPrevDiff: () => void
44
+ onNextDiff: () => void
45
+ onOpenLauncher: (tab: string) => void
46
+ onJump?: (region: SidecarRegion) => void
47
+ onRollback?: () => void
48
+ onRefresh?: () => void
49
+ reviewError?: string
50
+ reviewErrorTone?: 'info' | 'error'
51
+ }
52
+
53
+ /**
54
+ * 侧车(历史捕获)差异栏:与官方栏同一套版式、同一套按钮位置,只把数据源与标识换掉。
55
+ * 两套栏并存是数据现实,但外观不能分家,否则用户会以为插件版本不一致。
56
+ * @public
57
+ * @author ddj 2026年10月28号
58
+ * @param props 侧车区域计数、批量可用性与回调
59
+ * @returns 与官方栏同构的差异工具栏;展开后列出侧车区域
60
+ */
61
+ export function SidecarDiffBar(props: SidecarBarProps): React.ReactElement {
62
+ const pendingRegions = props.pendingRegions ?? []
63
+ const staleRegions = props.staleRegions ?? []
64
+ const [expanded, setExpanded] = React.useState(false)
65
+ const [menu, setMenu] = React.useState<'more' | null>(null)
66
+ const name = String(props.activePath || '').split(/[\\/]/).pop() || '当前文件'
67
+ const count = pendingRegions.length
68
+ const total = count + staleRegions.length
69
+ const busy = props.reviewBatchBusy === true
70
+ const canDecide = total > 0 && !busy
71
+ const view = reviewBarView({
72
+ jumps: count, stale: staleRegions.length, index: props.diffIdx ?? 0,
73
+ ready: props.contentReady === true, pendingRecords: total, canKeep: true,
74
+ })
75
+ const down = props.officialDown
76
+
77
+ /** @private @author ddj 2026年10月28号 @param tab 既有总览页签 @returns 打开既有总览并收起菜单 */
78
+ function openOverview(tab: string): void { props.onOpenLauncher(tab); setMenu(null) }
79
+
80
+ /** @private @author ddj 2026年10月28号 @param mark 工具栏图标 @param label 无障碍名称 @param action 既有回调 @param disabled 是否禁用 @param title 禁用原因 @returns 紧凑导航按钮 */
81
+ function navButton(mark: Parameters<typeof barIcon>[0], label: string, action: () => void, disabled: boolean, title?: string): React.ReactElement {
82
+ return <Button size="sm" variant="ghost" className="edrv-review-icon" aria-label={label} title={title || label} disabled={disabled} onClick={action}>{barIcon(mark)}</Button>
83
+ }
84
+
85
+ const moreTrigger = <Button size="sm" variant="ghost" className="edrv-review-icon" aria-label="更多审查操作" title="更多审查操作" aria-haspopup="menu" aria-expanded={menu === 'more'} onClick={() => setMenu(menu === 'more' ? null : 'more')}>{barIcon('more')}</Button>
86
+
87
+ const body = expanded
88
+ ? <div className="edrv-review-body">
89
+ {pendingRegions.map((region) => {
90
+ const key = callIdAttr(region.callId, region.idx)
91
+ return <div key={key} className="edrv-diffrow" data-edrv-hunk={key} title={'跳转到 L' + (region.start ?? '?')} onClick={() => props.onJump?.(region)}>
92
+ <span className="edrv-diffrow-l">{'L' + (region.start ?? '?') + '-' + (region.end ?? '?')}</span>
93
+ {(region.oldLines?.length ?? 0) > 0 ? <span className="edrv-diffrow-o">{'-' + (region.oldLines?.length ?? 0)}</span> : null}
94
+ {(region.newLines?.length ?? 0) > 0 ? <span className="edrv-diffrow-n">{'+' + (region.newLines?.length ?? 0)}</span> : null}
95
+ {region.create ? <span className="edrv-diffrow-tag">新建</span> : null}
96
+ </div>
97
+ })}
98
+ {staleRegions.map((region) => <div key={'stale' + callIdAttr(region.callId, region.idx)} className="edrv-diffrow edrv-diffrow-stale" title="差异无法定位(文件可能已被手动修改)">
99
+ <span className="edrv-diffrow-l">{'L' + (region.start ?? '?') + ' 无法定位'}</span>
100
+ <span className="edrv-diffrow-tag">冲突/需刷新</span>
101
+ <span className="edrv-diffrow-tag">{badgeOf(region.status ?? '')}</span>
102
+ </div>)}
103
+ </div>
104
+ : null
105
+
106
+ return <div className="edrv-diffbar edrv-diffbar-dock edrv-reviewbar" data-edrv-diffbox="1" data-edrv-diff-source="sidecar" role="region" aria-label="文件差异审查">
107
+ <ReviewAllRow
108
+ total={props.fileTotal ?? 0}
109
+ current={(props.fileTotal ?? 0) && (props.fileIdx ?? -1) >= 0 ? (props.fileIdx ?? 0) + 1 : 0}
110
+ busy={busy}
111
+ pending={props.allPendingCount}
112
+ onOpen={() => props.onOpenLauncher('pending')}
113
+ onKeepAll={props.onAcceptAllFiles}
114
+ onUndoAll={props.onUndoAllFiles}
115
+ keepTitle="把这批历史改动全部标记为已看过(只改记录,不动磁盘文件)"
116
+ undoTitle="逐项撤销这些历史改动;缺少证据或遇到冲突即停止"
117
+ />
118
+ {busy ? <div className="edrv-review-notice" role="status">正在处理历史改动…</div> : null}
119
+ {down ? <div className="edrv-review-notice edrv-review-notice-warn edrv-sidecar-down" role="status">
120
+ <span className="edrv-sidecar-down-text">{down.text}</span>
121
+ {props.onRetryOfficial ? <Button size="sm" variant="ghost" onClick={props.onRetryOfficial} title="重新读取官方待审记录">{down.retryLabel || '重试'}</Button> : null}
122
+ </div> : null}
123
+ <div className="edrv-review-heading">
124
+ <span className="edrv-review-filemark">{barIcon('file')}</span>
125
+ <span className="edrv-review-filename" title={props.activePath}>{name}</span>
126
+ <span className="edrv-review-source" title={SIDECAR_LABEL_TITLE}>{SIDECAR_LABEL}</span>
127
+ <span className="edrv-review-pending" title={view.pendingTitle}>待审 <strong>{total}</strong></span>
128
+ </div>
129
+ <div className="edrv-review-tools">
130
+ <div className="edrv-review-nav" role="group" aria-label="文件导航">
131
+ {navButton('left', '上一个差异文件', props.onPrevFile, !props.fileTotal)}
132
+ {navButton('right', '下一个差异文件', props.onNextFile, !props.fileTotal)}
133
+ </div>
134
+ <div className="edrv-review-nav edrv-review-blocknav" role="group" aria-label="差异导航">
135
+ {navButton('up', '上一个差异', props.onPrevDiff, !count, view.navPrevTitle)}
136
+ <span className="edrv-review-position" aria-live="polite">{view.position}</span>
137
+ {navButton('down', '下一个差异', props.onNextDiff, !count, view.navNextTitle)}
138
+ </div>
139
+ <div className="edrv-review-actions">
140
+ <Button size="sm" variant="ghost" className="edrv-review-undo" icon={barIcon('undo')} onClick={props.onUndoFile} disabled={!canDecide} title={SIDECAR_UNDO_TITLE}>Undo</Button>
141
+ <Button size="sm" variant="primary" className="edrv-review-keep" icon={barIcon('check')} onClick={props.onAcceptFile} disabled={!canDecide} title={SIDECAR_KEEP_TITLE}>Keep</Button>
142
+ <Button size="sm" variant="ghost" className="edrv-review-details" onClick={() => setExpanded(!expanded)} aria-expanded={expanded} aria-label={expanded ? '收起差异' : '展开差异'} title={expanded ? '收起差异' : '展开差异'}>详情{barIcon(expanded ? 'up' : 'down')}</Button>
143
+ <Menu open={menu === 'more'} anchor={moreTrigger} items={[{ id: 'pending', label: '差异总览' }, { id: 'archive', label: '归档 / 历史' }, { id: 'rollback', label: '回滚当前文件' }, { id: 'refresh', label: '刷新' }]} onSelect={(id: string) => {
144
+ if (id === 'rollback') { setMenu(null); props.onRollback?.(); return }
145
+ if (id === 'refresh') { setMenu(null); props.onRefresh?.(); return }
146
+ openOverview(id)
147
+ }} onClose={() => setMenu(null)} side="top" align="end" portal compact autoFocus />
148
+ </div>
149
+ </div>
150
+ {view.notice ? <div className={view.noticeTone === 'warn' ? 'edrv-review-notice edrv-review-notice-warn' : 'edrv-review-notice'} role="status">{view.notice}</div> : null}
151
+ {props.reviewError ? <div className={props.reviewErrorTone === 'info' ? 'edrv-review-notice' : 'edrv-review-notice edrv-review-error'} role={props.reviewErrorTone === 'info' ? 'status' : 'alert'}>{props.reviewError}</div> : null}
152
+ {body}
153
+ </div>
154
+ }
@@ -0,0 +1,48 @@
1
+ import React from 'react'
2
+ import { Button } from '@deepseek-ai/dsh-client-ui-primitives'
3
+
4
+ /** 全工作区批量行输入:官方栏与侧车栏共用同一套外观与禁用语义。 */
5
+ export interface ReviewAllRowProps {
6
+ /** 当前文件序号(1 基,0 表示未定位) */
7
+ current: number
8
+ /** 差异文件总数 */
9
+ total: number
10
+ /** 批量操作进行中 */
11
+ busy?: boolean
12
+ /** 批量不可用原因(悬浮提示) */
13
+ unavailable?: string
14
+ /** 工作区待处理项总数;为 0 时两个按钮禁用 */
15
+ pending?: number
16
+ /** 打开差异总览 */
17
+ onOpen: () => void
18
+ /** 全部 Keep */
19
+ onKeepAll?: () => void
20
+ /** 全部 Undo */
21
+ onUndoAll?: () => void
22
+ /** Keep All 悬浮说明 */
23
+ keepTitle?: string
24
+ /** Undo All 悬浮说明 */
25
+ undoTitle?: string
26
+ }
27
+
28
+ /**
29
+ * 全局批量行:差异文件计数 + Keep All / Undo All。
30
+ * 两套差异栏(官方 / 侧车)必须长得一样,否则用户会以为看到的是不同产品。
31
+ * @public
32
+ * @author ddj 2026年10月28号
33
+ * @param props 计数、批量可用性与回调
34
+ * @returns 持久化的全工作区控制条
35
+ */
36
+ export function ReviewAllRow(props: ReviewAllRowProps): React.ReactElement {
37
+ const total = props.total ?? 0
38
+ const current = total && props.current > 0 ? props.current : 0
39
+ const disabled = props.busy || !!props.unavailable || !props.pending
40
+
41
+ return <div className="edrv-review-global" role="group" aria-label="全部待审文件">
42
+ <Button size="sm" variant="ghost" className="edrv-review-total" onClick={props.onOpen} title="打开当前工作区全部待审差异文件">差异文件 <strong>{current} / {total}</strong></Button>
43
+ <span className="edrv-review-all-actions">
44
+ <Button size="sm" variant="ghost" onClick={props.onKeepAll} disabled={disabled || !props.onKeepAll} title={props.unavailable || props.keepTitle || 'Keep 当前工作区全部待审文件'}>Keep All</Button>
45
+ <Button size="sm" variant="ghost" className="edrv-review-undo" onClick={props.onUndoAll} disabled={disabled || !props.onUndoAll} title={props.unavailable || props.undoTitle || 'Undo 当前工作区全部待审文件'}>Undo All</Button>
46
+ </span>
47
+ </div>
48
+ }