1 |
|
2 |
|
3 | import { translateKernelStatuses, VDomModel, VDomRenderer } from '@jupyterlab/apputils';
|
4 | import { nullTranslator } from '@jupyterlab/translation';
|
5 | import React from 'react';
|
6 | import { interactiveItem, ProgressCircle } from '@jupyterlab/statusbar';
|
7 | import { circleIcon, offlineBoltIcon } from '@jupyterlab/ui-components';
|
8 | import { KernelMessage } from '@jupyterlab/services';
|
9 |
|
10 |
|
11 |
|
12 | export function ExecutionIndicatorComponent(props) {
|
13 | const translator = props.translator || nullTranslator;
|
14 | const kernelStatuses = translateKernelStatuses(translator);
|
15 | const trans = translator.load('jupyterlab');
|
16 | const state = props.state;
|
17 | const showOnToolBar = props.displayOption.showOnToolBar;
|
18 | const showProgress = props.displayOption.showProgress;
|
19 | const tooltipClass = showOnToolBar ? 'down' : 'up';
|
20 | const emptyDiv = React.createElement("div", null);
|
21 | if (!state) {
|
22 | return emptyDiv;
|
23 | }
|
24 | const kernelStatus = state.kernelStatus;
|
25 | const circleIconProps = {
|
26 | alignSelf: 'normal',
|
27 | height: '24px'
|
28 | };
|
29 | const time = state.totalTime;
|
30 | const scheduledCellNumber = state.scheduledCellNumber || 0;
|
31 | const remainingCellNumber = state.scheduledCell.size || 0;
|
32 | const executedCellNumber = scheduledCellNumber - remainingCellNumber;
|
33 | let percentage = (100 * executedCellNumber) / scheduledCellNumber;
|
34 | let displayClass = showProgress ? '' : 'hidden';
|
35 | if (!showProgress && percentage < 100) {
|
36 | percentage = 0;
|
37 | }
|
38 | const progressBar = (percentage) => (React.createElement(ProgressCircle, { progress: percentage, width: 16, height: 24 }));
|
39 | const titleFactory = (translatedStatus) => trans.__('Kernel status: %1', translatedStatus);
|
40 | const reactElement = (status, circle, popup) => (React.createElement("div", { className: 'jp-Notebook-ExecutionIndicator', title: showProgress ? '' : titleFactory(kernelStatuses[status]), "data-status": status },
|
41 | circle,
|
42 | React.createElement("div", { className: `jp-Notebook-ExecutionIndicator-tooltip ${tooltipClass} ${displayClass}` },
|
43 | React.createElement("span", null,
|
44 | " ",
|
45 | titleFactory(kernelStatuses[status]),
|
46 | " "),
|
47 | popup)));
|
48 | if (state.kernelStatus === 'connecting' ||
|
49 | state.kernelStatus === 'disconnected' ||
|
50 | state.kernelStatus === 'unknown') {
|
51 | return reactElement(kernelStatus, React.createElement(offlineBoltIcon.react, Object.assign({}, circleIconProps)), []);
|
52 | }
|
53 | if (state.kernelStatus === 'starting' ||
|
54 | state.kernelStatus === 'terminating' ||
|
55 | state.kernelStatus === 'restarting' ||
|
56 | state.kernelStatus === 'initializing') {
|
57 | return reactElement(kernelStatus, React.createElement(circleIcon.react, Object.assign({}, circleIconProps)), []);
|
58 | }
|
59 | if (state.executionStatus === 'busy') {
|
60 | return reactElement('busy', progressBar(percentage), [
|
61 | React.createElement("span", { key: 0 }, trans.__(`Executed ${executedCellNumber}/${scheduledCellNumber} cells`)),
|
62 | React.createElement("span", { key: 1 }, trans._n('Elapsed time: %1 second', 'Elapsed time: %1 seconds', time))
|
63 | ]);
|
64 | }
|
65 | else {
|
66 |
|
67 | const progress = state.kernelStatus === 'busy' ? 0 : 100;
|
68 | const popup = state.kernelStatus === 'busy' || time === 0
|
69 | ? []
|
70 | : [
|
71 | React.createElement("span", { key: 0 }, trans._n('Executed %1 cell', 'Executed %1 cells', scheduledCellNumber)),
|
72 | React.createElement("span", { key: 1 }, trans._n('Elapsed time: %1 second', 'Elapsed time: %1 seconds', time))
|
73 | ];
|
74 | return reactElement(state.kernelStatus, progressBar(progress), popup);
|
75 | }
|
76 | }
|
77 |
|
78 |
|
79 |
|
80 | export class ExecutionIndicator extends VDomRenderer {
|
81 | |
82 |
|
83 |
|
84 | constructor(translator, showProgress = true) {
|
85 | super(new ExecutionIndicator.Model());
|
86 | this.translator = translator || nullTranslator;
|
87 | this.addClass(interactiveItem);
|
88 | }
|
89 | |
90 |
|
91 |
|
92 | render() {
|
93 | if (this.model === null || !this.model.renderFlag) {
|
94 | return React.createElement("div", null);
|
95 | }
|
96 | else {
|
97 | const nb = this.model.currentNotebook;
|
98 | if (!nb) {
|
99 | return (React.createElement(ExecutionIndicatorComponent, { displayOption: this.model.displayOption, state: undefined, translator: this.translator }));
|
100 | }
|
101 | return (React.createElement(ExecutionIndicatorComponent, { displayOption: this.model.displayOption, state: this.model.executionState(nb), translator: this.translator }));
|
102 | }
|
103 | }
|
104 | }
|
105 |
|
106 |
|
107 |
|
108 | (function (ExecutionIndicator) {
|
109 | |
110 |
|
111 |
|
112 | class Model extends VDomModel {
|
113 | constructor() {
|
114 | super();
|
115 | |
116 |
|
117 |
|
118 | this._notebookExecutionProgress = new WeakMap();
|
119 | this._displayOption = { showOnToolBar: true, showProgress: true };
|
120 | this._renderFlag = true;
|
121 | }
|
122 | |
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | attachNotebook(data) {
|
130 | var _a, _b, _c, _d;
|
131 | if (data && data.content && data.context) {
|
132 | const nb = data.content;
|
133 | const context = data.context;
|
134 | this._currentNotebook = nb;
|
135 | if (!this._notebookExecutionProgress.has(nb)) {
|
136 | this._notebookExecutionProgress.set(nb, {
|
137 | executionStatus: 'idle',
|
138 | kernelStatus: 'idle',
|
139 | totalTime: 0,
|
140 | interval: 0,
|
141 | timeout: 0,
|
142 | scheduledCell: new Set(),
|
143 | scheduledCellNumber: 0,
|
144 | needReset: true
|
145 | });
|
146 | const state = this._notebookExecutionProgress.get(nb);
|
147 | const contextStatusChanged = (ctx) => {
|
148 | if (state) {
|
149 | state.kernelStatus = ctx.kernelDisplayStatus;
|
150 | }
|
151 | this.stateChanged.emit(void 0);
|
152 | };
|
153 | context.statusChanged.connect(contextStatusChanged, this);
|
154 | const contextConnectionStatusChanged = (ctx) => {
|
155 | if (state) {
|
156 | state.kernelStatus = ctx.kernelDisplayStatus;
|
157 | }
|
158 | this.stateChanged.emit(void 0);
|
159 | };
|
160 | context.connectionStatusChanged.connect(contextConnectionStatusChanged, this);
|
161 | context.disposed.connect(ctx => {
|
162 | ctx.connectionStatusChanged.disconnect(contextConnectionStatusChanged, this);
|
163 | ctx.statusChanged.disconnect(contextStatusChanged, this);
|
164 | });
|
165 | const handleKernelMsg = (sender, msg) => {
|
166 | const message = msg.msg;
|
167 | const msgId = message.header.msg_id;
|
168 | if (message.header.msg_type === 'execute_request') {
|
169 |
|
170 | this._cellScheduledCallback(nb, msgId);
|
171 | }
|
172 | else if (KernelMessage.isStatusMsg(message) &&
|
173 | message.content.execution_state === 'idle') {
|
174 |
|
175 | const parentId = message.parent_header
|
176 | .msg_id;
|
177 | this._cellExecutedCallback(nb, parentId);
|
178 | }
|
179 | else if (message.header.msg_type === 'execute_input') {
|
180 |
|
181 | this._startTimer(nb);
|
182 | }
|
183 | };
|
184 | (_b = (_a = context.session) === null || _a === void 0 ? void 0 : _a.kernel) === null || _b === void 0 ? void 0 : _b.anyMessage.connect(handleKernelMsg);
|
185 | (_d = (_c = context.session) === null || _c === void 0 ? void 0 : _c.kernel) === null || _d === void 0 ? void 0 : _d.disposed.connect(kernel => kernel.anyMessage.disconnect(handleKernelMsg));
|
186 | const kernelChangedSlot = (_, kernelData) => {
|
187 | if (state) {
|
188 | this._resetTime(state);
|
189 | this.stateChanged.emit(void 0);
|
190 | if (kernelData.newValue) {
|
191 | kernelData.newValue.anyMessage.connect(handleKernelMsg);
|
192 | }
|
193 | }
|
194 | };
|
195 | context.kernelChanged.connect(kernelChangedSlot);
|
196 | context.disposed.connect(ctx => ctx.kernelChanged.disconnect(kernelChangedSlot));
|
197 | }
|
198 | }
|
199 | }
|
200 | |
201 |
|
202 |
|
203 | get currentNotebook() {
|
204 | return this._currentNotebook;
|
205 | }
|
206 | |
207 |
|
208 |
|
209 | get displayOption() {
|
210 | return this._displayOption;
|
211 | }
|
212 | |
213 |
|
214 |
|
215 |
|
216 |
|
217 | set displayOption(options) {
|
218 | this._displayOption = options;
|
219 | }
|
220 | |
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 | executionState(nb) {
|
229 | return this._notebookExecutionProgress.get(nb);
|
230 | }
|
231 | |
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 | _cellExecutedCallback(nb, msg_id) {
|
248 | const state = this._notebookExecutionProgress.get(nb);
|
249 | if (state && state.scheduledCell.has(msg_id)) {
|
250 | state.scheduledCell.delete(msg_id);
|
251 | if (state.scheduledCell.size === 0) {
|
252 | window.setTimeout(() => {
|
253 | state.executionStatus = 'idle';
|
254 | clearInterval(state.interval);
|
255 | this.stateChanged.emit(void 0);
|
256 | }, 150);
|
257 | state.timeout = window.setTimeout(() => {
|
258 | state.needReset = true;
|
259 | }, 1000);
|
260 | }
|
261 | }
|
262 | }
|
263 | |
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 | _startTimer(nb) {
|
270 | const state = this._notebookExecutionProgress.get(nb);
|
271 | if (state) {
|
272 | if (state.executionStatus !== 'busy') {
|
273 | state.executionStatus = 'busy';
|
274 | clearTimeout(state.timeout);
|
275 | this.stateChanged.emit(void 0);
|
276 | state.interval = window.setInterval(() => {
|
277 | this._tick(state);
|
278 | }, 1000);
|
279 | }
|
280 | }
|
281 | }
|
282 | |
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 | _cellScheduledCallback(nb, msg_id) {
|
292 | const state = this._notebookExecutionProgress.get(nb);
|
293 | if (state && !state.scheduledCell.has(msg_id)) {
|
294 | if (state.needReset) {
|
295 | this._resetTime(state);
|
296 | }
|
297 | state.scheduledCell.add(msg_id);
|
298 | state.scheduledCellNumber += 1;
|
299 | }
|
300 | }
|
301 | |
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 | _tick(data) {
|
308 | data.totalTime += 1;
|
309 | this.stateChanged.emit(void 0);
|
310 | }
|
311 | |
312 |
|
313 |
|
314 |
|
315 |
|
316 | _resetTime(data) {
|
317 | data.totalTime = 0;
|
318 | data.scheduledCellNumber = 0;
|
319 | data.executionStatus = 'idle';
|
320 | data.scheduledCell = new Set();
|
321 | clearTimeout(data.timeout);
|
322 | clearInterval(data.interval);
|
323 | data.needReset = false;
|
324 | }
|
325 | get renderFlag() {
|
326 | return this._renderFlag;
|
327 | }
|
328 | updateRenderOption(options) {
|
329 | if (this.displayOption.showOnToolBar) {
|
330 | if (!options.showOnToolBar) {
|
331 | this._renderFlag = false;
|
332 | }
|
333 | else {
|
334 | this._renderFlag = true;
|
335 | }
|
336 | }
|
337 | this.displayOption.showProgress = options.showProgress;
|
338 | this.stateChanged.emit(void 0);
|
339 | }
|
340 | }
|
341 | ExecutionIndicator.Model = Model;
|
342 | function createExecutionIndicatorItem(panel, translator, loadSettings) {
|
343 | const toolbarItem = new ExecutionIndicator(translator);
|
344 | toolbarItem.model.displayOption = {
|
345 | showOnToolBar: true,
|
346 | showProgress: true
|
347 | };
|
348 | toolbarItem.model.attachNotebook({
|
349 | content: panel.content,
|
350 | context: panel.sessionContext
|
351 | });
|
352 | if (loadSettings) {
|
353 | loadSettings
|
354 | .then(settings => {
|
355 | const updateSettings = (newSettings) => {
|
356 | toolbarItem.model.updateRenderOption(getSettingValue(newSettings));
|
357 | };
|
358 | settings.changed.connect(updateSettings);
|
359 | updateSettings(settings);
|
360 | toolbarItem.disposed.connect(() => {
|
361 | settings.changed.disconnect(updateSettings);
|
362 | });
|
363 | })
|
364 | .catch((reason) => {
|
365 | console.error(reason.message);
|
366 | });
|
367 | }
|
368 | return toolbarItem;
|
369 | }
|
370 | ExecutionIndicator.createExecutionIndicatorItem = createExecutionIndicatorItem;
|
371 | function getSettingValue(settings) {
|
372 | let showOnToolBar = true;
|
373 | let showProgress = true;
|
374 | const configValues = settings.get('kernelStatus').composite;
|
375 | if (configValues) {
|
376 | showOnToolBar = !configValues.showOnStatusBar;
|
377 | showProgress = configValues.showProgress;
|
378 | }
|
379 | return { showOnToolBar, showProgress };
|
380 | }
|
381 | ExecutionIndicator.getSettingValue = getSettingValue;
|
382 | })(ExecutionIndicator || (ExecutionIndicator = {}));
|
383 |
|
\ | No newline at end of file |