Init React Project

This commit is contained in:
theaubmov 2023-12-18 18:09:32 +01:00
parent 67edf4c756
commit 60f2f25158
129 changed files with 12312 additions and 12218 deletions

View File

@ -1,54 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'airbnb',
'plugin:bpmn-io/es6',
'plugin:prettier/recommended',
'plugin:sonarjs/recommended',
'plugin:import/errors',
'plugin:import/warnings',
],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'jsx-a11y/no-autofocus': 'off',
'jsx-a11y/label-has-associated-control': 'off',
'no-console': 'off',
'no-unused-vars': [
'error',
{
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '_',
argsIgnorePattern: '^_',
},
],
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
// We could try turning these on at some point but do not want to force it now
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'no-use-before-define': 0,
'func-names': 'off',
'react/destructuring-assignment': 'off',
'import/prefer-default-export': 'off',
'no-restricted-syntax': 'off',
},
};

View File

@ -1,18 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
- package-ecosystem: pip
directory: "/.github/workflows"
schedule:
interval: daily
- package-ecosystem: pip
directory: "/docs"
schedule:
interval: daily
- package-ecosystem: pip
directory: "/"
schedule:
interval: daily

66
.github/labels.yml vendored
View File

@ -1,66 +0,0 @@
---
# Labels names are important as they are used by Release Drafter to decide
# regarding where to record them in changelog or if to skip them.
#
# The repository labels will be automatically configured using this file and
# the GitHub Action https://github.com/marketplace/actions/github-labeler.
- name: breaking
description: Breaking Changes
color: bfd4f2
- name: bug
description: Something isn't working
color: d73a4a
- name: build
description: Build System and Dependencies
color: bfdadc
- name: ci
description: Continuous Integration
color: 4a97d6
- name: dependencies
description: Pull requests that update a dependency file
color: 0366d6
- name: documentation
description: Improvements or additions to documentation
color: 0075ca
- name: duplicate
description: This issue or pull request already exists
color: cfd3d7
- name: enhancement
description: New feature or request
color: a2eeef
- name: github_actions
description: Pull requests that update Github_actions code
color: "000000"
- name: good first issue
description: Good for newcomers
color: 7057ff
- name: help wanted
description: Extra attention is needed
color: 008672
- name: invalid
description: This doesn't seem right
color: e4e669
- name: performance
description: Performance
color: "016175"
- name: python
description: Pull requests that update Python code
color: 2b67c6
- name: question
description: Further information is requested
color: d876e3
- name: refactoring
description: Refactoring
color: ef67c4
- name: removal
description: Removals and Deprecations
color: 9ae7ea
- name: style
description: Style
color: c120e5
- name: testing
description: Testing
color: b1fc6f
- name: wontfix
description: This will not be worked on
color: ffffff

View File

@ -1,29 +0,0 @@
categories:
- title: ":boom: Breaking Changes"
label: "breaking"
- title: ":rocket: Features"
label: "enhancement"
- title: ":fire: Removals and Deprecations"
label: "removal"
- title: ":beetle: Fixes"
label: "bug"
- title: ":racehorse: Performance"
label: "performance"
- title: ":rotating_light: Testing"
label: "testing"
- title: ":construction_worker: Continuous Integration"
label: "ci"
- title: ":books: Documentation"
label: "documentation"
- title: ":hammer: Refactoring"
label: "refactoring"
- title: ":lipstick: Style"
label: "style"
- title: ":package: Dependencies"
labels:
- "dependencies"
- "build"
template: |
## Changes
$CHANGES

View File

@ -1,28 +0,0 @@
name: Dependabot auto-merge
on:
workflow_run:
workflows: ["Tests"]
types:
- completed
permissions:
contents: write
jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' && github.event.workflow_run.conclusion == 'success' && github.event_name == 'pull_request' }}
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1.6.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Enable auto-merge for Dependabot PRs
# if: ${{contains(steps.metadata.outputs.dependency-names, 'pytest') && steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
# if: ${{contains(steps.metadata.outputs.dependency-names, 'pytest')}}
# ideally we auto-merge if all checks pass
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View File

@ -1,19 +0,0 @@
name: Labeler
on:
push:
branches:
- main
- master
jobs:
labeler:
runs-on: ubuntu-latest
steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Run Labeler
uses: crazy-max/ghaction-github-labeler@v5.0.0
with:
skip-delete: true

View File

@ -1,27 +0,0 @@
name: Publish NPM
# On a published release, run tests and deploy to NPM
on:
workflow_dispatch:
release:
types: [published]
# Job Setup
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 #Checkout Repo
- uses: actions/setup-node@v4 #Setup Node
with:
node-version: 18
- run: npm install
- run: npm test
- uses: JS-DevTools/npm-publish@v3
with:
token: ${{ secrets.NPM_TOKEN }}
access: public
- if: steps.publish.outputs.type != 'none'
run: |
echo "Version changed: ${{ steps.publish.outputs.old-version }} => ${{ steps.publish.outputs.version }}"

View File

@ -1,30 +0,0 @@
name: Tests
# Run on Pull Requests and pushes to main
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
# Job Setup
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 #Checkout Repo
- uses: actions/setup-node@v4 #Setup Node
- uses: nanasess/setup-chromedriver@v2 #Setup ChromeDriver
with:
node-version: '18'
- name: Run Karma Tests
run: |
npm ci
npm run test

26
.gitignore vendored
View File

@ -1,3 +1,23 @@
node_modules/
public/
.idea/
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -1,3 +0,0 @@
module.exports = {
singleQuote: true,
};

View File

@ -1 +0,0 @@
nodejs 18.3.0

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Sartography
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

123
README.md
View File

