@yiln-dsh/dsh-plugin-file-explorer 0.4.1 → 0.5.0
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/README.md +18 -27
- package/client.js +74 -278
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# @yiln-dsh/dsh-plugin-file-explorer
|
|
2
2
|
|
|
3
|
-
A DSH `dsh.bundle` that
|
|
4
|
-
|
|
3
|
+
A DSH `dsh.bundle` that contributes a workspace file explorer page to the
|
|
4
|
+
`@yiln-dsh/dsh-plugin-right-panel` host.
|
|
5
5
|
|
|
6
|
-
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **Files**
|
|
6
|
+
- Registers two independent right-panel pages: **Files** and **Git Graph**. The
|
|
7
|
+
host owns the right-column layout, navigation rail, width, and collapse
|
|
8
|
+
behavior.
|
|
9
|
+
- **Files** page: lists the active session's workspace directory, with folder
|
|
10
10
|
navigation, editable path input, parent/refresh buttons, file and folder
|
|
11
11
|
icons, and file sizes. File rows reveal view / download / delete buttons on
|
|
12
12
|
hover; delete uses a second-click confirm. Image View supports fullscreen,
|
|
13
13
|
25%-400% zoom, wheel zoom, and drag-to-pan after zooming.
|
|
14
|
-
- **Git Graph**
|
|
14
|
+
- **Git Graph** page: a vscode/le-git-graph style commit graph rendered from
|
|
15
15
|
the repository containing the current directory —
|
|
16
16
|
- colored lane graph with commit dots and merge curves (all branches or the
|
|
17
17
|
current branch, refreshable),
|
|
@@ -22,34 +22,26 @@ GUI with a workspace file explorer.
|
|
|
22
22
|
A/M/D/R status badges,
|
|
23
23
|
- click a file to open its diff patch (commit shows `git show`, working tree
|
|
24
24
|
shows `git diff HEAD`) in a dialog.
|
|
25
|
-
- The
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
the plugin captures the shell layout store actions when the root entry wires
|
|
29
|
-
them, restores the saved width right after `openDetails()`, and saves the
|
|
30
|
-
column width after every resizer drag.
|
|
31
|
-
- **Collapse to icon bar**: the collapse button matches the DSH session
|
|
32
|
-
menu's circular panel-toggle style, with the direction mirrored for the
|
|
33
|
-
right-side column. Clicking it keeps a real 56px rail in the layout with
|
|
34
|
-
**Files** and **Git Graph** icons; clicking either reopens that tab at the
|
|
35
|
-
last chosen width. The rail is not a floating overlay, and the panel state
|
|
36
|
-
is preserved.
|
|
25
|
+
- The host keeps a real 56px right-edge icon rail when collapsed. Other
|
|
26
|
+
right-panel pages can appear alongside Files and overflow into the host's
|
|
27
|
+
searchable More menu.
|
|
37
28
|
|
|
38
29
|
## Layout
|
|
39
30
|
|
|
40
31
|
| File | Content |
|
|
41
32
|
| --- | --- |
|
|
42
33
|
| `index.js` | Host half: registers exact `/ _dsh/file-explorer/*` routes backed by the Host `fs`/`subprocess` services, plus read-only git routes (`/ _dsh/file-explorer/git-log`, `git-commit`, `git-diff`, `git-status`) that run `git` with machine-readable separators and return JSON only. |
|
|
43
|
-
| `client.js` | Client half:
|
|
34
|
+
| `client.js` | Client half: registers independent keyed `right-panel.page` entries for Files and Git Graph. |
|
|
44
35
|
| `cordis.patch.yml` | Composition patch that mounts the host row — declared with `inject: [webServer]`, so it activates only after the stock webserver service (`127.0.0.1`) is up. |
|
|
45
36
|
|
|
46
37
|
## Install
|
|
47
38
|
|
|
48
|
-
The package version is `@yiln-dsh/dsh-plugin-file-explorer@0.
|
|
39
|
+
The package version is `@yiln-dsh/dsh-plugin-file-explorer@0.5.0`.
|
|
49
40
|
|
|
50
|
-
|
|
41
|
+
The right-panel package must be installed in the same `web` profile:
|
|
51
42
|
|
|
52
43
|
```bash
|
|
44
|
+
dsh plugin --profile web add file:/path/to/dsh-plugin-right-panel
|
|
53
45
|
dsh plugin --profile web add file:/path/to/dsh-plugin-file-explorer
|
|
54
46
|
```
|
|
55
47
|
|
|
@@ -61,7 +53,7 @@ pnpm pack
|
|
|
61
53
|
```
|
|
62
54
|
|
|
63
55
|
```bash
|
|
64
|
-
dsh plugin --profile web add ./yiln-dsh-dsh-plugin-file-explorer-0.
|
|
56
|
+
dsh plugin --profile web add ./yiln-dsh-dsh-plugin-file-explorer-0.5.0.tgz
|
|
65
57
|
```
|
|
66
58
|
|
|
67
59
|
### npm package
|
|
@@ -98,7 +90,6 @@ apply the new profile composition.
|
|
|
98
90
|
sentinel) and file paths against a non-option, non-control-character check.
|
|
99
91
|
- Rows have a fixed 34px height, so the hover action swap never changes the
|
|
100
92
|
row height; directories reveal a delete-only action set on hover.
|
|
101
|
-
- The browser module
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
`useSessions` hook, and its own stylesheet.
|
|
93
|
+
- The browser module registers `file-explorer.files` and
|
|
94
|
+
`file-explorer.git` into the keyed `right-panel.page` Slot and uses the
|
|
95
|
+
standard session `useSessions` hook.
|
package/client.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-plugin-file-explorer — browser bundle (static DSH client module).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* the conversation and keeps the native resizer handle.
|
|
4
|
+
* Registers the file explorer as a page in the `right-panel` host. The host
|
|
5
|
+
* owns the right layout column, width, navigation rail, and page switching.
|
|
7
6
|
*
|
|
8
|
-
* Two views behind the
|
|
7
|
+
* Two views behind the page's local tabs:
|
|
9
8
|
* - Files: directory browser (list / read / download / delete via the
|
|
10
9
|
* /_dsh/file-explorer API).
|
|
11
10
|
* - Git Graph: a vscode/git-graph style commit DAG with colored lanes, ref
|
|
@@ -20,12 +19,12 @@ window.__ModuleLoader__.load({
|
|
|
20
19
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
21
20
|
let React = require("react");
|
|
22
21
|
|
|
23
|
-
const inject = ["slots", "
|
|
22
|
+
const inject = ["slots", "rightPanel"];
|
|
24
23
|
|
|
25
24
|
function apply(ctx) {
|
|
26
25
|
const slots = ctx.get('slots')
|
|
27
|
-
const
|
|
28
|
-
if (slots === undefined) return
|
|
26
|
+
const rightPanel = ctx.get('rightPanel')
|
|
27
|
+
if (slots === undefined || rightPanel === undefined) return
|
|
29
28
|
|
|
30
29
|
const style = document.createElement("style");
|
|
31
30
|
style.id = "dsh-plugin-file-explorer-style";
|
|
@@ -77,35 +76,6 @@ window.__ModuleLoader__.load({
|
|
|
77
76
|
.dsh-fe-icon:hover {
|
|
78
77
|
background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2, #e7e5e4));
|
|
79
78
|
}
|
|
80
|
-
.dsh-fe-tabs {
|
|
81
|
-
display: flex;
|
|
82
|
-
gap: 2px;
|
|
83
|
-
padding: 8px 12px 0;
|
|
84
|
-
}
|
|
85
|
-
.dsh-fe-tab {
|
|
86
|
-
flex: 1 1 0;
|
|
87
|
-
height: 26px;
|
|
88
|
-
border: 0;
|
|
89
|
-
border-radius: 6px;
|
|
90
|
-
background: transparent;
|
|
91
|
-
color: var(--dsw-alias-label-secondary, #4b5563);
|
|
92
|
-
cursor: pointer;
|
|
93
|
-
font: inherit;
|
|
94
|
-
font-size: 12px;
|
|
95
|
-
display: inline-flex;
|
|
96
|
-
align-items: center;
|
|
97
|
-
justify-content: center;
|
|
98
|
-
gap: 6px;
|
|
99
|
-
}
|
|
100
|
-
.dsh-fe-tab:hover {
|
|
101
|
-
background: var(--dsw-alias-bg-layer-2, #e7e5e4);
|
|
102
|
-
}
|
|
103
|
-
.dsh-fe-tab-active,
|
|
104
|
-
.dsh-fe-tab-active:hover {
|
|
105
|
-
background: var(--dsw-alias-bg-layer-2, #e7e5e4);
|
|
106
|
-
color: var(--dsw-alias-label-primary, #111827);
|
|
107
|
-
font-weight: 600;
|
|
108
|
-
}
|
|
109
79
|
.dsh-fe-path {
|
|
110
80
|
min-width: 0;
|
|
111
81
|
margin: 8px 12px 0;
|
|
@@ -587,154 +557,19 @@ window.__ModuleLoader__.load({
|
|
|
587
557
|
font-size: 12px;
|
|
588
558
|
unicode-bidi: plaintext;
|
|
589
559
|
}
|
|
590
|
-
.dsh-fe-
|
|
560
|
+
.dsh-fe-page {
|
|
591
561
|
height: 100%;
|
|
592
|
-
|
|
593
|
-
box-sizing: border-box;
|
|
562
|
+
min-height: 0;
|
|
594
563
|
display: flex;
|
|
595
564
|
flex-direction: column;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
padding: 10px 6px;
|
|
565
|
+
box-sizing: border-box;
|
|
566
|
+
overflow: hidden;
|
|
599
567
|
background: var(--dsw-specific-sidebar-fill, var(--dsw-alias-bg-base, #f5f5f4));
|
|
600
|
-
|
|
601
|
-
}
|
|
602
|
-
/* While collapsed, keep a real RAIL_WIDTH column in the layout (like the left
|
|
603
|
-
sidebar's 56px rail) instead of a floating overlay. This !important rule
|
|
604
|
-
overrides React's inline grid-template-columns on the app frame; the data
|
|
605
|
-
attribute is added by applyRail() and removed on expand/unload. */
|
|
606
|
-
[data-dsh-fe-rail] {
|
|
607
|
-
grid-template-columns: var(--dsh-fe-rail-sidebar, 280px) minmax(0, 1fr) 56px !important;
|
|
608
|
-
}
|
|
609
|
-
.dsh-fe-rail-button {
|
|
610
|
-
width: 36px;
|
|
611
|
-
height: 36px;
|
|
612
|
-
border: 0;
|
|
613
|
-
border-radius: 8px;
|
|
614
|
-
background: transparent;
|
|
615
|
-
color: var(--dsw-alias-label-secondary, #4b5563);
|
|
616
|
-
cursor: pointer;
|
|
617
|
-
display: inline-flex;
|
|
618
|
-
align-items: center;
|
|
619
|
-
justify-content: center;
|
|
620
|
-
}
|
|
621
|
-
.dsh-fe-rail-button:hover {
|
|
622
|
-
background: var(--dsw-alias-bg-layer-2, #e7e5e4);
|
|
623
|
-
color: var(--dsw-alias-brand-primary, #4f46e5);
|
|
568
|
+
color: var(--dsw-alias-label-primary, #111827);
|
|
624
569
|
}
|
|
625
570
|
`;
|
|
626
571
|
document.head.append(style);
|
|
627
572
|
|
|
628
|
-
// --- details-column width persistence ---------------------------------
|
|
629
|
-
// The shell's layout store is transient: openDetails() resets the column
|
|
630
|
-
// to its 360px contract default on every mount and session switch. The
|
|
631
|
-
// bound store actions reach the LayoutController after every client
|
|
632
|
-
// module has applied (the root entry's inject hook fires on first
|
|
633
|
-
// render and again on re-register), so wrapping attachPanels on the
|
|
634
|
-
// prototype captures them reliably. setDetails then restores the last
|
|
635
|
-
// user-chosen width, and a document-level pointerup listener persists
|
|
636
|
-
// the column width after each resizer drag.
|
|
637
|
-
const WIDTH_KEY = "dsh-plugin-file-explorer.detailsWidth";
|
|
638
|
-
const WIDTH_MIN = 300; // the layout contract's clamp floor
|
|
639
|
-
let panelActions = null;
|
|
640
|
-
let savedWidth = 0;
|
|
641
|
-
try { savedWidth = Number(window.localStorage.getItem(WIDTH_KEY)) || 0 } catch (_e) { }
|
|
642
|
-
|
|
643
|
-
const findDetailsColumn = () => {
|
|
644
|
-
// The details column's own class is the reliable anchor: the drag
|
|
645
|
-
// handle's previousElementSibling is the sidebar handle or the
|
|
646
|
-
// overlay layer, never the column itself.
|
|
647
|
-
const byClass = document.querySelector('[class*="detailsCol"]')
|
|
648
|
-
if (byClass !== null) return byClass
|
|
649
|
-
const handle = document.querySelector('[data-side="details"]')
|
|
650
|
-
if (handle !== null && handle.previousElementSibling !== null) return handle.previousElementSibling
|
|
651
|
-
return null
|
|
652
|
-
}
|
|
653
|
-
const persistWidth = () => {
|
|
654
|
-
const column = findDetailsColumn()
|
|
655
|
-
if (column === null) return
|
|
656
|
-
const width = Math.round(column.getBoundingClientRect().width)
|
|
657
|
-
if (width < WIDTH_MIN) return
|
|
658
|
-
savedWidth = width
|
|
659
|
-
try { window.localStorage.setItem(WIDTH_KEY, String(width)) } catch (_e) { }
|
|
660
|
-
}
|
|
661
|
-
const onDocumentPointerUp = () => { persistWidth() }
|
|
662
|
-
document.addEventListener("pointerup", onDocumentPointerUp, true)
|
|
663
|
-
ctx.effect(() => () => document.removeEventListener("pointerup", onDocumentPointerUp, true))
|
|
664
|
-
|
|
665
|
-
if (layout !== undefined) {
|
|
666
|
-
const proto = Object.getPrototypeOf(layout)
|
|
667
|
-
if (proto !== null && typeof proto.attachPanels === "function") {
|
|
668
|
-
const originalAttach = proto.attachPanels
|
|
669
|
-
proto.attachPanels = function (actions) {
|
|
670
|
-
panelActions = actions
|
|
671
|
-
return originalAttach.call(this, actions)
|
|
672
|
-
}
|
|
673
|
-
ctx.effect(() => () => { proto.attachPanels = originalAttach })
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
const restoreWidth = () => {
|
|
677
|
-
if (savedWidth < WIDTH_MIN) return
|
|
678
|
-
if (panelActions === null || typeof panelActions.setDetails !== "function") return
|
|
679
|
-
try { panelActions.setDetails(savedWidth) } catch (_e) { }
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// --- collapsed rail as a real layout column --------------------------
|
|
683
|
-
// The layout contract gives the sidebar a 56px rail when closed but
|
|
684
|
-
// closes the details column to 0px (no rail). To collapse like the left
|
|
685
|
-
// sidebar, keep the store closed (no drag handle / border) and force the
|
|
686
|
-
// frame's third grid track to RAIL_WIDTH via an !important stylesheet
|
|
687
|
-
// rule keyed on a data attribute we own. CSS !important beats React's
|
|
688
|
-
// inline grid style, so there is no fight with React re-renders: set the
|
|
689
|
-
// attribute to collapse, remove it to expand. A MutationObserver only
|
|
690
|
-
// refreshes the sidebar-width variable (the first track) when the app
|
|
691
|
-
// re-renders the frame.
|
|
692
|
-
const RAIL_WIDTH = 56;
|
|
693
|
-
let railActive = false;
|
|
694
|
-
const frameOfDetails = () => {
|
|
695
|
-
const column = findDetailsColumn();
|
|
696
|
-
if (column === null || column.parentElement === null) return null;
|
|
697
|
-
return column.parentElement;
|
|
698
|
-
};
|
|
699
|
-
const syncRailVar = () => {
|
|
700
|
-
const frame = frameOfDetails();
|
|
701
|
-
if (frame === null) return;
|
|
702
|
-
const sideCol = frame.children.length > 0 ? frame.children[0] : null;
|
|
703
|
-
const sidebarPx = sideCol !== null ? Math.round(sideCol.getBoundingClientRect().width) : 280;
|
|
704
|
-
try { frame.style.setProperty("--dsh-fe-rail-sidebar", `${sidebarPx}px`) } catch (_e) { }
|
|
705
|
-
};
|
|
706
|
-
const applyRail = () => {
|
|
707
|
-
const frame = frameOfDetails();
|
|
708
|
-
if (frame === null) return;
|
|
709
|
-
if (railActive) {
|
|
710
|
-
frame.setAttribute("data-dsh-fe-rail", "");
|
|
711
|
-
syncRailVar();
|
|
712
|
-
} else {
|
|
713
|
-
frame.removeAttribute("data-dsh-fe-rail");
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
const releaseRail = () => {
|
|
717
|
-
railActive = false;
|
|
718
|
-
applyRail();
|
|
719
|
-
};
|
|
720
|
-
let railObserver = null;
|
|
721
|
-
if (typeof MutationObserver === "function") {
|
|
722
|
-
railObserver = new MutationObserver(() => {
|
|
723
|
-
if (railActive) syncRailVar();
|
|
724
|
-
});
|
|
725
|
-
ctx.effect(() => {
|
|
726
|
-
const frame = frameOfDetails();
|
|
727
|
-
if (frame !== null) railObserver.observe(frame, { attributes: true, attributeFilter: ["style"] });
|
|
728
|
-
return () => {
|
|
729
|
-
railObserver?.disconnect();
|
|
730
|
-
const frame = frameOfDetails();
|
|
731
|
-
if (frame !== null) frame.removeAttribute("data-dsh-fe-rail");
|
|
732
|
-
railActive = false;
|
|
733
|
-
};
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
// -----------------------------------------------------------------------
|
|
737
|
-
|
|
738
573
|
async function api(method, payload) {
|
|
739
574
|
const options = { headers: { "content-type": "application/json" } };
|
|
740
575
|
options.method = "POST";
|
|
@@ -1331,7 +1166,7 @@ window.__ModuleLoader__.load({
|
|
|
1331
1166
|
)
|
|
1332
1167
|
}
|
|
1333
1168
|
|
|
1334
|
-
function
|
|
1169
|
+
function FileExplorerPage(props) {
|
|
1335
1170
|
if (typeof props.useSessions !== 'function') return null
|
|
1336
1171
|
|
|
1337
1172
|
const sessionId = props.useSessions((state) => {
|
|
@@ -1364,23 +1199,11 @@ window.__ModuleLoader__.load({
|
|
|
1364
1199
|
const [imageDragging, setImageDragging] = React.useState(false)
|
|
1365
1200
|
const imageDrag = React.useRef(null)
|
|
1366
1201
|
const [pendingDelete, setPendingDelete] = React.useState(null)
|
|
1367
|
-
const [view, setView] = React.useState('files')
|
|
1368
|
-
const [collapsed, setCollapsed] = React.useState(false)
|
|
1369
|
-
|
|
1370
|
-
React.useEffect(() => {
|
|
1371
|
-
if (sessionId === undefined) return
|
|
1372
|
-
setCollapsed(false)
|
|
1373
|
-
if (layout !== undefined) {
|
|
1374
|
-
try { layout.openDetails() } catch (_e) { }
|
|
1375
|
-
}
|
|
1376
|
-
// Same-tick store updates batch in React, so restoring right after
|
|
1377
|
-
// openDetails() replaces the 360px default without a visible jump.
|
|
1378
|
-
restoreWidth()
|
|
1379
|
-
}, [sessionId])
|
|
1380
1202
|
|
|
1381
1203
|
React.useEffect(() => {
|
|
1382
1204
|
if (sessionId === undefined) {
|
|
1383
|
-
|
|
1205
|
+
setParentPath(null)
|
|
1206
|
+
setRequestPath('')
|
|
1384
1207
|
return
|
|
1385
1208
|
}
|
|
1386
1209
|
setParentPath(null)
|
|
@@ -1432,34 +1255,6 @@ window.__ModuleLoader__.load({
|
|
|
1432
1255
|
return aDir - bDir || a.name.localeCompare(b.name)
|
|
1433
1256
|
})
|
|
1434
1257
|
const isRoot = parentPath === null || parentPath === currentPath
|
|
1435
|
-
// Collapse into a slim icon rail that keeps a real 56px column in
|
|
1436
|
-
// the layout (like the left sidebar's rail): the details store stays
|
|
1437
|
-
// closed (no drag handle / border), and applyRail() toggles the
|
|
1438
|
-
// [data-dsh-fe-rail] attribute so the !important stylesheet rule
|
|
1439
|
-
// overrides the frame's third grid track. A MutationObserver keeps
|
|
1440
|
-
// the sidebar-width variable fresh across app re-renders.
|
|
1441
|
-
const collapse = () => {
|
|
1442
|
-
setCollapsed(true)
|
|
1443
|
-
railActive = true
|
|
1444
|
-
closePreview()
|
|
1445
|
-
setPendingDelete(null)
|
|
1446
|
-
setEditingPath(false)
|
|
1447
|
-
if (layout !== undefined) {
|
|
1448
|
-
try { layout.closeDetails() } catch (_e) { }
|
|
1449
|
-
}
|
|
1450
|
-
applyRail()
|
|
1451
|
-
}
|
|
1452
|
-
const expand = (nextView) => {
|
|
1453
|
-
releaseRail()
|
|
1454
|
-
setCollapsed(false)
|
|
1455
|
-
setView(nextView)
|
|
1456
|
-
if (layout !== undefined) {
|
|
1457
|
-
try { layout.openDetails() } catch (_e) { }
|
|
1458
|
-
}
|
|
1459
|
-
// Same-tick store updates batch in React, so restoring right after
|
|
1460
|
-
// openDetails() replaces the 360px default without a visible jump.
|
|
1461
|
-
restoreWidth()
|
|
1462
|
-
}
|
|
1463
1258
|
const reload = () => { setPendingDelete(null); setReloadTick((tick) => tick + 1) }
|
|
1464
1259
|
const startEditPath = () => {
|
|
1465
1260
|
setDraftPath(currentPath)
|
|
@@ -1678,65 +1473,13 @@ window.__ModuleLoader__.load({
|
|
|
1678
1473
|
),
|
|
1679
1474
|
)
|
|
1680
1475
|
|
|
1681
|
-
// Collapsed: a slim icon rail (file / git) that keeps a real 56px
|
|
1682
|
-
// column in the layout (the [data-dsh-fe-rail] !important grid rule;
|
|
1683
|
-
// see applyRail above), mirroring the left sidebar's collapsed rail.
|
|
1684
|
-
// Placed after every handler declaration: a collapsed render must not
|
|
1685
|
-
// return early and leave `expand` uninitialized (TDZ error on click).
|
|
1686
|
-
if (collapsed) {
|
|
1687
|
-
return React.createElement('div', {
|
|
1688
|
-
className: 'dsh-fe-rail',
|
|
1689
|
-
role: 'region',
|
|
1690
|
-
'aria-label': 'File explorer (collapsed)',
|
|
1691
|
-
},
|
|
1692
|
-
React.createElement('button', {
|
|
1693
|
-
type: 'button',
|
|
1694
|
-
className: 'dsh-fe-rail-button',
|
|
1695
|
-
onClick: () => expand('files'),
|
|
1696
|
-
title: 'Files',
|
|
1697
|
-
'aria-label': 'Open file explorer',
|
|
1698
|
-
}, svgIcon(folderIcon, 16)),
|
|
1699
|
-
React.createElement('button', {
|
|
1700
|
-
type: 'button',
|
|
1701
|
-
className: 'dsh-fe-rail-button',
|
|
1702
|
-
onClick: () => expand('git'),
|
|
1703
|
-
title: 'Git Graph',
|
|
1704
|
-
'aria-label': 'Open git graph',
|
|
1705
|
-
}, svgIcon(branchIcon, 16)),
|
|
1706
|
-
)
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
1476
|
return React.createElement(React.Fragment, null,
|
|
1710
1477
|
React.createElement('div', {
|
|
1711
|
-
className: 'dsh-fe-
|
|
1478
|
+
className: 'dsh-fe-page',
|
|
1712
1479
|
role: 'region',
|
|
1713
|
-
'aria-label': '
|
|
1480
|
+
'aria-label': 'Files',
|
|
1714
1481
|
},
|
|
1715
|
-
|
|
1716
|
-
React.createElement('button', {
|
|
1717
|
-
type: 'button',
|
|
1718
|
-
className: 'dsh-fe-icon',
|
|
1719
|
-
onClick: collapse,
|
|
1720
|
-
'aria-label': 'Collapse file explorer into icon bar',
|
|
1721
|
-
title: 'Collapse',
|
|
1722
|
-
}, collapseIcon),
|
|
1723
|
-
React.createElement('div', { className: 'dsh-fe-title' }, view === 'git' ? 'Git Graph' : 'Files'),
|
|
1724
|
-
),
|
|
1725
|
-
React.createElement('div', { className: 'dsh-fe-tabs' },
|
|
1726
|
-
React.createElement('button', {
|
|
1727
|
-
type: 'button',
|
|
1728
|
-
className: 'dsh-fe-tab' + (view === 'files' ? ' dsh-fe-tab-active' : ''),
|
|
1729
|
-
onClick: () => setView('files'),
|
|
1730
|
-
}, svgIcon(folderIcon, 13), 'Files'),
|
|
1731
|
-
React.createElement('button', {
|
|
1732
|
-
type: 'button',
|
|
1733
|
-
className: 'dsh-fe-tab' + (view === 'git' ? ' dsh-fe-tab-active' : ''),
|
|
1734
|
-
onClick: () => setView('git'),
|
|
1735
|
-
}, svgIcon(branchIcon, 13), 'Git Graph'),
|
|
1736
|
-
),
|
|
1737
|
-
view === 'git'
|
|
1738
|
-
? React.createElement(GitGraphView, { api, cwd })
|
|
1739
|
-
: filesView,
|
|
1482
|
+
filesView,
|
|
1740
1483
|
),
|
|
1741
1484
|
preview &&
|
|
1742
1485
|
React.createElement('div', {
|
|
@@ -1835,10 +1578,63 @@ window.__ModuleLoader__.load({
|
|
|
1835
1578
|
)
|
|
1836
1579
|
}
|
|
1837
1580
|
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1581
|
+
function FileExplorerGitPage(props) {
|
|
1582
|
+
if (typeof props.useSessions !== 'function') return null
|
|
1583
|
+
|
|
1584
|
+
const sessionId = props.useSessions((state) => {
|
|
1585
|
+
const current = state.current
|
|
1586
|
+
if (current === undefined) return undefined
|
|
1587
|
+
const row = state.byId[current]
|
|
1588
|
+
if (!row || row.blank === true) return undefined
|
|
1589
|
+
return current
|
|
1590
|
+
})
|
|
1591
|
+
const cwd = props.useSessions((state) => {
|
|
1592
|
+
const current = state.current
|
|
1593
|
+
if (current === undefined) return undefined
|
|
1594
|
+
const row = state.byId[current]
|
|
1595
|
+
return row ? row.cwd : undefined
|
|
1596
|
+
})
|
|
1597
|
+
|
|
1598
|
+
if (sessionId === undefined) return null
|
|
1599
|
+
return React.createElement('div', {
|
|
1600
|
+
className: 'dsh-fe-page',
|
|
1601
|
+
role: 'region',
|
|
1602
|
+
'aria-label': 'Git Graph',
|
|
1603
|
+
}, React.createElement(GitGraphView, { api, cwd }))
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
ctx.effect(() => {
|
|
1607
|
+
const disposeFilesPage = rightPanel.registerPage({
|
|
1608
|
+
id: 'file-explorer.files',
|
|
1609
|
+
title: 'Files',
|
|
1610
|
+
group: 'Workspace',
|
|
1611
|
+
order: 20,
|
|
1612
|
+
placement: 'rail',
|
|
1613
|
+
icon: (size) => svgIcon(folderIcon, size),
|
|
1614
|
+
})
|
|
1615
|
+
const disposeGitPage = rightPanel.registerPage({
|
|
1616
|
+
id: 'file-explorer.git',
|
|
1617
|
+
title: 'Git Graph',
|
|
1618
|
+
group: 'Workspace',
|
|
1619
|
+
order: 21,
|
|
1620
|
+
placement: 'rail',
|
|
1621
|
+
icon: (size) => svgIcon(branchIcon, size),
|
|
1622
|
+
})
|
|
1623
|
+
const disposeFilesSlot = slots.inject('right-panel.page', () => slots.register({
|
|
1624
|
+
name: 'right-panel.page',
|
|
1625
|
+
key: 'file-explorer.files',
|
|
1626
|
+
}, FileExplorerPage))
|
|
1627
|
+
const disposeGitSlot = slots.inject('right-panel.page', () => slots.register({
|
|
1628
|
+
name: 'right-panel.page',
|
|
1629
|
+
key: 'file-explorer.git',
|
|
1630
|
+
}, FileExplorerGitPage))
|
|
1631
|
+
return () => {
|
|
1632
|
+
disposeFilesSlot()
|
|
1633
|
+
disposeGitSlot()
|
|
1634
|
+
disposeFilesPage()
|
|
1635
|
+
disposeGitPage()
|
|
1636
|
+
}
|
|
1637
|
+
})
|
|
1842
1638
|
}
|
|
1843
1639
|
|
|
1844
1640
|
exports.apply = apply;
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yiln-dsh/dsh-plugin-file-explorer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"description": "DSH bundle plugin that
|
|
7
|
+
"description": "DSH bundle plugin that contributes a workspace file explorer page to the right-panel host.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "index.js",
|
|
10
10
|
"exports": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"client": {
|
|
20
20
|
"inject": [
|
|
21
|
+
"@yiln-dsh/dsh-plugin-right-panel",
|
|
21
22
|
"@deepseek-ai/dsh-client-runtime",
|
|
22
23
|
"@deepseek-ai/dsh-client-ui-layout",
|
|
23
24
|
"@deepseek-ai/dsh-client-ui-renderer"
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
"@deepseek-ai/cordis": ">=4.0.0",
|
|
36
37
|
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.0",
|
|
37
38
|
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.0-rc.0",
|
|
38
|
-
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.0-rc.0"
|
|
39
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.0-rc.0",
|
|
40
|
+
"@yiln-dsh/dsh-plugin-right-panel": ">=0.1.0"
|
|
39
41
|
},
|
|
40
42
|
"engines": {
|
|
41
43
|
"node": ">=22"
|