@difizen/libro-jupyter 0.1.32 → 0.1.34
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/es/cell/jupyter-code-cell-view.d.ts +3 -1
- package/es/cell/jupyter-code-cell-view.d.ts.map +1 -1
- package/es/cell/jupyter-code-cell-view.js +9 -0
- package/es/components/icons.js +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.d.ts.map +1 -1
- package/es/index.js +2 -1
- package/es/keybind-instructions/index.less +0 -5
- package/es/keybind-instructions/keybind-instructions-view.d.ts.map +1 -1
- package/es/keybind-instructions/keybind-instructions-view.js +67 -61
- package/es/module.d.ts.map +1 -1
- package/es/module.js +2 -3
- package/es/output/libro-jupyter-outputarea.d.ts.map +1 -1
- package/es/output/libro-jupyter-outputarea.js +60 -56
- package/es/toolbar/save-file-error.d.ts.map +1 -1
- package/es/toolbar/save-file-error.js +20 -13
- package/es/widget/box/contribution.d.ts +10 -0
- package/es/widget/box/contribution.d.ts.map +1 -0
- package/es/widget/box/contribution.js +48 -0
- package/es/widget/box/index.d.ts +3 -0
- package/es/widget/box/index.d.ts.map +1 -0
- package/es/widget/box/index.js +2 -0
- package/es/widget/box/index.less +3 -0
- package/es/widget/box/view.d.ts +19 -0
- package/es/widget/box/view.d.ts.map +1 -0
- package/es/widget/box/view.js +114 -0
- package/es/widget/comm.d.ts +65 -0
- package/es/widget/comm.d.ts.map +1 -0
- package/es/widget/comm.js +153 -0
- package/es/widget/index.d.ts +7 -0
- package/es/widget/index.d.ts.map +1 -1
- package/es/widget/index.js +8 -1
- package/es/widget/instance-progress/contribution.d.ts +10 -0
- package/es/widget/instance-progress/contribution.d.ts.map +1 -0
- package/es/widget/instance-progress/contribution.js +39 -0
- package/es/widget/instance-progress/index.d.ts +3 -0
- package/es/widget/instance-progress/index.d.ts.map +1 -0
- package/es/widget/instance-progress/index.js +2 -0
- package/es/widget/instance-progress/view.d.ts +30 -0
- package/es/widget/instance-progress/view.d.ts.map +1 -0
- package/es/widget/instance-progress/view.js +180 -0
- package/es/widget/libro-widgets.d.ts +84 -0
- package/es/widget/libro-widgets.d.ts.map +1 -0
- package/es/widget/libro-widgets.js +307 -0
- package/es/widget/module.d.ts +4 -0
- package/es/widget/module.d.ts.map +1 -0
- package/es/widget/module.js +38 -0
- package/es/widget/progress/contribution.d.ts +10 -0
- package/es/widget/progress/contribution.d.ts.map +1 -0
- package/es/widget/progress/contribution.js +39 -0
- package/es/widget/progress/index.d.ts +3 -0
- package/es/widget/progress/index.d.ts.map +1 -0
- package/es/widget/progress/index.js +2 -0
- package/es/widget/progress/progressBar.d.ts +15 -0
- package/es/widget/progress/progressBar.d.ts.map +1 -0
- package/es/widget/progress/progressBar.js +20 -0
- package/es/widget/progress/view.d.ts +19 -0
- package/es/widget/progress/view.d.ts.map +1 -0
- package/es/widget/progress/view.js +74 -0
- package/es/widget/protocol.d.ts +193 -0
- package/es/widget/protocol.d.ts.map +1 -0
- package/es/widget/protocol.js +33 -0
- package/es/widget/utils.d.ts +27 -0
- package/es/widget/utils.d.ts.map +1 -0
- package/es/widget/utils.js +59 -0
- package/es/widget/version.d.ts +3 -0
- package/es/widget/version.d.ts.map +1 -0
- package/es/widget/version.js +2 -0
- package/es/widget/widget-manager.d.ts +19 -0
- package/es/widget/widget-manager.d.ts.map +1 -0
- package/es/widget/widget-manager.js +77 -0
- package/es/widget/widget-render.d.ts.map +1 -1
- package/es/widget/widget-render.js +7 -3
- package/es/widget/widget-rendermime-contribution.d.ts +2 -1
- package/es/widget/widget-rendermime-contribution.d.ts.map +1 -1
- package/es/widget/widget-rendermime-contribution.js +2 -1
- package/es/widget/widget-view-contribution.d.ts +10 -0
- package/es/widget/widget-view-contribution.d.ts.map +1 -0
- package/es/widget/widget-view-contribution.js +36 -0
- package/es/widget/widget-view.d.ts +71 -0
- package/es/widget/widget-view.d.ts.map +1 -0
- package/es/widget/widget-view.js +273 -0
- package/package.json +17 -18
- package/src/cell/jupyter-code-cell-view.tsx +10 -1
- package/src/components/icons.tsx +1 -1
- package/src/index.ts +1 -0
- package/src/keybind-instructions/index.less +0 -5
- package/src/keybind-instructions/keybind-instructions-view.tsx +70 -60
- package/src/module.ts +1 -3
- package/src/output/libro-jupyter-outputarea.tsx +56 -49
- package/src/toolbar/save-file-error.tsx +25 -15
- package/src/widget/box/contribution.ts +29 -0
- package/src/widget/box/index.less +3 -0
- package/src/widget/box/index.ts +2 -0
- package/src/widget/box/view.tsx +112 -0
- package/src/widget/comm.ts +152 -0
- package/src/widget/index.ts +7 -0
- package/src/widget/instance-progress/contribution.ts +20 -0
- package/src/widget/instance-progress/index.ts +2 -0
- package/src/widget/instance-progress/view.tsx +155 -0
- package/src/widget/libro-widgets.ts +223 -0
- package/src/widget/module.ts +73 -0
- package/src/widget/progress/contribution.ts +24 -0
- package/src/widget/progress/index.ts +2 -0
- package/src/widget/progress/progressBar.tsx +29 -0
- package/src/widget/progress/view.tsx +70 -0
- package/src/widget/protocol.ts +255 -0
- package/src/widget/utils.ts +67 -0
- package/src/widget/version.ts +2 -0
- package/src/widget/widget-manager.ts +45 -0
- package/src/widget/widget-render.tsx +10 -5
- package/src/widget/widget-rendermime-contribution.ts +2 -1
- package/src/widget/widget-view-contribution.ts +14 -0
- package/src/widget/widget-view.tsx +259 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ViewManager, inject, singleton } from '@difizen/mana-app';
|
|
2
|
+
|
|
3
|
+
import type { IWidgetViewProps } from '../protocol.js';
|
|
4
|
+
import { WidgetViewContribution } from '../protocol.js';
|
|
5
|
+
|
|
6
|
+
import { InstancesProgressWidget } from './view.js';
|
|
7
|
+
|
|
8
|
+
@singleton({ contrib: WidgetViewContribution })
|
|
9
|
+
export class InstancesProgressWidgetViewContribution implements WidgetViewContribution {
|
|
10
|
+
@inject(ViewManager) viewManager: ViewManager;
|
|
11
|
+
canHandle = (attributes: any) => {
|
|
12
|
+
if (attributes._model_name === 'InstancesProgressModel') {
|
|
13
|
+
return 100;
|
|
14
|
+
}
|
|
15
|
+
return 1;
|
|
16
|
+
};
|
|
17
|
+
factory(props: IWidgetViewProps) {
|
|
18
|
+
return this.viewManager.getOrCreateView(InstancesProgressWidget, props);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { LibroContextKey } from '@difizen/libro-core';
|
|
2
|
+
import type { KernelMessage } from '@difizen/libro-kernel';
|
|
3
|
+
import {
|
|
4
|
+
useInject,
|
|
5
|
+
view,
|
|
6
|
+
ViewInstance,
|
|
7
|
+
ViewOption,
|
|
8
|
+
transient,
|
|
9
|
+
inject,
|
|
10
|
+
prop,
|
|
11
|
+
} from '@difizen/mana-app';
|
|
12
|
+
import { forwardRef } from 'react';
|
|
13
|
+
|
|
14
|
+
import type { IWidgetViewProps } from '../protocol.js';
|
|
15
|
+
import type { InstanceRecord, InstancesRecords, ProgressItem } from '../protocol.js';
|
|
16
|
+
import { WidgetView } from '../widget-view.js';
|
|
17
|
+
|
|
18
|
+
export interface ProgressOverviewProps {
|
|
19
|
+
progressMap: Record<string, ProgressItem>;
|
|
20
|
+
workingProgressKeys: string[];
|
|
21
|
+
prefix: string;
|
|
22
|
+
suffix: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const LibroInstancesProgressWidgetViewComponent = forwardRef<HTMLDivElement>(
|
|
26
|
+
function LibroInstancesProgressWidgetViewComponent(_props, ref) {
|
|
27
|
+
const widgetView = useInject<InstancesProgressWidget>(ViewInstance);
|
|
28
|
+
if (widgetView.isCommClosed) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
<div ref={ref} className="libro-instances-progress-widget">
|
|
33
|
+
<span style={{ paddingRight: 5 }}>{widgetView.prefix}</span>
|
|
34
|
+
<span>
|
|
35
|
+
{widgetView.workingProgressKeys.map((progressKey) => {
|
|
36
|
+
const progressItem = widgetView.progressMap[progressKey];
|
|
37
|
+
return (
|
|
38
|
+
<a
|
|
39
|
+
className="pyodps-progress-launcher"
|
|
40
|
+
style={{ marginRight: 5 }}
|
|
41
|
+
key={progressKey}
|
|
42
|
+
>
|
|
43
|
+
{progressItem && progressItem.name}
|
|
44
|
+
</a>
|
|
45
|
+
);
|
|
46
|
+
})}
|
|
47
|
+
</span>
|
|
48
|
+
<span>{widgetView.suffix}</span>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
@transient()
|
|
54
|
+
@view('libro-widget-instances-progress-view')
|
|
55
|
+
export class InstancesProgressWidget extends WidgetView {
|
|
56
|
+
override view = LibroInstancesProgressWidgetViewComponent;
|
|
57
|
+
@prop()
|
|
58
|
+
prefix: string;
|
|
59
|
+
@prop()
|
|
60
|
+
suffix: string;
|
|
61
|
+
progressMap: Record<string, ProgressItem> = {};
|
|
62
|
+
workingProgressKeys: string[] = []; // Order of groups by time of insertion
|
|
63
|
+
instanceRecords: InstancesRecords = {};
|
|
64
|
+
modalVisible = false;
|
|
65
|
+
modalProgressItemKey = '';
|
|
66
|
+
constructor(
|
|
67
|
+
@inject(ViewOption) props: IWidgetViewProps,
|
|
68
|
+
@inject(LibroContextKey) libroContextKey: LibroContextKey,
|
|
69
|
+
) {
|
|
70
|
+
super(props, libroContextKey);
|
|
71
|
+
this.prefix = props.attributes.prefix;
|
|
72
|
+
this.suffix = props.attributes.suffix;
|
|
73
|
+
}
|
|
74
|
+
updateRecords(progressKey: string) {
|
|
75
|
+
const progressItem = this.progressMap[progressKey];
|
|
76
|
+
if (progressItem) {
|
|
77
|
+
const { instances = [] } = progressItem;
|
|
78
|
+
instances.forEach((instance) => {
|
|
79
|
+
const { id, status } = instance;
|
|
80
|
+
if (!this.instanceRecords[id]) {
|
|
81
|
+
this.instanceRecords[id] = {
|
|
82
|
+
startDate: Date.now(),
|
|
83
|
+
} as InstanceRecord;
|
|
84
|
+
}
|
|
85
|
+
if (status === 'Terminated') {
|
|
86
|
+
if (!this.instanceRecords[id].endDate) {
|
|
87
|
+
this.instanceRecords[id].endDate = Date.now();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Handle incoming comm msg.
|
|
95
|
+
*/
|
|
96
|
+
override handleCommMsg(msg: KernelMessage.ICommMsgMsg): Promise<void> {
|
|
97
|
+
const data = msg.content.data as any;
|
|
98
|
+
const method = data.method;
|
|
99
|
+
switch (method) {
|
|
100
|
+
case 'update':
|
|
101
|
+
if (data.state.prefix) {
|
|
102
|
+
this.prefix = data.state.prefix;
|
|
103
|
+
}
|
|
104
|
+
if (data.state.suffix) {
|
|
105
|
+
this.suffix = data.state.suffix;
|
|
106
|
+
}
|
|
107
|
+
// eslint-disable-next-line no-fallthrough
|
|
108
|
+
case 'custom':
|
|
109
|
+
// eslint-disable-next-line no-case-declarations
|
|
110
|
+
const customMsg = data.content;
|
|
111
|
+
if (customMsg) {
|
|
112
|
+
// message format: '{"action": "action", content: ["content1", "content2"]}'
|
|
113
|
+
const msgObj: { action: 'update' | 'delete' | 'clear'; content: string[] } =
|
|
114
|
+
JSON.parse(customMsg);
|
|
115
|
+
const action: string = msgObj.action;
|
|
116
|
+
const content: string[] = [];
|
|
117
|
+
if (msgObj.content) {
|
|
118
|
+
content.push(...msgObj.content);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
switch (action) {
|
|
122
|
+
case 'update':
|
|
123
|
+
content.forEach((groupJson) => {
|
|
124
|
+
const parsedProgressItem: ProgressItem = JSON.parse(groupJson);
|
|
125
|
+
if (!this.progressMap[parsedProgressItem.key]) {
|
|
126
|
+
this.workingProgressKeys.push(parsedProgressItem.key);
|
|
127
|
+
}
|
|
128
|
+
this.progressMap[parsedProgressItem.key] = parsedProgressItem;
|
|
129
|
+
this.updateRecords(parsedProgressItem.key);
|
|
130
|
+
});
|
|
131
|
+
// ? TODO: 发出一个更新 modal signal 的信号,这里需要取到之前的 key
|
|
132
|
+
break;
|
|
133
|
+
case 'delete':
|
|
134
|
+
content.forEach((groupKey: string) => {
|
|
135
|
+
if (!this.progressMap[groupKey]) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const i = this.workingProgressKeys.indexOf(groupKey);
|
|
139
|
+
if (i >= 0) {
|
|
140
|
+
this.workingProgressKeys.splice(i, 1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
break;
|
|
144
|
+
case 'clear':
|
|
145
|
+
this.progressMap = {};
|
|
146
|
+
this.workingProgressKeys = [];
|
|
147
|
+
// ? TODO: 发出更新 overview 以及 modal 的 signal
|
|
148
|
+
break;
|
|
149
|
+
default:
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return Promise.resolve();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { JSONObject } from '@difizen/libro-common';
|
|
2
|
+
import type { IKernelConnection, KernelMessage } from '@difizen/libro-kernel';
|
|
3
|
+
import type { Contribution } from '@difizen/mana-app';
|
|
4
|
+
import { contrib, inject, Priority, prop, transient } from '@difizen/mana-app';
|
|
5
|
+
import { Emitter } from '@difizen/mana-app';
|
|
6
|
+
|
|
7
|
+
import type { Comm } from './comm.js';
|
|
8
|
+
import type {
|
|
9
|
+
ISerializedState,
|
|
10
|
+
IWidgets,
|
|
11
|
+
IWidgetViewOptions,
|
|
12
|
+
IClassicComm,
|
|
13
|
+
WidgetCommOption,
|
|
14
|
+
} from './protocol.js';
|
|
15
|
+
import {
|
|
16
|
+
LibroWidgetCommFactory,
|
|
17
|
+
WidgetsOption,
|
|
18
|
+
WidgetViewContribution,
|
|
19
|
+
} from './protocol.js';
|
|
20
|
+
import { put_buffers, reject } from './utils.js';
|
|
21
|
+
import { PROTOCOL_VERSION } from './version.js';
|
|
22
|
+
import type { WidgetView } from './widget-view.js';
|
|
23
|
+
|
|
24
|
+
const PROTOCOL_MAJOR_VERSION = PROTOCOL_VERSION.split('.', 1)[0];
|
|
25
|
+
|
|
26
|
+
@transient()
|
|
27
|
+
export class LibroWidgets implements IWidgets {
|
|
28
|
+
@contrib(WidgetViewContribution)
|
|
29
|
+
WidgetViewProvider: Contribution.Provider<WidgetViewContribution>;
|
|
30
|
+
widgetEmitter: Emitter<{ WidgetViewName: string }> = new Emitter();
|
|
31
|
+
widgetCommFactory: (options: WidgetCommOption) => Comm;
|
|
32
|
+
kernelConnection: IKernelConnection;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
@inject(WidgetsOption) options: WidgetsOption,
|
|
36
|
+
@inject(LibroWidgetCommFactory)
|
|
37
|
+
widgetCommFactory: (options: WidgetCommOption) => Comm,
|
|
38
|
+
) {
|
|
39
|
+
this.kernelConnection = options.kc;
|
|
40
|
+
this.id = options.id;
|
|
41
|
+
this.widgetCommFactory = widgetCommFactory;
|
|
42
|
+
this.kernelConnection.registerCommTarget(this.commTargetName, async (comm, msg) => {
|
|
43
|
+
const widgetComm = this.widgetCommFactory({ comm });
|
|
44
|
+
await this.handleCommOpen(widgetComm, msg);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
get onWidgetRender() {
|
|
48
|
+
return this.widgetEmitter.event;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected findProvider(attributes: any): WidgetViewContribution {
|
|
52
|
+
const prioritized = Priority.sortSync(
|
|
53
|
+
this.WidgetViewProvider.getContributions(),
|
|
54
|
+
(contribution) => contribution.canHandle(attributes),
|
|
55
|
+
);
|
|
56
|
+
const sorted = prioritized.map((c) => c.value);
|
|
57
|
+
return sorted[0]!;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a comm which can be used for communication for a widget.
|
|
62
|
+
*
|
|
63
|
+
* If the data/metadata is passed in, open the comm before returning (i.e.,
|
|
64
|
+
* send the comm_open message). If the data and metadata is undefined, we
|
|
65
|
+
* want to reconstruct a comm that already exists in the kernel, so do not
|
|
66
|
+
* open the comm by sending the comm_open message.
|
|
67
|
+
*
|
|
68
|
+
* @param comm_target_name Comm target name
|
|
69
|
+
* @param model_id The comm id
|
|
70
|
+
* @param data The initial data for the comm
|
|
71
|
+
* @param metadata The metadata in the open message
|
|
72
|
+
*/
|
|
73
|
+
async createComm(
|
|
74
|
+
comm_target_name: string,
|
|
75
|
+
model_id?: string,
|
|
76
|
+
data?: JSONObject,
|
|
77
|
+
metadata?: JSONObject,
|
|
78
|
+
buffers?: ArrayBuffer[] | ArrayBufferView[],
|
|
79
|
+
): Promise<IClassicComm> {
|
|
80
|
+
const kernel = this.kernelConnection;
|
|
81
|
+
if (!kernel) {
|
|
82
|
+
throw new Error('No current kernel');
|
|
83
|
+
}
|
|
84
|
+
const comm = kernel.createComm(comm_target_name, model_id);
|
|
85
|
+
if (data || metadata) {
|
|
86
|
+
comm.open(data, metadata, buffers);
|
|
87
|
+
}
|
|
88
|
+
return this.widgetCommFactory({ comm });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get a model by model id.
|
|
93
|
+
*
|
|
94
|
+
* #### Notes
|
|
95
|
+
* If the model is not found, throw error.
|
|
96
|
+
*
|
|
97
|
+
* If you would like to synchronously test if a model exists, use .hasModel().
|
|
98
|
+
*/
|
|
99
|
+
getModel(model_id: string): WidgetView {
|
|
100
|
+
const model = this.models.get(model_id);
|
|
101
|
+
if (model === undefined) {
|
|
102
|
+
throw new Error('widget model not found');
|
|
103
|
+
}
|
|
104
|
+
return model;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns true if the given model is registered, otherwise false.
|
|
109
|
+
*
|
|
110
|
+
* #### Notes
|
|
111
|
+
* This is a synchronous way to check if a model is registered.
|
|
112
|
+
*/
|
|
113
|
+
hasModel(model_id: string): boolean {
|
|
114
|
+
return this.models.get(model_id) !== undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Handle when a comm is opened.
|
|
119
|
+
*/
|
|
120
|
+
async handleCommOpen(
|
|
121
|
+
comm: IClassicComm,
|
|
122
|
+
msg: KernelMessage.ICommOpenMsg,
|
|
123
|
+
): Promise<WidgetView> {
|
|
124
|
+
const protocolVersion = ((msg.metadata || {})['version'] as string) || '';
|
|
125
|
+
if (protocolVersion.split('.', 1)[0] !== PROTOCOL_MAJOR_VERSION) {
|
|
126
|
+
const error = `Wrong widget protocol version: received protocol version '${protocolVersion}', but was expecting major version '${PROTOCOL_MAJOR_VERSION}'`;
|
|
127
|
+
console.error(error);
|
|
128
|
+
return Promise.reject(error);
|
|
129
|
+
}
|
|
130
|
+
const data = msg.content.data as unknown as ISerializedState;
|
|
131
|
+
const buffer_paths = data.buffer_paths || [];
|
|
132
|
+
const buffers = msg.buffers || [];
|
|
133
|
+
put_buffers(data.state, buffer_paths, buffers);
|
|
134
|
+
// this.createComm(msg.content.target_name, msg.content.comm_id, msg.content.data, msg.metadata);
|
|
135
|
+
return this.newWidgetView(data.state, {
|
|
136
|
+
model_id: msg.content.comm_id,
|
|
137
|
+
comm,
|
|
138
|
+
}).catch(reject('Could not create a model.', true));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
registerWidgetView(model_id: string, model: Promise<WidgetView>): void {
|
|
142
|
+
model
|
|
143
|
+
.then((model) => {
|
|
144
|
+
this.models.set(model_id, model);
|
|
145
|
+
this.models.set(model.toModelKey(), model);
|
|
146
|
+
this.widgetEmitter.fire({ WidgetViewName: model.model_name });
|
|
147
|
+
return;
|
|
148
|
+
})
|
|
149
|
+
.catch(() => {
|
|
150
|
+
//
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
handleCommClose(msg: KernelMessage.ICommCloseMsg) {
|
|
155
|
+
const comm_id = msg.content.comm_id;
|
|
156
|
+
const model = this.getModel(comm_id);
|
|
157
|
+
model.isCommClosed = true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
unregisterWidgetView(model_id: string): void {
|
|
161
|
+
const model = this.models.get(model_id);
|
|
162
|
+
model?.dispose();
|
|
163
|
+
this.models.delete(model_id);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async newWidgetView(
|
|
167
|
+
attributes: any,
|
|
168
|
+
options: IWidgetViewOptions,
|
|
169
|
+
): Promise<WidgetView> {
|
|
170
|
+
const model_id = options.model_id;
|
|
171
|
+
if (!model_id) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
'Neither comm nor model_id provided in options object. At least one must exist.',
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
options.model_id = model_id;
|
|
177
|
+
const provider = this.findProvider(attributes);
|
|
178
|
+
const WidgetView = provider.factory({
|
|
179
|
+
attributes: attributes,
|
|
180
|
+
options: options,
|
|
181
|
+
widgetsId: this.id,
|
|
182
|
+
});
|
|
183
|
+
this.registerWidgetView(model_id, WidgetView);
|
|
184
|
+
return WidgetView;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Close all widgets and empty the widget state.
|
|
189
|
+
* @return Promise that resolves when the widget state is cleared.
|
|
190
|
+
*/
|
|
191
|
+
clearState() {
|
|
192
|
+
this.models.clear();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Disconnect the widget manager from the kernel, setting each model's comm
|
|
196
|
+
* as dead.
|
|
197
|
+
*/
|
|
198
|
+
disconnect(): void {
|
|
199
|
+
// this.models.forEach(model => model.clear());
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Dictionary of model ids and model instance promises
|
|
203
|
+
*/
|
|
204
|
+
@prop()
|
|
205
|
+
protected models: Map<string, WidgetView> = new Map();
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The comm target name to register
|
|
209
|
+
*/
|
|
210
|
+
id: string;
|
|
211
|
+
readonly commTargetName = 'jupyter.widget';
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Serialize the model. See the deserialization function at the top of this file
|
|
215
|
+
* and the kernel-side serializer/deserializer.
|
|
216
|
+
*/
|
|
217
|
+
toJSON(): string {
|
|
218
|
+
return JSON.stringify({
|
|
219
|
+
kc_id: this.kernelConnection.id,
|
|
220
|
+
id: this.id,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { LibroKernelManageModule } from '@difizen/libro-kernel';
|
|
2
|
+
import { ManaModule } from '@difizen/mana-app';
|
|
3
|
+
|
|
4
|
+
import { VBoxWidget, VBoxWidgetContribution } from './box/index.js';
|
|
5
|
+
import { Comm } from './comm.js';
|
|
6
|
+
import {
|
|
7
|
+
InstancesProgressWidget,
|
|
8
|
+
InstancesProgressWidgetViewContribution,
|
|
9
|
+
} from './instance-progress/index.js';
|
|
10
|
+
import { LibroWidgets } from './libro-widgets.js';
|
|
11
|
+
import { ProgressWidget, ProgressWidgetViewContribution } from './progress/index.js';
|
|
12
|
+
import {
|
|
13
|
+
LibroWidgetCommFactory,
|
|
14
|
+
LibroWidgetsFactory,
|
|
15
|
+
WidgetCommOption,
|
|
16
|
+
WidgetsOption,
|
|
17
|
+
WidgetViewContribution,
|
|
18
|
+
} from './protocol.js';
|
|
19
|
+
import { LibroWidgetManager } from './widget-manager.js';
|
|
20
|
+
import { LibroWidgetMimeContribution } from './widget-rendermime-contribution.js';
|
|
21
|
+
import { DefaultWidgetViewContribution } from './widget-view-contribution.js';
|
|
22
|
+
import { WidgetView } from './widget-view.js';
|
|
23
|
+
|
|
24
|
+
export const BaseWidgetModule = ManaModule.create()
|
|
25
|
+
.contribution(WidgetViewContribution)
|
|
26
|
+
.register(
|
|
27
|
+
Comm,
|
|
28
|
+
{
|
|
29
|
+
token: LibroWidgetCommFactory,
|
|
30
|
+
useFactory: (ctx) => {
|
|
31
|
+
return (options: WidgetCommOption) => {
|
|
32
|
+
const child = ctx.container.createChild();
|
|
33
|
+
child.register({
|
|
34
|
+
token: WidgetCommOption,
|
|
35
|
+
useValue: options,
|
|
36
|
+
});
|
|
37
|
+
return child.get(Comm);
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
LibroWidgets,
|
|
42
|
+
{
|
|
43
|
+
token: LibroWidgetsFactory,
|
|
44
|
+
useFactory: (ctx) => {
|
|
45
|
+
return (options: WidgetsOption) => {
|
|
46
|
+
const child = ctx.container.createChild();
|
|
47
|
+
child.register({
|
|
48
|
+
token: WidgetsOption,
|
|
49
|
+
useValue: options,
|
|
50
|
+
});
|
|
51
|
+
return child.get(LibroWidgets);
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
LibroWidgetManager,
|
|
56
|
+
WidgetView,
|
|
57
|
+
DefaultWidgetViewContribution,
|
|
58
|
+
LibroWidgetMimeContribution,
|
|
59
|
+
)
|
|
60
|
+
.dependOn(LibroKernelManageModule);
|
|
61
|
+
|
|
62
|
+
export const WidgetModule = ManaModule.create()
|
|
63
|
+
.register(
|
|
64
|
+
VBoxWidget,
|
|
65
|
+
VBoxWidgetContribution,
|
|
66
|
+
|
|
67
|
+
ProgressWidget,
|
|
68
|
+
ProgressWidgetViewContribution,
|
|
69
|
+
|
|
70
|
+
InstancesProgressWidget,
|
|
71
|
+
InstancesProgressWidgetViewContribution,
|
|
72
|
+
)
|
|
73
|
+
.dependOn(BaseWidgetModule);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ViewManager, inject, singleton } from '@difizen/mana-app';
|
|
2
|
+
|
|
3
|
+
import type { IWidgetViewProps } from '../protocol.js';
|
|
4
|
+
import { WidgetViewContribution } from '../protocol.js';
|
|
5
|
+
|
|
6
|
+
import { ProgressWidget } from './view.js';
|
|
7
|
+
|
|
8
|
+
@singleton({ contrib: WidgetViewContribution })
|
|
9
|
+
export class ProgressWidgetViewContribution implements WidgetViewContribution {
|
|
10
|
+
@inject(ViewManager) viewManager: ViewManager;
|
|
11
|
+
canHandle = (attributes: any) => {
|
|
12
|
+
if (
|
|
13
|
+
attributes._model_name === 'FloatProgressModel' ||
|
|
14
|
+
attributes._model_name === 'IntProgressModel' ||
|
|
15
|
+
attributes._model_name === 'TransientProgressModel'
|
|
16
|
+
) {
|
|
17
|
+
return 100;
|
|
18
|
+
}
|
|
19
|
+
return 1;
|
|
20
|
+
};
|
|
21
|
+
factory(props: IWidgetViewProps) {
|
|
22
|
+
return this.viewManager.getOrCreateView(ProgressWidget, props);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Progress } from 'antd';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the ProgressBar.
|
|
5
|
+
*/
|
|
6
|
+
export interface IProgressBarProps {
|
|
7
|
+
/**
|
|
8
|
+
* The current progress percentage, from 0 to 100
|
|
9
|
+
*/
|
|
10
|
+
percent: number;
|
|
11
|
+
/**
|
|
12
|
+
* Width of progress bar in pixel.
|
|
13
|
+
*/
|
|
14
|
+
width?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ProgressBar(props: IProgressBarProps) {
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<Progress
|
|
21
|
+
strokeLinecap="butt"
|
|
22
|
+
percent={props.percent}
|
|
23
|
+
strokeWidth={18}
|
|
24
|
+
showInfo={false}
|
|
25
|
+
style={{ width: '200px' }}
|
|
26
|
+
/>
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { JSONObject } from '@difizen/libro-common';
|
|
2
|
+
import { LibroContextKey } from '@difizen/libro-core';
|
|
3
|
+
import {
|
|
4
|
+
view,
|
|
5
|
+
ViewOption,
|
|
6
|
+
transient,
|
|
7
|
+
useInject,
|
|
8
|
+
ViewInstance,
|
|
9
|
+
inject,
|
|
10
|
+
prop,
|
|
11
|
+
} from '@difizen/mana-app';
|
|
12
|
+
import { forwardRef } from 'react';
|
|
13
|
+
|
|
14
|
+
import type { IWidgetViewProps, WidgetState } from '../protocol.js';
|
|
15
|
+
import { defaultWidgetState } from '../protocol.js';
|
|
16
|
+
import { WidgetView } from '../widget-view.js';
|
|
17
|
+
|
|
18
|
+
import { ProgressBar } from './progressBar.js';
|
|
19
|
+
|
|
20
|
+
export const LibroProgressWidgetComponent = forwardRef<HTMLDivElement>(
|
|
21
|
+
function LibroProgressWidgetComponent() {
|
|
22
|
+
const widgetView = useInject<ProgressWidget>(ViewInstance);
|
|
23
|
+
const percent =
|
|
24
|
+
widgetView.state.max && widgetView.state.min
|
|
25
|
+
? widgetView.state.value / ((widgetView.state.max - widgetView.state.min) / 100)
|
|
26
|
+
: 0;
|
|
27
|
+
if (widgetView.isCommClosed) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
<div className="libro-progress-widget">
|
|
32
|
+
<div className="libro-progress-widget-description">
|
|
33
|
+
{widgetView.state.description}
|
|
34
|
+
</div>
|
|
35
|
+
<ProgressBar percent={percent} />
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
interface ProgressState extends WidgetState {
|
|
42
|
+
max?: number;
|
|
43
|
+
min?: number;
|
|
44
|
+
bar_style?: string;
|
|
45
|
+
value: number;
|
|
46
|
+
}
|
|
47
|
+
@transient()
|
|
48
|
+
@view('libro-widget-progress-view')
|
|
49
|
+
export class ProgressWidget extends WidgetView {
|
|
50
|
+
override view = LibroProgressWidgetComponent;
|
|
51
|
+
|
|
52
|
+
@prop()
|
|
53
|
+
override state: JSONObject & ProgressState = {
|
|
54
|
+
...defaultWidgetState,
|
|
55
|
+
max: 1,
|
|
56
|
+
min: 0,
|
|
57
|
+
value: 0,
|
|
58
|
+
};
|
|
59
|
+
constructor(
|
|
60
|
+
@inject(ViewOption) props: IWidgetViewProps,
|
|
61
|
+
@inject(LibroContextKey) libroContextKey: LibroContextKey,
|
|
62
|
+
) {
|
|
63
|
+
super(props, libroContextKey);
|
|
64
|
+
|
|
65
|
+
const attributes = props.attributes;
|
|
66
|
+
this.state.max = attributes.max;
|
|
67
|
+
this.state.min = attributes.min;
|
|
68
|
+
this.setState(attributes);
|
|
69
|
+
}
|
|
70
|
+
}
|