@ -1,105 +1,70 @@
# Getting Started with Create React App
![Tests](https://github.com/sartography/bpmn-js-spiffworkflow/actions/workflows/tests.yml/badge.svg?branch=main)
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
# SpiffWorkflow Extensions for BPMN.js
This package provides extensions that can be applied to BPMN.js that will enable some important features of [SpiffWorkflow](https://github.com/sartography/SpiffWorkflow) - the Python BPMN Library for executing business processes. See below for more information.
## Available Scripts
**IMPORTANT**: This is a work in progress, and is not yet released.
In the project directory, you can run:
# About
### `npm start`
This extension creates a BPMN editor with all the capabilities of [BPMN.js](https://github.com/bpmn-io/bpmn-js) and the following additions / modifications:
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
* Ability to insert BPMN's Data Input and Data Output Objects.
* A SpiffWorkflow centric Properties Panel for specifying scripts to run before and after a task, and for defining documentation, and Mark-up content for displaying in user and manual tasks. Among other things.
The page will reload when you make changes.\
You may also see any lint errors in the console.
# Data Input and Data Output Element
This extension will allow you to drag BPMN Data Input and Data Output elements onto the diagram and give them appropriate labels. This will generate valid BPMN elements in the underlying XML file - connecting them to the IO Specification of the process, as shown below:
```xml
<bpmn:process id="my_delightful_process" isExecutable="true">
<bpmn:ioSpecification>
<bpmn:dataInput id="DataInput-745019423-1" name="num_dogs" />
<bpmn:dataOutput id="DataOutput-711207596-1" name="happy_index" />
</bpmn:ioSpecification>
...
```
![Screenshot](docs/io.png)
### `npm test`
Using these data input and outputs will allow you to create processes designed to be used as Call Activities. SpiffWorkflow (in a soon-to-be released version) will pick up this information, and enforce it. So that you must provide these input variables to execute, and only the variables mentioned in the output will be passed back to the calling process.
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
## Usage
```javascript
import BpmnModeler from 'bpmn-js/lib/Modeler';
import spiffworkflow from 'bpmn-js-spiffworkflow/app/spiffworkflow';
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
var bpmnJS = new BpmnModeler({
additionalModules: [
spiffworkflow
],
moddleExtensions: {
spiffworkflowModdle: spiffModdleExtension
}
});
```
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
## Run the Example
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
You need a [NodeJS](http://nodejs.org) development stack with [npm](https://npmjs.org) installed to build the project.
### `npm run eject`
To install all project dependencies execute
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
```sh
npm install
```
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
To start the example execute
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
```sh
npm start
```
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
To build the example into the `public` folder execute
## Learn More
```sh
npm run all
```
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
# Integration Points
You can use the EventBus to communicate with this UI, sending and receiving messages to change
the behavior of the editor making it easier for your end users. There are many examples of
this in the app.js file.
Below is a table of all the events that are sent and accepted:
To learn React, check out the [React documentation](https://reactjs.org/).
| Event Name | Description | Fired or Acceped | Parameters | Description |
|--------------------------------|------------------------------------------------------------------|---------|----------------------|--------------------------------------------------------------------------|
| spiff.service\_tasks.requested | Request a list of available services for service task. | Fired | \- | |
| spiff.service\_tasks.returned | Provides a list of services. | Recieved | serviceTaskOperators | ex: \[{id:'Chuck Facts', parameters\[{id:'category', type:'string'}\]}\] |
| spiff.script.edit | Request to edit a python script in some sort of facy editor. | Fired | scriptType | one of: script, preScript, postScript |
| | | | value | The actual python script |
| | | | element | The element that needs updating |
| | | | eventBus | Used by receiver to fire back an event |
| spiff.script.update | Update a python script to a new value. | Recieved | scriptType | one of: script, preScript, postScript |
| | | | value | The updated script |
| | | | element | The element that needs updating |
| spiff.markdown.edit | Request to edit markdown in a fancy editor. | Fired | element | The element that needs updating |
| | | | value | The current markdown content |
| spiff.markdown.update | Update Markdown content for a paticular elements 'instructions'. | Recieved | element | The element that needs updating |
| | | | value | Tne updated Markdown content |
| spiff.callactivity.edit | Requst to edit a call activity by process id. | Fired | processId | The Process the users wants to edit |
| spiff.callactivity.search | Requst to search for a call activity | Fired | processUd | The currently seleted process id |
| | | | eventBus | For sending back the selected process id. |
| spiff.callactivity.update | Update the process id from a call activity (based on search) | Received | processId | The Process the users wants to edit |
| spiff.file.edit | request to edit a file, but file name. | Fired | value | The file name the user wants to edit |
| spiff.dmn.edit | request to edit a dmn by process id. | Fired | value | The DMN id the user wants to edit |
| spiff.json\_files.requested | request a list of local json files. | Fired | optionType | The type of options required ('json' or 'dmn') |
| spff.dmn\_files.requested | request of list of local dmn files. | | | |
| spiff.json\_files.returned | Return a list of available json files | Recieved | options | \[{lable:'My Label', value:'1'}\] |
| spff.dmn\_files.returned | Return a list of available dmn files. | Recieved | options | \[{lable:'My Label', value:'1'}\] |
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
## License
MIT
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

View File

@ -1,15 +0,0 @@
## Releases
Be sure to edit the package.json, and update the version. Releases won't create
a new NPM package unless the version was updated.
A good way to do go about this is with npm version. Which will increment the version in package.json and create a new commit and tag. Here are few examples that you might use, but
there is more information on [NPM Version](https://docs.npmjs.com/cli/v8/commands/npm-version).
For doing a patch release, you can do
```bash
npm version patch -m "Upgrade to %s for reasons"
```
aside from patch, you can use the keywords `minor`, and `major` (there are some others).
Once this is complete, log into GitHub and do an offical release of the package. A published release will result in a new published version on NPM (via a GitHub Action)

View File

@ -1,225 +0,0 @@
import BpmnModeler from 'bpmn-js/lib/Modeler';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import diagramXML from '../test/spec/bpmn/user_form.bpmn';
import spiffworkflow from './spiffworkflow';
import setupFileOperations from './fileOperations';
const modelerEl = document.getElementById('modeler');
const panelEl = document.getElementById('panel');
const spiffModdleExtension = require('./spiffworkflow/moddle/spiffworkflow.json');
let bpmnModeler;
/**
* This provides an example of how to instantiate a BPMN Modeler configured with
* all the extensions and modifications in this application.
*/
try {
bpmnModeler = new BpmnModeler({
container: modelerEl,
keyboard: { bindTo: document },
propertiesPanel: {
parent: panelEl,
},
additionalModules: [
spiffworkflow,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
],
moddleExtensions: {
spiffworkflowModdle: spiffModdleExtension,
},
});
} catch (error) {
if (error.constructor.name === 'AggregateError') {
console.log(error.message);
console.log(error.name);
console.log(error.errors);
}
throw error;
}
/**
* It is possible to populate certain components using API calls to
* a backend. Here we mock out the API call, but this gives you
* a sense of how things might work.
*
*/
bpmnModeler.on('spiff.service_tasks.requested', (event) => {
event.eventBus.fire('spiff.service_tasks.returned', {
serviceTaskOperators: [
{
id: 'Chuck Norris Fact Service',
parameters: [
{
id: 'category',
type: 'string',
},
],
},
{
id: 'Fact about a Number',
parameters: [
{
id: 'number',
type: 'integer',
},
],
},
],
});
});
/**
* Python Script authoring is best done in some sort of editor
* here is an example that will connect a large CodeMirror editor
* to the "Launch Editor" buttons (Script Tasks, and the Pre and Post
* scripts on all other tasks.
*/
const myCodeMirror = CodeMirror(document.getElementById('code_editor'), {
lineNumbers: true,
mode: 'python',
});
const saveCodeBtn = document.getElementById('saveCode');
let launchCodeEvent = null;
bpmnModeler.on('spiff.script.edit', (newEvent) => {
launchCodeEvent = newEvent;
myCodeMirror.setValue(launchCodeEvent.script);
setTimeout(function () {
myCodeMirror.refresh();
}, 1); // We have to wait a moment before calling refresh.
document.getElementById('code_overlay').style.display = 'block';
document.getElementById('code_editor').focus();
});
saveCodeBtn.addEventListener('click', (_event) => {
const { scriptType, element } = launchCodeEvent;
launchCodeEvent.eventBus.fire('spiff.script.update', {
element,
scriptType,
script: myCodeMirror.getValue(),
});
document.getElementById('code_overlay').style.display = 'none';
});
/**
* Like Python Script Editing, it can be nice to edit your Markdown in a
* good editor as well.
*/
const simplemde = new SimpleMDE({
element: document.getElementById('markdown_textarea'),
});
let launchMarkdownEvent = null;
bpmnModeler.on('spiff.markdown.edit', (newEvent) => {
launchMarkdownEvent = newEvent;
simplemde.value(launchMarkdownEvent.value);
document.getElementById('markdown_overlay').style.display = 'block';
document.getElementById('markdown_editor').focus();
});
const saveMarkdownBtn = document.getElementById('saveMarkdown');
saveMarkdownBtn.addEventListener('click', (_event) => {
const { element } = launchMarkdownEvent;
launchMarkdownEvent.eventBus.fire('spiff.markdown.update', {
element,
value: simplemde.value(),
});
document.getElementById('markdown_overlay').style.display = 'none';
});
/**
* Also can be good to launch an editor for a call activity, or file
* Not implemented here but imagine opening up a new browser tab
* and showing a different process or completly different file editor.
*/
bpmnModeler.on('spiff.callactivity.edit', (newEvent) => {
console.log(
'Open new window with editor for call activity: ',
newEvent.processId
);
});
/**
* Also can be good to launch an editor for a call activity, or DMN
* Not implemented here but imagine opening up a new browser tab
* and showing a different process.
*/
bpmnModeler.on('spiff.file.edit', (newEvent) => {
console.log('Open new window to edit file: ', newEvent.value);
});
bpmnModeler.on('spiff.dmn.edit', (newEvent) => {
console.log('Open new window to edit DMN table: ', newEvent.value);
});
/**
* Also handy to get a list of available files that can be used in a given
* context, say json files for a form, or a DMN file for a BusinessRuleTask
*/
bpmnModeler.on('spiff.json_schema_files.requested', (event) => {
event.eventBus.fire('spiff.json_schema_files.returned', {
options: [
{ label: 'pizza_form.json', value: 'pizza_form.json' },
{ label: 'credit_card_form.json', value: 'credit_card_form.json' },
],
});
});
bpmnModeler.on('spiff.dmn_files.requested', (event) => {
event.eventBus.fire('spiff.dmn_files.returned', {
options: [
{ label: 'Pizza Special Prices', value: 'pizza_prices' },
{ label: 'Topping Prices', value: 'topping_prices' },
{ label: 'Test Decision', value: 'test_decision' },
],
});
});
bpmnModeler.on('spiff.data_stores.requested', (event) => {
event.eventBus.fire('spiff.data_stores.returned', {
options: [
{ type: 'typeahead', name: 'countries' },
{ type: 'kkv', name: 'foods' }
],
});
});
// As call activites might refernce processes across the system
// it should be possible to search for a paticular call activity.
bpmnModeler.on('spiff.callactivity.search', (event) => {
console.log("Firing call activity update", event.element)
event.eventBus.fire('spiff.callactivity.update', {
value: 'searched_bpmn_id',
element: event.element,
});
});
/* This restores unresolved references that camunda removes */
bpmnModeler.on('import.parse.complete', event => {
const refs = event.references.filter(r => r.property === 'bpmn:loopDataInputRef' || r.property === 'bpmn:loopDataOutputRef');
const desc = bpmnModeler._moddle.registry.getEffectiveDescriptor('bpmn:ItemAwareElement');
refs.forEach(ref => {
const props = {
id: ref.id,
name: ref.id ? typeof (ref.name) === 'undefined' : ref.name,
};
let elem = bpmnModeler._moddle.create(desc, props);
elem.$parent = ref.element;
ref.element.set(ref.property, elem);
});
});
bpmnModeler.importXML(diagramXML).then(() => {
// Zoom up and center workflow in the middle of the canvas
bpmnModeler.get('canvas').zoom('fit-viewport', 'auto');
});
// This handles the download and upload buttons - it isn't specific to
// the BPMN modeler or these extensions, just a quick way to allow you to
// create and save files, so keeping it outside the example.
setupFileOperations(bpmnModeler);

View File

@ -1,341 +0,0 @@
html,
body {
height: 100%;
margin: 0;
}
.hidden {
display: none;
}
#container {
display: flex;
height: calc(100% - 80px);
}
#modeler {
flex-grow: 1;
}
#panel {
background-color: #fafafa;
border: solid 1px #ccc;
border-radius: 2px;
font-family: 'Arial', sans-serif;
padding: 10px;
min-width: 400px;
}
.djs-label {
font-family: 'Arial', sans-serif;
}
.spiffworkflow-properties-panel-button {
margin: 2px 32px 6px 12px;
padding-left: 2px;
padding-right: 2px;
}
/* Style buttons */
.bpmn-js-spiffworkflow-btn {
background-color: #ffffff;
color: #393939;
border: 1px solid #393939;
padding: 8px 15px;
cursor: pointer;
font-size: 16px;
margin: 12px;
}
.main-btn {
background-color: #0F62FE;
color: white;
border: 1px solid #0F62FE;
padding: 8px 15px;
cursor: pointer;
font-size: 16px;
margin: 12px;
}
.main-btn i {
margin-left: 15px;
}
/* Darker background on mouse-over */
.bpmn-js-spiffworkflow-btn:hover {
background-color: rgb(0, 0, 0);
border: 1px solid #000000;
color: white;
}
/* Code Editor -- provided as a div overlay */
.overlay {
position: fixed;
/* Sit on top of the page content */
display: none;
/* Hidden by default */
width: 100%;
/* Full width (cover the whole page) */
height: 100%;
/* Full height (cover the whole page) */
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
/* Black background with opacity */
z-index: 200;
/* BPMN Canvas has some huge z-indexes, pop-up tools are 100 for ex.*/
}
#code_editor,
#markdown_editor {
background-color: #ccc;
margin: 50px auto 10px auto;
max-width: 800px;
}
#code_buttons,
#markdown_buttons {
margin: 50px auto 10px auto;
max-width: 800px;
right: 10px;
}
.djs-palette.two-column.open {
width: 95px;
}
/* Header */
#header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #ffffff;
color: black;
border-bottom: 1px solid #5F5F5F;
}
#header-actions-center {
/* Adjust as needed */
display: flex;
justify-content: center;
align-items: center;
border-radius: 8px;
border: 0.75px solid #8F8F8F;
}
.header-btn {
background: none;
color: #3c3c3c;
border: none;
padding: 10px 10px;
cursor: pointer;
margin-left: 5px;
font-size: 20px;
}
.header-btn i {
margin-right: 5px;
/* Icon spacing */
}
#process-info h1 {
margin: 0;
font-size: 24px;
}
#process-info p {
margin: 5px 0 0 0;
font-size: 14px;
color: #666;
}
#header-actions {
display: flex;
align-items: center;
}
.bpmn-js-spiffworkflow-btn {
margin-left: 8px;
}
/* Left sidebar */
#left-sidebar {
display: flex;
max-width: 300px;
background-color: #ffffff;
/* background-color: #f4f4f4; */
overflow: hidden;
height: calc(100% - 80px);
float: left;
}
.tabs {
display: flex;
flex-direction: column;
border-right: 1px solid #5F5F5F;
}
.tab-button {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 50px;
background: none;
border: none;
cursor: pointer;
width: 100%;
}
.tab-button i {
font-size: 24px;
color: #333;
margin-bottom: 5px;
}
.tab-button .text {
font-size: 12px;
display: block;
}
.tab-button.active i {
color: #146D83;
}
.tab-button i {
transition: color 0.2s;
}
.tab-button.active i {
transition: color 0.2s;
}
.tab-button:hover {
background-color: #ddd;
}
.tab-button.active,
.tab-button:hover {
background-color: #e9e9e9;
color: DodgerBlue;
}
.tab-content {
display: none;
height: 100%;
width: 300px;
border-right: 1px solid #5F5F5F;
}
.tab-content.active {
display: block;
}
#container::after {
content: "";
clear: both;
display: table;
}
#BPMNElements {
border-bottom: 1px solid #5F5F5F;
}
.bpmn-elements-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #5F5F5F;
padding: 10px;
}
.bpmn-elements-title {
font-weight: bold;
}
.bpmn-elements-toggle {
background: none;
border: none;
cursor: pointer;
padding: 5px;
font-size: 1em;
}
.djs-palette {
position: relative;
display: unset;
padding: 0;
margin: 0;
left: 0;
top: 0;
}
.group-title {
display: flex;
align-items: center;
justify-content: space-between;
padding-block: 5px;
padding-inline: 10px;
background: #f8f8f8;
border-bottom: 1px solid #ddd;
/* cursor: pointer; */
}
.group-title span {
font-weight: normal;
}
.group.collapsed .entry {
display: none;
}
.group-toggle {
background: none;
border: none;
cursor: pointer;
}
.djs-palette-entries {
display: grid;
}
.djs-palette .entry,
.djs-palette .djs-palette-toggle {
justify-items: center;
padding-block: 5px;
height: unset;
width: unset;
line-height: unset;
display: inline-grid;
cursor: pointer;
}
.entry-label {
color: #22242A;
text-align: center;
font-family: Inter;
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.entries-container {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 10px;
}
.entry {
flex: 0 0 calc(25% - 10px);
display: flex;
align-items: center;
justify-content: center;
margin-block: 5px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,186 +0,0 @@
// FileSaver isn't really a dependency, we use it here to provide an example.
// eslint-disable-next-line import/no-extraneous-dependencies
import FileSaver from 'file-saver';
/** ****************************************
* Below are a few helper methods so we can upload and download files
* easily from the editor for testing purposes.
* -----------------------------------------
*/
export default function setupFileOperations(bpmnModeler) {
/**
* Just a quick bit of code so we can save the XML that is output.
* Helps for debugging against other libraries (like SpiffWorkflow)
*/
const btn = document.getElementById('downloadButton');
btn.addEventListener('click', (_event) => {
saveXML();
});
async function saveXML() {
const { xml } = await bpmnModeler.saveXML({ format: true });
const blob = new Blob([xml], { type: 'text/xml' });
FileSaver.saveAs(blob, 'diagram.bpmn');
}
/**
* Just a quick bit of code so we can open a local XML file
* Helps for debugging against other libraries (like SpiffWorkflow)
*/
const uploadBtn = document.getElementById('uploadButton');
uploadBtn.addEventListener('click', (_event) => {
openFile(bpmnModeler);
});
// Handle header actions
const headerButtons = document.querySelectorAll('.header-btn');
headerButtons.forEach(function (btn) {
btn.addEventListener('click', function (event) {
const action = event.target.closest('.header-btn').getAttribute('data-action');
handleHeaderAction(action, bpmnModeler);
});
});
// Handle sidebar toggle button
const toggleButtons = document.querySelectorAll('.bpmn-elements-toggle');
toggleButtons.forEach(function (btn) {
btn.addEventListener('click', function (event) {
// Use a data attribute to identify which tab to toggle
const tabTarget = event.target.closest('button').getAttribute('data-tab-target');
toggleTab(tabTarget);
});
});
// Setup tabs after modeler is initialized
setupTabs();
}
function clickElem(elem) {
const eventMouse = document.createEvent('MouseEvents');
eventMouse.initMouseEvent(
'click',
true,
false,
window,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
elem.dispatchEvent(eventMouse);
}
export function openFile(bpmnModeler) {
const readFile = function readFileCallback(e) {
const file = e.target.files[0];
if (!file) {
return;
}
const reader = new FileReader();
reader.onload = function onloadCallback(onloadEvent) {
const contents = onloadEvent.target.result;
bpmnModeler.importXML(contents);
document.body.removeChild(fileInput);
};
reader.readAsText(file);
};
let fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.style.display = 'none';
fileInput.onchange = readFile;
document.body.appendChild(fileInput);
clickElem(fileInput);
}
/** ****************************************
* Tab functionality
*/
function openTab(event, tabName) {
// Hide all tab contents
const tabContents = document.querySelectorAll('.tab-content');
tabContents.forEach(content => {
content.classList.remove('active');
});
// Remove active class from all tabs
const tabButtons = document.querySelectorAll('.tab-button');
tabButtons.forEach(button => {
button.classList.remove('active');
});
// append active tab content class to the clicked tab button
document.getElementById(tabName).classList.add('active');
event.currentTarget.classList.add('active');
}
function setupTabs() {
const tabs = document.querySelectorAll('.tab-button');
tabs.forEach(tab => {
tab.addEventListener('click', function (event) {
openTab(event, this.getAttribute('data-tab-target'));
});
});
}
function toggleTab(tabId) {
const tabContent = document.getElementById(tabId);
const allTabContents = document.querySelectorAll('.tab-content');
// Remove 'active' from all tabs
allTabContents.forEach(function (tab) {
tab.classList.remove('active');
});
}
/**
* Header functionality
*/
function handleHeaderAction(action, bpmnModeler) {
var commandStack = bpmnModeler.get('commandStack');
var paletteProvider = bpmnModeler.get('paletteProvider');
var canvas = bpmnModeler.get('canvas');
switch (action) {
case 'zoom-in':
bpmnModeler.get('zoomScroll').stepZoom(1);
break;
case 'zoom-out':
bpmnModeler.get('zoomScroll').stepZoom(-1);
break;
case 'expand':
canvas.zoom('fit-viewport', 'auto');
break;
case 'undo':
commandStack.undo();
break;
case 'redo':
commandStack.redo();
break;
case 'hand':
const handTool = paletteProvider._handTool;
handTool.activateHand();
break;
case 'lasso':
const lassoTool = paletteProvider._lassoTool;
lassoTool.activateSelection(event);
break;
case 'space':
const spaceTool = paletteProvider._spaceTool;
spaceTool.activateSelection();
break;
case 'connect':
const globalConnect = paletteProvider._globalConnect;
globalConnect.start();
break;
default:
console.log('Unknown action:', action);
}
}

View File

@ -1,172 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>bpmn-js-spiffworkflow</title>
<meta charset="utf-8" />
<!-- here are the core dependencies you will need to include -->
<link rel="stylesheet" href="vendor/bpmn-js/assets/diagram-js.css" />
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-js.css" />
<link rel="stylesheet" href="vendor/bpmn-js/assets/bpmn-font/css/bpmn-embedded.css" />
<link rel="stylesheet" href="vendor/bpmn-js-properties-panel/assets/properties-panel.css" />
<!-- Some local css settings -->
<link rel="stylesheet" href="css/app.css" />
<link rel="shortcut icon" href="#">
<!-- A python code editor, we are using CodeMirror here -- see app.js for how this is wired in -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/python/python.min.js"></script>
<!-- Markdown Editor -- see app.js for how to wire these in. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
<!-- Just have this for the download file icon -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div id="header">
<div id="process-info">
<h1>Process Name</h1>
<p>./Process Groups/bpmn_process.bpmn</p>
</div>
<div id="header-actions-center">
<button class="header-btn" title="Hand" data-action="hand">
<i class="bpmn-icon-hand-tool"></i>
</button>
<button class="header-btn" title="LassoTool" data-action="lasso">
<i class="bpmn-icon-lasso-tool"></i>
</button>
<button class="header-btn" title="SpaceTool" data-action="space">
<i class="bpmn-icon-space-tool"></i>
</button>
<button class="header-btn" title="Connect" data-action="connect">
<i class="bpmn-icon-connection-multi"></i>
</button>
<button class="header-btn" title="Zoom In" data-action="zoom-in">
<i class="fa fa-search-plus"></i>
</button>
<button class="header-btn" title="Zoom Out" data-action="zoom-out">
<i class="fa fa-search-minus"></i>
</button>
<button class="header-btn" title="Expand" data-action="expand">
<i class="fa fa-expand"></i>
</button>
<button class="header-btn" title="Undo" data-action="undo">
<i class="fa fa-undo"></i>
</button>
<button class="header-btn" title="Redo" data-action="redo">
<i class="fa fa-repeat"></i>
</button>
</div>
<div id="header-actions">
<button id="downloadButton" class="bpmn-js-spiffworkflow-btn">
Download
</button>
<button id="uploadButton" class="bpmn-js-spiffworkflow-btn">Open a file</button>
<button id="viewXmlButton" class="bpmn-js-spiffworkflow-btn">View XML</button>
<button id="saveButton" class="bpmn-js-spiffworkflow-btn main-btn">
Save <i class="fa fa-long-arrow-right"></i>
</button>
</div>
</div>
<div id="left-sidebar">
<div class="tabs">
<button class="tab-button active" data-tab-target="BPMNElements">
<i class="fa fa-th-large"></i>
</button>
<button class="tab-button" data-tab-target="SearchTab">
<i class="fa fa-search"></i>
</button>
<button class="tab-button" data-tab-target="ActionTab">
<i class="fa fa-bolt"></i>
</button>
<button class="tab-button" data-tab-target="ConnectorTab">
<i class="fa fa-cube"></i>
</button>
<button class="tab-button" data-tab-target="HistoryTab">
<i class="fa fa-clock-o"></i>
</button>
</div>
<div id="BPMNElements" class="tab-content active">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">BPMN Elements</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
</div>
<div id="HistoryTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">History</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
History Tab Content
</div>
<div id="ActionTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Visual Activity</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Pre built Actions Tab Content
</div>
<div id="SearchTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Search</span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Search Tab Content
</div>
<div id="ConnectorTab" class="tab-content">
<div class="bpmn-elements-header">
<span class="bpmn-elements-title">Integrations / Connectors </span>
<button class="bpmn-elements-toggle">
<i class="fa fa-outdent" aria-hidden="true"></i>
</button>
</div>
<!-- Content for BPMN Elements -->
Connectors Tab Content
</div>
</div>
<div id="container">
<div id="modeler"></div>
<div id="panel"></div>
</div>
<!-- the following are overlays to provide editors for Python and Markdown -->
<div id="code_overlay" class="overlay">
<div id="code_editor"></div>
<div id="code_buttons">
<button id="saveCode" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
</div>
<div id="markdown_overlay" class="overlay">
<div id="markdown_editor">
<textarea id="markdown_textarea"></textarea>
</div>
<div id="markdown_buttons">
<button id="saveMarkdown" class="bpmn-js-spiffworkflow-btn">Save</button>
</div>
</div>
<!-- Here we load up our application, it's where the configuration happens. -->
<script src="app.js"></script>
</body>
</html>

View File

@ -1,299 +0,0 @@
import { assign } from 'min-dash';
import translate from 'diagram-js/lib/i18n/translate/translate';
/**
* Add data inputs and data outputs to the panel.
*/
export default function IoPalette(palette, create, elementFactory, eventBus, handTool, globalConnect, lassoTool, spaceTool) {
this._create = create;
this._elementFactory = elementFactory;
this._handTool = handTool;
this._globalConnect = globalConnect;
this._lassoTool = lassoTool;
this._spaceTool = spaceTool;
eventBus.on('palette.create', function (event) {
this.init(event);
}.bind(this));
palette.registerProvider(this);
}
IoPalette.$inject = [
'palette',
'create',
'elementFactory',
'eventBus',
'handTool',
'globalConnect',
'lassoTool',
'spaceTool'
];
IoPalette.prototype.getPaletteEntries = function (e) {
let input_type = 'bpmn:DataInput';
let output_type = 'bpmn:DataOutput';
let elementFactory = this._elementFactory, create = this._create;
function createListener(event, type) {
let shape = elementFactory.createShape(assign({ type: type }, {}));
shape.width = 36; // Fix up the shape dimensions from the defaults.
shape.height = 50;
create.start(event, shape);
}
function createInputListener(event) {
createListener(event, input_type);
}
function createOutputListener(event) {
createListener(event, output_type);
}
function createShape(type, options = {}) {
return function(event) {
let shape = elementFactory.createShape(assign({ type: type }, options));
create.start(event, shape);
};
}
return {
// Events
'create.start-event': {
group: 'events',
className: 'bpmn-icon-start-event-none',
title: translate('Start'),
action: {
dragstart: createShape('bpmn:StartEvent'),
click: createShape('bpmn:StartEvent')
}
},
'create.intermediate-event': {
group: 'events',
className: 'bpmn-icon-intermediate-event-none',
title: translate('Intermediate'),
action: {
dragstart: createShape('bpmn:IntermediateCatchEvent'),
click: createShape('bpmn:IntermediateCatchEvent')
}
},
'create.end-event': {
group: 'events',
className: 'bpmn-icon-end-event-none',
title: translate('End'),
action: {
dragstart: createShape('bpmn:EndEvent'),
click: createShape('bpmn:EndEvent')
}
},
// Activities
'create.task': {
group: 'activities',
className: 'bpmn-icon-task',
title: translate('Task'),
action: {
dragstart: createShape('bpmn:Task'),
click: createShape('bpmn:Task')
}
},
'create.user-task': {
group: 'activities',
className: 'bpmn-icon-user',
title: translate('User Task'),
action: {
dragstart: createShape('bpmn:UserTask'),
click: createShape('bpmn:UserTask')
}
},
'create.scirpt-task': {
group: 'activities',
className: 'bpmn-icon-script',
title: translate('Script Task'),
action: {
dragstart: createShape('bpmn:ScriptTask'),
click: createShape('bpmn:ScriptTask')
}
},
'create.service-task': {
group: 'activities',
className: 'bpmn-icon-service',
title: translate('Service Task'),
action: {
dragstart: createShape('bpmn:ServiceTask'),
click: createShape('bpmn:ServiceTask')
}
},
// Gateways
'create.condition-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-xor',
title: translate('Decision'),
action: {
dragstart: createShape('bpmn:ExclusiveGateway'),
click: createShape('bpmn:ExclusiveGateway')
}
},
'create.parallel-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-parallel',
title: translate('Parallel'),
action: {
dragstart: createShape('bpmn:ParallelGateway'),
click: createShape('bpmn:ParallelGateway')
}
},
'create.eventbased-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-eventbased',
title: translate('Event Based'),
action: {
dragstart: createShape('bpmn:EventBasedGateway'),
click: createShape('bpmn:EventBasedGateway')
}
},
'create.inclusive-gateaway': {
group: 'decisions',
className: 'bpmn-icon-gateway-or',
title: translate('xOR'),
action: {
dragstart: createShape('bpmn:InclusiveGateway'),
click: createShape('bpmn:InclusiveGateway')
}
},
// Data Object
'create.data-store': {
group: 'advanced',
className: 'bpmn-icon-data-store',
title: translate('Data Store'),
action: {
dragstart: createShape('bpmn:DataStoreReference'),
click: createShape('bpmn:DataStoreReference')
}
},
'create.data-object': {
group: 'advanced',
className: 'bpmn-icon-data-object',
title: translate('Data Object'),
action: {
dragstart: createShape('bpmn:DataObjectReference'),
click: createShape('bpmn:DataObjectReference')
}
},
'create.data-input': {
group: 'advanced',
className: 'bpmn-icon-data-input',
title: translate('DataInput'),
action: {
dragstart: createInputListener,
click: createInputListener
}
},
'create.data-output': {
group: 'advanced',
className: 'bpmn-icon-data-output',
title: translate('DataOutput'),
action: {
dragstart: createOutputListener,
click: createOutputListener
}
},
'create.call-activity': {
group: 'advanced',
className: 'bpmn-icon-call-activity',
title: translate('Call Activity'),
action: {
dragstart: createShape('bpmn:CallActivity'),
click: createShape('bpmn:CallActivity')
}
},
'create.participant': {
group: 'advanced',
className: 'bpmn-icon-participant',
title: translate('Participant'),
action: {
dragstart: createShape('bpmn:Participant'),
click: createShape('bpmn:Participant')
}
},
'create.sub-process-expanded': {
group: 'advanced',
className: 'bpmn-icon-subprocess-expanded',
title: translate('SubProcess'),
action: {
dragstart: createShape('bpmn:SubProcess', {isExpanded: true}),
click: createShape('bpmn:SubProcess', {isExpanded: true})
}
},
};
};
IoPalette.prototype.init = function (event) {
// Override Palette DOM Generated by BPMN-JS Library
const paletteContainer = event.container;
const bpmnElementsDiv = document.getElementById('BPMNElements');
setTimeout(() => {
// Query all group elements
const groups = paletteContainer.querySelectorAll('.group');
groups.forEach(group => {
const groupName = group.getAttribute('data-group');
const title = groupName.charAt(0).toUpperCase() + groupName.slice(1).replace(/-/g, ' '); // Capitalize and format the title
// Check if group title already exists
let header = group.querySelector('.group-title');
let entriesContainer = group.querySelector('.entries-container'); // Container for entries
if (!header) {
// Creation the collapsible header
header = document.createElement('div');
header.classList.add('group-title');
// Creation the title span
const titleSpan = document.createElement('span');
titleSpan.textContent = title;
header.appendChild(titleSpan);
// Creation the toggle button
const toggleButton = document.createElement('button');
toggleButton.classList.add('group-toggle');
toggleButton.innerHTML = '<i class="fa fa-chevron-down" aria-hidden="true"></i>';
header.appendChild(toggleButton);
// Insert the header
group.insertBefore(header, group.firstChild);
// Create the entries container
entriesContainer = document.createElement('div');
entriesContainer.classList.add('entries-container');
group.appendChild(entriesContainer); // Append entries container after the header
toggleButton.addEventListener('click', function () {
entriesContainer.style.display = entriesContainer.style.display === 'none' ? '' : 'none';
toggleButton.innerHTML = entriesContainer.style.display === 'none' ? '<i class="fa fa-chevron-right" aria-hidden="true"></i>' : '<i class="fa fa-chevron-down" aria-hidden="true"></i>';
});
}
const entries = group.querySelectorAll('.entry');
entries.forEach(entry => {
entriesContainer.appendChild(entry);
let label = entry.querySelector('.entry-label');
if (!label) {
label = document.createElement('span');
label.classList.add('entry-label');
entry.appendChild(label);
}
label.textContent = entry.getAttribute('title');
});
});
// Move the palette
bpmnElementsDiv.appendChild(paletteContainer);
}, 200);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -1,126 +0,0 @@
'use strict';
const coverage = process.env.COVERAGE;
const path = require('path');
const {
DefinePlugin,
NormalModuleReplacementPlugin
} = require('webpack');
const basePath = '.';
const absoluteBasePath = path.resolve(path.join(__dirname, basePath));
module.exports = function(karma) {
karma.set({
frameworks: [
'webpack',
'mocha',
'sinon-chai'
],
files: [
'test/spec/**/*Spec.js',
],
reporters: [ 'dots' ],
preprocessors: {
'test/spec/**/*Spec.js': [ 'webpack', 'env' ]
},
browsers: [ 'ChromeHeadless' ],
browserNoActivityTimeout: 30000,
singleRun: true,
autoWatch: false,
webpack: {
mode: 'development',
module: {
rules: [
{
test: /\.(css|bpmn)$/,
use: 'raw-loader'
},
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
plugins: [
[ '@babel/plugin-transform-react-jsx', {
'importSource': '@bpmn-io/properties-panel/preact',
'runtime': 'automatic'
} ]
]
}
}
},
{
test: /\.svg$/,
use: [ 'react-svg-loader' ]
}
].concat(coverage ?
{
test: /\.js$/,
use: {
loader: 'istanbul-instrumenter-loader',
options: { esModules: true }
},
enforce: 'post',
include: /src\.*/,
exclude: /node_modules/
} : []
)
},
plugins: [
new DefinePlugin({
// @barmac: process.env has to be defined to make @testing-library/preact work
'process.env': {}
}),
new NormalModuleReplacementPlugin(
/^preact(\/[^/]+)?$/,
function(resource) {
const replMap = {
'preact/hooks': path.resolve('node_modules/@bpmn-io/properties-panel/preact/hooks/dist/hooks.module.js'),
'preact/jsx-runtime': path.resolve('node_modules/@bpmn-io/properties-panel/preact/jsx-runtime/dist/jsxRuntime.module.js'),
'preact': path.resolve('node_modules/@bpmn-io/properties-panel/preact/dist/preact.module.js')
};
const replacement = replMap[resource.request];
if (!replacement) {
return;
}
resource.request = replacement;
}
),
new NormalModuleReplacementPlugin(
/^preact\/hooks/,
path.resolve('node_modules/@bpmn-io/properties-panel/preact/hooks/dist/hooks.module.js')
)
],
resolve: {
mainFields: [
'browser',
'module',
'main'
],
alias: {
'preact': '@bpmn-io/properties-panel/preact',
'react': '@bpmn-io/properties-panel/preact/compat',
'react-dom': '@bpmn-io/properties-panel/preact/compat'
},
modules: [
'node_modules',
absoluteBasePath
]
},
devtool: 'eval-source-map'
}
});
};

