From 9aae9d8a259985e84f32317a1228aadffe7e20ba Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Mon, 18 Mar 2024 10:13:53 +0100 Subject: [PATCH 1/2] Improve relationship creation tool - Adapt edge creation tool to desired behavior - Only perform selection when select tool is active (default) - Select edge after it has been created --- .../handler/create-edge-operation-handler.ts | 14 +- .../src/browser/crossmodel-diagram-module.ts | 12 +- .../mapping-edge-creation-tool.ts | 4 +- .../edge-creation-tool-module.ts | 14 ++ .../system-edge-creation-tool.ts | 227 ++++++++++++++++++ .../select-tool/select-tool-module.ts | 23 ++ .../system-diagram/select-tool/select-tool.ts | 25 ++ .../system-diagram-configuration.ts | 11 +- packages/glsp-client/style/diagram.css | 16 ++ 9 files changed, 337 insertions(+), 9 deletions(-) create mode 100644 packages/glsp-client/src/browser/system-diagram/edge-creation-tool/edge-creation-tool-module.ts create mode 100644 packages/glsp-client/src/browser/system-diagram/edge-creation-tool/system-edge-creation-tool.ts create mode 100644 packages/glsp-client/src/browser/system-diagram/select-tool/select-tool-module.ts create mode 100644 packages/glsp-client/src/browser/system-diagram/select-tool/select-tool.ts diff --git a/extensions/crossmodel-lang/src/glsp-server/system-diagram/handler/create-edge-operation-handler.ts b/extensions/crossmodel-lang/src/glsp-server/system-diagram/handler/create-edge-operation-handler.ts index 3fa0f6d..2150476 100644 --- a/extensions/crossmodel-lang/src/glsp-server/system-diagram/handler/create-edge-operation-handler.ts +++ b/extensions/crossmodel-lang/src/glsp-server/system-diagram/handler/create-edge-operation-handler.ts @@ -3,7 +3,14 @@ ********************************************************************************/ import { RELATIONSHIP_EDGE_TYPE } from '@crossbreeze/protocol'; -import { Command, CreateEdgeOperation, JsonCreateEdgeOperationHandler, ModelState } from '@eclipse-glsp/server'; +import { + ActionDispatcher, + Command, + CreateEdgeOperation, + JsonCreateEdgeOperationHandler, + ModelState, + SelectAction +} from '@eclipse-glsp/server'; import { inject, injectable } from 'inversify'; import { URI, Utils as UriUtils } from 'vscode-uri'; import { CrossModelRoot, EntityNode, Relationship, RelationshipEdge, isCrossModelRoot } from '../../../language-server/generated/ast.js'; @@ -17,6 +24,7 @@ export class SystemDiagramCreateEdgeOperationHandler extends JsonCreateEdgeOpera elementTypeIds = [RELATIONSHIP_EDGE_TYPE]; @inject(ModelState) protected override modelState!: SystemModelState; + @inject(ActionDispatcher) protected actionDispatcher!: ActionDispatcher; createCommand(operation: CreateEdgeOperation): Command { return new CrossModelCommand(this.modelState, () => this.createEdge(operation)); @@ -48,6 +56,9 @@ export class SystemDiagramCreateEdgeOperationHandler extends JsonCreateEdgeOpera } }; this.modelState.systemDiagram.edges.push(edge); + this.actionDispatcher.dispatchAfterNextUpdate( + SelectAction.create({ selectedElementsIDs: [this.modelState.idProvider.getLocalId(edge) ?? edge.id] }) + ); } } } @@ -66,6 +77,7 @@ export class SystemDiagramCreateEdgeOperationHandler extends JsonCreateEdgeOpera $container: relationshipRoot, id: this.modelState.idProvider.findNextId(Relationship, source + 'To' + target), type: '1:1', + attributes: [], parent: { $refText: sourceNode.entity?.$refText || '' }, child: { $refText: targetNode.entity?.$refText || '' } }; diff --git a/packages/glsp-client/src/browser/crossmodel-diagram-module.ts b/packages/glsp-client/src/browser/crossmodel-diagram-module.ts index 9abca37..fb04dfe 100644 --- a/packages/glsp-client/src/browser/crossmodel-diagram-module.ts +++ b/packages/glsp-client/src/browser/crossmodel-diagram-module.ts @@ -2,7 +2,15 @@ * Copyright (c) 2024 CrossBreeze. ********************************************************************************/ -import { ConsoleLogger, LogLevel, SetViewportAction, TYPES, bindAsService, configureActionHandler } from '@eclipse-glsp/client'; +import { + ConsoleLogger, + LogLevel, + SetViewportAction, + TYPES, + bindAsService, + bindOrRebind, + configureActionHandler +} from '@eclipse-glsp/client'; import { TheiaGLSPSelectionForwarder } from '@eclipse-glsp/theia-integration'; import { ContainerModule, interfaces } from '@theia/core/shared/inversify'; import { GridAlignmentHandler } from './crossmodel-grid-handler'; @@ -16,7 +24,7 @@ export function createCrossModelDiagramModule(registry: interfaces.ContainerModu rebind(TYPES.LogLevel).toConstantValue(LogLevel.warn); bindAsService(bind, CrossModelSelectionDataService, CrossModelGLSPSelectionDataService); bind(CrossModelTheiaGLSPSelectionForwarder).toSelf().inSingletonScope(); - rebind(TheiaGLSPSelectionForwarder).toService(CrossModelTheiaGLSPSelectionForwarder); + bindOrRebind({ bind, isBound, rebind }, TheiaGLSPSelectionForwarder).toService(CrossModelTheiaGLSPSelectionForwarder); bind(TYPES.ISnapper).to(CrossModelGridSnapper); configureActionHandler({ bind, isBound }, SetViewportAction.KIND, GridAlignmentHandler); registry(bind, unbind, isBound, rebind, unbindAsync, onActivation, onDeactivation); diff --git a/packages/glsp-client/src/browser/mapping-diagram/edge-creation-tool/mapping-edge-creation-tool.ts b/packages/glsp-client/src/browser/mapping-diagram/edge-creation-tool/mapping-edge-creation-tool.ts index dd63bd8..101bd4a 100644 --- a/packages/glsp-client/src/browser/mapping-diagram/edge-creation-tool/mapping-edge-creation-tool.ts +++ b/packages/glsp-client/src/browser/mapping-diagram/edge-creation-tool/mapping-edge-creation-tool.ts @@ -9,6 +9,7 @@ import { Args, Bounds, CursorCSS, + Disposable, EdgeCreationTool, EdgeCreationToolMouseListener, FeedbackEdgeEndMovingMouseListener, @@ -156,9 +157,6 @@ export class MappingEdgeCreationToolMouseListener extends EdgeCreationToolMouseL DrawFeedbackEdgeAction.create({ elementTypeId: this.triggerAction.elementTypeId, sourceId: this.source }) ]); } - [Symbol.dispose](): void { - throw new Error('Method not implemented.'); - } override mouseOver(target: GModelElement, _event: MouseEvent): Action[] { const otherAttributeParent = revertAttributeParent(this.triggerAction.args.sourceAttributeParent); diff --git a/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/edge-creation-tool-module.ts b/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/edge-creation-tool-module.ts new file mode 100644 index 0000000..bf76062 --- /dev/null +++ b/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/edge-creation-tool-module.ts @@ -0,0 +1,14 @@ +/******************************************************************************** + * Copyright (c) 2024 CrossBreeze. + ********************************************************************************/ + +import { EdgeCreationTool, FeatureModule, edgeCreationToolModule, viewportModule } from '@eclipse-glsp/client'; +import { SystemEdgeCreationTool } from './system-edge-creation-tool'; + +export const systemEdgeCreationToolModule = new FeatureModule( + (bind, unbind, isBound, rebind) => { + const context = { bind, unbind, isBound, rebind }; + context.rebind(EdgeCreationTool).to(SystemEdgeCreationTool).inSingletonScope(); + }, + { requires: [edgeCreationToolModule, viewportModule] } +); diff --git a/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/system-edge-creation-tool.ts b/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/system-edge-creation-tool.ts new file mode 100644 index 0000000..efcea54 --- /dev/null +++ b/packages/glsp-client/src/browser/system-diagram/edge-creation-tool/system-edge-creation-tool.ts @@ -0,0 +1,227 @@ +/******************************************************************************** + * Copyright (c) 2024 CrossBreeze. + ********************************************************************************/ + +import { + Action, + Connectable, + CreateEdgeOperation, + CursorCSS, + Disposable, + DragAwareMouseListener, + EdgeCreationTool, + EnableDefaultToolsAction, + FeedbackEdgeEndMovingMouseListener, + GEdge, + GLSPActionDispatcher, + GModelElement, + HoverFeedbackAction, + ITypeHintProvider, + ModifyCSSFeedbackAction, + Point, + TriggerEdgeCreationAction, + cursorFeedbackAction, + findParentByFeature, + isConnectable, + isCtrlOrCmd +} from '@eclipse-glsp/client'; +import { + DrawFeedbackEdgeAction, + RemoveFeedbackEdgeAction +} from '@eclipse-glsp/client/lib/features/tools/edge-creation/dangling-edge-feedback'; +import { injectable } from '@theia/core/shared/inversify'; + +const CSS_EDGE_CREATION = 'edge-creation'; + +@injectable() +export class SystemEdgeCreationTool extends EdgeCreationTool { + override doEnable(): void { + const mouseMovingFeedback = new FeedbackEdgeEndMovingMouseListener(this.anchorRegistry, this.feedbackDispatcher); + const listener = new SystemEdgeCreationToolMouseListener(this.triggerAction, this.actionDispatcher, this.typeHintProvider, this); + this.toDisposeOnDisable.push( + listener, + mouseMovingFeedback, + this.mouseTool.registerListener(listener), + this.mouseTool.registerListener(mouseMovingFeedback), + this.registerFeedback([], this, [ + RemoveFeedbackEdgeAction.create(), + cursorFeedbackAction(), + ModifyCSSFeedbackAction.create({ remove: [CSS_EDGE_CREATION] }) + ]) + ); + } +} + +export interface ConnectionContext { + element?: GModelElement & Connectable; + canConnect?: boolean; +} + +export interface DragConnectionContext { + element: GModelElement & Connectable; + dragStart: Point; +} + +export class SystemEdgeCreationToolMouseListener extends DragAwareMouseListener implements Disposable { + protected source?: string; + protected target?: string; + protected proxyEdge: GEdge; + + protected dragContext?: DragConnectionContext; + protected mouseMoveFeedback?: Disposable; + protected sourceFeedback?: Disposable; + + constructor( + protected triggerAction: TriggerEdgeCreationAction, + protected actionDispatcher: GLSPActionDispatcher, + protected typeHintProvider: ITypeHintProvider, + protected tool: EdgeCreationTool + ) { + super(); + this.proxyEdge = new GEdge(); + this.proxyEdge.type = triggerAction.elementTypeId; + } + + protected isSourceSelected(): boolean { + return this.source !== undefined; + } + + protected isTargetSelected(): boolean { + return this.target !== undefined; + } + + override mouseDown(target: GModelElement, event: MouseEvent): Action[] { + const result = super.mouseDown(target, event); + if (event.button === 0 && !this.isSourceSelected()) { + // update the current target + const context = this.calculateContext(target, event); + if (context.element && context.canConnect) { + this.dragContext = { element: context.element, dragStart: { x: event.clientX, y: event.clientY } }; + } + } + return result; + } + + override mouseMove(target: GModelElement, event: MouseEvent): Action[] { + const result = super.mouseMove(target, event); + if (this.isMouseDrag && this.dragContext && !this.isSourceSelected()) { + const dragDistance = Point.maxDistance(this.dragContext.dragStart, { x: event.clientX, y: event.clientY }); + if (dragDistance > 3) { + // assign source if possible + this.source = this.dragContext.element.id; + this.tool.registerFeedback([ + DrawFeedbackEdgeAction.create({ elementTypeId: this.triggerAction.elementTypeId, sourceId: this.source }) + ]); + this.dragContext = undefined; + } + } + this.updateFeedback(target, event); + return result; + } + + override draggingMouseUp(target: GModelElement, event: MouseEvent): Action[] { + const result = super.draggingMouseUp(target, event); + if (this.isSourceSelected()) { + const context = this.calculateContext(target, event); + if (context.element && context.canConnect) { + this.target = context.element.id; + result.push( + CreateEdgeOperation.create({ + elementTypeId: this.triggerAction.elementTypeId, + sourceElementId: this.source!, + targetElementId: this.target, + args: this.triggerAction.args + }) + ); + if (!isCtrlOrCmd(event)) { + result.push(EnableDefaultToolsAction.create()); + } + } + } + this.reinitialize(); + return result; + } + + override nonDraggingMouseUp(_element: GModelElement, event: MouseEvent): Action[] { + this.reinitialize(); + return [EnableDefaultToolsAction.create()]; + } + + protected canConnect(element: GModelElement | undefined, role: 'source' | 'target'): boolean { + return ( + !!element && + !!isConnectable(element) && + element.canConnect(this.proxyEdge, role) && + (role !== 'target' || this.source !== element?.id) + ); + } + + protected updateFeedback(target: GModelElement, event: MouseEvent): void { + const context = this.calculateContext(target, event); + + // source element feedback + if (this.isSourceSelected()) { + this.sourceFeedback = this.tool.registerFeedback( + [HoverFeedbackAction.create({ mouseoverElement: this.source!, mouseIsOver: true })], + this.proxyEdge, + [HoverFeedbackAction.create({ mouseoverElement: this.source!, mouseIsOver: false })] + ); + } + + // cursor feedback + if (!context.element || context.element?.id === this.source) { + // by default we want to use the edge creation CSS when the tool is active + this.registerFeedback( + [ModifyCSSFeedbackAction.create({ add: [CSS_EDGE_CREATION] })], + [ModifyCSSFeedbackAction.create({ remove: [CSS_EDGE_CREATION] })] + ); + return; + } + + if (!context.canConnect) { + this.registerFeedback([cursorFeedbackAction(CursorCSS.OPERATION_NOT_ALLOWED)], [cursorFeedbackAction()]); + return; + } + + const cursorCss = this.isSourceSelected() ? CursorCSS.EDGE_CREATION_TARGET : CursorCSS.EDGE_CREATION_SOURCE; + this.registerFeedback( + [cursorFeedbackAction(cursorCss), HoverFeedbackAction.create({ mouseoverElement: context.element.id, mouseIsOver: true })], + [cursorFeedbackAction(), HoverFeedbackAction.create({ mouseoverElement: context.element.id, mouseIsOver: false })] + ); + } + + protected registerFeedback(feedbackActions: Action[], cleanupActions?: Action[]): Disposable { + this.mouseMoveFeedback?.dispose(); + this.mouseMoveFeedback = this.tool.registerFeedback(feedbackActions, this, cleanupActions); + return this.mouseMoveFeedback; + } + + protected calculateContext(target: GModelElement, event: MouseEvent, previousContext?: ConnectionContext): ConnectionContext { + const context: ConnectionContext = {}; + context.element = findParentByFeature(target, isConnectable); + if (previousContext && previousContext.element === context.element) { + return previousContext; + } + if (!this.isSourceSelected()) { + context.canConnect = this.canConnect(context.element, 'source'); + } else if (!this.isTargetSelected()) { + context.canConnect = this.canConnect(context.element, 'target'); + } else { + context.canConnect = false; + } + return context; + } + + protected reinitialize(): void { + this.source = undefined; + this.target = undefined; + this.tool.registerFeedback([RemoveFeedbackEdgeAction.create()]); + this.dragContext = undefined; + this.mouseMoveFeedback?.dispose(); + this.sourceFeedback?.dispose(); + } + + dispose(): void { + this.reinitialize(); + } +} diff --git a/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool-module.ts b/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool-module.ts new file mode 100644 index 0000000..043ea6f --- /dev/null +++ b/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool-module.ts @@ -0,0 +1,23 @@ +/******************************************************************************** + * Copyright (c) 2024 CrossBreeze. + ********************************************************************************/ +import { + FeatureModule, + RankedSelectMouseListener, + SelectAllCommand, + SelectCommand, + SelectFeedbackCommand, + TYPES, + bindAsService, + configureCommand +} from '@eclipse-glsp/client'; +import { SystemSelectTool } from './select-tool'; + +export const systemSelectModule = new FeatureModule((bind, _unbind, isBound) => { + const context = { bind, isBound }; + configureCommand(context, SelectCommand); + configureCommand(context, SelectAllCommand); + configureCommand(context, SelectFeedbackCommand); + bindAsService(context, TYPES.IDefaultTool, SystemSelectTool); + bind(RankedSelectMouseListener).toSelf().inSingletonScope(); +}); diff --git a/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool.ts b/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool.ts new file mode 100644 index 0000000..9951a35 --- /dev/null +++ b/packages/glsp-client/src/browser/system-diagram/select-tool/select-tool.ts @@ -0,0 +1,25 @@ +/******************************************************************************** + * Copyright (c) 2024 CrossBreeze. + ********************************************************************************/ + +import { GLSPMouseTool, RankedSelectMouseListener, Tool } from '@eclipse-glsp/client'; +import { inject, injectable } from '@theia/core/shared/inversify'; + +@injectable() +export class SystemSelectTool implements Tool { + static ID = 'tool_system_select'; + + id = SystemSelectTool.ID; + isEditTool = false; + + @inject(GLSPMouseTool) protected mouseTool: GLSPMouseTool; + @inject(RankedSelectMouseListener) protected listener: RankedSelectMouseListener; + + enable(): void { + this.mouseTool.registerListener(this.listener); + } + + disable(): void { + this.mouseTool.deregister(this.listener); + } +} diff --git a/packages/glsp-client/src/browser/system-diagram/system-diagram-configuration.ts b/packages/glsp-client/src/browser/system-diagram/system-diagram-configuration.ts index 7325f7d..4edc4be 100644 --- a/packages/glsp-client/src/browser/system-diagram/system-diagram-configuration.ts +++ b/packages/glsp-client/src/browser/system-diagram/system-diagram-configuration.ts @@ -2,22 +2,27 @@ * Copyright (c) 2023 CrossBreeze. ********************************************************************************/ import { ATTRIBUTE_COMPARTMENT_TYPE, ENTITY_NODE_TYPE, RELATIONSHIP_EDGE_TYPE } from '@crossbreeze/protocol'; -import { configureDefaultModelElements, configureModelElement, initializeDiagramContainer } from '@eclipse-glsp/client'; +import { configureDefaultModelElements, configureModelElement, initializeDiagramContainer, selectModule } from '@eclipse-glsp/client'; import { ContainerConfiguration } from '@eclipse-glsp/protocol'; import { GLSPDiagramConfiguration } from '@eclipse-glsp/theia-integration'; import { Container } from '@theia/core/shared/inversify/index'; import { SystemDiagramLanguage } from '../../common/crossmodel-diagram-language'; import { createCrossModelDiagramModule } from '../crossmodel-diagram-module'; +import { AttributeCompartment } from '../model'; import { AttributeCompartmentView } from '../views'; +import { systemEdgeCreationToolModule } from './edge-creation-tool/edge-creation-tool-module'; import { EntityNode, RelationshipEdge } from './model'; +import { systemSelectModule } from './select-tool/select-tool-module'; import { EntityNodeView, RelationshipEdgeView } from './views'; -import { AttributeCompartment } from '../model'; export class SystemDiagramConfiguration extends GLSPDiagramConfiguration { diagramType: string = SystemDiagramLanguage.diagramType; configureContainer(container: Container, ...containerConfiguration: ContainerConfiguration): Container { - return initializeDiagramContainer(container, ...containerConfiguration, systemDiagramModule); + return initializeDiagramContainer(container, ...containerConfiguration, systemDiagramModule, systemEdgeCreationToolModule, { + add: systemSelectModule, + remove: selectModule + }); } } diff --git a/packages/glsp-client/style/diagram.css b/packages/glsp-client/style/diagram.css index 3330bc1..a5b5f81 100644 --- a/packages/glsp-client/style/diagram.css +++ b/packages/glsp-client/style/diagram.css @@ -31,6 +31,13 @@ background-size: 11px; } +.sprotty + .edge-creation:not(.edge-check-pending-mode):not(.edge-creation-select-source-mode):not(.edge-creation-select-target-mode):not( + .edge-reconnect-select-target-mode:not(.edge-modification-not-allowed-mode) + ) { + cursor: ew-resize; +} + .sprotty text { font-family: monospace; } @@ -108,6 +115,10 @@ display: none; } +.sprotty[id^='system-diagram'] .tool-palette .tool-button { + outline-width: 0; +} + /* we know there is only the 1:1 relationship tool for now, if we ever need more styling, better to create a complete custom toolbar */ .sprotty[id^='system-diagram'] .tool-palette .tool-button::before { margin-right: var(--theia-ui-padding); @@ -118,6 +129,11 @@ -moz-osx-font-smoothing: grayscale; } +.sprotty[id^='system-diagram'] .tool-palette .tool-button.clicked { + background: var(--theia-activityBarBadge-background); + color: var(--theia-activityBarBadge-foreground); +} + .command-palette { animation: none; } From 2c658afc9bb1e11b07e5921e093e30429af92e93 Mon Sep 17 00:00:00 2001 From: Harmen Wessels <97173058+harmen-xb@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:44:40 +0000 Subject: [PATCH 2/2] Moved example files into subfolders for readability. --- .../ExampleDWH/{ => dagrams}/ExampleDWH.system-diagram.cm | 0 .../mapping-example/ExampleDWH/{ => entities}/CalcAge.entity.cm | 0 .../ExampleDWH/{ => entities}/CompleteCustomer.entity.cm | 0 .../{ => Sources}/ExampleCRM/diagrams/CRM.diagram.cm | 0 .../{ => Sources}/ExampleCRM/entities/Address.entity.cm | 0 .../{ => Sources}/ExampleCRM/entities/Customer.entity.cm | 0 .../{ => Sources}/ExampleCRM/entities/Order.entity.cm | 0 examples/mapping-example/{ => Sources}/ExampleCRM/package.json | 0 .../ExampleCRM/relationships/Address_Customer.relationship.cm | 0 .../ExampleCRM/relationships/Order_Customer.relationship.cm | 0 .../ExampleMasterdata/entities}/Country.entity.cm | 0 .../mapping-example/{ => Sources}/ExampleMasterdata/package.json | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename examples/mapping-example/ExampleDWH/{ => dagrams}/ExampleDWH.system-diagram.cm (100%) rename examples/mapping-example/ExampleDWH/{ => entities}/CalcAge.entity.cm (100%) rename examples/mapping-example/ExampleDWH/{ => entities}/CompleteCustomer.entity.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/diagrams/CRM.diagram.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/entities/Address.entity.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/entities/Customer.entity.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/entities/Order.entity.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/package.json (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/relationships/Address_Customer.relationship.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleCRM/relationships/Order_Customer.relationship.cm (100%) rename examples/mapping-example/{ExampleMasterdata => Sources/ExampleMasterdata/entities}/Country.entity.cm (100%) rename examples/mapping-example/{ => Sources}/ExampleMasterdata/package.json (100%) diff --git a/examples/mapping-example/ExampleDWH/ExampleDWH.system-diagram.cm b/examples/mapping-example/ExampleDWH/dagrams/ExampleDWH.system-diagram.cm similarity index 100% rename from examples/mapping-example/ExampleDWH/ExampleDWH.system-diagram.cm rename to examples/mapping-example/ExampleDWH/dagrams/ExampleDWH.system-diagram.cm diff --git a/examples/mapping-example/ExampleDWH/CalcAge.entity.cm b/examples/mapping-example/ExampleDWH/entities/CalcAge.entity.cm similarity index 100% rename from examples/mapping-example/ExampleDWH/CalcAge.entity.cm rename to examples/mapping-example/ExampleDWH/entities/CalcAge.entity.cm diff --git a/examples/mapping-example/ExampleDWH/CompleteCustomer.entity.cm b/examples/mapping-example/ExampleDWH/entities/CompleteCustomer.entity.cm similarity index 100% rename from examples/mapping-example/ExampleDWH/CompleteCustomer.entity.cm rename to examples/mapping-example/ExampleDWH/entities/CompleteCustomer.entity.cm diff --git a/examples/mapping-example/ExampleCRM/diagrams/CRM.diagram.cm b/examples/mapping-example/Sources/ExampleCRM/diagrams/CRM.diagram.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/diagrams/CRM.diagram.cm rename to examples/mapping-example/Sources/ExampleCRM/diagrams/CRM.diagram.cm diff --git a/examples/mapping-example/ExampleCRM/entities/Address.entity.cm b/examples/mapping-example/Sources/ExampleCRM/entities/Address.entity.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/entities/Address.entity.cm rename to examples/mapping-example/Sources/ExampleCRM/entities/Address.entity.cm diff --git a/examples/mapping-example/ExampleCRM/entities/Customer.entity.cm b/examples/mapping-example/Sources/ExampleCRM/entities/Customer.entity.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/entities/Customer.entity.cm rename to examples/mapping-example/Sources/ExampleCRM/entities/Customer.entity.cm diff --git a/examples/mapping-example/ExampleCRM/entities/Order.entity.cm b/examples/mapping-example/Sources/ExampleCRM/entities/Order.entity.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/entities/Order.entity.cm rename to examples/mapping-example/Sources/ExampleCRM/entities/Order.entity.cm diff --git a/examples/mapping-example/ExampleCRM/package.json b/examples/mapping-example/Sources/ExampleCRM/package.json similarity index 100% rename from examples/mapping-example/ExampleCRM/package.json rename to examples/mapping-example/Sources/ExampleCRM/package.json diff --git a/examples/mapping-example/ExampleCRM/relationships/Address_Customer.relationship.cm b/examples/mapping-example/Sources/ExampleCRM/relationships/Address_Customer.relationship.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/relationships/Address_Customer.relationship.cm rename to examples/mapping-example/Sources/ExampleCRM/relationships/Address_Customer.relationship.cm diff --git a/examples/mapping-example/ExampleCRM/relationships/Order_Customer.relationship.cm b/examples/mapping-example/Sources/ExampleCRM/relationships/Order_Customer.relationship.cm similarity index 100% rename from examples/mapping-example/ExampleCRM/relationships/Order_Customer.relationship.cm rename to examples/mapping-example/Sources/ExampleCRM/relationships/Order_Customer.relationship.cm diff --git a/examples/mapping-example/ExampleMasterdata/Country.entity.cm b/examples/mapping-example/Sources/ExampleMasterdata/entities/Country.entity.cm similarity index 100% rename from examples/mapping-example/ExampleMasterdata/Country.entity.cm rename to examples/mapping-example/Sources/ExampleMasterdata/entities/Country.entity.cm diff --git a/examples/mapping-example/ExampleMasterdata/package.json b/examples/mapping-example/Sources/ExampleMasterdata/package.json similarity index 100% rename from examples/mapping-example/ExampleMasterdata/package.json rename to examples/mapping-example/Sources/ExampleMasterdata/package.json