Skip to content

Commit

Permalink
feat(tabs): detect cloud-bpmn diagrams
Browse files Browse the repository at this point in the history
Closes #2029

Co-authored-by: Niklas Kiefer <niklas.kiefer@camunda.com>
  • Loading branch information
barmac and Niklas Kiefer committed Feb 22, 2021
1 parent 7d09e65 commit c136c20
Show file tree
Hide file tree
Showing 15 changed files with 563 additions and 31 deletions.
165 changes: 136 additions & 29 deletions client/src/app/TabsProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@ import replaceIds from '@bpmn-io/replace-ids';

import EmptyTab from './EmptyTab';

import { forEach } from 'min-dash';
import {
find,
forEach
} from 'min-dash';

import parseDiagramType from './util/parseDiagramType';

import parseExecutionPlatform from './util/parseExecutionPlatform';

import {
findUsages as findNamespaceUsages,
} from './tabs/util/namespace';

import {
Flags,
generateId
Expand Down Expand Up @@ -58,6 +67,9 @@ const EXPORT_SVG = {
extensions: [ 'svg' ]
};

const NAMESPACE_URL_ZEEBE = 'http://camunda.org/schema/zeebe/1.0';


/**
* A provider that allows us to customize available tabs.
*/
Expand All @@ -67,6 +79,9 @@ export default class TabsProvider {

this.providers = {
empty: {
canOpen(file) {
return false;
},
getComponent() {
return EmptyTab;
},
Expand All @@ -83,6 +98,9 @@ export default class TabsProvider {
svg: EXPORT_SVG
},
extensions: [ 'bpmn', 'xml' ],
canOpen(file) {
return parseDiagramType(file.contents) === 'bpmn';
},
getComponent(options) {
return import('./tabs/bpmn');
},
Expand Down Expand Up @@ -125,6 +143,31 @@ export default class TabsProvider {
svg: EXPORT_SVG
},
extensions: [ 'bpmn', 'xml' ],
canOpen(file) {
const {
contents
} = file;

// (0) can open only BPMN files
if (parseDiagramType(contents) !== 'bpmn') {
return false;
}

// (1) detect execution platform
const executionPlatformDetails = parseExecutionPlatform(contents);

if (executionPlatformDetails) {
return [
'Camunda Cloud',
'Zeebe'
].includes(executionPlatformDetails.executionPlatform);
}

// (2) detect zeebe namespace
const used = findNamespaceUsages(contents, NAMESPACE_URL_ZEEBE);

return !!used;
},
getComponent(options) {
return import('./tabs/cloud-bpmn');
},
Expand Down Expand Up @@ -159,14 +202,17 @@ export default class TabsProvider {
svg: EXPORT_SVG
},
extensions: [ 'cmmn', 'xml' ],
canOpen(file) {
return parseDiagramType(file.contents) === 'cmmn';
},
getComponent(options) {
return import('./tabs/cmmn');
},
getInitialContents(options) {
return cmmnDiagram;
},
getInitialFilename(suffix) {
return `diagram_${suffix}.dmn`;
return `diagram_${suffix}.cmmn`;
},
getHelpMenu() {
return [{
Expand Down Expand Up @@ -200,14 +246,17 @@ export default class TabsProvider {
svg: EXPORT_SVG
},
extensions: [ 'dmn', 'xml' ],
canOpen(file) {
return parseDiagramType(file.contents) === 'dmn';
},
getComponent(options) {
return import('./tabs/dmn');
},
getInitialContents() {
return dmnDiagram;
},
getInitialFilename(suffix) {
return `diagram_${suffix}.cmmn`;
return `diagram_${suffix}.dmn`;
},
getHelpMenu() {
return [{
Expand All @@ -230,14 +279,21 @@ export default class TabsProvider {
}
};

this.providersByFileType = {
bpmn: [ this.providers['cloud-bpmn'], this.providers.bpmn ],
dmn: [ this.providers.dmn ],
cmmn: [ this.providers.cmmn ]
};

if (Flags.get('disable-cmmn', true)) {
delete this.providers.cmmn;
delete this.providersByFileType.cmmn;
}

if (Flags.get('disable-dmn')) {
delete this.providers.dmn;
delete this.providersByFileType.dmn;
}

}

getProviderNames() {
Expand All @@ -258,8 +314,8 @@ export default class TabsProvider {
return this.providers;
}

hasProvider(type) {
return !!this.providers[type];
hasProvider(fileType) {
return !!this._getProvidersForExtension(fileType).length;
}

getProvider(type) {
Expand Down Expand Up @@ -308,33 +364,11 @@ export default class TabsProvider {
return this.createTabForFile(file);
}

getTabType(file) {

const {
name,
contents
} = file;

const typeFromExtension = name.substring(name.lastIndexOf('.') + 1).toLowerCase();

if (this.hasProvider(typeFromExtension)) {
return typeFromExtension;
}

const typeFromContents = parseDiagramType(contents);

if (typeFromContents && this.hasProvider(typeFromContents)) {
return typeFromContents;
}

return null;
}

createTabForFile(file) {

const id = generateId();

const type = this.getTabType(file);
const type = this._getTabType(file);

if (!type) {
return null;
Expand Down Expand Up @@ -362,4 +396,77 @@ export default class TabsProvider {

}

_getTabType(file) {
const provider = this._getFileProvider(file);

if (!provider) {
return null;
}

for (let type in this.providers) {
if (this.providers[type] === provider) {
return type;
}
}
}

/**
* Returns provider if available.
*
* Algorithm:
* * check if there are providers defined for the file extension
* * if there is only one, return it (happy path)
* * if there are more than one:
* * return the first provider which can open the file
* * otherwise return the last provider
* * if there are none, return the first provider which can open the file or `null`
*
* @param {import('./TabsProvider').File} file
* @returns {string | null}
*/
_getFileProvider(file) {
const typeFromExtension = getTypeFromFileExtension(file);

const providersForExtension = this._getProvidersForExtension(typeFromExtension);

// single provider specified for the extension
if (providersForExtension.length === 1) {
return providersForExtension[0];
}

// multiple providers specified for the extension
if (providersForExtension.length > 1) {
const provider = findProviderForFile(providersForExtension, file);

// return the matching provider or the last provider as fallback
return provider || providersForExtension[providersForExtension.length - 1];
}

// no providers specified for the extension; return the first that can open the file
const provider = findProviderForFile(this.providers, file);

return provider || null;
}

_getProvidersForExtension(extension) {
return this.providersByFileType[extension] || [];
}
}



// helper ///////////////////

function getTypeFromFileExtension(file) {
const { name } = file;

return name.substring(name.lastIndexOf('.') + 1).toLowerCase();
}

function findProviderForFile(providers, file) {
return find(providers, provider => {
if (provider.canOpen(file)) {
return provider;
}
});
}
2 changes: 1 addition & 1 deletion client/src/app/tabs/cloud-bpmn/diagram.bpmn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_{{ ID }}" targetNamespace="http://bpmn.io/schema/bpmn" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_{{ ID }}" targetNamespace="http://bpmn.io/schema/bpmn" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:modeler="http://camunda.org/schema/modeler/1.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="1.0.0">
<bpmn:process id="Process_{{ ID:process }}" isExecutable="true">
<bpmn:startEvent id="StartEvent_1" />
</bpmn:process>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:modeler2="http://camunda.org/schema/modeler/1.0" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" modeler2:executionPlatform="Camunda Platform" modeler2:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" />
<bpmn:task id="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="353" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
2 changes: 2 additions & 0 deletions client/src/app/util/__tests__/execution-platform/no-ns.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<definitions />
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions client/src/app/util/__tests__/execution-platform/random.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="NativePrefix" PREFIX_LENGTH="1"/>
<FIELD ID="2" xsi:type="NCharPrefix" PREFIX_LENGTH="8"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="c1" xsi:type="SQLINT"/>
<COLUMN SOURCE="2" NAME="c2" xsi:type="SQLNCHAR"/>
</ROW>
</BCPFORMAT>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:modeler="http://camunda.org/schema/modeler/1.0" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" />
<bpmn:task id="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="353" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:modeler="http://camunda.org/schema/modeler/1.0" xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:biodi="http://bpmn.io/schema/dmn/biodi/1.0" id="Definitions_07dtqfv" name="DRD" namespace="http://camunda.org/schema/1.0/dmn" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<decision id="Decision_13nychf" name="Decision 1">
<extensionElements>
<biodi:bounds x="200" y="200" width="180" height="80" />
</extensionElements>
<decisionTable id="decisionTable_1">
<input id="input_1">
<inputExpression id="inputExpression_1" typeRef="string">
<text></text>
</inputExpression>
</input>
<output id="output_1" typeRef="string" />
</decisionTable>
</decision>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:modeler="http://camunda.org/schema/modeler/1.0" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" />
<bpmn:task id="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="353" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns="http://camunda.org/schema/modeler/1.0" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" executionPlatform="Camunda Platform" executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" />
<bpmn:task id="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="353" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:modeler="http://camunda.org/schema/modeler/1.0" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" modeler:executionPlatform="Camunda Platform">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1" />
<bpmn:task id="Task_1" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="173" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Task_1_di" bpmnElement="Task_1">
<dc:Bounds x="353" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Loading

0 comments on commit c136c20

Please sign in to comment.