jupyter-specta 0.3.5 → 0.4.1

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 CHANGED
@@ -52,6 +52,8 @@ jupyter lite build
52
52
 
53
53
  Then serve the contents of the output directory (by default `./_output`) using any static file server. You can access the `Specta` app at the `/specta/` path.
54
54
 
55
+ If you want to disable specta loading spinner, you can set the environment variable `SPECTA_NO_LOADING_SCREEN` to `1`before calling jupyterlite build command
56
+
55
57
  ## Specta Configuration
56
58
 
57
59
  ### Available layouts
@@ -1,5 +1,6 @@
1
1
  import { ILabShell, JupyterFrontEndPlugin } from '@jupyterlab/application';
2
2
  import { IWidgetTracker } from '@jupyterlab/apputils';
3
- import { ISpectaShell } from '../token';
3
+ import { ISpectaShell, ISpectaUrlFactory } from '../token';
4
4
  export declare const spectaDocument: JupyterFrontEndPlugin<IWidgetTracker, ISpectaShell>;
5
+ export declare const spectaUrlFactory: JupyterFrontEndPlugin<ISpectaUrlFactory>;
5
6
  export declare const spectaOpener: JupyterFrontEndPlugin<void, ILabShell>;
@@ -1,13 +1,13 @@
1
1
  import { IThemeManager, WidgetTracker } from '@jupyterlab/apputils';
2
2
  import { IEditorServices } from '@jupyterlab/codeeditor';
3
- import { PathExt } from '@jupyterlab/coreutils';
3
+ import { PageConfig, PathExt, URLExt } from '@jupyterlab/coreutils';
4
4
  import { IDocumentManager } from '@jupyterlab/docmanager';
5
5
  import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
6
6
  import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
7
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
8
  import { IKernelSpecManager } from '@jupyterlab/services';
9
9
  import { Widget } from '@lumino/widgets';
10
- import { ISpectaDocTracker, ISpectaLayoutRegistry } from '../token';
10
+ import { ISpectaDocTracker, ISpectaLayoutRegistry, ISpectaUrlFactoryToken } from '../token';
11
11
  import { configLabLayout, createFileBrowser, hideAppLoadingIndicator, isSpectaApp, readSpectaConfig, registerDocumentFactory } from '../tool';