16054
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +1,42 @@
{
"name": "bpmn-js-spiffworkflow",
"version": "0.0.8",
"description": "Extensions and modifications of BPMN.js to improve BPMN development for SpiffWorkflow",
"scripts": {
"all": "run-s lint test build",
"build": "webpack --mode production",
"build:watch": "webpack --watch",
"dev": "run-p build:watch serve",
"serve": "sirv public --dev",
"lint": "./node_modules/.bin/eslint app *.js",
"lint:fix": "./node_modules/.bin/eslint --fix app *.js",
"start": "run-s build serve",
"test": "karma start karma.conf.js"
},
"repository": {
"type": "git",
"url": "https://github.com/sartography/bpmn-js-spiffworkflow"
},
"keywords": [
"bpmn",
"spiffworkflow"
],
"author": {
"name": "Dan Funk (Sartography)",
"url": "https://github.com/danfunk"
},
"contributors": [
{
"name": "bpmn.io contributors",
"url": "https://github.com/bpmn-io"
}
],
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.17.12",
"@babel/preset-env": "^7.18.6",
"@babel/preset-react": "^7.18.2",
"@testing-library/preact": "^2.0.1",
"@testing-library/preact-hooks": "^1.1.0",
"@types/mocha": "^9.1.1",
"babel-loader": "^8.2.5",
"chai": "^4.3.6",
"copy-webpack-plugin": "^11.0.0",
"eslint": "^8.18.0",
"eslint_d": "^12.2.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-bpmn-io": "^0.14.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-sonarjs": "^0.13.0",
"file-saver": "^2.0.5",
"karma": "^6.3.4",
"karma-chrome-launcher": "^3.1.1",
"karma-coverage": "^2.2.0",
"karma-env-preprocessor": "^0.1.1",
"karma-mocha": "^2.0.1",
"karma-sinon-chai": "^2.0.2",
"karma-webpack": "^5.0.0",
"mocha": "^10.0.0",
"mocha-test-container-support": "^0.2.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.7.1",
"raw-loader": "^4.0.2",
"sinon": "^14.0.0",
"sinon-chai": "^3.7.0",
"sirv-cli": "^2.0.2",
"stringify": "^5.2.0",
"webpack": "^5.73.0",
"webpack-cli": "^4.9.2"
},
"peerDependencies": {
"name": "bpmn-js-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"bpmn-js": "^13.0.0",
"bpmn-js-properties-panel": "*",
"diagram-js": "*"
"diagram-js": "*",
"font-awesome": "^4.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"dependencies": {
"inherits": "^2.0.4",
"inherits-browser": "^0.0.1",
"min-dash": "^3.8.1",
"min-dom": "^3.2.1",
"moddle": "^5.0.3",
"tiny-svg": "^2.2.3"
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -1,101 +0,0 @@
<?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" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_19o7vxg" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
<bpmn:process id="ProcessTest" isExecutable="true">
<bpmn:ioSpecification>
<bpmn:dataInput id="num_dogs" name="Number of Dogs" />
<bpmn:dataOutput id="happy_index" name="Happiness Index" />
</bpmn:ioSpecification>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1mezzcx</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:endEvent id="Event_14wzv4j">
<bpmn:incoming>Flow_0q4oys2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_01jg677" sourceRef="Activity_15zz6ya" targetRef="my_script_task" />
<bpmn:sequenceFlow id="Flow_1mezzcx" sourceRef="StartEvent_1" targetRef="Activity_15zz6ya" />
<bpmn:manualTask id="Activity_15zz6ya" name="eat hot dog">
<bpmn:incoming>Flow_1mezzcx</bpmn:incoming>
<bpmn:outgoing>Flow_01jg677</bpmn:outgoing>
<bpmn:dataOutputAssociation id="DataOutputAssociation_1uj5jzs">
<bpmn:targetRef>my_data_ref_1</bpmn:targetRef>
</bpmn:dataOutputAssociation>
<bpmn:standardLoopCharacteristics />
</bpmn:manualTask>
<bpmn:sequenceFlow id="Flow_0q4oys2" sourceRef="my_script_task" targetRef="Event_14wzv4j" />
<bpmn:scriptTask id="my_script_task" name="calculate contentment">
<bpmn:incoming>Flow_01jg677</bpmn:incoming>
<bpmn:outgoing>Flow_0q4oys2</bpmn:outgoing>
<bpmn:property id="Property_1w1963p" name="__targetRef_placeholder" />
<bpmn:dataInputAssociation id="DataInputAssociation_0thubmi">
<bpmn:sourceRef>my_data_ref_2</bpmn:sourceRef>
<bpmn:targetRef>Property_1w1963p</bpmn:targetRef>
</bpmn:dataInputAssociation>
</bpmn:scriptTask>
<bpmn:dataObject id="my_data_object" />
<bpmn:dataObject id="my_other_data_object" />
<bpmn:dataObject id="my_third_data_object" />
<bpmn:dataObjectReference id="my_data_ref_1" name="my_data_object" dataObjectRef="my_data_object" />
<bpmn:dataObjectReference id="my_data_ref_2" name="my_data_object" dataObjectRef="my_data_object" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="ProcessTest">
<bpmndi:BPMNEdge id="Flow_0q4oys2_di" bpmnElement="Flow_0q4oys2">
<di:waypoint x="540" y="197" />
<di:waypoint x="602" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1mezzcx_di" bpmnElement="Flow_1mezzcx">
<di:waypoint x="215" y="197" />
<di:waypoint x="280" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_01jg677_di" bpmnElement="Flow_01jg677">
<di:waypoint x="380" y="197" />
<di:waypoint x="440" y="197" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="179" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_14wzv4j_di" bpmnElement="Event_14wzv4j">
<dc:Bounds x="602" y="179" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0t7iwfm_di" bpmnElement="Activity_15zz6ya">
<dc:Bounds x="280" y="157" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0h86vbv_di" bpmnElement="my_script_task">
<dc:Bounds x="440" y="157" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_1cezipn_di" bpmnElement="my_data_ref_1">
<dc:Bounds x="312" y="275" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="314" y="332" width="33" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="DataObjectReference_08bm72g_di" bpmnElement="my_data_ref_2">
<dc:Bounds x="462" y="275" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="464" y="332" width="33" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="dataInput_1" bpmnElement="num_dogs">
<dc:Bounds x="179" y="85" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="158" y="135" width="81" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="dataInput_2" bpmnElement="happy_index">
<dc:Bounds x="602" y="85" width="36" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="580" y="142" width="83" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="DataOutputAssociation_1uj5jzs_di" bpmnElement="DataOutputAssociation_1uj5jzs">
<di:waypoint x="329" y="237" />
<di:waypoint x="328" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DataInputAssociation_0thubmi_di" bpmnElement="DataInputAssociation_0thubmi">
<di:waypoint x="483" y="275" />
<di:waypoint x="489" y="237" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

83
src/App.css Normal file
View File

@ -0,0 +1,83 @@
html, body, .App, #root {
height: 100%;
}
.hidden {
display: none;
}
#container {
display: flex;
width: 100%;
height: 100%;
}
#modeler {
flex-grow: 1;
}
#panel {
background-color: #fafafa;
border: solid 1px #ccc;
border-radius: 2px;
font-family: 'Arial', sans-serif;
padding: 10px;
min-width: 400px;
}
.djs-label {
font-family: 'Arial', sans-serif;
}
.spiffworkflow-properties-panel-button {
margin: 2px 32px 6px 12px;
padding-left: 2px;
padding-right: 2px;
}
/* Style buttons */
.bpmn-js-spiffworkflow-btn {
background-color: DodgerBlue;
border: none;
color: white;
padding: 8px 15px;
cursor: pointer;
font-size: 16px;
margin: 12px;
}
/* Darker background on mouse-over */
.bpmn-js-spiffworkflow-btn:hover {
background-color: RoyalBlue;
}
/* Code Editor -- provided as a div overlay */
.overlay {
position: fixed; /* Sit on top of the page content */
display: none; /* Hidden by default */
width: 100%; /* Full width (cover the whole page) */
height: 100%; /* Full height (cover the whole page) */
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
z-index: 200; /* BPMN Canvas has some huge z-indexes, pop-up tools are 100 for ex.*/
}
#code_editor, #markdown_editor {
background-color: #ccc;
margin: 50px auto 10px auto;
max-width: 800px;
}
#code_buttons, #markdown_buttons {
margin: 50px auto 10px auto;
max-width: 800px;
right: 10px;
}
.djs-palette.two-column.open {
width: 95px;
}

