|
5 | 5 | JupyterFrontEnd, |
6 | 6 | JupyterFrontEndPlugin |
7 | 7 | } from '@jupyterlab/application'; |
| 8 | +import { IDocumentWidgetOpener } from '@jupyterlab/docmanager'; |
| 9 | +import { IStatusBar } from '@jupyterlab/statusbar'; |
8 | 10 | import { |
9 | 11 | IFileBrowserFactory, |
10 | 12 | FileBrowser, |
@@ -38,6 +40,67 @@ import { Drive } from '../contents'; |
38 | 40 | import { setListingLimit } from '../requests'; |
39 | 41 | import { CommandIDs } from '../token'; |
40 | 42 |
|
| 43 | +/** |
| 44 | + * Status bar widget for displaying drive information |
| 45 | + */ |
| 46 | +class DriveStatusWidget extends Widget { |
| 47 | + constructor() { |
| 48 | + super(); |
| 49 | + this.node.classList.add( |
| 50 | + 'drive-status-widget', |
| 51 | + 'drive-status-loading', |
| 52 | + 'lm-mod-hidden' |
| 53 | + ); |
| 54 | + |
| 55 | + this._textSpan = document.createElement('span'); |
| 56 | + this._textSpan.textContent = ''; |
| 57 | + this.node.appendChild(this._textSpan); |
| 58 | + |
| 59 | + this._isLoading = false; |
| 60 | + } |
| 61 | + |
| 62 | + updateStatus(text: string) { |
| 63 | + this._textSpan.textContent = text; |
| 64 | + } |
| 65 | + |
| 66 | + /** |
| 67 | + * Update status when loading a directory or file |
| 68 | + */ |
| 69 | + setLoading(path: string, type: string) { |
| 70 | + this._isLoading = true; |
| 71 | + |
| 72 | + if (type === 'directory') { |
| 73 | + const displayPath = |
| 74 | + path === '' ? 'Root' : path.split('/').pop() || 'Directory'; |
| 75 | + this.updateStatus(`Opening: ${displayPath}`); |
| 76 | + } else { |
| 77 | + const fileName = path.split('/').pop() || 'File'; |
| 78 | + this.updateStatus(`Opening: ${fileName}`); |
| 79 | + } |
| 80 | + this.removeClass('lm-mod-hidden'); |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Clear loading state and show current status |
| 85 | + */ |
| 86 | + setLoaded(path?: string) { |
| 87 | + this._isLoading = false; |
| 88 | + this.addClass('lm-mod-hidden'); |
| 89 | + |
| 90 | + this.updateStatus(''); |
| 91 | + } |
| 92 | + |
| 93 | + /** |
| 94 | + * Check if currently loading |
| 95 | + */ |
| 96 | + get isLoading(): boolean { |
| 97 | + return this._isLoading; |
| 98 | + } |
| 99 | + |
| 100 | + private _isLoading: boolean; |
| 101 | + private _textSpan: HTMLSpanElement; |
| 102 | +} |
| 103 | + |
41 | 104 | /** |
42 | 105 | * The file browser factory ID. |
43 | 106 | */ |
@@ -69,24 +132,28 @@ export const driveFileBrowser: JupyterFrontEndPlugin<void> = { |
69 | 132 | IFileBrowserFactory, |
70 | 133 | IToolbarWidgetRegistry, |
71 | 134 | ISettingRegistry, |
72 | | - ITranslator |
| 135 | + ITranslator, |
| 136 | + IDocumentWidgetOpener |
73 | 137 | ], |
74 | 138 | optional: [ |
75 | 139 | IRouter, |
76 | 140 | JupyterFrontEnd.ITreeResolver, |
77 | 141 | ILabShell, |
78 | | - ILayoutRestorer |
| 142 | + ILayoutRestorer, |
| 143 | + IStatusBar |
79 | 144 | ], |
80 | 145 | activate: async ( |
81 | 146 | app: JupyterFrontEnd, |
82 | 147 | fileBrowserFactory: IFileBrowserFactory, |
83 | 148 | toolbarRegistry: IToolbarWidgetRegistry, |
84 | 149 | settingsRegistry: ISettingRegistry, |
85 | 150 | translator: ITranslator, |
| 151 | + docWidgetOpener: IDocumentWidgetOpener, |
86 | 152 | router: IRouter | null, |
87 | 153 | tree: JupyterFrontEnd.ITreeResolver | null, |
88 | 154 | labShell: ILabShell | null, |
89 | | - restorer: ILayoutRestorer | null |
| 155 | + restorer: ILayoutRestorer | null, |
| 156 | + statusBar: IStatusBar | null |
90 | 157 | ): Promise<void> => { |
91 | 158 | console.log( |
92 | 159 | 'JupyterLab extension jupyter-drives:drives-file-browser is activated!' |
@@ -125,6 +192,34 @@ export const driveFileBrowser: JupyterFrontEndPlugin<void> = { |
125 | 192 | restorer.add(driveBrowser, 'drive-file-browser'); |
126 | 193 | } |
127 | 194 |
|
| 195 | + // Register status bar widget |
| 196 | + if (statusBar) { |
| 197 | + const driveStatusWidget = new DriveStatusWidget(); |
| 198 | + |
| 199 | + statusBar.registerStatusItem('driveBrowserStatus', { |
| 200 | + item: driveStatusWidget, |
| 201 | + align: 'right', |
| 202 | + rank: 500 |
| 203 | + }); |
| 204 | + |
| 205 | + // Item/dir being opened |
| 206 | + //@ts-expect-error listing is protected |
| 207 | + driveBrowser.listing.onItemOpened.connect((_, args) => { |
| 208 | + const { path, type } = args; |
| 209 | + driveStatusWidget.setLoading(path, type); |
| 210 | + }); |
| 211 | + |
| 212 | + const doneLoading = () => { |
| 213 | + driveStatusWidget.setLoaded(); |
| 214 | + }; |
| 215 | + |
| 216 | + // Item done opening |
| 217 | + docWidgetOpener.opened.connect(doneLoading); |
| 218 | + |
| 219 | + // Directory done opening |
| 220 | + driveBrowser.model.pathChanged.connect(doneLoading); |
| 221 | + } |
| 222 | + |
128 | 223 | const uploader = new Uploader({ model: driveBrowser.model, translator }); |
129 | 224 | toolbarRegistry.addFactory(FILE_BROWSER_FACTORY, 'uploader', () => { |
130 | 225 | return uploader; |
|
0 commit comments