@jupyterlab/filebrowser 4.0.0-alpha.9 → 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.
@@ -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-FileBrowser-filterBox {
113
- padding: 0;
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,7 +116,8 @@
131
116
  }
132
117
 
133
118
  .jp-DirListing:focus-visible {
134
- border: 1px solid var(--jp-brand-color1);
119
+ outline: 1px solid var(--jp-brand-color1);
120
+ outline-offset: -2px;
135
121
  }
136
122
 
137
123
  .jp-DirListing-header {
@@ -165,6 +151,12 @@
165
151
  text-align: right;
166
152
  }
167
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
+
168
160
  .jp-id-narrow {
169
161
  display: none;
170
162
  flex: 0 0 5px;
@@ -294,10 +286,17 @@
294
286
  text-align: right;
295
287
  }
296
288
 
289
+ .jp-DirListing-itemFileSize {
290
+ flex: 0 0 90px;
291
+ text-align: right;
292
+ }
293
+
297
294
  .jp-DirListing-editor {
298
295
  flex: 1 0 64px;
299
296
  outline: none;
300
297
  border: none;
298
+ color: var(--jp-ui-font-color1);
299
+ background-color: var(--jp-layout-color1);
301
300
  }
302
301
 
303
302
  .jp-DirListing-item.jp-mod-running .jp-DirListing-itemIcon::before {
@@ -326,15 +325,6 @@
326
325
  transform: translateX(-40%) translateY(-58%);
327
326
  }
328
327
 
329
- .jp-DirListing-deadSpace {
330
- flex: 1 1 auto;
331
- margin: 0;
332
- padding: 0;
333
- list-style-type: none;
334
- overflow: auto;
335
- background-color: var(--jp-layout-color1);
336
- }
337
-
338
328
  .jp-Document {
339
329
  min-width: 120px;
340
330
  min-height: 120px;