133
src/App.js Normal file
View File

@ -0,0 +1,133 @@
import React, { useEffect, useRef } from 'react';
import BpmnModeler from 'bpmn-js/lib/Modeler';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import spiffworkflow from './spiffworkflow';
import './App.css';
// Import BPMN JS CSS
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
import 'bpmn-js-properties-panel/dist/assets/properties-panel.css'
// Import Font Awesome
import 'font-awesome/css/font-awesome.min.css';
function App() {
const modelerRef = useRef(null);
const panelRef = useRef(null);
// const codeEditorRef = useRef(null);
// const markdownTextareaRef = useRef(null);
useEffect(() => {
console.log('Hi App!');
// If modelerRef or panelRef are not empty, make it empty
if (modelerRef.current) {
modelerRef.current.innerHTML = '';
}
if (panelRef.current) {
panelRef.current.innerHTML = '';
}
// Initialize BPMN Modeler
const spiffModdleExtension = require('./spiffworkflow/moddle/spiffworkflow.json');
let bpmnModeler;
// Initialize BPMN Modeler
try {
bpmnModeler = new BpmnModeler({
container: modelerRef.current,
keyboard: { bindTo: document },
propertiesPanel: {
parent: panelRef.current,
},
additionalModules: [
spiffworkflow,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
],
moddleExtensions: {
spiffworkflowModdle: spiffModdleExtension,
},
});
// ... rest of the initialization code
// Declare XML content as string example
try {
let xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="sample-diagram" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn:process id="Process_1" isExecutable="false">
<bpmn:startEvent id="StartEvent_1"/>
<bpmn:task id="Task_1" name="Sample Task"/>
<bpmn:endEvent id="EndEvent_1"/>
<bpmn:sequenceFlow id="Flow_1" sourceRef="StartEvent_1" targetRef="Task_1"/>
<bpmn:sequenceFlow id="Flow_2" sourceRef="Task_1" targetRef="EndEvent_1"/>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="StartEvent_1_di" 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="233" y="80" width="100" height="80"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
<dc:Bounds x="383" y="102" width="36" height="36"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1_di" bpmnElement="Flow_1">
<di:waypoint x="209" y="120"/>
<di:waypoint x="233" y="120"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_2_di" bpmnElement="Flow_2">
<di:waypoint x="333" y="120"/>
<di:waypoint x="383" y="120"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
`
bpmnModeler.importXML(xmlContent).then(() => { });
} catch (error) {
console.log(error);
}
// setupFileOperations(bpmnModeler);
} catch (error) {
// Error handling
console.error(error);
}
// Initialize CodeMirror and SimpleMDE if necessary
// ...
return () => {
// Cleanup
// Destroy instances or remove event listeners if necessary
};
}, []);
return (
<div className="App">
<div id="menu">
<button id="downloadButton" className="bpmn-js-spiffworkflow-btn"><i className="fa fa-download"></i> Download</button>
<button id="uploadButton" className="bpmn-js-spiffworkflow-btn">Open a file</button>
</div>
<div id="container">
<div id="modeler" ref={modelerRef}></div>
<div id="panel" ref={panelRef}></div>
</div>
</div>
);
}
export default App;

8
src/App.test.js Normal file
View File

@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

13
src/index.css Normal file
View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

17
src/index.js Normal file
View File

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

1
src/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

13
src/reportWebVitals.js Normal file
View File

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

5
src/setupTests.js Normal file
View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View File

@ -44,6 +44,7 @@ export default function DataObjectPropertiesProvider(
return groups;
};
};
console.log('DataObjectPropertiesProvider', this);
propertiesPanel.registerProvider(LOW_PRIORITY, this);
}

View File

@ -0,0 +1,62 @@
import { assign } from 'min-dash';
import translate from 'diagram-js/lib/i18n/translate/translate';
/**
* Add data inputs and data outputs to the panel.
*/
export default function IoPalette(palette, create, elementFactory,) {
this._create = create;
this._elementFactory = elementFactory;
palette.registerProvider(this);
}
IoPalette.$inject = [
'palette',
'create',
'elementFactory'
];
IoPalette.prototype.getPaletteEntries = function() {
let input_type = 'bpmn:DataInput';
let output_type = 'bpmn:DataOutput';
let elementFactory = this._elementFactory, create = this._create;
function createListener(event, type) {
let shape = elementFactory.createShape(assign({ type: type }, {}));
shape.width = 36; // Fix up the shape dimensions from the defaults.
shape.height = 50;
create.start(event, shape);
}
function createInputListener(event) {
createListener(event, input_type);
}
function createOutputListener(event) {
createListener(event, output_type);
}
return {
'create.data-input': {
group: 'data-object',
className: 'bpmn-icon-data-input',
title: translate('Create DataInput'),
action: {
dragstart: createInputListener,
click: createInputListener
}
},
'create.data-output': {
group: 'data-object',
className: 'bpmn-icon-data-output',
title: translate('Create DataOutput'),
action: {
dragstart: createOutputListener,
click: createOutputListener
}
}
};
};

View File

@ -36,7 +36,6 @@ export default {
'escalationPropertiesProvider',
'callActivityPropertiesProvider',
'ioPalette',
'paletteProvider',
'ioRules',
'ioInterceptor',
'dataObjectRenderer',
@ -58,7 +57,6 @@ export default {
messagesPropertiesProvider: ['type', MessagesPropertiesProvider],
callActivityPropertiesProvider: ['type', CallActivityPropertiesProvider],
ioPalette: ['type', IoPalette],
paletteProvider: ['type', IoPalette],
ioRules: ['type', IoRules],
ioInterceptor: ['type', IoInterceptor],
multiInstancePropertiesProvider: ['type', MultiInstancePropertiesProvider],

View File

@ -1,3 +0,0 @@
{
"extends": "plugin:bpmn-io/mocha"
}

View File

@ -0,0 +1,50 @@
import { bootstrapPropertiesPanel, expectSelected } from './helpers';
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js-properties-panel';
import dataStoreInterceptor from '../../app/spiffworkflow/DataStoreReference';
describe('DataStore Interceptor', () => {
let xml = require('./bpmn/data_store.bpmn').default;
let modeler;
beforeEach(() => {
// Initialize your properties panel and BPMN modeler here
// You'll need to adapt bootstrapPropertiesPanel to return the modeler instance
modeler = bootstrapPropertiesPanel(xml, {
debounceInput: false,
additionalModules: [
dataStoreInterceptor,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
]
});
});
it('should delete dataStore in case dataStoreRef is deleted - DataStoreReference element', async () => {
// Replace inject function with direct async function
// Select a DataStoreReference element
const shapeElement = await expectSelected('DataStoreReference_0eqeh4p');
expect(shapeElement).toBeTruthy(); // Jest assertion
let definitions = modeler.getDefinitions();
let dataStoreExists = definitions.get('rootElements').some(element =>
element.$type === 'bpmn:DataStore' && element.id === 'countries'
);
expect(dataStoreExists).toBe(true); // Jest assertion
// Remove dataStoreReference
modeler.get('modeling').removeShape(shapeElement);
const nwshapeElement = await expectSelected('DataStoreReference_0eqeh4p');
expect(nwshapeElement).toBeFalsy(); // Jest assertion
// Check that DataStore countries is removed from the root of the process
definitions = modeler.getDefinitions();
dataStoreExists = definitions.get('rootElements').some(element =>
element.$type === 'bpmn:DataStore' && element.id === 'countries'
);
expect(dataStoreExists).toBe(false); // Jest assertion
});
// Additional tests...
});

View File

@ -1,29 +0,0 @@
import {
query as domQuery,
queryAll as domQueryAll
} from 'min-dom';
import { bootstrapPropertiesPanel, CONTAINER } from './helpers';
import inputOutput from '../../app/spiffworkflow/InputOutput';
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js-properties-panel';
describe('BPMN Input / Output', function() {
let xml = require('./bpmn/diagram.bpmn').default;
beforeEach(bootstrapPropertiesPanel(xml, {
debounceInput: false,
additionalModules: [
inputOutput,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
]
}));
it('should have a data input and data output in the properties panel', function() {
var paletteElement = domQuery('.djs-palette', CONTAINER);
var entries = domQueryAll('.entry', paletteElement);
expect(entries[11].title).to.equals('Create DataInput');
expect(entries[12].title).to.equals('Create DataOutput');
});
});

View File

@ -1,87 +0,0 @@
import { getBpmnJS } from 'bpmn-js/test/helper';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
import {
bootstrapPropertiesPanel,
changeInput,
expectSelected,
findEntry,
findSelect,
getPropertiesPanel,
} from './helpers';
import extensions from '../../app/spiffworkflow/extensions';
describe('Business Rule Properties Panel', function () {
const xml = require('./bpmn/diagram.bpmn').default;
beforeEach(
bootstrapPropertiesPanel(xml, {
debounceInput: false,
additionalModules: [
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
extensions,
],
moddleExtensions: {
spiffworkflow: spiffModdleExtension,
},
})
);
const return_files = (event) => {
event.eventBus.fire('spiff.dmn_files.returned', {
options: [
{ label: 'Calculate Pizza Price', value: 'Decision_Pizza_Price' },
{ label: 'Viking Availability', value: 'Decision_Vikings' },
{ label: 'Test Decision', value: 'test_decision' },
],
});
}
it('should display a dropdown to select from available decision tables', async function () {
const modeler = getBpmnJS();
modeler.get('eventBus').once('spiff.dmn_files.requested', return_files);
expectSelected('business_rule_task');
// THEN - a properties panel exists with a section for editing that script
const entry = findEntry('extension_spiffworkflow:CalledDecisionId', getPropertiesPanel());
expect(entry, 'No Entry').to.exist;
const selectList = findSelect(entry);
expect(selectList, 'No Select').to.exist;
});
it('should update the spiffworkflow:calledDecisionId tag when you modify the called decision select box', async function () {
// IF - a script tag is selected, and you change the script in the properties panel
const modeler = getBpmnJS();
modeler.get('eventBus').once('spiff.dmn_files.requested', return_files);
const businessRuleTask = await expectSelected('business_rule_task');
const entry = findEntry('extension_CalledDecisionId', getPropertiesPanel());
const selectList = findSelect(entry);
changeInput(selectList, 'Decision_Pizza_Price');
// THEN - the script tag in the BPMN Business object / XML is updated as well.
const businessObject = getBusinessObject(businessRuleTask);
expect(businessObject.extensionElements).to.exist;
const element = businessObject.extensionElements.values[0];
expect(element.value).to.equal('Decision_Pizza_Price');
});
it('should load up the xml and the value for the called decision should match the xml', async function () {
const businessRuleTask = await expectSelected('business_rule_task');
const entry = findEntry('extension_CalledDecisionId', getPropertiesPanel());
const selectList = findSelect(entry);
expect(selectList.value, "initial value is wrong").to.equal('test_decision');
// THEN - the script tag in the BPMN Business object / XML is updated as well.
const businessObject = getBusinessObject(businessRuleTask);
expect(businessObject.extensionElements).to.exist;
const element = businessObject.extensionElements.values[0];
expect(element.value).to.equal('test_decision');
});
});

View File

@ -1,112 +0,0 @@
import TestContainer from 'mocha-test-container-support';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import { query as domQuery } from 'min-dom';
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
import { inject } from 'bpmn-js/test/helper';
import {
bootstrapPropertiesPanel,
changeInput,
expectSelected,
findButton,
findGroupEntry,
pressButton,
} from './helpers';
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
import callActivity from '../../app/spiffworkflow/callActivity';
describe('Call Activities should work', function () {
const xml = require('./bpmn/call_activity.bpmn').default;
let container;
beforeEach(function () {
container = TestContainer.get(this);
});
beforeEach(
bootstrapPropertiesPanel(xml, {
container,
debounceInput: false,
additionalModules: [
callActivity,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
],
moddleExtensions: {
spiffworkflow: spiffModdleExtension,
},
})
);
it('should allow you to view the called element section of a Call Activity', async function () {
const shapeElement = await expectSelected('the_call_activity');
expect(shapeElement, "Can't find Call Activity").to.exist;
const entry = findGroupEntry('called_element', container);
expect(entry).to.exist;
});
it('should allow you to edit the called element section of a Call Activity', async function () {
const shapeElement = await expectSelected('the_call_activity');
expect(shapeElement, "Can't find Call Activity").to.exist;
const businessObject = getBusinessObject(shapeElement);
expect(businessObject.get('calledElement')).to.equal('ProcessIdTBD1');
const entry = findGroupEntry('called_element', container);
expect(entry).to.exist;
const textInput = domQuery('input', entry);
changeInput(textInput, 'newProcessId');
expect(businessObject.get('calledElement')).to.equal('newProcessId');
});
it('should issue an event to the event bus if user clicks the edit button', inject(async function (
eventBus
) {
const shapeElement = await expectSelected('the_call_activity');
expect(shapeElement, "Can't find Call Activity").to.exist;
const businessObject = getBusinessObject(shapeElement);
expect(businessObject.get('calledElement')).to.equal('ProcessIdTBD1');
const entry = findGroupEntry('called_element', container);
const button = findButton('spiffworkflow-open-call-activity-button', entry);
expect(button).to.exist;
let launchEvent;
eventBus.on('spiff.callactivity.edit', function (event) {
launchEvent = event;
});
await pressButton(button);
expect(launchEvent.processId).to.exist;
}));
it('should issue an event to the event bus if user clicks the search button', inject(async function (
eventBus
) {
const shapeElement = await expectSelected('the_call_activity');
expect(shapeElement, "Can't find Call Activity").to.exist;
const businessObject = getBusinessObject(shapeElement);
expect(businessObject.get('calledElement')).to.equal('ProcessIdTBD1');
const entry = findGroupEntry('called_element', container);
const button = findButton(
'spiffworkflow-search-call-activity-button',
entry
);
expect(button).to.exist;
let launchEvent;
eventBus.on('spiff.callactivity.search', function (event) {
launchEvent = event;
});
await pressButton(button);
expect(launchEvent.processId).to.exist;
expect(launchEvent.element).to.exist;
eventBus.fire('spiff.callactivity.update', {value: 'searchedProcessId', element: launchEvent.element});
const textInput = domQuery('input', entry);
expect(businessObject.get('calledElement')).to.equal('searchedProcessId');
}));
});

View File

@ -1,40 +0,0 @@
import {
query as domQuery,
queryAll as domQueryAll
} from 'min-dom';
import {
bootstrapPropertiesPanel,
expectSelected,
findGroupEntry,
changeInput,
PROPERTIES_PANEL_CONTAINER,
} from './helpers';
import conditionsPanel from '../../app/spiffworkflow/conditions';
import { BpmnPropertiesPanelModule, BpmnPropertiesProviderModule } from 'bpmn-js-properties-panel';
import { getBusinessObject } from 'bpmn-js/lib/util/ModelUtil';
describe('BPMN Condition', function() {
let xml = require('./bpmn/conditional_event.bpmn').default;
beforeEach(bootstrapPropertiesPanel(xml, {
debounceInput: false,
additionalModules: [
conditionsPanel,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
]
}));
it('should add a condition panel when Conditional Event is selected', async function() {
const shapeElement = await expectSelected('conditional_event');
const businessObject = getBusinessObject(shapeElement);
const conditions = findGroupEntry('conditions', PROPERTIES_PANEL_CONTAINER);
expect(conditions).to.exist;
const textInput = domQuery('textarea', conditions);
expect(textInput.value).to.equal('cancel_task_2');
changeInput(textInput, 'True');
});
});

View File

@ -1,66 +0,0 @@
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import TestContainer from 'mocha-test-container-support';
import {
bootstrapPropertiesPanel,
changeInput,
expectSelected,
findEntry,
findSelect,
} from './helpers';
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
import DataObject from '../../app/spiffworkflow/DataObject';
describe('Properties Panel for Data Objects', function () {
const xml = require('./bpmn/data_objects_in_pools.bpmn').default;
let container;
beforeEach(function () {
container = TestContainer.get(this);
});
beforeEach(
bootstrapPropertiesPanel(xml, {
container,
debounceInput: false,
additionalModules: [
DataObject,
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
],
moddleExtensions: {
spiffworkflow: spiffModdleExtension,
},
})
);
it('should allow you to select other data objects within the same participant', async function () {
// IF - a data object reference is selected
const doREF = await expectSelected('pool1Do1_REF');
expect(doREF).to.exist;
// THEN - a select Data Object section should appear in the properties panel
const entry = findEntry('selectDataObject', container);
const selector = findSelect(entry);
changeInput(selector, 'pool1Do2');
// then this data reference object now references that data object.
const { businessObject } = doREF;
expect(businessObject.get('dataObjectRef').id).to.equal('pool1Do2');
});
it('should NOT allow you to select data objects within other participants', async function () {
// IF - a data object reference is selected
const doREF = await expectSelected('pool1Do1_REF');
expect(doREF).to.exist;
// THEN - a select Data Object section should appear in the properties panel but pool2Do1 should not be an option
const entry = findEntry('selectDataObject', container);
const selector = findSelect(entry);
expect(selector.length).to.equal(2);
expect(selector[0].value === 'pool1Do2');
expect(selector[1].value === 'pool1Do1');
});
});

Some files were not shown because too many files have changed in this diff Show More