From 491b6d2b17d4b9175930a0f5e15a6f54f8da8c62 Mon Sep 17 00:00:00 2001 From: Matthias Lehner <143808484+matthiaslehnertum@users.noreply.github.com> Date: Mon, 16 Oct 2023 04:47:00 +0900 Subject: [PATCH] Add initial bpmn diagram implementation (#303) --- .gitignore | 3 +- public/index.html.ejs | 3 +- .../components/create-pane/create-pane.tsx | 5 + src/main/i18n/de.json | 23 ++++ src/main/i18n/en.json | 23 ++++ .../bpmn-annotation-component.tsx | 41 +++++++ .../bpmn/bpmn-annotation/bpmn-annotation.ts | 18 +++ .../bpmn-call-activity-component.tsx | 35 ++++++ .../bpmn-call-activity/bpmn-call-activity.ts | 15 +++ .../bpmn-conversation-component.tsx | 35 ++++++ .../bpmn-conversation-update.tsx | 94 ++++++++++++++ .../bpmn-conversation/bpmn-conversation.ts | 47 +++++++ .../packages/bpmn/bpmn-diagram-preview.ts | 93 ++++++++++++++ .../bpmn-end-event-component.tsx | 55 +++++++++ .../bpmn/bpmn-end-event/bpmn-end-event.ts | 27 ++++ .../bpmn/bpmn-flow/bpmn-flow-component.tsx | 90 ++++++++++++++ .../bpmn/bpmn-flow/bpmn-flow-update.tsx | 115 ++++++++++++++++++ src/main/packages/bpmn/bpmn-flow/bpmn-flow.ts | 40 ++++++ .../bpmn-gateway/bpmn-gateway-component.tsx | 47 +++++++ .../bpmn/bpmn-gateway/bpmn-gateway-update.tsx | 110 +++++++++++++++++ .../bpmn/bpmn-gateway/bpmn-gateway.ts | 54 ++++++++ .../bpmn-complex-gateway-component.tsx | 48 ++++++++ .../bpmn-event-based-gateway-component.tsx | 54 ++++++++ ...xclusive-event-based-gateway-component.tsx | 48 ++++++++ .../bpmn-exclusive-gateway-component.tsx | 38 ++++++ .../bpmn-inclusive-gateway-component.tsx | 34 ++++++ ...parallel-event-based-gateway-component.tsx | 44 +++++++ .../bpmn-parallel-gateway-component.tsx | 38 ++++++ .../bpmn-intermediate-event-component.tsx | 60 +++++++++ .../bpmn-intermediate-event.ts | 26 ++++ .../bpmn-start-event-component.tsx | 54 ++++++++ .../bpmn/bpmn-start-event/bpmn-start-event.ts | 27 ++++ .../bpmn-subprocess-component.tsx | 35 ++++++ .../bpmn/bpmn-subprocess/bpmn-subprocess.ts | 15 +++ .../bpmn/bpmn-task/bpmn-task-component.tsx | 34 ++++++ src/main/packages/bpmn/bpmn-task/bpmn-task.ts | 15 +++ .../bpmn-transaction-component.tsx | 44 +++++++ .../bpmn/bpmn-transaction/bpmn-transaction.ts | 15 +++ src/main/packages/bpmn/index.ts | 18 +++ src/main/packages/components.ts | 22 ++++ src/main/packages/diagram-type.ts | 1 + src/main/packages/popups.ts | 14 +++ src/main/packages/uml-element-type.ts | 6 +- src/main/packages/uml-elements.ts | 20 +++ src/main/packages/uml-relationship-type.ts | 6 +- src/main/packages/uml-relationships.ts | 2 + src/main/typings.ts | 14 +++ .../bpmn-annotation-component-test.tsx.snap | 43 +++++++ .../bpmn-annotation-component-test.tsx | 24 ++++ ...bpmn-call-activity-component-test.tsx.snap | 38 ++++++ .../bpmn-call-activity-component-test.tsx | 26 ++++ .../bpmn-conversation-component-test.tsx.snap | 34 ++++++ .../bpmn-conversation-component-test.tsx | 26 ++++ .../bpmn-end-event-component-test.tsx.snap | 36 ++++++ .../bpmn-end-event-component-test.tsx | 26 ++++ .../bpmn-flow-component-test.tsx.snap | 69 +++++++++++ .../bpmn-flow/bpmn-flow-component-test.tsx | 26 ++++ .../bpmn-gateway-component-test.tsx.snap | 47 +++++++ .../bpmn-gateway-component-test.tsx | 26 ++++ ...intermediate-event-component-test.tsx.snap | 43 +++++++ ...bpmn-intermediate-event-component-test.tsx | 26 ++++ .../bpmn-start-event-component-test.tsx.snap | 35 ++++++ .../bpmn-start-event-component-test.tsx | 26 ++++ .../bpmn-subprocess-component-test.tsx.snap | 38 ++++++ .../bpmn-subprocess-component-test.tsx | 26 ++++ .../bpmn-task-component-test.tsx.snap | 37 ++++++ .../bpmn-task/bpmn-task-component-test.tsx | 26 ++++ .../bpmn-transaction-component-test.tsx.snap | 48 ++++++++ .../bpmn-transaction-component-test.tsx | 26 ++++ 69 files changed, 2453 insertions(+), 4 deletions(-) create mode 100644 src/main/packages/bpmn/bpmn-annotation/bpmn-annotation-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-annotation/bpmn-annotation.ts create mode 100644 src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity.ts create mode 100644 src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-update.tsx create mode 100644 src/main/packages/bpmn/bpmn-conversation/bpmn-conversation.ts create mode 100644 src/main/packages/bpmn/bpmn-diagram-preview.ts create mode 100644 src/main/packages/bpmn/bpmn-end-event/bpmn-end-event-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-end-event/bpmn-end-event.ts create mode 100644 src/main/packages/bpmn/bpmn-flow/bpmn-flow-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-flow/bpmn-flow-update.tsx create mode 100644 src/main/packages/bpmn/bpmn-flow/bpmn-flow.ts create mode 100644 src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-update.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/bpmn-gateway.ts create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-complex-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-event-based-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-event-based-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-inclusive-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-event-based-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-gateway-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event.ts create mode 100644 src/main/packages/bpmn/bpmn-start-event/bpmn-start-event-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-start-event/bpmn-start-event.ts create mode 100644 src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess.ts create mode 100644 src/main/packages/bpmn/bpmn-task/bpmn-task-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-task/bpmn-task.ts create mode 100644 src/main/packages/bpmn/bpmn-transaction/bpmn-transaction-component.tsx create mode 100644 src/main/packages/bpmn/bpmn-transaction/bpmn-transaction.ts create mode 100644 src/main/packages/bpmn/index.ts create mode 100644 src/tests/unit/packages/bpmn/bpmn-annotation/__snapshots__/bpmn-annotation-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-annotation/bpmn-annotation-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-call-activity/__snapshots__/bpmn-call-activity-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-conversation/__snapshots__/bpmn-conversation-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-conversation/bpmn-conversation-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-end-event/__snapshots__/bpmn-end-event-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-end-event/bpmn-end-event-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-flow/__snapshots__/bpmn-flow-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-flow/bpmn-flow-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-gateway/__snapshots__/bpmn-gateway-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-gateway/bpmn-gateway-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-intermediate-event/__snapshots__/bpmn-intermediate-event-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-start-event/__snapshots__/bpmn-start-event-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-start-event/bpmn-start-event-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-subprocess/__snapshots__/bpmn-subprocess-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-task/__snapshots__/bpmn-task-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-task/bpmn-task-component-test.tsx create mode 100644 src/tests/unit/packages/bpmn/bpmn-transaction/__snapshots__/bpmn-transaction-component-test.tsx.snap create mode 100644 src/tests/unit/packages/bpmn/bpmn-transaction/bpmn-transaction-component-test.tsx diff --git a/.gitignore b/.gitignore index 541fa922a..f697294d2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ dist/ /coverage/ /docs/build/ cypress -test-report.html \ No newline at end of file +test-report.html +**/.DS_Store diff --git a/public/index.html.ejs b/public/index.html.ejs index 329fcb85b..446a166c5 100644 --- a/public/index.html.ejs +++ b/public/index.html.ejs @@ -36,6 +36,7 @@ + @@ -88,4 +89,4 @@ - \ No newline at end of file + diff --git a/src/main/components/create-pane/create-pane.tsx b/src/main/components/create-pane/create-pane.tsx index f4960b0c1..6369944f3 100644 --- a/src/main/components/create-pane/create-pane.tsx +++ b/src/main/components/create-pane/create-pane.tsx @@ -28,6 +28,7 @@ import { composeSyntaxTreePreview } from '../../packages/syntax-tree/syntax-tree import { composeFlowchartPreview } from '../../packages/flowchart/flowchart-diagram-preview'; import { ColorLegend } from '../../packages/common/color-legend/color-legend'; import { Separator } from './create-pane-styles'; +import { composeBPMNPreview } from '../../packages/bpmn/bpmn-diagram-preview'; type OwnProps = {}; type StateProps = { @@ -78,6 +79,10 @@ const getInitialState = ({ type, canvas, translate, colorEnabled }: Props) => { break; case UMLDiagramType.Flowchart: previews.push(...composeFlowchartPreview(canvas, translate)); + break; + case UMLDiagramType.BPMN: + previews.push(...composeBPMNPreview(canvas, translate)); + break; } if (colorEnabled) { utils.push( diff --git a/src/main/i18n/de.json b/src/main/i18n/de.json index cb7f1b77f..f6e018b2b 100644 --- a/src/main/i18n/de.json +++ b/src/main/i18n/de.json @@ -117,6 +117,29 @@ }, "ColorLegend": { "ColorLegend": "Farbe Beschreibung" + }, + "BPMN": { + "BPMNTask": "Task", + "BPMNSubprocess": "Sub-Prozess", + "BPMNTransaction": "Transaktion", + "BPMNCallActivity": "Aufruf-Aktivität", + "BPMNAnnotation": "Annotation", + "BPMNStartEvent": "Start-Event", + "BPMNIntermediateEvent": "Event", + "BPMNEndEvent": "End-Event", + "BPMNGateway": "Gateway", + "BPMNComplexGateway": "Komplex", + "BPMNEventBasedGateway": "Ereignis-basiert", + "BPMNExclusiveGateway": "Exklusiv", + "BPMNExclusiveEventBasedGateway": "Exklusiv Ereignis-basiert", + "BPMNInclusiveGateway": "Inklusiv", + "BPMNParallelGateway": "Parallel", + "BPMNParallelEventBasedGateway": "Parallel Ereignis-basiert", + "BPMNConversation": "Konversation", + "BPMNCallConversation": "Aufruf-Konversation", + "BPMNSequenceFlow": "Sequenz", + "BPMNMessageFlow": "Nachricht", + "BPMNAssociationFlow": "Assoziation" } } } diff --git a/src/main/i18n/en.json b/src/main/i18n/en.json index 952e0ff3c..25d8cf30c 100644 --- a/src/main/i18n/en.json +++ b/src/main/i18n/en.json @@ -117,6 +117,29 @@ }, "ColorLegend": { "ColorLegend": "Color Description" + }, + "BPMN": { + "BPMNTask": "Task", + "BPMNSubprocess": "Subprocess", + "BPMNTransaction": "Transaction", + "BPMNCallActivity": "Call Activity", + "BPMNAnnotation": "Annotation", + "BPMNStartEvent": "Start", + "BPMNIntermediateEvent": "Event", + "BPMNEndEvent": "End", + "BPMNGateway": "Gateway", + "BPMNComplexGateway": "Complex", + "BPMNEventBasedGateway": "Event-based", + "BPMNInclusiveGateway": "Inclusive", + "BPMNExclusiveGateway": "Exclusive", + "BPMNExclusiveEventBasedGateway": "Exclusive Event-based", + "BPMNParallelGateway": "Parallel", + "BPMNParallelEventBasedGateway": "Parallel Event-based", + "BPMNConversation": "Conversation", + "BPMNCallConversation": "Call Conversation", + "BPMNSequenceFlow": "Sequence", + "BPMNMessageFlow": "Message", + "BPMNAssociationFlow": "Association" } } } diff --git a/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation-component.tsx b/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation-component.tsx new file mode 100644 index 000000000..3ad159e2d --- /dev/null +++ b/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation-component.tsx @@ -0,0 +1,41 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNAnnotation } from './bpmn-annotation'; +import { ThemedPath, ThemedRect } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNAnnotationComponent: FunctionComponent = ({ element }) => ( + + + + + {element.name} + + +); + +interface Props { + element: BPMNAnnotation; + fillColor?: string; +} diff --git a/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation.ts b/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation.ts new file mode 100644 index 000000000..c8f6b0d81 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-annotation/bpmn-annotation.ts @@ -0,0 +1,18 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import { calculateNameBounds } from '../../../utils/name-bounds'; +import { UMLElementType } from '../../uml-element-type'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; + +export class BPMNAnnotation extends UMLElement { + static features: UMLElementFeatures = { ...UMLElement.features }; + + type: UMLElementType = BPMNElementType.BPMNAnnotation; + + render(canvas: ILayer): ILayoutable[] { + this.bounds = calculateNameBounds(this, canvas); + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component.tsx b/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component.tsx new file mode 100644 index 000000000..22b7c19c7 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component.tsx @@ -0,0 +1,35 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNCallActivity } from './bpmn-call-activity'; +import { ThemedRect } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNCallActivityComponent: FunctionComponent = ({ element, fillColor }) => ( + + + + {element.name} + + +); + +interface Props { + element: BPMNCallActivity; + fillColor?: string; +} diff --git a/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity.ts b/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity.ts new file mode 100644 index 000000000..9437227a8 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-call-activity/bpmn-call-activity.ts @@ -0,0 +1,15 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import { calculateNameBounds } from '../../../utils/name-bounds'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNCallActivity extends UMLElement { + type: UMLElementType = BPMNElementType.BPMNCallActivity; + + render(canvas: ILayer): ILayoutable[] { + this.bounds = calculateNameBounds(this, canvas); + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-component.tsx b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-component.tsx new file mode 100644 index 000000000..962fefb57 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-component.tsx @@ -0,0 +1,35 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNConversation } from './bpmn-conversation'; +import { ThemedPolyline } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNConversationComponent: FunctionComponent = ({ element }) => ( + + + + {element.name} + + +); + +export interface Props { + element: BPMNConversation; +} diff --git a/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-update.tsx b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-update.tsx new file mode 100644 index 000000000..c7eaf3900 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation-update.tsx @@ -0,0 +1,94 @@ +import React, { Component, ComponentClass } from 'react'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { Button } from '../../../components/controls/button/button'; +import { Divider } from '../../../components/controls/divider/divider'; +import { TrashIcon } from '../../../components/controls/icon/trash'; +import { Textfield } from '../../../components/controls/textfield/textfield'; +import { I18nContext } from '../../../components/i18n/i18n-context'; +import { localized } from '../../../components/i18n/localized'; +import { ModelState } from '../../../components/store/model-state'; +import { styled } from '../../../components/theme/styles'; +import { UMLElementRepository } from '../../../services/uml-element/uml-element-repository'; +import { Switch } from '../../../components/controls/switch/switch'; +import { BPMNConversation, BPMNConversationType } from './bpmn-conversation'; +import { Dropdown } from '../../../components/controls/dropdown/dropdown'; + +interface OwnProps { + element: BPMNConversation; +} + +type StateProps = {}; + +interface DispatchProps { + update: typeof UMLElementRepository.update; + delete: typeof UMLElementRepository.delete; +} + +type Props = OwnProps & StateProps & DispatchProps & I18nContext; + +const enhance = compose>( + localized, + connect(null, { + update: UMLElementRepository.update, + delete: UMLElementRepository.delete, + }), +); + +const Flex = styled.div` + display: flex; + align-items: baseline; + justify-content: space-between; +`; + +class BPMNConversationUpdateComponent extends Component { + render() { + const { element } = this.props; + + return ( +
+
+ + + + + +
+
+ + {this.props.translate('packages.BPMN.BPMNConversation')} + {this.props.translate('packages.BPMN.BPMNCallConversation')} + +
+
+ ); + } + + /** + * Rename the conversation + * @param id The ID of the conversation that should be renamed + */ + private rename = (id: string) => (value: string) => { + this.props.update(id, { name: value }); + }; + + /** + * Change the type of the conversation + * @param id The ID of the conversation whose type should be changed + */ + private changeConversationType = (id: string) => (value: string) => { + this.props.update(id, { conversationType: value as BPMNConversationType }); + }; + + /** + * Delete a conversation + * @param id The ID of the conversation that should be deleted + */ + private delete = (id: string) => () => { + this.props.delete(id); + }; +} + +export const BPMNConversationUpdate = enhance(BPMNConversationUpdateComponent); diff --git a/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation.ts b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation.ts new file mode 100644 index 000000000..d9b6573dc --- /dev/null +++ b/src/main/packages/bpmn/bpmn-conversation/bpmn-conversation.ts @@ -0,0 +1,47 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { IUMLElement, UMLElement } from '../../../services/uml-element/uml-element'; +import { UMLElementType } from '../../uml-element-type'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; +import { IBoundary } from '../../../utils/geometry/boundary'; +import { DeepPartial } from 'redux'; +import { assign } from '../../../utils/fx/assign'; +import * as Apollon from '../../../typings'; + +export type BPMNConversationType = 'default' | 'call'; + +export class BPMNConversation extends UMLElement { + static features: UMLElementFeatures = { ...UMLElement.features, resizable: false }; + static defaultConversationType: BPMNConversationType = 'default'; + + type: UMLElementType = BPMNElementType.BPMNConversation; + bounds: IBoundary = { ...this.bounds, width: 40, height: 40 }; + conversationType: BPMNConversationType; + + constructor(values?: DeepPartial) { + super(values); + assign(this, values); + this.conversationType = values?.conversationType || BPMNConversation.defaultConversationType; + } + + serialize(children?: UMLElement[]): Apollon.BPMNConversation { + return { + ...super.serialize(), + type: this.type as keyof typeof BPMNElementType, + conversationType: this.conversationType, + }; + } + + deserialize( + values: T & { conversationType?: BPMNConversationType }, + children?: Apollon.UMLModelElement[], + ): void { + super.deserialize(values, children); + this.conversationType = values.conversationType || BPMNConversation.defaultConversationType; + } + + render(canvas: ILayer): ILayoutable[] { + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-diagram-preview.ts b/src/main/packages/bpmn/bpmn-diagram-preview.ts new file mode 100644 index 000000000..3ab3e4c6b --- /dev/null +++ b/src/main/packages/bpmn/bpmn-diagram-preview.ts @@ -0,0 +1,93 @@ +import { ILayer } from '../../services/layouter/layer'; +import { computeDimension, IBoundary } from '../../utils/geometry/boundary'; +import { ComposePreview, PreviewElement } from '../compose-preview'; +import { BPMNTask } from './bpmn-task/bpmn-task'; +import { BPMNSubprocess } from './bpmn-subprocess/bpmn-subprocess'; +import { BPMNStartEvent } from './bpmn-start-event/bpmn-start-event'; +import { BPMNIntermediateEvent } from './bpmn-intermediate-event/bpmn-intermediate-event'; +import { BPMNEndEvent } from './bpmn-end-event/bpmn-end-event'; +import { BPMNGateway } from './bpmn-gateway/bpmn-gateway'; +import { BPMNTransaction } from './bpmn-transaction/bpmn-transaction'; +import { BPMNCallActivity } from './bpmn-call-activity/bpmn-call-activity'; +import { BPMNAnnotation } from './bpmn-annotation/bpmn-annotation'; +import { BPMNConversation } from './bpmn-conversation/bpmn-conversation'; + +export const composeBPMNPreview: ComposePreview = ( + layer: ILayer, + translate: (id: string) => string, +): PreviewElement[] => { + const elements: PreviewElement[] = []; + const defaultBounds: IBoundary = { x: 0, y: 0, width: 150, height: computeDimension(1.0, 60) }; + + elements.push( + new BPMNTask({ + name: translate('packages.BPMN.BPMNTask'), + bounds: defaultBounds, + }), + ); + + elements.push( + new BPMNSubprocess({ + name: translate('packages.BPMN.BPMNSubprocess'), + bounds: defaultBounds, + }), + ); + + elements.push( + new BPMNTransaction({ + name: translate('packages.BPMN.BPMNTransaction'), + bounds: defaultBounds, + }), + ); + + elements.push( + new BPMNCallActivity({ + name: translate('packages.BPMN.BPMNCallActivity'), + bounds: defaultBounds, + }), + ); + + elements.push( + new BPMNAnnotation({ + name: translate('packages.BPMN.BPMNAnnotation'), + bounds: defaultBounds, + }), + ); + + elements.push( + new BPMNStartEvent({ + name: translate('packages.BPMN.BPMNStartEvent'), + bounds: { x: 0, y: 0, width: 40, height: 40 }, + }), + ); + + elements.push( + new BPMNIntermediateEvent({ + name: translate('packages.BPMN.BPMNIntermediateEvent'), + bounds: { x: 0, y: 0, width: 40, height: 40 }, + }), + ); + + elements.push( + new BPMNEndEvent({ + name: translate('packages.BPMN.BPMNEndEvent'), + bounds: { x: 0, y: 0, width: 40, height: 40 }, + }), + ); + + elements.push( + new BPMNGateway({ + name: translate('packages.BPMN.BPMNGateway'), + bounds: { x: 0, y: 0, width: 40, height: 40 }, + }), + ); + + elements.push( + new BPMNConversation({ + name: translate('packages.BPMN.BPMNConversation'), + bounds: { x: 0, y: 0, width: 40, height: 40 }, + }), + ); + + return elements; +}; diff --git a/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event-component.tsx b/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event-component.tsx new file mode 100644 index 000000000..15424dc52 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event-component.tsx @@ -0,0 +1,55 @@ +import React, { ComponentType, FunctionComponent } from 'react'; +import { BPMNEndEvent } from './bpmn-end-event'; +import { withTheme, withThemeProps } from '../../../components/theme/styles'; +import { compose } from 'redux'; +import { connect, ConnectedComponent } from 'react-redux'; +import { ModelState } from '../../../components/store/model-state'; +import { ApollonView } from '../../../services/editor/editor-types'; +import { ThemedCircle } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +type OwnProps = { + element: BPMNEndEvent; +}; + +type StateProps = { interactive: boolean; interactable: boolean }; + +type DispatchProps = {}; + +type Props = OwnProps & StateProps & DispatchProps & withThemeProps; + +const enhance = compose, OwnProps>>( + withTheme, + connect((state, props) => ({ + interactive: state.interactive.includes(props.element.id), + interactable: state.editor.view === ApollonView.Exporting || state.editor.view === ApollonView.Highlight, + })), +); + +export const BPMNEndEventC: FunctionComponent = ({ element, interactive, interactable, theme }) => { + return ( + + + + {element.name} + + + ); +}; + +export const BPMNEndEventComponent = enhance(BPMNEndEventC); diff --git a/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event.ts b/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event.ts new file mode 100644 index 000000000..7318cfcf5 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-end-event/bpmn-end-event.ts @@ -0,0 +1,27 @@ +import { DeepPartial } from 'redux'; +import { BPMNElementType, BPMNRelationshipType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { IUMLElement, UMLElement } from '../../../services/uml-element/uml-element'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; +import { assign } from '../../../utils/fx/assign'; +import { IBoundary } from '../../../utils/geometry/boundary'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNEndEvent extends UMLElement { + static supportedRelationships = [BPMNRelationshipType.BPMNFlow]; + static features: UMLElementFeatures = { ...UMLElement.features, resizable: false }; + + type: UMLElementType = BPMNElementType.BPMNEndEvent; + bounds: IBoundary = { ...this.bounds, width: 40, height: 40 }; + name = 'End Event'; + + constructor(values?: DeepPartial) { + super(values); + assign(this, values); + } + + render(canvas: ILayer): ILayoutable[] { + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-flow/bpmn-flow-component.tsx b/src/main/packages/bpmn/bpmn-flow/bpmn-flow-component.tsx new file mode 100644 index 000000000..9c7d6659f --- /dev/null +++ b/src/main/packages/bpmn/bpmn-flow/bpmn-flow-component.tsx @@ -0,0 +1,90 @@ +import React, { FunctionComponent } from 'react'; +import { Point } from '../../../utils/geometry/point'; +import { BPMNFlow } from './bpmn-flow'; +import { ThemedCircle, ThemedPath, ThemedPolyline } from '../../../components/theme/themedComponents'; + +export const BPMNFlowComponent: FunctionComponent = ({ element }) => { + let position = { x: 0, y: 0 }; + let direction: 'vertical' | 'horizontal' = 'vertical'; + const path = element.path.map((point) => new Point(point.x, point.y)); + let distance = + path.reduce( + (length, point, i, points) => (i + 1 < points.length ? length + points[i + 1].subtract(point).length : length), + 0, + ) / 2; + + for (let index = 0; index < path.length - 1; index++) { + const vector = path[index + 1].subtract(path[index]); + if (vector.length > distance) { + const normalized = vector.normalize(); + direction = Math.abs(normalized.x) > Math.abs(normalized.y) ? 'horizontal' : 'vertical'; + position = path[index].add(normalized.scale(distance)); + break; + } + distance -= vector.length; + } + + const layoutText = (dir: 'vertical' | 'horizontal') => { + switch (dir) { + case 'vertical': + return { + dx: 5, + dominantBaseline: 'middle', + textAnchor: 'start', + }; + case 'horizontal': + return { + dy: -5, + dominantBaseline: 'text-after-edge', + textAnchor: 'middle', + }; + } + }; + + const textColor = element.textColor ? { fill: element.textColor } : {}; + + return ( + + + + + + + + `${point.x} ${point.y}`).join(',')} + strokeColor={element.strokeColor} + fillColor="none" + strokeWidth={1} + markerStart={element.flowType === 'message' ? `url(#marker-start-${element.id})` : undefined} + markerEnd={element.flowType !== 'association' ? `url(#marker-end-${element.id})` : undefined} + strokeDasharray={element.flowType !== 'sequence' ? 4 : undefined} + /> + + {element.name} + + + ); +}; + +interface Props { + element: BPMNFlow; +} diff --git a/src/main/packages/bpmn/bpmn-flow/bpmn-flow-update.tsx b/src/main/packages/bpmn/bpmn-flow/bpmn-flow-update.tsx new file mode 100644 index 000000000..56156f504 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-flow/bpmn-flow-update.tsx @@ -0,0 +1,115 @@ +import React, { Component, ComponentClass } from 'react'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { Button } from '../../../components/controls/button/button'; +import { TrashIcon } from '../../../components/controls/icon/trash'; +import { Textfield } from '../../../components/controls/textfield/textfield'; +import { I18nContext } from '../../../components/i18n/i18n-context'; +import { localized } from '../../../components/i18n/localized'; +import { ModelState } from '../../../components/store/model-state'; +import { styled } from '../../../components/theme/styles'; +import { UMLElementRepository } from '../../../services/uml-element/uml-element-repository'; +import { ExchangeIcon } from '../../../components/controls/icon/exchange'; +import { UMLRelationshipRepository } from '../../../services/uml-relationship/uml-relationship-repository'; +import { BPMNFlowType, BPMNFlow } from './bpmn-flow'; +import { ColorButton } from '../../../components/controls/color-button/color-button'; +import { StylePane } from '../../../components/style-pane/style-pane'; +import { Dropdown } from '../../../components/controls/dropdown/dropdown'; +import { Divider } from '../../../components/controls/divider/divider'; + +interface OwnProps { + element: BPMNFlow; +} + +type StateProps = {}; + +interface DispatchProps { + update: typeof UMLElementRepository.update; + delete: typeof UMLElementRepository.delete; + flip: typeof UMLRelationshipRepository.flip; +} + +type Props = OwnProps & StateProps & DispatchProps & I18nContext; + +const enhance = compose>( + localized, + connect(null, { + update: UMLElementRepository.update, + delete: UMLElementRepository.delete, + flip: UMLRelationshipRepository.flip, + }), +); + +const Flex = styled.div` + display: flex; + align-items: baseline; + justify-content: space-between; +`; + +type State = { colorOpen: boolean }; + +class BPMNFlowUpdateComponent extends Component { + state = { colorOpen: false }; + + private toggleColor = () => { + this.setState((state) => ({ + colorOpen: !state.colorOpen, + })); + }; + + render() { + const { element } = this.props; + + return ( +
+
+ + + + + + +
+ +
+ + {this.props.translate('packages.BPMN.BPMNSequenceFlow')} + {this.props.translate('packages.BPMN.BPMNMessageFlow')} + + {this.props.translate('packages.BPMN.BPMNAssociationFlow')} + + +
+ +
+ ); + } + + private rename = (id: string) => (value: string) => { + this.props.update(id, { name: value }); + }; + + /** + * Change the type of the gateway + * @param id The ID of the gateway whose type should be changed + */ + private changeFlowType = (id: string) => (value: string) => { + this.props.update(id, { flowType: value as BPMNFlowType }); + }; + + private delete = (id: string) => () => { + this.props.delete(id); + }; +} + +export const BPMNFlowUpdate = enhance(BPMNFlowUpdateComponent); diff --git a/src/main/packages/bpmn/bpmn-flow/bpmn-flow.ts b/src/main/packages/bpmn/bpmn-flow/bpmn-flow.ts new file mode 100644 index 000000000..23dc9f7d9 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-flow/bpmn-flow.ts @@ -0,0 +1,40 @@ +import { BPMNRelationshipType } from '..'; +import { UMLRelationship } from '../../../services/uml-relationship/uml-relationship'; +import { DeepPartial } from 'redux'; +import { UMLRelationshipCenteredDescription } from '../../../services/uml-relationship/uml-relationship-centered-description'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import * as Apollon from '../../../typings'; + +export type BPMNFlowType = 'sequence' | 'message' | 'association'; + +export class BPMNFlow extends UMLRelationshipCenteredDescription { + static features = { ...UMLRelationship.features }; + static defaultFlowType: BPMNFlowType = 'sequence'; + + type = BPMNRelationshipType.BPMNFlow; + name = ''; + + flowType: BPMNFlowType; + + constructor(values?: DeepPartial) { + super(values); + this.name = values?.name || this.name; + this.flowType = values?.flowType || BPMNFlow.defaultFlowType; + } + + serialize(children?: UMLElement[]): Apollon.BPMNFlow { + return { + ...super.serialize(), + type: this.type as keyof typeof BPMNRelationshipType, + flowType: this.flowType, + }; + } + + deserialize( + values: T & { flowType?: BPMNFlowType }, + children?: Apollon.UMLModelElement[], + ): void { + super.deserialize(values, children); + this.flowType = values.flowType || BPMNFlow.defaultFlowType; + } +} diff --git a/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-component.tsx new file mode 100644 index 000000000..a7c436ac4 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-component.tsx @@ -0,0 +1,47 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNGateway } from './bpmn-gateway'; +import { BPMNEventBasedGatewayComponent } from './gateways-components/bpmn-event-based-gateway-component'; +import { BPMNExclusiveGatewayComponent } from './gateways-components/bpmn-exclusive-gateway-component'; +import { BPMNInclusiveGatewayComponent } from './gateways-components/bpmn-inclusive-gateway-component'; +import { BPMNParallelGatewayComponent } from './gateways-components/bpmn-parallel-gateway-component'; +import { BPMNComplexGatewayComponent } from './gateways-components/bpmn-complex-gateway-component'; +import { BPMNExclusiveEventBasedGatewayComponent } from './gateways-components/bpmn-exclusive-event-based-gateway-component'; +import { BPMNParallelEventBasedGatewayComponent } from './gateways-components/bpmn-parallel-event-based-gateway-component'; + +export const BPMNGatewayComponent: FunctionComponent = (props) => { + let GatewayComponent = BPMNExclusiveGatewayComponent; + + switch (props.element.gatewayType) { + case 'complex': + GatewayComponent = BPMNComplexGatewayComponent; + break; + case 'event-based': + GatewayComponent = BPMNEventBasedGatewayComponent; + break; + case 'exclusive': + GatewayComponent = BPMNExclusiveGatewayComponent; + break; + case 'exclusive-event-based': + GatewayComponent = BPMNExclusiveEventBasedGatewayComponent; + break; + case 'inclusive': + GatewayComponent = BPMNInclusiveGatewayComponent; + break; + case 'parallel': + GatewayComponent = BPMNParallelGatewayComponent; + break; + case 'parallel-event-based': + GatewayComponent = BPMNParallelEventBasedGatewayComponent; + break; + } + + return ( + + + + ); +}; + +export interface Props { + element: BPMNGateway; +} diff --git a/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-update.tsx b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-update.tsx new file mode 100644 index 000000000..fc45d44bc --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway-update.tsx @@ -0,0 +1,110 @@ +import React, { Component, ComponentClass } from 'react'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { Button } from '../../../components/controls/button/button'; +import { Divider } from '../../../components/controls/divider/divider'; +import { TrashIcon } from '../../../components/controls/icon/trash'; +import { Textfield } from '../../../components/controls/textfield/textfield'; +import { I18nContext } from '../../../components/i18n/i18n-context'; +import { localized } from '../../../components/i18n/localized'; +import { ModelState } from '../../../components/store/model-state'; +import { styled } from '../../../components/theme/styles'; +import { UMLElementRepository } from '../../../services/uml-element/uml-element-repository'; +import { BPMNGateway, BPMNGatewayType } from './bpmn-gateway'; +import { Dropdown } from '../../../components/controls/dropdown/dropdown'; + +interface OwnProps { + element: BPMNGateway; +} + +type StateProps = {}; + +interface DispatchProps { + update: typeof UMLElementRepository.update; + delete: typeof UMLElementRepository.delete; +} + +type Props = OwnProps & StateProps & DispatchProps & I18nContext; + +const enhance = compose>( + localized, + connect(null, { + update: UMLElementRepository.update, + delete: UMLElementRepository.delete, + }), +); + +const Flex = styled.div` + display: flex; + align-items: baseline; + justify-content: space-between; +`; + +class BPMNGatewayUpdateComponent extends Component { + render() { + const { element } = this.props; + + return ( +
+
+ + + + + +
+
+ + {this.props.translate('packages.BPMN.BPMNComplexGateway')} + + {this.props.translate('packages.BPMN.BPMNEventBasedGateway')} + + + {this.props.translate('packages.BPMN.BPMNExclusiveGateway')} + + + {this.props.translate('packages.BPMN.BPMNExclusiveEventBasedGateway')} + + + {this.props.translate('packages.BPMN.BPMNInclusiveGateway')} + + + {this.props.translate('packages.BPMN.BPMNParallelGateway')} + + + {this.props.translate('packages.BPMN.BPMNParallelEventBasedGateway')} + + +
+
+ ); + } + + /** + * Rename the gateway + * @param id The ID of the gateway that should be renamed + */ + private rename = (id: string) => (value: string) => { + this.props.update(id, { name: value }); + }; + + /** + * Change the type of the gateway + * @param id The ID of the gateway whose type should be changed + */ + private changeGatewayType = (id: string) => (value: string) => { + this.props.update(id, { gatewayType: value as BPMNGatewayType }); + }; + + /** + * Delete a gateway + * @param id The ID of the gateway that should be deleted + */ + private delete = (id: string) => () => { + this.props.delete(id); + }; +} + +export const BPMNGatewayUpdate = enhance(BPMNGatewayUpdateComponent); diff --git a/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway.ts b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway.ts new file mode 100644 index 000000000..c6280c0ec --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/bpmn-gateway.ts @@ -0,0 +1,54 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { IUMLElement, UMLElement } from '../../../services/uml-element/uml-element'; +import { UMLElementType } from '../../uml-element-type'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; +import { IBoundary } from '../../../utils/geometry/boundary'; +import { DeepPartial } from 'redux'; +import { assign } from '../../../utils/fx/assign'; +import * as Apollon from '../../../typings'; + +export type BPMNGatewayType = + | 'complex' + | 'event-based' + | 'exclusive' + | 'exclusive-event-based' + | 'inclusive' + | 'parallel' + | 'parallel-event-based'; + +export class BPMNGateway extends UMLElement { + static features: UMLElementFeatures = { ...UMLElement.features, resizable: false }; + static defaultGatewayType: BPMNGatewayType = 'exclusive'; + + type: UMLElementType = BPMNElementType.BPMNGateway; + bounds: IBoundary = { ...this.bounds, width: 40, height: 40 }; + gatewayType: BPMNGatewayType; + + constructor(values?: DeepPartial) { + super(values); + assign(this, values); + this.gatewayType = values?.gatewayType || BPMNGateway.defaultGatewayType; + } + + serialize(children?: UMLElement[]): Apollon.BPMNGateway { + return { + ...super.serialize(), + type: this.type as keyof typeof BPMNElementType, + gatewayType: this.gatewayType, + }; + } + + deserialize( + values: T & { gatewayType?: BPMNGatewayType }, + children?: Apollon.UMLModelElement[], + ): void { + super.deserialize(values, children); + this.gatewayType = values.gatewayType || BPMNGateway.defaultGatewayType; + } + + render(canvas: ILayer): ILayoutable[] { + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-complex-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-complex-gateway-component.tsx new file mode 100644 index 000000000..70a8e1712 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-complex-gateway-component.tsx @@ -0,0 +1,48 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNComplexGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-event-based-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-event-based-gateway-component.tsx new file mode 100644 index 000000000..aa76c6997 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-event-based-gateway-component.tsx @@ -0,0 +1,54 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedCircle, ThemedPath, ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNEventBasedGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-event-based-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-event-based-gateway-component.tsx new file mode 100644 index 000000000..d9521b2df --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-event-based-gateway-component.tsx @@ -0,0 +1,48 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedCircle, ThemedPath, ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNExclusiveEventBasedGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-gateway-component.tsx new file mode 100644 index 000000000..b1576ff4b --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-exclusive-gateway-component.tsx @@ -0,0 +1,38 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNExclusiveGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-inclusive-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-inclusive-gateway-component.tsx new file mode 100644 index 000000000..b78e33c18 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-inclusive-gateway-component.tsx @@ -0,0 +1,34 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedCircle, ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNInclusiveGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-event-based-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-event-based-gateway-component.tsx new file mode 100644 index 000000000..24216d564 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-event-based-gateway-component.tsx @@ -0,0 +1,44 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedCircle, ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNParallelEventBasedGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-gateway-component.tsx b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-gateway-component.tsx new file mode 100644 index 000000000..ccc2ab639 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-gateway/gateways-components/bpmn-parallel-gateway-component.tsx @@ -0,0 +1,38 @@ +import React, { FunctionComponent } from 'react'; +import { ThemedPolyline } from '../../../../components/theme/themedComponents'; +import { Multiline } from '../../../../utils/svg/multiline'; +import { Props } from '../bpmn-gateway-component'; + +export const BPMNParallelGatewayComponent: FunctionComponent = ({ element }) => ( + + + + + + {element.name} + + +); diff --git a/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component.tsx b/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component.tsx new file mode 100644 index 000000000..62c842cbc --- /dev/null +++ b/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component.tsx @@ -0,0 +1,60 @@ +import React, { ComponentType, FunctionComponent } from 'react'; +import { BPMNIntermediateEvent } from './bpmn-intermediate-event'; +import { connect, ConnectedComponent } from 'react-redux'; +import { ModelState } from '../../../components/store/model-state'; +import { compose } from 'redux'; +import { withTheme, withThemeProps } from '../../../components/theme/styles'; +import { ApollonView } from '../../../services/editor/editor-types'; +import { ThemedCircle } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +type OwnProps = { + element: BPMNIntermediateEvent; +}; + +type StateProps = { interactive: boolean; interactable: boolean }; + +type DispatchProps = {}; + +type Props = OwnProps & StateProps & DispatchProps & withThemeProps; + +const enhance = compose, OwnProps>>( + withTheme, + connect((state, props) => ({ + interactive: state.interactive.includes(props.element.id), + interactable: state.editor.view === ApollonView.Exporting || state.editor.view === ApollonView.Highlight, + })), +); + +const BPMNIntermediateEventC: FunctionComponent = ({ element, interactive, interactable, theme }) => { + return ( + + + + + {element.name} + + + ); +}; + +export const BPMNIntermediateEventComponent = enhance(BPMNIntermediateEventC); diff --git a/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event.ts b/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event.ts new file mode 100644 index 000000000..b375dfeaf --- /dev/null +++ b/src/main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event.ts @@ -0,0 +1,26 @@ +import { DeepPartial } from 'redux'; +import { BPMNElementType, BPMNRelationshipType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { IUMLElement, UMLElement } from '../../../services/uml-element/uml-element'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; +import { assign } from '../../../utils/fx/assign'; +import { IBoundary } from '../../../utils/geometry/boundary'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNIntermediateEvent extends UMLElement { + static supportedRelationships = [BPMNRelationshipType.BPMNFlow]; + static features: UMLElementFeatures = { ...UMLElement.features, resizable: false }; + + type: UMLElementType = BPMNElementType.BPMNIntermediateEvent; + bounds: IBoundary = { ...this.bounds, width: 40, height: 40 }; + + constructor(values?: DeepPartial) { + super(values); + assign(this, values); + } + + render(canvas: ILayer): ILayoutable[] { + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event-component.tsx b/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event-component.tsx new file mode 100644 index 000000000..f0c1b5910 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event-component.tsx @@ -0,0 +1,54 @@ +import React, { ComponentType, FunctionComponent } from 'react'; +import { BPMNStartEvent } from './bpmn-start-event'; +import { connect, ConnectedComponent } from 'react-redux'; +import { ModelState } from '../../../components/store/model-state'; +import { compose } from 'redux'; +import { withTheme, withThemeProps } from '../../../components/theme/styles'; +import { ApollonView } from '../../../services/editor/editor-types'; +import { ThemedCircle } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +type OwnProps = { + element: BPMNStartEvent; +}; + +type StateProps = { interactive: boolean; interactable: boolean }; + +type DispatchProps = {}; + +type Props = OwnProps & StateProps & DispatchProps & withThemeProps; + +const enhance = compose, OwnProps>>( + withTheme, + connect((state, props) => ({ + interactive: state.interactive.includes(props.element.id), + interactable: state.editor.view === ApollonView.Exporting || state.editor.view === ApollonView.Highlight, + })), +); + +const BPMNStartEventC: FunctionComponent = ({ element, interactive, interactable, theme }) => { + return ( + + + + {element.name} + + + ); +}; + +export const BPMNStartEventComponent = enhance(BPMNStartEventC); diff --git a/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event.ts b/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event.ts new file mode 100644 index 000000000..9c1aa60f5 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-start-event/bpmn-start-event.ts @@ -0,0 +1,27 @@ +import { DeepPartial } from 'redux'; +import { BPMNElementType, BPMNRelationshipType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { IUMLElement, UMLElement } from '../../../services/uml-element/uml-element'; +import { UMLElementFeatures } from '../../../services/uml-element/uml-element-features'; +import { assign } from '../../../utils/fx/assign'; +import { IBoundary } from '../../../utils/geometry/boundary'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNStartEvent extends UMLElement { + static supportedRelationships = [BPMNRelationshipType.BPMNFlow]; + static features: UMLElementFeatures = { ...UMLElement.features, resizable: false }; + + type: UMLElementType = BPMNElementType.BPMNStartEvent; + bounds: IBoundary = { ...this.bounds, width: 40, height: 40 }; + name = 'Start Event'; + + constructor(values?: DeepPartial) { + super(values); + assign(this, values); + } + + render(canvas: ILayer): ILayoutable[] { + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component.tsx b/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component.tsx new file mode 100644 index 000000000..40e7bf83a --- /dev/null +++ b/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component.tsx @@ -0,0 +1,35 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNSubprocess } from './bpmn-subprocess'; +import { ThemedRect } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNSubprocessComponent: FunctionComponent = ({ element, fillColor }) => ( + + + + {element.name} + + +); + +interface Props { + element: BPMNSubprocess; + fillColor?: string; +} diff --git a/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess.ts b/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess.ts new file mode 100644 index 000000000..9ef36f354 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-subprocess/bpmn-subprocess.ts @@ -0,0 +1,15 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import { calculateNameBounds } from '../../../utils/name-bounds'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNSubprocess extends UMLElement { + type: UMLElementType = BPMNElementType.BPMNSubprocess; + + render(canvas: ILayer): ILayoutable[] { + this.bounds = calculateNameBounds(this, canvas); + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-task/bpmn-task-component.tsx b/src/main/packages/bpmn/bpmn-task/bpmn-task-component.tsx new file mode 100644 index 000000000..8b7dcca0f --- /dev/null +++ b/src/main/packages/bpmn/bpmn-task/bpmn-task-component.tsx @@ -0,0 +1,34 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNTask } from './bpmn-task'; +import { ThemedRect } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNTaskComponent: FunctionComponent = ({ element, fillColor }) => ( + + + + {element.name} + + +); + +interface Props { + element: BPMNTask; + fillColor?: string; +} diff --git a/src/main/packages/bpmn/bpmn-task/bpmn-task.ts b/src/main/packages/bpmn/bpmn-task/bpmn-task.ts new file mode 100644 index 000000000..b12311079 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-task/bpmn-task.ts @@ -0,0 +1,15 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import { calculateNameBounds } from '../../../utils/name-bounds'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNTask extends UMLElement { + type: UMLElementType = BPMNElementType.BPMNTask; + + render(canvas: ILayer): ILayoutable[] { + this.bounds = calculateNameBounds(this, canvas); + return [this]; + } +} diff --git a/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction-component.tsx b/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction-component.tsx new file mode 100644 index 000000000..a48280a83 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction-component.tsx @@ -0,0 +1,44 @@ +import React, { FunctionComponent } from 'react'; +import { BPMNTransaction } from './bpmn-transaction'; +import { ThemedRect } from '../../../components/theme/themedComponents'; +import { Multiline } from '../../../utils/svg/multiline'; + +export const BPMNTransactionComponent: FunctionComponent = ({ element, fillColor }) => ( + + + + + {element.name} + + +); + +interface Props { + element: BPMNTransaction; + fillColor?: string; +} diff --git a/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction.ts b/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction.ts new file mode 100644 index 000000000..3f5e3ea82 --- /dev/null +++ b/src/main/packages/bpmn/bpmn-transaction/bpmn-transaction.ts @@ -0,0 +1,15 @@ +import { BPMNElementType } from '..'; +import { ILayer } from '../../../services/layouter/layer'; +import { ILayoutable } from '../../../services/layouter/layoutable'; +import { UMLElement } from '../../../services/uml-element/uml-element'; +import { calculateNameBounds } from '../../../utils/name-bounds'; +import { UMLElementType } from '../../uml-element-type'; + +export class BPMNTransaction extends UMLElement { + type: UMLElementType = BPMNElementType.BPMNTransaction; + + render(canvas: ILayer): ILayoutable[] { + this.bounds = calculateNameBounds(this, canvas); + return [this]; + } +} diff --git a/src/main/packages/bpmn/index.ts b/src/main/packages/bpmn/index.ts new file mode 100644 index 000000000..561b81495 --- /dev/null +++ b/src/main/packages/bpmn/index.ts @@ -0,0 +1,18 @@ +import { BPMNFlow } from './bpmn-flow/bpmn-flow'; + +export const BPMNElementType = { + BPMNTask: 'BPMNTask', + BPMNSubprocess: 'BPMNSubprocess', + BPMNTransaction: 'BPMNTransaction', + BPMNCallActivity: 'BPMNCallActivity', + BPMNAnnotation: 'BPMNAnnotation', + BPMNStartEvent: 'BPMNStartEvent', + BPMNIntermediateEvent: 'BPMNIntermediateEvent', + BPMNEndEvent: 'BPMNEndEvent', + BPMNGateway: 'BPMNGateway', + BPMNConversation: 'BPMNConversation', +} as const; + +export const BPMNRelationshipType = { + BPMNFlow: 'BPMNFlow', +} as const; diff --git a/src/main/packages/components.ts b/src/main/packages/components.ts index 2d6baa130..822dbae96 100644 --- a/src/main/packages/components.ts +++ b/src/main/packages/components.ts @@ -47,6 +47,17 @@ import { FlowchartDecisionComponent } from './flowchart/flowchart-decision/flowc import { FlowchartFunctionCallComponent } from './flowchart/flowchart-function-call/flowchart-function-call-component'; import { FlowchartInputOutputComponent } from './flowchart/flowchart-input-output/flowchart-input-output-component'; import { ColorLegendComponent } from './common/color-legend/color-legend-component'; +import { BPMNFlowComponent } from './bpmn/bpmn-flow/bpmn-flow-component'; +import { BPMNTaskComponent } from './bpmn/bpmn-task/bpmn-task-component'; +import { BPMNSubprocessComponent } from './bpmn/bpmn-subprocess/bpmn-subprocess-component'; +import { BPMNStartEventComponent } from './bpmn/bpmn-start-event/bpmn-start-event-component'; +import { BPMNIntermediateEventComponent } from './bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component'; +import { BPMNEndEventComponent } from './bpmn/bpmn-end-event/bpmn-end-event-component'; +import { BPMNGatewayComponent } from './bpmn/bpmn-gateway/bpmn-gateway-component'; +import { BPMNTransactionComponent } from './bpmn/bpmn-transaction/bpmn-transaction-component'; +import { BPMNCallActivityComponent } from './bpmn/bpmn-call-activity/bpmn-call-activity-component'; +import { BPMNAnnotationComponent } from './bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNConversationComponent } from './bpmn/bpmn-conversation/bpmn-conversation-component'; export const Components: { [key in UMLElementType | UMLRelationshipType]: @@ -92,6 +103,16 @@ export const Components: { [UMLElementType.FlowchartInputOutput]: FlowchartInputOutputComponent, [UMLElementType.FlowchartFunctionCall]: FlowchartFunctionCallComponent, [UMLElementType.ColorLegend]: ColorLegendComponent, + [UMLElementType.BPMNTask]: BPMNTaskComponent, + [UMLElementType.BPMNSubprocess]: BPMNSubprocessComponent, + [UMLElementType.BPMNTransaction]: BPMNTransactionComponent, + [UMLElementType.BPMNCallActivity]: BPMNCallActivityComponent, + [UMLElementType.BPMNAnnotation]: BPMNAnnotationComponent, + [UMLElementType.BPMNStartEvent]: BPMNStartEventComponent, + [UMLElementType.BPMNIntermediateEvent]: BPMNIntermediateEventComponent, + [UMLElementType.BPMNEndEvent]: BPMNEndEventComponent, + [UMLElementType.BPMNGateway]: BPMNGatewayComponent, + [UMLElementType.BPMNConversation]: BPMNConversationComponent, [UMLRelationshipType.ClassAggregation]: UMLAssociationComponent, [UMLRelationshipType.ClassBidirectional]: UMLAssociationComponent, [UMLRelationshipType.ClassComposition]: UMLAssociationComponent, @@ -117,4 +138,5 @@ export const Components: { [UMLRelationshipType.ReachabilityGraphArc]: UMLReachabilityGraphArcComponent, [UMLRelationshipType.SyntaxTreeLink]: SyntaxTreeLinkComponent, [UMLRelationshipType.FlowchartFlowline]: FlowchartFlowlineComponent, + [UMLRelationshipType.BPMNFlow]: BPMNFlowComponent, }; diff --git a/src/main/packages/diagram-type.ts b/src/main/packages/diagram-type.ts index af1e54a17..6b6630838 100644 --- a/src/main/packages/diagram-type.ts +++ b/src/main/packages/diagram-type.ts @@ -12,4 +12,5 @@ export const UMLDiagramType = { ReachabilityGraph: 'ReachabilityGraph', SyntaxTree: 'SyntaxTree', Flowchart: 'Flowchart', + BPMN: 'BPMN', } as const; diff --git a/src/main/packages/popups.ts b/src/main/packages/popups.ts index c28035a2d..d8269d9da 100644 --- a/src/main/packages/popups.ts +++ b/src/main/packages/popups.ts @@ -26,6 +26,9 @@ import { FlowchartFunctionCallUpdate } from './flowchart/flowchart-function-call import { FlowchartInputOutputUpdate } from './flowchart/flowchart-input-output/flowchart-input-output-update'; import { FlowchartFlowlineUpdate } from './flowchart/flowchart-flowline/flowchart-flowline-update'; import { ColorLegendUpdate } from './common/color-legend/color-legend-update'; +import { BPMNFlowUpdate } from './bpmn/bpmn-flow/bpmn-flow-update'; +import { BPMNGatewayUpdate } from './bpmn/bpmn-gateway/bpmn-gateway-update'; +import { BPMNConversationUpdate } from './bpmn/bpmn-conversation/bpmn-conversation-update'; export type Popups = { [key in UMLElementType | UMLRelationshipType]: ComponentType<{ element: any }> | null }; export const Popups: { [key in UMLElementType | UMLRelationshipType]: ComponentType<{ element: any }> | null } = { @@ -69,6 +72,16 @@ export const Popups: { [key in UMLElementType | UMLRelationshipType]: ComponentT [UMLElementType.FlowchartFunctionCall]: FlowchartFunctionCallUpdate, [UMLElementType.FlowchartInputOutput]: FlowchartInputOutputUpdate, [UMLElementType.ColorLegend]: ColorLegendUpdate, + [UMLElementType.BPMNTask]: DefaultPopup, + [UMLElementType.BPMNSubprocess]: DefaultPopup, + [UMLElementType.BPMNTransaction]: DefaultPopup, + [UMLElementType.BPMNCallActivity]: DefaultPopup, + [UMLElementType.BPMNAnnotation]: DefaultPopup, + [UMLElementType.BPMNStartEvent]: DefaultPopup, + [UMLElementType.BPMNIntermediateEvent]: DefaultPopup, + [UMLElementType.BPMNEndEvent]: DefaultPopup, + [UMLElementType.BPMNGateway]: BPMNGatewayUpdate, + [UMLElementType.BPMNConversation]: BPMNConversationUpdate, // Relationships [UMLRelationshipType.ClassAggregation]: UMLClassAssociationUpdate, [UMLRelationshipType.ClassBidirectional]: UMLClassAssociationUpdate, @@ -95,4 +108,5 @@ export const Popups: { [key in UMLElementType | UMLRelationshipType]: ComponentT [UMLRelationshipType.ReachabilityGraphArc]: UMLReachabilityGraphArcUpdate, [UMLRelationshipType.SyntaxTreeLink]: DefaultRelationshipPopup, [UMLRelationshipType.FlowchartFlowline]: FlowchartFlowlineUpdate, + [UMLRelationshipType.BPMNFlow]: BPMNFlowUpdate, }; diff --git a/src/main/packages/uml-element-type.ts b/src/main/packages/uml-element-type.ts index a8a6d4524..8d1c783ed 100644 --- a/src/main/packages/uml-element-type.ts +++ b/src/main/packages/uml-element-type.ts @@ -11,6 +11,7 @@ import { SyntaxTreeElementType } from './syntax-tree'; import { FlowchartElementType } from './flowchart'; import { ColorLegendElementType } from './common/color-legend'; import { ReachabilityGraphElementType } from './uml-reachability-graph'; +import { BPMNElementType } from './bpmn'; export type UMLElementType = | keyof typeof ClassElementType @@ -24,7 +25,8 @@ export type UMLElementType = | keyof typeof ReachabilityGraphElementType | keyof typeof SyntaxTreeElementType | keyof typeof FlowchartElementType - | keyof typeof ColorLegendElementType; + | keyof typeof ColorLegendElementType + | keyof typeof BPMNElementType; export const UMLElementType = { ...ClassElementType, @@ -39,6 +41,7 @@ export const UMLElementType = { ...SyntaxTreeElementType, ...FlowchartElementType, ...ColorLegendElementType, + ...BPMNElementType, }; export const UMLElementsForDiagram: { [key in UMLDiagramType]: any } = { @@ -54,6 +57,7 @@ export const UMLElementsForDiagram: { [key in UMLDiagramType]: any } = { [UMLDiagramType.ReachabilityGraph]: ReachabilityGraphElementType, [UMLDiagramType.SyntaxTree]: SyntaxTreeElementType, [UMLDiagramType.Flowchart]: FlowchartElementType, + [UMLDiagramType.BPMN]: BPMNElementType, }, ...ColorLegendElementType, }; diff --git a/src/main/packages/uml-elements.ts b/src/main/packages/uml-elements.ts index e338649b4..f6c8cc6be 100644 --- a/src/main/packages/uml-elements.ts +++ b/src/main/packages/uml-elements.ts @@ -38,6 +38,16 @@ import { FlowchartDecision } from './flowchart/flowchart-decision/flowchart-deci import { FlowchartProcess } from './flowchart/flowchart-process/flowchart-process'; import { FlowchartInputOutput } from './flowchart/flowchart-input-output/flowchart-input-output'; import { ColorLegend } from './common/color-legend/color-legend'; +import { BPMNTask } from './bpmn/bpmn-task/bpmn-task'; +import { BPMNSubprocess } from './bpmn/bpmn-subprocess/bpmn-subprocess'; +import { BPMNStartEvent } from './bpmn/bpmn-start-event/bpmn-start-event'; +import { BPMNIntermediateEvent } from './bpmn/bpmn-intermediate-event/bpmn-intermediate-event'; +import { BPMNEndEvent } from './bpmn/bpmn-end-event/bpmn-end-event'; +import { BPMNGateway } from './bpmn/bpmn-gateway/bpmn-gateway'; +import { BPMNTransaction } from './bpmn/bpmn-transaction/bpmn-transaction'; +import { BPMNCallActivity } from './bpmn/bpmn-call-activity/bpmn-call-activity'; +import { BPMNAnnotation } from './bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNConversation } from './bpmn/bpmn-conversation/bpmn-conversation'; export const UMLElements = { [UMLElementType.Package]: UMLClassPackage, @@ -79,4 +89,14 @@ export const UMLElements = { [UMLElementType.FlowchartDecision]: FlowchartDecision, [UMLElementType.FlowchartInputOutput]: FlowchartInputOutput, [UMLElementType.ColorLegend]: ColorLegend, + [UMLElementType.BPMNTask]: BPMNTask, + [UMLElementType.BPMNSubprocess]: BPMNSubprocess, + [UMLElementType.BPMNTransaction]: BPMNTransaction, + [UMLElementType.BPMNCallActivity]: BPMNCallActivity, + [UMLElementType.BPMNAnnotation]: BPMNAnnotation, + [UMLElementType.BPMNStartEvent]: BPMNStartEvent, + [UMLElementType.BPMNIntermediateEvent]: BPMNIntermediateEvent, + [UMLElementType.BPMNEndEvent]: BPMNEndEvent, + [UMLElementType.BPMNGateway]: BPMNGateway, + [UMLElementType.BPMNConversation]: BPMNConversation, }; diff --git a/src/main/packages/uml-relationship-type.ts b/src/main/packages/uml-relationship-type.ts index 2fb4b0711..555e7811d 100644 --- a/src/main/packages/uml-relationship-type.ts +++ b/src/main/packages/uml-relationship-type.ts @@ -10,6 +10,7 @@ import { PetriNetRelationshipType } from './uml-petri-net'; import { ReachabilityGraphRelationshipType } from './uml-reachability-graph'; import { SyntaxTreeRelationshipType } from './syntax-tree'; import { FlowchartRelationshipType } from './flowchart'; +import { BPMNRelationshipType } from './bpmn'; export type UMLRelationshipType = | keyof typeof ClassRelationshipType @@ -22,7 +23,8 @@ export type UMLRelationshipType = | keyof typeof PetriNetRelationshipType | keyof typeof ReachabilityGraphRelationshipType | keyof typeof SyntaxTreeRelationshipType - | keyof typeof FlowchartRelationshipType; + | keyof typeof FlowchartRelationshipType + | keyof typeof BPMNRelationshipType; export const UMLRelationshipType = { ...ClassRelationshipType, @@ -36,6 +38,7 @@ export const UMLRelationshipType = { ...ReachabilityGraphRelationshipType, ...SyntaxTreeRelationshipType, ...FlowchartRelationshipType, + ...BPMNRelationshipType, }; export const DefaultUMLRelationshipType: { [key in UMLDiagramType]: UMLRelationshipType } = { @@ -50,4 +53,5 @@ export const DefaultUMLRelationshipType: { [key in UMLDiagramType]: UMLRelations [UMLDiagramType.ReachabilityGraph]: ReachabilityGraphRelationshipType.ReachabilityGraphArc, [UMLDiagramType.SyntaxTree]: SyntaxTreeRelationshipType.SyntaxTreeLink, [UMLDiagramType.Flowchart]: FlowchartRelationshipType.FlowchartFlowline, + [UMLDiagramType.BPMN]: BPMNRelationshipType.BPMNFlow, }; diff --git a/src/main/packages/uml-relationships.ts b/src/main/packages/uml-relationships.ts index bd729d7c4..18e9fecda 100644 --- a/src/main/packages/uml-relationships.ts +++ b/src/main/packages/uml-relationships.ts @@ -25,6 +25,7 @@ import { UMLPetriNetArc } from './uml-petri-net/uml-petri-net-arc/uml-petri-net- import { UMLReachabilityGraphArc } from './uml-reachability-graph/uml-reachability-graph-arc/uml-reachability-graph-arc'; import { SyntaxTreeLink } from './syntax-tree/syntax-tree-link/syntax-tree-link'; import { FlowchartFlowline } from './flowchart/flowchart-flowline/flowchart-flowline'; +import { BPMNFlow } from './bpmn/bpmn-flow/bpmn-flow'; type UMLRelationships = { [key in UMLRelationshipType]: new (values?: IUMLRelationship) => UMLRelationship }; @@ -54,4 +55,5 @@ export const UMLRelationships = { [UMLRelationshipType.ReachabilityGraphArc]: UMLReachabilityGraphArc, [UMLRelationshipType.SyntaxTreeLink]: SyntaxTreeLink, [UMLRelationshipType.FlowchartFlowline]: FlowchartFlowline, + [UMLRelationshipType.BPMNFlow]: BPMNFlow, }; diff --git a/src/main/typings.ts b/src/main/typings.ts index 2cadf5b15..97e08226f 100644 --- a/src/main/typings.ts +++ b/src/main/typings.ts @@ -8,6 +8,8 @@ import { ApollonMode, Locale } from './services/editor/editor-types'; import { Direction } from './services/uml-element/uml-element-port'; import { IBoundary } from './utils/geometry/boundary'; import { IPath } from './utils/geometry/path'; +import { BPMNGatewayType } from './packages/bpmn/bpmn-gateway/bpmn-gateway'; +import { BPMNConversationType } from './packages/bpmn/bpmn-conversation/bpmn-conversation'; export { UMLDiagramType, UMLElementType, UMLRelationshipType, ApollonMode, Locale }; export type { Styles }; @@ -88,6 +90,18 @@ export type UMLPetriNetPlace = UMLElement & { capacity: number | string; }; +export type BPMNGateway = UMLElement & { + gatewayType: BPMNGatewayType; +}; + +export type BPMNConversation = UMLElement & { + conversationType: BPMNConversationType; +}; + +export type BPMNFlow = UMLRelationship & { + flowType: 'sequence' | 'message' | 'association'; +}; + export type UMLReachabilityGraphMarking = UMLElement & { isInitialMarking: boolean; }; diff --git a/src/tests/unit/packages/bpmn/bpmn-annotation/__snapshots__/bpmn-annotation-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-annotation/__snapshots__/bpmn-annotation-component-test.tsx.snap new file mode 100644 index 000000000..15dbc7af4 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-annotation/__snapshots__/bpmn-annotation-component-test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-annotation-component 1`] = ` + +
+ + + + + + + Annotation + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-annotation/bpmn-annotation-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-annotation/bpmn-annotation-component-test.tsx new file mode 100644 index 000000000..3b147d685 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-annotation/bpmn-annotation-component-test.tsx @@ -0,0 +1,24 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-annotation-component', () => { + const annotation: BPMNAnnotation = new BPMNAnnotation({ name: 'Annotation' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(annotation.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-call-activity/__snapshots__/bpmn-call-activity-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-call-activity/__snapshots__/bpmn-call-activity-component-test.tsx.snap new file mode 100644 index 000000000..f4aba5d8a --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-call-activity/__snapshots__/bpmn-call-activity-component-test.tsx.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-call-activity-component 1`] = ` + +
+ + + + + + Call Activity + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component-test.tsx new file mode 100644 index 000000000..f5380daa2 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNCallActivity } from '../../../../../main/packages/bpmn/bpmn-call-activity/bpmn-call-activity'; +import { BPMNCallActivityComponent } from '../../../../../main/packages/bpmn/bpmn-call-activity/bpmn-call-activity-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-call-activity-component', () => { + const callActivity: BPMNCallActivity = new BPMNCallActivity({ name: 'Call Activity' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(callActivity.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-conversation/__snapshots__/bpmn-conversation-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-conversation/__snapshots__/bpmn-conversation-component-test.tsx.snap new file mode 100644 index 000000000..cfc3bbfe2 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-conversation/__snapshots__/bpmn-conversation-component-test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-conversation-component 1`] = ` + +
+ + + + + + Conversation + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-conversation/bpmn-conversation-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-conversation/bpmn-conversation-component-test.tsx new file mode 100644 index 000000000..c8ea06c93 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-conversation/bpmn-conversation-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNConversationComponent } from '../../../../../main/packages/bpmn/bpmn-conversation/bpmn-conversation-component'; +import { BPMNConversation } from '../../../../../main/packages/bpmn/bpmn-conversation/bpmn-conversation'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-conversation-component', () => { + const conversation: BPMNConversation = new BPMNConversation({ name: 'Conversation' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(conversation.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-end-event/__snapshots__/bpmn-end-event-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-end-event/__snapshots__/bpmn-end-event-component-test.tsx.snap new file mode 100644 index 000000000..41345541b --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-end-event/__snapshots__/bpmn-end-event-component-test.tsx.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-end-event-component 1`] = ` + +
+ + + + + + End + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-end-event/bpmn-end-event-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-end-event/bpmn-end-event-component-test.tsx new file mode 100644 index 000000000..f7b5f1b57 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-end-event/bpmn-end-event-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNEndEventComponent } from '../../../../../main/packages/bpmn/bpmn-end-event/bpmn-end-event-component'; +import { BPMNEndEvent } from '../../../../../main/packages/bpmn/bpmn-end-event/bpmn-end-event'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-end-event-component', () => { + const endEvent: BPMNEndEvent = new BPMNEndEvent({ name: 'End' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(endEvent.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-flow/__snapshots__/bpmn-flow-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-flow/__snapshots__/bpmn-flow-component-test.tsx.snap new file mode 100644 index 000000000..b04755b94 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-flow/__snapshots__/bpmn-flow-component-test.tsx.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-flow-component 1`] = ` + +
+ + + + + + + + + + + Sequence + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-flow/bpmn-flow-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-flow/bpmn-flow-component-test.tsx new file mode 100644 index 000000000..049fb22d0 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-flow/bpmn-flow-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNFlow } from '../../../../../main/packages/bpmn/bpmn-flow/bpmn-flow'; +import { BPMNFlowComponent } from '../../../../../main/packages/bpmn/bpmn-flow/bpmn-flow-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-flow-component', () => { + const flow: BPMNFlow = new BPMNFlow({ id: '1', name: 'Sequence' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(flow.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-gateway/__snapshots__/bpmn-gateway-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-gateway/__snapshots__/bpmn-gateway-component-test.tsx.snap new file mode 100644 index 000000000..d37dcf9a5 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-gateway/__snapshots__/bpmn-gateway-component-test.tsx.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-gateway-component 1`] = ` + +
+ + + + + + + + + Gateway + + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-gateway/bpmn-gateway-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-gateway/bpmn-gateway-component-test.tsx new file mode 100644 index 000000000..6da9e308e --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-gateway/bpmn-gateway-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNGateway } from '../../../../../main/packages/bpmn/bpmn-gateway/bpmn-gateway'; +import { BPMNGatewayComponent } from '../../../../../main/packages/bpmn/bpmn-gateway/bpmn-gateway-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-gateway-component', () => { + const gateway: BPMNGateway = new BPMNGateway({ name: 'Gateway' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(gateway.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-intermediate-event/__snapshots__/bpmn-intermediate-event-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-intermediate-event/__snapshots__/bpmn-intermediate-event-component-test.tsx.snap new file mode 100644 index 000000000..bdbb19d4f --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-intermediate-event/__snapshots__/bpmn-intermediate-event-component-test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-intermediate-event-component 1`] = ` + +
+ + + + + + + Event + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component-test.tsx new file mode 100644 index 000000000..07db25765 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNIntermediateEvent } from '../../../../../main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event'; +import { BPMNIntermediateEventComponent } from '../../../../../main/packages/bpmn/bpmn-intermediate-event/bpmn-intermediate-event-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-intermediate-event-component', () => { + const intermediateEvent: BPMNIntermediateEvent = new BPMNIntermediateEvent({ name: 'Event' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(intermediateEvent.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-start-event/__snapshots__/bpmn-start-event-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-start-event/__snapshots__/bpmn-start-event-component-test.tsx.snap new file mode 100644 index 000000000..808137bfc --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-start-event/__snapshots__/bpmn-start-event-component-test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-start-event-component 1`] = ` + +
+ + + + + + Start + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-start-event/bpmn-start-event-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-start-event/bpmn-start-event-component-test.tsx new file mode 100644 index 000000000..53a1589d3 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-start-event/bpmn-start-event-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNStartEvent } from '../../../../../main/packages/bpmn/bpmn-start-event/bpmn-start-event'; +import { BPMNStartEventComponent } from '../../../../../main/packages/bpmn/bpmn-start-event/bpmn-start-event-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-start-event-component', () => { + const startEvent: BPMNStartEvent = new BPMNStartEvent({ name: 'Start' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(startEvent.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-subprocess/__snapshots__/bpmn-subprocess-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-subprocess/__snapshots__/bpmn-subprocess-component-test.tsx.snap new file mode 100644 index 000000000..bf892c3cc --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-subprocess/__snapshots__/bpmn-subprocess-component-test.tsx.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-subprocess-component 1`] = ` + +
+ + + + + + SyntaxTreeTerminal + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component-test.tsx new file mode 100644 index 000000000..1d325f3e9 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNSubprocess } from '../../../../../main/packages/bpmn/bpmn-subprocess/bpmn-subprocess'; +import { BPMNSubprocessComponent } from '../../../../../main/packages/bpmn/bpmn-subprocess/bpmn-subprocess-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-subprocess-component', () => { + const subprocess: BPMNSubprocess = new BPMNSubprocess({ name: 'SyntaxTreeTerminal' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(subprocess.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-task/__snapshots__/bpmn-task-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-task/__snapshots__/bpmn-task-component-test.tsx.snap new file mode 100644 index 000000000..de09db07a --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-task/__snapshots__/bpmn-task-component-test.tsx.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-task-component 1`] = ` + +
+ + + + + + Task + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-task/bpmn-task-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-task/bpmn-task-component-test.tsx new file mode 100644 index 000000000..23883fbaf --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-task/bpmn-task-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNTask } from '../../../../../main/packages/bpmn/bpmn-task/bpmn-task'; +import { BPMNTaskComponent } from '../../../../../main/packages/bpmn/bpmn-task/bpmn-task-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-task-component', () => { + const task: BPMNTask = new BPMNTask({ name: 'Task' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(task.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +}); diff --git a/src/tests/unit/packages/bpmn/bpmn-transaction/__snapshots__/bpmn-transaction-component-test.tsx.snap b/src/tests/unit/packages/bpmn/bpmn-transaction/__snapshots__/bpmn-transaction-component-test.tsx.snap new file mode 100644 index 000000000..003470487 --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-transaction/__snapshots__/bpmn-transaction-component-test.tsx.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the bpmn-transaction-component 1`] = ` + +
+ + + + + + + Transaction + + + + +
+ +`; diff --git a/src/tests/unit/packages/bpmn/bpmn-transaction/bpmn-transaction-component-test.tsx b/src/tests/unit/packages/bpmn/bpmn-transaction/bpmn-transaction-component-test.tsx new file mode 100644 index 000000000..c963fb01b --- /dev/null +++ b/src/tests/unit/packages/bpmn/bpmn-transaction/bpmn-transaction-component-test.tsx @@ -0,0 +1,26 @@ +import { wrappedRender } from '../../../test-utils/render'; +import * as React from 'react'; +import { SyntaxTreeTerminal } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal'; +import { SyntaxTreeTerminalComponent } from '../../../../../main/packages/syntax-tree/syntax-tree-terminal/syntax-tree-terminal-component'; +import { Multiline } from '../../../../../main/utils/svg/multiline'; +import { CSSProperties } from 'react'; +import { BPMNAnnotation } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation'; +import { BPMNAnnotationComponent } from '../../../../../main/packages/bpmn/bpmn-annotation/bpmn-annotation-component'; +import { BPMNTransaction } from '../../../../../main/packages/bpmn/bpmn-transaction/bpmn-transaction'; +import { BPMNTransactionComponent } from '../../../../../main/packages/bpmn/bpmn-transaction/bpmn-transaction-component'; + +// override getStringWidth, because it uses by jsdom unsupported SVGElement methods +Multiline.prototype.getStringWidth = (str: string, style?: CSSProperties) => { + return 0; +}; + +it('render the bpmn-transaction-component', () => { + const transaction: BPMNTransaction = new BPMNTransaction({ name: 'Transaction' }); + const { getByText, baseElement } = wrappedRender( + + + , + ); + expect(getByText(transaction.name)).toBeInTheDocument(); + expect(baseElement).toMatchSnapshot(); +});