Skip to content

Commit

Permalink
Types the API and hides Y data structures (#68)
Browse files Browse the repository at this point in the history
* Hides and types objects

* Hide options

* Hide metadata

* Removes unnecessary methods

* Fixes type issue

* Fix
  • Loading branch information
hbcarlos authored Dec 19, 2022
1 parent 7d5af28 commit e227097
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 146 deletions.
2 changes: 1 addition & 1 deletion src/annotation/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class AnnotationModel {
}

getAnnotation(id: string): IAnnotation | undefined {
const rawData = this._sharedModel.metadata.get(id);
const rawData = this._sharedModel.getMetadata(id);
if (rawData) {
return JSON.parse(rawData) as IAnnotation;
}
Expand Down
3 changes: 1 addition & 2 deletions src/mainview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -657,13 +657,12 @@ export class MainView extends React.Component<IProps, IStates> {
_: IJupyterCadDoc,
changes: MapChange
) => {
const metaData = this._model.sharedModel.metadata;
const newState = { ...this.state.annotations };
changes.forEach((val, key) => {
if (!key.startsWith('annotation')) {
return;
}
const data = metaData.get(key);
const data = this._model.sharedModel.getMetadata(key);
let open = true;
if (this.state.firstLoad) {
open = false;
Expand Down
162 changes: 75 additions & 87 deletions src/model.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { IChangedArgs } from '@jupyterlab/coreutils';
import { IModelDB, ModelDB } from '@jupyterlab/observables';

import { MapChange, YDocument } from '@jupyter/ydoc';
import { PartialJSONObject } from '@lumino/coreutils';

import {
PartialJSONObject,
JSONExt,
JSONValue,
JSONObject
} from '@lumino/coreutils';
import { ISignal, Signal } from '@lumino/signaling';

import Ajv from 'ajv';
import * as Y from 'yjs';

import { IJCadContent, IJCadModel } from './_interface/jcad';
import { IJCadContent, IJCadModel, IJCadObject } from './_interface/jcad';
import jcadSchema from './schema/jcad.json';
import {
IJCadObjectDoc,
IJupyterCadClientState,
IJupyterCadDoc,
IJupyterCadDocChange,
IJupyterCadModel,
PointerPosition,
Camera
} from './types';
import { yMapToJcadObject } from './tools';

export class JupyterCadModel implements IJupyterCadModel {
constructor(languagePreference?: string, modelDB?: IModelDB) {
Expand Down Expand Up @@ -93,21 +99,14 @@ export class JupyterCadModel implements IJupyterCadModel {
const ajv = new Ajv();
const validate = ajv.compile(jcadSchema);
const valid = validate(jsonData);

if (!valid) {
throw Error('File format error');
}

this.sharedModel.transact(() => {
for (const obj of jsonData.objects) {
const entries = Object.entries(obj);
const jcadObj = new Y.Map<any>(entries);
this.sharedModel.addObject(jcadObj);
}
const options = jsonData.options;
if (options) {
for (const [opt, val] of Object.entries(options)) {
this.sharedModel.setOption(opt, val);
}
}
this.sharedModel.addObjects(jsonData.objects);
this.sharedModel.setOptions(jsonData.options ?? {});
});
}

Expand All @@ -133,27 +132,14 @@ export class JupyterCadModel implements IJupyterCadModel {
}

getContent(): IJCadContent {
const content: IJCadContent = { objects: [], options: {} };
const sharedContent = this.sharedModel.objects;
sharedContent.forEach((obj, id) => {
const newObj = yMapToJcadObject(obj);
content.objects[id] = newObj;
});
const sharedOption = this.sharedModel.options;
if (sharedOption) {
sharedOption.forEach((obj, id) => {
content.options![id] = obj;
});
}
return content;
return {
objects: this.sharedModel.objects,
options: this.sharedModel.options
};
}

getAllObject(): IJCadModel {
const all: IJCadModel = [];
this.sharedModel.objects.forEach(obj => {
all.push(yMapToJcadObject(obj));
});
return all;
return this.sharedModel.objects;
}

syncPointer(position?: PointerPosition, emitter?: string): void {
Expand Down Expand Up @@ -240,7 +226,7 @@ export class JupyterCadDoc
super();

this._options = this.ydoc.getMap<any>('options');
this._objects = this.ydoc.getArray<IJCadObjectDoc>('objects');
this._objects = this.ydoc.getArray<Y.Map<any>>('objects');
this._metadata = this.ydoc.getMap<string>('metadata');

this.undoManager.addToScope(this._objects);
Expand All @@ -254,56 +240,26 @@ export class JupyterCadDoc
this._metadata.unobserve(this._metaObserver);
}

get objects(): Y.Array<IJCadObjectDoc> {
return this._objects;
get objects(): Array<IJCadObject> {
return this._objects.map(
obj => JSONExt.deepCopy(obj.toJSON()) as IJCadObject
);
}
get options(): Y.Map<any> {
return this._options;
get options(): JSONObject {
return JSONExt.deepCopy(this._options.toJSON());
}
get metadata(): Y.Map<string> {
return this._metadata;
get metadata(): JSONObject {
return JSONExt.deepCopy(this._metadata.toJSON());
}

get metadataChanged(): ISignal<IJupyterCadDoc, MapChange> {
return this._metadataChanged;
}

setMetadata(key: string, value: string): void {
this._metadata.set(key, value);
}

removeMetadata(key: string): void {
if (this._metadata.has(key)) {
this._metadata.delete(key);
}
}

/**
* Undo an operation.
*/
undo(): void {
this.undoManager.undo();
}

/**
* Redo an operation.
*/
redo(): void {
this.undoManager.redo();
}

/**
* Clear the change stack.
*/
clearUndoHistory(): void {
this.undoManager.clear();
}

getObjectByName(name: string): IJCadObjectDoc | undefined {
for (const iterator of this._objects) {
if (iterator.get('name') === name) {
return iterator;
}
getObjectByName(name: string): IJCadObject | undefined {
const obj = this._getObjectAsYMapByName(name);
if (obj) {
return JSONExt.deepCopy(obj.toJSON()) as IJCadObject;
}
return undefined;
}
Expand All @@ -322,35 +278,67 @@ export class JupyterCadDoc
}
}

addObject(value: IJCadObjectDoc): void {
addObject(value: IJCadObject): void {
this.addObjects([value]);
}

addObjects(value: Array<IJCadObject>): void {
this.transact(() => {
this._objects.push([value]);
const objs = value.map(obj => new Y.Map(Object.create(obj)));
this._objects.push(objs);
});
}

updateObjectByName(name: string, key: string, value: any): void {
const object = this.getObjectByName(name);
if (!object) {
const obj = this._getObjectAsYMapByName(name);
if (!obj) {
return;
}

this.transact(() => {
object.set(key, value);
});
this.transact(() => obj.set(key, value));
}

getOption(key: string): any {
return this._options.get(key);
getOption(key: string): JSONValue {
return JSONExt.deepCopy(this._options.get(key));
}

setOption(key: string, value: any): void {
setOption(key: string, value: JSONValue): void {
this._options.set(key, value);
}

setOptions(options: JSONObject): void {
for (const [key, value] of Object.entries(options)) {
this._options.set(key, value);
}
}

getMetadata(key: string): string | undefined {
return this._metadata.get(key);
}

setMetadata(key: string, value: string): void {
this._metadata.set(key, value);
}

removeMetadata(key: string): void {
if (this._metadata.has(key)) {
this._metadata.delete(key);
}
}

static create(): IJupyterCadDoc {
return new JupyterCadDoc();
}

private _getObjectAsYMapByName(name: string): Y.Map<any> | undefined {
for (const obj of this._objects) {
if (obj.get('name') === name) {
return obj;
}
}
return undefined;
}

private _objectsObserver = (event: Y.YEvent<any>[]): void => {
this._changed.emit({ objectChange: [] });
};
Expand All @@ -359,7 +347,7 @@ export class JupyterCadDoc
this._metadataChanged.emit(event.keys);
};

private _objects: Y.Array<IJCadObjectDoc>;
private _objects: Y.Array<Y.Map<any>>;
private _options: Y.Map<any>;
private _metadata: Y.Map<string>;
private _metadataChanged = new Signal<IJupyterCadDoc, MapChange>(this);
Expand Down
23 changes: 10 additions & 13 deletions src/panelview/objectproperties.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { ReactWidget } from '@jupyterlab/apputils';
import { PanelWithToolbar } from '@jupyterlab/ui-components';

import { Panel } from '@lumino/widgets';
import { JSONExt } from '@lumino/coreutils';

import { v4 as uuid } from 'uuid';
import * as React from 'react';

import {
focusInputField,
itemFromName,
Expand All @@ -19,7 +22,6 @@ import {
import { IJCadModel } from '../_interface/jcad';
import { ObjectPropertiesForm } from './formbuilder';
import formSchema from '../_interface/forms.json';
import { v4 as uuid } from 'uuid';

export class ObjectProperties extends PanelWithToolbar {
constructor(params: ObjectProperties.IOptions) {
Expand Down Expand Up @@ -99,18 +101,13 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
return;
}

const currentYMap =
this.props.cpModel.jcadModel?.sharedModel.getObjectByName(objectName);
if (currentYMap) {
const newParams = {
...JSONExt.deepCopy(currentYMap.get('parameters')),
const model = this.props.cpModel.jcadModel?.sharedModel;
const obj = model?.getObjectByName(objectName);
if (model && obj) {
model.updateObjectByName(objectName, 'parameters', {
...obj['parameters'],
...properties
};
this.props.cpModel.jcadModel?.sharedModel.updateObjectByName(
objectName,
'parameters',
newParams
);
});
}
}

Expand Down
Loading

0 comments on commit e227097

Please sign in to comment.