jupyterpack 0.3.0 → 0.4.0

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.
Files changed (68) hide show
  1. package/lib/document/commands.d.ts +8 -0
  2. package/lib/document/commands.js +76 -0
  3. package/lib/document/iframePanel.d.ts +4 -1
  4. package/lib/document/plugin.d.ts +2 -1
  5. package/lib/document/plugin.js +22 -4
  6. package/lib/document/toolbar.d.ts +9 -0
  7. package/lib/document/toolbar.js +20 -0
  8. package/lib/document/widgetFactory.d.ts +2 -1
  9. package/lib/document/widgetFactory.js +11 -5
  10. package/lib/index.d.ts +1 -1
  11. package/lib/pythonServer/dash/dashServer.d.ts +4 -6
  12. package/lib/pythonServer/dash/dashServer.js +18 -10
  13. package/lib/pythonServer/kernelExecutor.d.ts +5 -0
  14. package/lib/pythonServer/kernelExecutor.js +13 -6
  15. package/lib/pythonServer/streamlit/streamlitServer.d.ts +7 -26
  16. package/lib/pythonServer/streamlit/streamlitServer.js +32 -36
  17. package/lib/pythonServer/tornado/tornadoServer.d.ts +5 -3
  18. package/lib/pythonServer/tornado/tornadoServer.js +31 -14
  19. package/lib/pythonWidget/comm.d.ts +11 -0
  20. package/lib/pythonWidget/comm.js +52 -0
  21. package/lib/pythonWidget/pythonWidget.d.ts +5 -0
  22. package/lib/pythonWidget/pythonWidget.js +19 -0
  23. package/lib/pythonWidget/pythonWidgetModel.d.ts +16 -4
  24. package/lib/pythonWidget/pythonWidgetModel.js +77 -13
  25. package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
  26. package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
  27. package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
  28. package/lib/sandpackWidget/sandpackPanel.js +38 -3
  29. package/lib/token.d.ts +2 -1
  30. package/lib/token.js +1 -0
  31. package/lib/tools.d.ts +5 -0
  32. package/lib/tools.js +17 -0
  33. package/lib/type.d.ts +27 -1
  34. package/package.json +6 -6
  35. package/src/document/commands.ts +91 -0
  36. package/src/document/iframePanel.ts +4 -1
  37. package/src/document/plugin.ts +28 -7
  38. package/src/document/toolbar.ts +39 -0
  39. package/src/document/widgetFactory.ts +13 -5
  40. package/src/global.d.ts +5 -0
  41. package/src/pythonServer/dash/dashServer.ts +23 -14
  42. package/src/pythonServer/kernelExecutor.ts +21 -7
  43. package/src/pythonServer/streamlit/streamlitServer.ts +41 -61
  44. package/src/pythonServer/tornado/tornadoServer.ts +35 -18
  45. package/src/pythonWidget/comm.ts +65 -0
  46. package/src/pythonWidget/pythonWidget.ts +19 -1
  47. package/src/pythonWidget/pythonWidgetModel.ts +105 -18
  48. package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
  49. package/src/sandpackWidget/sandpackPanel.ts +45 -4
  50. package/src/token.ts +5 -1
  51. package/src/tools.ts +22 -0
  52. package/src/type.ts +29 -1
  53. package/style/base.css +7 -0
  54. package/style/icons/autoreload.svg +16 -0
  55. package/style/icons/box.svg +12 -0
  56. package/style/icons/externallink.svg +10 -0
  57. package/lib/pythonServer/common/generatedPythonFiles.d.ts +0 -2
  58. package/lib/pythonServer/common/generatedPythonFiles.js +0 -72
  59. package/lib/pythonServer/dash/generatedPythonFiles.d.ts +0 -2
  60. package/lib/pythonServer/dash/generatedPythonFiles.js +0 -31
  61. package/lib/pythonServer/streamlit/generatedPythonFiles.d.ts +0 -2
  62. package/lib/pythonServer/streamlit/generatedPythonFiles.js +0 -147
  63. package/lib/pythonServer/tornado/generatedPythonFiles.d.ts +0 -3
  64. package/lib/pythonServer/tornado/generatedPythonFiles.js +0 -456
  65. package/src/pythonServer/common/generatedPythonFiles.ts +0 -73
  66. package/src/pythonServer/dash/generatedPythonFiles.ts +0 -32
  67. package/src/pythonServer/streamlit/generatedPythonFiles.ts +0 -148
  68. package/src/pythonServer/tornado/generatedPythonFiles.ts +0 -457
