jupyterlab-pioneer 0.1.5 → 0.1.7
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/README.md +23 -10
- package/lib/index.d.ts +11 -4
- package/lib/index.js +47 -10
- package/lib/producer.d.ts +29 -24
- package/lib/producer.js +221 -154
- package/lib/types.d.ts +20 -0
- package/lib/types.js +1 -0
- package/package.json +1 -1
- package/lib/router.d.ts +0 -18
- package/lib/router.js +0 -45
package/README.md
CHANGED
|
@@ -40,12 +40,12 @@ To add a data exporter, users should assign a callable function along with funct
|
|
|
40
40
|
|
|
41
41
|
This extension provides 4 default exporters.
|
|
42
42
|
|
|
43
|
-
- [`console_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/
|
|
44
|
-
- [`command_line_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/
|
|
45
|
-
- [`file_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/
|
|
46
|
-
- [`remote_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/
|
|
43
|
+
- [`console_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/default_exporters.py#L9), which sends telemetry data to the browser console
|
|
44
|
+
- [`command_line_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/default_exporters.py#L32), which sends telemetry data to the python console jupyter is running on
|
|
45
|
+
- [`file_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/default_exporters.py#L57), which saves telemetry data to local file
|
|
46
|
+
- [`remote_exporter`](https://github.com/educational-technology-collective/jupyterlab-pioneer/blob/main/jupyterlab_pioneer/default_exporters.py#L85), which sends telemetry data to a remote http endpoint
|
|
47
47
|
|
|
48
|
-
Additionally, users can
|
|
48
|
+
Additionally, users can write customized exporters in the configuration file.
|
|
49
49
|
|
|
50
50
|
### Configuration file name & path
|
|
51
51
|
|
|
@@ -57,16 +57,29 @@ Check jupyter server [doc](https://jupyter-server.readthedocs.io/en/latest/opera
|
|
|
57
57
|
|
|
58
58
|
### Syntax
|
|
59
59
|
|
|
60
|
-
`activateEvents`: An array of
|
|
60
|
+
`activateEvents`: An array of active events. Each active event in the array should have the following structure:
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
```python
|
|
63
|
+
{
|
|
64
|
+
'name': string # string, event name
|
|
65
|
+
'logWholeNotebook': # boolean, whether to export the entire notebook content when event is triggered
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The extension would only generate and export data for valid events ( 1. that have an id associated with the event class, 2. and the event name is included in `activeEvents`
|
|
70
|
+
).
|
|
71
|
+
The extension will export the entire notebook content only for valid events with the `logWholeNotebook` flag == True.
|
|
63
72
|
|
|
64
|
-
`exporters`: An array of exporters. Each exporter should have the following structure:
|
|
73
|
+
`exporters`: An array of exporters. Each exporter in the array should have the following structure:
|
|
65
74
|
|
|
66
75
|
```python
|
|
67
76
|
{
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
'type': # one of 'console_exporter', 'command_line_exporter',
|
|
78
|
+
# 'file_exporter', 'remote_exporter',
|
|
79
|
+
# or 'custom_exporter'.
|
|
80
|
+
'args': # arguments passed to the exporter function.
|
|
81
|
+
# It needs to contain 'path' for file_exporter, 'url' for remote_exporter.
|
|
82
|
+
'activeEvents': # exporter's local active_events config will override global activeEvents config
|
|
70
83
|
}
|
|
71
84
|
```
|
|
72
85
|
|
package/lib/index.d.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
2
|
+
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
2
3
|
import { Token } from '@lumino/coreutils';
|
|
3
|
-
import {
|
|
4
|
+
import { Exporter } from './types';
|
|
4
5
|
export declare const IJupyterLabPioneer: Token<IJupyterLabPioneer>;
|
|
5
6
|
export interface IJupyterLabPioneer {
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Send event data to exporters defined in the configuration file.
|
|
9
|
+
*
|
|
10
|
+
* @param {NotebookPanel} notebookPanel The notebook panel the extension currently listens to.
|
|
11
|
+
* @param {Object} eventDetail An object containing event details
|
|
12
|
+
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
13
|
+
*/
|
|
14
|
+
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object, logWholeNotebook?: Boolean, exporter?: Exporter): Promise<void>;
|
|
7
15
|
}
|
|
8
16
|
declare class JupyterLabPioneer implements IJupyterLabPioneer {
|
|
9
|
-
|
|
10
|
-
constructor();
|
|
17
|
+
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object, logWholeNotebook?: Boolean, exporter?: Exporter): Promise<void>;
|
|
11
18
|
}
|
|
12
19
|
declare const plugin: JupyterFrontEndPlugin<JupyterLabPioneer>;
|
|
13
20
|
export default plugin;
|
package/lib/index.js
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
2
2
|
import { Token } from '@lumino/coreutils';
|
|
3
3
|
import { requestAPI } from './handler';
|
|
4
|
-
import { Router } from './router';
|
|
5
4
|
import { producerCollection } from './producer';
|
|
6
5
|
const PLUGIN_ID = 'jupyterlab-pioneer:plugin';
|
|
7
6
|
export const IJupyterLabPioneer = new Token(PLUGIN_ID);
|
|
8
7
|
class JupyterLabPioneer {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
async publishEvent(notebookPanel, eventDetail, logWholeNotebook, exporter) {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
if (!notebookPanel) {
|
|
11
|
+
throw Error('router is listening to a null notebook panel');
|
|
12
|
+
}
|
|
13
|
+
const requestBody = {
|
|
14
|
+
eventDetail: eventDetail,
|
|
15
|
+
notebookState: {
|
|
16
|
+
sessionID: (_a = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.sessionContext.session) === null || _a === void 0 ? void 0 : _a.id,
|
|
17
|
+
notebookPath: notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.context.path,
|
|
18
|
+
notebookContent: logWholeNotebook
|
|
19
|
+
? (_b = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.model) === null || _b === void 0 ? void 0 : _b.toJSON()
|
|
20
|
+
: null // decide whether to log the entire notebook
|
|
21
|
+
},
|
|
22
|
+
exporter: exporter
|
|
23
|
+
};
|
|
24
|
+
const response = await requestAPI('export', {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
body: JSON.stringify(requestBody)
|
|
27
|
+
});
|
|
28
|
+
console.log(response);
|
|
11
29
|
}
|
|
12
30
|
}
|
|
13
31
|
const plugin = {
|
|
@@ -18,15 +36,34 @@ const plugin = {
|
|
|
18
36
|
activate: async (app, notebookTracker) => {
|
|
19
37
|
const version = await requestAPI('version');
|
|
20
38
|
console.log(`${PLUGIN_ID}: ${version}`);
|
|
21
|
-
const config = await requestAPI('config');
|
|
39
|
+
const config = (await requestAPI('config'));
|
|
22
40
|
const pioneer = new JupyterLabPioneer();
|
|
23
41
|
notebookTracker.widgetAdded.connect(async (_, notebookPanel) => {
|
|
24
|
-
|
|
25
|
-
await
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
42
|
+
var _a;
|
|
43
|
+
await notebookPanel.revealed;
|
|
44
|
+
await notebookPanel.sessionContext.ready;
|
|
45
|
+
const activeEvents = config.activeEvents;
|
|
46
|
+
const exporters = ((_a = notebookPanel.content.model) === null || _a === void 0 ? void 0 : _a.getMetadata('exporters')) ||
|
|
47
|
+
config.exporters;
|
|
48
|
+
const processedExporters = activeEvents && activeEvents.length
|
|
49
|
+
? exporters.map(e => {
|
|
50
|
+
if (!e.activeEvents) {
|
|
51
|
+
e.activeEvents = activeEvents;
|
|
52
|
+
return e;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return e;
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
: exporters.filter(e => e.activeEvents && e.activeEvents.length);
|
|
59
|
+
console.log(processedExporters);
|
|
60
|
+
processedExporters.forEach(exporter => {
|
|
61
|
+
producerCollection.forEach(producer => {
|
|
62
|
+
var _a;
|
|
63
|
+
if ((_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.map(o => o.name).includes(producer.id)) {
|
|
64
|
+
new producer().listen(notebookPanel, pioneer, exporter);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
30
67
|
});
|
|
31
68
|
});
|
|
32
69
|
return pioneer;
|
package/lib/producer.d.ts
CHANGED
|
@@ -1,53 +1,58 @@
|
|
|
1
1
|
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
2
2
|
import { IJupyterLabPioneer } from './index';
|
|
3
|
-
|
|
3
|
+
import { Exporter } from './types';
|
|
4
|
+
export declare class ActiveCellChangeEventProducer {
|
|
4
5
|
static id: string;
|
|
5
|
-
|
|
6
|
-
listen(_: NotebookPanel, pioneer: IJupyterLabPioneer, logNotebookContentEvent: boolean): Promise<void>;
|
|
6
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
7
7
|
}
|
|
8
|
-
export declare class
|
|
8
|
+
export declare class CellAddEventProducer {
|
|
9
9
|
static id: string;
|
|
10
|
-
|
|
11
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, logNotebookContentEvent: boolean): void;
|
|
10
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
12
11
|
}
|
|
13
|
-
export declare class
|
|
12
|
+
export declare class CellEditEventProducer {
|
|
14
13
|
static id: string;
|
|
15
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
14
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
16
15
|
}
|
|
17
|
-
export declare class
|
|
16
|
+
export declare class CellExecuteEventProducer {
|
|
17
|
+
static id: string;
|
|
18
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
19
|
+
}
|
|
20
|
+
export declare class CellRemoveEventProducer {
|
|
18
21
|
static id: string;
|
|
19
|
-
listen(
|
|
22
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
20
23
|
}
|
|
21
24
|
export declare class ClipboardCopyEventProducer {
|
|
22
25
|
static id: string;
|
|
23
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
26
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
24
27
|
}
|
|
25
28
|
export declare class ClipboardCutEventProducer {
|
|
26
29
|
static id: string;
|
|
27
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
30
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
28
31
|
}
|
|
29
32
|
export declare class ClipboardPasteEventProducer {
|
|
30
33
|
static id: string;
|
|
31
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
34
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
32
35
|
}
|
|
33
|
-
export declare class
|
|
36
|
+
export declare class NotebookHiddenEventProducer {
|
|
34
37
|
static id: string;
|
|
35
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
38
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
36
39
|
}
|
|
37
|
-
export declare class
|
|
40
|
+
export declare class NotebookOpenEventProducer {
|
|
38
41
|
static id: string;
|
|
39
|
-
|
|
42
|
+
private produced;
|
|
43
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): Promise<void>;
|
|
40
44
|
}
|
|
41
|
-
export declare class
|
|
45
|
+
export declare class NotebookSaveEventProducer {
|
|
42
46
|
static id: string;
|
|
43
|
-
listen(
|
|
47
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
44
48
|
}
|
|
45
|
-
export declare class
|
|
49
|
+
export declare class NotebookScrollProducer {
|
|
46
50
|
static id: string;
|
|
47
|
-
|
|
51
|
+
private timeout;
|
|
52
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
48
53
|
}
|
|
49
|
-
export declare class
|
|
54
|
+
export declare class NotebookVisibleEventProducer {
|
|
50
55
|
static id: string;
|
|
51
|
-
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
56
|
+
listen(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer, exporter: Exporter): void;
|
|
52
57
|
}
|
|
53
|
-
export declare const producerCollection: (typeof
|
|
58
|
+
export declare const producerCollection: (typeof ActiveCellChangeEventProducer)[];
|
package/lib/producer.js
CHANGED
|
@@ -1,102 +1,156 @@
|
|
|
1
1
|
import { NotebookActions } from '@jupyterlab/notebook';
|
|
2
|
+
import { EditorView } from '@codemirror/view';
|
|
2
3
|
import { requestAPI } from './handler';
|
|
3
|
-
class
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
class ActiveCellChangeEventProducer {
|
|
5
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
6
|
+
notebookPanel.content.activeCellChanged.connect(async (_, cell) => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
if (cell && notebookPanel.content.widgets) {
|
|
9
|
+
const activatedCell = {
|
|
10
|
+
id: cell === null || cell === void 0 ? void 0 : cell.model.id,
|
|
11
|
+
index: notebookPanel.content.widgets.findIndex(value => value === cell)
|
|
12
|
+
};
|
|
13
|
+
const event = {
|
|
14
|
+
eventName: ActiveCellChangeEventProducer.id,
|
|
15
|
+
eventTime: Date.now(),
|
|
16
|
+
eventInfo: {
|
|
17
|
+
cells: [activatedCell] // activated cell
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == ActiveCellChangeEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
export {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.timeout = 0;
|
|
25
|
+
ActiveCellChangeEventProducer.id = 'ActiveCellChangeEvent';
|
|
26
|
+
export { ActiveCellChangeEventProducer };
|
|
27
|
+
class CellAddEventProducer {
|
|
28
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
29
|
+
var _a;
|
|
30
|
+
(_a = notebookPanel.content.model) === null || _a === void 0 ? void 0 : _a.cells.changed.connect(async (_, args) => {
|
|
31
|
+
var _a, _b;
|
|
32
|
+
if (args.type === 'add') {
|
|
33
|
+
const addedCell = {
|
|
34
|
+
id: args.newValues[0].id,
|
|
35
|
+
index: args.newIndex
|
|
36
|
+
};
|
|
37
|
+
const event = {
|
|
38
|
+
eventName: CellAddEventProducer.id,
|
|
39
|
+
eventTime: Date.now(),
|
|
40
|
+
eventInfo: {
|
|
41
|
+
cells: [addedCell]
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == CellAddEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
44
47
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
}
|
|
49
|
+
CellAddEventProducer.id = 'CellAddEvent';
|
|
50
|
+
export { CellAddEventProducer };
|
|
51
|
+
class CellEditEventProducer {
|
|
52
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
const sendDoc = async (_, cell) => {
|
|
55
|
+
var _a, _b, _c, _d;
|
|
56
|
+
await (cell === null || cell === void 0 ? void 0 : cell.ready); // wait until cell is ready, to prevent errors when creating new cells
|
|
57
|
+
const editor = cell === null || cell === void 0 ? void 0 : cell.editor;
|
|
50
58
|
const event = {
|
|
51
|
-
eventName:
|
|
59
|
+
eventName: CellEditEventProducer.id,
|
|
52
60
|
eventTime: Date.now(),
|
|
53
61
|
eventInfo: {
|
|
54
|
-
|
|
62
|
+
index: notebookPanel.content.widgets.findIndex(value => value === cell),
|
|
63
|
+
doc: (_b = (_a = editor === null || editor === void 0 ? void 0 : editor.state) === null || _a === void 0 ? void 0 : _a.doc) === null || _b === void 0 ? void 0 : _b.toJSON() // send entire cell content if this is a new cell
|
|
55
64
|
}
|
|
56
65
|
};
|
|
57
|
-
await pioneer.
|
|
58
|
-
}
|
|
66
|
+
await pioneer.publishEvent(notebookPanel, event, (_d = (_c = exporter.activeEvents) === null || _c === void 0 ? void 0 : _c.find(o => o.name == CellEditEventProducer.id)) === null || _d === void 0 ? void 0 : _d.logWholeNotebook, exporter);
|
|
67
|
+
};
|
|
68
|
+
const addDocChangeListener = async (cell) => {
|
|
69
|
+
await (cell === null || cell === void 0 ? void 0 : cell.ready); // wait until cell is ready, to prevent errors when creating new cells
|
|
70
|
+
const editor = cell === null || cell === void 0 ? void 0 : cell.editor;
|
|
71
|
+
editor === null || editor === void 0 ? void 0 : editor.injectExtension(EditorView.updateListener.of(async (v) => {
|
|
72
|
+
if (v.docChanged) {
|
|
73
|
+
const event = {
|
|
74
|
+
eventName: CellEditEventProducer.id,
|
|
75
|
+
eventTime: Date.now(),
|
|
76
|
+
eventInfo: {
|
|
77
|
+
index: notebookPanel.content.widgets.findIndex(value => value === cell),
|
|
78
|
+
changes: v.changes.toJSON() // send changes
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
await pioneer.publishEvent(notebookPanel, event, false, // do not log whole notebook for doc changes
|
|
82
|
+
exporter);
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
85
|
+
};
|
|
86
|
+
(_a = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.content) === null || _a === void 0 ? void 0 : _a.widgets.forEach(cell => {
|
|
87
|
+
addDocChangeListener(cell);
|
|
88
|
+
}); // add listener to existing cells
|
|
89
|
+
sendDoc(notebookPanel.content, notebookPanel.content.activeCell); // send initial active cell content
|
|
90
|
+
(_b = notebookPanel.content.model) === null || _b === void 0 ? void 0 : _b.cells.changed.connect(async (_, args) => {
|
|
91
|
+
var _a;
|
|
92
|
+
if (args.type === 'add') {
|
|
93
|
+
addDocChangeListener((_a = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.content) === null || _a === void 0 ? void 0 : _a.widgets[args.newIndex]);
|
|
94
|
+
}
|
|
95
|
+
}); // add doc change listener to cells created after initialization
|
|
96
|
+
notebookPanel.content.activeCellChanged.connect(sendDoc); // send active cell content when active cell changes
|
|
59
97
|
}
|
|
60
98
|
}
|
|
61
|
-
|
|
62
|
-
export {
|
|
63
|
-
class
|
|
64
|
-
listen(notebookPanel, pioneer,
|
|
65
|
-
|
|
66
|
-
|
|
99
|
+
CellEditEventProducer.id = 'CellEditEvent';
|
|
100
|
+
export { CellEditEventProducer };
|
|
101
|
+
class CellExecuteEventProducer {
|
|
102
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
103
|
+
NotebookActions.executed.connect(async (_, args) => {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
if (notebookPanel.content === args.notebook) {
|
|
106
|
+
const executedCell = {
|
|
107
|
+
id: args.cell.model.id,
|
|
108
|
+
index: args.notebook.widgets.findIndex(value => value == args.cell)
|
|
109
|
+
};
|
|
67
110
|
const event = {
|
|
68
|
-
eventName:
|
|
111
|
+
eventName: CellExecuteEventProducer.id,
|
|
69
112
|
eventTime: Date.now(),
|
|
70
113
|
eventInfo: {
|
|
71
|
-
cells:
|
|
114
|
+
cells: [executedCell],
|
|
115
|
+
success: args.success,
|
|
116
|
+
kernelError: args.success ? null : args.error
|
|
72
117
|
}
|
|
73
118
|
};
|
|
74
|
-
await pioneer.
|
|
119
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == CellExecuteEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
75
120
|
}
|
|
76
121
|
});
|
|
77
122
|
}
|
|
78
123
|
}
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
class
|
|
82
|
-
listen(
|
|
83
|
-
|
|
84
|
-
|
|
124
|
+
CellExecuteEventProducer.id = 'CellExecuteEvent';
|
|
125
|
+
export { CellExecuteEventProducer };
|
|
126
|
+
class CellRemoveEventProducer {
|
|
127
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
128
|
+
var _a;
|
|
129
|
+
(_a = notebookPanel.content.model) === null || _a === void 0 ? void 0 : _a.cells.changed.connect(async (_, args) => {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
if (args.type === 'remove') {
|
|
132
|
+
const removedCell = {
|
|
133
|
+
newIndex: args.newIndex,
|
|
134
|
+
oldIndex: args.oldIndex
|
|
135
|
+
};
|
|
85
136
|
const event = {
|
|
86
|
-
eventName:
|
|
87
|
-
eventTime: Date.now()
|
|
137
|
+
eventName: CellRemoveEventProducer.id,
|
|
138
|
+
eventTime: Date.now(),
|
|
139
|
+
eventInfo: {
|
|
140
|
+
cells: [removedCell]
|
|
141
|
+
}
|
|
88
142
|
};
|
|
89
|
-
await pioneer.
|
|
143
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == CellRemoveEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
90
144
|
}
|
|
91
145
|
});
|
|
92
146
|
}
|
|
93
147
|
}
|
|
94
|
-
|
|
95
|
-
export {
|
|
148
|
+
CellRemoveEventProducer.id = 'CellRemoveEvent';
|
|
149
|
+
export { CellRemoveEventProducer };
|
|
96
150
|
class ClipboardCopyEventProducer {
|
|
97
|
-
listen(notebookPanel, pioneer,
|
|
151
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
98
152
|
notebookPanel.node.addEventListener('copy', async () => {
|
|
99
|
-
var _a, _b;
|
|
153
|
+
var _a, _b, _c, _d;
|
|
100
154
|
const cell = {
|
|
101
155
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
102
156
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -110,16 +164,16 @@ class ClipboardCopyEventProducer {
|
|
|
110
164
|
selection: text
|
|
111
165
|
}
|
|
112
166
|
};
|
|
113
|
-
await pioneer.
|
|
167
|
+
await pioneer.publishEvent(notebookPanel, event, (_d = (_c = exporter.activeEvents) === null || _c === void 0 ? void 0 : _c.find(o => o.name == ClipboardCopyEventProducer.id)) === null || _d === void 0 ? void 0 : _d.logWholeNotebook, exporter);
|
|
114
168
|
});
|
|
115
169
|
}
|
|
116
170
|
}
|
|
117
171
|
ClipboardCopyEventProducer.id = 'ClipboardCopyEvent';
|
|
118
172
|
export { ClipboardCopyEventProducer };
|
|
119
173
|
class ClipboardCutEventProducer {
|
|
120
|
-
listen(notebookPanel, pioneer,
|
|
174
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
121
175
|
notebookPanel.node.addEventListener('cut', async () => {
|
|
122
|
-
var _a, _b;
|
|
176
|
+
var _a, _b, _c, _d;
|
|
123
177
|
const cell = {
|
|
124
178
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
125
179
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -133,16 +187,16 @@ class ClipboardCutEventProducer {
|
|
|
133
187
|
selection: text
|
|
134
188
|
}
|
|
135
189
|
};
|
|
136
|
-
await pioneer.
|
|
190
|
+
await pioneer.publishEvent(notebookPanel, event, (_d = (_c = exporter.activeEvents) === null || _c === void 0 ? void 0 : _c.find(o => o.name == ClipboardCutEventProducer.id)) === null || _d === void 0 ? void 0 : _d.logWholeNotebook, exporter);
|
|
137
191
|
});
|
|
138
192
|
}
|
|
139
193
|
}
|
|
140
194
|
ClipboardCutEventProducer.id = 'ClipboardCutEvent';
|
|
141
195
|
export { ClipboardCutEventProducer };
|
|
142
196
|
class ClipboardPasteEventProducer {
|
|
143
|
-
listen(notebookPanel, pioneer,
|
|
197
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
144
198
|
notebookPanel.node.addEventListener('paste', async (e) => {
|
|
145
|
-
var _a;
|
|
199
|
+
var _a, _b, _c;
|
|
146
200
|
const cell = {
|
|
147
201
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
148
202
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -156,128 +210,141 @@ class ClipboardPasteEventProducer {
|
|
|
156
210
|
selection: text
|
|
157
211
|
}
|
|
158
212
|
};
|
|
159
|
-
await pioneer.
|
|
213
|
+
await pioneer.publishEvent(notebookPanel, event, (_c = (_b = exporter.activeEvents) === null || _b === void 0 ? void 0 : _b.find(o => o.name == ClipboardPasteEventProducer.id)) === null || _c === void 0 ? void 0 : _c.logWholeNotebook, exporter);
|
|
160
214
|
});
|
|
161
215
|
}
|
|
162
216
|
}
|
|
163
217
|
ClipboardPasteEventProducer.id = 'ClipboardPasteEvent';
|
|
164
218
|
export { ClipboardPasteEventProducer };
|
|
165
|
-
class
|
|
166
|
-
listen(notebookPanel, pioneer,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
index: notebookPanel.content.widgets.findIndex(value => value === cell)
|
|
172
|
-
};
|
|
219
|
+
class NotebookHiddenEventProducer {
|
|
220
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
221
|
+
document.addEventListener('visibilitychange', async (e) => {
|
|
222
|
+
var _a, _b;
|
|
223
|
+
if (document.visibilityState === 'hidden' &&
|
|
224
|
+
document.contains(notebookPanel.node)) {
|
|
173
225
|
const event = {
|
|
174
|
-
eventName:
|
|
226
|
+
eventName: NotebookHiddenEventProducer.id,
|
|
175
227
|
eventTime: Date.now(),
|
|
176
|
-
eventInfo:
|
|
177
|
-
cells: [activatedCell] // activated cell
|
|
178
|
-
}
|
|
228
|
+
eventInfo: null
|
|
179
229
|
};
|
|
180
|
-
await pioneer.
|
|
230
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == NotebookHiddenEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
181
231
|
}
|
|
182
232
|
});
|
|
183
233
|
}
|
|
184
234
|
}
|
|
185
|
-
|
|
186
|
-
export {
|
|
235
|
+
NotebookHiddenEventProducer.id = 'NotebookHiddenEvent';
|
|
236
|
+
export { NotebookHiddenEventProducer };
|
|
237
|
+
class NotebookOpenEventProducer {
|
|
238
|
+
constructor() {
|
|
239
|
+
this.produced = false;
|
|
240
|
+
}
|
|
241
|
+
async listen(notebookPanel, pioneer, exporter) {
|
|
242
|
+
var _a, _b;
|
|
243
|
+
if (!this.produced) {
|
|
244
|
+
const event = {
|
|
245
|
+
eventName: NotebookOpenEventProducer.id,
|
|
246
|
+
eventTime: Date.now(),
|
|
247
|
+
eventInfo: {
|
|
248
|
+
environ: await requestAPI('environ')
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == NotebookOpenEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
252
|
+
this.produced = true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
NotebookOpenEventProducer.id = 'NotebookOpenEvent';
|
|
257
|
+
export { NotebookOpenEventProducer };
|
|
187
258
|
class NotebookSaveEventProducer {
|
|
188
|
-
listen(notebookPanel, pioneer,
|
|
259
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
189
260
|
notebookPanel.context.saveState.connect(async (_, saveState) => {
|
|
261
|
+
var _a, _b;
|
|
190
262
|
if (saveState.match('completed')) {
|
|
191
263
|
const event = {
|
|
192
264
|
eventName: NotebookSaveEventProducer.id,
|
|
193
|
-
eventTime: Date.now()
|
|
265
|
+
eventTime: Date.now(),
|
|
266
|
+
eventInfo: null
|
|
194
267
|
};
|
|
195
|
-
await pioneer.
|
|
268
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == NotebookSaveEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
196
269
|
}
|
|
197
270
|
});
|
|
198
271
|
}
|
|
199
272
|
}
|
|
200
273
|
NotebookSaveEventProducer.id = 'NotebookSaveEvent';
|
|
201
274
|
export { NotebookSaveEventProducer };
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
275
|
+
const getVisibleCells = (notebookPanel) => {
|
|
276
|
+
const visibleCells = [];
|
|
277
|
+
for (let index = 0; index < notebookPanel.content.widgets.length; index++) {
|
|
278
|
+
const cell = notebookPanel.content.widgets[index];
|
|
279
|
+
const cellTop = cell.node.offsetTop;
|
|
280
|
+
const cellBottom = cell.node.offsetTop + cell.node.offsetHeight;
|
|
281
|
+
const viewTop = notebookPanel.content.node.scrollTop;
|
|
282
|
+
const viewBottom = notebookPanel.content.node.scrollTop +
|
|
283
|
+
notebookPanel.content.node.clientHeight;
|
|
284
|
+
if (cellTop <= viewBottom && cellBottom >= viewTop) {
|
|
285
|
+
visibleCells.push({
|
|
286
|
+
id: cell.model.id,
|
|
287
|
+
index: index
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return visibleCells;
|
|
292
|
+
};
|
|
293
|
+
class NotebookScrollProducer {
|
|
294
|
+
constructor() {
|
|
295
|
+
this.timeout = 0;
|
|
296
|
+
}
|
|
297
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
298
|
+
notebookPanel.content.node.addEventListener('scroll', async (e) => {
|
|
299
|
+
var _a, _b;
|
|
300
|
+
e.stopPropagation();
|
|
301
|
+
clearTimeout(this.timeout);
|
|
302
|
+
await new Promise(resolve => (this.timeout = window.setTimeout(resolve, 1500))); // wait 1.5 seconds before preceding
|
|
209
303
|
const event = {
|
|
210
|
-
eventName:
|
|
304
|
+
eventName: NotebookScrollProducer.id,
|
|
211
305
|
eventTime: Date.now(),
|
|
212
306
|
eventInfo: {
|
|
213
|
-
cells:
|
|
214
|
-
success: args.success,
|
|
215
|
-
kernelError: args.success ? null : args.error
|
|
307
|
+
cells: getVisibleCells(notebookPanel)
|
|
216
308
|
}
|
|
217
309
|
};
|
|
218
|
-
await pioneer.
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
CellExecuteEventProducer.id = 'CellExecuteEvent';
|
|
223
|
-
export { CellExecuteEventProducer };
|
|
224
|
-
class CellAddEventProducer {
|
|
225
|
-
listen(notebookPanel, pioneer, logNotebookContentEvent) {
|
|
226
|
-
var _a;
|
|
227
|
-
(_a = notebookPanel.content.model) === null || _a === void 0 ? void 0 : _a.cells.changed.connect(async (_, args) => {
|
|
228
|
-
if (args.type === 'add') {
|
|
229
|
-
const addedCell = {
|
|
230
|
-
id: args.newValues[0].id,
|
|
231
|
-
index: args.newIndex
|
|
232
|
-
};
|
|
233
|
-
const event = {
|
|
234
|
-
eventName: CellAddEventProducer.id,
|
|
235
|
-
eventTime: Date.now(),
|
|
236
|
-
eventInfo: {
|
|
237
|
-
cells: [addedCell]
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
await pioneer.router.publishEvent(event, logNotebookContentEvent);
|
|
241
|
-
}
|
|
310
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == NotebookScrollProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
242
311
|
});
|
|
243
312
|
}
|
|
244
313
|
}
|
|
245
|
-
|
|
246
|
-
export {
|
|
247
|
-
class
|
|
248
|
-
listen(notebookPanel, pioneer,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (
|
|
252
|
-
|
|
253
|
-
newIndex: args.newIndex,
|
|
254
|
-
oldIndex: args.oldIndex
|
|
255
|
-
};
|
|
314
|
+
NotebookScrollProducer.id = 'NotebookScrollEvent';
|
|
315
|
+
export { NotebookScrollProducer };
|
|
316
|
+
class NotebookVisibleEventProducer {
|
|
317
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
318
|
+
document.addEventListener('visibilitychange', async () => {
|
|
319
|
+
var _a, _b;
|
|
320
|
+
if (document.visibilityState === 'visible' &&
|
|
321
|
+
document.contains(notebookPanel.node)) {
|
|
256
322
|
const event = {
|
|
257
|
-
eventName:
|
|
323
|
+
eventName: NotebookVisibleEventProducer.id,
|
|
258
324
|
eventTime: Date.now(),
|
|
259
325
|
eventInfo: {
|
|
260
|
-
cells:
|
|
326
|
+
cells: getVisibleCells(notebookPanel)
|
|
261
327
|
}
|
|
262
328
|
};
|
|
263
|
-
await pioneer.
|
|
329
|
+
await pioneer.publishEvent(notebookPanel, event, (_b = (_a = exporter.activeEvents) === null || _a === void 0 ? void 0 : _a.find(o => o.name == NotebookVisibleEventProducer.id)) === null || _b === void 0 ? void 0 : _b.logWholeNotebook, exporter);
|
|
264
330
|
}
|
|
265
331
|
});
|
|
266
332
|
}
|
|
267
333
|
}
|
|
268
|
-
|
|
269
|
-
export {
|
|
334
|
+
NotebookVisibleEventProducer.id = 'NotebookVisibleEvent';
|
|
335
|
+
export { NotebookVisibleEventProducer };
|
|
270
336
|
export const producerCollection = [
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
337
|
+
ActiveCellChangeEventProducer,
|
|
338
|
+
CellAddEventProducer,
|
|
339
|
+
CellExecuteEventProducer,
|
|
340
|
+
CellRemoveEventProducer,
|
|
341
|
+
CellEditEventProducer,
|
|
275
342
|
ClipboardCopyEventProducer,
|
|
276
343
|
ClipboardCutEventProducer,
|
|
277
344
|
ClipboardPasteEventProducer,
|
|
278
|
-
|
|
345
|
+
NotebookHiddenEventProducer,
|
|
346
|
+
NotebookOpenEventProducer,
|
|
279
347
|
NotebookSaveEventProducer,
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
CellRemoveEventProducer
|
|
348
|
+
NotebookScrollProducer,
|
|
349
|
+
NotebookVisibleEventProducer
|
|
283
350
|
];
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ActiveEvent {
|
|
2
|
+
name: string;
|
|
3
|
+
logWholeNotebook: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface ExporterArgs {
|
|
6
|
+
id: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
params?: Object;
|
|
9
|
+
path?: string;
|
|
10
|
+
env?: Object[];
|
|
11
|
+
}
|
|
12
|
+
export interface Exporter {
|
|
13
|
+
type: string;
|
|
14
|
+
args?: ExporterArgs;
|
|
15
|
+
activeEvents?: ActiveEvent[];
|
|
16
|
+
}
|
|
17
|
+
export interface Config {
|
|
18
|
+
activeEvents: ActiveEvent[];
|
|
19
|
+
exporters: Exporter[];
|
|
20
|
+
}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
package/lib/router.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
2
|
-
export declare class Router {
|
|
3
|
-
private sessionID?;
|
|
4
|
-
private notebookPanel?;
|
|
5
|
-
/**
|
|
6
|
-
* Load notebookPanel.
|
|
7
|
-
*
|
|
8
|
-
* @param {NotebookPanel} notebookPanel
|
|
9
|
-
*/
|
|
10
|
-
loadNotebookPanel(notebookPanel: NotebookPanel): Promise<void>;
|
|
11
|
-
/**
|
|
12
|
-
* Send event data to exporters defined in the configuration file.
|
|
13
|
-
*
|
|
14
|
-
* @param {Object} eventDetail An object containing event details
|
|
15
|
-
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
16
|
-
*/
|
|
17
|
-
publishEvent(eventDetail: Object, logNotebookContent?: Boolean): Promise<void>;
|
|
18
|
-
}
|
package/lib/router.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { requestAPI } from './handler';
|
|
2
|
-
export class Router {
|
|
3
|
-
/**
|
|
4
|
-
* Load notebookPanel.
|
|
5
|
-
*
|
|
6
|
-
* @param {NotebookPanel} notebookPanel
|
|
7
|
-
*/
|
|
8
|
-
async loadNotebookPanel(notebookPanel) {
|
|
9
|
-
this.notebookPanel = notebookPanel;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Send event data to exporters defined in the configuration file.
|
|
13
|
-
*
|
|
14
|
-
* @param {Object} eventDetail An object containing event details
|
|
15
|
-
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
16
|
-
*/
|
|
17
|
-
async publishEvent(eventDetail, logNotebookContent) {
|
|
18
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
19
|
-
if (!this.notebookPanel) {
|
|
20
|
-
throw Error('router needs to load notebookPanel first.');
|
|
21
|
-
}
|
|
22
|
-
// Check if session id received is equal to the stored session id
|
|
23
|
-
if (!this.sessionID ||
|
|
24
|
-
this.sessionID !== ((_b = (_a = this.notebookPanel) === null || _a === void 0 ? void 0 : _a.sessionContext.session) === null || _b === void 0 ? void 0 : _b.id)) {
|
|
25
|
-
this.sessionID = (_d = (_c = this.notebookPanel) === null || _c === void 0 ? void 0 : _c.sessionContext.session) === null || _d === void 0 ? void 0 : _d.id;
|
|
26
|
-
}
|
|
27
|
-
// Construct data
|
|
28
|
-
const requestBody = {
|
|
29
|
-
eventDetail: eventDetail,
|
|
30
|
-
notebookState: {
|
|
31
|
-
sessionID: this.sessionID,
|
|
32
|
-
notebookPath: (_e = this.notebookPanel) === null || _e === void 0 ? void 0 : _e.context.path,
|
|
33
|
-
notebookContent: logNotebookContent
|
|
34
|
-
? (_g = (_f = this.notebookPanel) === null || _f === void 0 ? void 0 : _f.model) === null || _g === void 0 ? void 0 : _g.toJSON()
|
|
35
|
-
: null // decide whether to log the entire notebook
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
// Send data to exporters
|
|
39
|
-
const response = await requestAPI('export', {
|
|
40
|
-
method: 'POST',
|
|
41
|
-
body: JSON.stringify(requestBody)
|
|
42
|
-
});
|
|
43
|
-
console.log(response);
|
|
44
|
-
}
|
|
45
|
-
}
|