Adds example code from bpmn-js-example-angular-properties-panel
This commit is contained in:
parent
94dcd9788e
commit
169f7bb291
|
@ -1,46 +1,305 @@
|
|||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Created by https://www.gitignore.io/api/node,angular,eclipse,intellij,visualstudiocode
|
||||
# Edit at https://www.gitignore.io/?templates=node,angular,eclipse,intellij,visualstudiocode
|
||||
|
||||
### Angular ###
|
||||
## Angular ##
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
dist/
|
||||
tmp/
|
||||
app/**/*.js
|
||||
app/**/*.js.map
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
node_modules/
|
||||
bower_components/
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.idea/
|
||||
|
||||
# IDE - VSCode
|
||||
# misc
|
||||
.sass-cache/
|
||||
connect.lock/
|
||||
coverage/
|
||||
libpeerconnection.log/
|
||||
npm-debug.log
|
||||
testem.log
|
||||
typings/
|
||||
|
||||
# e2e
|
||||
e2e/*.js
|
||||
e2e/*.map
|
||||
|
||||
#System Files
|
||||
.DS_Store/
|
||||
|
||||
### Eclipse ###
|
||||
.metadata
|
||||
bin/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# PyDev specific (Python IDE for Eclipse)
|
||||
*.pydevproject
|
||||
|
||||
# CDT-specific (C/C++ Development Tooling)
|
||||
.cproject
|
||||
|
||||
# CDT- autotools
|
||||
.autotools
|
||||
|
||||
# Java annotation processor (APT)
|
||||
.factorypath
|
||||
|
||||
# PDT-specific (PHP Development Tools)
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# Tern plugin
|
||||
.tern-project
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
# STS (Spring Tool Suite)
|
||||
.springBeans
|
||||
|
||||
# Code Recommenders
|
||||
.recommenders/
|
||||
|
||||
# Annotation Processing
|
||||
.apt_generated/
|
||||
|
||||
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||
.cache-main
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
### Eclipse Patch ###
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# Annotation Processing
|
||||
.apt_generated
|
||||
|
||||
.sts4-cache/
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# rollup.js default build output
|
||||
|
||||
# Uncomment the public line if your project uses Gatsby
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# https://create-react-app.dev/docs/using-the-public-folder/#docsNav
|
||||
# public
|
||||
|
||||
# Storybook build outputs
|
||||
.out
|
||||
.storybook-out
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Temporary folders
|
||||
temp/
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
# End of https://www.gitignore.io/api/node,angular,eclipse,intellij,visualstudiocode
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# CrConnectBpmn
|
||||
# BpmnJsAngular
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.15.
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.1.1.
|
||||
|
||||
## Development server
|
||||
|
||||
|
|
85
angular.json
85
angular.json
|
@ -3,32 +3,30 @@
|
|||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"cr-connect-bpmn": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"bpmn-js-angular": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/cr-connect-bpmn",
|
||||
"outputPath": "dist/bpmn-js-angular",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": false,
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"node_modules/bpmn-js/dist/assets/diagram-js.css",
|
||||
"node_modules/bpmn-js/dist/assets/bpmn-font/css/bpmn.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
|
@ -54,11 +52,6 @@
|
|||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -67,18 +60,18 @@
|
|||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "cr-connect-bpmn:build"
|
||||
"browserTarget": "bpmn-js-angular:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "cr-connect-bpmn:build:production"
|
||||
"browserTarget": "bpmn-js-angular:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "cr-connect-bpmn:build"
|
||||
"browserTarget": "bpmn-js-angular:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
|
@ -86,44 +79,72 @@
|
|||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
"codeCoverageExclude": [
|
||||
"src/testing/mocks/*.ts",
|
||||
"src/app/_interfaces/*.ts",
|
||||
"src/polyfills.ts",
|
||||
"src/test.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bpmn-js-angular-e2e": {
|
||||
"root": "e2e/",
|
||||
"projectType": "application",
|
||||
"prefix": "",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "cr-connect-bpmn:serve"
|
||||
"devServerTarget": "bpmn-js-angular:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "cr-connect-bpmn:serve:production"
|
||||
"devServerTarget": "bpmn-js-angular:serve:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
"defaultProject": "cr-connect-bpmn"
|
||||
},
|
||||
"defaultProject": "bpmn-js-angular",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
#
|
||||
# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
||||
not IE 9-11
|
|
@ -1,19 +1,20 @@
|
|||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
'browserName': 'chrome',
|
||||
'chromeOptions': {
|
||||
'args': [
|
||||
'--headless'
|
||||
]
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
|
@ -25,7 +26,7 @@ exports.config = {
|
|||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
@ -8,16 +7,9 @@ describe('workspace-project App', () => {
|
|||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
it('should display diagram', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('cr-connect-bpmn app is running!');
|
||||
expect(page.getDiagramContainer()).toBeTruthy();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,10 +2,10 @@ import { browser, by, element } from 'protractor';
|
|||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get(browser.baseUrl) as Promise<any>;
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||
getDiagramContainer() {
|
||||
return element(by.css('app-root .diagram-container'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
|
@ -2,8 +2,13 @@
|
|||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
|
||||
if (config.browsers.indexOf('ChromeHeadlessCI') !== -1) {
|
||||
process.env.CHROME_BIN = require('puppeteer').executablePath();
|
||||
}
|
||||
|
||||
config.set({
|
||||
basePath: '',
|
||||
basePath: 'src',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
|
@ -16,17 +21,22 @@ module.exports = function (config) {
|
|||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/cr-connect-bpmn'),
|
||||
dir: require('path').join(__dirname, './coverage'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
customLaunchers: {
|
||||
ChromeHeadlessCI: {
|
||||
base: 'ChromeHeadless',
|
||||
flags: ['--no-sandbox', '--disable-gpu' ]
|
||||
}
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
63
package.json
63
package.json
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "cr-connect-bpmn",
|
||||
"name": "bpmn-js-angular",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
|
@ -7,44 +7,53 @@
|
|||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
"e2e": "./node_modules/protractor/bin/webdriver-manager update && ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~8.2.12",
|
||||
"@angular/common": "~8.2.12",
|
||||
"@angular/compiler": "~8.2.12",
|
||||
"@angular/core": "~8.2.12",
|
||||
"@angular/forms": "~8.2.12",
|
||||
"@angular/platform-browser": "~8.2.12",
|
||||
"@angular/platform-browser-dynamic": "~8.2.12",
|
||||
"@angular/router": "~8.2.12",
|
||||
"bpmn-js": "^6.1.1",
|
||||
"@angular/animations": "^8.2.14",
|
||||
"@angular/cdk": "^8.2.3",
|
||||
"@angular/common": "^8.2.14",
|
||||
"@angular/compiler": "^8.2.14",
|
||||
"@angular/core": "^8.2.14",
|
||||
"@angular/flex-layout": "^8.0.0-beta.27",
|
||||
"@angular/forms": "^8.2.14",
|
||||
"@angular/material": "^8.2.3",
|
||||
"@angular/platform-browser": "^8.2.14",
|
||||
"@angular/platform-browser-dynamic": "^8.2.14",
|
||||
"@angular/router": "^8.2.14",
|
||||
"bpmn-js": "^3.5.0",
|
||||
"bpmn-js-properties-panel": "^0.33.1",
|
||||
"camunda-bpmn-moddle": "^4.3.0",
|
||||
"rxjs": "~6.4.0",
|
||||
"core-js": "^2.6.11",
|
||||
"diagram-js-minimap": "^2.0.3",
|
||||
"file-saver": "^2.0.2",
|
||||
"hammerjs": "^2.0.8",
|
||||
"rxjs": "~6.5.4",
|
||||
"tslib": "^1.10.0",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.803.15",
|
||||
"@angular/cli": "~8.3.15",
|
||||
"@angular/compiler-cli": "~8.2.12",
|
||||
"@angular/language-service": "~8.2.12",
|
||||
"@angular-devkit/build-angular": "^0.803.22",
|
||||
"@angular/cli": "^8.3.22",
|
||||
"@angular/compiler-cli": "^8.2.14",
|
||||
"@angular/language-service": "^8.2.14",
|
||||
"@types/jasmine": "^3.5.0",
|
||||
"@types/jasminewd2": "^2.0.8",
|
||||
"@types/node": "~8.9.4",
|
||||
"@types/jasmine": "~3.3.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"codelyzer": "^5.0.0",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"codelyzer": "^5.0.1",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.1.0",
|
||||
"karma": "^3.1.4",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.0",
|
||||
"protractor": "~5.4.0",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||
"karma-jasmine": "~1.1.2",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "^5.4.2",
|
||||
"puppeteer": "^1.20.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.15.0",
|
||||
"typescript": "~3.5.3"
|
||||
"tslint": "~5.11.0",
|
||||
"typescript": "~3.5.3",
|
||||
"webpack-dev-server": "^3.10.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export interface BpmnWarning {
|
||||
message?: string;
|
||||
element?: any;
|
||||
property?: string;
|
||||
value?: string;
|
||||
context?: any;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import {HttpErrorResponse} from '@angular/common/http';
|
||||
import {BpmnWarning} from './bpmn-warning';
|
||||
|
||||
export interface ImportEvent {
|
||||
type: string;
|
||||
warnings?: BpmnWarning[];
|
||||
error?: HttpErrorResponse | Error;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ApiService} from './api.service';
|
||||
|
||||
describe('ApiService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
providers: [ApiService]
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const httpMock = TestBed.get(HttpTestingController);
|
||||
httpMock.verify();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
const service: ApiService = TestBed.get(ApiService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
import {HttpClient} from '@angular/common/http';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable, throwError} from 'rxjs';
|
||||
import {catchError} from 'rxjs/operators';
|
||||
|
||||
export interface ApiError {
|
||||
code: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ApiService {
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
getBpmnXml(url: string): Observable<string> {
|
||||
return this.httpClient
|
||||
.get(url, {responseType: 'text'})
|
||||
.pipe(catchError(this._handleError));
|
||||
}
|
||||
|
||||
private _handleError(error: ApiError) {
|
||||
return throwError(error.message || 'Could not complete your request; please try again later.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
|
||||
const routes: Routes = [];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
|
@ -1,49 +1,57 @@
|
|||
<h1>Add bpmn-js to Angular</h1>
|
||||
<mat-toolbar [ngClass]="{'expanded': expandToolbar}">
|
||||
<mat-toolbar-row>
|
||||
<button mat-button (click)="diagram.createNewDiagram()" title="Create new BPMN diagram"><mat-icon>insert_drive_file</mat-icon></button>
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean a tincidunt dolor. Nam semper est ut mauris cursus,
|
||||
vel laoreet nunc vehicula. Mauris nec semper ipsum. Integer feugiat mi at elementum fringilla. Nunc malesuada ante sed
|
||||
ligula pretium, eu lobortis lorem rhoncus. Praesent et ipsum ante. Aliquam est mi, ultrices ut neque eget, mollis
|
||||
pulvinar sem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam
|
||||
auctor porta sapien in venenatis.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In fringilla suscipit odio quis tincidunt. Morbi felis elit, blandit a volutpat eget, rutrum ut mi. Duis ac orci at
|
||||
nibh semper vehicula. Quisque vulputate, nibh vitae laoreet convallis, urna erat imperdiet eros, et interdum arcu arcu
|
||||
ac risus. Maecenas in tellus nisi. Mauris quis lectus luctus, condimentum orci eu, rhoncus sapien. Aliquam at lobortis
|
||||
mauris, eget facilisis arcu. Quisque metus purus, rhoncus et tortor id, ornare maximus neque. Donec et ex tincidunt,
|
||||
malesuada lacus in, volutpat eros. Cras nisi arcu, dapibus quis odio sit amet, placerat blandit elit. Nullam at dictum
|
||||
mauris. Nulla feugiat elit ex, a pulvinar velit faucibus a. Nulla tincidunt velit purus, in faucibus ligula ornare
|
||||
venenatis.
|
||||
</p>
|
||||
<button mat-button [matMenuTriggerFor]="importMenu" title="Open diagram">
|
||||
<mat-icon>folder</mat-icon>
|
||||
<mat-icon>arrow_drop_down</mat-icon>
|
||||
</button>
|
||||
<mat-menu #importMenu="matMenu">
|
||||
<button mat-menu-item (click)="openMethod = 'file'; expandToolbar = true">
|
||||
<mat-icon>code</mat-icon>
|
||||
Open from XML File
|
||||
</button>
|
||||
<button mat-menu-item (click)="openMethod = 'url'; expandToolbar = true">
|
||||
<mat-icon>link</mat-icon>
|
||||
Open from URL
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<button mat-button [matMenuTriggerFor]="downloadMenu" title="Download diagram">
|
||||
<mat-icon>save</mat-icon>
|
||||
<mat-icon>arrow_drop_down</mat-icon>
|
||||
</button>
|
||||
<mat-menu #downloadMenu="matMenu">
|
||||
<button mat-menu-item (click)="diagram.saveSVG()"><mat-icon>image</mat-icon> Download SVG Image</button>
|
||||
<button mat-menu-item (click)="diagram.saveXML()"><mat-icon>code</mat-icon> Download XML File</button>
|
||||
</mat-menu>
|
||||
</mat-toolbar-row>
|
||||
<mat-toolbar-row *ngIf="expandToolbar">
|
||||
<ng-container *ngIf="openMethod === 'file'">
|
||||
<mat-form-field (click)="fileInput.click()">
|
||||
<input matInput disabled [value]="getFileName()" type="text">
|
||||
<mat-icon matSuffix>folder_open</mat-icon>
|
||||
</mat-form-field>
|
||||
<input hidden (change)="onFileSelected($event)" #fileInput type="file" id="file" accept="text/xml">
|
||||
</ng-container>
|
||||
<ng-container *ngIf="openMethod === 'url'">
|
||||
<mat-form-field>
|
||||
<input name="diagramUrl" [(ngModel)]="diagramUrl" matInput placeholder="Open diagram from URL" type="text">
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
<button mat-icon-button (click)="onSubmit($event)"><mat-icon>arrow_forward</mat-icon></button>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button (click)="expandToolbar = false"><mat-icon>close</mat-icon></button>
|
||||
</mat-toolbar-row>
|
||||
</mat-toolbar>
|
||||
<div fxLayout="column">
|
||||
<div class="diagram-parent">
|
||||
<app-diagram (importDone)="handleImported($event)" [url]="diagramUrl"></app-diagram>
|
||||
<app-diagram #diagram (importDone)="handleImported($event)"></app-diagram>
|
||||
|
||||
<div *ngIf="importError" class="import-error">
|
||||
<strong>Failed to render diagram: </strong>
|
||||
{{ importError.message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Ut vestibulum, magna at molestie tempus, enim sem molestie est, vel tincidunt orci leo vel sapien. Vivamus convallis,
|
||||
purus in rhoncus ultricies, mauris sapien condimentum sapien, vel porta urna est eu leo. Nam dui erat, venenatis at
|
||||
metus ut, rutrum rutrum lacus. Fusce non eros vehicula, aliquet nibh vitae, bibendum dolor. Sed hendrerit lectus ex.
|
||||
Mauris id venenatis metus. In hac habitasse platea dictumst.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Etiam molestie, erat eget tincidunt rutrum, nulla odio pulvinar nibh, in pulvinar felis mauris a nunc. Sed eu
|
||||
ullamcorper ex, id tincidunt metus. Quisque lectus enim, vehicula eget aliquam sit amet, semper ut nisl. Vivamus
|
||||
ultrices, cras odio massa, sagittis in luctus sed, mattis eu massa. Nam erat nibh, pulvinar vel hendrerit quis,
|
||||
ultricies eu sapien. Integer fringilla sapien ex, et posuere arcu euismod et.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Suspendisse potenti. In ut lorem vitae dolor molestie commodo. Vivamus mattis gravida metus, porttitor ornare augue
|
||||
lacinia suscipit. Duis condimentum fringilla nisl, non consequat odio mollis id. Nulla tincidunt interdum elit, sed
|
||||
tristique ex laoreet lobortis. Suspendisse in felis vitae magna convallis semper. Nullam odio risus, venenatis eget
|
||||
erat ac, pretium aliquet urna. Duis luctus lobortis maximus.
|
||||
</p>
|
||||
|
|
|
@ -1,14 +1,30 @@
|
|||
.diagram-parent {
|
||||
height: 400px;
|
||||
border: solid 3px #EEE;
|
||||
height: 90vh;
|
||||
position: relative;
|
||||
border-top: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.import-error {
|
||||
color: red;
|
||||
padding: 20px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
mat-form-field {
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
mat-toolbar {
|
||||
transition: all 200ms ease-in-out;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
mat-toolbar.expanded {
|
||||
height: 128px;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,163 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import {HttpErrorResponse} from '@angular/common/http';
|
||||
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||
import {DebugNode} from '@angular/core';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {MatMenuModule} from '@angular/material/menu';
|
||||
import {MatToolbarModule} from '@angular/material/toolbar';
|
||||
import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {BPMN_DIAGRAM, BPMN_DIAGRAM_WITH_WARNINGS} from '../testing/mocks/diagram.mocks';
|
||||
import {BpmnWarning} from './_interfaces/bpmn-warning';
|
||||
import {AppComponent} from './app.component';
|
||||
import {DiagramComponent} from './diagram/diagram.component';
|
||||
|
||||
|
||||
describe('AppComponent', () => {
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
let component: DebugNode['componentInstance'];
|
||||
let httpMock: HttpTestingController;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
AppComponent,
|
||||
DiagramComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
NoopAnimationsModule,
|
||||
FormsModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatMenuModule,
|
||||
MatToolbarModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
HttpClientTestingModule,
|
||||
]
|
||||
}).compileComponents();
|
||||
httpMock = TestBed.get(HttpTestingController);
|
||||
fixture = TestBed.createComponent(AppComponent);
|
||||
component = fixture.debugElement.componentInstance;
|
||||
component.diagramComponent = TestBed.createComponent(DiagramComponent).componentInstance;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'cr-connect-bpmn'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('cr-connect-bpmn');
|
||||
|
||||
it('renders a diagram component', () => {
|
||||
expect(fixture.nativeElement.querySelector('app-diagram')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain('cr-connect-bpmn app is running!');
|
||||
|
||||
it('sets an error message', () => {
|
||||
const error = new HttpErrorResponse({error: 'ERROR'});
|
||||
|
||||
component.handleImported({
|
||||
type: 'error',
|
||||
error
|
||||
});
|
||||
|
||||
expect(component.importError).toEqual(error);
|
||||
});
|
||||
|
||||
it('sets warning messages', () => {
|
||||
const warnings: BpmnWarning[] = [{
|
||||
message: 'WARNING'
|
||||
}];
|
||||
|
||||
component.handleImported({
|
||||
type: 'success',
|
||||
error: null,
|
||||
warnings: warnings,
|
||||
});
|
||||
|
||||
expect(component.importWarnings).toEqual(warnings);
|
||||
});
|
||||
|
||||
it('loads a diagram from URL', () => {
|
||||
component.diagramUrl = 'some-url';
|
||||
component.openMethod = 'url';
|
||||
const event = new MouseEvent('click');
|
||||
component['onSubmit'](event);
|
||||
|
||||
const sReq = httpMock.expectOne(component.diagramUrl);
|
||||
expect(sReq.request.method).toEqual('GET');
|
||||
sReq.flush(BPMN_DIAGRAM);
|
||||
});
|
||||
|
||||
it('loads a diagram from URL with warnings', () => {
|
||||
component.diagramUrl = 'some-url';
|
||||
component.openMethod = 'url';
|
||||
const event = new MouseEvent('click');
|
||||
component['onSubmit'](event);
|
||||
|
||||
const sReq = httpMock.expectOne(component.diagramUrl);
|
||||
expect(sReq.request.method).toEqual('GET');
|
||||
sReq.flush(BPMN_DIAGRAM_WITH_WARNINGS);
|
||||
});
|
||||
|
||||
it('loads a diagram from File', () => {
|
||||
const readFileSpy = spyOn(component, 'readFile').and.stub();
|
||||
const newFile = new File([BPMN_DIAGRAM], 'filename.xml', {type: 'text/xml'});
|
||||
component.diagramFile = newFile;
|
||||
component.openMethod = 'file';
|
||||
const event = new MouseEvent('click');
|
||||
component['onSubmit'](event);
|
||||
expect(readFileSpy).toHaveBeenCalledWith(newFile);
|
||||
});
|
||||
|
||||
it('opens a diagram from File', () => {
|
||||
const mockFileReader = {
|
||||
target: {result: BPMN_DIAGRAM},
|
||||
readAsText: (blob) => {
|
||||
}
|
||||
};
|
||||
spyOn((window as any), 'FileReader').and.returnValue(mockFileReader);
|
||||
spyOn(mockFileReader, 'readAsText').and.callFake((blob) => {
|
||||
component.onLoad({target: {result: BPMN_DIAGRAM}});
|
||||
});
|
||||
const openDiagramSpy = spyOn(component.diagramComponent, 'openDiagram').and.stub();
|
||||
const newFile = new File([BPMN_DIAGRAM], 'filename.xml', {type: 'text/xml'});
|
||||
component.readFile(newFile);
|
||||
expect(openDiagramSpy).toHaveBeenCalledWith(BPMN_DIAGRAM);
|
||||
});
|
||||
|
||||
it('loads a diagram from File with error', () => {
|
||||
const handleImportedSpy = spyOn(component, 'handleImported').and.stub();
|
||||
|
||||
component.diagramFile = new File([], 'filename.jpg', {type: 'image/jpeg'});
|
||||
component.openMethod = 'file';
|
||||
const event = new MouseEvent('click');
|
||||
component['onSubmit'](event);
|
||||
const expectedParams = {
|
||||
type: 'error',
|
||||
error: new Error('Wrong file type. Please choose a BPMN XML file.')
|
||||
};
|
||||
expect(handleImportedSpy).toHaveBeenCalledWith(expectedParams);
|
||||
});
|
||||
|
||||
it('should get the diagram file name', () => {
|
||||
expect(component.getFileName()).toEqual('No file selected');
|
||||
|
||||
const filename = 'expected_file_name.jpg';
|
||||
component.diagramFile = new File([], filename, {type: 'image/jpeg'});
|
||||
expect(component.getFileName()).toEqual(filename);
|
||||
});
|
||||
|
||||
it('should get the diagram file from the file input form control', () => {
|
||||
const expectedFile = new File([], 'filename.jpg', {type: 'image/jpeg'});
|
||||
const event = {target: {files: [expectedFile]}};
|
||||
component['onFileSelected'](event);
|
||||
expect(component.diagramFile).toEqual(expectedFile);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {BPMN_DIAGRAM} from '../testing/mocks/diagram.mocks';
|
||||
import {BpmnWarning} from './_interfaces/bpmn-warning';
|
||||
import {ImportEvent} from './_interfaces/import-event';
|
||||
import {DiagramComponent} from './diagram/diagram.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -9,9 +13,18 @@ export class AppComponent {
|
|||
title = 'bpmn-js-angular';
|
||||
diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
|
||||
importError?: Error;
|
||||
importWarnings?: BpmnWarning[];
|
||||
xmlModel: any;
|
||||
expandToolbar = false;
|
||||
openMethod: string;
|
||||
diagramFile: File;
|
||||
@ViewChild(DiagramComponent, {static: false}) private diagramComponent: DiagramComponent;
|
||||
|
||||
handleImported(event) {
|
||||
constructor() {
|
||||
this.xmlModel = BPMN_DIAGRAM;
|
||||
}
|
||||
|
||||
handleImported(event: ImportEvent) {
|
||||
const {
|
||||
type,
|
||||
error,
|
||||
|
@ -19,7 +32,7 @@ export class AppComponent {
|
|||
} = event;
|
||||
|
||||
if (type === 'success') {
|
||||
console.log(`Rendered diagram (%s warnings)`, warnings.length);
|
||||
console.log(`Rendered diagram (${warnings.length} warnings)`);
|
||||
}
|
||||
|
||||
if (type === 'error') {
|
||||
|
@ -27,6 +40,49 @@ export class AppComponent {
|
|||
}
|
||||
|
||||
this.importError = error;
|
||||
this.importWarnings = warnings;
|
||||
|
||||
// Clear the inputs
|
||||
this.diagramFile = undefined;
|
||||
this.diagramUrl = undefined;
|
||||
}
|
||||
|
||||
onSubmit($event: MouseEvent) {
|
||||
this.expandToolbar = false;
|
||||
|
||||
if (this.openMethod === 'url') {
|
||||
this.diagramComponent.loadUrl(this.diagramUrl);
|
||||
} else if (this.openMethod === 'file') {
|
||||
if (this.diagramFile && this.diagramFile.type === 'text/xml') {
|
||||
this.readFile(this.diagramFile);
|
||||
} else {
|
||||
this.handleImported({
|
||||
type: 'error',
|
||||
error: new Error('Wrong file type. Please choose a BPMN XML file.')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.openMethod = undefined;
|
||||
}
|
||||
|
||||
getFileName() {
|
||||
return this.diagramFile ? this.diagramFile.name : 'No file selected';
|
||||
}
|
||||
|
||||
onFileSelected($event: Event) {
|
||||
this.diagramFile = ($event.target as HTMLFormElement).files[0];
|
||||
}
|
||||
|
||||
onLoad(event: ProgressEvent) {
|
||||
const xml = (event.target as FileReader).result;
|
||||
this.diagramComponent.openDiagram(xml.toString());
|
||||
}
|
||||
|
||||
readFile(file: File) {
|
||||
// FileReader must be instantiated this way so unit test can spy on it.
|
||||
const fileReader = new (window as any).FileReader();
|
||||
fileReader.onload = this.onLoad;
|
||||
fileReader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import {HttpClientModule} from '@angular/common/http';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {MatMenuModule} from '@angular/material/menu';
|
||||
import {MatTabsModule} from '@angular/material/tabs';
|
||||
import {MatToolbarModule} from '@angular/material/toolbar';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {AppComponent} from './app.component';
|
||||
import {DiagramComponent} from './diagram/diagram.component';
|
||||
|
||||
|
@ -12,11 +19,20 @@ import { DiagramComponent } from './diagram/diagram.component';
|
|||
DiagramComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
HttpClientModule
|
||||
FlexLayoutModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatMenuModule,
|
||||
MatTabsModule,
|
||||
MatToolbarModule,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
export class AppModule {
|
||||
}
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
<div #ref class="diagram-container"></div>
|
||||
<div fxLayout="row" class="modeler-wrapper">
|
||||
<div fxFlex="75%" class="diagram-container" #containerRef></div>
|
||||
<div fxFlex="25%" class="properties-container" #propertiesRef></div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
.diagram-container {
|
||||
.modeler-wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
::ng-deep .djs-minimap:not(.open) .toggle:before {
|
||||
font-family: 'Material Icons';
|
||||
content: "map";
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
::ng-deep .djs-minimap.open .toggle:before {
|
||||
font-family: 'Material Icons';
|
||||
content: "close";
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,193 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||
|
||||
import {DebugNode} from '@angular/core';
|
||||
import {async, ComponentFixture, getTestBed, TestBed} from '@angular/core/testing';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import {BPMN_DIAGRAM, BPMN_DIAGRAM_WITH_WARNINGS} from '../../testing/mocks/diagram.mocks';
|
||||
import {ApiService} from '../_services/api.service';
|
||||
|
||||
import {DiagramComponent} from './diagram.component';
|
||||
|
||||
describe('DiagramComponent', () => {
|
||||
let component: DiagramComponent;
|
||||
|
||||
let httpMock: HttpTestingController;
|
||||
let fixture: ComponentFixture<DiagramComponent>;
|
||||
let component: DebugNode['componentInstance'];
|
||||
|
||||
const injector: TestBed = getTestBed();
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ DiagramComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
MatIconModule,
|
||||
],
|
||||
declarations: [DiagramComponent],
|
||||
providers: [ApiService]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(DiagramComponent);
|
||||
component = fixture.debugElement.componentInstance;
|
||||
httpMock = injector.get(HttpTestingController);
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DiagramComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
afterEach(() => {
|
||||
httpMock.verify();
|
||||
fixture.destroy();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
|
||||
it('should create and tear down', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it('should load and render successfully', (done) => {
|
||||
|
||||
// given
|
||||
const diagramURL = 'some-url';
|
||||
|
||||
component.importDone.subscribe(result => {
|
||||
|
||||
// then
|
||||
expect(result).toEqual({
|
||||
type: 'success',
|
||||
warnings: []
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
// when
|
||||
component.loadUrl(diagramURL);
|
||||
|
||||
const request = httpMock.expectOne({url: diagramURL, method: 'GET'});
|
||||
|
||||
request.flush(BPMN_DIAGRAM);
|
||||
});
|
||||
|
||||
|
||||
it('should expose import warnings', (done) => {
|
||||
|
||||
// given
|
||||
const diagramURL = 'some-url';
|
||||
|
||||
component.importDone.subscribe(result => {
|
||||
// then
|
||||
expect(result.type).toEqual('success');
|
||||
|
||||
expect(result.warnings.length).toEqual(1);
|
||||
expect(result.warnings[0].message).toContain('unparsable content <process> detected');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
// when
|
||||
component.loadUrl(diagramURL);
|
||||
|
||||
const request = httpMock.expectOne({url: diagramURL, method: 'GET'});
|
||||
|
||||
request.flush(BPMN_DIAGRAM_WITH_WARNINGS);
|
||||
});
|
||||
|
||||
|
||||
it('should fail to load and render', (done) => {
|
||||
|
||||
// given
|
||||
const diagramURL = 'some-url';
|
||||
|
||||
// when
|
||||
component.loadUrl(diagramURL);
|
||||
|
||||
component.importDone.subscribe(result => {
|
||||
|
||||
// then
|
||||
expect(result.type).toEqual('error');
|
||||
expect(result.error).toEqual('Http failure response for some-url: 404 FOO');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
const request = httpMock.expectOne({url: diagramURL, method: 'GET'});
|
||||
|
||||
request.flush('Not Found', {
|
||||
status: 404,
|
||||
statusText: 'FOO'
|
||||
});
|
||||
});
|
||||
|
||||
it('should save diagram as SVG', () => {
|
||||
const fileSaverSpy = spyOn(FileSaver, 'saveAs').and.stub();
|
||||
component.saveSVG();
|
||||
expect(fileSaverSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should save diagram as XML', () => {
|
||||
const fileSaverSpy = spyOn(FileSaver, 'saveAs').and.stub();
|
||||
component.saveXML();
|
||||
expect(fileSaverSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should create a new diagram', () => {
|
||||
const importXMLSpy = spyOn(component.modeler, 'importXML').and.stub();
|
||||
component.createNewDiagram();
|
||||
expect(importXMLSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should open an existing diagram from XML', () => {
|
||||
const importXMLSpy = spyOn(component.modeler, 'importXML').and.stub();
|
||||
component.openDiagram(BPMN_DIAGRAM);
|
||||
expect(importXMLSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fail to open diagram', (done) => {
|
||||
component.openDiagram('INVALID BPMN XML');
|
||||
component.importDone.subscribe(result => {
|
||||
expect(result.type).toEqual('error');
|
||||
expect(result.error.message).toContain('unparsable content INVALID BPMN XML detected');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should edit diagram', () => {
|
||||
const importXMLSpy = spyOn(component.modeler, 'importXML').and.stub();
|
||||
const createDiagramSpy = spyOn(component.modeler, 'createDiagram').and.stub();
|
||||
component.createNewDiagram();
|
||||
expect(createDiagramSpy).toHaveBeenCalled();
|
||||
|
||||
component.writeValue(BPMN_DIAGRAM);
|
||||
expect(importXMLSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should register onChange function', () => {
|
||||
const fn = (s: string) => s.toLowerCase().trim();
|
||||
const input = ' TRIMMED AND LOWERCASED ';
|
||||
|
||||
component.registerOnChange(fn);
|
||||
expect(component.onChange).toEqual(fn);
|
||||
|
||||
const result = component.onChange(input);
|
||||
expect(result).toEqual('trimmed and lowercased');
|
||||
});
|
||||
|
||||
it('should register onTouched function', () => {
|
||||
const fn = () => 123456;
|
||||
|
||||
component.registerOnTouched(fn);
|
||||
expect(component.onTouched).toEqual(fn);
|
||||
|
||||
const result = component.onTouched();
|
||||
expect(result).toEqual(123456);
|
||||
});
|
||||
|
||||
it('should set disabled state', () => {
|
||||
component.setDisabledState(true);
|
||||
expect(component.disabled).toEqual(true);
|
||||
|
||||
component.setDisabledState(false);
|
||||
expect(component.disabled).toEqual(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,93 +1,167 @@
|
|||
import {HttpClient} from '@angular/common/http';
|
||||
import {
|
||||
AfterContentInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
/**
|
||||
* You may include a different variant of BpmnJS:
|
||||
*
|
||||
* bpmn-viewer - displays BPMN diagrams without the ability
|
||||
* to navigate them
|
||||
* bpmn-modeler - bootstraps a full-fledged BPMN editor
|
||||
*/
|
||||
import * as BpmnJS from 'bpmn-js/dist/bpmn-modeler.production.min.js';
|
||||
import {HttpErrorResponse} from '@angular/common/http';
|
||||
import {AfterViewInit, Component, ElementRef, EventEmitter, NgZone, Output, ViewChild} from '@angular/core';
|
||||
import {ControlValueAccessor} from '@angular/forms';
|
||||
import propertiesPanelModule from 'bpmn-js-properties-panel';
|
||||
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda';
|
||||
import BpmnModeler from 'bpmn-js/lib/Modeler';
|
||||
import * as camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda.json';
|
||||
import minimapModule from 'diagram-js-minimap';
|
||||
|
||||
import {throwError} from 'rxjs';
|
||||
import {catchError} from 'rxjs/operators';
|
||||
|
||||
import {importDiagram} from './rx';
|
||||
import * as fileSaver from 'file-saver';
|
||||
import {BpmnWarning} from '../_interfaces/bpmn-warning';
|
||||
import {ImportEvent} from '../_interfaces/import-event';
|
||||
import {ApiService} from '../_services/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-diagram',
|
||||
templateUrl: './diagram.component.html',
|
||||
styleUrls: ['./diagram.component.scss']
|
||||
templateUrl: 'diagram.component.html',
|
||||
styleUrls: ['diagram.component.scss'],
|
||||
})
|
||||
export class DiagramComponent implements AfterContentInit, OnChanges, OnDestroy {
|
||||
private bpmnJS: BpmnJS;
|
||||
export class DiagramComponent implements ControlValueAccessor, AfterViewInit {
|
||||
@ViewChild('containerRef', {static: true}) containerRef: ElementRef;
|
||||
@ViewChild('propertiesRef', {static: true}) propertiesRef: ElementRef;
|
||||
@Output() private importDone: EventEmitter<ImportEvent> = new EventEmitter();
|
||||
private modeler: BpmnModeler;
|
||||
private xml = '';
|
||||
private disabled = false;
|
||||
|
||||
@ViewChild('ref', {static: true}) private el: ElementRef;
|
||||
@Output() private importDone: EventEmitter<any> = new EventEmitter();
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private api: ApiService,
|
||||
) {
|
||||
}
|
||||
|
||||
@Input() private url: string;
|
||||
get value(): any {
|
||||
return this.xml;
|
||||
}
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
ngAfterViewInit() {
|
||||
this.initializeModeler();
|
||||
this.openDiagram(this.xml);
|
||||
}
|
||||
|
||||
this.bpmnJS = new BpmnJS();
|
||||
onChange(value: any) {
|
||||
}
|
||||
|
||||
this.bpmnJS.on('import.done', ({error}) => {
|
||||
onTouched() {
|
||||
}
|
||||
|
||||
initializeModeler() {
|
||||
this.modeler = new BpmnModeler({
|
||||
container: this.containerRef.nativeElement,
|
||||
propertiesPanel: {
|
||||
parent: this.propertiesRef.nativeElement,
|
||||
},
|
||||
additionalModules: [
|
||||
propertiesProviderModule,
|
||||
propertiesPanelModule,
|
||||
minimapModule,
|
||||
],
|
||||
moddleExtensions: {
|
||||
camunda: camundaModdleDescriptor['default']
|
||||
}
|
||||
});
|
||||
|
||||
this.modeler.get('eventBus').on('commandStack.changed', () => this.saveDiagram());
|
||||
|
||||
this.modeler.on('import.done', ({error}) => {
|
||||
if (!error) {
|
||||
this.bpmnJS.get('canvas').zoom('fit-viewport');
|
||||
this.modeler.get('canvas').zoom('fit-viewport');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterContentInit(): void {
|
||||
this.bpmnJS.attachTo(this.el.nativeElement);
|
||||
// Allows Angular to update the model.
|
||||
// Update the model and changes needed for the view here.
|
||||
writeValue(value: any): void {
|
||||
if (value !== this.xml) {
|
||||
this.openDiagram(value);
|
||||
}
|
||||
this.xml = value;
|
||||
this.onChange(this.value);
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
// re-import whenever the url changes
|
||||
if (changes.url) {
|
||||
this.loadUrl(changes.url.currentValue);
|
||||
}
|
||||
// Allows Angular to register a function to call when the model changes.
|
||||
// Save the function as a property to call later here.
|
||||
registerOnChange(fn: (rating: number) => void): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.bpmnJS.destroy();
|
||||
// Allows Angular to register a function to call when the input has been touched.
|
||||
// Save the function as a property to call later here.
|
||||
registerOnTouched(fn: () => void): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
// Allows Angular to disable the input.
|
||||
setDisabledState(isDisabled: boolean): void {
|
||||
this.disabled = isDisabled;
|
||||
}
|
||||
|
||||
createNewDiagram() {
|
||||
this.openDiagram();
|
||||
}
|
||||
|
||||
openDiagram(xml?: string) {
|
||||
return this.zone.run(
|
||||
() => xml ?
|
||||
this.modeler.importXML(xml, (e, w) => this.onImport(e, w)) :
|
||||
this.modeler.createDiagram((e, w) => this.onImport(e, w))
|
||||
);
|
||||
}
|
||||
|
||||
saveSVG() {
|
||||
this.saveDiagram();
|
||||
this.modeler.saveSVG((err, svg) => {
|
||||
const blob = new Blob([svg], {type: 'image/svg+xml'});
|
||||
fileSaver.saveAs(blob, `BPMN Diagram - ${new Date().toISOString()}.svg`);
|
||||
});
|
||||
}
|
||||
|
||||
saveDiagram() {
|
||||
this.modeler.saveXML({format: true}, (err, xml) => {
|
||||
this.xml = xml;
|
||||
this.writeValue(xml);
|
||||
});
|
||||
}
|
||||
|
||||
saveXML() {
|
||||
this.saveDiagram();
|
||||
this.modeler.saveXML({format: true}, (err, xml) => {
|
||||
const blob = new Blob([xml], {type: 'text/xml'});
|
||||
fileSaver.saveAs(blob, `BPMN Diagram - ${new Date().toISOString()}.xml`);
|
||||
});
|
||||
}
|
||||
|
||||
onImport(err?: HttpErrorResponse, warnings?: BpmnWarning[]) {
|
||||
if (err) {
|
||||
this._handleErrors(err);
|
||||
} else {
|
||||
this._handleWarnings(warnings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load diagram from URL and emit completion event
|
||||
*/
|
||||
loadUrl(url: string) {
|
||||
this.api.getBpmnXml(url).subscribe(xml => {
|
||||
this.openDiagram(xml);
|
||||
}, error => this._handleErrors(error));
|
||||
}
|
||||
|
||||
return (
|
||||
this.http.get(url, {responseType: 'text'}).pipe(
|
||||
catchError(err => throwError(err)),
|
||||
importDiagram(this.bpmnJS)
|
||||
).subscribe(
|
||||
(warnings) => {
|
||||
private _handleWarnings(warnings: BpmnWarning[]) {
|
||||
this.importDone.emit({
|
||||
type: 'success',
|
||||
warnings
|
||||
warnings: warnings
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
}
|
||||
|
||||
private _handleErrors(err) {
|
||||
this.importDone.emit({
|
||||
type: 'error',
|
||||
error: err
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
import {Observable} from 'rxjs';
|
||||
|
||||
/**
|
||||
* An operator that imports the first XML piped via the piped diagram XML
|
||||
* into the passed BpmnJS instance.
|
||||
*/
|
||||
export const importDiagram = (bpmnJS) => <Object>(source: Observable<string>) =>
|
||||
new Observable<string>(observer => {
|
||||
|
||||
const subscription = source.subscribe({
|
||||
next(xml: string) {
|
||||
|
||||
// canceling the subscription as we are interested
|
||||
// in the first diagram to display only
|
||||
subscription.unsubscribe();
|
||||
|
||||
bpmnJS.importXML(xml, (err, warnings) => {
|
||||
|
||||
if (err) {
|
||||
observer.error(err);
|
||||
} else {
|
||||
observer.next(warnings);
|
||||
}
|
||||
|
||||
observer.complete();
|
||||
});
|
||||
},
|
||||
error(e) {
|
||||
console.log('ERROR');
|
||||
observer.error(e);
|
||||
},
|
||||
complete() {
|
||||
observer.complete();
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
<?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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_06g9dcb" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.4.1">
|
||||
<bpmn:process id="Process_1giz8il" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>SequenceFlow_0myefwb</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0myefwb" sourceRef="StartEvent_1" targetRef="StepOne" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_00p5po6" sourceRef="StepOne" targetRef="StepTwo" />
|
||||
<bpmn:endEvent id="EndEvent_1gsujvg">
|
||||
<bpmn:incoming>SequenceFlow_0huye14</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0huye14" sourceRef="StepTwo" targetRef="EndEvent_1gsujvg" />
|
||||
<bpmn:userTask id="StepOne" name="Step 1" camunda:formKey="StepOneForm">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="color" label="What is your favorite color?" type="string" />
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>SequenceFlow_0myefwb</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_00p5po6</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:userTask id="StepTwo" name="Step 2" camunda:formKey="StepTwoForm">
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="capital" label="What is the capital of Assyria?" type="string" />
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>SequenceFlow_00p5po6</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_0huye14</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1giz8il">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0myefwb_di" bpmnElement="SequenceFlow_0myefwb">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="270" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_00p5po6_di" bpmnElement="SequenceFlow_00p5po6">
|
||||
<di:waypoint x="370" y="117" />
|
||||
<di:waypoint x="430" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="EndEvent_1gsujvg_di" bpmnElement="EndEvent_1gsujvg">
|
||||
<dc:Bounds x="592" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0huye14_di" bpmnElement="SequenceFlow_0huye14">
|
||||
<di:waypoint x="530" y="117" />
|
||||
<di:waypoint x="592" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="UserTask_1xakn8i_di" bpmnElement="StepOne">
|
||||
<dc:Bounds x="270" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_0fltcd6_di" bpmnElement="StepTwo">
|
||||
<dc:Bounds x="430" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 948 B After Width: | Height: | Size: 5.3 KiB |
|
@ -2,10 +2,13 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CrConnectBpmn</title>
|
||||
<title>BpmnJsAngular</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'hammerjs';
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
|
||||
@import '~bpmn-js/dist/assets/diagram-js.css';
|
||||
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
|
||||
@import '~bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css';
|
||||
@import '~diagram-js-minimap/assets/diagram-js-minimap.css';
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
/* You can add global styles to this file, and also import other style files */
|
|
@ -0,0 +1,31 @@
|
|||
export const BPMN_DIAGRAM = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2"
|
||||
targetNamespace="http://bpmn.io/bpmn"
|
||||
exporter="http://bpmn.io"
|
||||
exporterVersion="0.10.1">
|
||||
<process id="Process_1" isExecutable="false" />
|
||||
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1" />
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
`;
|
||||
|
||||
export const BPMN_DIAGRAM_WITH_WARNINGS = `
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2"
|
||||
targetNamespace="http://bpmn.io/bpmn"
|
||||
exporter="http://bpmn.io"
|
||||
exporterVersion="0.10.1">
|
||||
<process id="Process_1" isExecutable="false" a:b="C" />
|
||||
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1" />
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
`;
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"src/**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -2,13 +2,14 @@
|
|||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"downlevelIteration": true,
|
||||
"outDir": "./dist/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"typeRoots": [
|
||||
|
@ -17,10 +18,9 @@
|
|||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true
|
||||
],
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts",
|
||||
"src/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
122
tslint.json
122
tslint.json
|
@ -1,32 +1,32 @@
|
|||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
"severity": "warn"
|
||||
},
|
||||
"component-class-suffix": true,
|
||||
"contextual-lifecycle": true,
|
||||
"directive-class-suffix": true,
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
|
@ -43,7 +43,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
|
@ -52,40 +53,79 @@
|
|||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-redundant-jsdoc": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-key-quotes": [
|
||||
true,
|
||||
"as-needed"
|
||||
],
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"ordered-imports": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"trailing-comma": false,
|
||||
"no-conflicting-lifecycle": true,
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"no-host-metadata-property": true,
|
||||
"no-input-rename": true,
|
||||
"no-inputs-metadata-property": true,
|
||||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"no-outputs-metadata-property": true,
|
||||
"template-banana-in-box": true,
|
||||
"template-no-negated-async": true,
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true
|
||||
},
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
]
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue