Skip to content

Commit

Permalink
feat: allow to type services and events
Browse files Browse the repository at this point in the history
This PR builds on upon diagram-js provided service and event typing:

* bpmn-io/diagram-js#862

It allows you to specify (public) types exposed by your BPMN toolkit
trough a ServiceMap. Events exposed are parsed from the EventBus
dynamic types.

Closes #2121
  • Loading branch information
nikku committed Apr 29, 2024
1 parent 4d0c0f4 commit 5c72257
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 12 deletions.
6 changes: 5 additions & 1 deletion lib/BaseModeler.js
Expand Up @@ -15,7 +15,11 @@ import BaseViewer from './BaseViewer';
/**
* A base modeler for BPMN 2.0 diagrams.
*
* See {@link Modeler} for a fully-featured modeler.
* See {@link bpmn-js/lib/Modeler} for a fully-featured modeler.
*
* @template [ServiceMap=null]
*
* @extends BaseViewer<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the modeler.
*/
Expand Down
39 changes: 38 additions & 1 deletion lib/BaseModeler.spec.ts
@@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';

import BaseModeler from './BaseModeler';

import { testViewer } from './BaseViewer.spec';
Expand All @@ -19,4 +22,38 @@ const extendedModeler = new BaseModeler({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});


// typed API usage

type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};

type EventMap = {

foo: FooEvent
};

type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};

const typedModeler = new BaseModeler<TypeMap>();

const bus = typedModeler.get('eventBus');

const canvas = typedModeler.get('canvas');

canvas.zoom('fit-viewport');

typedModeler.on('foo', event => {
console.log(event.foo);
});

typedModeler.get('eventBus').on('foo', e => console.log(e.foo));
50 changes: 47 additions & 3 deletions lib/BaseViewer.js
Expand Up @@ -31,6 +31,12 @@ import {
importBpmnDiagram
} from './import/Importer';

/**
* @template T
*
* @typedef { import('diagram-js/lib/core/EventBus').default<T> } EventBus
*/

/**
* @template T
*
Expand Down Expand Up @@ -116,12 +122,22 @@ import {
* } } SaveSVGDoneEvent
*/

/**
* @template Type
*
* @typedef { Type extends { eventBus: EventBus<infer X> } ? X : never } EventMap
*/

/**
* A base viewer for BPMN 2.0 diagrams.
*
* Have a look at {@link Viewer}, {@link NavigatedViewer} or {@link Modeler} for
* Have a look at {@link bpmn-js/lib/Viewer}, {@link bpmn-js/lib/NavigatedViewer} or {@link bpmn-js/lib/Modeler} for
* bundles that include actual features.
*
* @template [ServiceMap=null]
*
* @extends Diagram<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the viewer.
*/
export default function BaseViewer(options) {
Expand Down Expand Up @@ -542,9 +558,18 @@ BaseViewer.prototype.destroy = function() {
};

/**
* Register an event listener.
* @overlord
*
* Remove an event listener via {@link BaseViewer#off}.
* Register an event listener for events with the given name.
*
* The callback will be invoked with `event, ...additionalArguments`
* that have been passed to {@link EventBus#fire}.
*
* Returning false from a listener will prevent the events default action
* (if any is specified). To stop an event from being processed further in
* other listeners execute {@link Event#stopPropagation}.
*
* Returning anything but `undefined` from a listener will stop the listener propagation.
*
* @template T
*
Expand All @@ -553,6 +578,25 @@ BaseViewer.prototype.destroy = function() {
* @param {EventBusEventCallback<T>} callback The callback.
* @param {any} [that] Value of `this` the callback will be called with.
*/
/**
* Register an event listener for events with the given name.
*
* The callback will be invoked with `event, ...additionalArguments`
* that have been passed to {@link EventBus#fire}.
*
* Returning false from a listener will prevent the events default action
* (if any is specified). To stop an event from being processed further in
* other listeners execute {@link Event#stopPropagation}.
*
* Returning anything but `undefined` from a listener will stop the listener propagation.
*
* @template {keyof EventMap<ServiceMap>} EventName
*
* @param {EventName} events to subscribe to
* @param {number} [priority=1000] listen priority
* @param {EventBusEventCallback<(EventMap<ServiceMap>)[EventName]>} callback
* @param {any} [that] callback context
*/
BaseViewer.prototype.on = function(events, priority, callback, that) {
return this.get('eventBus').on(events, priority, callback, that);
};
Expand Down
38 changes: 36 additions & 2 deletions lib/BaseViewer.spec.ts
@@ -1,6 +1,6 @@
import CommandStack from 'diagram-js/lib/command/CommandStack';

import { Event } from 'diagram-js/lib/core/EventBus';
import EventBus, { Event } from 'diagram-js/lib/core/EventBus';

import BaseViewer, {
ImportDoneEvent,
Expand All @@ -11,6 +11,7 @@ import BaseViewer, {
} from './BaseViewer';

import OverlaysModule from 'diagram-js/lib/features/overlays';
import Canvas from 'diagram-js/lib/core/Canvas';

const viewer = new BaseViewer();

Expand Down Expand Up @@ -170,4 +171,37 @@ export function testViewer(viewer: BaseViewer) {
});

viewer.on<Event>('detach', () => {});
}
}

