Skip to content

Commit

Permalink
Upgrade Theia to 1.43.1 and GLSP to 2.0.0 (#34)
Browse files Browse the repository at this point in the history
Upgrade Theia to 1.43.1:
- Use Node webpack configuration for Electron for smaller package
- Adapt start script to use the new backend entry point

Upgrade GLSP to 2.0.0:
- Re-use Json-based command/operation API in GLSP server
- Adapt to new diagram configuration in GLSP client
- Remove unused CrossModelUpdateClientOperationHandler

Bonus: Fix issue with wrong updates in model service and undo/redo
  • Loading branch information
martin-fleck-at authored Nov 15, 2023
1 parent ce0fa56 commit 021aa09
Show file tree
Hide file tree
Showing 39 changed files with 907 additions and 887 deletions.
28 changes: 14 additions & 14 deletions applications/browser-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,22 @@
"@crossbreeze/model-service": "^1.0.0",
"@crossbreeze/product": "0.0.0",
"@crossbreeze/property-view": "^1.0.0",
"@theia/core": "1.37.2",
"@theia/editor": "1.37.2",
"@theia/filesystem": "1.37.2",
"@theia/markers": "1.37.2",
"@theia/messages": "1.37.2",
"@theia/monaco": "1.37.2",
"@theia/navigator": "1.37.2",
"@theia/plugin-ext": "1.37.2",
"@theia/plugin-ext-vscode": "1.37.2",
"@theia/preferences": "1.37.2",
"@theia/process": "1.37.2",
"@theia/terminal": "1.37.2",
"@theia/workspace": "1.37.2"
"@theia/core": "1.43.1",
"@theia/editor": "1.43.1",
"@theia/filesystem": "1.43.1",
"@theia/markers": "1.43.1",
"@theia/messages": "1.43.1",
"@theia/monaco": "1.43.1",
"@theia/navigator": "1.43.1",
"@theia/plugin-ext": "1.43.1",
"@theia/plugin-ext-vscode": "1.43.1",
"@theia/preferences": "1.43.1",
"@theia/process": "1.43.1",
"@theia/terminal": "1.43.1",
"@theia/workspace": "1.43.1"
},
"devDependencies": {
"@theia/cli": "1.37.2"
"@theia/cli": "1.43.1"
},
"productName": "CrossModel Community Edition",
"theia": {
Expand Down
34 changes: 18 additions & 16 deletions applications/electron-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
},
"main": "scripts/electron-main.js",
"scripts": {
"build": "yarn bundle",
"bundle": "yarn rebuild && theia build --mode development",
"clean": "theia clean && rimraf lib && rimraf src-gen",
"deploy": "rimraf dist && electron-builder -c.mac.identity=null --publish always",
"download:plugins": "theia download:plugins",
Expand All @@ -25,7 +27,7 @@
"package:preview": "yarn package:pre && electron-builder -c.mac.identity=null --dir && yarn package:post",
"prepare": "theia build --mode development && yarn download:plugins",
"rebuild": "theia rebuild:electron --cacheRoot ../..",
"start": "yarn rebuild && cross-env NODE_ENV=development theia start --plugins=local-dir:plugins",
"start": "cross-env NODE_ENV=development theia start --plugins=local-dir:plugins",
"test": "jest --passWithNoTests",
"watch": "theia build --watch --mode development"
},
Expand All @@ -36,23 +38,23 @@
"@crossbreeze/model-service": "^1.0.0",
"@crossbreeze/product": "0.0.0",
"@crossbreeze/property-view": "^1.0.0",
"@theia/core": "1.37.2",
"@theia/editor": "1.37.2",
"@theia/electron": "1.37.2",
"@theia/filesystem": "1.37.2",
"@theia/markers": "1.37.2",
"@theia/messages": "1.37.2",
"@theia/monaco": "1.37.2",
"@theia/navigator": "1.37.2",
"@theia/plugin-ext": "1.37.2",
"@theia/plugin-ext-vscode": "1.37.2",
"@theia/preferences": "1.37.2",
"@theia/process": "1.37.2",
"@theia/terminal": "1.37.2",
"@theia/workspace": "1.37.2"
"@theia/core": "1.43.1",
"@theia/editor": "1.43.1",
"@theia/electron": "1.43.1",
"@theia/filesystem": "1.43.1",
"@theia/markers": "1.43.1",
"@theia/messages": "1.43.1",
"@theia/monaco": "1.43.1",
"@theia/navigator": "1.43.1",
"@theia/plugin-ext": "1.43.1",
"@theia/plugin-ext-vscode": "1.43.1",
"@theia/preferences": "1.43.1",
"@theia/process": "1.43.1",
"@theia/terminal": "1.43.1",
"@theia/workspace": "1.43.1"
},
"devDependencies": {
"@theia/cli": "1.37.2",
"@theia/cli": "1.43.1",
"electron": "^23.2.4",
"electron-builder": "^23.6.0"
},
Expand Down
2 changes: 1 addition & 1 deletion applications/electron-app/scripts/electron-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ process.env.THEIA_PLUGINS = [process.env.THEIA_PLUGINS, `local-dir:${path.resolv
.join(',');

// Handover to the auto-generated electron application handler.
require('../src-gen/frontend/electron-main.js');
require('../lib/backend/electron-main.js');
5 changes: 3 additions & 2 deletions applications/electron-app/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* To reset delete this file and rerun theia build again.
*/
// @ts-check
const config = require('./gen-webpack.config.js');
const configs = require('./gen-webpack.config.js');
const nodeConfig = require('./gen-webpack.node.config.js');

/**
* Expose bundled modules on window.theia.moduleName namespace, e.g.
Expand All @@ -14,4 +15,4 @@ config.module.rules.push({
loader: require.resolve('@theia/application-manager/lib/expose-loader')
}); */

module.exports = config;
module.exports = [...configs, nodeConfig.config];
4 changes: 2 additions & 2 deletions extensions/crossmodel-lang/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
],
"dependencies": {
"@crossbreeze/protocol": "0.0.0",
"@eclipse-glsp/layout-elk": "1.1.0-RC10",
"@eclipse-glsp/server": "1.1.0-RC10",
"@eclipse-glsp/layout-elk": "2.0.0",
"@eclipse-glsp/server": "2.0.0",
"chalk": "~4.1.2",
"chevrotain": "~10.4.2",
"commander": "~10.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { CrossModelChangeBoundsOperationHandler } from '../handler/change-bounds
import { CrossModelCreateEdgeOperationHandler } from '../handler/create-edge-operation-handler';
import { CrossModelDeleteOperationHandler } from '../handler/delete-operation-handler';
import { CrossModelDropEntityOperationHandler } from '../handler/drop-entity-operation-handler';
import { CrossModelUpdateClientOperationHandler } from '../handler/update-glsp-client-handler';
import { CrossModelGModelFactory } from '../model/cross-model-gmodel-factory';
import { CrossModelIndex } from '../model/cross-model-index';
import { CrossModelState } from '../model/cross-model-state';
Expand Down Expand Up @@ -50,7 +49,6 @@ export class CrossModelDiagramModule extends DiagramModule {
binding.add(CrossModelDeleteOperationHandler); // delete elements
binding.add(CrossModelDropEntityOperationHandler);
binding.add(CrossModelAddEntityOperationHandler);
binding.add(CrossModelUpdateClientOperationHandler);
}

protected override configureContextActionProviders(binding: MultiBinding<ContextActionsProvider>): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
********************************************************************************/

import { AddEntityOperation } from '@crossbreeze/protocol';
import { Command, OperationHandler } from '@eclipse-glsp/server';
import { inject, injectable } from 'inversify';
import { Command, JsonOperationHandler, ModelState } from '@eclipse-glsp/server';
import { injectable, inject } from 'inversify';
import { DiagramNode, Entity } from '../../language-server/generated/ast';
import { createNodeToEntityReference } from '../../language-server/util/ast-util';
import { findAvailableNodeName } from '../../language-server/util/name-util';
Expand All @@ -15,19 +15,18 @@ import { CrossModelCommand } from './cross-model-command';
* An operation handler for the 'AddEntityOperation' that resolves the referenced entity by name and places it in a new node on the diagram.
*/
@injectable()
export class CrossModelAddEntityOperationHandler extends OperationHandler {
export class CrossModelAddEntityOperationHandler extends JsonOperationHandler {
override operationType = AddEntityOperation.KIND;

@inject(CrossModelState) protected state: CrossModelState;
@inject(ModelState) protected override modelState: CrossModelState;

createCommand(operation: AddEntityOperation): Command {
return new CrossModelCommand(this.state, () => this.createEntityNode(operation));
return new CrossModelCommand(this.modelState, () => this.createEntityNode(operation));
}

protected async createEntityNode(operation: AddEntityOperation): Promise<void> {
const container = this.state.diagramRoot;
const container = this.modelState.diagramRoot;
const refInfo = createNodeToEntityReference(container);
const scope = this.state.services.language.references.ScopeProvider.getScope(refInfo);
const scope = this.modelState.services.language.references.ScopeProvider.getScope(refInfo);
const entityDescription = scope.getElement(operation.entityName);

if (entityDescription) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
/********************************************************************************
* Copyright (c) 2023 CrossBreeze.
********************************************************************************/
import { ChangeBoundsOperation, Command, OperationHandler } from '@eclipse-glsp/server';
import { ChangeBoundsOperation, Command, JsonOperationHandler, ModelState } from '@eclipse-glsp/server';
import { inject, injectable } from 'inversify';
import { CrossModelState } from '../model/cross-model-state';
import { CrossModelCommand } from './cross-model-command';

@injectable()
export class CrossModelChangeBoundsOperationHandler extends OperationHandler {
operationType = ChangeBoundsOperation.KIND;
export class CrossModelChangeBoundsOperationHandler extends JsonOperationHandler {
operationType = ChangeBoundsOperation.KIND;
@inject(ModelState) protected override modelState: CrossModelState;

@inject(CrossModelState) protected state: CrossModelState;
createCommand(operation: ChangeBoundsOperation): Command {
return new CrossModelCommand(this.modelState, () => this.changeBounds(operation));
}

createCommand(operation: ChangeBoundsOperation): Command {
return new CrossModelCommand(this.state, () => this.changeBounds(operation));
}

protected changeBounds(operation: ChangeBoundsOperation): void {
operation.newBounds.forEach(elementAndBounds => {
const node = this.state.index.findDiagramNode(elementAndBounds.elementId);
if (node) {
// we store the given bounds directly in our diagram node
node.x = elementAndBounds.newPosition?.x || node.x;
node.y = elementAndBounds.newPosition?.y || node.y;
node.width = elementAndBounds.newSize.width;
node.height = elementAndBounds.newSize.height;
}
});
}
protected changeBounds(operation: ChangeBoundsOperation): void {
operation.newBounds.forEach(elementAndBounds => {
const node = this.modelState.index.findDiagramNode(elementAndBounds.elementId);
if (node) {
// we store the given bounds directly in our diagram node
node.x = elementAndBounds.newPosition?.x || node.x;
node.y = elementAndBounds.newPosition?.y || node.y;
node.width = elementAndBounds.newSize.width;
node.height = elementAndBounds.newSize.height;
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@
* Copyright (c) 2023 CrossBreeze.
********************************************************************************/

import {
Command,
CreateEdgeOperation,
CreateOperationHandler,
CreateOperationKind,
DefaultTypes,
OperationHandler,
TriggerEdgeCreationAction,
TriggerNodeCreationAction
} from '@eclipse-glsp/server';
import { Command, CreateEdgeOperation, DefaultTypes, JsonCreateEdgeOperationHandler, ModelState } from '@eclipse-glsp/server';
import { inject, injectable } from 'inversify';
import { URI, Utils as UriUtils } from 'vscode-uri';
import { CrossModelRoot, DiagramEdge, DiagramNode, Relationship, isCrossModelRoot } from '../../language-server/generated/ast';
Expand All @@ -20,39 +11,42 @@ import { CrossModelState } from '../model/cross-model-state';
import { CrossModelCommand } from './cross-model-command';

@injectable()
export class CrossModelCreateEdgeOperationHandler extends OperationHandler implements CreateOperationHandler {
export class CrossModelCreateEdgeOperationHandler extends JsonCreateEdgeOperationHandler {
override label = '1:1 Relationship';
elementTypeIds = [DefaultTypes.EDGE];
operationType: CreateOperationKind = CreateEdgeOperation.KIND;

@inject(CrossModelState) protected state: CrossModelState;

getTriggerActions(): (TriggerEdgeCreationAction | TriggerNodeCreationAction)[] {
// return trigger actions that are shown in the tool palette on the client
return this.elementTypeIds.map(typeId => TriggerEdgeCreationAction.create(typeId));
}
@inject(ModelState) protected override modelState: CrossModelState;

createCommand(operation: CreateEdgeOperation): Command {
return new CrossModelCommand(this.state, () => this.createEdge(operation));
return new CrossModelCommand(this.modelState, () => this.createEdge(operation));
}

protected async createEdge(operation: CreateEdgeOperation): Promise<void> {
const sourceNode = this.state.index.findDiagramNode(operation.sourceElementId);
const targetNode = this.state.index.findDiagramNode(operation.targetElementId);
const sourceNode = this.modelState.index.findDiagramNode(operation.sourceElementId);
const targetNode = this.modelState.index.findDiagramNode(operation.targetElementId);

if (sourceNode && targetNode) {
// before we can create a digram edge, we need to create the corresponding relationship that it is based on
const relationship = await this.createAndSaveRelationship(sourceNode, targetNode);
if (relationship) {
const edge: DiagramEdge = {
$type: DiagramEdge,
$container: this.state.diagramRoot,
$container: this.modelState.diagramRoot,
name: relationship.name,
relationship: { ref: relationship, $refText: this.state.nameProvider.getName(relationship) || relationship.name || '' },
sourceNode: { ref: sourceNode, $refText: this.state.nameProvider.getLocalName(sourceNode) || sourceNode.name || '' },
targetNode: { ref: targetNode, $refText: this.state.nameProvider.getLocalName(targetNode) || targetNode.name || '' }
relationship: {
ref: relationship,
$refText: this.modelState.nameProvider.getName(relationship) || relationship.name || ''
},
sourceNode: {
ref: sourceNode,
$refText: this.modelState.nameProvider.getLocalName(sourceNode) || sourceNode.name || ''
},
targetNode: {
ref: targetNode,
$refText: this.modelState.nameProvider.getLocalName(targetNode) || targetNode.name || ''
}
};
this.state.diagramRoot.edges.push(edge);
this.modelState.diagramRoot.edges.push(edge);
}
}
}
Expand All @@ -66,7 +60,7 @@ export class CrossModelCreateEdgeOperationHandler extends OperationHandler imple

// search for unique file name for the relationship and use file base name as relationship name
// if the user doesn't rename any files we should end up with unique names ;-)
const dirName = UriUtils.dirname(URI.parse(this.state.semanticUri));
const dirName = UriUtils.dirname(URI.parse(this.modelState.semanticUri));
const targetUri = UriUtils.joinPath(dirName, source + 'To' + target + '.relationship.cm');
const uri = Utils.findNewUri(targetUri);
const name = UriUtils.basename(uri).split('.')[0];
Expand All @@ -82,10 +76,10 @@ export class CrossModelCreateEdgeOperationHandler extends OperationHandler imple
child: { $refText: targetNode.entity?.$refText || '' }
};
relationshipRoot.relationship = relationship;
const text = this.state.semanticSerializer.serialize(relationshipRoot);
const text = this.modelState.semanticSerializer.serialize(relationshipRoot);

await this.state.modelService.save({ uri: uri.toString(), model: text, clientId: this.state.clientId });
const root = await this.state.modelService.request<CrossModelRoot>(uri.toString(), isCrossModelRoot);
await this.modelState.modelService.save({ uri: uri.toString(), model: text, clientId: this.modelState.clientId });
const root = await this.modelState.modelService.request<CrossModelRoot>(uri.toString(), isCrossModelRoot);
return root?.relationship;
}
}
Loading

0 comments on commit 021aa09

Please sign in to comment.