@jupyterlab/apputils-extension 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.
- package/lib/announcements.d.ts +2 -0
- package/lib/announcements.js +227 -0
- package/lib/announcements.js.map +1 -0
- package/lib/index.js +44 -11
- package/lib/index.js.map +1 -1
- package/lib/notificationplugin.d.ts +5 -0
- package/lib/notificationplugin.js +504 -0
- package/lib/notificationplugin.js.map +1 -0
- package/lib/palette.js +3 -3
- package/lib/palette.js.map +1 -1
- package/lib/settingconnector.js +4 -0
- package/lib/settingconnector.js.map +1 -1
- package/lib/statusbarplugin.js +10 -9
- package/lib/statusbarplugin.js.map +1 -1
- package/lib/themesplugins.js +3 -0
- package/lib/themesplugins.js.map +1 -1
- package/lib/toolbarregistryplugin.js +4 -0
- package/lib/toolbarregistryplugin.js.map +1 -1
- package/lib/workspacesplugin.js +6 -6
- package/lib/workspacesplugin.js.map +1 -1
- package/package.json +27 -23
- package/schema/notification.json +48 -0
- package/schema/palette.json +2 -0
- package/schema/sanitizer.json +25 -0
- package/src/announcements.ts +297 -0
- package/src/index.ts +687 -0
- package/src/notificationplugin.tsx +902 -0
- package/src/palette.ts +213 -0
- package/src/settingconnector.ts +63 -0
- package/src/settingsplugin.ts +65 -0
- package/src/statusbarplugin.ts +145 -0
- package/src/themesplugins.ts +266 -0
- package/src/toolbarregistryplugin.ts +29 -0
- package/src/workspacesplugin.ts +306 -0
- package/style/base.css +1 -1
- package/style/notification.css +227 -0
- package/style/redirect.css +0 -15
package/src/palette.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* -----------------------------------------------------------------------------
|
|
2
|
+
| Copyright (c) Jupyter Development Team.
|
|
3
|
+
| Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|----------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import { ILayoutRestorer, JupyterFrontEnd } from '@jupyterlab/application';
|
|
7
|
+
import {
|
|
8
|
+
ICommandPalette,
|
|
9
|
+
IPaletteItem,
|
|
10
|
+
ModalCommandPalette
|
|
11
|
+
} from '@jupyterlab/apputils';
|
|
12
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
13
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
14
|
+
import { CommandPaletteSvg, paletteIcon } from '@jupyterlab/ui-components';
|
|
15
|
+
import { find } from '@lumino/algorithm';
|
|
16
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
17
|
+
import { DisposableDelegate, IDisposable } from '@lumino/disposable';
|
|
18
|
+
import { CommandPalette } from '@lumino/widgets';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The command IDs used by the apputils extension.
|
|
22
|
+
*/
|
|
23
|
+
namespace CommandIDs {
|
|
24
|
+
export const activate = 'apputils:activate-command-palette';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const PALETTE_PLUGIN_ID = '@jupyterlab/apputils-extension:palette';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A thin wrapper around the `CommandPalette` class to conform with the
|
|
31
|
+
* JupyterLab interface for the application-wide command palette.
|
|
32
|
+
*/
|
|
33
|
+
export class Palette implements ICommandPalette {
|
|
34
|
+
/**
|
|
35
|
+
* Create a palette instance.
|
|
36
|
+
*/
|
|
37
|
+
constructor(palette: CommandPalette, translator?: ITranslator) {
|
|
38
|
+
this.translator = translator || nullTranslator;
|
|
39
|
+
const trans = this.translator.load('jupyterlab');
|
|
40
|
+
this._palette = palette;
|
|
41
|
+
this._palette.title.label = '';
|
|
42
|
+
this._palette.title.caption = trans.__('Command Palette');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The placeholder text of the command palette's search input.
|
|
47
|
+
*/
|
|
48
|
+
set placeholder(placeholder: string) {
|
|
49
|
+
this._palette.inputNode.placeholder = placeholder;
|
|
50
|
+
}
|
|
51
|
+
get placeholder(): string {
|
|
52
|
+
return this._palette.inputNode.placeholder;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Activate the command palette for user input.
|
|
57
|
+
*/
|
|
58
|
+
activate(): void {
|
|
59
|
+
this._palette.activate();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Add a command item to the command palette.
|
|
64
|
+
*
|
|
65
|
+
* @param options - The options for creating the command item.
|
|
66
|
+
*
|
|
67
|
+
* @returns A disposable that will remove the item from the palette.
|
|
68
|
+
*/
|
|
69
|
+
addItem(options: IPaletteItem): IDisposable {
|
|
70
|
+
const item = this._palette.addItem(options as CommandPalette.IItemOptions);
|
|
71
|
+
return new DisposableDelegate(() => {
|
|
72
|
+
this._palette.removeItem(item);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected translator: ITranslator;
|
|
77
|
+
private _palette: CommandPalette;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A namespace for `Palette` statics.
|
|
82
|
+
*/
|
|
83
|
+
export namespace Palette {
|
|
84
|
+
/**
|
|
85
|
+
* Activate the command palette.
|
|
86
|
+
*/
|
|
87
|
+
export function activate(
|
|
88
|
+
app: JupyterFrontEnd,
|
|
89
|
+
translator: ITranslator,
|
|
90
|
+
settingRegistry: ISettingRegistry | null
|
|
91
|
+
): ICommandPalette {
|
|
92
|
+
const { commands, shell } = app;
|
|
93
|
+
const trans = translator.load('jupyterlab');
|
|
94
|
+
const palette = Private.createPalette(app, translator);
|
|
95
|
+
const modalPalette = new ModalCommandPalette({ commandPalette: palette });
|
|
96
|
+
let modal = false;
|
|
97
|
+
|
|
98
|
+
palette.node.setAttribute('role', 'region');
|
|
99
|
+
palette.node.setAttribute(
|
|
100
|
+
'aria-label',
|
|
101
|
+
trans.__('Command Palette Section')
|
|
102
|
+
);
|
|
103
|
+
shell.add(palette, 'left', { rank: 300, type: 'Command Palette' });
|
|
104
|
+
if (settingRegistry) {
|
|
105
|
+
const loadSettings = settingRegistry.load(PALETTE_PLUGIN_ID);
|
|
106
|
+
const updateSettings = (settings: ISettingRegistry.ISettings): void => {
|
|
107
|
+
const newModal = settings.get('modal').composite as boolean;
|
|
108
|
+
if (modal && !newModal) {
|
|
109
|
+
palette.parent = null;
|
|
110
|
+
modalPalette.detach();
|
|
111
|
+
shell.add(palette, 'left', { rank: 300, type: 'Command Palette' });
|
|
112
|
+
} else if (!modal && newModal) {
|
|
113
|
+
palette.parent = null;
|
|
114
|
+
modalPalette.palette = palette;
|
|
115
|
+
palette.show();
|
|
116
|
+
modalPalette.attach();
|
|
117
|
+
}
|
|
118
|
+
modal = newModal;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
Promise.all([loadSettings, app.restored])
|
|
122
|
+
.then(([settings]) => {
|
|
123
|
+
updateSettings(settings);
|
|
124
|
+
settings.changed.connect(settings => {
|
|
125
|
+
updateSettings(settings);
|
|
126
|
+
});
|
|
127
|
+
})
|
|
128
|
+
.catch((reason: Error) => {
|
|
129
|
+
console.error(reason.message);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Show the current palette shortcut in its title.
|
|
134
|
+
const updatePaletteTitle = () => {
|
|
135
|
+
const binding = find(
|
|
136
|
+
app.commands.keyBindings,
|
|
137
|
+
b => b.command === CommandIDs.activate
|
|
138
|
+
);
|
|
139
|
+
if (binding) {
|
|
140
|
+
const ks = binding.keys.map(CommandRegistry.formatKeystroke).join(', ');
|
|
141
|
+
palette.title.caption = trans.__('Commands (%1)', ks);
|
|
142
|
+
} else {
|
|
143
|
+
palette.title.caption = trans.__('Commands');
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
updatePaletteTitle();
|
|
147
|
+
app.commands.keyBindingChanged.connect(() => {
|
|
148
|
+
updatePaletteTitle();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
commands.addCommand(CommandIDs.activate, {
|
|
152
|
+
execute: () => {
|
|
153
|
+
if (modal) {
|
|
154
|
+
modalPalette.activate();
|
|
155
|
+
} else {
|
|
156
|
+
shell.activateById(palette.id);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
label: trans.__('Activate Command Palette')
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
palette.inputNode.placeholder = trans.__('SEARCH');
|
|
163
|
+
|
|
164
|
+
return new Palette(palette, translator);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Restore the command palette.
|
|
169
|
+
*/
|
|
170
|
+
export function restore(
|
|
171
|
+
app: JupyterFrontEnd,
|
|
172
|
+
restorer: ILayoutRestorer,
|
|
173
|
+
translator: ITranslator
|
|
174
|
+
): void {
|
|
175
|
+
const palette = Private.createPalette(app, translator);
|
|
176
|
+
// Let the application restorer track the command palette for restoration of
|
|
177
|
+
// application state (e.g. setting the command palette as the current side bar
|
|
178
|
+
// widget).
|
|
179
|
+
restorer.add(palette, 'command-palette');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The namespace for module private data.
|
|
185
|
+
*/
|
|
186
|
+
namespace Private {
|
|
187
|
+
/**
|
|
188
|
+
* The private command palette instance.
|
|
189
|
+
*/
|
|
190
|
+
let palette: CommandPalette;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Create the application-wide command palette.
|
|
194
|
+
*/
|
|
195
|
+
export function createPalette(
|
|
196
|
+
app: JupyterFrontEnd,
|
|
197
|
+
translator: ITranslator
|
|
198
|
+
): CommandPalette {
|
|
199
|
+
if (!palette) {
|
|
200
|
+
// use a renderer tweaked to use inline svg icons
|
|
201
|
+
palette = new CommandPalette({
|
|
202
|
+
commands: app.commands,
|
|
203
|
+
renderer: CommandPaletteSvg.defaultRenderer
|
|
204
|
+
});
|
|
205
|
+
palette.id = 'command-palette';
|
|
206
|
+
palette.title.icon = paletteIcon;
|
|
207
|
+
const trans = translator.load('jupyterlab');
|
|
208
|
+
palette.title.label = trans.__('Commands');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return palette;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { PageConfig } from '@jupyterlab/coreutils';
|
|
7
|
+
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
8
|
+
import { DataConnector, IDataConnector } from '@jupyterlab/statedb';
|
|
9
|
+
import { Throttler } from '@lumino/polling';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A data connector for fetching settings.
|
|
13
|
+
*
|
|
14
|
+
* #### Notes
|
|
15
|
+
* This connector adds a query parameter to the base services setting manager.
|
|
16
|
+
*/
|
|
17
|
+
export class SettingConnector extends DataConnector<
|
|
18
|
+
ISettingRegistry.IPlugin,
|
|
19
|
+
string
|
|
20
|
+
> {
|
|
21
|
+
constructor(connector: IDataConnector<ISettingRegistry.IPlugin, string>) {
|
|
22
|
+
super();
|
|
23
|
+
this._connector = connector;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Fetch settings for a plugin.
|
|
28
|
+
* @param id - The plugin ID
|
|
29
|
+
*
|
|
30
|
+
* #### Notes
|
|
31
|
+
* The REST API requests are throttled at one request per plugin per 100ms.
|
|
32
|
+
*/
|
|
33
|
+
fetch(id: string): Promise<ISettingRegistry.IPlugin | undefined> {
|
|
34
|
+
const throttlers = this._throttlers;
|
|
35
|
+
if (!(id in throttlers)) {
|
|
36
|
+
throttlers[id] = new Throttler(() => this._connector.fetch(id), 100);
|
|
37
|
+
}
|
|
38
|
+
return throttlers[id].invoke();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async list(
|
|
42
|
+
query: 'active' | 'all' = 'all'
|
|
43
|
+
): Promise<{ ids: string[]; values: ISettingRegistry.IPlugin[] }> {
|
|
44
|
+
const { isDeferred, isDisabled } = PageConfig.Extension;
|
|
45
|
+
const { ids, values } = await this._connector.list();
|
|
46
|
+
|
|
47
|
+
if (query === 'all') {
|
|
48
|
+
return { ids, values };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
ids: ids.filter(id => !isDeferred(id) && !isDisabled(id)),
|
|
53
|
+
values: values.filter(({ id }) => !isDeferred(id) && !isDisabled(id))
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async save(id: string, raw: string): Promise<void> {
|
|
58
|
+
await this._connector.save(id, raw);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private _connector: IDataConnector<ISettingRegistry.IPlugin, string>;
|
|
62
|
+
private _throttlers: { [key: string]: Throttler } = Object.create(null);
|
|
63
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* -----------------------------------------------------------------------------
|
|
2
|
+
| Copyright (c) Jupyter Development Team.
|
|
3
|
+
| Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|----------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
JupyterFrontEnd,
|
|
8
|
+
JupyterFrontEndPlugin
|
|
9
|
+
} from '@jupyterlab/application';
|
|
10
|
+
import { PageConfig } from '@jupyterlab/coreutils';
|
|
11
|
+
import { ISettingRegistry, SettingRegistry } from '@jupyterlab/settingregistry';
|
|
12
|
+
import { SettingConnector } from './settingconnector';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The default setting registry provider.
|
|
16
|
+
*/
|
|
17
|
+
export const settingsPlugin: JupyterFrontEndPlugin<ISettingRegistry> = {
|
|
18
|
+
id: '@jupyterlab/apputils-extension:settings',
|
|
19
|
+
activate: async (app: JupyterFrontEnd): Promise<ISettingRegistry> => {
|
|
20
|
+
const { isDisabled } = PageConfig.Extension;
|
|
21
|
+
const connector = new SettingConnector(app.serviceManager.settings);
|
|
22
|
+
|
|
23
|
+
// On startup, check if a plugin is available in the application.
|
|
24
|
+
// This helps avoid loading plugin files from other lab-based applications
|
|
25
|
+
// that have placed their schemas next to the JupyterLab schemas. Different lab-based
|
|
26
|
+
// applications might not have the same set of plugins loaded on the page.
|
|
27
|
+
// As an example this helps prevent having new toolbar items added by another application
|
|
28
|
+
// appear in JupyterLab as a side-effect when they are defined via the settings system.
|
|
29
|
+
const registry = new SettingRegistry({
|
|
30
|
+
connector,
|
|
31
|
+
plugins: (await connector.list('active')).values.filter(value =>
|
|
32
|
+
app.hasPlugin(value.id)
|
|
33
|
+
)
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// If there are plugins that have schemas that are not in the setting
|
|
37
|
+
// registry after the application has restored, try to load them manually
|
|
38
|
+
// because otherwise, its settings will never become available in the
|
|
39
|
+
// setting registry.
|
|
40
|
+
void app.restored.then(async () => {
|
|
41
|
+
const plugins = await connector.list('all');
|
|
42
|
+
plugins.ids.forEach(async (id, index) => {
|
|
43
|
+
if (!app.hasPlugin(id) || isDisabled(id) || id in registry.plugins) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await registry.load(id);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn(`Settings failed to load for (${id})`, error);
|
|
51
|
+
if (plugins.values[index].schema['jupyter.lab.transform']) {
|
|
52
|
+
console.warn(
|
|
53
|
+
`This may happen if {autoStart: false} in (${id}) ` +
|
|
54
|
+
`or if it is one of the deferredExtensions in page config.`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return registry;
|
|
62
|
+
},
|
|
63
|
+
autoStart: true,
|
|
64
|
+
provides: ISettingRegistry
|
|
65
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* -----------------------------------------------------------------------------
|
|
2
|
+
| Copyright (c) Jupyter Development Team.
|
|
3
|
+
| Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|----------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ILabShell,
|
|
8
|
+
JupyterFrontEnd,
|
|
9
|
+
JupyterFrontEndPlugin
|
|
10
|
+
} from '@jupyterlab/application';
|
|
11
|
+
import {
|
|
12
|
+
IKernelStatusModel,
|
|
13
|
+
ISessionContext,
|
|
14
|
+
ISessionContextDialogs,
|
|
15
|
+
KernelStatus,
|
|
16
|
+
RunningSessions,
|
|
17
|
+
SessionContextDialogs
|
|
18
|
+
} from '@jupyterlab/apputils';
|
|
19
|
+
import { IStatusBar } from '@jupyterlab/statusbar';
|
|
20
|
+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
21
|
+
import { Title, Widget } from '@lumino/widgets';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A plugin that provides a kernel status item to the status bar.
|
|
25
|
+
*/
|
|
26
|
+
export const kernelStatus: JupyterFrontEndPlugin<IKernelStatusModel> = {
|
|
27
|
+
id: '@jupyterlab/apputils-extension:kernel-status',
|
|
28
|
+
autoStart: true,
|
|
29
|
+
requires: [IStatusBar],
|
|
30
|
+
provides: IKernelStatusModel,
|
|
31
|
+
optional: [ISessionContextDialogs, ITranslator, ILabShell],
|
|
32
|
+
activate: (
|
|
33
|
+
app: JupyterFrontEnd,
|
|
34
|
+
statusBar: IStatusBar,
|
|
35
|
+
sessionDialogs_: ISessionContextDialogs | null,
|
|
36
|
+
translator_: ITranslator | null,
|
|
37
|
+
labShell: ILabShell | null
|
|
38
|
+
): IKernelStatusModel => {
|
|
39
|
+
const translator = translator_ ?? nullTranslator;
|
|
40
|
+
const sessionDialogs =
|
|
41
|
+
sessionDialogs_ ?? new SessionContextDialogs({ translator });
|
|
42
|
+
// When the status item is clicked, launch the kernel
|
|
43
|
+
// selection dialog for the current session.
|
|
44
|
+
const changeKernel = async () => {
|
|
45
|
+
if (!item.model.sessionContext) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await sessionDialogs.selectKernel(item.model.sessionContext);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Create the status item.
|
|
52
|
+
const item = new KernelStatus({ onClick: changeKernel }, translator);
|
|
53
|
+
|
|
54
|
+
const providers = new Set<(w: Widget | null) => ISessionContext | null>();
|
|
55
|
+
|
|
56
|
+
const addSessionProvider = (
|
|
57
|
+
provider: (w: Widget | null) => ISessionContext | null
|
|
58
|
+
): void => {
|
|
59
|
+
providers.add(provider);
|
|
60
|
+
|
|
61
|
+
if (app.shell.currentWidget) {
|
|
62
|
+
updateSession(app.shell, {
|
|
63
|
+
newValue: app.shell.currentWidget,
|
|
64
|
+
oldValue: null
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function updateSession(
|
|
70
|
+
shell: JupyterFrontEnd.IShell,
|
|
71
|
+
changes: ILabShell.IChangedArgs
|
|
72
|
+
) {
|
|
73
|
+
const { oldValue, newValue } = changes;
|
|
74
|
+
|
|
75
|
+
// Clean up after the old value if it exists,
|
|
76
|
+
// listen for changes to the title of the activity
|
|
77
|
+
if (oldValue) {
|
|
78
|
+
oldValue.title.changed.disconnect(onTitleChanged);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
item.model.sessionContext =
|
|
82
|
+
[...providers]
|
|
83
|
+
.map(provider => provider(changes.newValue))
|
|
84
|
+
.filter(session => session !== null)[0] ?? null;
|
|
85
|
+
|
|
86
|
+
if (newValue && item.model.sessionContext) {
|
|
87
|
+
onTitleChanged(newValue.title);
|
|
88
|
+
newValue.title.changed.connect(onTitleChanged);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// When the title of the active widget changes, update the label
|
|
93
|
+
// of the hover text.
|
|
94
|
+
const onTitleChanged = (title: Title<Widget>) => {
|
|
95
|
+
item.model!.activityName = title.label;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (labShell) {
|
|
99
|
+
labShell.currentChanged.connect(updateSession);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
statusBar.registerStatusItem(kernelStatus.id, {
|
|
103
|
+
item,
|
|
104
|
+
align: 'left',
|
|
105
|
+
rank: 1,
|
|
106
|
+
isActive: () => item.model!.sessionContext !== null
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return { addSessionProvider };
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* A plugin providing running terminals and sessions information
|
|
115
|
+
* to the status bar.
|
|
116
|
+
*/
|
|
117
|
+
export const runningSessionsStatus: JupyterFrontEndPlugin<void> = {
|
|
118
|
+
id: '@jupyterlab/apputils-extension:running-sessions-status',
|
|
119
|
+
autoStart: true,
|
|
120
|
+
requires: [IStatusBar, ITranslator],
|
|
121
|
+
activate: (
|
|
122
|
+
app: JupyterFrontEnd,
|
|
123
|
+
statusBar: IStatusBar,
|
|
124
|
+
translator: ITranslator
|
|
125
|
+
) => {
|
|
126
|
+
const item = new RunningSessions({
|
|
127
|
+
onClick: () => app.shell.activateById('jp-running-sessions'),
|
|
128
|
+
serviceManager: app.serviceManager,
|
|
129
|
+
translator
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
item.model.sessions = Array.from(
|
|
133
|
+
app.serviceManager.sessions.running()
|
|
134
|
+
).length;
|
|
135
|
+
item.model.terminals = Array.from(
|
|
136
|
+
app.serviceManager.terminals.running()
|
|
137
|
+
).length;
|
|
138
|
+
|
|
139
|
+
statusBar.registerStatusItem(runningSessionsStatus.id, {
|
|
140
|
+
item,
|
|
141
|
+
align: 'left',
|
|
142
|
+
rank: 0
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|