dsh-ide-git 0.16.0 → 0.16.2
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.
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +70 -52
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-ide-git",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ide-git",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
4
4
|
"description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -8243,7 +8243,7 @@ window.__ModuleLoader__.load({
|
|
|
8243
8243
|
fetch — a BROKEN stem: the references come down, nothing is merged;
|
|
8244
8244
|
pull — a solid stem pointing down: the remote lands here;
|
|
8245
8245
|
push — a solid stem pointing up: the local goes out. */
|
|
8246
|
-
fetch: ['M8
|
|
8246
|
+
fetch: [{ d: 'M8 1.5v8.3', dash: '2.4 2.6' }, { d: 'M4.6 6.4 8 9.8l3.4-3.4' }, { d: 'M3 13h10', w: 2 }],
|
|
8247
8247
|
pull: ['M8 2v7.8', 'M4.6 6.4 8 9.8l3.4-3.4', 'M3 13h10'],
|
|
8248
8248
|
push: ['M8 9.8V2.2', 'M4.6 5.6 8 2.2l3.4 3.4', 'M3 13h10'],
|
|
8249
8249
|
plus: ['M8 3v10', 'M3 8h10'],
|
|
@@ -8295,11 +8295,22 @@ window.__ModuleLoader__.load({
|
|
|
8295
8295
|
const size = props.size === undefined ? 14 : props.size
|
|
8296
8296
|
const shape = ICONS[props.name] === undefined ? ICONS.commit : ICONS[props.name]
|
|
8297
8297
|
const weight = props.name === 'more' ? 2.6 : props.name === 'grip' ? 1.6 : 1.4
|
|
8298
|
+
/* A shape entry is either a plain `d` string or { d, w, dash } for
|
|
8299
|
+
per-path overrides — fetch's broken stem needs a real stroke-dasharray
|
|
8300
|
+
(hand-drawn gaps were being re-filled by the round line caps at 15px),
|
|
8301
|
+
and its ground rail carries a heavier stroke like the VS Code original. */
|
|
8298
8302
|
return E('svg', {
|
|
8299
8303
|
className: 'dig-icon', width: size, height: size, viewBox: '0 0 16 16',
|
|
8300
8304
|
fill: 'none', stroke: 'currentColor', strokeWidth: weight,
|
|
8301
8305
|
strokeLinecap: 'round', strokeLinejoin: 'round',
|
|
8302
|
-
}, shape.map((
|
|
8306
|
+
}, shape.map((entry, index) => {
|
|
8307
|
+
const path = typeof entry === 'string' ? { d: entry } : entry
|
|
8308
|
+
return E('path', {
|
|
8309
|
+
key: index, d: path.d,
|
|
8310
|
+
strokeWidth: path.w === undefined ? undefined : path.w,
|
|
8311
|
+
strokeDasharray: path.dash === undefined ? undefined : path.dash,
|
|
8312
|
+
})
|
|
8313
|
+
}))
|
|
8303
8314
|
}
|
|
8304
8315
|
|
|
8305
8316
|
/* Menus are laid out INSIDE the panel on purpose: dsh-better-sidebar's bottom
|
|
@@ -8314,9 +8325,9 @@ window.__ModuleLoader__.load({
|
|
|
8314
8325
|
const cardRef = useRef(null)
|
|
8315
8326
|
const closeRef = useRef(props.onClose)
|
|
8316
8327
|
const [position, setPosition] = useState({ left: props.anchor.x, top: props.anchor.y })
|
|
8317
|
-
/* The open submenu: { items,
|
|
8318
|
-
|
|
8319
|
-
|
|
8328
|
+
/* The open submenu: { items, top, flip } or null. Hover-driven — moving
|
|
8329
|
+
onto a different parent row swaps or closes it, so no timers are
|
|
8330
|
+
needed. Horizontal placement is pure CSS against the wrapper. */
|
|
8320
8331
|
const [sub, setSub] = useState(null)
|
|
8321
8332
|
useEffect(() => { closeRef.current = props.onClose })
|
|
8322
8333
|
// Layout effect: the clamp below runs before the browser paints, so the menu
|
|
@@ -8358,10 +8369,11 @@ window.__ModuleLoader__.load({
|
|
|
8358
8369
|
const cardRect = card.getBoundingClientRect()
|
|
8359
8370
|
const itemRect = event.currentTarget.getBoundingClientRect()
|
|
8360
8371
|
const bounds = props.boundsWidth === undefined ? 0 : props.boundsWidth
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8372
|
+
/* Direction only — the flush offset is CSS (`left:100%` / `right:100%`
|
|
8373
|
+
against the wrapper, whose width IS the parent card), so the seam is
|
|
8374
|
+
zero no matter how wide the submenu actually renders. */
|
|
8375
|
+
const flip = bounds > 0 && position.left + cardRect.width + 220 > bounds - 4
|
|
8376
|
+
setSub({ items: item.items, flip: flip, top: Math.max(0, itemRect.top - cardRect.top - 4) })
|
|
8365
8377
|
}
|
|
8366
8378
|
const renderItem = (item, index, inSub) => {
|
|
8367
8379
|
if (item === null) return E('div', { key: 'sep-' + index, className: 'dig-menu-sep' })
|
|
@@ -8402,7 +8414,7 @@ window.__ModuleLoader__.load({
|
|
|
8402
8414
|
E('div', { className: 'dig-menu', ref: cardRef, 'data-menu-material': 'translucent' },
|
|
8403
8415
|
E('div', { className: 'dig-menu-scroll' },
|
|
8404
8416
|
props.items.map((item, index) => renderItem(item, index, false)))),
|
|
8405
|
-
sub === null ? null : E('div', { className: 'dig-menu dig-menu-sub', 'data-menu-material': 'translucent', style: {
|
|
8417
|
+
sub === null ? null : E('div', { className: 'dig-menu dig-menu-sub', 'data-menu-material': 'translucent', style: sub.flip === true ? { right: '100%', top: sub.top + 'px' } : { left: '100%', top: sub.top + 'px' } },
|
|
8406
8418
|
E('div', { className: 'dig-menu-scroll' },
|
|
8407
8419
|
sub.items.map((item, index) => renderItem(item, index, true)))))
|
|
8408
8420
|
}
|
|
@@ -9440,7 +9452,11 @@ window.__ModuleLoader__.load({
|
|
|
9440
9452
|
const groupBy = props.groupBy === 'dir' ? 'dir' : 'flat'
|
|
9441
9453
|
const setGroupBy = props.onGroupBy
|
|
9442
9454
|
const sortKey = props.sortKey === undefined ? 'git' : props.sortKey
|
|
9443
|
-
|
|
9455
|
+
/* foldedDirs lifted too (v0.16.1): the header row lost its four buttons —
|
|
9456
|
+
everything they did lives in the ⋯ menu now, so the menu drives this
|
|
9457
|
+
state directly through props. */
|
|
9458
|
+
const foldedDirs = props.foldedDirs === undefined ? {} : props.foldedDirs
|
|
9459
|
+
const setFoldedDirs = props.onFoldedDirs
|
|
9444
9460
|
const changes = summary === null ? null : summary.changes
|
|
9445
9461
|
const conflicted = changes === null ? [] : changes.conflicted
|
|
9446
9462
|
const staged = changes === null ? [] : changes.staged
|
|
@@ -9568,14 +9584,6 @@ window.__ModuleLoader__.load({
|
|
|
9568
9584
|
let used = 0
|
|
9569
9585
|
while (winLast < changeItems.length && used < winLimit) { used += changeItems[winLast].h; winLast += 1 }
|
|
9570
9586
|
const visibleItems = changeItems.slice(winFirst, winLast)
|
|
9571
|
-
const foldAll = (value) => {
|
|
9572
|
-
const next = {}
|
|
9573
|
-
if (value === true) {
|
|
9574
|
-
const groups = [['conflicted', conflicted], ['staged', staged], ['unstaged', unstaged], ['untracked', untracked], ['ignored', ignored]]
|
|
9575
|
-
for (const pair of groups) for (const item of pair[1]) next[pair[0] + '|' + folderOf(item)] = true
|
|
9576
|
-
}
|
|
9577
|
-
setFoldedDirs(next)
|
|
9578
|
-
}
|
|
9579
9587
|
const aiConfirmDialog = aiAsk !== true ? null : E(ConfirmDialog, {
|
|
9580
9588
|
t: t,
|
|
9581
9589
|
title: t('changes.aiOverwriteTitle'),
|
|
@@ -9654,35 +9662,18 @@ window.__ModuleLoader__.load({
|
|
|
9654
9662
|
E('span', null, t('changes.title')),
|
|
9655
9663
|
E('span', { className: 'dig-count' }, String(total))),
|
|
9656
9664
|
E('span', { className: 'dig-topbar-spacer' }),
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
title: t('changes.groupBy') + ': ' + (groupBy === 'dir' ? t('changes.groupDir') : t('changes.groupFlat')),
|
|
9661
|
-
onClick: () => setGroupBy((value) => (value === 'dir' ? 'flat' : 'dir')),
|
|
9662
|
-
}, E(Icon, { name: 'folder', size: 13 })),
|
|
9663
|
-
E('button', {
|
|
9664
|
-
type: 'button', className: 'dig-icon-btn dig-icon-btn-small',
|
|
9665
|
-
title: t('changes.expandAll'), disabled: groupBy !== 'dir',
|
|
9666
|
-
onClick: () => foldAll(false),
|
|
9667
|
-
}, E(Icon, { name: 'expand', size: 13 })),
|
|
9668
|
-
E('button', {
|
|
9669
|
-
type: 'button', className: 'dig-icon-btn dig-icon-btn-small',
|
|
9670
|
-
title: t('changes.foldAll'), disabled: groupBy !== 'dir',
|
|
9671
|
-
onClick: () => foldAll(true),
|
|
9672
|
-
}, E(Icon, { name: 'collapse', size: 13 })),
|
|
9673
|
-
E('button', {
|
|
9674
|
-
type: 'button',
|
|
9675
|
-
className: 'dig-icon-btn dig-icon-btn-small' + (props.showIgnored === true ? ' dig-icon-btn-active' : ''),
|
|
9676
|
-
title: t('changes.showIgnored'),
|
|
9677
|
-
onClick: () => props.onToggleIgnored(),
|
|
9678
|
-
}, E(Icon, { name: props.showIgnored === true ? 'eye' : 'eyeOff', size: 13 })),
|
|
9665
|
+
/* The four header toggles (group-by / expand / fold / ignored) moved
|
|
9666
|
+
INTO the ⋯ menu (v0.16.1, user request): one consistent entry point
|
|
9667
|
+
instead of five small buttons, same actions, same state. */
|
|
9679
9668
|
props.onMoreMenu === undefined ? null : E('button', {
|
|
9680
9669
|
type: 'button',
|
|
9681
|
-
|
|
9670
|
+
/* Same 24px footprint and 15px glyph as the rail buttons above — the
|
|
9671
|
+
user asked for one consistent size across both rows. */
|
|
9672
|
+
className: 'dig-icon-btn',
|
|
9682
9673
|
title: t('toolbar.more'),
|
|
9683
9674
|
'data-action': 'more',
|
|
9684
9675
|
onClick: (event) => props.onMoreMenu(event),
|
|
9685
|
-
}, E(Icon, { name: 'more', size:
|
|
9676
|
+
}, E(Icon, { name: 'more', size: 16 })))
|
|
9686
9677
|
return E('div', { className: 'dig-changes' },
|
|
9687
9678
|
aiConfirmDialog,
|
|
9688
9679
|
head,
|
|
@@ -10511,6 +10502,10 @@ window.__ModuleLoader__.load({
|
|
|
10511
10502
|
fetches only when a remote exists. */
|
|
10512
10503
|
const remoteReady = branches !== null && Array.isArray(branches.remotes) && branches.remotes.length > 0
|
|
10513
10504
|
const [refreshSpinning, setRefreshSpinning] = useState(false)
|
|
10505
|
+
/* Fold state of the per-directory groups, lifted from ChangesPanel so the
|
|
10506
|
+
⋯ menu's 展开全部/折叠全部 entries drive the same map the folder
|
|
10507
|
+
headers toggle. */
|
|
10508
|
+
const [foldedDirs, setFoldedDirs] = useState({})
|
|
10514
10509
|
const refresh = useCallback(async (opts) => {
|
|
10515
10510
|
if (repoRoot === null) return
|
|
10516
10511
|
const withFetch = opts !== null && typeof opts === 'object' && opts.fetchRemote === true && remoteReady === true
|
|
@@ -11325,6 +11320,26 @@ window.__ModuleLoader__.load({
|
|
|
11325
11320
|
{ id: 'sort-path', label: t('more.sortPath'), active: sortKey === 'path', run: sort('path') },
|
|
11326
11321
|
{ id: 'sort-name', label: t('more.sortName'), active: sortKey === 'name', run: sort('name') },
|
|
11327
11322
|
{ id: 'sort-status', label: t('more.sortStatus'), active: sortKey === 'status', run: sort('status') },
|
|
11323
|
+
null,
|
|
11324
|
+
/* The old header toggles live here now (v0.16.1): fold/unfold need
|
|
11325
|
+
the directory map, which only exists when grouping is on. */
|
|
11326
|
+
{ id: 'view-expand', label: t('changes.expandAll'), disabled: groupBy !== 'dir', reason, run: () => setFoldedDirs({}) },
|
|
11327
|
+
{ id: 'view-fold', label: t('changes.foldAll'), disabled: groupBy !== 'dir', reason, run: () => {
|
|
11328
|
+
const next = {}
|
|
11329
|
+
const changes = summary === null ? null : summary.changes
|
|
11330
|
+
if (changes !== null) {
|
|
11331
|
+
const groups = [['conflicted', changes.conflicted], ['staged', changes.staged], ['unstaged', changes.unstaged], ['untracked', changes.untracked], ['ignored', changes.ignored === undefined ? [] : changes.ignored]]
|
|
11332
|
+
for (const pair of groups) {
|
|
11333
|
+
for (const item of pair[1]) {
|
|
11334
|
+
const dir = dirName(item.path)
|
|
11335
|
+
next[pair[0] + '|' + (dir === '' ? t('changes.rootDir') : dir)] = true
|
|
11336
|
+
}
|
|
11337
|
+
}
|
|
11338
|
+
}
|
|
11339
|
+
setFoldedDirs(next)
|
|
11340
|
+
} },
|
|
11341
|
+
null,
|
|
11342
|
+
{ id: 'view-ignored', label: t('changes.showIgnored'), active: showIgnored === true, run: () => setShowIgnored(showIgnored !== true) },
|
|
11328
11343
|
] },
|
|
11329
11344
|
null,
|
|
11330
11345
|
/* —— top-level sync (VS Code header row) —— */
|
|
@@ -11423,6 +11438,7 @@ window.__ModuleLoader__.load({
|
|
|
11423
11438
|
const changesPane = E(ChangesPanel, {
|
|
11424
11439
|
t: t, summary: summary, busy: busy, compact: compact, hideHeader: compact,
|
|
11425
11440
|
groupBy: groupBy, sortKey: sortKey, onGroupBy: setGroupBy,
|
|
11441
|
+
foldedDirs: foldedDirs, onFoldedDirs: setFoldedDirs,
|
|
11426
11442
|
onMoreMenu: moreMenu,
|
|
11427
11443
|
request: request, cwd: cwd, sessionId: sessionId, commitSettings: commitSettings, base: base,
|
|
11428
11444
|
showIgnored: showIgnored,
|
|
@@ -11563,7 +11579,7 @@ window.__ModuleLoader__.load({
|
|
|
11563
11579
|
title: action.disabled === true ? action.label + ' · ' + reason : action.label,
|
|
11564
11580
|
disabled: action.disabled === true,
|
|
11565
11581
|
onClick: action.run,
|
|
11566
|
-
}, E(Icon, { name: action.icon, size:
|
|
11582
|
+
}, E(Icon, { name: action.icon, size: 16 })))
|
|
11567
11583
|
if (overflow === true) {
|
|
11568
11584
|
children.push(E('button', {
|
|
11569
11585
|
key: 'more',
|
|
@@ -11597,7 +11613,7 @@ window.__ModuleLoader__.load({
|
|
|
11597
11613
|
if (target === 'page') { openSettingsPage(); return }
|
|
11598
11614
|
setRailSettings(true)
|
|
11599
11615
|
},
|
|
11600
|
-
}, E(Icon, { name: 'settings', size:
|
|
11616
|
+
}, E(Icon, { name: 'settings', size: 16 })))
|
|
11601
11617
|
return E('div', { className: vertical ? 'dig-rail' : 'dig-rail-row', ref: railHostRef }, children)
|
|
11602
11618
|
}
|
|
11603
11619
|
|
|
@@ -12242,13 +12258,15 @@ window.__ModuleLoader__.load({
|
|
|
12242
12258
|
'.dig-dialog-text{color:var(--dsw-alias-label-secondary);white-space:pre-wrap}',
|
|
12243
12259
|
'.dig-dialog-actions{display:flex;justify-content:flex-end;gap:8px}',
|
|
12244
12260
|
'.dig-dialog-actions .dig-btn-primary{margin-left:0}',
|
|
12245
|
-
/* The wrapper carries the panel-relative anchor and the outside-click ref
|
|
12246
|
-
the
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
'.dig-menu-
|
|
12261
|
+
/* The wrapper carries the panel-relative anchor and the outside-click ref,
|
|
12262
|
+
plus the ONLY percentage widths (its containing block is .dig-root, so
|
|
12263
|
+
`max-width` resolves against the panel — on the card it would resolve
|
|
12264
|
+
against the shrink-to-fit wrapper and collapse the menu, cutting labels).
|
|
12265
|
+
The submenu is a second card offset to the parent card's edge, flipping
|
|
12266
|
+
left when the panel runs out of room (see ContextMenu.openSub). */
|
|
12267
|
+
'.dig-menu-wrap{position:absolute;z-index:70;width:max-content;max-width:calc(100% - 8px)}',
|
|
12268
|
+
'.dig-menu{box-sizing:border-box;min-width:200px;max-height:calc(100% - 8px);padding:4px;border:0;border-radius:var(--dsw-radius-md,12px);background:transparent;box-shadow:var(--dsw-elevation-prominent,0 10px 28px rgba(0,0,0,.35));--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);isolation:isolate;display:flex;flex-direction:column}',
|
|
12269
|
+
'.dig-menu-sub{position:absolute;min-width:180px;max-width:300px;z-index:71}',
|
|
12252
12270
|
'.dig-menu::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-layer-1)));-webkit-backdrop-filter:var(--dsw-menu-backdrop-filter,blur(14px) saturate(1.2));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(14px) saturate(1.2));pointer-events:none}',
|
|
12253
12271
|
'.dig-menu-scroll{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;display:flex;flex-direction:column}',
|
|
12254
12272
|
'.dig-menu-item{display:flex;align-items:center;gap:8px;padding:4px 8px;border:none;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-weight:500;text-align:left;border-radius:var(--dsw-radius-sm,8px);cursor:pointer;white-space:nowrap;overflow:hidden}',
|