12
12
  const activate = (app, rendermime, tracker, editorServices, contentFactory, spectaLayoutRegistry, themeManager) => {
13
13
  const namespace = 'specta';
@@ -39,6 +39,29 @@ export const spectaDocument = {
39
39
  activate,
40
40
  provides: ISpectaDocTracker
41
41
  };
42
+ export const spectaUrlFactory = {
43
+ id: 'specta/application-extension:urlFactory',
44
+ autoStart: true,
45
+ provides: ISpectaUrlFactoryToken,
46
+ activate() {
47
+ const urlFactory = (path) => {
48
+ const baseUrl = PageConfig.getBaseUrl();
49
+ let appUrl = PageConfig.getOption('appUrl');
50
+ if (!appUrl.endsWith('/')) {
51
+ appUrl = `${appUrl}/`;
52
+ }
53
+ const url = new URL(URLExt.join(baseUrl, appUrl));
54
+ url.searchParams.set('path', path);
55
+ const queries = PageConfig.getOption('query').split('&').filter(Boolean);
56
+ queries.forEach(query => {
57
+ const [key, value] = query.split('=');
58
+ url.searchParams.set(key, value);
59
+ });
60
+ return url.toString();
61
+ };
62
+ return urlFactory;
63
+ }
64
+ };
42
65
  export const spectaOpener = {
43
66
  id: 'specta/application-extension:opener',
44
67
  autoStart: true,
@@ -48,7 +71,8 @@ export const spectaOpener = {
48
71
  ISpectaDocTracker,
49
72
  IKernelSpecManager
50
73
  ],
51
- activate: async (app, docManager, defaultBrowser) => {
74
+ optional: [ISpectaUrlFactoryToken],
75
+ activate: async (app, docManager, defaultBrowser, tracker, kernelSpecManager, urlFactory) => {
52
76
  const urlParams = new URLSearchParams(window.location.search);
53
77
  if (!isSpectaApp()) {
54
78
  // Not a specta app
@@ -61,7 +85,6 @@ export const spectaOpener = {
61
85
  if (PathExt.extname(path) === '.ipynb') {
62
86
  const commands = app.commands;
63
87
  const spectaConfig = readSpectaConfig({});
64
- console.log('spectaConfig', spectaConfig);
65
88
  await configLabLayout({
66
89
  config: spectaConfig.labConfig,
67
90
  labShell,
@@ -79,7 +102,7 @@ export const spectaOpener = {
79
102
  // Specta app
80
103
  const path = urlParams.get('path');
81
104
  if (!path) {
82
- const browser = createFileBrowser({ defaultBrowser });
105
+ const browser = createFileBrowser({ defaultBrowser, urlFactory });
83
106
  app.shell.add(browser, 'main', { rank: 100 });
84
107
  hideAppLoadingIndicator();
85
108
  }
@@ -1,4 +1,4 @@
1
1
  export * from './tool';
2
2
  export * from './token';
3
- declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("@jupyterlab/apputils").IWidgetTracker<import("@lumino/widgets").Widget>, import("./token").ISpectaShell> | import("@jupyterlab/application").JupyterFrontEndPlugin<void, import("@jupyterlab/application").ILabShell> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./token").ISpectaLayoutRegistry> | import("@jupyterlab/application").JupyterFrontEndPlugin<void, import("./token").ISpectaShell>)[];
3
+ declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("@jupyterlab/apputils").IWidgetTracker<import("@lumino/widgets").Widget>, import("./token").ISpectaShell> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./token").ISpectaUrlFactory> | import("@jupyterlab/application").JupyterFrontEndPlugin<void, import("@jupyterlab/application").ILabShell> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./token").ISpectaLayoutRegistry> | import("@jupyterlab/application").JupyterFrontEndPlugin<void, import("./token").ISpectaShell>)[];
4
4
  export default _default;
@@ -1,4 +1,4 @@
1
- import { spectaDocument, spectaOpener } from './document/plugin';
1
+ import { spectaDocument, spectaOpener, spectaUrlFactory } from './document/plugin';
2
2
  import { spectaLayoutRegistry } from './layout';
3
3
  import { appMeta, cellMeta } from './metadata';
4
4
  import { topbarPlugin } from './topbar';
@@ -10,5 +10,6 @@ export default [
10
10
  spectaLayoutRegistry,
11
11
  topbarPlugin,
12
12
  appMeta,
13
- cellMeta
13
+ cellMeta,
14
+ spectaUrlFactory
14
15
  ];
package/lib/token.d.ts CHANGED
@@ -64,5 +64,7 @@ export interface ISpectaCellConfig {
64
64
  showOutput?: boolean;
65
65
  outputSize?: 'Small' | 'Big' | 'Full';
66
66
  }
67
+ export type ISpectaUrlFactory = (path: string) => string;
67
68
  export declare const ISpectaLayoutRegistry: Token<ISpectaLayoutRegistry>;
68
69
  export declare const ISpectaDocTracker: Token<IWidgetTracker<Widget>>;
70
+ export declare const ISpectaUrlFactoryToken: Token<ISpectaUrlFactory>;
package/lib/token.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { Token } from '@lumino/coreutils';
2
2
  export const ISpectaLayoutRegistry = new Token('specta:ISpectaLayoutRegistry');
3
3
  export const ISpectaDocTracker = new Token('exampleDocTracker');
4
+ export const ISpectaUrlFactoryToken = new Token('specta:ISpectaUrlFactoryToken');
package/lib/tool.d.ts CHANGED
@@ -6,7 +6,7 @@ import { ICell, INotebookMetadata } from '@jupyterlab/nbformat';
6
6
  import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
7
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8
8
  import { CommandRegistry } from '@lumino/commands';
9
- import { ISpectaAppConfig, ISpectaCellConfig, ISpectaLayoutRegistry, ISpectaShell } from './token';
9
+ import { ISpectaAppConfig, ISpectaCellConfig, ISpectaLayoutRegistry, ISpectaShell, ISpectaUrlFactory } from './token';
10
10
  export declare function registerDocumentFactory(options: {
11
11
  factoryName: string;
12
12
  app: JupyterFrontEnd<ISpectaShell>;
@@ -20,9 +20,10 @@ export declare function registerDocumentFactory(options: {
20
20
  }): void;
21
21
  export declare function createFileBrowser(options: {
22
22
  defaultBrowser: IDefaultFileBrowser;
23
+ urlFactory: ISpectaUrlFactory | null;
23
24
  }): any;
24
25
  export declare function hideAppLoadingIndicator(): void;
25
- export declare function mergeObjects(...objects: Record<string, any>[]): Record<string, any>;
26
+ export declare function mergeObjects(lowerPriority: Record<string, any>, higherPriority: Record<string, any>): Record<string, any>;
26
27
  export declare function getSpectaAssetUrl(path: string): string;
27
28
  export declare function isSpectaApp(): boolean;
28
29
  export declare function readSpectaConfig({ nbMetadata, nbPath }: {
package/lib/tool.js CHANGED
@@ -42,27 +42,31 @@ export function registerDocumentFactory(options) {
42
42
  });
43
43
  }
44
44
  export function createFileBrowser(options) {
45
- const { defaultBrowser } = options;
45
+ const { defaultBrowser, urlFactory } = options;
46
46
  const browser = defaultBrowser;
47
47
  browser.singleClickNavigation = true;
48
48
  browser.showFileCheckboxes = false;
49
49
  browser.showLastModifiedColumn = false;
50
50
  browser.addClass('specta-file-browser');
51
- const urlFactory = (path) => {
52
- const baseUrl = PageConfig.getBaseUrl();
53
- let appUrl = PageConfig.getOption('appUrl');
54
- if (!appUrl.endsWith('/')) {
55
- appUrl = `${appUrl}/`;
56
- }
57
- const url = new URL(URLExt.join(baseUrl, appUrl));
58
- url.searchParams.set('path', path);
59
- const queries = PageConfig.getOption('query').split('&').filter(Boolean);
60
- queries.forEach(query => {
61
- const [key, value] = query.split('=');
62
- url.searchParams.set(key, value);
63
- });
64
- return url.toString();
65
- };
51
+ const urlFactoryFn = urlFactory
52
+ ? urlFactory
53
+ : (path) => {
54
+ const baseUrl = PageConfig.getBaseUrl();
55
+ let appUrl = PageConfig.getOption('appUrl');
56
+ if (!appUrl.endsWith('/')) {
57
+ appUrl = `${appUrl}/`;
58
+ }
59
+ const url = new URL(URLExt.join(baseUrl, appUrl));
60
+ url.searchParams.set('path', path);
61
+ const queries = PageConfig.getOption('query')
62
+ .split('&')
63
+ .filter(Boolean);
64
+ queries.forEach(query => {
65
+ const [key, value] = query.split('=');
66
+ url.searchParams.set(key, value);
67
+ });
68
+ return url.toString();
69
+ };
66
70
  const oldHandler = browser.listing.handleOpen.bind(browser.listing);
67
71
  browser.listing.handleOpen = (item) => {
68
72
  if (item.type === 'directory') {
@@ -70,7 +74,7 @@ export function createFileBrowser(options) {
70
74
  return;
71
75
  }
72
76
  else {
73
- window.open(urlFactory(item.path), '_blank');
77
+ window.open(urlFactoryFn(item.path), '_blank');
74
78
  }
75
79
  };
76
80
  return browser;
@@ -87,18 +91,31 @@ export function hideAppLoadingIndicator() {
87
91
  }, 1000);
88
92
  }
89
93
  }
90
- export function mergeObjects(...objects) {
91
- const result = {};
92
- for (const obj of objects) {
93
- for (const [key, value] of Object.entries(obj)) {
94
- if (value !== null && value !== undefined) {
95
- console.log('setting', key, value);
96
- result[key] = value;
94
+ export function mergeObjects(lowerPriority, higherPriority) {
95
+ const result = Object.assign({}, lowerPriority);
96
+ for (const key of Object.keys(higherPriority)) {
97
+ const highVal = higherPriority[key];
98
+ const lowVal = lowerPriority[key];
99
+ // If higher is null or undefined, keep lower if it exists
100
+ if (highVal === null || highVal === undefined) {
101
+ if (lowVal !== null && lowVal !== undefined) {
102
+ result[key] = lowVal;
97
103
  }
104
+ continue;
105
+ }
106
+ // Deep merge plain objects
107
+ if (isPlainObject(lowVal) && isPlainObject(highVal)) {
108
+ result[key] = mergeObjects(lowVal, highVal);
109
+ continue;
98
110
  }
111
+ // Otherwise, higher priority wins
112
+ result[key] = highVal;
99
113
  }
100
114
  return result;
101
115
  }
116
+ function isPlainObject(value) {
117
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
118
+ }
102
119
  export function getSpectaAssetUrl(path) {
103
120
  const labExtension = PageConfig.getOption('fullLabextensionsUrl');
104
121
  const url = URLExt.join(labExtension, 'jupyter-specta', 'static', path);
@@ -30,7 +30,6 @@ export function TopbarElement(props) {
30
30
  document.addEventListener('mousedown', handleClickOutside);
31
31
  return () => document.removeEventListener('mousedown', handleClickOutside);
32
32
  }, []);
33
- console.log('config.background ', config.background);
34
33
  return (React.createElement("div", { className: "specta-topbar", style: { background: (_a = config.background) !== null && _a !== void 0 ? _a : 'var(--jp-layout-color1)' } },
35
34
  React.createElement("div", { className: "specta-topbar-left" },
36
35
  React.createElement("div", { className: "specta-topbar-icon-container" }, config.icon && React.createElement("img", { style: { height: '100%' }, src: config.icon })),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyter-specta",
3
- "version": "0.3.5",
3
+ "version": "0.4.1",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/trungleduc/specta",
@@ -78,7 +78,7 @@
78
78
  "@jupyterlab/outputarea": "^4.5.0",
79
79
  "@jupyterlab/rendermime": "^4.5.0",
80
80
  "@jupyterlab/rendermime-extension": "^4.5.0",
81
- "@jupyterlab/services": "^7.2.4",
81
+ "@jupyterlab/services": "^7.5.1",
82
82
  "@jupyterlab/services-extension": "^4.5.0",
83
83
  "@jupyterlab/settingeditor-extension": "^4.5.0",
84
84
  "@jupyterlab/settingregistry": "^4.5.0",
package/style/base.css CHANGED
@@ -92,7 +92,7 @@
92
92
  gap: 10px;
93
93
  align-items: center;
94
94
  justify-content: space-between;
95
- padding: 0 1rem;
95
+ padding: 0;
96
96
  position: relative;
97
97
  }
98
98