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,10 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
IMovableSectionDestination,
|
|
5
|
+
IMovableSectionSource,
|
|
6
|
+
ISectionEntry
|
|
7
|
+
} from '@jupyterlab/apputils';
|
|
3
8
|
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
4
9
|
import { Contents } from '@jupyterlab/services';
|
|
5
|
-
import {
|
|
10
|
+
import { ITranslator } from '@jupyterlab/translation';
|
|
11
|
+
import {
|
|
12
|
+
AccordionToolbar,
|
|
13
|
+
PanelWithToolbar,
|
|
14
|
+
ReactWidget,
|
|
15
|
+
Toolbar
|
|
16
|
+
} from '@jupyterlab/ui-components';
|
|
6
17
|
import { Signal, ISignal } from '@lumino/signaling';
|
|
7
|
-
import { PanelLayout, Widget } from '@lumino/widgets';
|
|
18
|
+
import { AccordionPanel, PanelLayout, Widget } from '@lumino/widgets';
|
|
8
19
|
|
|
9
20
|
import { FileBrowserComponent } from './fileBrowser';
|
|
10
21
|
import { xtralabFileBrowserIcon } from './icons';
|
|
@@ -12,20 +23,46 @@ import { xtralabFileBrowserIcon } from './icons';
|
|
|
12
23
|
export const FILE_BROWSER_ID = 'xtralab:file-browser';
|
|
13
24
|
|
|
14
25
|
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
* Persisted by the movable-sections plugin, so it must stay stable.
|
|
27
|
+
*/
|
|
28
|
+
const TREE_SECTION_ID = 'xtralab-file-tree-section';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Context menu selectors hang off this class, so it sits on the section and
|
|
32
|
+
* keeps matching once the tree moves to another panel.
|
|
19
33
|
*/
|
|
20
34
|
const FILE_BROWSER_CSS_CLASS = 'jp-xtralab-FileBrowser';
|
|
21
35
|
|
|
36
|
+
const PANEL_CSS_CLASS = 'jp-xtralab-FileBrowserPanel';
|
|
37
|
+
|
|
22
38
|
const TOOLBAR_CSS_CLASS = 'jp-xtralab-FileBrowser-toolbar';
|
|
23
39
|
const CONTENT_CSS_CLASS = 'jp-xtralab-FileBrowser-content';
|
|
24
40
|
|
|
41
|
+
const ACCORDION_CSS_CLASS = 'jp-xtralab-FileBrowser-accordion';
|
|
42
|
+
|
|
43
|
+
const MOVABLE_SECTION_CLASS = 'jp-movable-section';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The options used to create an {@link XtralabFileBrowser}.
|
|
47
|
+
*/
|
|
25
48
|
interface IXtralabFileBrowserOptions {
|
|
49
|
+
/**
|
|
50
|
+
* The contents manager backing the tree.
|
|
51
|
+
*/
|
|
26
52
|
contentsManager: Contents.IManager;
|
|
53
|
+
/**
|
|
54
|
+
* The document manager used to open files from the tree.
|
|
55
|
+
*/
|
|
27
56
|
docManager: IDocumentManager;
|
|
57
|
+
/**
|
|
58
|
+
* Callback invoked with a file's server path when its row is
|
|
59
|
+
* double-clicked. No double-click handler is installed when absent.
|
|
60
|
+
*/
|
|
28
61
|
onOpenFile?: (serverPath: string) => void;
|
|
62
|
+
/**
|
|
63
|
+
* The application language translator.
|
|
64
|
+
*/
|
|
65
|
+
translator?: ITranslator;
|
|
29
66
|
}
|
|
30
67
|
|
|
31
68
|
/**
|
|
@@ -35,82 +72,62 @@ interface IXtralabFileBrowserOptions {
|
|
|
35
72
|
*/
|
|
36
73
|
export interface IXtralabFileBrowser {
|
|
37
74
|
/**
|
|
38
|
-
* The contents manager backing the tree
|
|
39
|
-
*
|
|
40
|
-
* drive the tree was loaded from.
|
|
75
|
+
* The contents manager backing the tree; command handlers issue rename,
|
|
76
|
+
* delete, copy, … against the same drive.
|
|
41
77
|
*/
|
|
42
78
|
readonly contentsManager: Contents.IManager;
|
|
43
79
|
|
|
44
80
|
/**
|
|
45
|
-
* The toolbar
|
|
46
|
-
* buttons after the widget is constructed.
|
|
81
|
+
* The toolbar above the tree, populated by plugin code after construction.
|
|
47
82
|
*/
|
|
48
83
|
readonly toolbar: Toolbar;
|
|
49
84
|
|
|
50
85
|
/**
|
|
51
|
-
* Canonical paths
|
|
52
|
-
* paths carry a trailing slash; file paths do not.
|
|
86
|
+
* Canonical selected paths; folder paths carry a trailing slash.
|
|
53
87
|
*/
|
|
54
88
|
readonly selectedPaths: readonly string[];
|
|
55
89
|
|
|
56
90
|
/**
|
|
57
|
-
* Emits when the tree's selection changes.
|
|
58
|
-
* `isVisible` / `isEnabled` predicate should listen so they re-evaluate.
|
|
91
|
+
* Emits when the tree's selection changes.
|
|
59
92
|
*/
|
|
60
93
|
readonly selectionChanged: ISignal<IXtralabFileBrowser, readonly string[]>;
|
|
61
94
|
|
|
62
95
|
/**
|
|
63
|
-
* Emits when {@link refresh} is called.
|
|
64
|
-
* re-fetches the directories that were previously loaded so the tree
|
|
65
|
-
* matches the contents on disk again.
|
|
96
|
+
* Emits when {@link refresh} is called.
|
|
66
97
|
*/
|
|
67
98
|
readonly refreshRequested: ISignal<IXtralabFileBrowser, void>;
|
|
68
99
|
|
|
69
100
|
/**
|
|
70
|
-
* Emits
|
|
71
|
-
*
|
|
72
|
-
* component listens and inserts the path into the model so the user
|
|
73
|
-
* sees the new item without a full refresh.
|
|
101
|
+
* Emits a newly-created canonical path so the tree inserts it without a
|
|
102
|
+
* full refresh.
|
|
74
103
|
*/
|
|
75
104
|
readonly pathAdded: ISignal<IXtralabFileBrowser, string>;
|
|
76
105
|
|
|
77
106
|
/**
|
|
78
|
-
* Emits
|
|
79
|
-
* the
|
|
80
|
-
* any unloaded ancestor directories, expands them, and selects the
|
|
81
|
-
* target. Used by the editor breadcrumbs to jump back to a file or
|
|
82
|
-
* folder shown in the breadcrumb trail.
|
|
107
|
+
* Emits a canonical path to load, expand, select, and scroll to. Used by
|
|
108
|
+
* the editor breadcrumbs.
|
|
83
109
|
*/
|
|
84
110
|
readonly revealRequested: ISignal<IXtralabFileBrowser, string>;
|
|
85
111
|
|
|
86
112
|
/**
|
|
87
|
-
* Emits when
|
|
88
|
-
*
|
|
89
|
-
* first row. Distinct from {@link revealRequested} because the
|
|
90
|
-
* workspace root has no tree row of its own — it cannot be reached
|
|
91
|
-
* by passing a path.
|
|
113
|
+
* Emits when the tree should return to the workspace root — the root has
|
|
114
|
+
* no tree row of its own, so it cannot be revealed by path.
|
|
92
115
|
*/
|
|
93
116
|
readonly rootRequested: ISignal<IXtralabFileBrowser, void>;
|
|
94
117
|
|
|
95
118
|
/**
|
|
96
|
-
* Emits when
|
|
97
|
-
* expanded folder. The React component listens and walks the loaded
|
|
98
|
-
* directories, calling `.collapse()` on each expanded one.
|
|
119
|
+
* Emits when every expanded folder should collapse.
|
|
99
120
|
*/
|
|
100
121
|
readonly collapseAllRequested: ISignal<IXtralabFileBrowser, void>;
|
|
101
122
|
|
|
102
123
|
/**
|
|
103
|
-
* Whether the filter box above the tree is shown
|
|
104
|
-
*
|
|
105
|
-
* toolbar toggle. Also forced to `true` when the tree opens a search
|
|
106
|
-
* session on its own — typing a letter while the tree has focus.
|
|
124
|
+
* Whether the filter box above the tree is shown; also forced `true` when
|
|
125
|
+
* the tree opens a search session itself (typing while it has focus).
|
|
107
126
|
*/
|
|
108
127
|
readonly fileFilterVisible: boolean;
|
|
109
128
|
|
|
110
129
|
/**
|
|
111
|
-
* Emits when {@link fileFilterVisible} changes.
|
|
112
|
-
* listens to show or hide the filter box; the toggle command listens
|
|
113
|
-
* to refresh its toggled state.
|
|
130
|
+
* Emits when {@link fileFilterVisible} changes.
|
|
114
131
|
*/
|
|
115
132
|
readonly fileFilterVisibleChanged: ISignal<IXtralabFileBrowser, boolean>;
|
|
116
133
|
|
|
@@ -120,24 +137,19 @@ export interface IXtralabFileBrowser {
|
|
|
120
137
|
refresh(): void;
|
|
121
138
|
|
|
122
139
|
/**
|
|
123
|
-
* Notify the React component that a new path was created and
|
|
124
|
-
* appear in the tree.
|
|
125
|
-
* convention: directories carry a trailing slash, files do not.
|
|
140
|
+
* Notify the React component that a new canonical path was created and
|
|
141
|
+
* should appear in the tree.
|
|
126
142
|
*/
|
|
127
143
|
notifyPathAdded(canonicalPath: string): void;
|
|
128
144
|
|
|
129
145
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* into view. `canonicalPath` follows the `@pierre/trees` convention
|
|
133
|
-
* (directories carry a trailing slash, files do not). Must be a
|
|
134
|
-
* non-empty path — use {@link scrollToRoot} for the root gesture.
|
|
146
|
+
* Reveal a non-empty canonical path: load and expand ancestors, then
|
|
147
|
+
* select and scroll to it. Use {@link scrollToRoot} for the root gesture.
|
|
135
148
|
*/
|
|
136
149
|
reveal(canonicalPath: string): void;
|
|
137
150
|
|
|
138
151
|
/**
|
|
139
|
-
*
|
|
140
|
-
* selection and scroll back to the top of the tree.
|
|
152
|
+
* Return to the workspace root: clear the selection and scroll to the top.
|
|
141
153
|
*/
|
|
142
154
|
scrollToRoot(): void;
|
|
143
155
|
|
|
@@ -155,102 +167,165 @@ export interface IXtralabFileBrowser {
|
|
|
155
167
|
* Toggle the filter box above the tree.
|
|
156
168
|
*/
|
|
157
169
|
toggleFileFilter(): void;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The DOM node of the movable "Files" section, used to locate the panel
|
|
173
|
+
* currently hosting the tree.
|
|
174
|
+
*/
|
|
175
|
+
readonly sectionNode: HTMLElement;
|
|
158
176
|
}
|
|
159
177
|
|
|
160
178
|
/**
|
|
161
|
-
* Lumino widget
|
|
162
|
-
*
|
|
163
|
-
*
|
|
179
|
+
* Lumino widget hosting the React-based `@pierre/trees` file browser. The tree
|
|
180
|
+
* and its toolbar form one movable "Files" section, and sections from other
|
|
181
|
+
* panels can be moved in below it.
|
|
164
182
|
*/
|
|
165
|
-
export class XtralabFileBrowser
|
|
183
|
+
export class XtralabFileBrowser
|
|
184
|
+
extends Widget
|
|
185
|
+
implements
|
|
186
|
+
IXtralabFileBrowser,
|
|
187
|
+
IMovableSectionSource,
|
|
188
|
+
IMovableSectionDestination
|
|
189
|
+
{
|
|
166
190
|
constructor(options: IXtralabFileBrowserOptions) {
|
|
167
191
|
super();
|
|
168
|
-
const layout = (this.layout = new PanelLayout());
|
|
192
|
+
const layout = (this._panelLayout = this.layout = new PanelLayout());
|
|
169
193
|
|
|
170
194
|
this._contentsManager = options.contentsManager;
|
|
171
195
|
this._docManager = options.docManager;
|
|
172
196
|
this._onOpenFile = options.onOpenFile;
|
|
197
|
+
this._translator = options.translator;
|
|
173
198
|
this.id = FILE_BROWSER_ID;
|
|
174
199
|
this.title.icon = xtralabFileBrowserIcon;
|
|
175
200
|
this.title.caption = 'xtralab File Browser';
|
|
176
|
-
this.addClass(
|
|
201
|
+
this.addClass(PANEL_CSS_CLASS);
|
|
177
202
|
|
|
178
203
|
this._toolbar = new Toolbar();
|
|
179
204
|
this._toolbar.addClass(TOOLBAR_CSS_CLASS);
|
|
180
205
|
this._toolbar.node.setAttribute('aria-label', 'file browser');
|
|
181
|
-
layout.addWidget(this._toolbar);
|
|
182
206
|
|
|
183
207
|
this._content = new XtralabFileTreeContent({
|
|
184
208
|
contentsManager: this._contentsManager,
|
|
185
209
|
docManager: this._docManager,
|
|
186
210
|
onOpenFile: this._onOpenFile,
|
|
211
|
+
translator: this._translator,
|
|
187
212
|
browser: this
|
|
188
213
|
});
|
|
189
214
|
this._content.addClass(CONTENT_CSS_CLASS);
|
|
190
|
-
|
|
215
|
+
|
|
216
|
+
this._section = new PanelWithToolbar({ toolbar: this._toolbar });
|
|
217
|
+
this._section.id = TREE_SECTION_ID;
|
|
218
|
+
// Only an accordion host draws this; a plain `PanelLayout` shows no title.
|
|
219
|
+
this._section.title.label = 'Files';
|
|
220
|
+
this._section.addClass(FILE_BROWSER_CSS_CLASS);
|
|
221
|
+
this._section.addWidget(this._toolbar);
|
|
222
|
+
this._section.addWidget(this._content);
|
|
223
|
+
layout.addWidget(this._section);
|
|
191
224
|
}
|
|
192
225
|
|
|
226
|
+
/**
|
|
227
|
+
* The contents manager backing the tree.
|
|
228
|
+
*/
|
|
193
229
|
get contentsManager(): Contents.IManager {
|
|
194
230
|
return this._contentsManager;
|
|
195
231
|
}
|
|
196
232
|
|
|
233
|
+
/**
|
|
234
|
+
* The toolbar above the tree.
|
|
235
|
+
*/
|
|
197
236
|
get toolbar(): Toolbar {
|
|
198
237
|
return this._toolbar;
|
|
199
238
|
}
|
|
200
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Canonical selected paths; folder paths carry a trailing slash.
|
|
242
|
+
*/
|
|
201
243
|
get selectedPaths(): readonly string[] {
|
|
202
244
|
return this._selectedPaths;
|
|
203
245
|
}
|
|
204
246
|
|
|
247
|
+
/**
|
|
248
|
+
* A signal emitted when the tree's selection changes.
|
|
249
|
+
*/
|
|
205
250
|
get selectionChanged(): ISignal<this, readonly string[]> {
|
|
206
251
|
return this._selectionChanged;
|
|
207
252
|
}
|
|
208
253
|
|
|
254
|
+
/**
|
|
255
|
+
* A signal emitted when {@link refresh} is called.
|
|
256
|
+
*/
|
|
209
257
|
get refreshRequested(): ISignal<this, void> {
|
|
210
258
|
return this._refreshRequested;
|
|
211
259
|
}
|
|
212
260
|
|
|
261
|
+
/**
|
|
262
|
+
* A signal emitting a newly-created canonical path for the tree to insert.
|
|
263
|
+
*/
|
|
213
264
|
get pathAdded(): ISignal<this, string> {
|
|
214
265
|
return this._pathAdded;
|
|
215
266
|
}
|
|
216
267
|
|
|
268
|
+
/**
|
|
269
|
+
* A signal emitting a canonical path to load, expand, select, and scroll to.
|
|
270
|
+
*/
|
|
217
271
|
get revealRequested(): ISignal<this, string> {
|
|
218
272
|
return this._revealRequested;
|
|
219
273
|
}
|
|
220
274
|
|
|
275
|
+
/**
|
|
276
|
+
* A signal emitted when the tree should return to the workspace root.
|
|
277
|
+
*/
|
|
221
278
|
get rootRequested(): ISignal<this, void> {
|
|
222
279
|
return this._rootRequested;
|
|
223
280
|
}
|
|
224
281
|
|
|
282
|
+
/**
|
|
283
|
+
* A signal emitted when every expanded folder should collapse.
|
|
284
|
+
*/
|
|
225
285
|
get collapseAllRequested(): ISignal<this, void> {
|
|
226
286
|
return this._collapseAllRequested;
|
|
227
287
|
}
|
|
228
288
|
|
|
289
|
+
/**
|
|
290
|
+
* Whether the filter box above the tree is shown.
|
|
291
|
+
*/
|
|
229
292
|
get fileFilterVisible(): boolean {
|
|
230
293
|
return this._fileFilterVisible;
|
|
231
294
|
}
|
|
232
295
|
|
|
296
|
+
/**
|
|
297
|
+
* A signal emitted when {@link fileFilterVisible} changes.
|
|
298
|
+
*/
|
|
233
299
|
get fileFilterVisibleChanged(): ISignal<this, boolean> {
|
|
234
300
|
return this._fileFilterVisibleChanged;
|
|
235
301
|
}
|
|
236
302
|
|
|
237
303
|
/**
|
|
238
|
-
* Update the cached selection
|
|
239
|
-
* underlying `@pierre/trees` model emits a selection change.
|
|
304
|
+
* Update the cached selection from the React tree.
|
|
240
305
|
*/
|
|
241
306
|
updateSelection(paths: readonly string[]): void {
|
|
242
307
|
this._selectedPaths = paths;
|
|
243
308
|
this._selectionChanged.emit(paths);
|
|
244
309
|
}
|
|
245
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Trigger a refresh of every loaded directory in the tree.
|
|
313
|
+
*/
|
|
246
314
|
refresh(): void {
|
|
247
315
|
this._refreshRequested.emit();
|
|
248
316
|
}
|
|
249
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Notify the tree that a new canonical path was created.
|
|
320
|
+
*/
|
|
250
321
|
notifyPathAdded(canonicalPath: string): void {
|
|
251
322
|
this._pathAdded.emit(canonicalPath);
|
|
252
323
|
}
|
|
253
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Reveal a non-empty canonical path in the tree; use {@link scrollToRoot}
|
|
327
|
+
* for the workspace root, which has no tree row of its own.
|
|
328
|
+
*/
|
|
254
329
|
reveal(canonicalPath: string): void {
|
|
255
330
|
if (canonicalPath.length === 0) {
|
|
256
331
|
throw new Error(
|
|
@@ -260,14 +335,23 @@ export class XtralabFileBrowser extends Widget implements IXtralabFileBrowser {
|
|
|
260
335
|
this._revealRequested.emit(canonicalPath);
|
|
261
336
|
}
|
|
262
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Return to the workspace root: clear the selection and scroll to the top.
|
|
340
|
+
*/
|
|
263
341
|
scrollToRoot(): void {
|
|
264
342
|
this._rootRequested.emit();
|
|
265
343
|
}
|
|
266
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Ask the tree to collapse every currently expanded folder.
|
|
347
|
+
*/
|
|
267
348
|
collapseAll(): void {
|
|
268
349
|
this._collapseAllRequested.emit();
|
|
269
350
|
}
|
|
270
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Show or hide the filter box above the tree.
|
|
354
|
+
*/
|
|
271
355
|
setFileFilterVisible(visible: boolean): void {
|
|
272
356
|
if (this._fileFilterVisible === visible) {
|
|
273
357
|
return;
|
|
@@ -276,13 +360,181 @@ export class XtralabFileBrowser extends Widget implements IXtralabFileBrowser {
|
|
|
276
360
|
this._fileFilterVisibleChanged.emit(visible);
|
|
277
361
|
}
|
|
278
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Toggle the filter box above the tree.
|
|
365
|
+
*/
|
|
279
366
|
toggleFileFilter(): void {
|
|
280
367
|
this.setFileFilterVisible(!this._fileFilterVisible);
|
|
281
368
|
}
|
|
282
369
|
|
|
370
|
+
/**
|
|
371
|
+
* The DOM node of the movable "Files" section.
|
|
372
|
+
*/
|
|
373
|
+
get sectionNode(): HTMLElement {
|
|
374
|
+
return this._section.node;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Whether the panel currently holds no sections, its own tree included.
|
|
379
|
+
*/
|
|
380
|
+
get isEmpty(): boolean {
|
|
381
|
+
return this._panelLayout.widgets.length === 0;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* A signal emitted when a section is added to or removed from the panel.
|
|
386
|
+
*/
|
|
387
|
+
get contentChanged(): ISignal<this, void> {
|
|
388
|
+
return this._contentChanged;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A signal emitting each section entry announced to the move plugin.
|
|
393
|
+
*/
|
|
394
|
+
get sectionAdded(): ISignal<this, ISectionEntry> {
|
|
395
|
+
return this._sectionAdded;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* The accordion hosting the sections, or `null` while the tree sits alone.
|
|
400
|
+
*/
|
|
401
|
+
get accordionPanel(): AccordionPanel | null {
|
|
402
|
+
return this._accordion;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Section widgets hosted from other panels; the tree section is excluded.
|
|
407
|
+
*/
|
|
408
|
+
get sections(): ReadonlyArray<Widget> {
|
|
409
|
+
if (!this._accordion) {
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
return this._accordion.widgets.filter(w => w !== this._section);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* The toolbar is the section's title node: it is the tree's header row at
|
|
417
|
+
* home, and an accordion host renders it inside the section title.
|
|
418
|
+
*/
|
|
419
|
+
getSections(): ReadonlyArray<ISectionEntry> {
|
|
420
|
+
return this._isSectionHome()
|
|
421
|
+
? [
|
|
422
|
+
{
|
|
423
|
+
id: TREE_SECTION_ID,
|
|
424
|
+
titleNode: this._toolbar.node,
|
|
425
|
+
widget: this._section
|
|
426
|
+
}
|
|
427
|
+
]
|
|
428
|
+
: [];
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Detach and return the tree section so the move plugin can re-host it;
|
|
433
|
+
* `null` for any other id or when the section is already away from home.
|
|
434
|
+
*/
|
|
435
|
+
removeSectionById(sectionId: string): Widget | null {
|
|
436
|
+
if (sectionId !== TREE_SECTION_ID || !this._isSectionHome()) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
this._section.parent = null;
|
|
440
|
+
if (this._accordion && this._accordion.widgets.length === 0) {
|
|
441
|
+
this._accordion.dispose();
|
|
442
|
+
this._accordion = null;
|
|
443
|
+
}
|
|
444
|
+
// Away from home the toolbar must not offer "Move to …" as well;
|
|
445
|
+
// `getSections` re-marks it on the way back.
|
|
446
|
+
this._toolbar.node.classList.remove(MOVABLE_SECTION_CLASS);
|
|
447
|
+
this._contentChanged.emit();
|
|
448
|
+
return this._section;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Re-attach the tree section after a move back to this panel.
|
|
453
|
+
*/
|
|
454
|
+
reinsertSection(widget: Widget): void {
|
|
455
|
+
if (this._accordion) {
|
|
456
|
+
this._accordion.insertWidget(0, widget);
|
|
457
|
+
} else {
|
|
458
|
+
this._panelLayout.addWidget(widget);
|
|
459
|
+
this._restoreToolbar();
|
|
460
|
+
}
|
|
461
|
+
this._contentChanged.emit();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* The move plugin reconciles persisted moves only against sections announced
|
|
466
|
+
* after `registerSource`, and this panel builds its section in the constructor.
|
|
467
|
+
*/
|
|
468
|
+
announceSections(): void {
|
|
469
|
+
for (const entry of this.getSections()) {
|
|
470
|
+
this._sectionAdded.emit(entry);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* The first hosted section moves the tree into an accordion.
|
|
476
|
+
*/
|
|
477
|
+
addSection(widget: Widget): void {
|
|
478
|
+
if (!this._accordion) {
|
|
479
|
+
const accordion = new AccordionPanel({
|
|
480
|
+
layout: AccordionToolbar.createLayout({})
|
|
481
|
+
});
|
|
482
|
+
accordion.addClass(ACCORDION_CSS_CLASS);
|
|
483
|
+
if (this._section.parent === this) {
|
|
484
|
+
accordion.addWidget(this._section);
|
|
485
|
+
}
|
|
486
|
+
accordion.addWidget(widget);
|
|
487
|
+
this._accordion = accordion;
|
|
488
|
+
this._panelLayout.addWidget(accordion);
|
|
489
|
+
} else {
|
|
490
|
+
this._accordion.addWidget(widget);
|
|
491
|
+
}
|
|
492
|
+
this._contentChanged.emit();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Remove a hosted section; the accordion is torn down once only the
|
|
497
|
+
* panel's own tree section (or nothing) remains.
|
|
498
|
+
*/
|
|
499
|
+
removeSectionWidget(widget: Widget): void {
|
|
500
|
+
if (!this._accordion || widget.parent !== this._accordion) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
widget.parent = null;
|
|
504
|
+
const remaining = this._accordion.widgets;
|
|
505
|
+
const treeOnly = remaining.length === 1 && remaining[0] === this._section;
|
|
506
|
+
if (treeOnly || remaining.length === 0) {
|
|
507
|
+
if (treeOnly) {
|
|
508
|
+
if (this._section.isHidden) {
|
|
509
|
+
this._section.show();
|
|
510
|
+
}
|
|
511
|
+
this._panelLayout.addWidget(this._section);
|
|
512
|
+
this._restoreToolbar();
|
|
513
|
+
}
|
|
514
|
+
this._accordion.dispose();
|
|
515
|
+
this._accordion = null;
|
|
516
|
+
}
|
|
517
|
+
this._contentChanged.emit();
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private _isSectionHome(): boolean {
|
|
521
|
+
const parent = this._section.parent;
|
|
522
|
+
return parent === this || (!!this._accordion && parent === this._accordion);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* An accordion host moves the toolbar node into the section title and leaves
|
|
527
|
+
* it orphaned on detach; re-parenting makes the layout attach it again.
|
|
528
|
+
*/
|
|
529
|
+
private _restoreToolbar(): void {
|
|
530
|
+
this._toolbar.parent = null;
|
|
531
|
+
this._section.insertWidget(0, this._toolbar);
|
|
532
|
+
}
|
|
533
|
+
|
|
283
534
|
private _contentsManager: Contents.IManager;
|
|
284
535
|
private _docManager: IDocumentManager;
|
|
285
536
|
private _onOpenFile: ((serverPath: string) => void) | undefined;
|
|
537
|
+
private _translator: ITranslator | undefined;
|
|
286
538
|
private _selectedPaths: readonly string[] = [];
|
|
287
539
|
private _selectionChanged = new Signal<this, readonly string[]>(this);
|
|
288
540
|
private _refreshRequested = new Signal<this, void>(this);
|
|
@@ -294,18 +546,42 @@ export class XtralabFileBrowser extends Widget implements IXtralabFileBrowser {
|
|
|
294
546
|
private _fileFilterVisibleChanged = new Signal<this, boolean>(this);
|
|
295
547
|
private _toolbar: Toolbar;
|
|
296
548
|
private _content: XtralabFileTreeContent;
|
|
549
|
+
private _section: PanelWithToolbar;
|
|
550
|
+
private _panelLayout: PanelLayout;
|
|
551
|
+
private _accordion: AccordionPanel | null = null;
|
|
552
|
+
private _contentChanged = new Signal<this, void>(this);
|
|
553
|
+
private _sectionAdded = new Signal<this, ISectionEntry>(this);
|
|
297
554
|
}
|
|
298
555
|
|
|
556
|
+
/**
|
|
557
|
+
* The options used to create an {@link XtralabFileTreeContent}.
|
|
558
|
+
*/
|
|
299
559
|
interface IFileTreeContentOptions {
|
|
560
|
+
/**
|
|
561
|
+
* The contents manager backing the tree.
|
|
562
|
+
*/
|
|
300
563
|
contentsManager: Contents.IManager;
|
|
564
|
+
/**
|
|
565
|
+
* The document manager used to open files from the tree.
|
|
566
|
+
*/
|
|
301
567
|
docManager: IDocumentManager;
|
|
568
|
+
/**
|
|
569
|
+
* Callback invoked with a file's server path when its row is
|
|
570
|
+
* double-clicked. No double-click handler is installed when absent.
|
|
571
|
+
*/
|
|
302
572
|
onOpenFile?: (serverPath: string) => void;
|
|
573
|
+
/**
|
|
574
|
+
* The application language translator.
|
|
575
|
+
*/
|
|
576
|
+
translator?: ITranslator;
|
|
577
|
+
/**
|
|
578
|
+
* The host widget the React tree reports selection and state changes to.
|
|
579
|
+
*/
|
|
303
580
|
browser: XtralabFileBrowser;
|
|
304
581
|
}
|
|
305
582
|
|
|
306
583
|
/**
|
|
307
|
-
* The React-rendered region
|
|
308
|
-
* widget below the toolbar and renders the actual tree.
|
|
584
|
+
* The React-rendered region below the toolbar that hosts the actual tree.
|
|
309
585
|
*/
|
|
310
586
|
class XtralabFileTreeContent extends ReactWidget {
|
|
311
587
|
constructor(options: IFileTreeContentOptions) {
|
|
@@ -313,12 +589,16 @@ class XtralabFileTreeContent extends ReactWidget {
|
|
|
313
589
|
this._options = options;
|
|
314
590
|
}
|
|
315
591
|
|
|
592
|
+
/**
|
|
593
|
+
* Render the file browser React component.
|
|
594
|
+
*/
|
|
316
595
|
protected render(): React.ReactElement {
|
|
317
596
|
return (
|
|
318
597
|
<FileBrowserComponent
|
|
319
598
|
contentsManager={this._options.contentsManager}
|
|
320
599
|
docManager={this._options.docManager}
|
|
321
600
|
onOpenFile={this._options.onOpenFile}
|
|
601
|
+
translator={this._options.translator}
|
|
322
602
|
widget={this._options.browser}
|
|
323
603
|
/>
|
|
324
604
|
);
|
|
@@ -25,13 +25,9 @@ function representativePath(
|
|
|
25
25
|
if (extension === undefined || extension === '') {
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
-
// Extensions are stored with a leading dot (e.g. `.py`, `.tar.gz`).
|
|
29
28
|
return `file${extension.startsWith('.') ? extension : `.${extension}`}`;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* Point a file type's icon at the tree glyph for its extension.
|
|
34
|
-
*/
|
|
35
31
|
function applyTreeIcon(fileType: DocumentRegistry.IFileType): void {
|
|
36
32
|
const path = representativePath(fileType);
|
|
37
33
|
if (path === null) {
|
|
@@ -79,9 +75,6 @@ const EXTRA_FILE_TYPE_EXTENSIONS = [
|
|
|
79
75
|
'.wasm'
|
|
80
76
|
];
|
|
81
77
|
|
|
82
|
-
/**
|
|
83
|
-
* Register icon-only file types for unclaimed source extensions.
|
|
84
|
-
*/
|
|
85
78
|
function registerExtraFileTypes(docRegistry: DocumentRegistry): void {
|
|
86
79
|
for (const extension of EXTRA_FILE_TYPE_EXTENSIONS) {
|
|
87
80
|
const icon = getSpecificTreeIcon(`file${extension}`);
|
|
@@ -125,7 +118,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
125
118
|
applyTreeIcon(fileType);
|
|
126
119
|
}
|
|
127
120
|
registerExtraFileTypes(docRegistry);
|
|
128
|
-
// Pick up file types registered after this plugin activates.
|
|
129
121
|
docRegistry.changed.connect((_, args) => {
|
|
130
122
|
if (
|
|
131
123
|
args.type === 'fileType' &&
|
|
@@ -148,8 +140,6 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
148
140
|
}
|
|
149
141
|
};
|
|
150
142
|
setIcon();
|
|
151
|
-
// Keep the tab icon right after a rename, and release the listener
|
|
152
|
-
// when the document closes.
|
|
153
143
|
widget.context.pathChanged.connect(setIcon);
|
|
154
144
|
widget.disposed.connect(() => {
|
|
155
145
|
widget.context.pathChanged.disconnect(setIcon);
|