jupyterlab-ipyflow 0.0.86
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/lib/index.d.ts +6 -0
- package/lib/index.js +366 -0
- package/package.json +69 -0
- package/style/index.css +64 -0
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { CodeCell } from '@jupyterlab/cells';
|
|
2
|
+
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
3
|
+
const IPYFLOW_KERNEL_NAME = 'ipyflow';
|
|
4
|
+
/**
|
|
5
|
+
* Initialization data for the jupyterlab-ipyflow extension.
|
|
6
|
+
*/
|
|
7
|
+
const extension = {
|
|
8
|
+
id: 'jupyterlab-ipyflow',
|
|
9
|
+
requires: [INotebookTracker],
|
|
10
|
+
autoStart: true,
|
|
11
|
+
activate: (app, notebooks) => {
|
|
12
|
+
notebooks.widgetAdded.connect((sender, nbPanel) => {
|
|
13
|
+
const session = nbPanel.sessionContext;
|
|
14
|
+
session.ready.then(() => {
|
|
15
|
+
clearCellState(nbPanel.content);
|
|
16
|
+
activeCell = nbPanel.content.activeCell;
|
|
17
|
+
activeCellId = nbPanel.content.activeCell.model.id;
|
|
18
|
+
let commDisconnectHandler = () => { };
|
|
19
|
+
if (session.session.kernel.name === IPYFLOW_KERNEL_NAME) {
|
|
20
|
+
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
21
|
+
}
|
|
22
|
+
session.kernelChanged.connect((_, args) => {
|
|
23
|
+
clearCellState(nbPanel.content);
|
|
24
|
+
commDisconnectHandler();
|
|
25
|
+
commDisconnectHandler = () => { };
|
|
26
|
+
if (args.newValue !== null && args.newValue.name === IPYFLOW_KERNEL_NAME) {
|
|
27
|
+
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
let shouldReconnect = false;
|
|
31
|
+
session.statusChanged.connect((session, status) => {
|
|
32
|
+
if (status === 'restarting' || status === 'autorestarting') {
|
|
33
|
+
shouldReconnect = true;
|
|
34
|
+
}
|
|
35
|
+
if ((status === 'idle' || status === 'busy') && shouldReconnect) {
|
|
36
|
+
shouldReconnect = false;
|
|
37
|
+
session.ready.then(() => {
|
|
38
|
+
clearCellState(nbPanel.content);
|
|
39
|
+
commDisconnectHandler();
|
|
40
|
+
commDisconnectHandler = () => { };
|
|
41
|
+
if (session.session.kernel.name === IPYFLOW_KERNEL_NAME) {
|
|
42
|
+
commDisconnectHandler = connectToComm(session, nbPanel.content);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const staleClass = 'stale-cell';
|
|
52
|
+
const freshClass = 'fresh-cell';
|
|
53
|
+
const refresherClass = 'refresher-cell';
|
|
54
|
+
const refresherInputClass = 'refresher-input-cell';
|
|
55
|
+
const linkedStaleClass = 'linked-stale';
|
|
56
|
+
const linkedRefresherClass = 'linked-refresher';
|
|
57
|
+
let dirtyCells = new Set();
|
|
58
|
+
let staleCells = new Set();
|
|
59
|
+
let freshCells = new Set();
|
|
60
|
+
let staleLinks = {};
|
|
61
|
+
let refresherLinks = {};
|
|
62
|
+
let activeCell = null;
|
|
63
|
+
let activeCellId = null;
|
|
64
|
+
let cellsById = {};
|
|
65
|
+
let orderIdxById = {};
|
|
66
|
+
let cellPendingExecution = null;
|
|
67
|
+
let lastExecutionMode = null;
|
|
68
|
+
let lastExecutionHighlightsEnabled = null;
|
|
69
|
+
let executedReactiveFreshCells = new Set();
|
|
70
|
+
let newFreshCells = new Set();
|
|
71
|
+
let forcedReactiveCells = new Set();
|
|
72
|
+
const cleanup = new Event('cleanup');
|
|
73
|
+
const getJpInputCollapser = (elem) => {
|
|
74
|
+
if (elem === null || elem === undefined) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const child = elem.children.item(1);
|
|
78
|
+
if (child === null) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return child.firstElementChild;
|
|
82
|
+
};
|
|
83
|
+
const getJpOutputCollapser = (elem) => {
|
|
84
|
+
if (elem === null || elem === undefined) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const child = elem.children.item(2);
|
|
88
|
+
if (child === null) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return child.firstElementChild;
|
|
92
|
+
};
|
|
93
|
+
const attachCleanupListener = (elem, evt, listener) => {
|
|
94
|
+
const cleanupListener = () => {
|
|
95
|
+
elem.removeEventListener(evt, listener);
|
|
96
|
+
elem.removeEventListener('cleanup', cleanupListener);
|
|
97
|
+
};
|
|
98
|
+
elem.addEventListener(evt, listener);
|
|
99
|
+
elem.addEventListener('cleanup', cleanupListener);
|
|
100
|
+
};
|
|
101
|
+
const addStaleOutputInteraction = (elem, linkedElem, evt, add_or_remove, css) => {
|
|
102
|
+
if (elem === null || linkedElem === null) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const listener = () => {
|
|
106
|
+
linkedElem.firstElementChild.classList[add_or_remove](css);
|
|
107
|
+
};
|
|
108
|
+
attachCleanupListener(elem, evt, listener);
|
|
109
|
+
};
|
|
110
|
+
const addStaleOutputInteractions = (elem, linkedInputClass) => {
|
|
111
|
+
addStaleOutputInteraction(getJpInputCollapser(elem), getJpOutputCollapser(elem), 'mouseover', 'add', linkedStaleClass);
|
|
112
|
+
addStaleOutputInteraction(getJpInputCollapser(elem), getJpOutputCollapser(elem), 'mouseout', 'remove', linkedStaleClass);
|
|
113
|
+
addStaleOutputInteraction(getJpOutputCollapser(elem), getJpInputCollapser(elem), 'mouseover', 'add', linkedInputClass);
|
|
114
|
+
addStaleOutputInteraction(getJpOutputCollapser(elem), getJpInputCollapser(elem), 'mouseout', 'remove', linkedInputClass);
|
|
115
|
+
};
|
|
116
|
+
const refreshNodeMapping = (notebook) => {
|
|
117
|
+
cellsById = {};
|
|
118
|
+
orderIdxById = {};
|
|
119
|
+
notebook.widgets.forEach((cell, idx) => {
|
|
120
|
+
cellsById[cell.model.id] = cell.node;
|
|
121
|
+
orderIdxById[cell.model.id] = idx;
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
const clearCellState = (notebook) => {
|
|
125
|
+
notebook.widgets.forEach((cell, idx) => {
|
|
126
|
+
cell.node.classList.remove(staleClass);
|
|
127
|
+
cell.node.classList.remove(refresherClass);
|
|
128
|
+
cell.node.classList.remove(freshClass);
|
|
129
|
+
cell.node.classList.remove(refresherInputClass);
|
|
130
|
+
// clear any old event listeners
|
|
131
|
+
const inputCollapser = getJpInputCollapser(cell.node);
|
|
132
|
+
if (inputCollapser !== null) {
|
|
133
|
+
inputCollapser.firstElementChild.classList.remove(linkedStaleClass);
|
|
134
|
+
inputCollapser.firstElementChild.classList.remove(linkedRefresherClass);
|
|
135
|
+
inputCollapser.dispatchEvent(cleanup);
|
|
136
|
+
}
|
|
137
|
+
const outputCollapser = getJpOutputCollapser(cell.node);
|
|
138
|
+
if (outputCollapser !== null) {
|
|
139
|
+
outputCollapser.firstElementChild.classList.remove(linkedStaleClass);
|
|
140
|
+
outputCollapser.firstElementChild.classList.remove(linkedRefresherClass);
|
|
141
|
+
outputCollapser.dispatchEvent(cleanup);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
const addUnsafeCellInteraction = (elem, linkedElems, cellsById, collapserFun, evt, add_or_remove, staleCells) => {
|
|
146
|
+
if (elem === null) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const listener = () => {
|
|
150
|
+
for (const linkedId of linkedElems) {
|
|
151
|
+
let css = linkedRefresherClass;
|
|
152
|
+
if (staleCells.has(linkedId)) {
|
|
153
|
+
css = linkedStaleClass;
|
|
154
|
+
}
|
|
155
|
+
const collapser = collapserFun(cellsById[linkedId]);
|
|
156
|
+
if (collapser === null || collapser.firstElementChild === null) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
collapser.firstElementChild.classList[add_or_remove](css);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
elem.addEventListener(evt, listener);
|
|
163
|
+
attachCleanupListener(elem, evt, listener);
|
|
164
|
+
};
|
|
165
|
+
const connectToComm = (session, notebook) => {
|
|
166
|
+
const comm = session.session.kernel.createComm('ipyflow');
|
|
167
|
+
let disconnected = false;
|
|
168
|
+
const onExecution = (cell, args) => {
|
|
169
|
+
if (disconnected) {
|
|
170
|
+
cell.stateChanged.disconnect(onExecution);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (args.name !== 'executionCount' || args.newValue === null) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const order_index_by_cell_id = {};
|
|
177
|
+
notebook.widgets.forEach((itercell, idx) => {
|
|
178
|
+
order_index_by_cell_id[itercell.model.id] = idx;
|
|
179
|
+
if (itercell.model.id === cell.id) {
|
|
180
|
+
itercell.node.classList.remove(freshClass);
|
|
181
|
+
itercell.node.classList.remove(refresherInputClass);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
const payload = {
|
|
185
|
+
type: 'cell_freshness',
|
|
186
|
+
executed_cell_id: cell.id,
|
|
187
|
+
order_index_by_cell_id: order_index_by_cell_id,
|
|
188
|
+
};
|
|
189
|
+
comm.send(payload).done.then(() => {
|
|
190
|
+
if (cellPendingExecution !== null) {
|
|
191
|
+
CodeCell.execute(cellPendingExecution, session);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
if (lastExecutionMode === 'reactive') {
|
|
195
|
+
freshCells = executedReactiveFreshCells;
|
|
196
|
+
updateUI(notebook);
|
|
197
|
+
}
|
|
198
|
+
newFreshCells = new Set();
|
|
199
|
+
forcedReactiveCells = new Set();
|
|
200
|
+
executedReactiveFreshCells = new Set();
|
|
201
|
+
comm.send({
|
|
202
|
+
type: 'reactivity_cleanup',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
const notifyActiveCell = (newActiveCell) => {
|
|
208
|
+
let newActiveCellOrderIdx = -1;
|
|
209
|
+
notebook.widgets.forEach((itercell, idx) => {
|
|
210
|
+
if (itercell.model.id === newActiveCell.id) {
|
|
211
|
+
newActiveCellOrderIdx = idx;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
const payload = {
|
|
215
|
+
type: 'change_active_cell',
|
|
216
|
+
active_cell_id: newActiveCell.id,
|
|
217
|
+
active_cell_order_idx: newActiveCellOrderIdx
|
|
218
|
+
};
|
|
219
|
+
comm.send(payload);
|
|
220
|
+
};
|
|
221
|
+
const onActiveCellChange = (nb, cell) => {
|
|
222
|
+
if (notebook !== nb) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (disconnected) {
|
|
226
|
+
notebook.activeCellChanged.disconnect(onActiveCellChange);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
notifyActiveCell(cell.model);
|
|
230
|
+
if (activeCell !== null && activeCell.model !== null) {
|
|
231
|
+
if (activeCell.model.isDirty) {
|
|
232
|
+
dirtyCells.add(activeCellId);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
dirtyCells.delete(activeCellId);
|
|
236
|
+
}
|
|
237
|
+
activeCell.model.stateChanged.disconnect(onExecution, activeCell.model.stateChanged);
|
|
238
|
+
}
|
|
239
|
+
activeCell = cell;
|
|
240
|
+
activeCellId = cell.model.id;
|
|
241
|
+
if (activeCell === null || activeCell.model === null || activeCell.model.type !== "code") {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
activeCell.model.stateChanged.connect(onExecution);
|
|
245
|
+
notifyActiveCell(activeCell.model);
|
|
246
|
+
if (dirtyCells.has(activeCellId)) {
|
|
247
|
+
const activeCellModel = activeCell.model;
|
|
248
|
+
if (activeCellModel._setDirty !== undefined) {
|
|
249
|
+
activeCellModel._setDirty(true);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
refreshNodeMapping(notebook);
|
|
253
|
+
updateOneCellUI(activeCellId);
|
|
254
|
+
};
|
|
255
|
+
notebook.activeCellChanged.connect(onActiveCellChange);
|
|
256
|
+
const actionUpdatePairs = [
|
|
257
|
+
{
|
|
258
|
+
action: 'mouseover',
|
|
259
|
+
update: 'add',
|
|
260
|
+
}, {
|
|
261
|
+
action: 'mouseout',
|
|
262
|
+
update: 'remove',
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
const updateOneCellUI = (id) => {
|
|
266
|
+
const elem = cellsById[id];
|
|
267
|
+
if (staleCells.has(id)) {
|
|
268
|
+
elem.classList.add(staleClass);
|
|
269
|
+
elem.classList.add(freshClass);
|
|
270
|
+
elem.classList.remove(refresherInputClass);
|
|
271
|
+
addStaleOutputInteractions(elem, linkedStaleClass);
|
|
272
|
+
}
|
|
273
|
+
else if (freshCells.has(id)) {
|
|
274
|
+
elem.classList.add(refresherInputClass);
|
|
275
|
+
if (lastExecutionMode === 'normal') {
|
|
276
|
+
elem.classList.add(freshClass);
|
|
277
|
+
addStaleOutputInteractions(elem, linkedRefresherClass);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (lastExecutionMode === 'reactive') {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (staleLinks.hasOwnProperty(id)) {
|
|
284
|
+
actionUpdatePairs.forEach(({ action, update }) => {
|
|
285
|
+
addUnsafeCellInteraction(getJpInputCollapser(elem), staleLinks[id], cellsById, getJpInputCollapser, action, update, staleCells);
|
|
286
|
+
addUnsafeCellInteraction(getJpOutputCollapser(elem), staleLinks[id], cellsById, getJpInputCollapser, action, update, staleCells);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (refresherLinks.hasOwnProperty(id)) {
|
|
290
|
+
if (!staleCells.has(id)) {
|
|
291
|
+
elem.classList.add(refresherClass);
|
|
292
|
+
elem.classList.add(freshClass);
|
|
293
|
+
}
|
|
294
|
+
actionUpdatePairs.forEach(({ action, update }) => {
|
|
295
|
+
addUnsafeCellInteraction(getJpInputCollapser(elem), refresherLinks[id], cellsById, getJpInputCollapser, action, update, staleCells);
|
|
296
|
+
addUnsafeCellInteraction(getJpInputCollapser(elem), refresherLinks[id], cellsById, getJpOutputCollapser, action, update, staleCells);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const updateUI = (notebook) => {
|
|
301
|
+
clearCellState(notebook);
|
|
302
|
+
if (!lastExecutionHighlightsEnabled) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
refreshNodeMapping(notebook);
|
|
306
|
+
for (const [id] of Object.entries(cellsById)) {
|
|
307
|
+
updateOneCellUI(id);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
comm.onMsg = (msg) => {
|
|
311
|
+
if (disconnected) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (msg.content.data['type'] === 'establish') {
|
|
315
|
+
notebook.activeCell.model.stateChanged.connect(onExecution);
|
|
316
|
+
notifyActiveCell(notebook.activeCell.model);
|
|
317
|
+
}
|
|
318
|
+
else if (msg.content.data['type'] === 'cell_freshness') {
|
|
319
|
+
staleCells = new Set(msg.content.data['stale_cells']);
|
|
320
|
+
freshCells = new Set(msg.content.data['fresh_cells']);
|
|
321
|
+
newFreshCells = new Set([...newFreshCells, ...msg.content.data['new_fresh_cells']]);
|
|
322
|
+
forcedReactiveCells = new Set([...forcedReactiveCells, ...msg.content.data['forced_reactive_cells']]);
|
|
323
|
+
staleLinks = msg.content.data['stale_links'];
|
|
324
|
+
refresherLinks = msg.content.data['refresher_links'];
|
|
325
|
+
cellPendingExecution = null;
|
|
326
|
+
const exec_mode = msg.content.data['exec_mode'];
|
|
327
|
+
const flow_order = msg.content.data['flow_order'];
|
|
328
|
+
const exec_schedule = msg.content.data['exec_schedule'];
|
|
329
|
+
lastExecutionMode = exec_mode;
|
|
330
|
+
lastExecutionHighlightsEnabled = msg.content.data['highlights_enabled'];
|
|
331
|
+
executedReactiveFreshCells.add(msg.content.data['last_executed_cell_id']);
|
|
332
|
+
let found = false;
|
|
333
|
+
notebook.widgets.forEach(cell => {
|
|
334
|
+
if (found || cell.model.type !== 'code' || executedReactiveFreshCells.has(cell.model.id)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if ((exec_mode === 'reactive' && newFreshCells.has(cell.model.id)) || forcedReactiveCells.has(cell.model.id)) {
|
|
338
|
+
const codeCell = cell;
|
|
339
|
+
if (cellPendingExecution === null) {
|
|
340
|
+
cellPendingExecution = codeCell;
|
|
341
|
+
// break early if using one of the order-based semantics
|
|
342
|
+
found = (flow_order === 'in_order' || exec_schedule === 'strict');
|
|
343
|
+
}
|
|
344
|
+
else if (codeCell.model.executionCount !== null && codeCell.model.executionCount < cellPendingExecution.model.executionCount) {
|
|
345
|
+
// otherwise, execute in order of earliest execution counter
|
|
346
|
+
cellPendingExecution = codeCell;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
if (cellPendingExecution === null) {
|
|
351
|
+
newFreshCells = new Set();
|
|
352
|
+
forcedReactiveCells = new Set();
|
|
353
|
+
updateUI(notebook);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
clearCellState(notebook);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
comm.open({});
|
|
361
|
+
// return a disconnection handle
|
|
362
|
+
return () => {
|
|
363
|
+
disconnected = true;
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
export default extension;
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jupyterlab-ipyflow",
|
|
3
|
+
"description": "JupyterLab extension for ipyflow user interface",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"jupyter",
|
|
6
|
+
"jupyterlab",
|
|
7
|
+
"jupyterlab-extension"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://github.com/nbsafety-project/nbsafety",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/nbsafety-project/nbsafety/issues"
|
|
12
|
+
},
|
|
13
|
+
"license": "BSD-3-Clause",
|
|
14
|
+
"author": "Stephen Macke",
|
|
15
|
+
"files": [
|
|
16
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
17
|
+
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}"
|
|
18
|
+
],
|
|
19
|
+
"main": "lib/index.js",
|
|
20
|
+
"types": "lib/index.d.ts",
|
|
21
|
+
"style": "style/index.css",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/nbsafety-project/nbsafety.git"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "jlpm run build:lib && jlpm run build:labextension:dev",
|
|
28
|
+
"build:prod": "jlpm run build:lib && jlpm run build:labextension",
|
|
29
|
+
"build:labextension": "jupyter labextension build .",
|
|
30
|
+
"build:labextension:dev": "jupyter labextension build --development True .",
|
|
31
|
+
"build:lib": "tsc",
|
|
32
|
+
"clean": "jlpm run clean:lib",
|
|
33
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
34
|
+
"eslint": "eslint . --ext .ts,.tsx --fix",
|
|
35
|
+
"eslint:check": "eslint . --ext .ts,.tsx",
|
|
36
|
+
"install:extension": "jupyter labextension develop --overwrite .",
|
|
37
|
+
"prepare": "jlpm run clean && jlpm run build:prod",
|
|
38
|
+
"watch": "run-p watch:src watch:labextension",
|
|
39
|
+
"watch:src": "tsc -w",
|
|
40
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@jupyterlab/application": "^3.3.2",
|
|
44
|
+
"@jupyterlab/coreutils": "^5.3.2",
|
|
45
|
+
"@jupyterlab/notebook": "^3.3.2",
|
|
46
|
+
"codemirror": "^5.65.0",
|
|
47
|
+
"normalize-url": "^7.0.2"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@jupyterlab/builder": "^3.3.2",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
|
52
|
+
"@typescript-eslint/parser": "^5.15.0",
|
|
53
|
+
"@wdio/cli": "^7.13.1",
|
|
54
|
+
"eslint": "^8.11.0",
|
|
55
|
+
"eslint-config-prettier": "^8.3.0",
|
|
56
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
57
|
+
"prettier": "2.6.0",
|
|
58
|
+
"rimraf": "^3.0.2",
|
|
59
|
+
"typescript": "^3.7.7"
|
|
60
|
+
},
|
|
61
|
+
"sideEffects": [
|
|
62
|
+
"style/*.css"
|
|
63
|
+
],
|
|
64
|
+
"jupyterlab": {
|
|
65
|
+
"extension": true,
|
|
66
|
+
"outputDir": "../../core/ipyflow/resources/labextension/"
|
|
67
|
+
},
|
|
68
|
+
"version": "0.0.86"
|
|
69
|
+
}
|
package/style/index.css
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--stale-color: rgb(254,0,82);
|
|
3
|
+
--refresher-color: rgb(0,197,158);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.stale-cell .jp-InputCollapser {
|
|
7
|
+
border: 1px solid var(--stale-color);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.stale-cell.jp-mod-selected .jp-Collapser-child {
|
|
11
|
+
background-color: var(--stale-color);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.stale-cell .jp-Collapser:hover > .jp-Collapser-child {
|
|
15
|
+
background-color: var(--stale-color);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.jp-Collapser-child.linked-stale {
|
|
19
|
+
background-color: var(--stale-color);
|
|
20
|
+
opacity: 0.6;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.refresher-cell .jp-InputCollapser {
|
|
24
|
+
border: 1px solid var(--refresher-color);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.refresher-cell.jp-mod-selected .jp-Collapser-child {
|
|
28
|
+
background-color: var(--refresher-color);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.refresher-cell .jp-Collapser:hover > .jp-Collapser-child {
|
|
32
|
+
background-color: var(--refresher-color);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.jp-Collapser-child.linked-refresher {
|
|
36
|
+
background-color: var(--refresher-color);
|
|
37
|
+
opacity: 0.6;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* put input / output cells later since they should take precedence */
|
|
41
|
+
|
|
42
|
+
.fresh-cell .jp-OutputCollapser {
|
|
43
|
+
border: 1px solid var(--stale-color);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.fresh-cell.jp-mod-selected .jp-OutputCollapser .jp-Collapser-child {
|
|
47
|
+
background-color: var(--stale-color);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.fresh-cell .jp-OutputCollapser:hover > .jp-Collapser-child {
|
|
51
|
+
background-color: var(--stale-color);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.refresher-input-cell .jp-InputCollapser {
|
|
55
|
+
border: 1px solid var(--refresher-color);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.refresher-input-cell.jp-mod-selected .jp-InputCollapser .jp-Collapser-child {
|
|
59
|
+
background-color: var(--refresher-color);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.refresher-input-cell .jp-InputCollapser:hover > .jp-Collapser-child {
|
|
63
|
+
background-color: var(--refresher-color);
|
|
64
|
+
}
|