@@ -0,0 +1,52 @@
1
+ const COMM_NAME = 'jupyterpack:broadcast:comm';
2
+ export class CommBroadcastManager {
3
+ constructor() {
4
+ this._handle_comm_open = async (comm, msg, kernelId) => {
5
+ var _a;
6
+ if (this._comms.has(kernelId)) {
7
+ (_a = this._comms.get(kernelId)) === null || _a === void 0 ? void 0 : _a.push(comm);
8
+ }
9
+ else {
10
+ this._comms.set(kernelId, [comm]);
11
+ }
12
+ const channelName = msg.metadata.channel_name;
13
+ if (!channelName) {
14
+ return;
15
+ }
16
+ if (!this._broadcastChannels.has(channelName)) {
17
+ this._broadcastChannels.set(channelName, new BroadcastChannel(channelName));
18
+ }
19
+ const broadcastChannel = this._broadcastChannels.get(channelName);
20
+ comm.onMsg = commMsg => {
21
+ const { data } = commMsg.content;
22
+ broadcastChannel.postMessage(data);
23
+ };
24
+ };
25
+ this._kernels = new Map();
26
+ this._comms = new Map();
27
+ this._broadcastChannels = new Map();
28
+ this._kernels = new Map();
29
+ this._comms = new Map();
30
+ }
31
+ registerKernel(kernel) {
32
+ this._kernels.set(kernel.id, kernel);
33
+ kernel.registerCommTarget(COMM_NAME, (comm, msg) => this._handle_comm_open(comm, msg, kernel.id));
34
+ }
35
+ unregisterKernel(kernelId) {
36
+ var _a;
37
+ if (kernelId) {
38
+ this._kernels.delete(kernelId);
39
+ const comms = (_a = this._comms.get(kernelId)) !== null && _a !== void 0 ? _a : [];
40
+ comms.forEach(comm => comm.dispose());
41
+ this._comms.delete(kernelId);
42
+ }
43
+ }
44
+ dispose() {
45
+ this._kernels.clear();
46
+ this._comms.clear();
47
+ this._broadcastChannels.forEach(it => {
48
+ it.close();
49
+ });
50
+ this._broadcastChannels.clear();
51
+ }
52
+ }
@@ -2,9 +2,14 @@ import { PythonWidgetModel } from './pythonWidgetModel';
2
2
  import { IFramePanel } from '../document/iframePanel';
3
3
  export declare class PythonWidget extends IFramePanel {
4
4
  constructor(options: PythonWidget.IOptions);
5
+ get autoreload(): boolean;
6
+ set autoreload(value: boolean);
7
+ get isReady(): Promise<void>;
5
8
  get model(): PythonWidgetModel;
9
+ reload(): Promise<void>;
6
10
  dispose(): void;
7
11
  private _model;
12
+ private _isReady;
8
13
  }
