Skip to content

Commit 34be2a4

Browse files
committed
add create new drive command
1 parent 106b0a8 commit 34be2a4

File tree

4 files changed

+143
-3
lines changed

4 files changed

+143
-3
lines changed

jupyter_drives/handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async def get(self, drive: str = "", path: str = ""):
9090
async def post(self, drive: str = "", path: str = ""):
9191
body = self.get_json_body()
9292
if 'location' in body:
93-
result = await self._manager.new_drive(**body)
93+
result = await self._manager.new_drive(drive, **body)
9494
else:
9595
result = await self._manager.new_file(drive, path, **body)
9696
self.finish(result)

src/contents.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
countObjectNameAppearances,
2020
renameObjects,
2121
copyObjects,
22-
presignedLink
22+
presignedLink,
23+
createDrive
2324
} from './requests';
2425

2526
let data: Contents.IModel = {
@@ -625,6 +626,31 @@ export class Drive implements Contents.IDrive {
625626
return data;
626627
}
627628

629+
/**
630+
* Create a new drive.
631+
*
632+
* @param options: The options used to create the drive.
633+
*
634+
* @returns A promise which resolves with the contents model.
635+
*/
636+
async newDrive(
637+
newDriveName: string,
638+
region: string
639+
): Promise<Contents.IModel> {
640+
data = await createDrive(newDriveName, {
641+
location: region
642+
});
643+
644+
Contents.validateContentsModel(data);
645+
this._fileChanged.emit({
646+
type: 'new',
647+
oldValue: null,
648+
newValue: data
649+
});
650+
651+
return data;
652+
}
653+
628654
/**
629655
* Create a checkpoint for a file.
630656
*

src/plugins/driveBrowserPlugin.ts

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ import { ITranslator } from '@jupyterlab/translation';
1414
import {
1515
createToolbarFactory,
1616
IToolbarWidgetRegistry,
17-
setToolbar
17+
setToolbar,
18+
showDialog,
19+
Dialog
1820
} from '@jupyterlab/apputils';
1921
import { ISettingRegistry } from '@jupyterlab/settingregistry';
2022
import { FilenameSearcher, IScore } from '@jupyterlab/ui-components';
2123
import { CommandRegistry } from '@lumino/commands';
24+
import { Widget } from '@lumino/widgets';
2225

2326
import { driveBrowserIcon } from '../icons';
2427
import { Drive } from '../contents';
@@ -35,6 +38,16 @@ const FILE_BROWSER_FACTORY = 'DriveBrowser';
3538
*/
3639
const FILTERBOX_CLASS = 'jp-drive-browser-search-box';
3740

41+
/**
42+
* The class name added to dialogs.
43+
*/
44+
const FILE_DIALOG_CLASS = 'jp-FileDialog';
45+
46+
/**
47+
* The class name added for the new drive label in the creating new drive dialog.
48+
*/
49+
const CREATE_DRIVE_TITLE_CLASS = 'jp-new-drive-title';
50+
3851
/**
3952
* The drives list provider.
4053
*/
@@ -184,6 +197,9 @@ export const driveFileBrowser: JupyterFrontEndPlugin<void> = {
184197

185198
// Listen for your plugin setting changes using Signal
186199
setting.changed.connect(loadSetting);
200+
201+
// Add commands
202+
Private.addCommands(app, drive);
187203
})
188204
.catch(reason => {
189205
console.error(
@@ -246,4 +262,101 @@ namespace Private {
246262
};
247263
router.routed.connect(listener);
248264
}
265+
266+
/**
267+
* Create the node for a creating a new drive handler.
268+
*/
269+
const createNewDriveNode = (newDriveName: string): HTMLElement => {
270+
const body = document.createElement('div');
271+
272+
const drive = document.createElement('label');
273+
drive.textContent = 'Name';
274+
drive.className = CREATE_DRIVE_TITLE_CLASS;
275+
const driveName = document.createElement('input');
276+
277+
const region = document.createElement('label');
278+
region.textContent = 'Region';
279+
region.className = CREATE_DRIVE_TITLE_CLASS;
280+
const regionName = document.createElement('input');
281+
regionName.placeholder = 'us-east-1';
282+
283+
body.appendChild(drive);
284+
body.appendChild(driveName);
285+
body.appendChild(region);
286+
body.appendChild(regionName);
287+
return body;
288+
};
289+
290+
/**
291+
* A widget used to create a new drive.
292+
*/
293+
export class CreateDriveHandler extends Widget {
294+
/**
295+
* Construct a new "create-drive" dialog.
296+
*/
297+
constructor(newDriveName: string) {
298+
super({ node: createNewDriveNode(newDriveName) });
299+
this.onAfterAttach();
300+
}
301+
302+
protected onAfterAttach(): void {
303+
this.addClass(FILE_DIALOG_CLASS);
304+
const drive = this.driveInput.value;
305+
this.driveInput.setSelectionRange(0, drive.length);
306+
const region = this.regionInput.value;
307+
this.regionInput.setSelectionRange(0, region.length);
308+
}
309+
310+
/**
311+
* Get the input text node for drive name.
312+
*/
313+
get driveInput(): HTMLInputElement {
314+
return this.node.getElementsByTagName('input')[0] as HTMLInputElement;
315+
}
316+
317+
/**
318+
* Get the input text node for region.
319+
*/
320+
get regionInput(): HTMLInputElement {
321+
return this.node.getElementsByTagName('input')[1] as HTMLInputElement;
322+
}
323+
324+
/**
325+
* Get the value of the widget.
326+
*/
327+
getValue(): string[] {
328+
return [this.driveInput.value, this.regionInput.value];
329+
}
330+
}
331+
332+
export function addCommands(app: JupyterFrontEnd, drive: Drive): void {
333+
app.commands.addCommand(CommandIDs.createNewDrive, {
334+
execute: async () => {
335+
return showDialog({
336+
title: 'Create New Drive',
337+
body: new Private.CreateDriveHandler(drive.name),
338+
focusNodeSelector: 'input',
339+
buttons: [
340+
Dialog.cancelButton(),
341+
Dialog.okButton({
342+
label: 'Create',
343+
ariaLabel: 'Create New Drive'
344+
})
345+
]
346+
}).then(result => {
347+
if (result.value) {
348+
drive.newDrive(result.value[0], result.value[1]);
349+
}
350+
});
351+
},
352+
label: 'Create New Drive',
353+
icon: driveBrowserIcon.bindprops({ stylesheet: 'menuItem' })
354+
});
355+
356+
app.contextMenu.addItem({
357+
command: CommandIDs.createNewDrive,
358+
selector: '#drive-file-browser.jp-SidePanel .jp-DirListing-content',
359+
rank: 10
360+
});
361+
}
249362
}

src/token.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export namespace CommandIDs {
88
export const openDrivesDialog = 'drives:open-drives-dialog';
99
export const openPath = 'drives:open-path';
1010
export const toggleBrowser = 'drives:toggle-main';
11+
export const createNewDrive = 'drives:create-new-drive';
1112
export const launcher = 'launcher:create';
1213
}
1314

0 commit comments

Comments
 (0)