xtralab 0.14.1 → 0.15.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/README.md +10 -0
- package/lib/about/icons.d.ts +0 -5
- package/lib/about/icons.js +0 -5
- package/lib/about/index.d.ts +4 -8
- package/lib/about/index.js +6 -17
- package/lib/agentSessions.d.ts +9 -29
- package/lib/agentSessions.js +2 -7
- package/lib/askAgent/editorSelection.d.ts +20 -26
- package/lib/askAgent/editorSelection.js +11 -26
- package/lib/askAgent/icons.d.ts +2 -3
- package/lib/askAgent/icons.js +2 -3
- package/lib/askAgent/index.d.ts +4 -26
- package/lib/askAgent/index.js +54 -158
- package/lib/askAgent/popup.d.ts +12 -16
- package/lib/askAgent/popup.js +18 -37
- package/lib/askAgent/prompt.d.ts +3 -5
- package/lib/askAgent/prompt.js +6 -19
- package/lib/askAgent/queue.d.ts +11 -21
- package/lib/askAgent/queue.js +9 -19
- package/lib/askAgent/queuePanel.d.ts +13 -18
- package/lib/askAgent/queuePanel.js +15 -37
- package/lib/askAgent/targetPicker.d.ts +2 -9
- package/lib/askAgent/targetPicker.js +6 -11
- package/lib/askAgent/tokens.d.ts +32 -46
- package/lib/askAgent/tokens.js +4 -6
- package/lib/commandBar/index.d.ts +4 -13
- package/lib/commandBar/index.js +21 -39
- package/lib/customPanel/index.d.ts +7 -0
- package/lib/customPanel/index.js +89 -0
- package/lib/editorBreadcrumbs/index.d.ts +3 -6
- package/lib/editorBreadcrumbs/index.js +10 -6
- package/lib/editorBreadcrumbs/widget.d.ts +17 -4
- package/lib/editorBreadcrumbs/widget.js +11 -17
- package/lib/editorIndent/index.d.ts +4 -12
- package/lib/editorIndent/index.js +8 -23
- package/lib/fileBrowser/commands.d.ts +28 -19
- package/lib/fileBrowser/commands.js +51 -98
- package/lib/fileBrowser/contents.d.ts +14 -0
- package/lib/fileBrowser/contents.js +28 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
- package/lib/fileBrowser/dragAndDrop.js +110 -0
- package/lib/fileBrowser/fileBrowser.d.ts +21 -9
- package/lib/fileBrowser/fileBrowser.js +211 -405
- package/lib/fileBrowser/gitStatus.d.ts +4 -9
- package/lib/fileBrowser/gitStatus.js +7 -17
- package/lib/fileBrowser/gitignore.d.ts +4 -17
- package/lib/fileBrowser/gitignore.js +4 -25
- package/lib/fileBrowser/icons.d.ts +7 -17
- package/lib/fileBrowser/icons.js +25 -80
- package/lib/fileBrowser/index.js +41 -10
- package/lib/fileBrowser/widget.d.ts +170 -53
- package/lib/fileBrowser/widget.js +242 -18
- package/lib/fileTypeIcons/index.js +0 -10
- package/lib/git/api.d.ts +5 -13
- package/lib/git/api.js +10 -36
- package/lib/git/askRequest.d.ts +4 -8
- package/lib/git/askRequest.js +6 -20
- package/lib/git/commands.d.ts +40 -5
- package/lib/git/commands.js +16 -10
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffSurface.d.ts +41 -55
- package/lib/git/diffSurface.js +42 -117
- package/lib/git/diffWidget.d.ts +81 -2
- package/lib/git/diffWidget.js +62 -12
- package/lib/git/imageDiff.d.ts +5 -6
- package/lib/git/imageDiff.js +18 -48
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +3 -8
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +52 -195
- package/lib/git/tokens.d.ts +73 -31
- package/lib/git/tokens.js +2 -3
- package/lib/highlight/index.d.ts +4 -10
- package/lib/highlight/index.js +10 -41
- package/lib/index.d.ts +0 -9
- package/lib/index.js +2 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +25 -54
- package/lib/launcher/availability.d.ts +3 -9
- package/lib/launcher/availability.js +3 -9
- package/lib/launcher/commands.d.ts +7 -32
- package/lib/launcher/commands.js +14 -45
- package/lib/launcher/dashboard.d.ts +19 -24
- package/lib/launcher/dashboard.js +21 -67
- package/lib/launcher/editorRegistry.d.ts +10 -22
- package/lib/launcher/editorRegistry.js +14 -18
- package/lib/launcher/editors.d.ts +39 -45
- package/lib/launcher/editors.js +8 -34
- package/lib/launcher/icons.d.ts +0 -12
- package/lib/launcher/icons.js +14 -37
- package/lib/launcher/index.js +12 -55
- package/lib/launcher/invocation.d.ts +4 -10
- package/lib/launcher/invocation.js +7 -22
- package/lib/launcher/registry.d.ts +9 -7
- package/lib/launcher/registry.js +9 -7
- package/lib/launcher/schemaDefaults.d.ts +2 -9
- package/lib/launcher/schemaDefaults.js +37 -13
- package/lib/launcher/tokens.d.ts +10 -22
- package/lib/launcher/tokens.js +5 -8
- package/lib/menuBar/index.d.ts +3 -10
- package/lib/menuBar/index.js +11 -28
- package/lib/menus/index.d.ts +3 -9
- package/lib/menus/index.js +14 -30
- package/lib/omnibox/files.d.ts +2 -4
- package/lib/omnibox/files.js +5 -11
- package/lib/omnibox/index.d.ts +4 -14
- package/lib/omnibox/index.js +9 -27
- package/lib/omnibox/model.d.ts +38 -10
- package/lib/omnibox/model.js +15 -33
- package/lib/omnibox/recents.d.ts +15 -17
- package/lib/omnibox/recents.js +12 -17
- package/lib/omnibox/tokens.d.ts +5 -10
- package/lib/omnibox/tokens.js +2 -6
- package/lib/omnibox/widget.d.ts +11 -7
- package/lib/omnibox/widget.js +8 -16
- package/lib/searchReplace/index.d.ts +4 -20
- package/lib/searchReplace/index.js +7 -27
- package/lib/showOutput/index.d.ts +3 -12
- package/lib/showOutput/index.js +6 -22
- package/lib/sidebar/index.d.ts +4 -13
- package/lib/sidebar/index.js +73 -46
- package/lib/terminalNotifications/index.d.ts +4 -10
- package/lib/terminalNotifications/index.js +6 -20
- package/lib/terminals/agentTerminals.d.ts +12 -5
- package/lib/terminals/agentTerminals.js +25 -44
- package/lib/terminals/detection.d.ts +4 -8
- package/lib/terminals/detection.js +4 -8
- package/lib/terminals/index.d.ts +0 -33
- package/lib/terminals/index.js +24 -102
- package/lib/terminals/model.d.ts +64 -139
- package/lib/terminals/model.js +80 -220
- package/lib/terminals/tokens.d.ts +11 -22
- package/lib/terminals/tokens.js +2 -2
- package/lib/terminals/widget.d.ts +72 -38
- package/lib/terminals/widget.js +173 -73
- package/lib/topBar/icons.d.ts +3 -8
- package/lib/topBar/icons.js +3 -8
- package/lib/topBar/index.d.ts +4 -11
- package/lib/topBar/index.js +10 -38
- package/lib/walkthrough/index.d.ts +4 -9
- package/lib/walkthrough/index.js +6 -20
- package/lib/walkthrough/panel.d.ts +40 -9
- package/lib/walkthrough/panel.js +4 -10
- package/package.json +2 -2
- package/schema/launcher.json +2 -2
- package/schema/sidebar.json +47 -7
- package/src/about/icons.ts +0 -5
- package/src/about/index.tsx +6 -17
- package/src/agentSessions.ts +9 -29
- package/src/askAgent/editorSelection.ts +22 -29
- package/src/askAgent/icons.ts +2 -3
- package/src/askAgent/index.ts +54 -158
- package/src/askAgent/popup.tsx +23 -45
- package/src/askAgent/prompt.ts +6 -19
- package/src/askAgent/queue.ts +13 -24
- package/src/askAgent/queuePanel.tsx +21 -46
- package/src/askAgent/targetPicker.tsx +5 -15
- package/src/askAgent/tokens.ts +32 -46
- package/src/commandBar/index.ts +24 -39
- package/src/customPanel/index.ts +119 -0
- package/src/editorBreadcrumbs/index.ts +10 -6
- package/src/editorBreadcrumbs/widget.ts +23 -17
- package/src/editorIndent/index.ts +17 -23
- package/src/fileBrowser/commands.ts +70 -98
- package/src/fileBrowser/contents.ts +33 -0
- package/src/fileBrowser/dragAndDrop.ts +188 -0
- package/src/fileBrowser/fileBrowser.tsx +259 -440
- package/src/fileBrowser/gitStatus.ts +7 -17
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +43 -10
- package/src/fileBrowser/widget.tsx +344 -64
- package/src/fileTypeIcons/index.ts +0 -10
- package/src/git/api.ts +10 -36
- package/src/git/askRequest.ts +6 -20
- package/src/git/commands.ts +70 -10
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffSurface.tsx +71 -159
- package/src/git/diffWidget.tsx +104 -14
- package/src/git/imageDiff.tsx +45 -51
- package/src/git/index.ts +3 -8
- package/src/git/notebookDiff.tsx +211 -238
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +2 -9
- package/src/launcher/agents.ts +74 -92
- package/src/launcher/availability.ts +3 -9
- package/src/launcher/commands.ts +14 -51
- package/src/launcher/dashboard.tsx +49 -88
- package/src/launcher/editorRegistry.ts +21 -29
- package/src/launcher/editors.ts +39 -58
- package/src/launcher/icons.ts +15 -37
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- package/src/launcher/schemaDefaults.ts +43 -13
- package/src/launcher/tokens.ts +10 -22
- package/src/menuBar/index.ts +11 -28
- package/src/menus/index.ts +14 -30
- package/src/omnibox/files.ts +10 -14
- package/src/omnibox/index.ts +9 -27
- package/src/omnibox/model.ts +50 -38
- package/src/omnibox/recents.ts +17 -22
- package/src/omnibox/tokens.ts +5 -10
- package/src/omnibox/widget.tsx +14 -19
- package/src/searchReplace/index.ts +7 -27
- package/src/showOutput/index.ts +6 -22
- package/src/sidebar/index.ts +103 -52
- package/src/terminalNotifications/index.ts +42 -25
- package/src/terminals/agentTerminals.ts +25 -49
- package/src/terminals/detection.ts +4 -8
- package/src/terminals/index.ts +31 -102
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +229 -113
- package/src/topBar/icons.ts +3 -8
- package/src/topBar/index.ts +21 -44
- package/src/walkthrough/index.ts +6 -20
- package/src/walkthrough/panel.ts +40 -10
- package/style/about.css +2 -7
- package/style/askAgent.css +8 -40
- package/style/base.css +25 -73
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +6 -0
- package/style/git.css +22 -184
- package/style/highlight.css +1 -3
- package/style/index.js +1 -0
- package/style/launcher.css +6 -70
- package/style/omnibox.css +2 -14
- package/style/showOutput.css +0 -6
- package/style/sidebar.css +29 -9
- package/style/tabs.css +5 -13
- package/style/terminals.css +18 -123
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ReactWidget, Toolbar } from '@jupyterlab/ui-components';
|
|
2
|
+
import { AccordionToolbar, PanelWithToolbar, ReactWidget, Toolbar } from '@jupyterlab/ui-components';
|
|
3
3
|
import { Signal } from '@lumino/signaling';
|
|
4
|
-
import { PanelLayout, Widget } from '@lumino/widgets';
|
|
4
|
+
import { AccordionPanel, PanelLayout, Widget } from '@lumino/widgets';
|
|
5
5
|
import { FileBrowserComponent } from './fileBrowser';
|
|
6
6
|
import { xtralabFileBrowserIcon } from './icons';
|
|
7
7
|
export const FILE_BROWSER_ID = 'xtralab:file-browser';
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
* Persisted by the movable-sections plugin, so it must stay stable.
|
|
10
|
+
*/
|
|
11
|
+
const TREE_SECTION_ID = 'xtralab-file-tree-section';
|
|
12
|
+
/**
|
|
13
|
+
* Context menu selectors hang off this class, so it sits on the section and
|
|
14
|
+
* keeps matching once the tree moves to another panel.
|
|
13
15
|
*/
|
|
14
16
|
const FILE_BROWSER_CSS_CLASS = 'jp-xtralab-FileBrowser';
|
|
17
|
+
const PANEL_CSS_CLASS = 'jp-xtralab-FileBrowserPanel';
|
|
15
18
|
const TOOLBAR_CSS_CLASS = 'jp-xtralab-FileBrowser-toolbar';
|
|
16
19
|
const CONTENT_CSS_CLASS = 'jp-xtralab-FileBrowser-content';
|
|
20
|
+
const ACCORDION_CSS_CLASS = 'jp-xtralab-FileBrowser-accordion';
|
|
21
|
+
const MOVABLE_SECTION_CLASS = 'jp-movable-section';
|
|
17
22
|
/**
|
|
18
|
-
* Lumino widget
|
|
19
|
-
*
|
|
20
|
-
*
|
|
23
|
+
* Lumino widget hosting the React-based `@pierre/trees` file browser. The tree
|
|
24
|
+
* and its toolbar form one movable "Files" section, and sections from other
|
|
25
|
+
* panels can be moved in below it.
|
|
21
26
|
*/
|
|
22
27
|
export class XtralabFileBrowser extends Widget {
|
|
23
28
|
constructor(options) {
|
|
@@ -31,86 +36,148 @@ export class XtralabFileBrowser extends Widget {
|
|
|
31
36
|
this._collapseAllRequested = new Signal(this);
|
|
32
37
|
this._fileFilterVisible = false;
|
|
33
38
|
this._fileFilterVisibleChanged = new Signal(this);
|
|
34
|
-
|
|
39
|
+
this._accordion = null;
|
|
40
|
+
this._contentChanged = new Signal(this);
|
|
41
|
+
this._sectionAdded = new Signal(this);
|
|
42
|
+
const layout = (this._panelLayout = this.layout = new PanelLayout());
|
|
35
43
|
this._contentsManager = options.contentsManager;
|
|
36
44
|
this._docManager = options.docManager;
|
|
37
45
|
this._onOpenFile = options.onOpenFile;
|
|
46
|
+
this._translator = options.translator;
|
|
38
47
|
this.id = FILE_BROWSER_ID;
|
|
39
48
|
this.title.icon = xtralabFileBrowserIcon;
|
|
40
49
|
this.title.caption = 'xtralab File Browser';
|
|
41
|
-
this.addClass(
|
|
50
|
+
this.addClass(PANEL_CSS_CLASS);
|
|
42
51
|
this._toolbar = new Toolbar();
|
|
43
52
|
this._toolbar.addClass(TOOLBAR_CSS_CLASS);
|
|
44
53
|
this._toolbar.node.setAttribute('aria-label', 'file browser');
|
|
45
|
-
layout.addWidget(this._toolbar);
|
|
46
54
|
this._content = new XtralabFileTreeContent({
|
|
47
55
|
contentsManager: this._contentsManager,
|
|
48
56
|
docManager: this._docManager,
|
|
49
57
|
onOpenFile: this._onOpenFile,
|
|
58
|
+
translator: this._translator,
|
|
50
59
|
browser: this
|
|
51
60
|
});
|
|
52
61
|
this._content.addClass(CONTENT_CSS_CLASS);
|
|
53
|
-
|
|
62
|
+
this._section = new PanelWithToolbar({ toolbar: this._toolbar });
|
|
63
|
+
this._section.id = TREE_SECTION_ID;
|
|
64
|
+
// Only an accordion host draws this; a plain `PanelLayout` shows no title.
|
|
65
|
+
this._section.title.label = 'Files';
|
|
66
|
+
this._section.addClass(FILE_BROWSER_CSS_CLASS);
|
|
67
|
+
this._section.addWidget(this._toolbar);
|
|
68
|
+
this._section.addWidget(this._content);
|
|
69
|
+
layout.addWidget(this._section);
|
|
54
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The contents manager backing the tree.
|
|
73
|
+
*/
|
|
55
74
|
get contentsManager() {
|
|
56
75
|
return this._contentsManager;
|
|
57
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* The toolbar above the tree.
|
|
79
|
+
*/
|
|
58
80
|
get toolbar() {
|
|
59
81
|
return this._toolbar;
|
|
60
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Canonical selected paths; folder paths carry a trailing slash.
|
|
85
|
+
*/
|
|
61
86
|
get selectedPaths() {
|
|
62
87
|
return this._selectedPaths;
|
|
63
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* A signal emitted when the tree's selection changes.
|
|
91
|
+
*/
|
|
64
92
|
get selectionChanged() {
|
|
65
93
|
return this._selectionChanged;
|
|
66
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* A signal emitted when {@link refresh} is called.
|
|
97
|
+
*/
|
|
67
98
|
get refreshRequested() {
|
|
68
99
|
return this._refreshRequested;
|
|
69
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* A signal emitting a newly-created canonical path for the tree to insert.
|
|
103
|
+
*/
|
|
70
104
|
get pathAdded() {
|
|
71
105
|
return this._pathAdded;
|
|
72
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* A signal emitting a canonical path to load, expand, select, and scroll to.
|
|
109
|
+
*/
|
|
73
110
|
get revealRequested() {
|
|
74
111
|
return this._revealRequested;
|
|
75
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* A signal emitted when the tree should return to the workspace root.
|
|
115
|
+
*/
|
|
76
116
|
get rootRequested() {
|
|
77
117
|
return this._rootRequested;
|
|
78
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* A signal emitted when every expanded folder should collapse.
|
|
121
|
+
*/
|
|
79
122
|
get collapseAllRequested() {
|
|
80
123
|
return this._collapseAllRequested;
|
|
81
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Whether the filter box above the tree is shown.
|
|
127
|
+
*/
|
|
82
128
|
get fileFilterVisible() {
|
|
83
129
|
return this._fileFilterVisible;
|
|
84
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* A signal emitted when {@link fileFilterVisible} changes.
|
|
133
|
+
*/
|
|
85
134
|
get fileFilterVisibleChanged() {
|
|
86
135
|
return this._fileFilterVisibleChanged;
|
|
87
136
|
}
|
|
88
137
|
/**
|
|
89
|
-
* Update the cached selection
|
|
90
|
-
* underlying `@pierre/trees` model emits a selection change.
|
|
138
|
+
* Update the cached selection from the React tree.
|
|
91
139
|
*/
|
|
92
140
|
updateSelection(paths) {
|
|
93
141
|
this._selectedPaths = paths;
|
|
94
142
|
this._selectionChanged.emit(paths);
|
|
95
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Trigger a refresh of every loaded directory in the tree.
|
|
146
|
+
*/
|
|
96
147
|
refresh() {
|
|
97
148
|
this._refreshRequested.emit();
|
|
98
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Notify the tree that a new canonical path was created.
|
|
152
|
+
*/
|
|
99
153
|
notifyPathAdded(canonicalPath) {
|
|
100
154
|
this._pathAdded.emit(canonicalPath);
|
|
101
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Reveal a non-empty canonical path in the tree; use {@link scrollToRoot}
|
|
158
|
+
* for the workspace root, which has no tree row of its own.
|
|
159
|
+
*/
|
|
102
160
|
reveal(canonicalPath) {
|
|
103
161
|
if (canonicalPath.length === 0) {
|
|
104
162
|
throw new Error('XtralabFileBrowser.reveal requires a non-empty canonical path; use scrollToRoot for the workspace root.');
|
|
105
163
|
}
|
|
106
164
|
this._revealRequested.emit(canonicalPath);
|
|
107
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Return to the workspace root: clear the selection and scroll to the top.
|
|
168
|
+
*/
|
|
108
169
|
scrollToRoot() {
|
|
109
170
|
this._rootRequested.emit();
|
|
110
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Ask the tree to collapse every currently expanded folder.
|
|
174
|
+
*/
|
|
111
175
|
collapseAll() {
|
|
112
176
|
this._collapseAllRequested.emit();
|
|
113
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Show or hide the filter box above the tree.
|
|
180
|
+
*/
|
|
114
181
|
setFileFilterVisible(visible) {
|
|
115
182
|
if (this._fileFilterVisible === visible) {
|
|
116
183
|
return;
|
|
@@ -118,20 +185,177 @@ export class XtralabFileBrowser extends Widget {
|
|
|
118
185
|
this._fileFilterVisible = visible;
|
|
119
186
|
this._fileFilterVisibleChanged.emit(visible);
|
|
120
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Toggle the filter box above the tree.
|
|
190
|
+
*/
|
|
121
191
|
toggleFileFilter() {
|
|
122
192
|
this.setFileFilterVisible(!this._fileFilterVisible);
|
|
123
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* The DOM node of the movable "Files" section.
|
|
196
|
+
*/
|
|
197
|
+
get sectionNode() {
|
|
198
|
+
return this._section.node;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Whether the panel currently holds no sections, its own tree included.
|
|
202
|
+
*/
|
|
203
|
+
get isEmpty() {
|
|
204
|
+
return this._panelLayout.widgets.length === 0;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* A signal emitted when a section is added to or removed from the panel.
|
|
208
|
+
*/
|
|
209
|
+
get contentChanged() {
|
|
210
|
+
return this._contentChanged;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* A signal emitting each section entry announced to the move plugin.
|
|
214
|
+
*/
|
|
215
|
+
get sectionAdded() {
|
|
216
|
+
return this._sectionAdded;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The accordion hosting the sections, or `null` while the tree sits alone.
|
|
220
|
+
*/
|
|
221
|
+
get accordionPanel() {
|
|
222
|
+
return this._accordion;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Section widgets hosted from other panels; the tree section is excluded.
|
|
226
|
+
*/
|
|
227
|
+
get sections() {
|
|
228
|
+
if (!this._accordion) {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
return this._accordion.widgets.filter(w => w !== this._section);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The toolbar is the section's title node: it is the tree's header row at
|
|
235
|
+
* home, and an accordion host renders it inside the section title.
|
|
236
|
+
*/
|
|
237
|
+
getSections() {
|
|
238
|
+
return this._isSectionHome()
|
|
239
|
+
? [
|
|
240
|
+
{
|
|
241
|
+
id: TREE_SECTION_ID,
|
|
242
|
+
titleNode: this._toolbar.node,
|
|
243
|
+
widget: this._section
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
: [];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Detach and return the tree section so the move plugin can re-host it;
|
|
250
|
+
* `null` for any other id or when the section is already away from home.
|
|
251
|
+
*/
|
|
252
|
+
removeSectionById(sectionId) {
|
|
253
|
+
if (sectionId !== TREE_SECTION_ID || !this._isSectionHome()) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
this._section.parent = null;
|
|
257
|
+
if (this._accordion && this._accordion.widgets.length === 0) {
|
|
258
|
+
this._accordion.dispose();
|
|
259
|
+
this._accordion = null;
|
|
260
|
+
}
|
|
261
|
+
// Away from home the toolbar must not offer "Move to …" as well;
|
|
262
|
+
// `getSections` re-marks it on the way back.
|
|
263
|
+
this._toolbar.node.classList.remove(MOVABLE_SECTION_CLASS);
|
|
264
|
+
this._contentChanged.emit();
|
|
265
|
+
return this._section;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Re-attach the tree section after a move back to this panel.
|
|
269
|
+
*/
|
|
270
|
+
reinsertSection(widget) {
|
|
271
|
+
if (this._accordion) {
|
|
272
|
+
this._accordion.insertWidget(0, widget);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
this._panelLayout.addWidget(widget);
|
|
276
|
+
this._restoreToolbar();
|
|
277
|
+
}
|
|
278
|
+
this._contentChanged.emit();
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The move plugin reconciles persisted moves only against sections announced
|
|
282
|
+
* after `registerSource`, and this panel builds its section in the constructor.
|
|
283
|
+
*/
|
|
284
|
+
announceSections() {
|
|
285
|
+
for (const entry of this.getSections()) {
|
|
286
|
+
this._sectionAdded.emit(entry);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The first hosted section moves the tree into an accordion.
|
|
291
|
+
*/
|
|
292
|
+
addSection(widget) {
|
|
293
|
+
if (!this._accordion) {
|
|
294
|
+
const accordion = new AccordionPanel({
|
|
295
|
+
layout: AccordionToolbar.createLayout({})
|
|
296
|
+
});
|
|
297
|
+
accordion.addClass(ACCORDION_CSS_CLASS);
|
|
298
|
+
if (this._section.parent === this) {
|
|
299
|
+
accordion.addWidget(this._section);
|
|
300
|
+
}
|
|
301
|
+
accordion.addWidget(widget);
|
|
302
|
+
this._accordion = accordion;
|
|
303
|
+
this._panelLayout.addWidget(accordion);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
this._accordion.addWidget(widget);
|
|
307
|
+
}
|
|
308
|
+
this._contentChanged.emit();
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Remove a hosted section; the accordion is torn down once only the
|
|
312
|
+
* panel's own tree section (or nothing) remains.
|
|
313
|
+
*/
|
|
314
|
+
removeSectionWidget(widget) {
|
|
315
|
+
if (!this._accordion || widget.parent !== this._accordion) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
widget.parent = null;
|
|
319
|
+
const remaining = this._accordion.widgets;
|
|
320
|
+
const treeOnly = remaining.length === 1 && remaining[0] === this._section;
|
|
321
|
+
if (treeOnly || remaining.length === 0) {
|
|
322
|
+
if (treeOnly) {
|
|
323
|
+
if (this._section.isHidden) {
|
|
324
|
+
this._section.show();
|
|
325
|
+
}
|
|
326
|
+
this._panelLayout.addWidget(this._section);
|
|
327
|
+
this._restoreToolbar();
|
|
328
|
+
}
|
|
329
|
+
this._accordion.dispose();
|
|
330
|
+
this._accordion = null;
|
|
331
|
+
}
|
|
332
|
+
this._contentChanged.emit();
|
|
333
|
+
}
|
|
334
|
+
_isSectionHome() {
|
|
335
|
+
const parent = this._section.parent;
|
|
336
|
+
return parent === this || (!!this._accordion && parent === this._accordion);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* An accordion host moves the toolbar node into the section title and leaves
|
|
340
|
+
* it orphaned on detach; re-parenting makes the layout attach it again.
|
|
341
|
+
*/
|
|
342
|
+
_restoreToolbar() {
|
|
343
|
+
this._toolbar.parent = null;
|
|
344
|
+
this._section.insertWidget(0, this._toolbar);
|
|
345
|
+
}
|
|
124
346
|
}
|
|
125
347
|
/**
|
|
126
|
-
* The React-rendered region
|
|
127
|
-
* widget below the toolbar and renders the actual tree.
|
|
348
|
+
* The React-rendered region below the toolbar that hosts the actual tree.
|
|
128
349
|
*/
|
|
129
350
|
class XtralabFileTreeContent extends ReactWidget {
|
|
130
351
|
constructor(options) {
|
|
131
352
|
super();
|
|
132
353
|
this._options = options;
|
|
133
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Render the file browser React component.
|
|
357
|
+
*/
|
|
134
358
|
render() {
|
|
135
|
-
return (React.createElement(FileBrowserComponent, { contentsManager: this._options.contentsManager, docManager: this._options.docManager, onOpenFile: this._options.onOpenFile, widget: this._options.browser }));
|
|
359
|
+
return (React.createElement(FileBrowserComponent, { contentsManager: this._options.contentsManager, docManager: this._options.docManager, onOpenFile: this._options.onOpenFile, translator: this._options.translator, widget: this._options.browser }));
|
|
136
360
|
}
|
|
137
361
|
}
|
|
@@ -11,12 +11,8 @@ function representativePath(fileType) {
|
|
|
11
11
|
if (extension === undefined || extension === '') {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
|
-
// Extensions are stored with a leading dot (e.g. `.py`, `.tar.gz`).
|
|
15
14
|
return `file${extension.startsWith('.') ? extension : `.${extension}`}`;
|
|
16
15
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Point a file type's icon at the tree glyph for its extension.
|
|
19
|
-
*/
|
|
20
16
|
function applyTreeIcon(fileType) {
|
|
21
17
|
const path = representativePath(fileType);
|
|
22
18
|
if (path === null) {
|
|
@@ -62,9 +58,6 @@ const EXTRA_FILE_TYPE_EXTENSIONS = [
|
|
|
62
58
|
'.graphql',
|
|
63
59
|
'.wasm'
|
|
64
60
|
];
|
|
65
|
-
/**
|
|
66
|
-
* Register icon-only file types for unclaimed source extensions.
|
|
67
|
-
*/
|
|
68
61
|
function registerExtraFileTypes(docRegistry) {
|
|
69
62
|
for (const extension of EXTRA_FILE_TYPE_EXTENSIONS) {
|
|
70
63
|
const icon = getSpecificTreeIcon(`file${extension}`);
|
|
@@ -100,7 +93,6 @@ const plugin = {
|
|
|
100
93
|
applyTreeIcon(fileType);
|
|
101
94
|
}
|
|
102
95
|
registerExtraFileTypes(docRegistry);
|
|
103
|
-
// Pick up file types registered after this plugin activates.
|
|
104
96
|
docRegistry.changed.connect((_, args) => {
|
|
105
97
|
if (args.type === 'fileType' &&
|
|
106
98
|
args.change === 'added' &&
|
|
@@ -120,8 +112,6 @@ const plugin = {
|
|
|
120
112
|
}
|
|
121
113
|
};
|
|
122
114
|
setIcon();
|
|
123
|
-
// Keep the tab icon right after a rename, and release the listener
|
|
124
|
-
// when the document closes.
|
|
125
115
|
widget.context.pathChanged.connect(setIcon);
|
|
126
116
|
widget.disposed.connect(() => {
|
|
127
117
|
widget.context.pathChanged.disconnect(setIcon);
|
package/lib/git/api.d.ts
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import { GitReference, IFileChange, IGitContentResult, IGitStatusFile, IGitStatusResult } from './tokens';
|
|
2
2
|
/**
|
|
3
|
-
* Fetch `git status --porcelain` for the
|
|
4
|
-
*
|
|
5
|
-
* from the JupyterLab server's root directory.
|
|
3
|
+
* Fetch `git status --porcelain` for the repo at `repoPath` (empty string
|
|
4
|
+
* resolves from the server's root directory).
|
|
6
5
|
*/
|
|
7
6
|
export declare function status(repoPath: string): Promise<IGitStatusResult>;
|
|
8
7
|
/**
|
|
9
|
-
* Fetch a file's contents at a
|
|
10
|
-
*
|
|
11
|
-
* of {@link status}'s response).
|
|
8
|
+
* Fetch a file's contents at a git reference; `filename` is relative to the
|
|
9
|
+
* git repository root.
|
|
12
10
|
*/
|
|
13
11
|
export declare function content(repoPath: string, filename: string, reference: GitReference): Promise<IGitContentResult>;
|
|
14
12
|
/**
|
|
15
13
|
* Expand the porcelain `files` array into one entry per logical change.
|
|
16
|
-
*
|
|
17
|
-
* both staged and modified again in the worktree); callers that just want
|
|
18
|
-
* a flat list of all changes — without any staged-vs-unstaged grouping —
|
|
19
|
-
* can use this helper.
|
|
20
|
-
*
|
|
21
|
-
* Provided as a manual concat rather than `Array.prototype.flatMap` so we
|
|
22
|
-
* don't pin our `tsconfig.lib` to ES2019.
|
|
14
|
+
* Manual concat rather than `flatMap` so `tsconfig.lib` need not be ES2019.
|
|
23
15
|
*/
|
|
24
16
|
export declare function expandStatusFiles(files: IGitStatusFile[]): IFileChange[];
|
package/lib/git/api.js
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { URLExt } from '@jupyterlab/coreutils';
|
|
2
2
|
import { ServerConnection } from '@jupyterlab/services';
|
|
3
|
-
/**
|
|
4
|
-
* Root URL segment used by the `jupyterlab_git` server extension. Every
|
|
5
|
-
* endpoint hangs off this prefix; the `<repoPath>` between it and the
|
|
6
|
-
* endpoint suffix is the JupyterLab server-relative path of the git
|
|
7
|
-
* repository (URL-encoded). For an empty `repoPath` the URL collapses to
|
|
8
|
-
* `/git/<endpoint>` — a shape git's URL routing also accepts.
|
|
9
|
-
*/
|
|
10
3
|
const GIT_NAMESPACE = 'git';
|
|
11
|
-
/**
|
|
12
|
-
* Issue a `POST` against a `jupyterlab_git` endpoint that takes a `<path>`
|
|
13
|
-
* prefix (e.g. `/git/<path>/status`). The response body is decoded as JSON;
|
|
14
|
-
* non-2xx responses are surfaced via the JupyterLab `ServerConnection`
|
|
15
|
-
* machinery so callers can show their `message` field as-is.
|
|
16
|
-
*/
|
|
17
4
|
async function postWithPath(endpoint, repoPath, body) {
|
|
18
5
|
var _a, _b;
|
|
19
6
|
const settings = ServerConnection.makeSettings();
|
|
20
|
-
//
|
|
21
|
-
// between them — the server expects the path to look like a posix path.
|
|
7
|
+
// encodeParts keeps the slashes the server's posix-path routing expects.
|
|
22
8
|
const encodedPath = repoPath.length > 0 ? URLExt.encodeParts(repoPath) : '';
|
|
23
9
|
const url = URLExt.join(settings.baseUrl, GIT_NAMESPACE, encodedPath, endpoint);
|
|
24
10
|
const init = {
|
|
@@ -33,7 +19,7 @@ async function postWithPath(endpoint, repoPath, body) {
|
|
|
33
19
|
data = JSON.parse(text);
|
|
34
20
|
}
|
|
35
21
|
catch (_c) {
|
|
36
|
-
//
|
|
22
|
+
// Non-JSON bodies still surface via the ResponseError below.
|
|
37
23
|
}
|
|
38
24
|
}
|
|
39
25
|
if (!response.ok) {
|
|
@@ -43,17 +29,15 @@ async function postWithPath(endpoint, repoPath, body) {
|
|
|
43
29
|
return (data !== null && data !== void 0 ? data : {});
|
|
44
30
|
}
|
|
45
31
|
/**
|
|
46
|
-
* Fetch `git status --porcelain` for the
|
|
47
|
-
*
|
|
48
|
-
* from the JupyterLab server's root directory.
|
|
32
|
+
* Fetch `git status --porcelain` for the repo at `repoPath` (empty string
|
|
33
|
+
* resolves from the server's root directory).
|
|
49
34
|
*/
|
|
50
35
|
export async function status(repoPath) {
|
|
51
36
|
return postWithPath('status', repoPath, {});
|
|
52
37
|
}
|
|
53
38
|
/**
|
|
54
|
-
* Fetch a file's contents at a
|
|
55
|
-
*
|
|
56
|
-
* of {@link status}'s response).
|
|
39
|
+
* Fetch a file's contents at a git reference; `filename` is relative to the
|
|
40
|
+
* git repository root.
|
|
57
41
|
*/
|
|
58
42
|
export async function content(repoPath, filename, reference) {
|
|
59
43
|
return postWithPath('content', repoPath, {
|
|
@@ -63,13 +47,7 @@ export async function content(repoPath, filename, reference) {
|
|
|
63
47
|
}
|
|
64
48
|
/**
|
|
65
49
|
* Expand the porcelain `files` array into one entry per logical change.
|
|
66
|
-
*
|
|
67
|
-
* both staged and modified again in the worktree); callers that just want
|
|
68
|
-
* a flat list of all changes — without any staged-vs-unstaged grouping —
|
|
69
|
-
* can use this helper.
|
|
70
|
-
*
|
|
71
|
-
* Provided as a manual concat rather than `Array.prototype.flatMap` so we
|
|
72
|
-
* don't pin our `tsconfig.lib` to ES2019.
|
|
50
|
+
* Manual concat rather than `flatMap` so `tsconfig.lib` need not be ES2019.
|
|
73
51
|
*/
|
|
74
52
|
export function expandStatusFiles(files) {
|
|
75
53
|
const result = [];
|
|
@@ -81,16 +59,12 @@ export function expandStatusFiles(files) {
|
|
|
81
59
|
return result;
|
|
82
60
|
}
|
|
83
61
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* per non-empty side, so a "modified-staged-and-then-modified-again" file
|
|
88
|
-
* shows up twice in the panel — once under "Staged Changes" and once under
|
|
89
|
-
* "Changes" — matching the layout the user sees in VS Code.
|
|
62
|
+
* Map one porcelain entry to up to two {@link IFileChange} rows — one per
|
|
63
|
+
* non-empty index/worktree side — so a staged-then-modified-again file
|
|
64
|
+
* appears under both groups, as in VS Code.
|
|
90
65
|
*/
|
|
91
66
|
function porcelainToFileChanges(file) {
|
|
92
67
|
const result = [];
|
|
93
|
-
// Untracked files are reported with `??` and only appear under "Changes".
|
|
94
68
|
if (file.x === '?' && file.y === '?') {
|
|
95
69
|
return [
|
|
96
70
|
{
|
package/lib/git/askRequest.d.ts
CHANGED
|
@@ -4,14 +4,10 @@ import type { IAskAgentRequest } from '../askAgent/tokens';
|
|
|
4
4
|
import type { IXtralabDiffModel } from './diffWidget';
|
|
5
5
|
/**
|
|
6
6
|
* Build the ask-agent request for a line range selected in a git diff.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* whose gutter shows new-side numbers — reads from the challenger text. A
|
|
12
|
-
* gutter drag that crosses the two split columns has endpoints in different
|
|
13
|
-
* line-number spaces, so it is described textually instead of as a numeric
|
|
14
|
-
* range.
|
|
7
|
+
* `deletions` ranges index the reference text; other ranges — including
|
|
8
|
+
* sideless unified context rows, whose gutter shows new-side numbers —
|
|
9
|
+
* index the challenger. A drag across the two split columns mixes
|
|
10
|
+
* line-number spaces, so it is described textually instead of numerically.
|
|
15
11
|
*/
|
|
16
12
|
export declare function buildDiffAskRequest(options: {
|
|
17
13
|
model: IXtralabDiffModel;
|
package/lib/git/askRequest.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Git } from '@jupyterlab/git';
|
|
2
2
|
/**
|
|
3
|
-
* Agent-facing name of a diff content source
|
|
4
|
-
*
|
|
5
|
-
* side name. English on purpose — this ends up in the agent prompt, not in
|
|
6
|
-
* the UI.
|
|
3
|
+
* Agent-facing name of a diff content source. English on purpose — this
|
|
4
|
+
* ends up in the agent prompt, not in the UI.
|
|
7
5
|
*/
|
|
8
6
|
function describeSource(source, fallback) {
|
|
9
7
|
if (source === Git.Diff.SpecialRef.WORKING) {
|
|
@@ -23,9 +21,6 @@ function describeSource(source, fallback) {
|
|
|
23
21
|
function sideName(side) {
|
|
24
22
|
return side === 'deletions' ? 'old side' : 'new side';
|
|
25
23
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Extract lines `startLine`–`endLine` (1-indexed, inclusive) from `text`.
|
|
28
|
-
*/
|
|
29
24
|
function sliceLines(text, startLine, endLine) {
|
|
30
25
|
return text
|
|
31
26
|
.split('\n')
|
|
@@ -34,14 +29,10 @@ function sliceLines(text, startLine, endLine) {
|
|
|
34
29
|
}
|
|
35
30
|
/**
|
|
36
31
|
* Build the ask-agent request for a line range selected in a git diff.
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* whose gutter shows new-side numbers — reads from the challenger text. A
|
|
42
|
-
* gutter drag that crosses the two split columns has endpoints in different
|
|
43
|
-
* line-number spaces, so it is described textually instead of as a numeric
|
|
44
|
-
* range.
|
|
32
|
+
* `deletions` ranges index the reference text; other ranges — including
|
|
33
|
+
* sideless unified context rows, whose gutter shows new-side numbers —
|
|
34
|
+
* index the challenger. A drag across the two split columns mixes
|
|
35
|
+
* line-number spaces, so it is described textually instead of numerically.
|
|
45
36
|
*/
|
|
46
37
|
export function buildDiffAskRequest(options) {
|
|
47
38
|
var _a, _b, _c;
|
|
@@ -75,14 +66,9 @@ export function buildDiffAskRequest(options) {
|
|
|
75
66
|
...base,
|
|
76
67
|
startLine,
|
|
77
68
|
endLine,
|
|
78
|
-
// Only new-side lines of a working-tree diff index the file on disk;
|
|
79
|
-
// old-side and historical line numbers must not be used to highlight
|
|
80
|
-
// the working file.
|
|
81
69
|
linesInWorkingFile: !isOld && model.challenger.source === Git.Diff.SpecialRef.WORKING,
|
|
82
70
|
text: sliceLines(isOld ? oldText : newText, startLine, endLine),
|
|
83
71
|
location: `the ${sideName(startSide)} (${ref}) of the current git diff`,
|
|
84
|
-
// New-side lines read as the file's current content, so only old-side
|
|
85
|
-
// ranges need a clarifying tag in the popup header.
|
|
86
72
|
...(isOld ? { note: trans.__('old version') } : {})
|
|
87
73
|
},
|
|
88
74
|
anchor
|