9
14
  export declare namespace PythonWidget {
10
15
  interface IOptions {
@@ -1,8 +1,10 @@
1
1
  import { PageConfig, URLExt } from '@jupyterlab/coreutils';
2
2
  import { IFramePanel } from '../document/iframePanel';
3
+ import { PromiseDelegate } from '@lumino/coreutils';
3
4
  export class PythonWidget extends IFramePanel {
4
5
  constructor(options) {
5
6
  super();
7
+ this._isReady = new PromiseDelegate();
6
8
  this._model = options.model;
7
9
  this._model.initialize().then(connectionData => {
8
10
  if (!connectionData.success) {
@@ -10,6 +12,7 @@ export class PythonWidget extends IFramePanel {
10
12
  this._iframe.contentDocument.body.innerText = `Failed to start server: ${connectionData.error}`;
11
13
  return;
12
14
  }
15
+ this._isReady.resolve();
13
16
  const iframe = this._iframe;
14
17
  const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
15
18
  const iframeUrl = URLExt.join(fullLabextensionsUrl, 'jupyterpack/static', connectionData.instanceId, connectionData.framework, connectionData.kernelClientId, connectionData.rootUrl);
@@ -17,11 +20,27 @@ export class PythonWidget extends IFramePanel {
17
20
  iframe.addEventListener('load', () => {
18
21
  this.toggleSpinner(false);
19
22
  });
23
+ this._model.serverReloaded.connect(() => {
24
+ var _a, _b, _c;
25
+ (_c = (_b = (_a = this._iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.reload();
26
+ });
20
27
  });
21
28
  }
29
+ get autoreload() {
30
+ return this._model.autoreload;
31
+ }
32
+ set autoreload(value) {
33
+ this._model.autoreload = value;
34
+ }
35
+ get isReady() {
36
+ return this._isReady.promise;
37
+ }
22
38
  get model() {
23
39
  return this._model;
24
40
  }
41
+ async reload() {
42
+ await this._model.reload();
43
+ }
25
44
  dispose() {
26
45
  this._model.dispose();
27
46
  }
@@ -1,11 +1,16 @@
1
1
  import { DocumentRegistry } from '@jupyterlab/docregistry';
2
2
  import { Contents, ServiceManager } from '@jupyterlab/services';
3
- import { IDisposable } from '@lumino/disposable';
4
- import { IConnectionManager, IJupyterPackFileFormat, JupyterPackFramework } from '../type';
5
- export declare class PythonWidgetModel implements IDisposable {
3
+ import { Signal } from '@lumino/signaling';
4
+ import { IConnectionManager, IJupyterPackFileFormat, IPythonWidgetModel, JupyterPackFramework } from '../type';
5
+ export declare class PythonWidgetModel implements IPythonWidgetModel {
6
6
  constructor(options: PythonWidgetModel.IOptions);
7
+ get autoreload(): boolean;
8
+ set autoreload(val: boolean);
7
9
  get isDisposed(): boolean;
8
10
  get connectionManager(): IConnectionManager;
11
+ get serverReloaded(): Signal<IPythonWidgetModel, void>;
12
+ get kernelStatusChanged(): Signal<IPythonWidgetModel, "started" | "stopped">;
13
+ reload(): Promise<void>;
9
14
  initialize(): Promise<{
10
15
  success: true;
11
16
  instanceId: string;
@@ -16,7 +21,10 @@ export declare class PythonWidgetModel implements IDisposable {
16
21
  success: false;
17
22
  error: string;
18
23
  }>;
19
- dispose(): void;
24
+ dispose(): Promise<void>;
25
+ private _loadData;
26
+ private _onFileChanged;
27
+ private _commBroadcastManager;
20
28
  private _isDisposed;
21
29
  private _kernelStarted;
22
30
  private _sessionConnection;
@@ -26,6 +34,10 @@ export declare class PythonWidgetModel implements IDisposable {
26
34
  private _contentsManager;
27
35
  private _jpackModel;
28
36
  private _executor?;
37
+ private _localPath;
38
+ private _serverReloaded;
39
+ private _kernelStatusChanged;
40
+ private _autoreload;
29
41
  }
30
42
  export declare namespace PythonWidgetModel {
31
43
  interface IOptions {
@@ -1,15 +1,31 @@
1
1
  import { PathExt } from '@jupyterlab/coreutils';
2
2
  import { PromiseDelegate } from '@lumino/coreutils';
3
3
  import { PYTHON_SERVER } from '../pythonServer';
4
+ import { Signal } from '@lumino/signaling';
5
+ import { CommBroadcastManager } from './comm';
6
+ import { IS_LITE } from '../tools';
4
7
  export class PythonWidgetModel {
5
8
  constructor(options) {
9
+ var _a, _b;
10
+ this._commBroadcastManager = new CommBroadcastManager();
6
11
  this._isDisposed = false;
7
12
  this._kernelStarted = false;
13
+ this._serverReloaded = new Signal(this);
14
+ this._kernelStatusChanged = new Signal(this);
8
15
  this._context = options.context;
9
16
  this._manager = options.manager;
10
17
  this._connectionManager = options.connectionManager;
11
18
  this._contentsManager = options.contentsManager;
12
19
  this._jpackModel = options.jpackModel;
20
+ this._localPath = PathExt.dirname(this._context.localPath);
21
+ this._autoreload = Boolean((_b = (_a = this._jpackModel) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.autoreload);
22
+ this._contentsManager.fileChanged.connect(this._onFileChanged, this);
23
+ }
24
+ get autoreload() {
25
+ return this._autoreload;
26
+ }
27
+ set autoreload(val) {
28
+ this._autoreload = val;
13
29
  }
14
30
  get isDisposed() {
15
31
  return this._isDisposed;
@@ -17,22 +33,33 @@ export class PythonWidgetModel {
17
33
  get connectionManager() {
18
34
  return this._connectionManager;
19
35
  }
36
+ get serverReloaded() {
37
+ return this._serverReloaded;
38
+ }
39
+ get kernelStatusChanged() {
40
+ return this._kernelStatusChanged;
41
+ }
42
+ async reload() {
43
+ var _a;
44
+ if (!this._kernelStarted) {
45
+ return;
46
+ }
47
+ const { spkContent, entryContent } = await this._loadData();
48
+ await ((_a = this._executor) === null || _a === void 0 ? void 0 : _a.reloadPythonServer({
49
+ entryPath: spkContent.entry,
50
+ initCode: entryContent.content
51
+ }));
52
+ this._serverReloaded.emit();
53
+ }
20
54
  async initialize() {
21
- var _a, _b;
55
+ var _a;
22
56
  if (this._kernelStarted) {
23
57
  return {
24
58
  success: false,
25
59
  error: 'Server is called twice'
26
60
  };
27
61
  }
28
- const filePath = this._context.localPath;
29
- const spkContent = this._jpackModel;
30
- const entryPath = PathExt.join(PathExt.dirname(filePath), spkContent.entry);
31
- const rootUrl = (_a = spkContent.rootUrl) !== null && _a !== void 0 ? _a : '/';
32
- const entryContent = await this._contentsManager.get(entryPath, {
33
- content: true,
34
- format: 'text'
35
- });
62
+ const { filePath, spkContent, rootUrl, entryContent } = await this._loadData();
36
63
  const sessionManager = this._manager.sessions;
37
64
  await sessionManager.ready;
38
65
  await this._manager.kernelspecs.ready;
@@ -55,7 +82,18 @@ export class PythonWidgetModel {
55
82
  name: kernelName
56
83
  },
57
84
  type: 'notebook'
85
+ }, {
86
+ kernelConnectionOptions: { handleComms: true }
58
87
  });
88
+ const kernel = this._sessionConnection.kernel;
89
+ if (kernel) {
90
+ this._kernelStatusChanged.emit('started');
91
+ this._commBroadcastManager.registerKernel(kernel);
92
+ kernel.disposed.connect(() => {
93
+ this._kernelStatusChanged.emit('stopped');
94
+ this._commBroadcastManager.unregisterKernel(kernel.id);
95
+ });
96
+ }
59
97
  const framework = spkContent.framework;
60
98
  const ServerClass = PYTHON_SERVER.get(framework);
61
99
  if (!ServerClass) {
@@ -81,17 +119,43 @@ export class PythonWidgetModel {
81
119
  finish.resolve();
82
120
  }
83
121
  };
84
- (_b = this._sessionConnection.kernel) === null || _b === void 0 ? void 0 : _b.statusChanged.connect(cb);
122
+ (_a = this._sessionConnection.kernel) === null || _a === void 0 ? void 0 : _a.statusChanged.connect(cb);
85
123
  await finish.promise;
86
124
  this._kernelStarted = true;
87
125
  return { ...data, rootUrl, framework, success: true };
88
126
  }
89
- dispose() {
90
- var _a;
127
+ async dispose() {
128
+ var _a, _b, _c;
91
129
  if (this._isDisposed) {
92
130
  return;
93
131
  }
94
- void ((_a = this._executor) === null || _a === void 0 ? void 0 : _a.disposePythonServer());
132
+ if (!IS_LITE) {
133
+ (_b = (_a = this._sessionConnection) === null || _a === void 0 ? void 0 : _a.kernel) === null || _b === void 0 ? void 0 : _b.shutdown();
134
+ }
135
+ void ((_c = this._executor) === null || _c === void 0 ? void 0 : _c.disposePythonServer());
136
+ this._contentsManager.fileChanged.disconnect(this._onFileChanged);
137
+ this._commBroadcastManager.dispose();
95
138
  this._isDisposed = true;
96
139
  }
140
+ async _loadData() {
141
+ var _a;
142
+ const filePath = this._context.localPath;
143
+ const spkContent = this._jpackModel;
144
+ const entryPath = PathExt.join(PathExt.dirname(filePath), spkContent.entry);
145
+ const rootUrl = (_a = spkContent.rootUrl) !== null && _a !== void 0 ? _a : '/';
146
+ const entryContent = await this._contentsManager.get(entryPath, {
147
+ content: true,
148
+ format: 'text'
149
+ });
150
+ return { filePath, spkContent, rootUrl, entryContent };
151
+ }
152
+ async _onFileChanged(sender, args) {
153
+ var _a;
154
+ if (this._autoreload && args.type === 'save') {
155
+ if (((_a = args.newValue) === null || _a === void 0 ? void 0 : _a.path) &&
156
+ args.newValue.path.startsWith(this._localPath)) {
157
+ await this.reload();
158
+ }
159
+ }
160
+ }
97
161
  }
@@ -1,19 +1,22 @@
1
1
  import { Contents } from '@jupyterlab/services';
2
2
  import { ISignal } from '@lumino/signaling';
3
3
  import { IDict } from '../type';
4
- export declare class SandpackFilesModel {
4
+ import { IDisposable } from '@lumino/disposable';
5
+ export declare class SandpackFilesModel implements IDisposable {
5
6
  constructor(options: {
6
7
  contentsManager: Contents.IManager;
7
8
  path: string;
8
9
  });
9
- getAllFiles(): Promise<IDict<{
10
+ getAllFiles(force?: boolean): Promise<IDict<{
10
11
  code: string;
11
12
  }>>;
13
+ get isDisposed(): boolean;
12
14
  get fileChanged(): ISignal<SandpackFilesModel, {
13
15
  allFiles: IDict<{
14
16
  code: string;
15
17
  }>;
16
18
  }>;
19
+ dispose(): void;
17
20
  flattenDirectory(dirContent: Contents.IModel): Promise<IDict<{
18
21
  code: string;
19
22
  }>>;
@@ -24,4 +27,5 @@ export declare class SandpackFilesModel {
24
27
  private _fileChanged;
25
28
  private _contentManager;
26
29
  private _allFiles?;
30
+ private _isDisposed;
27
31
  }
@@ -3,12 +3,13 @@ import { removePrefix } from '../tools';
3
3
  export class SandpackFilesModel {
4
4
  constructor(options) {
5
5
  this._fileChanged = new Signal(this);
6
+ this._isDisposed = false;
6
7
  this._contentManager = options.contentsManager;
7
8
  this._path = options.path;
8
9
  this._contentManager.fileChanged.connect(this._onFileChanged, this);
9
10
  }
10
- async getAllFiles() {
11
- if (!this._allFiles) {
11
+ async getAllFiles(force = false) {
12
+ if (!this._allFiles || force) {
12
13
  const files = await this._contentManager.get(this._path, {
13
14
  content: true
14
15
  });
@@ -16,9 +17,19 @@ export class SandpackFilesModel {
16
17
  }
17
18
  return this._allFiles;
18
19
  }
20
+ get isDisposed() {
21
+ return this._isDisposed;
22
+ }
19
23
  get fileChanged() {
20
24
  return this._fileChanged;
21
25
  }
26
+ dispose() {
27
+ if (this._isDisposed) {
28
+ return;
29
+ }
30
+ this._isDisposed = true;
31
+ this._contentManager.fileChanged.disconnect(this._onFileChanged);
32
+ }
22
33
  async flattenDirectory(dirContent) {
23
34
  const flatDict = {};
24
35
  const content = dirContent.content;
@@ -2,15 +2,24 @@ import { SandpackClient } from '@codesandbox/sandpack-client';
2
2
  import { DocumentRegistry } from '@jupyterlab/docregistry';
3
3
  import { Contents } from '@jupyterlab/services';
4
4
  import { IFramePanel } from '../document/iframePanel';
5
+ import { IJupyterPackFileFormat } from '../type';
5
6
  import { SandpackFilesModel } from './sandpackFilesModel';
6
7
  export declare class SandpackPanel extends IFramePanel {
7
8
  constructor(options: {
8
9
  context: DocumentRegistry.IContext<DocumentRegistry.IModel>;
9
10
  contentsManager: Contents.IManager;
10
11
  });
11
- init(localPath: string): Promise<void>;
12
+ dispose(): void;
13
+ get isReady(): Promise<void>;
14
+ get autoreload(): boolean;
15
+ set autoreload(val: boolean);
16
+ init(localPath: string, jpackModel: IJupyterPackFileFormat): Promise<void>;
12
17
  connectSignals(filesModel: SandpackFilesModel, sandpackClient: SandpackClient): Promise<void>;
18
+ reload(): Promise<void>;
13
19
  private _onFileChanged;
14
20
  private _spClient?;
15
21
  private _contentsManager;
22
+ private _fileModel;
23
+ private _autoreload;
24
+ private _isReady;
16
25
  }
@@ -1,20 +1,46 @@
1
1
  import { loadSandpackClient } from '@codesandbox/sandpack-client';
2
2
  import { IFramePanel } from '../document/iframePanel';
3
3
  import { SandpackFilesModel } from './sandpackFilesModel';
4
+ import { PromiseDelegate } from '@lumino/coreutils';
4
5
  export class SandpackPanel extends IFramePanel {
5
6
  constructor(options) {
6
7
  super();
8
+ this._autoreload = false;
9
+ this._isReady = new PromiseDelegate();
7
10
  this._contentsManager = options.contentsManager;
11
+ const { context } = options;
8
12
  options.context.ready.then(async () => {
9
- await this.init(options.context.localPath);
13
+ const jpackModel = context.model.toJSON();
14
+ await this.init(context.localPath, jpackModel);
10
15
  });
11
16
  }
12
- async init(localPath) {
17
+ dispose() {
18
+ var _a, _b, _c;
19
+ (_a = this._fileModel) === null || _a === void 0 ? void 0 : _a.fileChanged.disconnect(this._onFileChanged);
20
+ (_b = this._fileModel) === null || _b === void 0 ? void 0 : _b.dispose();
21
+ (_c = this._spClient) === null || _c === void 0 ? void 0 : _c.destroy();
22
+ super.dispose();
23
+ }
24
+ get isReady() {
25
+ return this._isReady.promise;
26
+ }
27
+ get autoreload() {
28
+ return this._autoreload;
29
+ }
30
+ set autoreload(val) {
31
+ this._autoreload = val;
32
+ }
33
+ async init(localPath, jpackModel) {
34
+ var _a;
35
+ if (((_a = jpackModel === null || jpackModel === void 0 ? void 0 : jpackModel.metadata) === null || _a === void 0 ? void 0 : _a.autoreload) === true) {
36
+ this._autoreload = true;
37
+ }
13
38
  const currentDir = localPath.split('/').slice(0, -1).join('/');
14
39
  const filesModel = new SandpackFilesModel({
15
40
  contentsManager: this._contentsManager,
16
41
  path: currentDir
17
42
  });
43
+ this._fileModel = filesModel;
18
44
  const allFiles = await filesModel.getAllFiles();
19
45
  const options = {
20
46
  showLoadingScreen: true,
@@ -24,6 +50,7 @@ export class SandpackPanel extends IFramePanel {
24
50
  files: allFiles
25
51
  }, options);
26
52
  await this.connectSignals(filesModel, this._spClient);
53
+ this._isReady.resolve();
27
54
  }
28
55
  async connectSignals(filesModel, sandpackClient) {
29
56
  filesModel.fileChanged.connect(this._onFileChanged, this);
@@ -42,8 +69,16 @@ export class SandpackPanel extends IFramePanel {
42
69
  }
43
70
  });
44
71
  }
72
+ async reload() {
73
+ if (this._spClient && this._fileModel) {
74
+ const allFiles = await this._fileModel.getAllFiles();
75
+ this._spClient.updateSandbox({
76
+ files: allFiles
77
+ });
78
+ }
79
+ }
45
80
  _onFileChanged(sender, { allFiles }) {
46
- if (this._spClient) {
81
+ if (this._autoreload && this._spClient) {
47
82
  this._spClient.updateSandbox({
48
83
  files: allFiles
49
84
  });
package/lib/token.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Token } from '@lumino/coreutils';
2
- import { IConnectionManager } from './type';
2
+ import { IConnectionManager, IJupyterpackDocTracker } from './type';
3
3
  export declare const IConnectionManagerToken: Token<IConnectionManager>;
4
+ export declare const IJupyterpackDocTrackerToken: Token<IJupyterpackDocTracker>;
package/lib/token.js CHANGED
@@ -1,2 +1,3 @@
1
1
  import { Token } from '@lumino/coreutils';
2
2
  export const IConnectionManagerToken = new Token('jupyterpack:connection-manager');
3
+ export const IJupyterpackDocTrackerToken = new Token('jupyterpack:dock-tracker');
package/lib/tools.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ import { LabIcon } from '@jupyterlab/ui-components';
2
+ export declare const IS_LITE: boolean;
3
+ export declare const logoIcon: LabIcon;
4
+ export declare const autoReloadIcon: LabIcon;
5
+ export declare const linkIcon: LabIcon;
1
6
  export declare function removePrefix(path: string, prefix: string): string;
2
7
  export declare function arrayBufferToBase64(buffer: ArrayBuffer): string;
3
8
  export declare function base64ToArrayBuffer(base64: string): Uint8Array;
package/lib/tools.js CHANGED
@@ -1,3 +1,20 @@
1
+ import logoStr from '../style/icons/box.svg';
2
+ import autoReloadStr from '../style/icons/autoreload.svg';
3
+ import linkStr from '../style/icons/externallink.svg';
4
+ import { LabIcon } from '@jupyterlab/ui-components';
5
+ export const IS_LITE = !!document.getElementById('jupyter-lite-main');
6
+ export const logoIcon = new LabIcon({
7
+ name: 'jupyterpack:logo',
8
+ svgstr: logoStr
9
+ });
10
+ export const autoReloadIcon = new LabIcon({
11
+ name: 'jupyterpack:autoReload',
12
+ svgstr: autoReloadStr
13
+ });
14
+ export const linkIcon = new LabIcon({
15
+ name: 'jupyterpack:externalLink',
16
+ svgstr: linkStr
17
+ });
1
18
  export function removePrefix(path, prefix) {
2
19
  if (path.startsWith(prefix)) {
3
20
  return path.slice(prefix.length);
package/lib/type.d.ts CHANGED
@@ -1,5 +1,8 @@
1
+ import { DocumentWidget } from '@jupyterlab/docregistry';
1
2
  import { KernelMessage } from '@jupyterlab/services';
2
3
  import { IDisposable } from '@lumino/disposable';
4
+ import { IWidgetTracker } from '@jupyterlab/apputils';
5
+ import { ISignal } from '@lumino/signaling';
3
6
  export interface IDict<T = any> {
4
7
  [key: string]: T;
5
8
  }
@@ -19,7 +22,9 @@ export interface IJupyterPackFileFormat {
19
22
  entry: string;
20
23
  framework: JupyterPackFramework;
21
24
  name?: string;
22
- metadata?: IDict;
25
+ metadata?: {
26
+ autoreload?: boolean;
27
+ };
23
28
  rootUrl?: string;
24
29
  }
25
30
  export declare enum MessageAction {
@@ -54,6 +59,10 @@ export interface IKernelExecutor extends IDisposable {
54
59
  kernelClientId: string;
55
60
  }): Promise<void>;
56
61
  disposePythonServer(): Promise<void>;
62
+ reloadPythonServer(options: {
63
+ entryPath?: string;
64
+ initCode?: string;
65
+ }): Promise<void>;
57
66
  getResponseFunctionFactory(options: {
58
67
  urlPath: string;
59
68
  method: string;
@@ -71,3 +80,20 @@ export interface IConnectionManager {
71
80
  kernelClientId: string;
72
81
  } & IKernelExecutorParams): Promise<IDict | null>;
73
82
  }
83
+ export type IJupyterpackDocTracker = IWidgetTracker<DocumentWidget>;
84
+ export interface IPythonWidgetModel extends IDisposable {
85
+ connectionManager: IConnectionManager;
86
+ serverReloaded: ISignal<IPythonWidgetModel, void>;
87
+ kernelStatusChanged: ISignal<IPythonWidgetModel, 'started' | 'stopped'>;
88
+ reload(): Promise<void>;
89
+ initialize(): Promise<{
90
+ success: true;
91
+ instanceId: string;
92
+ kernelClientId: string;
93
+ rootUrl: string;
94
+ framework: JupyterPackFramework;
95
+ } | {
96
+ success: false;
97
+ error: string;
98
+ }>;
99
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterpack",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A JupyterLab extension for serving web app.",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -29,13 +29,12 @@
29
29
  "url": "https://github.com/trungleduc/jupyterpack.git"
30
30
  },
31
31
  "scripts": {
32
- "build:demo": "cd demo && rm -rf .jupyterlite.doit.db _output && jupyter lite build .",
32
+ "build:demo": "node script/build-demo.mjs",
33
33
  "update:demo": "node script/update-demo.mjs",
34
- "combine:python": "node script/combine-python.mjs",
35
34
  "build:worker": "webpack --config sw.webpack.config.js --mode development",
36
35
  "build:worker:prod": "webpack --config sw.webpack.config.js --mode production",
37
- "build": "jlpm combine:python && jlpm build:lib && jlpm build:labextension:dev && jlpm build:worker",
38
- "build:prod": "jlpm clean && jlpm combine:python && jlpm build:lib:prod && jlpm build:labextension && jlpm build:worker:prod",
36
+ "build": "jlpm build:lib && jlpm build:labextension:dev && jlpm build:worker",
37
+ "build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension && jlpm build:worker:prod",
39
38
  "build:labextension": "jupyter labextension build .",
40
39
  "build:labextension:dev": "jupyter labextension build --development True .",
41
40
  "build:lib": "tsc --sourceMap",
@@ -80,7 +79,7 @@
80
79
  "eslint-plugin-prettier": "^5.0.0",
81
80
  "npm-run-all2": "^7.0.1",
82
81
  "prettier": "^3.0.0",
83
- "rimraf": "^5.0.1",
82
+ "rimraf": "^6.1.0",
84
83
  "source-map-loader": "^1.0.2",
85
84
  "style-loader": "^3.3.1",
86
85
  "stylelint": "^15.10.1",
@@ -88,6 +87,7 @@
88
87
  "stylelint-config-standard": "^34.0.0",
89
88
  "stylelint-csstree-validator": "^3.0.0",
90
89
  "stylelint-prettier": "^4.0.0",
90
+ "tar": "^7.5.2",
91
91
  "ts-loader": "^9.2.6",
92
92
  "typescript": "~5.8.0",
93
93
  "webpack": "^5.76.3",