Skip to content

Commit 60ef40e

Browse files
committed
Add a new widget to be include in Notebook cell output
1 parent 6fdd7ad commit 60ef40e

File tree

7 files changed

+147
-38
lines changed

7 files changed

+147
-38
lines changed

packages/base/src/commands.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
SourceType
1111
} from '@jupytergis/schema';
1212
import { JupyterFrontEnd } from '@jupyterlab/application';
13-
import { WidgetTracker, showErrorMessage } from '@jupyterlab/apputils';
13+
import { showErrorMessage } from '@jupyterlab/apputils';
1414
import { ICompletionProviderManager } from '@jupyterlab/completer';
1515
import { IStateDB } from '@jupyterlab/statedb';
1616
import { ITranslator } from '@jupyterlab/translation';
@@ -21,10 +21,10 @@ import { CreationFormDialog } from './dialogs/formdialog';
2121
import { LayerBrowserWidget } from './dialogs/layerBrowserDialog';
2222
import { SymbologyWidget } from './dialogs/symbology/symbologyDialog';
2323
import keybindings from './keybindings.json';
24-
import { JupyterGISWidget } from './widget';
24+
import { JupyterGISTracker } from './types';
2525

2626
interface ICreateEntry {
27-
tracker: WidgetTracker<JupyterGISWidget>;
27+
tracker: JupyterGISTracker;
2828
formSchemaRegistry: IJGISFormSchemaRegistry;
2929
title: string;
3030
createLayer: boolean;
@@ -50,7 +50,7 @@ function loadKeybindings(commands: CommandRegistry, keybindings: any[]) {
5050
*/
5151
export function addCommands(
5252
app: JupyterFrontEnd,
53-
tracker: WidgetTracker<JupyterGISWidget>,
53+
tracker: JupyterGISTracker,
5454
translator: ITranslator,
5555
formSchemaRegistry: IJGISFormSchemaRegistry,
5656
layerBrowserRegistry: IJGISLayerBrowserRegistry,
@@ -932,7 +932,7 @@ export function addCommands(
932932

933933
namespace Private {
934934
export function createLayerBrowser(
935-
tracker: WidgetTracker<JupyterGISWidget>,
935+
tracker: JupyterGISTracker,
936936
layerBrowserRegistry: IJGISLayerBrowserRegistry,
937937
formSchemaRegistry: IJGISFormSchemaRegistry
938938
) {
@@ -953,7 +953,7 @@ namespace Private {
953953
}
954954

955955
export function createSymbologyDialog(
956-
tracker: WidgetTracker<JupyterGISWidget>,
956+
tracker: JupyterGISTracker,
957957
state: IStateDB
958958
) {
959959
return async () => {
@@ -1112,9 +1112,7 @@ namespace Private {
11121112
}
11131113
}
11141114

1115-
export function executeConsole(
1116-
tracker: WidgetTracker<JupyterGISWidget>
1117-
): void {
1115+
export function executeConsole(tracker: JupyterGISTracker): void {
11181116
const current = tracker.currentWidget;
11191117

11201118
if (!current) {
@@ -1123,9 +1121,7 @@ namespace Private {
11231121
current.content.executeConsole();
11241122
}
11251123

1126-
export function removeConsole(
1127-
tracker: WidgetTracker<JupyterGISWidget>
1128-
): void {
1124+
export function removeConsole(tracker: JupyterGISTracker): void {
11291125
const current = tracker.currentWidget;
11301126

11311127
if (!current) {
@@ -1135,7 +1131,7 @@ namespace Private {
11351131
}
11361132

11371133
export async function toggleConsole(
1138-
tracker: WidgetTracker<JupyterGISWidget>
1134+
tracker: JupyterGISTracker
11391135
): Promise<void> {
11401136
const current = tracker.currentWidget;
11411137

packages/base/src/panelview/model.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
IJupyterGISDoc,
33
IJupyterGISModel,
4+
IJupyterGISOutputWidget,
45
IJupyterGISTracker,
56
IJupyterGISWidget
67
} from '@jupytergis/schema';
@@ -14,7 +15,10 @@ export class ControlPanelModel implements IControlPanelModel {
1415
this._documentChanged = this._tracker.currentChanged;
1516
}
1617

17-
get documentChanged(): ISignal<IJupyterGISTracker, IJupyterGISWidget | null> {
18+
get documentChanged(): ISignal<
19+
IJupyterGISTracker,
20+
IJupyterGISWidget | IJupyterGISOutputWidget | null
21+
> {
1822
return this._documentChanged;
1923
}
2024

@@ -45,7 +49,7 @@ export class ControlPanelModel implements IControlPanelModel {
4549
private readonly _tracker: IJupyterGISTracker;
4650
private _documentChanged: ISignal<
4751
IJupyterGISTracker,
48-
IJupyterGISWidget | null
52+
IJupyterGISWidget | IJupyterGISOutputWidget | null
4953
>;
5054
}
5155

packages/base/src/types.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,29 @@ import {
22
IDict,
33
IJupyterGISDoc,
44
IJupyterGISModel,
5+
IJupyterGISOutputWidget,
56
IJupyterGISTracker,
67
IJupyterGISWidget
78
} from '@jupytergis/schema';
9+
import { WidgetTracker } from '@jupyterlab/apputils';
810
import { ISignal } from '@lumino/signaling';
911
import { Map } from 'ol';
1012

13+
import { JupyterGISOutputWidget, JupyterGISWidget } from './widget';
14+
1115
export { IDict };
1216
export type ValueOf<T> = T[keyof T];
1317

18+
export type JupyterGISTracker = WidgetTracker<
19+
JupyterGISWidget | JupyterGISOutputWidget
20+
>;
21+
1422
export interface IControlPanelModel {
1523
disconnect(f: any): void;
16-
documentChanged: ISignal<IJupyterGISTracker, IJupyterGISWidget | null>;
24+
documentChanged: ISignal<
25+
IJupyterGISTracker,
26+
IJupyterGISWidget | IJupyterGISOutputWidget | null
27+
>;
1728
filePath: string | undefined;
1829
jGISModel: IJupyterGISModel | undefined;
1930
sharedModel: IJupyterGISDoc | undefined;

packages/base/src/widget.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { JSONValue } from '@lumino/coreutils';
2-
import { ISignal, Signal } from '@lumino/signaling';
3-
import { SplitPanel } from '@lumino/widgets';
4-
1+
import { MainAreaWidget } from '@jupyterlab/apputils';
52
import { ConsolePanel, IConsoleTracker } from '@jupyterlab/console';
63
import { DocumentWidget } from '@jupyterlab/docregistry';
74
import { IObservableMap, ObservableMap } from '@jupyterlab/observables';
8-
9-
import { IJupyterGISModel, IJupyterGISWidget } from '@jupytergis/schema';
5+
import { JSONValue } from '@lumino/coreutils';
6+
import { ISignal, Signal } from '@lumino/signaling';
7+
import { SplitPanel } from '@lumino/widgets';
8+
import {
9+
IJupyterGISModel,
10+
IJupyterGISWidgetContext,
11+
IJupyterGISOutputWidget,
12+
IJupyterGISWidget
13+
} from '@jupytergis/schema';
1014

1115
import { JupyterGISMainViewPanel } from './mainview';
1216
import { MainViewModel } from './mainview/mainviewmodel';
@@ -35,6 +39,28 @@ export class JupyterGISWidget
3539
};
3640
}
3741

42+
/**
43+
* A main area widget designed to be used as Notebook cell output widget, to ease the
44+
* integration of toolbar and tracking.
45+
*/
46+
export class JupyterGISOutputWidget
47+
extends MainAreaWidget<JupyterGISPanel>
48+
implements IJupyterGISOutputWidget
49+
{
50+
constructor(options: JupyterGISOutputWidget.IOptions) {
51+
super(options);
52+
this.context = options.context;
53+
}
54+
55+
readonly context: IJupyterGISWidgetContext;
56+
}
57+
58+
export namespace JupyterGISOutputWidget {
59+
export interface IOptions extends MainAreaWidget.IOptions<JupyterGISPanel> {
60+
context: IJupyterGISWidgetContext;
61+
}
62+
}
63+
3864
export class JupyterGISPanel extends SplitPanel {
3965
constructor(options: JupyterGISPanel.IOptions) {
4066
super({ orientation: 'vertical', spacing: 0 });

packages/schema/src/interfaces.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry';
1212
import { Contents, User } from '@jupyterlab/services';
1313
import { JSONObject } from '@lumino/coreutils';
1414
import { ISignal, Signal } from '@lumino/signaling';
15-
import { SplitPanel } from '@lumino/widgets';
15+
import { SplitPanel, Widget } from '@lumino/widgets';
1616

1717
import {
1818
IJGISContent,
@@ -228,7 +228,13 @@ export interface IJupyterGISWidgetContext {
228228
path: string;
229229
}
230230

231-
export type IJupyterGISTracker = IWidgetTracker<IJupyterGISWidget>;
231+
export interface IJupyterGISOutputWidget extends Widget {
232+
context: IJupyterGISWidgetContext;
233+
}
234+
235+
export type IJupyterGISTracker = IWidgetTracker<
236+
IJupyterGISWidget | IJupyterGISOutputWidget
237+
>;
232238

233239
export interface IJGISFormSchemaRegistry {
234240
/**

python/jupytergis_core/src/plugin.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { AnnotationModel, JupyterGISWidget } from '@jupytergis/base';
1+
import {
2+
AnnotationModel,
3+
JupyterGISOutputWidget,
4+
JupyterGISWidget
5+
} from '@jupytergis/base';
26
import {
37
IAnnotationModel,
48
IAnnotationToken,
@@ -37,7 +41,9 @@ export const trackerPlugin: JupyterFrontEndPlugin<IJupyterGISTracker> = {
3741
translator: ITranslator,
3842
mainMenu?: IMainMenu
3943
): IJupyterGISTracker => {
40-
const tracker = new WidgetTracker<JupyterGISWidget>({
44+
const tracker = new WidgetTracker<
45+
JupyterGISWidget | JupyterGISOutputWidget
46+
>({
4147
namespace: NAME_SPACE
4248
});
4349
console.log('jupytergis:core:tracker is activated!');

python/jupytergis_lab/src/notebookrenderer.ts

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import { ICollaborativeDrive } from '@jupyter/collaborative-drive';
2-
import { JupyterGISPanel } from '@jupytergis/base';
3-
import { JupyterGISModel, IJupyterGISDoc } from '@jupytergis/schema';
4-
2+
import {
3+
JupyterGISOutputWidget,
4+
JupyterGISPanel,
5+
JupyterGISTracker,
6+
ToolbarWidget
7+
} from '@jupytergis/base';
8+
import {
9+
IJGISExternalCommandRegistry,
10+
IJGISExternalCommandRegistryToken,
11+
IJupyterGISDoc,
12+
IJupyterGISDocTracker,
13+
IJupyterGISWidgetContext,
14+
JupyterGISModel
15+
} from '@jupytergis/schema';
516
import {
617
JupyterFrontEnd,
718
JupyterFrontEndPlugin
819
} from '@jupyterlab/application';
920
import { Contents } from '@jupyterlab/services';
21+
import { CommandRegistry } from '@lumino/commands';
1022
import { MessageLoop } from '@lumino/messaging';
1123
import { Panel, Widget } from '@lumino/widgets';
1224
import * as Y from 'yjs';
@@ -31,14 +43,37 @@ export class YJupyterGISModel extends JupyterYModel {
3143
}
3244

3345
export class YJupyterGISLuminoWidget extends Panel {
34-
constructor(options: { model: JupyterGISModel }) {
46+
constructor(options: {
47+
commands: CommandRegistry;
48+
model: JupyterGISModel;
49+
externalCommands: IJGISExternalCommandRegistry;
50+
}) {
3551
super();
36-
52+
const { commands, model, externalCommands } = options;
3753
this.addClass(CLASS_NAME);
38-
this._jgisWidget = new JupyterGISPanel(options);
54+
const content = new JupyterGISPanel({ model });
55+
const toolbar = new ToolbarWidget({
56+
commands,
57+
model,
58+
externalCommands: externalCommands.getCommands()
59+
});
60+
const context: IJupyterGISWidgetContext = {
61+
model,
62+
path: model.filePath
63+
};
64+
this._jgisWidget = new JupyterGISOutputWidget({
65+
context,
66+
content,
67+
toolbar
68+
});
69+
3970
this.addWidget(this._jgisWidget);
4071
}
4172

73+
get jgisWidget(): JupyterGISOutputWidget {
74+
return this._jgisWidget;
75+
}
76+
4277
onResize = (): void => {
4378
if (this._jgisWidget) {
4479
MessageLoop.sendMessage(
@@ -48,15 +83,22 @@ export class YJupyterGISLuminoWidget extends Panel {
4883
}
4984
};
5085

51-
private _jgisWidget: JupyterGISPanel;
86+
private _jgisWidget: JupyterGISOutputWidget;
5287
}
5388

5489
export const notebookRendererPlugin: JupyterFrontEndPlugin<void> = {
5590
id: 'jupytergis:yjswidget-plugin',
5691
autoStart: true,
57-
optional: [IJupyterYWidgetManager, ICollaborativeDrive],
92+
optional: [
93+
IJGISExternalCommandRegistryToken,
94+
IJupyterGISDocTracker,
95+
IJupyterYWidgetManager,
96+
ICollaborativeDrive
97+
],
5898
activate: (
5999
app: JupyterFrontEnd,
100+
externalCommandRegistry: IJGISExternalCommandRegistry,
101+
jgisTracker: JupyterGISTracker,
60102
yWidgetManager?: IJupyterYWidgetManager,
61103
drive?: ICollaborativeDrive
62104
): void => {
@@ -75,7 +117,6 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin<void> = {
75117
const { path, format, contentType } = commMetadata;
76118

77119
const fileFormat = format as Contents.FileFormat;
78-
79120
const sharedModel = drive!.sharedModelFactory.createNew({
80121
path,
81122
format: fileFormat,
@@ -85,7 +126,24 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin<void> = {
85126
this.jupyterGISModel = new JupyterGISModel({
86127
sharedModel: sharedModel as IJupyterGISDoc
87128
});
88-
129+
const onchange = (_: any, args: any) => {
130+
if (args.stateChange) {
131+
args.stateChange.forEach((change: any) => {
132+
if (change.name === 'path') {
133+
this.jupyterGISModel.filePath = change.newValue;
134+
}
135+
});
136+
}
137+
};
138+
139+
this.jupyterGISModel.contentsManager = app.serviceManager.contents;
140+
sharedModel.changed.connect(onchange);
141+
142+
if (sharedModel.getState('path')) {
143+
this.jupyterGISModel.filePath = sharedModel.getState(
144+
'path'
145+
) as string;
146+
}
89147
return this.jupyterGISModel.sharedModel.ydoc;
90148
}
91149
}
@@ -96,10 +154,12 @@ export const notebookRendererPlugin: JupyterFrontEndPlugin<void> = {
96154
this.node = node;
97155

98156
const widget = new YJupyterGISLuminoWidget({
99-
model: yModel.jupyterGISModel
157+
commands: app.commands,
158+
model: yModel.jupyterGISModel,
159+
externalCommands: externalCommandRegistry
100160
});
101161
// Widget.attach(widget, node);
102-
162+
jgisTracker.add(widget.jgisWidget);
103163
MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
104164
node.appendChild(widget.node);
105165
MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);

0 commit comments

Comments
 (0)