forked from jupyterlab-contrib/jupyterlab-quickopen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
153 lines (133 loc) · 5.37 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { ILabShell, JupyterFrontEnd, JupyterFrontEndPlugin } from "@jupyterlab/application";
import { ICommandPalette } from "@jupyterlab/apputils";
import { URLExt, PathExt } from "@jupyterlab/coreutils";
import { IDocumentManager } from "@jupyterlab/docmanager";
import { ServerConnection } from "@jupyterlab/services";
import { ISettingRegistry } from "@jupyterlab/settingregistry";
import { FileBrowser, IFileBrowserFactory } from '@jupyterlab/filebrowser';
import { CommandRegistry } from "@lumino/commands";
import { ReadonlyJSONObject } from "@lumino/coreutils";
import { Message } from "@lumino/messaging";
import { ISignal, Signal } from "@lumino/signaling";
import { CommandPalette } from "@lumino/widgets";
import "../style/index.css";
/** Structure of the JSON response from the server */
interface QuickOpenResponse {
readonly contents: { [key: string]: string[] };
readonly scanSeconds: number;
}
/** Makes a HTTP request for the server-side quick open scan */
async function fetchContents(path: string, excludes: string[]): Promise<QuickOpenResponse> {
const query = excludes
.map(exclude => {
return "excludes=" + encodeURIComponent(exclude);
})
.join("&");
const settings = ServerConnection.makeSettings();
const fullUrl = URLExt.join(settings.baseUrl, "/api/quickopen") + "?" + query + "&path=" + path;
const response = await ServerConnection.makeRequest(fullUrl, { method: "GET" }, settings);
if (response.status !== 200) {
throw new ServerConnection.ResponseError(response);
}
return await response.json();
}
/**
* Shows files nested under directories in the root notebooks directory
* configured on the server.
*/
class QuickOpenWidget extends CommandPalette {
private _pathSelected = new Signal<this, string>(this);
private _settings: ReadonlyJSONObject;
private _fileBrowser: FileBrowser;
constructor(factory: IFileBrowserFactory, options: CommandPalette.IOptions) {
super(options);
this.id = "jupyterlab-quickopen";
this.title.iconClass = "jp-SideBar-tabIcon jp-SearchIcon";
this.title.caption = "Quick Open";
this._fileBrowser = factory.defaultBrowser;
}
/** Signal when a selected path is activated. */
get pathSelected(): ISignal<this, string> {
return this._pathSelected;
}
/** Current extension settings */
set settings(settings: ReadonlyJSONObject) {
this._settings = settings;
}
/**
* Refreshes the widget with the paths of files on the server.
*/
protected async onActivateRequest(msg: Message) {
super.onActivateRequest(msg);
// Fetch the current contents from the server
let path = this._settings.relativeSearch ? this._fileBrowser.model.path : "";
let response = await fetchContents(path, <string[]>this._settings.excludes);
// Remove all paths from the view
this.clearItems();
for (let category in response.contents) {
for (let fn of response.contents[category]) {
// Creates commands that are relative file paths on the server
let command = `${category}/${fn}`;
if (!this.commands.hasCommand(command)) {
// Only add the command to the registry if it does not yet exist
// TODO: Track disposables and remove
this.commands.addCommand(command, {
label: fn,
execute: () => {
// Emit a selection signal
this._pathSelected.emit(command);
}
});
}
// Make the file visible under its parent directory heading
this.addItem({ command, category });
}
}
}
}
/**
* Initialization data for the jupyterlab-quickopen extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: "@parente/jupyterlab-quickopen:plugin",
autoStart: true,
requires: [ICommandPalette, IDocumentManager, ILabShell, ISettingRegistry, IFileBrowserFactory],
activate: async (
app: JupyterFrontEnd,
palette: ICommandPalette,
docManager: IDocumentManager,
labShell: ILabShell,
settingRegistry: ISettingRegistry,
fileBrowserFactory: IFileBrowserFactory
) => {
window["docManager"] = docManager;
console.log(`Activated extension: ${extension.id}`);
const commands: CommandRegistry = new CommandRegistry();
const widget: QuickOpenWidget = new QuickOpenWidget(fileBrowserFactory, { commands });
const settings: ISettingRegistry.ISettings = await settingRegistry.load(extension.id);
// Listen for path selection signals and show the selected files in the
// appropriate editor/viewer
widget.pathSelected.connect((sender: QuickOpenWidget, path: string) => {
labShell.collapseLeft();
docManager.openOrReveal(PathExt.normalize(path));
});
// Listen for setting changes and apply them to the widget
widget.settings = settings.composite;
settings.changed.connect((settings: ISettingRegistry.ISettings) => {
widget.settings = settings.composite;
});
// Add a command to activate the quickopen sidebar so that the user can
// find it in the command palette, assign a hotkey, etc.
const command: string = "quickopen:activate";
app.commands.addCommand(command, {
label: "Quick Open",
execute: () => {
labShell.activateById(widget.id);
}
});
palette.addItem({ command, category: "File Operations" });
// Add the quickopen widget as a left sidebar
labShell.add(widget, "left", { rank: 1000 });
}
};
export default extension;