Skip to content

Commit

Permalink
feature dockerize & deployment plugin & attachment button (#69)
Browse files Browse the repository at this point in the history
* Refactor deployment processing in own plugin

refs: #2
refs: #14

* feat(ci): dockerize
Refs: #6

* docs: serve from docker container

* docs(ci): extend documentation of docker build

* Add feature issue template (#15)

* Add Issue Templates for Features

Add feature issue templates similar to the ones of the qunicorn repository but adjusted to the style of the workflow modeler.

* Implement attachment of deployment artifacts

Ref: #1

* Add xml viewer (#70)

* add xml viewer

* remove ace

* add border to resize editor

* enable live update on diagram change

* fix tests

* increase initial size of xml viewer & limit max height

* change size of modeler when xml viewer is enabled

* remove jump after first resize

* remove button from bottom left, add button to toolbar

* add icon

* Feature/9 visualize deployment model (#17)

* Add deployment model visualization

Ref: #9

* Add deployment model visualization

Ref: #9

* Orientate at top-node

* refactor stroke style

* add test

* add test

* add test

* fix top level node detection behavior and error handling

* Fix crash on hide

---------

Co-authored-by: Maximilian Kuhn <maximilian.kuhn@ymail.com>

* Feature/11 deployment model show all button (#18)

* Fix/upstream pr comments (#21)

* Fix/upstream pr comments
ref: #20

* Rename ArtifactWizardModal

Also fixed some typos in the code comments

* Feature/10 deployment model prevent overlap (#19)

refs: #10

* Feature/3 preparation of attached deployment artifacts (#23)

* Implement ArtifactType Dropdown

* Implement artifact upload

* Add Creation of Service Template

Add functionality which creates the service template, which includes a node of a fitting node type for the selected artifact.

* Auto Update SCAR

* Add loading notification and change CSAR naming

* fix artifact upload

---------

Co-authored-by: Maximilian Kuhn <maximilian.kuhn@ymail.com>
Co-authored-by: Christoph Walcher <christoph-wa@gmx.de>

* nit picking

Signed-off-by: Christoph Walcher <st180462@stud.uni-stuttgart.de>
Signed-off-by: Maximilian Kuhn <maximilian.kuhn@ymail.com>
Signed-off-by: Furkan Lokman <furkan.lokman@hotmail.com>

* Add On-Demand Deployment Pop-Up

* Fix button integration

* implement on demand transformation

* Move connectorUrl to opentosca plugin

* fix merge of upstream

* upload transformed xml

* fix review comments

Signed-off-by: Maximilian Kuhn <maximilian.kuhn@ymail.com>

* Prototyp script task

* fixup! Prototyp script task

* fix input parameter supplier

* fix tests

* implement push on-demand deployements

* improve  retry mechanism

* Implement changes suggested in review

* change organization in docker-push.yaml to planqk

* name tasks in subprocess & extend timeout

* Implement PR comments

* Rename BPMNConfigTab

---------

Signed-off-by: Christoph Walcher <st180462@stud.uni-stuttgart.de>
Signed-off-by: Maximilian Kuhn <maximilian.kuhn@ymail.com>
Signed-off-by: Furkan Lokman <furkan.lokman@hotmail.com>
Co-authored-by: Christoph Walcher <st180462@stud.uni-stuttgart.de>
Co-authored-by: Christoph Walcher <christoph-wa@gmx.de>
Co-authored-by: LaviniaStiliadou <livia_16@live.de>
Co-authored-by: lokmanfl <furkan.lokman@hotmail.com>
Co-authored-by: lokmanfl <44772645+lokmanfl@users.noreply.github.com>
  • Loading branch information
6 people authored Oct 23, 2023
1 parent 77f804f commit 28dedbc
Show file tree
Hide file tree
Showing 78 changed files with 2,533 additions and 722 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
components/bpmn-q/node_modules/
npm-debug.log
yarn-error.log
23 changes: 23 additions & 0 deletions .github/workflows/docker-publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

on:
push:
branches:
- 'master'

jobs:
docker-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: planqk/workflow-modeler:latest
48 changes: 41 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
FROM node:18-alpine

FROM node:18-alpine as builder
LABEL maintainer = "Martin Beisel <martin.beisel@iaas.uni-stuttgart.de>"
COPY "components/bpmn-q" /tmp
WORKDIR /tmp
COPY "components/bpmn-q" /app
WORKDIR /app
RUN npm ci

ARG DATA_CONFIG
ARG OPENTOSCA_ENDPOINT
ARG WINERY_ENDPOINT
ARG NISQ_ANALYZER_ENDPOINT
ARG TRANSFORMATION_FRAMEWORK_ENDPOINT
ARG QISKIT_RUNTIME_HANDLER_ENDPOINT
ARG AWS_RUNTIME_HANDLER_ENDPOINT
ARG SCRIPT_SPLITTER_ENDPOINT
ARG SCRIPT_SPLITTER_THRESHOLD
ARG QRM_REPONAME
ARG QRM_USERNAME
ARG QRM_REPOPATH
ARG PROVENANCE_COLLECTION
ARG ENABLE_DATA_FLOW_PLUGIN
ARG ENABLE_PLANQK_PLUGIN
ARG ENABLE_QHANA_PLUGIN
ARG ENABLE_QUANTME_PLUGIN
ARG ENABLE_OPENTOSCA_PLUGIN
ARG AUTOSAVE_INTERVAL
ARG CAMUNDA_ENDPOINT
ARG DOWNLOAD_FILE_NAME
ARG GITHUB_TOKEN
ARG QHANA_GET_PLUGIN_URL
ARG QHANA_LIST_PLUGINS_URL
ARG SERVICE_DATA_CONFIG
ARG UPLOAD_BRANCH_NAME
ARG UPLOAD_FILE_NAME
ARG UPLOAD_GITHUB_REPO
ARG UPLOAD_GITHUB_USER

RUN npm install
RUN env
RUN npm run build -- --mode=production

EXPOSE 8080

CMD npm run dev
FROM nginxinc/nginx-unprivileged:alpine
USER root
RUN rm -rf /usr/share/nginx/html
COPY --from=builder /app/public /usr/share/nginx/html
USER 101
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ npm run dev
```
to start the modeler in a simple html website which runs on localhost:8080.

## Execution in Docker
To serve the application from a Docker container execute:
```
docker run --name workflow-modeler -p 8080:8080 planqk/workflow-modeler
```
Afterwards the application is available in a browser on localhost:8080

To build and run an own image execute:
```
docker build -t workflow-modeler [--build-arg <Key>=<Value>] .
docker run --name workflow-modeler -p 8080:8080 workflow-modeler
```


## How to use this Library

To use the Quantum Workflow Modeler component in your application you have to install its npm package which is published
Expand Down
5 changes: 4 additions & 1 deletion components/bpmn-q/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ module.exports = function (config) {
'test/tests/editor/editor.spec.js',
'test/tests/editor/plugin.spec.js',
'test/tests/planqk/planqk-transformation.spec.js',
'test/tests/quantme/quantme-transformation.spec.js',
'test/tests/editor/utils/modelling-util.spec.js',
'test/tests/qhana/qhana-plugin-config.spec.js',
'test/tests/qhana/qhana-service-configs.spec.js',
'test/tests/quantme/quantme-transformation.spec.js',
'test/tests/quantme/data-object-configs.spec.js',
'test/tests/quantme/quantme-config.spec.js',
'test/tests/opentosca/opentosca-config.spec.js',
'test/tests/opentosca/deployment-utils.spec.js',
'test/tests/opentosca/deployment-model-renderer.spec.js',
'test/tests/dataflow/data-flow-transformation.spec.js',
'test/tests/dataflow/data-flow-plugin-config.spec.js',
'test/tests/dataflow/data-flow-configurations-endpoint.spec.js',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class QuantumWorkflowModeler extends HTMLElement {
<div id="main-div" style="display: flex; flex: 1; height: 100%">
<div id="canvas" style="width: 100%"></div>
<div id="properties" style="overflow: auto; width:350px; max-height: 93.5vh; background: #f8f8f8;"></div>
<div id="modal-container"></div>
</div>
<div id="qwm-notification-container"></div>
</div>`;
Expand Down
15 changes: 11 additions & 4 deletions components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PlanQKPlugin from '../../extensions/planqk/PlanQKPlugin';
import QuantMEPlugin from '../../extensions/quantme/QuantMEPlugin';
import OpenTOSCAPlugin from "../../extensions/opentosca/OpenTOSCAPlugin";
import DataFlowPlugin from '../../extensions/data-extension/DataFlowPlugin';
import QHAnaPlugin from '../../extensions/qhana/QHAnaPlugin';
import { getAllConfigs } from './PluginConfigHandler';
Expand Down Expand Up @@ -29,6 +30,10 @@ const PLUGINS = [
{
plugin: PlanQKPlugin,
dependencies: []
},
{
plugin: OpenTOSCAPlugin,
dependencies: []
}
];

Expand Down Expand Up @@ -72,13 +77,15 @@ export function getActivePlugins() {
export function checkEnabledStatus(pluginName) {
switch (pluginName) {
case 'dataflow':
return process.env.ENABLE_DATA_FLOW_PLUGIN;
return process.env.ENABLE_DATA_FLOW_PLUGIN !== "false";
case 'planqk':
return process.env.ENABLE_PLANQK_PLUGIN;
return process.env.ENABLE_PLANQK_PLUGIN !== "false";
case 'qhana':
return process.env.ENABLE_QHANA_PLUGIN;
return process.env.ENABLE_QHANA_PLUGIN !== "false";
case 'quantme':
return process.env.ENABLE_QUANTME_PLUGIN;
return process.env.ENABLE_QUANTME_PLUGIN !== "false";
case 'opentosca':
return process.env.ENABLE_OPENTOSCA_PLUGIN !== "false";
}
}
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@
color: #636363;
}

.qwm-properties-btn {
box-sizing: border-box;
outline: none;
background-color: transparent;
border: solid;
border-radius: 6px;
font-size: 15px;
font-family: Arial, serif;
font-weight: bold;
margin: 2px;
padding: 8px;
color: #636363;
}

.qwm-shortcuts {
right: 0px;
position: absolute;
Expand Down
56 changes: 50 additions & 6 deletions components/bpmn-q/modeler-component/editor/ui/DeploymentButton.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import React from 'react';
import React, {Fragment, useState} from 'react';
import NotificationHandler from './notifications/NotificationHandler';
import {deployWorkflowToCamunda} from '../util/IoUtilities';
import {getCamundaEndpoint} from '../config/EditorConfigManager';
import {getRootProcess} from '../util/ModellingUtilities';
import {getServiceTasksToDeploy} from '../../extensions/opentosca/deployment/DeploymentUtils';
import {getModeler} from '../ModelerHandler';
import OnDemandDeploymentModal from './OnDemandDeploymentModal';
import {startOnDemandReplacementProcess} from "../../extensions/opentosca/replacement/OnDemandTransformator";

const defaultState = {
windowOpenOnDemandDeployment: false,
};

/**
* React button for starting the deployment of the workflow.
Expand All @@ -12,13 +20,36 @@ import {getRootProcess} from '../util/ModellingUtilities';
* @constructor
*/
export default function DeploymentButton(props) {
const [windowOpenOnDemandDeployment, setWindowOpenOnDemandDeployment] = useState(false);

const {modeler} = props;


/**
* Handle result of the on demand deployment dialog
*
* @param result the result from the dialog
*/
async function handleOnDemandDeployment(result) {
if (result && result.hasOwnProperty('onDemand')) {
// get XML of the current workflow
let xml = (await modeler.saveXML({format: true})).xml;
console.log("XML", xml)
if (result.onDemand === true) {
xml = await startOnDemandReplacementProcess(xml);
}
// deploy in any case
deploy(xml);
}
// handle cancellation (don't deploy)
setWindowOpenOnDemandDeployment(false);

}

/**
* Deploy the current workflow to the Camunda engine
*/
async function deploy() {
async function deploy(xml) {

NotificationHandler.getInstance().displayNotification({
title: 'Deployment started',
Expand All @@ -27,7 +58,6 @@ export default function DeploymentButton(props) {

// get XML of the current workflow
const rootElement = getRootProcess(modeler.getDefinitions());
const xml = (await modeler.saveXML({format: true})).xml;

// check if there are views defined for the modeler and include them in the deployment
let viewsDict = {};
Expand Down Expand Up @@ -56,12 +86,26 @@ export default function DeploymentButton(props) {
}
}

async function onClick() {
let csarsToDeploy = getServiceTasksToDeploy(getRootProcess(getModeler().getDefinitions()));
if (csarsToDeploy.length > 0) {
setWindowOpenOnDemandDeployment(true);
} else {
deploy((await modeler.saveXML({format: true})).xml);
}
}

return (
<>
<Fragment>
<button type="button" className="qwm-toolbar-btn" title="Deploy the current workflow to a workflow engine"
onClick={() => deploy()}>
onClick={() => onClick()}>
<span className="qwm-workflow-deployment-btn"><span className="qwm-indent">Deploy Workflow</span></span>
</button>
</>
{windowOpenOnDemandDeployment && (
<OnDemandDeploymentModal
onClose={(e) => handleOnDemandDeployment(e)}
/>
)}
</Fragment>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2023 Institute of Architecture of Application Systems -
* University of Stuttgart
*
* This program and the accompanying materials are made available under the
* terms the Apache Software License 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: Apache-2.0
*/

/* eslint-disable no-unused-vars */
import React from 'react';

// polyfill upcoming structural components
import Modal from './modal/Modal';

const Title = Modal.Title || (({children}) => <h2>{children}</h2>);
const Body = Modal.Body || (({children}) => <div>{children}</div>);
const Footer = Modal.Footer || (({children}) => <div>{children}</div>);

export default function OnDemandDeploymentModal({onClose}) {

const onOnDemand = (value) => onClose({
onDemand: value,
});

return <Modal onClose={onClose}>

<Title>
Workflow Deployment
</Title>
<Body>
The current workflow contains service task with attached deployment models which support on-demand service deployment.
Would you like to use on-demand service deployment?
</Body>
<Footer>
<div id="deploymentButtons">
<button type="button" className="qwm-btn qwm-btn-primary" onClick={() => onOnDemand(true)}>Yes</button>
<button type="button" className="qwm-btn qwm-btn-secondary" onClick={() => onOnDemand(false)}>No</button>
</div>
</Footer>
</Modal>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ export default class NotificationHandler {
* @param title The title of the notification.
* @param content The text displayed by the notification.
* @param duration The duration in milliseconds.
* @returns {{update: update, close: close}}
*/
displayNotification({type = 'info', title, content, duration = 4000}) {
this.notificationRef.current.displayNotification({
return this.notificationRef.current.displayNotification({
type: type,
title: title,
content: content,
Expand Down
18 changes: 13 additions & 5 deletions components/bpmn-q/modeler-component/editor/util/RenderUtilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,32 @@ function drawRect(parentNode, width, height, borderRadius, color) {
* @param parentGfx The parent element the SVG is drawn in
* @param importSVG The SVG
* @param svgAttributes Attributes for the SVG
* @param foreground true if SVG should be above Task
* @returns The created svg element
*/
export function drawTaskSVG(parentGfx, importSVG, svgAttributes) {
export function drawTaskSVG(parentGfx, importSVG, svgAttributes, foreground) {
const innerSvgStr = importSVG.svg,
transformDef = importSVG.transform;

const groupDef = svgCreate('g');
svgAttr(groupDef, {transform: transformDef});
innerSVG(groupDef, innerSvgStr);

// set task box opacity to 0 such that icon can be in the background
svgAttr(svgSelect(parentGfx, 'rect'), {'fill-opacity': 0});
if(!foreground) {
// set task box opacity to 0 such that icon can be in the background
svgAttr(svgSelect(parentGfx, 'rect'), { 'fill-opacity': 0 });
}

if (svgAttributes) {
svgAttr(groupDef, svgAttributes);
}

// draw svg in the background
parentGfx.prepend(groupDef);
if(foreground) {
parentGfx.append(groupDef);
} else {
parentGfx.prepend(groupDef);
}
return groupDef;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as consts from '../Constants';
export default class DataFlowPaletteProvider {

constructor(bpmnFactory, create, elementFactory, palette, translate) {

this.bpmnFactory = bpmnFactory;
this.create = create;
this.elementFactory = elementFactory;
Expand Down
Loading

0 comments on commit 28dedbc

Please sign in to comment.