// typed API usage

type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};

type EventMap = {

foo: FooEvent
};

type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};

const typedViewer = new BaseViewer<TypeMap>();

const bus = typedViewer.get('eventBus');

const canvas = typedViewer.get('canvas');

canvas.zoom('fit-viewport');

typedViewer.on('foo', event => {
console.log(event.foo);
});

typedViewer.get('eventBus').on('foo', e => console.log(e.foo));
5 changes: 4 additions & 1 deletion lib/Modeler.js
Expand Up @@ -64,7 +64,6 @@ var initialDiagram =
/**
* A modeler for BPMN 2.0 diagrams.
*
*
* ## Extending the Modeler
*
* In order to extend the viewer pass extension modules to bootstrap via the
Expand Down Expand Up @@ -125,6 +124,10 @@ var initialDiagram =
* var bpmnModeler = new Modeler({ additionalModules: [ overrideModule ]});
* ```
*
* @template [ServiceMap=null]
*
* @extends BaseModeler<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the modeler.
*/
export default function Modeler(options) {
Expand Down
39 changes: 38 additions & 1 deletion lib/Modeler.spec.ts
@@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';

import Modeler from './Modeler';

import { testViewer } from './BaseViewer.spec';
Expand All @@ -21,4 +24,38 @@ const extendedModeler = new Modeler({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});


// typed API usage

type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};

type EventMap = {

foo: FooEvent
};

type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};

const typedViewer = new Modeler<TypeMap>();

const bus = typedViewer.get('eventBus');

const canvas = typedViewer.get('canvas');

canvas.zoom('fit-viewport');

typedViewer.on('foo', event => {
console.log(event.foo);
});

typedViewer.get('eventBus').on('foo', e => console.log(e.foo));
4 changes: 4 additions & 0 deletions lib/NavigatedViewer.js
Expand Up @@ -13,6 +13,10 @@ import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
/**
* A viewer with mouse and keyboard navigation features.
*
* @template [ServiceMap=null]
*
* @extends Viewer<ServiceMap>
*
* @param {BaseViewerOptions} [options]
*/
export default function NavigatedViewer(options) {
Expand Down
38 changes: 37 additions & 1 deletion lib/NavigatedViewer.spec.ts
@@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';

import NavigatedViewer from './NavigatedViewer';

import { testViewer } from './BaseViewer.spec';
Expand All @@ -14,4 +17,37 @@ const extendedViewer = new NavigatedViewer({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});

// typed API usage

type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};

type EventMap = {

foo: FooEvent
};

type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};

const typedViewer = new NavigatedViewer<TypeMap>();

const bus = typedViewer.get('eventBus');

const canvas = typedViewer.get('canvas');

canvas.zoom('fit-viewport');

typedViewer.on('foo', event => {
console.log(event.foo);
});

typedViewer.get('eventBus').on('foo', e => console.log(e.foo));
6 changes: 5 additions & 1 deletion lib/Viewer.js
Expand Up @@ -17,7 +17,7 @@ import BaseViewer from './BaseViewer';
/**
* A viewer for BPMN 2.0 diagrams.
*
* Have a look at {@link NavigatedViewer} or {@link Modeler} for bundles that include
* Have a look at {@link bpmn-js/lib/NavigatedViewer} or {@link bpmn-js/lib/Modeler} for bundles that include
* additional features.
*
*
Expand Down Expand Up @@ -53,6 +53,10 @@ import BaseViewer from './BaseViewer';
* bpmnViewer.importXML(...);
* ```
*
* @template [ServiceMap=null]
*
* @extends BaseViewer<ServiceMap>
*
* @param {BaseViewerOptions} [options] The options to configure the viewer.
*/
export default function Viewer(options) {
Expand Down
39 changes: 38 additions & 1 deletion lib/Viewer.spec.ts
@@ -1,3 +1,6 @@
import Canvas from 'diagram-js/lib/core/Canvas';
import EventBus from 'diagram-js/lib/core/EventBus';

import Viewer from './Viewer';

import { testViewer } from './BaseViewer.spec';
Expand All @@ -14,4 +17,38 @@ const extendedViewer = new Viewer({
propertiesPanel: {
attachTo: '#properties-panel'
}
});
});


// typed API usage

type FooEvent = {
/**
* Very cool field!
*/
foo: string;
};

type EventMap = {

foo: FooEvent
};

type TypeMap = {
canvas: Canvas,
eventBus: EventBus<EventMap>
};

const typedViewer = new Viewer<TypeMap>();

const bus = typedViewer.get('eventBus');

const canvas = typedViewer.get('canvas');

canvas.zoom('fit-viewport');

typedViewer.on('foo', event => {
console.log(event.foo);
});

typedViewer.get('eventBus').on('foo', e => console.log(e.foo));

0 comments on commit 5c72257

Please sign in to comment.