Skip to content

Commit 049a6ae

Browse files
authored
Allow opening JupyterCAD documents with the JSON viewer + Allow opening STL and STEP in JupyterLite (#531)
* JSON viewer * Working with jupytercad app * Add support for opening STL and STEP files in JupyterLite * Update jupyter-collaboration packages
1 parent 3ca79e7 commit 049a6ae

File tree

20 files changed

+295
-55
lines changed

20 files changed

+295
-55
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ jobs:
239239
working-directory: lite
240240
run: |
241241
set -eux
242-
mkdir -p content && cp ../examples/test.jcad ./content
242+
mkdir -p content && cp ../examples/*.jcad ../examples/*.STEP ../examples/*.stl ./content
243243
jupyter lite build --contents content --output-dir dist
244244
245245
- name: Upload github-pages artifact

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"build:app": "lerna run --ignore @jupytercad/jupytercad-lab build"
5353
},
5454
"resolutions": {
55-
"@jupyter/collaboration": "^3.0.0-rc.0",
55+
"@jupyter/collaboration": "^3.0.0-rc.1",
5656
"@jupyter/ydoc": "^3.0.0-b0",
5757
"@jupyterlab/apputils": "^4.0.0",
5858
"@lumino/coreutils": "^2.0.0",

packages/base/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
},
3737
"dependencies": {
3838
"@deathbeds/jupyterlab-rjsf": "^1.1.0",
39-
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
39+
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
4040
"@jupyter/ydoc": "^3.0.0-b0",
4141
"@jupytercad/occ-worker": "^3.0.0-alpha.4",
4242
"@jupytercad/schema": "^3.0.0-alpha.4",

packages/schema/src/model.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@ export class JupyterCadModel implements IJupyterCadModel {
2626
if (sharedModel) {
2727
this._sharedModel = sharedModel;
2828
} else {
29-
this._sharedModel = JupyterCadDoc.create();
29+
this._sharedModel = this.createSharedModel();
3030
this._sharedModel.changed.connect(this._onSharedModelChanged);
3131
}
3232
this.sharedModel.awareness.on('change', this._onClientStateChanged);
3333
this.annotationModel = annotationModel;
3434
}
3535

36+
protected createSharedModel(): IJupyterCadDoc {
37+
return JupyterCadDoc.create();
38+
}
39+
3640
private _onSharedModelChanged = (sender: any, changes: any): void => {
3741
if (changes && changes?.objectChange?.length) {
3842
this._contentChanged.emit(void 0);

python/jupytercad_app/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
"dependencies": {
5252
"@codemirror/state": "^6.2.0",
5353
"@codemirror/view": "^6.9.3",
54-
"@jupyter/collaboration": "^3.0.0-rc.0",
55-
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
56-
"@jupyter/docprovider": "^3.0.0-rc.0",
54+
"@jupyter/collaboration": "^3.0.0-rc.1",
55+
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
56+
"@jupyter/docprovider": "^3.0.0-rc.1",
5757
"@jupyter/ydoc": "^3.0.0-b0",
5858
"@jupytercad/base": "^3.0.0-alpha.4",
5959
"@jupytercad/schema": "^3.0.0-alpha.4",
@@ -75,6 +75,7 @@
7575
"@jupyterlab/filebrowser": "^4.0.0",
7676
"@jupyterlab/filebrowser-extension": "^4.0.0",
7777
"@jupyterlab/fileeditor": "^4.2.0",
78+
"@jupyterlab/json-extension": "^4.0.0",
7879
"@jupyterlab/launcher": "^4.0.0",
7980
"@jupyterlab/launcher-extension": "^4.0.0",
8081
"@jupyterlab/logconsole": "^4.0.0",

python/jupytercad_app/src/app/app.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {
2+
createRendermimePlugins,
23
JupyterFrontEnd,
34
JupyterFrontEndPlugin
45
} from '@jupyterlab/application';
56

67
import { PageConfig } from '@jupyterlab/coreutils';
78

89
import { IShell, Shell } from './shell';
10+
import { IRenderMime } from '@jupyterlab/rendermime';
911

1012
/**
1113
* App is the main application class. It is instantiated once and shared.
@@ -16,10 +18,16 @@ export class App extends JupyterFrontEnd<IShell> {
1618
*
1719
* @param options The instantiation options for an application.
1820
*/
19-
constructor(options: App.IOptions = { shell: new Shell() }) {
21+
constructor(options: App.IOptions) {
2022
super({
21-
shell: options.shell
23+
...options,
24+
shell: options.shell ?? new Shell()
2225
});
26+
if (options.mimeExtensions) {
27+
for (const plugin of createRendermimePlugins(options.mimeExtensions)) {
28+
this.registerPlugin(plugin);
29+
}
30+
}
2331
}
2432

2533
/**
@@ -112,7 +120,21 @@ export namespace App {
112120
/**
113121
* The instantiation options for an App application.
114122
*/
115-
export type IOptions = JupyterFrontEnd.IOptions<IShell>;
123+
export interface IOptions
124+
extends JupyterFrontEnd.IOptions<IShell>,
125+
Partial<IInfo> {
126+
paths?: Partial<JupyterFrontEnd.IPaths>;
127+
}
128+
129+
/**
130+
* The information about a application.
131+
*/
132+
export interface IInfo {
133+
/**
134+
* The mime renderer extensions.
135+
*/
136+
readonly mimeExtensions: IRenderMime.IExtensionModule[];
137+
}
116138

117139
/**
118140
* The interface for a module that exports a plugin or plugins as

python/jupytercad_app/src/main.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '@jupyterlab/console/style/index.js';
1515
import '@jupyterlab/completer/style/index.js';
1616
import '../style/index.css';
1717
import './sharedscope';
18+
import { Shell } from './app/shell';
1819

1920
function loadScript(url: string) {
2021
return new Promise((resolve, reject) => {
@@ -61,7 +62,6 @@ async function createModule(scope: string, module: string) {
6162
async function main(): Promise<void> {
6263
// Inject some packages in the shared scope
6364

64-
const app = new App();
6565
// populate the list of disabled extensions
6666
const disabled: any[] = [
6767
'jupytercad:serverInfoPlugin',
@@ -142,8 +142,10 @@ async function main(): Promise<void> {
142142
require('./app/plugins/browser'),
143143
require('./app/plugins/launcher')
144144
];
145+
const mimeExtensions = [require('@jupyterlab/json-extension')];
145146

146147
const federatedExtensionPromises: Promise<any>[] = [];
148+
const federatedMimeExtensionPromises: Promise<any>[] = [];
147149
const federatedStylePromises: Promise<any>[] = [];
148150

149151
const extension_data = JSON.parse(
@@ -176,8 +178,9 @@ async function main(): Promise<void> {
176178
federatedExtensionPromises.push(createModule(data.name, data.extension));
177179
}
178180
if (data.mimeExtension) {
179-
// TODO Do we need mime extensions?
180-
return;
181+
federatedMimeExtensionPromises.push(
182+
createModule(data.name, data.mimeExtension)
183+
);
181184
}
182185
if (data.style && !PageConfig.Extension.isDisabled(data.name)) {
183186
federatedStylePromises.push(createModule(data.name, data.style));
@@ -200,13 +203,28 @@ async function main(): Promise<void> {
200203
}
201204
});
202205

206+
// Add the federated mime extensions.
207+
const federatedMimeExtensions = await Promise.allSettled(
208+
federatedMimeExtensionPromises
209+
);
210+
federatedMimeExtensions.forEach(p => {
211+
if (p.status === 'fulfilled') {
212+
for (const plugin of activePlugins(p.value)) {
213+
mimeExtensions.push(plugin);
214+
}
215+
} else {
216+
console.error(p.reason);
217+
}
218+
});
219+
203220
// Load all federated component styles and log errors for any that do not
204221
(await Promise.allSettled(federatedStylePromises))
205222
.filter(({ status }) => status === 'rejected')
206223
.forEach(e => {
207224
console.error((e as any).reason);
208225
});
209226

227+
const app = new App({ mimeExtensions, shell: new Shell() });
210228
app.registerPluginModules(mods);
211229

212230
await app.start();

python/jupytercad_core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"build:worker:prod": "webpack --config worker.webpack.config.js --mode=production"
5454
},
5555
"dependencies": {
56-
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
56+
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
5757
"@jupytercad/base": "^3.0.0-alpha.4",
5858
"@jupytercad/occ-worker": "^3.0.0-alpha.4",
5959
"@jupytercad/schema": "^3.0.0-alpha.4",

python/jupytercad_core/src/jcadplugin/plugins.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
3131

3232
import { JupyterCadWidgetFactory } from '../factory';
3333
import { JupyterCadJcadModelFactory } from './modelfactory';
34+
import { MimeDocumentFactory } from '@jupyterlab/docregistry';
3435

35-
const FACTORY = 'JupyterCAD .jcad Viewer';
36+
const FACTORY = 'JupyterCAD';
37+
const CONTENT_TYPE = 'jcad';
3638
const PALETTE_CATEGORY = 'JupyterCAD';
3739

3840
namespace CommandIDs {
@@ -58,8 +60,8 @@ const activate = (
5860
const widgetFactory = new JupyterCadWidgetFactory({
5961
name: FACTORY,
6062
modelName: 'jupytercad-jcadmodel',
61-
fileTypes: ['jcad'],
62-
defaultFor: ['jcad'],
63+
fileTypes: [CONTENT_TYPE],
64+
defaultFor: [CONTENT_TYPE],
6365
tracker,
6466
commands: app.commands,
6567
workerRegistry,
@@ -70,22 +72,33 @@ const activate = (
7072
mimeTypeService: editorServices.mimeTypeService,
7173
consoleTracker
7274
});
75+
7376
// Registering the widget factory
7477
app.docRegistry.addWidgetFactory(widgetFactory);
7578

79+
const factory = new MimeDocumentFactory({
80+
dataType: 'json',
81+
rendermime,
82+
modelName: 'jupytercad-jcadmodel',
83+
name: 'JSON Editor',
84+
primaryFileType: app.docRegistry.getFileType('json'),
85+
fileTypes: [CONTENT_TYPE]
86+
});
87+
app.docRegistry.addWidgetFactory(factory);
88+
7689
// Creating and registering the model factory for our custom DocumentModel
7790
const modelFactory = new JupyterCadJcadModelFactory({
7891
annotationModel
7992
});
8093
app.docRegistry.addModelFactory(modelFactory);
8194
// register the filetype
8295
app.docRegistry.addFileType({
83-
name: 'jcad',
96+
name: CONTENT_TYPE,
8497
displayName: 'JCAD',
8598
mimeTypes: ['text/json'],
8699
extensions: ['.jcad', '.JCAD'],
87100
fileFormat: 'text',
88-
contentType: 'jcad',
101+
contentType: CONTENT_TYPE,
89102
icon: logoIcon
90103
});
91104

@@ -94,7 +107,7 @@ const activate = (
94107
};
95108
if (drive) {
96109
drive.sharedModelFactory.registerDocumentFactory(
97-
'jcad',
110+
CONTENT_TYPE,
98111
jcadSharedModelFactory
99112
);
100113
}

python/jupytercad_core/src/stepplugin/model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export class JupyterCadStepDoc extends JupyterCadDoc {
1717
this._source.observeDeep(this._sourceObserver);
1818
}
1919

20+
set source(value: string) {
21+
this._source.insert(0, value);
22+
}
23+
2024
get version(): string {
2125
return '0.1.0';
2226
}

0 commit comments

Comments
 (0)