dsh-ide-git 0.16.0 → 0.16.1
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 +56 -49
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.1",
|
|
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.1",
|
|
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: ['M8 2v1.6', 'M8 4.8v1.6', 'M8 7.7v1.6', 'M4.6 6.4 8 9.8l3.4-3.4', 'M3 13h10'],
|
|
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'],
|
|
@@ -8314,9 +8314,9 @@ window.__ModuleLoader__.load({
|
|
|
8314
8314
|
const cardRef = useRef(null)
|
|
8315
8315
|
const closeRef = useRef(props.onClose)
|
|
8316
8316
|
const [position, setPosition] = useState({ left: props.anchor.x, top: props.anchor.y })
|
|
8317
|
-
/* The open submenu: { items,
|
|
8318
|
-
|
|
8319
|
-
|
|
8317
|
+
/* The open submenu: { items, top, flip } or null. Hover-driven — moving
|
|
8318
|
+
onto a different parent row swaps or closes it, so no timers are
|
|
8319
|
+
needed. Horizontal placement is pure CSS against the wrapper. */
|
|
8320
8320
|
const [sub, setSub] = useState(null)
|
|
8321
8321
|
useEffect(() => { closeRef.current = props.onClose })
|
|
8322
8322
|
// Layout effect: the clamp below runs before the browser paints, so the menu
|
|
@@ -8358,10 +8358,11 @@ window.__ModuleLoader__.load({
|
|
|
8358
8358
|
const cardRect = card.getBoundingClientRect()
|
|
8359
8359
|
const itemRect = event.currentTarget.getBoundingClientRect()
|
|
8360
8360
|
const bounds = props.boundsWidth === undefined ? 0 : props.boundsWidth
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8361
|
+
/* Direction only — the flush offset is CSS (`left:100%` / `right:100%`
|
|
8362
|
+
against the wrapper, whose width IS the parent card), so the seam is
|
|
8363
|
+
zero no matter how wide the submenu actually renders. */
|
|
8364
|
+
const flip = bounds > 0 && position.left + cardRect.width + 220 > bounds - 4
|
|
8365
|
+
setSub({ items: item.items, flip: flip, top: Math.max(0, itemRect.top - cardRect.top - 4) })
|
|
8365
8366
|
}
|
|
8366
8367
|
const renderItem = (item, index, inSub) => {
|
|
8367
8368
|
if (item === null) return E('div', { key: 'sep-' + index, className: 'dig-menu-sep' })
|
|
@@ -8402,7 +8403,7 @@ window.__ModuleLoader__.load({
|
|
|
8402
8403
|
E('div', { className: 'dig-menu', ref: cardRef, 'data-menu-material': 'translucent' },
|
|
8403
8404
|
E('div', { className: 'dig-menu-scroll' },
|
|
8404
8405
|
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: {
|
|
8406
|
+
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
8407
|
E('div', { className: 'dig-menu-scroll' },
|
|
8407
8408
|
sub.items.map((item, index) => renderItem(item, index, true)))))
|
|
8408
8409
|
}
|
|
@@ -9440,7 +9441,11 @@ window.__ModuleLoader__.load({
|
|
|
9440
9441
|
const groupBy = props.groupBy === 'dir' ? 'dir' : 'flat'
|
|
9441
9442
|
const setGroupBy = props.onGroupBy
|
|
9442
9443
|
const sortKey = props.sortKey === undefined ? 'git' : props.sortKey
|
|
9443
|
-
|
|
9444
|
+
/* foldedDirs lifted too (v0.16.1): the header row lost its four buttons —
|
|
9445
|
+
everything they did lives in the ⋯ menu now, so the menu drives this
|
|
9446
|
+
state directly through props. */
|
|
9447
|
+
const foldedDirs = props.foldedDirs === undefined ? {} : props.foldedDirs
|
|
9448
|
+
const setFoldedDirs = props.onFoldedDirs
|
|
9444
9449
|
const changes = summary === null ? null : summary.changes
|
|
9445
9450
|
const conflicted = changes === null ? [] : changes.conflicted
|
|
9446
9451
|
const staged = changes === null ? [] : changes.staged
|
|
@@ -9568,14 +9573,6 @@ window.__ModuleLoader__.load({
|
|
|
9568
9573
|
let used = 0
|
|
9569
9574
|
while (winLast < changeItems.length && used < winLimit) { used += changeItems[winLast].h; winLast += 1 }
|
|
9570
9575
|
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
9576
|
const aiConfirmDialog = aiAsk !== true ? null : E(ConfirmDialog, {
|
|
9580
9577
|
t: t,
|
|
9581
9578
|
title: t('changes.aiOverwriteTitle'),
|
|
@@ -9654,35 +9651,18 @@ window.__ModuleLoader__.load({
|
|
|
9654
9651
|
E('span', null, t('changes.title')),
|
|
9655
9652
|
E('span', { className: 'dig-count' }, String(total))),
|
|
9656
9653
|
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 })),
|
|
9654
|
+
/* The four header toggles (group-by / expand / fold / ignored) moved
|
|
9655
|
+
INTO the ⋯ menu (v0.16.1, user request): one consistent entry point
|
|
9656
|
+
instead of five small buttons, same actions, same state. */
|
|
9679
9657
|
props.onMoreMenu === undefined ? null : E('button', {
|
|
9680
9658
|
type: 'button',
|
|
9681
|
-
|
|
9659
|
+
/* Same 24px footprint and 15px glyph as the rail buttons above — the
|
|
9660
|
+
user asked for one consistent size across both rows. */
|
|
9661
|
+
className: 'dig-icon-btn',
|
|
9682
9662
|
title: t('toolbar.more'),
|
|
9683
9663
|
'data-action': 'more',
|
|
9684
9664
|
onClick: (event) => props.onMoreMenu(event),
|
|
9685
|
-
}, E(Icon, { name: 'more', size:
|
|
9665
|
+
}, E(Icon, { name: 'more', size: 15 })))
|
|
9686
9666
|
return E('div', { className: 'dig-changes' },
|
|
9687
9667
|
aiConfirmDialog,
|
|
9688
9668
|
head,
|
|
@@ -10511,6 +10491,10 @@ window.__ModuleLoader__.load({
|
|
|
10511
10491
|
fetches only when a remote exists. */
|
|
10512
10492
|
const remoteReady = branches !== null && Array.isArray(branches.remotes) && branches.remotes.length > 0
|
|
10513
10493
|
const [refreshSpinning, setRefreshSpinning] = useState(false)
|
|
10494
|
+
/* Fold state of the per-directory groups, lifted from ChangesPanel so the
|
|
10495
|
+
⋯ menu's 展开全部/折叠全部 entries drive the same map the folder
|
|
10496
|
+
headers toggle. */
|
|
10497
|
+
const [foldedDirs, setFoldedDirs] = useState({})
|
|
10514
10498
|
const refresh = useCallback(async (opts) => {
|
|
10515
10499
|
if (repoRoot === null) return
|
|
10516
10500
|
const withFetch = opts !== null && typeof opts === 'object' && opts.fetchRemote === true && remoteReady === true
|
|
@@ -11325,6 +11309,26 @@ window.__ModuleLoader__.load({
|
|
|
11325
11309
|
{ id: 'sort-path', label: t('more.sortPath'), active: sortKey === 'path', run: sort('path') },
|
|
11326
11310
|
{ id: 'sort-name', label: t('more.sortName'), active: sortKey === 'name', run: sort('name') },
|
|
11327
11311
|
{ id: 'sort-status', label: t('more.sortStatus'), active: sortKey === 'status', run: sort('status') },
|
|
11312
|
+
null,
|
|
11313
|
+
/* The old header toggles live here now (v0.16.1): fold/unfold need
|
|
11314
|
+
the directory map, which only exists when grouping is on. */
|
|
11315
|
+
{ id: 'view-expand', label: t('changes.expandAll'), disabled: groupBy !== 'dir', reason, run: () => setFoldedDirs({}) },
|
|
11316
|
+
{ id: 'view-fold', label: t('changes.foldAll'), disabled: groupBy !== 'dir', reason, run: () => {
|
|
11317
|
+
const next = {}
|
|
11318
|
+
const changes = summary === null ? null : summary.changes
|
|
11319
|
+
if (changes !== null) {
|
|
11320
|
+
const groups = [['conflicted', changes.conflicted], ['staged', changes.staged], ['unstaged', changes.unstaged], ['untracked', changes.untracked], ['ignored', changes.ignored === undefined ? [] : changes.ignored]]
|
|
11321
|
+
for (const pair of groups) {
|
|
11322
|
+
for (const item of pair[1]) {
|
|
11323
|
+
const dir = dirName(item.path)
|
|
11324
|
+
next[pair[0] + '|' + (dir === '' ? t('changes.rootDir') : dir)] = true
|
|
11325
|
+
}
|
|
11326
|
+
}
|
|
11327
|
+
}
|
|
11328
|
+
setFoldedDirs(next)
|
|
11329
|
+
} },
|
|
11330
|
+
null,
|
|
11331
|
+
{ id: 'view-ignored', label: t('changes.showIgnored'), active: showIgnored === true, run: () => setShowIgnored(showIgnored !== true) },
|
|
11328
11332
|
] },
|
|
11329
11333
|
null,
|
|
11330
11334
|
/* —— top-level sync (VS Code header row) —— */
|
|
@@ -11423,6 +11427,7 @@ window.__ModuleLoader__.load({
|
|
|
11423
11427
|
const changesPane = E(ChangesPanel, {
|
|
11424
11428
|
t: t, summary: summary, busy: busy, compact: compact, hideHeader: compact,
|
|
11425
11429
|
groupBy: groupBy, sortKey: sortKey, onGroupBy: setGroupBy,
|
|
11430
|
+
foldedDirs: foldedDirs, onFoldedDirs: setFoldedDirs,
|
|
11426
11431
|
onMoreMenu: moreMenu,
|
|
11427
11432
|
request: request, cwd: cwd, sessionId: sessionId, commitSettings: commitSettings, base: base,
|
|
11428
11433
|
showIgnored: showIgnored,
|
|
@@ -12242,13 +12247,15 @@ window.__ModuleLoader__.load({
|
|
|
12242
12247
|
'.dig-dialog-text{color:var(--dsw-alias-label-secondary);white-space:pre-wrap}',
|
|
12243
12248
|
'.dig-dialog-actions{display:flex;justify-content:flex-end;gap:8px}',
|
|
12244
12249
|
'.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-
|
|
12250
|
+
/* The wrapper carries the panel-relative anchor and the outside-click ref,
|
|
12251
|
+
plus the ONLY percentage widths (its containing block is .dig-root, so
|
|
12252
|
+
`max-width` resolves against the panel — on the card it would resolve
|
|
12253
|
+
against the shrink-to-fit wrapper and collapse the menu, cutting labels).
|
|
12254
|
+
The submenu is a second card offset to the parent card's edge, flipping
|
|
12255
|
+
left when the panel runs out of room (see ContextMenu.openSub). */
|
|
12256
|
+
'.dig-menu-wrap{position:absolute;z-index:70;width:max-content;max-width:calc(100% - 8px)}',
|
|
12257
|
+
'.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}',
|
|
12258
|
+
'.dig-menu-sub{position:absolute;min-width:180px;max-width:300px;z-index:71}',
|
|
12252
12259
|
'.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
12260
|
'.dig-menu-scroll{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;display:flex;flex-direction:column}',
|
|
12254
12261
|
'.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}',
|