jupyterlab-pioneer 0.1.6 → 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 +3 -2
- package/lib/index.js +28 -11
- package/lib/producer.d.ts +29 -24
- package/lib/producer.js +222 -159
- package/lib/types.d.ts +20 -0
- package/lib/types.js +1 -0
- package/package.json +1 -1
- package/lib/router.d.ts +0 -11
- package/lib/router.js +0 -33
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,6 +1,7 @@
|
|
|
1
1
|
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
|
|
2
2
|
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
3
3
|
import { Token } from '@lumino/coreutils';
|
|
4
|
+
import { Exporter } from './types';
|
|
4
5
|
export declare const IJupyterLabPioneer: Token<IJupyterLabPioneer>;
|
|
5
6
|
export interface IJupyterLabPioneer {
|
|
6
7
|
/**
|
|
@@ -10,10 +11,10 @@ export interface IJupyterLabPioneer {
|
|
|
10
11
|
* @param {Object} eventDetail An object containing event details
|
|
11
12
|
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
12
13
|
*/
|
|
13
|
-
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object,
|
|
14
|
+
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object, logWholeNotebook?: Boolean, exporter?: Exporter): Promise<void>;
|
|
14
15
|
}
|
|
15
16
|
declare class JupyterLabPioneer implements IJupyterLabPioneer {
|
|
16
|
-
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object,
|
|
17
|
+
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object, logWholeNotebook?: Boolean, exporter?: Exporter): Promise<void>;
|
|
17
18
|
}
|
|
18
19
|
declare const plugin: JupyterFrontEndPlugin<JupyterLabPioneer>;
|
|
19
20
|
export default plugin;
|
package/lib/index.js
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
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
|
-
async publishEvent(notebookPanel, eventDetail,
|
|
8
|
+
async publishEvent(notebookPanel, eventDetail, logWholeNotebook, exporter) {
|
|
10
9
|
var _a, _b;
|
|
11
10
|
if (!notebookPanel) {
|
|
12
11
|
throw Error('router is listening to a null notebook panel');
|
|
13
12
|
}
|
|
14
|
-
// Construct data
|
|
15
13
|
const requestBody = {
|
|
16
14
|
eventDetail: eventDetail,
|
|
17
15
|
notebookState: {
|
|
18
16
|
sessionID: (_a = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.sessionContext.session) === null || _a === void 0 ? void 0 : _a.id,
|
|
19
17
|
notebookPath: notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.context.path,
|
|
20
|
-
notebookContent:
|
|
18
|
+
notebookContent: logWholeNotebook
|
|
21
19
|
? (_b = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.model) === null || _b === void 0 ? void 0 : _b.toJSON()
|
|
22
20
|
: null // decide whether to log the entire notebook
|
|
23
|
-
}
|
|
21
|
+
},
|
|
22
|
+
exporter: exporter
|
|
24
23
|
};
|
|
25
|
-
// Send data to exporters
|
|
26
24
|
const response = await requestAPI('export', {
|
|
27
25
|
method: 'POST',
|
|
28
26
|
body: JSON.stringify(requestBody)
|
|
@@ -38,15 +36,34 @@ const plugin = {
|
|
|
38
36
|
activate: async (app, notebookTracker) => {
|
|
39
37
|
const version = await requestAPI('version');
|
|
40
38
|
console.log(`${PLUGIN_ID}: ${version}`);
|
|
41
|
-
const config = await requestAPI('config');
|
|
39
|
+
const config = (await requestAPI('config'));
|
|
42
40
|
const pioneer = new JupyterLabPioneer();
|
|
43
41
|
notebookTracker.widgetAdded.connect(async (_, notebookPanel) => {
|
|
42
|
+
var _a;
|
|
44
43
|
await notebookPanel.revealed;
|
|
45
44
|
await notebookPanel.sessionContext.ready;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
+
});
|
|
50
67
|
});
|
|
51
68
|
});
|
|
52
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: 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(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
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(notebookPanel: NotebookPanel, pioneer: IJupyterLabPioneer,
|
|
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,103 +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.publishEvent(notebookPanel, event,
|
|
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.publishEvent(notebookPanel, event,
|
|
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(notebookPanel, pioneer,
|
|
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:
|
|
137
|
+
eventName: CellRemoveEventProducer.id,
|
|
87
138
|
eventTime: Date.now(),
|
|
88
|
-
eventInfo:
|
|
139
|
+
eventInfo: {
|
|
140
|
+
cells: [removedCell]
|
|
141
|
+
}
|
|
89
142
|
};
|
|
90
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
91
144
|
}
|
|
92
145
|
});
|
|
93
146
|
}
|
|
94
147
|
}
|
|
95
|
-
|
|
96
|
-
export {
|
|
148
|
+
CellRemoveEventProducer.id = 'CellRemoveEvent';
|
|
149
|
+
export { CellRemoveEventProducer };
|
|
97
150
|
class ClipboardCopyEventProducer {
|
|
98
|
-
listen(notebookPanel, pioneer,
|
|
151
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
99
152
|
notebookPanel.node.addEventListener('copy', async () => {
|
|
100
|
-
var _a, _b;
|
|
153
|
+
var _a, _b, _c, _d;
|
|
101
154
|
const cell = {
|
|
102
155
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
103
156
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -111,16 +164,16 @@ class ClipboardCopyEventProducer {
|
|
|
111
164
|
selection: text
|
|
112
165
|
}
|
|
113
166
|
};
|
|
114
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
115
168
|
});
|
|
116
169
|
}
|
|
117
170
|
}
|
|
118
171
|
ClipboardCopyEventProducer.id = 'ClipboardCopyEvent';
|
|
119
172
|
export { ClipboardCopyEventProducer };
|
|
120
173
|
class ClipboardCutEventProducer {
|
|
121
|
-
listen(notebookPanel, pioneer,
|
|
174
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
122
175
|
notebookPanel.node.addEventListener('cut', async () => {
|
|
123
|
-
var _a, _b;
|
|
176
|
+
var _a, _b, _c, _d;
|
|
124
177
|
const cell = {
|
|
125
178
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
126
179
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -134,16 +187,16 @@ class ClipboardCutEventProducer {
|
|
|
134
187
|
selection: text
|
|
135
188
|
}
|
|
136
189
|
};
|
|
137
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
138
191
|
});
|
|
139
192
|
}
|
|
140
193
|
}
|
|
141
194
|
ClipboardCutEventProducer.id = 'ClipboardCutEvent';
|
|
142
195
|
export { ClipboardCutEventProducer };
|
|
143
196
|
class ClipboardPasteEventProducer {
|
|
144
|
-
listen(notebookPanel, pioneer,
|
|
197
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
145
198
|
notebookPanel.node.addEventListener('paste', async (e) => {
|
|
146
|
-
var _a;
|
|
199
|
+
var _a, _b, _c;
|
|
147
200
|
const cell = {
|
|
148
201
|
id: (_a = notebookPanel.content.activeCell) === null || _a === void 0 ? void 0 : _a.model.id,
|
|
149
202
|
index: notebookPanel.content.widgets.findIndex(value => value === notebookPanel.content.activeCell)
|
|
@@ -157,131 +210,141 @@ class ClipboardPasteEventProducer {
|
|
|
157
210
|
selection: text
|
|
158
211
|
}
|
|
159
212
|
};
|
|
160
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
161
214
|
});
|
|
162
215
|
}
|
|
163
216
|
}
|
|
164
217
|
ClipboardPasteEventProducer.id = 'ClipboardPasteEvent';
|
|
165
218
|
export { ClipboardPasteEventProducer };
|
|
166
|
-
class
|
|
167
|
-
listen(notebookPanel, pioneer,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
index: notebookPanel.content.widgets.findIndex(value => value === cell)
|
|
173
|
-
};
|
|
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)) {
|
|
174
225
|
const event = {
|
|
175
|
-
eventName:
|
|
226
|
+
eventName: NotebookHiddenEventProducer.id,
|
|
176
227
|
eventTime: Date.now(),
|
|
177
|
-
eventInfo:
|
|
178
|
-
cells: [activatedCell] // activated cell
|
|
179
|
-
}
|
|
228
|
+
eventInfo: null
|
|
180
229
|
};
|
|
181
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
182
231
|
}
|
|
183
232
|
});
|
|
184
233
|
}
|
|
185
234
|
}
|
|
186
|
-
|
|
187
|
-
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 };
|
|
188
258
|
class NotebookSaveEventProducer {
|
|
189
|
-
listen(notebookPanel, pioneer,
|
|
259
|
+
listen(notebookPanel, pioneer, exporter) {
|
|
190
260
|
notebookPanel.context.saveState.connect(async (_, saveState) => {
|
|
261
|
+
var _a, _b;
|
|
191
262
|
if (saveState.match('completed')) {
|
|
192
263
|
const event = {
|
|
193
264
|
eventName: NotebookSaveEventProducer.id,
|
|
194
265
|
eventTime: Date.now(),
|
|
195
266
|
eventInfo: null
|
|
196
267
|
};
|
|
197
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
198
269
|
}
|
|
199
270
|
});
|
|
200
271
|
}
|
|
201
272
|
}
|
|
202
273
|
NotebookSaveEventProducer.id = 'NotebookSaveEvent';
|
|
203
274
|
export { NotebookSaveEventProducer };
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
await pioneer.publishEvent(notebookPanel, event, logNotebookContentEvent);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
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
|
+
}
|
|
224
290
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
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
|
|
303
|
+
const event = {
|
|
304
|
+
eventName: NotebookScrollProducer.id,
|
|
305
|
+
eventTime: Date.now(),
|
|
306
|
+
eventInfo: {
|
|
307
|
+
cells: getVisibleCells(notebookPanel)
|
|
308
|
+
}
|
|
309
|
+
};
|
|
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);
|
|
246
311
|
});
|
|
247
312
|
}
|
|
248
313
|
}
|
|
249
|
-
|
|
250
|
-
export {
|
|
251
|
-
class
|
|
252
|
-
listen(notebookPanel, pioneer,
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
newIndex: args.newIndex,
|
|
258
|
-
oldIndex: args.oldIndex
|
|
259
|
-
};
|
|
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)) {
|
|
260
322
|
const event = {
|
|
261
|
-
eventName:
|
|
323
|
+
eventName: NotebookVisibleEventProducer.id,
|
|
262
324
|
eventTime: Date.now(),
|
|
263
325
|
eventInfo: {
|
|
264
|
-
cells:
|
|
326
|
+
cells: getVisibleCells(notebookPanel)
|
|
265
327
|
}
|
|
266
328
|
};
|
|
267
|
-
await pioneer.publishEvent(notebookPanel, event,
|
|
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);
|
|
268
330
|
}
|
|
269
331
|
});
|
|
270
332
|
}
|
|
271
333
|
}
|
|
272
|
-
|
|
273
|
-
export {
|
|
334
|
+
NotebookVisibleEventProducer.id = 'NotebookVisibleEvent';
|
|
335
|
+
export { NotebookVisibleEventProducer };
|
|
274
336
|
export const producerCollection = [
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
337
|
+
ActiveCellChangeEventProducer,
|
|
338
|
+
CellAddEventProducer,
|
|
339
|
+
CellExecuteEventProducer,
|
|
340
|
+
CellRemoveEventProducer,
|
|
341
|
+
CellEditEventProducer,
|
|
279
342
|
ClipboardCopyEventProducer,
|
|
280
343
|
ClipboardCutEventProducer,
|
|
281
344
|
ClipboardPasteEventProducer,
|
|
282
|
-
|
|
345
|
+
NotebookHiddenEventProducer,
|
|
346
|
+
NotebookOpenEventProducer,
|
|
283
347
|
NotebookSaveEventProducer,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
CellRemoveEventProducer
|
|
348
|
+
NotebookScrollProducer,
|
|
349
|
+
NotebookVisibleEventProducer
|
|
287
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,11 +0,0 @@
|
|
|
1
|
-
import { NotebookPanel } from '@jupyterlab/notebook';
|
|
2
|
-
export declare class Router {
|
|
3
|
-
/**
|
|
4
|
-
* Send event data to exporters defined in the configuration file.
|
|
5
|
-
*
|
|
6
|
-
* @param {NotebookPanel} notebookPanel The notebook panel the extension currently listens to.
|
|
7
|
-
* @param {Object} eventDetail An object containing event details
|
|
8
|
-
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
9
|
-
*/
|
|
10
|
-
publishEvent(notebookPanel: NotebookPanel, eventDetail: Object, logNotebookContent?: Boolean): Promise<void>;
|
|
11
|
-
}
|
package/lib/router.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { requestAPI } from './handler';
|
|
2
|
-
export class Router {
|
|
3
|
-
/**
|
|
4
|
-
* Send event data to exporters defined in the configuration file.
|
|
5
|
-
*
|
|
6
|
-
* @param {NotebookPanel} notebookPanel The notebook panel the extension currently listens to.
|
|
7
|
-
* @param {Object} eventDetail An object containing event details
|
|
8
|
-
* @param {Boolean} logNotebookContent A boolean indicating whether to log the entire notebook or not
|
|
9
|
-
*/
|
|
10
|
-
async publishEvent(notebookPanel, eventDetail, logNotebookContent) {
|
|
11
|
-
var _a, _b;
|
|
12
|
-
if (!notebookPanel) {
|
|
13
|
-
throw Error('router is listening to a null notebook panel');
|
|
14
|
-
}
|
|
15
|
-
// Construct data
|
|
16
|
-
const requestBody = {
|
|
17
|
-
eventDetail: eventDetail,
|
|
18
|
-
notebookState: {
|
|
19
|
-
sessionID: (_a = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.sessionContext.session) === null || _a === void 0 ? void 0 : _a.id,
|
|
20
|
-
notebookPath: notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.context.path,
|
|
21
|
-
notebookContent: logNotebookContent
|
|
22
|
-
? (_b = notebookPanel === null || notebookPanel === void 0 ? void 0 : notebookPanel.model) === null || _b === void 0 ? void 0 : _b.toJSON()
|
|
23
|
-
: null // decide whether to log the entire notebook
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
// Send data to exporters
|
|
27
|
-
const response = await requestAPI('export', {
|
|
28
|
-
method: 'POST',
|
|
29
|
-
body: JSON.stringify(requestBody)
|
|
30
|
-
});
|
|
31
|
-
console.log(response);
|
|
32
|
-
}
|
|
33
|
-
}
|