@jupyterlab/filebrowser 4.0.0-alpha.8 → 4.0.0-beta.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/lib/browser.d.ts +11 -6
- package/lib/browser.js +30 -35
- package/lib/browser.js.map +1 -1
- package/lib/crumbs.d.ts +1 -0
- package/lib/crumbs.js +41 -10
- package/lib/crumbs.js.map +1 -1
- package/lib/listing.d.ts +54 -12
- package/lib/listing.js +296 -56
- package/lib/listing.js.map +1 -1
- package/lib/model.d.ts +19 -9
- package/lib/model.js +28 -11
- package/lib/model.js.map +1 -1
- package/lib/opendialog.d.ts +2 -1
- package/lib/opendialog.js +13 -8
- package/lib/opendialog.js.map +1 -1
- package/lib/tokens.d.ts +16 -8
- package/lib/tokens.js +9 -1
- package/lib/tokens.js.map +1 -1
- package/lib/upload.d.ts +4 -0
- package/lib/upload.js +1 -0
- package/lib/upload.js.map +1 -1
- package/lib/uploadstatus.js +4 -4
- package/lib/uploadstatus.js.map +1 -1
- package/package.json +28 -28
- package/src/browser.ts +444 -0
- package/src/crumbs.ts +441 -0
- package/src/index.ts +15 -0
- package/src/listing.ts +2609 -0
- package/src/model.ts +832 -0
- package/src/opendialog.ts +257 -0
- package/src/tokens.ts +122 -0
- package/src/upload.ts +119 -0
- package/src/uploadstatus.tsx +259 -0
- package/style/base.css +57 -31
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
6
|
+
import { IChangedArgs } from '@jupyterlab/coreutils';
|
|
7
|
+
import { GroupItem, ProgressBar, TextItem } from '@jupyterlab/statusbar';
|
|
8
|
+
import {
|
|
9
|
+
ITranslator,
|
|
10
|
+
nullTranslator,
|
|
11
|
+
TranslationBundle
|
|
12
|
+
} from '@jupyterlab/translation';
|
|
13
|
+
import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components';
|
|
14
|
+
import { ArrayExt } from '@lumino/algorithm';
|
|
15
|
+
import React from 'react';
|
|
16
|
+
import { FileBrowser, FileBrowserModel, IUploadModel } from '.';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Half-spacing between items in the overall status item.
|
|
20
|
+
*/
|
|
21
|
+
const HALF_SPACING = 4;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A pure function component for a FileUpload status item.
|
|
25
|
+
*
|
|
26
|
+
* @param props: the props for the component.
|
|
27
|
+
*
|
|
28
|
+
* @returns a tsx component for the file upload status.
|
|
29
|
+
*/
|
|
30
|
+
function FileUploadComponent(
|
|
31
|
+
props: FileUploadComponent.IProps
|
|
32
|
+
): React.ReactElement<FileUploadComponent.IProps> {
|
|
33
|
+
const translator = props.translator || nullTranslator;
|
|
34
|
+
const trans = translator.load('jupyterlab');
|
|
35
|
+
return (
|
|
36
|
+
<GroupItem spacing={HALF_SPACING}>
|
|
37
|
+
<TextItem source={trans.__('Uploading…')} />
|
|
38
|
+
<ProgressBar percentage={props.upload} />
|
|
39
|
+
</GroupItem>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A namespace for FileUploadComponent statics.
|
|
45
|
+
*/
|
|
46
|
+
namespace FileUploadComponent {
|
|
47
|
+
/**
|
|
48
|
+
* The props for the FileUploadComponent.
|
|
49
|
+
*/
|
|
50
|
+
export interface IProps {
|
|
51
|
+
/**
|
|
52
|
+
* The current upload percentage, from 0 to 100.
|
|
53
|
+
*/
|
|
54
|
+
upload: number;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The language translator.
|
|
58
|
+
*/
|
|
59
|
+
translator?: ITranslator;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The time for which to show the "Complete!" message after uploading.
|
|
65
|
+
*/
|
|
66
|
+
const UPLOAD_COMPLETE_MESSAGE_MILLIS: number = 2000;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Status bar item to display file upload progress.
|
|
70
|
+
*/
|
|
71
|
+
export class FileUploadStatus extends VDomRenderer<FileUploadStatus.Model> {
|
|
72
|
+
/**
|
|
73
|
+
* Construct a new FileUpload status item.
|
|
74
|
+
*/
|
|
75
|
+
constructor(opts: FileUploadStatus.IOptions) {
|
|
76
|
+
super(
|
|
77
|
+
new FileUploadStatus.Model(
|
|
78
|
+
opts.tracker.currentWidget && opts.tracker.currentWidget.model
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
this.translator = opts.translator || nullTranslator;
|
|
82
|
+
this._trans = this.translator.load('jupyterlab');
|
|
83
|
+
this._tracker = opts.tracker;
|
|
84
|
+
this._tracker.currentChanged.connect(this._onBrowserChange);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Render the FileUpload status.
|
|
89
|
+
*/
|
|
90
|
+
render(): JSX.Element {
|
|
91
|
+
const uploadPaths = this.model!.items;
|
|
92
|
+
if (uploadPaths.length > 0) {
|
|
93
|
+
const item = this.model!.items[0];
|
|
94
|
+
|
|
95
|
+
if (item.complete) {
|
|
96
|
+
return <TextItem source={this._trans.__('Complete!')} />;
|
|
97
|
+
} else {
|
|
98
|
+
return (
|
|
99
|
+
<FileUploadComponent
|
|
100
|
+
upload={this.model!.items[0].progress}
|
|
101
|
+
translator={this.translator}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
return <FileUploadComponent upload={100} translator={this.translator} />;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
dispose(): void {
|
|
111
|
+
super.dispose();
|
|
112
|
+
this._tracker.currentChanged.disconnect(this._onBrowserChange);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private _onBrowserChange = (
|
|
116
|
+
tracker: WidgetTracker<FileBrowser>,
|
|
117
|
+
browser: FileBrowser | null
|
|
118
|
+
) => {
|
|
119
|
+
if (browser === null) {
|
|
120
|
+
this.model!.browserModel = null;
|
|
121
|
+
} else {
|
|
122
|
+
this.model!.browserModel = browser.model;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
private readonly translator: ITranslator;
|
|
127
|
+
private _trans: TranslationBundle;
|
|
128
|
+
private _tracker: WidgetTracker<FileBrowser>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A namespace for FileUpload class statics.
|
|
133
|
+
*/
|
|
134
|
+
export namespace FileUploadStatus {
|
|
135
|
+
/**
|
|
136
|
+
* The VDomModel for the FileUpload renderer.
|
|
137
|
+
*/
|
|
138
|
+
export class Model extends VDomModel {
|
|
139
|
+
/**
|
|
140
|
+
* Construct a new model.
|
|
141
|
+
*/
|
|
142
|
+
constructor(browserModel: FileBrowserModel | null) {
|
|
143
|
+
super();
|
|
144
|
+
this.browserModel = browserModel;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The currently uploading items.
|
|
149
|
+
*/
|
|
150
|
+
get items(): IFileUploadItem[] {
|
|
151
|
+
return this._items;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The current file browser model.
|
|
156
|
+
*/
|
|
157
|
+
get browserModel(): FileBrowserModel | null {
|
|
158
|
+
return this._browserModel;
|
|
159
|
+
}
|
|
160
|
+
set browserModel(browserModel: FileBrowserModel | null) {
|
|
161
|
+
const oldBrowserModel = this._browserModel;
|
|
162
|
+
if (oldBrowserModel) {
|
|
163
|
+
oldBrowserModel.uploadChanged.disconnect(this._uploadChanged);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this._browserModel = browserModel;
|
|
167
|
+
this._items = [];
|
|
168
|
+
|
|
169
|
+
if (this._browserModel !== null) {
|
|
170
|
+
this._browserModel.uploadChanged.connect(this._uploadChanged);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this.stateChanged.emit(void 0);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Handle an uploadChanged event in the filebrowser model.
|
|
178
|
+
*/
|
|
179
|
+
private _uploadChanged = (
|
|
180
|
+
browse: FileBrowserModel,
|
|
181
|
+
uploads: IChangedArgs<IUploadModel>
|
|
182
|
+
) => {
|
|
183
|
+
if (uploads.name === 'start') {
|
|
184
|
+
this._items.push({
|
|
185
|
+
path: uploads.newValue.path,
|
|
186
|
+
progress: uploads.newValue.progress * 100,
|
|
187
|
+
complete: false
|
|
188
|
+
});
|
|
189
|
+
} else if (uploads.name === 'update') {
|
|
190
|
+
const idx = ArrayExt.findFirstIndex(
|
|
191
|
+
this._items,
|
|
192
|
+
val => val.path === uploads.oldValue.path
|
|
193
|
+
);
|
|
194
|
+
if (idx !== -1) {
|
|
195
|
+
this._items[idx].progress = uploads.newValue.progress * 100;
|
|
196
|
+
}
|
|
197
|
+
} else if (uploads.name === 'finish') {
|
|
198
|
+
const finishedItem = ArrayExt.findFirstValue(
|
|
199
|
+
this._items,
|
|
200
|
+
val => val.path === uploads.oldValue.path
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
if (finishedItem) {
|
|
204
|
+
finishedItem.complete = true;
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
ArrayExt.removeFirstOf(this._items, finishedItem);
|
|
207
|
+
this.stateChanged.emit(void 0);
|
|
208
|
+
}, UPLOAD_COMPLETE_MESSAGE_MILLIS);
|
|
209
|
+
}
|
|
210
|
+
} else if (uploads.name === 'failure') {
|
|
211
|
+
ArrayExt.removeFirstWhere(
|
|
212
|
+
this._items,
|
|
213
|
+
val => val.path === uploads.newValue.path
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this.stateChanged.emit(void 0);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
private _items: Array<IFileUploadItem> = [];
|
|
221
|
+
private _browserModel: FileBrowserModel | null = null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Options for creating the upload status item.
|
|
226
|
+
*/
|
|
227
|
+
export interface IOptions {
|
|
228
|
+
/**
|
|
229
|
+
* The application file browser tracker.
|
|
230
|
+
*/
|
|
231
|
+
readonly tracker: WidgetTracker<FileBrowser>;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* The translation language bundle.
|
|
235
|
+
*/
|
|
236
|
+
readonly translator?: ITranslator;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* The interface for an item that is being uploaded to
|
|
242
|
+
* the file system.
|
|
243
|
+
*/
|
|
244
|
+
interface IFileUploadItem {
|
|
245
|
+
/**
|
|
246
|
+
* The path on the filesystem that is being uploaded to.
|
|
247
|
+
*/
|
|
248
|
+
path: string;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The upload progress fraction.
|
|
252
|
+
*/
|
|
253
|
+
progress: number;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Whether the upload is complete.
|
|
257
|
+
*/
|
|
258
|
+
complete: boolean;
|
|
259
|
+
}
|
package/style/base.css
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.jp-FileBrowser-toolbar.jp-Toolbar {
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
row-gap: 12px;
|
|
26
28
|
border-bottom: none;
|
|
27
29
|
height: auto;
|
|
28
30
|
margin: 8px 12px 0;
|
|
@@ -70,29 +72,14 @@
|
|
|
70
72
|
flex: 0 0 auto;
|
|
71
73
|
padding-left: 0;
|
|
72
74
|
padding-right: 2px;
|
|
75
|
+
align-items: center;
|
|
76
|
+
height: unset;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
.jp-FileBrowser-toolbar > .jp-Toolbar-item .jp-ToolbarButtonComponent {
|
|
76
80
|
width: 40px;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
.jp-FileBrowser-toolbar
|
|
80
|
-
.jp-ToolbarButtonComponent[data-command='filebrowser:create-main-launcher'] {
|
|
81
|
-
width: 72px;
|
|
82
|
-
background: var(--jp-brand-color1);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.jp-FileBrowser-toolbar
|
|
86
|
-
.jp-ToolbarButtonComponent[data-command='filebrowser:create-main-launcher']:focus-visible {
|
|
87
|
-
background-color: var(--jp-accept-color-active, var(--jp-brand-color0));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.jp-FileBrowser-toolbar
|
|
91
|
-
.jp-ToolbarButtonComponent[data-command='filebrowser:create-main-launcher']
|
|
92
|
-
.jp-icon3 {
|
|
93
|
-
fill: var(--jp-layout-color1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
83
|
/*-----------------------------------------------------------------------------
|
|
97
84
|
| Other styles
|
|
98
85
|
|----------------------------------------------------------------------------*/
|
|
@@ -109,10 +96,8 @@
|
|
|
109
96
|
display: none;
|
|
110
97
|
}
|
|
111
98
|
|
|
112
|
-
.jp-
|
|
113
|
-
|
|
114
|
-
flex: 0 0 auto;
|
|
115
|
-
margin: 8px 12px 0;
|
|
99
|
+
.jp-FileSize-hidden {
|
|
100
|
+
display: none;
|
|
116
101
|
}
|
|
117
102
|
|
|
118
103
|
.jp-FileBrowser .lm-AccordionPanel > h3:first-child {
|
|
@@ -131,13 +116,15 @@
|
|
|
131
116
|
}
|
|
132
117
|
|
|
133
118
|
.jp-DirListing:focus-visible {
|
|
134
|
-
|
|
119
|
+
outline: 1px solid var(--jp-brand-color1);
|
|
120
|
+
outline-offset: -2px;
|
|
135
121
|
}
|
|
136
122
|
|
|
137
123
|
.jp-DirListing-header {
|
|
138
124
|
flex: 0 0 auto;
|
|
139
125
|
display: flex;
|
|
140
126
|
flex-direction: row;
|
|
127
|
+
align-items: center;
|
|
141
128
|
overflow: hidden;
|
|
142
129
|
border-top: var(--jp-border-width) solid var(--jp-border-color2);
|
|
143
130
|
border-bottom: var(--jp-border-width) solid var(--jp-border-color1);
|
|
@@ -164,6 +151,12 @@
|
|
|
164
151
|
text-align: right;
|
|
165
152
|
}
|
|
166
153
|
|
|
154
|
+
.jp-DirListing-headerItem.jp-id-filesize {
|
|
155
|
+
flex: 0 0 75px;
|
|
156
|
+
border-left: var(--jp-border-width) solid var(--jp-border-color2);
|
|
157
|
+
text-align: right;
|
|
158
|
+
}
|
|
159
|
+
|
|
167
160
|
.jp-id-narrow {
|
|
168
161
|
display: none;
|
|
169
162
|
flex: 0 0 5px;
|
|
@@ -216,6 +209,7 @@
|
|
|
216
209
|
.jp-DirListing-item {
|
|
217
210
|
display: flex;
|
|
218
211
|
flex-direction: row;
|
|
212
|
+
align-items: center;
|
|
219
213
|
padding: 4px 12px;
|
|
220
214
|
-webkit-user-select: none;
|
|
221
215
|
-moz-user-select: none;
|
|
@@ -223,6 +217,40 @@
|
|
|
223
217
|
user-select: none;
|
|
224
218
|
}
|
|
225
219
|
|
|
220
|
+
.jp-DirListing-checkboxWrapper {
|
|
221
|
+
/* Increases hit area of checkbox. */
|
|
222
|
+
padding: 4px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.jp-DirListing-header
|
|
226
|
+
.jp-DirListing-checkboxWrapper
|
|
227
|
+
+ .jp-DirListing-headerItem {
|
|
228
|
+
padding-left: 4px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.jp-DirListing-content .jp-DirListing-checkboxWrapper {
|
|
232
|
+
position: relative;
|
|
233
|
+
left: -4px;
|
|
234
|
+
margin: -4px 0 -4px -8px;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.jp-DirListing-checkboxWrapper.jp-mod-visible {
|
|
238
|
+
visibility: visible;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* For devices that support hovering, hide checkboxes until hovered, selected...
|
|
242
|
+
*/
|
|
243
|
+
@media (hover: hover) {
|
|
244
|
+
.jp-DirListing-checkboxWrapper {
|
|
245
|
+
visibility: hidden;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.jp-DirListing-item:hover .jp-DirListing-checkboxWrapper,
|
|
249
|
+
.jp-DirListing-item.jp-mod-selected .jp-DirListing-checkboxWrapper {
|
|
250
|
+
visibility: visible;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
226
254
|
.jp-DirListing-item[data-is-dot] {
|
|
227
255
|
opacity: 75%;
|
|
228
256
|
}
|
|
@@ -258,10 +286,17 @@
|
|
|
258
286
|
text-align: right;
|
|
259
287
|
}
|
|
260
288
|
|
|
289
|
+
.jp-DirListing-itemFileSize {
|
|
290
|
+
flex: 0 0 90px;
|
|
291
|
+
text-align: right;
|
|
292
|
+
}
|
|
293
|
+
|
|
261
294
|
.jp-DirListing-editor {
|
|
262
295
|
flex: 1 0 64px;
|
|
263
296
|
outline: none;
|
|
264
297
|
border: none;
|
|
298
|
+
color: var(--jp-ui-font-color1);
|
|
299
|
+
background-color: var(--jp-layout-color1);
|
|
265
300
|
}
|
|
266
301
|
|
|
267
302
|
.jp-DirListing-item.jp-mod-running .jp-DirListing-itemIcon::before {
|
|
@@ -290,15 +325,6 @@
|
|
|
290
325
|
transform: translateX(-40%) translateY(-58%);
|
|
291
326
|
}
|
|
292
327
|
|
|
293
|
-
.jp-DirListing-deadSpace {
|
|
294
|
-
flex: 1 1 auto;
|
|
295
|
-
margin: 0;
|
|
296
|
-
padding: 0;
|
|
297
|
-
list-style-type: none;
|
|
298
|
-
overflow: auto;
|
|
299
|
-
background-color: var(--jp-layout-color1);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
328
|
.jp-Document {
|
|
303
329
|
min-width: 120px;
|
|
304
330
|
min-height: 120px;
|