Skip to content

Commit

Permalink
Allow opening JupyterCAD documents with the JSON viewer + Allow openi…
Browse files Browse the repository at this point in the history
…ng STL and STEP in JupyterLite (jupytercad#531)

* JSON viewer

* Working with jupytercad app

* Add support for opening STL and STEP files in JupyterLite

* Update jupyter-collaboration packages
  • Loading branch information
martinRenou authored Oct 24, 2024
1 parent 3ca79e7 commit 049a6ae
Show file tree
Hide file tree
Showing 20 changed files with 295 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ jobs:
working-directory: lite
run: |
set -eux
mkdir -p content && cp ../examples/test.jcad ./content
mkdir -p content && cp ../examples/*.jcad ../examples/*.STEP ../examples/*.stl ./content
jupyter lite build --contents content --output-dir dist
- name: Upload github-pages artifact
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"build:app": "lerna run --ignore @jupytercad/jupytercad-lab build"
},
"resolutions": {
"@jupyter/collaboration": "^3.0.0-rc.0",
"@jupyter/collaboration": "^3.0.0-rc.1",
"@jupyter/ydoc": "^3.0.0-b0",
"@jupyterlab/apputils": "^4.0.0",
"@lumino/coreutils": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"dependencies": {
"@deathbeds/jupyterlab-rjsf": "^1.1.0",
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
"@jupyter/ydoc": "^3.0.0-b0",
"@jupytercad/occ-worker": "^3.0.0-alpha.4",
"@jupytercad/schema": "^3.0.0-alpha.4",
Expand Down
6 changes: 5 additions & 1 deletion packages/schema/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ export class JupyterCadModel implements IJupyterCadModel {
if (sharedModel) {
this._sharedModel = sharedModel;
} else {
this._sharedModel = JupyterCadDoc.create();
this._sharedModel = this.createSharedModel();
this._sharedModel.changed.connect(this._onSharedModelChanged);
}
this.sharedModel.awareness.on('change', this._onClientStateChanged);
this.annotationModel = annotationModel;
}

protected createSharedModel(): IJupyterCadDoc {
return JupyterCadDoc.create();
}

private _onSharedModelChanged = (sender: any, changes: any): void => {
if (changes && changes?.objectChange?.length) {
this._contentChanged.emit(void 0);
Expand Down
7 changes: 4 additions & 3 deletions python/jupytercad_app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
"dependencies": {
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.3",
"@jupyter/collaboration": "^3.0.0-rc.0",
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
"@jupyter/docprovider": "^3.0.0-rc.0",
"@jupyter/collaboration": "^3.0.0-rc.1",
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
"@jupyter/docprovider": "^3.0.0-rc.1",
"@jupyter/ydoc": "^3.0.0-b0",
"@jupytercad/base": "^3.0.0-alpha.4",
"@jupytercad/schema": "^3.0.0-alpha.4",
Expand All @@ -75,6 +75,7 @@
"@jupyterlab/filebrowser": "^4.0.0",
"@jupyterlab/filebrowser-extension": "^4.0.0",
"@jupyterlab/fileeditor": "^4.2.0",
"@jupyterlab/json-extension": "^4.0.0",
"@jupyterlab/launcher": "^4.0.0",
"@jupyterlab/launcher-extension": "^4.0.0",
"@jupyterlab/logconsole": "^4.0.0",
Expand Down
28 changes: 25 additions & 3 deletions python/jupytercad_app/src/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
createRendermimePlugins,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';

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

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

/**
* App is the main application class. It is instantiated once and shared.
Expand All @@ -16,10 +18,16 @@ export class App extends JupyterFrontEnd<IShell> {
*
* @param options The instantiation options for an application.
*/
constructor(options: App.IOptions = { shell: new Shell() }) {
constructor(options: App.IOptions) {
super({
shell: options.shell
...options,
shell: options.shell ?? new Shell()
});
if (options.mimeExtensions) {
for (const plugin of createRendermimePlugins(options.mimeExtensions)) {
this.registerPlugin(plugin);
}
}
}

/**
Expand Down Expand Up @@ -112,7 +120,21 @@ export namespace App {
/**
* The instantiation options for an App application.
*/
export type IOptions = JupyterFrontEnd.IOptions<IShell>;
export interface IOptions
extends JupyterFrontEnd.IOptions<IShell>,
Partial<IInfo> {
paths?: Partial<JupyterFrontEnd.IPaths>;
}

/**
* The information about a application.
*/
export interface IInfo {
/**
* The mime renderer extensions.
*/
readonly mimeExtensions: IRenderMime.IExtensionModule[];
}

/**
* The interface for a module that exports a plugin or plugins as
Expand Down
24 changes: 21 additions & 3 deletions python/jupytercad_app/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import '@jupyterlab/console/style/index.js';
import '@jupyterlab/completer/style/index.js';
import '../style/index.css';
import './sharedscope';
import { Shell } from './app/shell';

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

const app = new App();
// populate the list of disabled extensions
const disabled: any[] = [
'jupytercad:serverInfoPlugin',
Expand Down Expand Up @@ -142,8 +142,10 @@ async function main(): Promise<void> {
require('./app/plugins/browser'),
require('./app/plugins/launcher')
];
const mimeExtensions = [require('@jupyterlab/json-extension')];

const federatedExtensionPromises: Promise<any>[] = [];
const federatedMimeExtensionPromises: Promise<any>[] = [];
const federatedStylePromises: Promise<any>[] = [];

const extension_data = JSON.parse(
Expand Down Expand Up @@ -176,8 +178,9 @@ async function main(): Promise<void> {
federatedExtensionPromises.push(createModule(data.name, data.extension));
}
if (data.mimeExtension) {
// TODO Do we need mime extensions?
return;
federatedMimeExtensionPromises.push(
createModule(data.name, data.mimeExtension)
);
}
if (data.style && !PageConfig.Extension.isDisabled(data.name)) {
federatedStylePromises.push(createModule(data.name, data.style));
Expand All @@ -200,13 +203,28 @@ async function main(): Promise<void> {
}
});

// Add the federated mime extensions.
const federatedMimeExtensions = await Promise.allSettled(
federatedMimeExtensionPromises
);
federatedMimeExtensions.forEach(p => {
if (p.status === 'fulfilled') {
for (const plugin of activePlugins(p.value)) {
mimeExtensions.push(plugin);
}
} else {
console.error(p.reason);
}
});

// Load all federated component styles and log errors for any that do not
(await Promise.allSettled(federatedStylePromises))
.filter(({ status }) => status === 'rejected')
.forEach(e => {
console.error((e as any).reason);
});

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

await app.start();
Expand Down
2 changes: 1 addition & 1 deletion python/jupytercad_core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"build:worker:prod": "webpack --config worker.webpack.config.js --mode=production"
},
"dependencies": {
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
"@jupytercad/base": "^3.0.0-alpha.4",
"@jupytercad/occ-worker": "^3.0.0-alpha.4",
"@jupytercad/schema": "^3.0.0-alpha.4",
Expand Down
25 changes: 19 additions & 6 deletions python/jupytercad_core/src/jcadplugin/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import { IRenderMimeRegistry } from '@jupyterlab/rendermime';

import { JupyterCadWidgetFactory } from '../factory';
import { JupyterCadJcadModelFactory } from './modelfactory';
import { MimeDocumentFactory } from '@jupyterlab/docregistry';

const FACTORY = 'JupyterCAD .jcad Viewer';
const FACTORY = 'JupyterCAD';
const CONTENT_TYPE = 'jcad';
const PALETTE_CATEGORY = 'JupyterCAD';

namespace CommandIDs {
Expand All @@ -58,8 +60,8 @@ const activate = (
const widgetFactory = new JupyterCadWidgetFactory({
name: FACTORY,
modelName: 'jupytercad-jcadmodel',
fileTypes: ['jcad'],
defaultFor: ['jcad'],
fileTypes: [CONTENT_TYPE],
defaultFor: [CONTENT_TYPE],
tracker,
commands: app.commands,
workerRegistry,
Expand All @@ -70,22 +72,33 @@ const activate = (
mimeTypeService: editorServices.mimeTypeService,
consoleTracker
});

// Registering the widget factory
app.docRegistry.addWidgetFactory(widgetFactory);

const factory = new MimeDocumentFactory({
dataType: 'json',
rendermime,
modelName: 'jupytercad-jcadmodel',
name: 'JSON Editor',
primaryFileType: app.docRegistry.getFileType('json'),
fileTypes: [CONTENT_TYPE]
});
app.docRegistry.addWidgetFactory(factory);

// Creating and registering the model factory for our custom DocumentModel
const modelFactory = new JupyterCadJcadModelFactory({
annotationModel
});
app.docRegistry.addModelFactory(modelFactory);
// register the filetype
app.docRegistry.addFileType({
name: 'jcad',
name: CONTENT_TYPE,
displayName: 'JCAD',
mimeTypes: ['text/json'],
extensions: ['.jcad', '.JCAD'],
fileFormat: 'text',
contentType: 'jcad',
contentType: CONTENT_TYPE,
icon: logoIcon
});

Expand All @@ -94,7 +107,7 @@ const activate = (
};
if (drive) {
drive.sharedModelFactory.registerDocumentFactory(
'jcad',
CONTENT_TYPE,
jcadSharedModelFactory
);
}
Expand Down
4 changes: 4 additions & 0 deletions python/jupytercad_core/src/stepplugin/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class JupyterCadStepDoc extends JupyterCadDoc {
this._source.observeDeep(this._sourceObserver);
}

set source(value: string) {
this._source.insert(0, value);
}

get version(): string {
return '0.1.0';
}
Expand Down
18 changes: 15 additions & 3 deletions python/jupytercad_core/src/stepplugin/modelfactory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { IJupyterCadDoc, JupyterCadModel } from '@jupytercad/schema';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import { Contents } from '@jupyterlab/services';
import { JupyterCadStepDoc } from './model';

class JupyterCadStepModel extends JupyterCadModel {
fromString(data: string): void {
(this.sharedModel as JupyterCadStepDoc).source = data;
this.dirty = true;
}

protected createSharedModel(): IJupyterCadDoc {
return JupyterCadStepDoc.create();
}
}

/**
* A Model factory to create new instances of JupyterCadModel.
Expand Down Expand Up @@ -68,14 +80,14 @@ export class JupyterCadStepModelFactory
}

/**
* Create a new instance of JupyterCadModel.
* Create a new instance of JupyterCadStepModel.
*
* @returns The model
*/
createNew(
options: DocumentRegistry.IModelOptions<IJupyterCadDoc>
): JupyterCadModel {
const model = new JupyterCadModel({
): JupyterCadStepModel {
const model = new JupyterCadStepModel({
sharedModel: options.sharedModel,
languagePreference: options.languagePreference
});
Expand Down
2 changes: 1 addition & 1 deletion python/jupytercad_core/src/stepplugin/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const activate = (
app.docRegistry.addFileType({
name: 'step',
displayName: 'STEP',
mimeTypes: ['text/json'],
mimeTypes: ['text/plain'],
extensions: ['.step', '.STEP'],
fileFormat: 'text',
contentType: 'step',
Expand Down
4 changes: 4 additions & 0 deletions python/jupytercad_core/src/stlplugin/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class JupyterCadStlDoc extends JupyterCadDoc {
this._source.observeDeep(this._sourceObserver);
}

set source(value: string) {
this._source.insert(0, value);
}

get version(): string {
return '0.1.0';
}
Expand Down
22 changes: 17 additions & 5 deletions python/jupytercad_core/src/stlplugin/modelfactory.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { IJupyterCadDoc, JupyterCadModel } from '@jupytercad/schema';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import { Contents } from '@jupyterlab/services';
import { JupyterCadStlDoc } from './model';

class JupyterCadStlModel extends JupyterCadModel {
fromString(data: string): void {
(this.sharedModel as JupyterCadStlDoc).source = data;
this.dirty = true;
}

protected createSharedModel(): IJupyterCadDoc {
return JupyterCadStlDoc.create();
}
}

/**
* A Model factory to create new instances of JupyterCadModel.
* A Model factory to create new instances of JupyterCadSTLModel.
*/
export class JupyterCadStlModelFactory
implements DocumentRegistry.IModelFactory<JupyterCadModel>
implements DocumentRegistry.IModelFactory<JupyterCadStlModel>
{
/**
* Whether the model is collaborative or not.
Expand Down Expand Up @@ -68,14 +80,14 @@ export class JupyterCadStlModelFactory
}

/**
* Create a new instance of JupyterCadModel.
* Create a new instance of JupyterCadSTLModel.
*
* @returns The model
*/
createNew(
options: DocumentRegistry.IModelOptions<IJupyterCadDoc>
): JupyterCadModel {
const model = new JupyterCadModel({
): JupyterCadStlModel {
const model = new JupyterCadStlModel({
sharedModel: options.sharedModel,
languagePreference: options.languagePreference
});
Expand Down
2 changes: 1 addition & 1 deletion python/jupytercad_core/src/stlplugin/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const activate = (
app.docRegistry.addFileType({
name: 'stl',
displayName: 'STL',
mimeTypes: ['text/json'],
mimeTypes: ['text/plain'],
extensions: ['.stl', '.STL'],
fileFormat: 'text',
contentType: 'stl',
Expand Down
2 changes: 1 addition & 1 deletion python/jupytercad_lab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"watch:labextension": "jupyter labextension watch ."
},
"dependencies": {
"@jupyter/collaborative-drive": "^3.0.0-rc.0",
"@jupyter/collaborative-drive": "^3.0.0-rc.1",
"@jupytercad/base": "^3.0.0-alpha.4",
"@jupytercad/jupytercad-core": "^3.0.0-alpha.4",
"@jupytercad/schema": "^3.0.0-alpha.4",
Expand Down
Loading

0 comments on commit 049a6ae

Please sign in to comment.