diff --git a/components/bpmn-q/modeler-component/QuantumWorkflowModeler.js b/components/bpmn-q/modeler-component/QuantumWorkflowModeler.js index ce9da905..26908445 100644 --- a/components/bpmn-q/modeler-component/QuantumWorkflowModeler.js +++ b/components/bpmn-q/modeler-component/QuantumWorkflowModeler.js @@ -12,7 +12,7 @@ import './modeler.css'; import React from 'react'; import { createRoot } from 'react-dom/client'; import ButtonToolbar from "./editor/ui/ButtonToolbar"; -import { createNewDiagram, loadDiagram } from "./editor/util/IoUtilities"; +import { createNewDiagram, loadDiagram, setAutoSaveInterval } from "./editor/util/IoUtilities"; import NotificationHandler from "./editor/ui/notifications/NotificationHandler"; import { createModeler, getModeler } from "./editor/ModelerHandler"; import { getPluginButtons, getTransformationButtons } from "./editor/plugin/PluginHandler"; @@ -335,6 +335,7 @@ export class QuantumWorkflowModeler extends HTMLElement { // restart modeler to apply plugin config when shadow dom is rendered requestAnimationFrame(() => { this.startModeler(); + setAutoSaveInterval(); }); } } diff --git a/components/bpmn-q/modeler-component/editor/EditorConstants.js b/components/bpmn-q/modeler-component/editor/EditorConstants.js index 3ede37e5..288375b2 100644 --- a/components/bpmn-q/modeler-component/editor/EditorConstants.js +++ b/components/bpmn-q/modeler-component/editor/EditorConstants.js @@ -10,13 +10,18 @@ export const workflowEventTypes = { LOADED: 'quantum-workflow-loaded', // New Workflow loaded in modeler SAVED: 'quantum-workflow-saved', // Workflow saved TRANSFORMED: 'quantum-workflow-transformed', // Workflow transformed - DEPLOYED: 'quantum-workflow-deployed' // Workflow deployed to workflow engine + DEPLOYED: 'quantum-workflow-deployed', // Workflow deployed to workflow engine }; +export const autoSaveFile = { + INTERVAL: 'Interval', + ON_ACTION: 'On Action' +} + // supported save file options export const saveFileFormats = { ALL: 'all', BPMN: '.bpmn', PNG: '.png', SVG: '.svg' -}; \ No newline at end of file +}; diff --git a/components/bpmn-q/modeler-component/editor/config/EditorConfigManager.js b/components/bpmn-q/modeler-component/editor/config/EditorConfigManager.js index 1339fedd..43b7baf2 100644 --- a/components/bpmn-q/modeler-component/editor/config/EditorConfigManager.js +++ b/components/bpmn-q/modeler-component/editor/config/EditorConfigManager.js @@ -1,12 +1,14 @@ import { getPluginConfig } from '../plugin/PluginConfigHandler'; -import { saveFileFormats, transformedWorkflowHandlers } from '../EditorConstants'; +import { saveFileFormats, transformedWorkflowHandlers, autoSaveFile } from '../EditorConstants'; // default configurations of the editor const defaultConfig = { camundaEndpoint: process.env.CAMUNDA_ENDPOINT, fileName: process.env.DOWNLOAD_FILE_NAME, transformedWorkflowHandler: transformedWorkflowHandlers.NEW_TAB, - fileFormat: saveFileFormats.BPMN + autoSaveFileOption: autoSaveFile.INTERVAL, + fileFormat: saveFileFormats.BPMN, + autoSaveIntervalSize: process.env.AUTOSAVE_INTERVAL }; let config = {}; @@ -90,6 +92,33 @@ export function setTransformedWorkflowHandler(transformedWorkflowHandler) { } /** + * Get the id of the handler to handle auto save of files. + * + * @return {string} the currently specified handler id + */ +export function getAutoSaveFileOption() { + if (config.autoSaveFileOption === undefined) { + const autoSaveFileOption = autoSaveFile[getPluginConfig('editor').autoSaveFileOption]; + setAutoSaveFileOption(autoSaveFileOption || defaultConfig.autoSaveFileOption); + } + return config.autoSaveFileOption; +} + +/** + * Set the id of the handler to handle auto save of files + * + * @param autoSaveFileOption the id of the transformed workflow handler + */ +export function setAutoSaveFileOption(autoSaveFileOption) { + if (autoSaveFileOption !== null && autoSaveFileOption !== undefined + // check that the new value is a valid handler id + && Object.values(autoSaveFile).includes(autoSaveFileOption)) { + + config.autoSaveFileOption = autoSaveFileOption; + } +} + +/** * Get the file format * * @return {string} the currently specified handler id @@ -116,6 +145,29 @@ export function setFileFormat(fileFormat) { } } +/** + * Get the autosave interval size + * + * @return {string} the current interval size + */ +export function getAutoSaveIntervalSize() { + if (config.autoSaveIntervalSize === undefined) { + setAutoSaveIntervalSize(getPluginConfig('editor').autoSaveIntervalSize || defaultConfig.autoSaveIntervalSize); + } + return config.autoSaveIntervalSize; +} + +/** + * Set the interval size of the autosave function + * + * @param intervalSize the interval size + */ +export function setAutoSaveIntervalSize(intervalSize) { + if (intervalSize !== null && intervalSize !== undefined) { + config.autoSaveIntervalSize = intervalSize; + } +} + /** * Resets the current editor configs */ diff --git a/components/bpmn-q/modeler-component/editor/config/EditorTab.js b/components/bpmn-q/modeler-component/editor/config/GeneralTab.js similarity index 71% rename from components/bpmn-q/modeler-component/editor/config/EditorTab.js rename to components/bpmn-q/modeler-component/editor/config/GeneralTab.js index 38ed8bc6..4f6f822a 100644 --- a/components/bpmn-q/modeler-component/editor/config/EditorTab.js +++ b/components/bpmn-q/modeler-component/editor/config/GeneralTab.js @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { getModeler } from "../ModelerHandler"; import * as editorConfig from "./EditorConfigManager"; -import { transformedWorkflowHandlers, saveFileFormats } from '../EditorConstants'; +import { autoSaveFile, saveFileFormats, transformedWorkflowHandlers } from '../EditorConstants'; /** * Tab for the ConfigModal. Used to allow the configurations of the editor configs, namely the camunda endpoint and the @@ -14,8 +14,11 @@ export default function EditorTab() { const [camundaEndpoint, setCamundaEndpoint] = useState(editorConfig.getCamundaEndpoint()); const [workflowHandler, setWorkflowHandler] = useState(editorConfig.getTransformedWorkflowHandler()); + const [autoSaveFileOption, setAutoSaveFileOption] = useState(editorConfig.getAutoSaveFileOption()); const [fileName, setFileName] = useState(editorConfig.getFileName()); const [fileFormat, setFileFormat] = useState(editorConfig.getFileFormat()); + const [autoSaveIntervalSize, setAutoSaveIntervalSize] = useState(editorConfig.getAutoSaveIntervalSize()); + const modeler = getModeler(); @@ -45,8 +48,11 @@ export default function EditorTab() { modeler.config.fileName = fileName; editorConfig.setCamundaEndpoint(camundaEndpoint); editorConfig.setTransformedWorkflowHandler(workflowHandler); + editorConfig.setAutoSaveFileOption(autoSaveFileOption); + modeler.get('eventBus').fire('autoSaveOptionChanged', { autoSaveFileOption }); editorConfig.setFileName(fileName); editorConfig.setFileFormat(fileFormat); + editorConfig.setAutoSaveIntervalSize(autoSaveIntervalSize); }; // return tab which contains entries to change the camunda endpoint and the workflow handler @@ -118,6 +124,38 @@ export default function EditorTab() { +

Auto save file:

+ + + + + + + {autoSaveFileOption === autoSaveFile.INTERVAL && ( + + + + + )} + +
Auto save file option: + +
Auto save interval size: + setAutoSaveIntervalSize(event.target.value)} /> +
); } diff --git a/components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js b/components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js index 2b45efb1..cc1d95fd 100644 --- a/components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js +++ b/components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js @@ -1,9 +1,10 @@ -import PlanQKPlugin from "../../extensions/planqk/PlanQKPlugin"; -import QuantMEPlugin from "../../extensions/quantme/QuantMEPlugin"; +import PlanQKPlugin from '../../extensions/planqk/PlanQKPlugin'; +import QuantMEPlugin from '../../extensions/quantme/QuantMEPlugin'; import DataFlowPlugin from '../../extensions/data-extension/DataFlowPlugin'; import QHAnaPlugin from '../../extensions/qhana/QHAnaPlugin'; -import {getAllConfigs} from "./PluginConfigHandler"; -import EditorTab from "../config/EditorTab"; +import { getAllConfigs } from './PluginConfigHandler'; +import GeneralTab from '../config/GeneralTab'; +import GitHubTab from '../../extensions/quantme/configTabs/GitHubTab'; /** * Handler for plugins of the modeler. Controls active plugins and the properties they define. Central access point to @@ -11,50 +12,65 @@ import EditorTab from "../config/EditorTab"; */ // list of plugins integrated in the modeler, register new plugins here +// dependencies can be specified by the name of the corresponding plugins const PLUGINS = [ - DataFlowPlugin, - QHAnaPlugin, - PlanQKPlugin, - QuantMEPlugin, + { + plugin: QuantMEPlugin, + dependencies: [] + }, + { + plugin: DataFlowPlugin, + dependencies: [] + }, + { + plugin: QHAnaPlugin, + dependencies: [] + }, + { + plugin: PlanQKPlugin, + dependencies: [] + } ]; // list of currently active plugins in the current running instance of the modeler, defined based on the plugin configuration let activePlugins = []; -/** - * Returns these plugins of PLUGINS which have an entry in the current plugin configuration of the modeler. - * - * @returns {*[]} Array of active plugins. - */ export function getActivePlugins() { - - // return saved active plugins array if (activePlugins.length > 0) { return activePlugins; - - // determine active plugins } else { - activePlugins = []; - - let plugin; - - // add all plugins of PLUGINS to active plugins which have a config entry for them - for (let pluginConfig of getAllConfigs()) { - - plugin = PLUGINS.find(plugin => plugin.name === pluginConfig.name && checkEnabledStatus(plugin.name)); + const loadPlugin = (plugin) => { + if (!activePlugins.includes(plugin.plugin)) { + for (const dependency of plugin.dependencies) { + const dependencyPlugin = PLUGINS.find((p) => p.plugin.name === dependency); + if (dependencyPlugin && !activePlugins.includes(dependencyPlugin.plugin)) { + activePlugins.push(dependencyPlugin.plugin); + loadPlugin(dependencyPlugin); + } + } + activePlugins.push(plugin.plugin); + } + }; + for (const pluginConfig of getAllConfigs()) { + const plugin = PLUGINS.find( + (p) => p.plugin.name === pluginConfig.name && checkEnabledStatus(p.plugin.name) + ); if (plugin) { - activePlugins.push(plugin); + loadPlugin(plugin); } } + return activePlugins; } } + + export function checkEnabledStatus(pluginName) { - switch(pluginName) { + switch (pluginName) { case 'dataflow': return process.env.ENABLE_DATA_FLOW_PLUGIN; case 'planqk': @@ -179,13 +195,17 @@ export function getConfigTabs() { // add default editor tab to configure editor configs let configTabs = [{ tabId: 'EditorTab', - tabTitle: 'Editor', - configTab: EditorTab, + tabTitle: 'General', + configTab: GeneralTab, + }, { + tabId: 'GitHubTab', + tabTitle: 'GitHub', + configTab: GitHubTab, }]; // load the config tabs of the active plugins into one array for (let plugin of getActivePlugins()) { - if (plugin.configTabs) { + if (plugin.configTabs && checkEnabledStatus(plugin.name)) { configTabs = configTabs.concat(plugin.configTabs); } } diff --git a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js index db34386b..425f3a36 100644 --- a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js +++ b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js @@ -1,11 +1,11 @@ -import { file } from 'jszip'; -import { transformedWorkflowHandlers, workflowEventTypes, saveFileFormats } from '../EditorConstants'; -import { dispatchWorkflowEvent } from '../events/EditorEventHandler'; +import { autoSaveFile, saveFileFormats, transformedWorkflowHandlers, workflowEventTypes } from "../EditorConstants"; +import { getModeler } from "../ModelerHandler"; +import { dispatchWorkflowEvent } from "../events/EditorEventHandler"; +import fetch from "node-fetch"; const editorConfig = require('../config/EditorConfigManager'); let FormData = require('form-data'); -import fetch from 'node-fetch'; // workflow with a start event to use as template for new workflows const NEW_DIAGRAM_XML = '\n' + @@ -47,18 +47,19 @@ export async function saveXmlAsLocalFile(xml, fileName = editorConfig.getFileNam * @param fileName The name of the file. * @returns {Promise} */ -export async function saveModelerAsLocalFile(modeler, fileName = editorConfig.getFileName(), fileFormat = editorConfig.getFileFormat()) { +export async function saveModelerAsLocalFile(modeler, fileName = editorConfig.getFileName(), fileFormat = editorConfig.getFileFormat(), openWindow = true) { const xml = await getXml(modeler); - if (fileFormat === saveFileFormats.BPMN || fileFormat === saveFileFormats.ALL) { - await openFileDialog(xml, fileName, saveFileFormats.BPMN); + if (openWindow) { + await openFileDialog(xml, fileName, saveFileFormats.BPMN); + } else { + await saveXmlAsLocalFile(xml, fileName); + } } if (fileFormat === saveFileFormats.ALL || fileFormat === saveFileFormats.SVG || fileFormat === saveFileFormats.PNG) { await saveWorkflowAsSVG(modeler, fileName, fileFormat); } - - return; } /** @@ -231,6 +232,36 @@ export function openInNewTab(workflowXml, fileName) { }; } +export function setAutoSaveInterval(autoSaveFileOption = editorConfig.getAutoSaveFileOption()) { + if (autoSaveFileOption === autoSaveFile.INTERVAL) { + getModeler().autosaveIntervalId = setInterval(() => { saveFile(); }, editorConfig.getAutoSaveIntervalSize()); + } else { + saveFile(); + } +} + +export function saveFile() { + // extract the xml and save it to a file + getModeler().saveXML({ format: true }, function (err, xml) { + if (!err) { + let oldXml = getModeler().oldXml; + if (oldXml !== xml && oldXml !== undefined) { + // Save the XML + console.log('Autosaved:', xml); + getModeler().oldXml = xml; + const timestamp = getTimestamp(); + const filename = `${editorConfig.getFileName().replace('.bpmn','')}_autosave_${timestamp}`; + saveXmlAsLocalFile(xml, filename); + } + } + }); +} + +function getTimestamp() { + const date = new Date(); + return date.toISOString().replace(/:/g, '-'); +} + export async function saveWorkflowAsSVG(modeler, fileName, fileFormat) { modeler.saveSVG({ format: true }, function (error, svg) { if (error) { @@ -269,8 +300,8 @@ function downloadPng(pngDataUrl, fileName, fileFormat) { async function openFileDialog(content, fileName, fileFormat) { let suggestedName = fileName; if (suggestedName.includes('.bpmn')) { - suggestedName = fileName.split('.bpmn')[0]; - } + suggestedName = fileName.split('.bpmn')[0]; + } let fileHandle = await window.showSaveFilePicker({ startIn: 'downloads', suggestedName: suggestedName + fileFormat, types: [ { @@ -289,8 +320,8 @@ async function openFileDialog(content, fileName, fileFormat) { async function openFileUrlDialog(content, fileName, fileFormat) { let suggestedName = fileName; if (suggestedName.includes('.bpmn')) { - suggestedName = fileName.split('.bpmn')[0]; - } + suggestedName = fileName.split('.bpmn')[0]; + } let fileHandle = await window.showSaveFilePicker({ startIn: 'downloads', suggestedName: suggestedName + fileFormat, types: [ { diff --git a/components/bpmn-q/modeler-component/extensions/data-extension/DataFlowPlugin.js b/components/bpmn-q/modeler-component/extensions/data-extension/DataFlowPlugin.js index 0f458134..d4a31260 100644 --- a/components/bpmn-q/modeler-component/extensions/data-extension/DataFlowPlugin.js +++ b/components/bpmn-q/modeler-component/extensions/data-extension/DataFlowPlugin.js @@ -25,7 +25,7 @@ export default { configTabs: [ { tabId: 'DataEndpointsTab', - tabTitle: 'Data Endpoints', + tabTitle: 'Data Flow Plugin', configTab: TransformationTaskConfigurationsTab, }, ], diff --git a/components/bpmn-q/modeler-component/extensions/data-extension/rules/DataFlowRulesProvider.js b/components/bpmn-q/modeler-component/extensions/data-extension/rules/DataFlowRulesProvider.js index 63cb439a..55037fc3 100644 --- a/components/bpmn-q/modeler-component/extensions/data-extension/rules/DataFlowRulesProvider.js +++ b/components/bpmn-q/modeler-component/extensions/data-extension/rules/DataFlowRulesProvider.js @@ -5,8 +5,11 @@ import { } from 'bpmn-js/lib/features/modeling/util/ModelingUtil'; import * as consts from '../Constants'; import { isConnectedWith } from '../../../editor/util/ModellingUtilities'; +import { saveFile, setAutoSaveInterval } from '../../../editor/util/IoUtilities'; import { getModeler } from '../../../editor/ModelerHandler'; import ace from 'ace-builds'; +import * as editorConfig from "../../../editor/config/EditorConfigManager"; +import { autoSaveFile } from '../../../editor/EditorConstants'; /** * Custom rules provider for the DataFlow elements. Extends the BpmnRules. @@ -20,8 +23,7 @@ export default class CustomRulesProvider extends BpmnRules { const canConnect = this.canConnect.bind(this); const canCreate = this.canCreate.bind(this); - // persist into local storage whenever - // copy took place + // persist into local storage whenever copy took place eventBus.on('copyPaste.elementsCopied', event => { const { tree } = event; @@ -68,21 +70,41 @@ export default class CustomRulesProvider extends BpmnRules { ); }); + // save every change when the autosave option is on action + eventBus.on("commandStack.changed", function () { + if (editorConfig.getAutoSaveFileOption() === autoSaveFile.ON_ACTION) { + saveFile(); + } + }); + + // remove interval when autosave option is on action + eventBus.on("autoSaveOptionChanged", function (context) { + if (context.autoSaveFileOption === autoSaveFile.ON_ACTION) { + clearInterval(getModeler().autosaveIntervalId); + } else { + setAutoSaveInterval(); + } + }); + // update xml viewer on diagram change eventBus.on("commandStack.changed", function () { let editor = document.getElementById('editor'); let aceEditor = ace.edit(editor); let modeler = getModeler(); if (modeler) { + if (modeler.xml !== undefined) { + modeler.oldXml = getModeler().xml; + if (getModeler().xml.xml !== undefined) + modeler.oldXml = getModeler().xml.xml; + } modeler.saveXML({ format: true }).then(function (result) { - if (result.xml != undefined) { + if (result.xml !== undefined) { result = result.xml; } aceEditor.setValue(result); - }) + }); } }); - } /** diff --git a/components/bpmn-q/modeler-component/extensions/qhana/QHAnaPlugin.js b/components/bpmn-q/modeler-component/extensions/qhana/QHAnaPlugin.js index 4219772f..63a86d72 100644 --- a/components/bpmn-q/modeler-component/extensions/qhana/QHAnaPlugin.js +++ b/components/bpmn-q/modeler-component/extensions/qhana/QHAnaPlugin.js @@ -23,7 +23,7 @@ export default { configTabs: [ { tabId: 'QHAnaEndpointsTab', - tabTitle: 'QHAna Endpoints', + tabTitle: 'QHAna Plugin', configTab: QHAnaConfigurationsTab, }, ], diff --git a/components/bpmn-q/modeler-component/extensions/quantme/QuantMEPlugin.js b/components/bpmn-q/modeler-component/extensions/quantme/QuantMEPlugin.js index 7a99ad35..f1574810 100644 --- a/components/bpmn-q/modeler-component/extensions/quantme/QuantMEPlugin.js +++ b/components/bpmn-q/modeler-component/extensions/quantme/QuantMEPlugin.js @@ -1,21 +1,14 @@ -import React from "react"; - -import QuantMEExtensionModule from "./modeling"; -import BPMNConfigTab from "./configTabs/BPMNConfigTab"; -import OpenToscaTab from "./configTabs/OpenToscaTab"; -import NisqAnalyzerTab from "./configTabs/NisqAnalyzerTab"; -import QrmDataTab from "./configTabs/QrmDataTab"; -import HybridRuntimeTab from "./configTabs/HybridRuntimeTab"; -import UploadTab from "./configTabs/UploadTab"; -import {getQRMs} from "./qrm-manager"; -import {startQuantmeReplacementProcess} from "./replacement/QuantMETransformator"; -import * as camundaConfig from "../../editor/config/EditorConfigManager"; -import * as config from "./framework-config/config-manager"; -import TransformationButton from "../../editor/ui/TransformationButton"; -import DataObjectConfigurationsTab from './configurations/DataObjectConfigurationsTab'; +import React from 'react'; +import QuantMEExtensionModule from './modeling'; +import QuantMETab from './configTabs/QuantMETab'; +import {getQRMs} from './qrm-manager'; +import {startQuantmeReplacementProcess} from './replacement/QuantMETransformator'; +import * as camundaConfig from '../../editor/config/EditorConfigManager'; +import * as config from './framework-config/config-manager'; +import TransformationButton from '../../editor/ui/TransformationButton'; import quantMEStyles from './styling/quantme.css'; -import QuantMEPluginButton from "./ui/QuantMEPluginButton"; +import QuantMEPluginButton from './ui/QuantMEPluginButton'; let quantMEModdleExtension = require('./resources/quantum4bpmn.json'); @@ -23,42 +16,12 @@ let quantMEModdleExtension = require('./resources/quantum4bpmn.json'); * Plugin Object of the QuantME extension. Used to register the plugin in the plugin handler of the modeler. */ export default { - buttons: [], + buttons: [], configTabs: [ - { - tabId: 'DataConfigurationEndpointTab', - tabTitle: 'QuantME Data', - configTab: DataObjectConfigurationsTab, - }, - { - tabId: 'OpenTOSCAEndpointTab', - tabTitle: 'OpenTOSCA', - configTab: OpenToscaTab, - }, { tabId: 'BPMNTab', - tabTitle: 'Workflow', - configTab: BPMNConfigTab, - }, - { - tabId: 'NISQAnalyzerEndpointTab', - tabTitle: 'NISQ Analyzer', - configTab: NisqAnalyzerTab, - }, - { - tabId: 'QRMDataTab', - tabTitle: 'QRM Data', - configTab: QrmDataTab, - }, - { - tabId: 'HybridRuntimesTab', - tabTitle: 'Hybrid Runtimes', - configTab: HybridRuntimeTab, - }, - { - tabId: 'UploadTab', - tabTitle: 'Upload data', - configTab: UploadTab, + tabTitle: 'QuantME Plugin', + configTab: QuantMETab, } ], name: 'quantme', @@ -77,5 +40,5 @@ export default { } ); } - }/>, + }/> }; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/BPMNConfigTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/BPMNConfigTab.js deleted file mode 100644 index ac63d075..00000000 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/BPMNConfigTab.js +++ /dev/null @@ -1,107 +0,0 @@ -import React, {useState} from 'react'; -import {getModeler} from "../../../editor/ModelerHandler"; -import * as config from "../framework-config/config-manager"; - -/** - * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change workflow - * related configuration entries of the QuantME configs. - * - * @return {JSX.Element} The tab as a React component - * @constructor - */ -export default function BPMNConfigTab() { - - const [transformationFrameworkEndpoint, setTransformationFrameworkEndpoint] = useState(config.getTransformationFrameworkEndpoint()); - const [scriptSplitterEndpoint, setScriptSplitterEndpoint] = useState(config.getScriptSplitterEndpoint()); - const [scriptSplitterThreshold, setScriptSplitterThreshold] = useState(config.getScriptSplitterThreshold()); - - const modeler = getModeler(); - - const editorActions = modeler.get('editorActions'); - const eventBus = modeler.get('eventBus'); - - // register editor action listener for changes in config entries - if (!editorActions._actions.hasOwnProperty('transformationFrameworkEndpointChanged')) { - editorActions.register({ - transformationFrameworkEndpointChanged: function (transformationFrameworkEndpoint) { - modeler.config.transformationFrameworkEndpoint = transformationFrameworkEndpoint; - } - }); - } - if (!editorActions._actions.hasOwnProperty('scriptSplitterEndpointChanged')) { - editorActions.register({ - scriptSplitterEndpointChanged: function (scriptSplitterEndpoint) { - modeler.config.scriptSplitterEndpoint = scriptSplitterEndpoint; - eventBus.fire('config.updated', self.modeler.config); - } - }); - } - if (!editorActions._actions.hasOwnProperty('scriptSplitterThresholdChanged')) { - editorActions.register({ - scriptSplitterThresholdChanged: function (scriptSplitterEndpoint) { - modeler.config.scriptSplitterThreshold = scriptSplitterEndpoint; - } - }); - } - - // save changed config entries on close - BPMNConfigTab.prototype.onClose = () => { - modeler.config.transformationFrameworkEndpoint = transformationFrameworkEndpoint; - modeler.config.scriptSplitterEndpoint = scriptSplitterEndpoint; - modeler.config.scriptSplitterThreshold = scriptSplitterThreshold; - config.setTransformationFrameworkEndpoint(transformationFrameworkEndpoint); - config.setScriptSplitterEndpoint(scriptSplitterEndpoint); - config.setScriptSplitterThreshold(scriptSplitterThreshold); - }; - - return <> -

BPMN related configurations:

- - - - - - - -
QuantME Framework Endpoint - setTransformationFrameworkEndpoint(event.target.value)}/> -
-

Workflow generation:

- - - - - - - - - - - -
Script Splitter Endpoint - setScriptSplitterEndpoint(event.target.value)}/> -
Script Splitter Threshold - setScriptSplitterThreshold(event.target.value)}/> -
- ; -} - -BPMNConfigTab.prototype.config = () => { - const modeler = getModeler(); - - modeler.config.transformationFrameworkEndpoint = config.getTransformationFrameworkEndpoint(); - modeler.config.scriptSplitterEndpoint = config.getScriptSplitterEndpoint(); - modeler.config.scriptSplitterThreshold = config.getScriptSplitterThreshold(); -}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/UploadTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/GitHubTab.js similarity index 53% rename from components/bpmn-q/modeler-component/extensions/quantme/configTabs/UploadTab.js rename to components/bpmn-q/modeler-component/extensions/quantme/configTabs/GitHubTab.js index 66624d03..e99c95f8 100644 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/UploadTab.js +++ b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/GitHubTab.js @@ -9,8 +9,12 @@ import * as config from "../framework-config/config-manager"; * @return {JSX.Element} The tab as a React component * @constructor */ -export default function UploadTab() { +export default function GitHubTab() { + const [githubRepositoryName, setGithubRepositoryName] = useState(config.getQRMRepositoryName()); + const [githubUsername, setGithubUsername] = useState(config.getQRMRepositoryUserName()); + const [githubRepositoryPath, setGithubRepositoryPath] = useState(config.getQRMRepositoryPath()); + const [githubToken, setGitHubToken] = useState(config.getGitHubToken()); const [uploadGithubRepositoryName, setUploadGithubRepositoryName] = useState(config.getUploadGithubRepositoryName()); const [uploadGithubOwner, setUploadGithubOwner] = useState(config.getUploadGithubRepositoryOwner()); const [uploadFileName, setUploadFileName] = useState(config.getUploadFileName()); @@ -20,6 +24,35 @@ export default function UploadTab() { const editorActions = modeler.get('editorActions'); // register editor action listener for changes in config entries + if (!editorActions._actions.hasOwnProperty('qrmRepoNameChanged')) { + editorActions.register({ + qrmRepoNameChanged: function (qrmRepoName) { + self.modeler.config.githubRepositoryName = qrmRepoName; + } + }); + } + if (!editorActions._actions.hasOwnProperty('qrmUserNameChanged')) { + editorActions.register({ + qrmUserNameChanged: function (qrmUserName) { + self.modeler.config.githubUsername = qrmUserName; + } + }); + } + if (!editorActions._actions.hasOwnProperty('qrmRepoPathChanged')) { + editorActions.register({ + qrmRepoPathChanged: function (qrmRepoPath) { + self.modeler.config.githubRepositoryPath = qrmRepoPath; + } + }); + } + if (!editorActions._actions.hasOwnProperty('githubTokenChanged')) { + editorActions.register({ + githubTokenChanged: function (githubToken) { + self.modeler.config.githubToken = githubToken; + } + }); + } + if (!editorActions._actions.hasOwnProperty('uploadGithubRepositoryNameChanged')) { editorActions.register({ uploadGithubRepositoryNameChanged: function (uploadGithubRepositoryName) { @@ -51,7 +84,11 @@ export default function UploadTab() { } // save changed config entries on close - UploadTab.prototype.onClose = () => { + GitHubTab.prototype.onClose = () => { + modeler.config.githubRepositoryName = githubRepositoryName; + modeler.config.githubUsername = githubUsername; + modeler.config.githubRepositoryPath = githubRepositoryPath; + modeler.config.githubToken = githubToken; modeler.config.uploadGithubRepositoryName = uploadGithubRepositoryName; modeler.config.uploadGithubRepositoryOwner = uploadGithubOwner; modeler.config.uploadFileName = uploadFileName; @@ -61,10 +98,63 @@ export default function UploadTab() { config.setUploadGithubRepositoryOwner(uploadGithubOwner); config.setUploadFileName(uploadFileName); config.setUploadBranchName(uploadBranchName); - + config.setQRMRepositoryName(githubRepositoryName); + config.setQRMUserName(githubUsername); + config.setQRMRepositoryPath(githubRepositoryPath); + config.setGitHubToken(githubToken); }; return <> +

QRM Data

+ + + + + + + + + + + + + + + +
QRM Repository User: + setGithubUsername(event.target.value)}/> +
QRM Repository Name: + setGithubRepositoryName(event.target.value)}/> +
QRM Repository Path: + setGithubRepositoryPath(event.target.value)}/> +
+

GitHub Authentication

+ + + + + + + +
GitHub Token [1]: + setGitHubToken(event.target.value)}/> +

Upload Data

@@ -113,9 +203,14 @@ export default function UploadTab() { ; } -UploadTab.prototype.config = () => { +GitHubTab.prototype.config = () => { const modeler = getModeler(); + modeler.config.githubRepositoryName = config.getQRMRepositoryName(); + modeler.config.githubUsername = config.getQRMRepositoryUserName(); + modeler.config.githubRepositoryPath = config.getQRMRepositoryPath(); + modeler.config.githubToken = config.getGitHubToken(); + modeler.config.uploadGithubRepositoryName = config.getUploadGithubRepositoryName(); modeler.config.uploadGithubRepositoryOwner = config.getUploadGithubRepositoryOwner(); modeler.config.uploadFileName = config.getUploadFileName(); diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/HybridRuntimeTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/HybridRuntimeTab.js deleted file mode 100644 index 7a4b370d..00000000 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/HybridRuntimeTab.js +++ /dev/null @@ -1,114 +0,0 @@ -import React, {useState} from 'react'; -import {getModeler} from "../../../editor/ModelerHandler"; -import * as config from "../framework-config/config-manager"; - -/** - * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change the - * hybrid runtime configs. - * - * @return {JSX.Element} The tab as a React component - * @constructor - */ -export default function HybridRuntimeTab() { - - const [qiskitRuntimeHandlerEndpoint, setQiskitRuntimeHandlerEndpoint] = useState(config.getQiskitRuntimeHandlerEndpoint()); - const [hybridRuntimeProvenance, setHybridRuntimeProvenance] = useState(config.getHybridRuntimeProvenance()); - const [awsRuntimeHandlerEndpoint, setAWSRuntimeHandlerEndpoint] = useState(config.getAWSRuntimeHandlerEndpoint()); - - let hybridRuntimeProvenanceBoolean = hybridRuntimeProvenance; - - const modeler = getModeler(); - - const editorActions = modeler.get('editorActions'); - const eventBus = modeler.get('eventBus'); - - // register editor action listener for changes in config entries - if (!editorActions._actions.hasOwnProperty('qiskitRuntimeHandlerEndpointChanged')) { - editorActions.register({ - qiskitRuntimeHandlerEndpointChanged: function (qiskitRuntimeHandlerEndpoint) { - self.modeler.config.qiskitRuntimeHandlerEndpoint = qiskitRuntimeHandlerEndpoint; - eventBus.fire('config.updated', self.modeler.config); - } - }); - } - if (!editorActions._actions.hasOwnProperty('awsRuntimeHandlerEndpointChanged')) { - editorActions.register({ - awsRuntimeHandlerEndpointChanged: function (awsRuntimeHandlerEndpoint) { - self.modeler.config.awsRuntimeHandlerEndpoint = awsRuntimeHandlerEndpoint; - eventBus.fire('config.updated', self.modeler.config); - } - }); - } - if (!editorActions._actions.hasOwnProperty('hybridRuntimeProvenanceChanged')) { - editorActions.register({ - hybridRuntimeProvenanceChanged: function (hybridRuntimeProvenance) { - self.modeler.config.hybridRuntimeProvenance = hybridRuntimeProvenance; - eventBus.fire('config.updated', self.modeler.config); - } - }); - } - - // save changed config entries on close - HybridRuntimeTab.prototype.onClose = () => { - modeler.config.qiskitRuntimeHandlerEndpoint = qiskitRuntimeHandlerEndpoint; - modeler.config.hybridRuntimeProvenance = hybridRuntimeProvenance; - modeler.config.awsRuntimeHandlerEndpoint = awsRuntimeHandlerEndpoint; - config.setQiskitRuntimeHandlerEndpoint(qiskitRuntimeHandlerEndpoint); - config.setAWSRuntimeHandlerEndpoint(awsRuntimeHandlerEndpoint); - config.setHybridRuntimeProvenance(hybridRuntimeProvenance); - }; - - return (<> -

Hybrid Runtime Handler Endpoints

-
- - - - - - - - - - -
Qiskit Runtime Handler Endpoint: - setQiskitRuntimeHandlerEndpoint(event.target.value)}/> -
AWS Runtime Handler Endpoint: - setAWSRuntimeHandlerEndpoint(event.target.value)}/> -
-

Provenance Collection for Hybrid Runtime

- - - - - - - -
Retrieve Intermediate Results: - { - hybridRuntimeProvenanceBoolean = !hybridRuntimeProvenanceBoolean; - setHybridRuntimeProvenance(hybridRuntimeProvenanceBoolean); - }}/> -
- ); -} - -HybridRuntimeTab.prototype.config = () => { - const modeler = getModeler(); - - modeler.config.qiskitRuntimeHandlerEndpoint = config.getQiskitRuntimeHandlerEndpoint(); - modeler.config.hybridRuntimeProvenance = config.getHybridRuntimeProvenance(); - modeler.config.awsRuntimeHandlerEndpoint = config.getAWSRuntimeHandlerEndpoint(); -}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/NisqAnalyzerTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/NisqAnalyzerTab.js deleted file mode 100644 index 45bcdcd7..00000000 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/NisqAnalyzerTab.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, {useState} from 'react'; -import {getModeler} from "../../../editor/ModelerHandler"; -import * as config from "../framework-config/config-manager"; - -/** - * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change the - * NISQ analyzer endpoint. - * - * @return {JSX.Element} The tab as a React component - * @constructor - */ -export default function NisqAnalyzerTab() { - - const [nisqAnalyzerEndpoint, setNisqAnalyzerEndpoint] = useState(config.getNisqAnalyzerEndpoint()); - - const modeler = getModeler(); - - const editorActions = modeler.get('editorActions'); - - // register editor action listener for changes in config entries - if (!editorActions._actions.hasOwnProperty('nisqAnalyzerEndpointChanged')) { - editorActions.register({ - nisqAnalyzerEndpointChanged: function (nisqAnalyzerEndpoint) { - self.modeler.config.nisqAnalyzerEndpoint = nisqAnalyzerEndpoint; - } - }); - } - - // save changed config entries on close - NisqAnalyzerTab.prototype.onClose = () => { - modeler.config.nisqAnalyzerEndpoint = nisqAnalyzerEndpoint; - config.setNisqAnalyzerEndpoint(nisqAnalyzerEndpoint); - }; - - return <> -

NISQ Analyzer

- - - - - - - -
NISQ Analyzer Endpoint: - setNisqAnalyzerEndpoint(event.target.value)}/> -
- ; -} - -NisqAnalyzerTab.prototype.config = () => { - const modeler = getModeler(); - - modeler.config.nisqAnalyzerEndpoint = config.getNisqAnalyzerEndpoint(); -}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/OpenToscaTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/OpenToscaTab.js deleted file mode 100644 index 2cf3550b..00000000 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/OpenToscaTab.js +++ /dev/null @@ -1,81 +0,0 @@ -import React, {useState} from 'react'; -import {getModeler} from "../../../editor/ModelerHandler"; -import * as config from "../framework-config/config-manager"; - -/** - * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change the - * OpenTOSCA and Winery endpoint. - * - * @return {JSX.Element} The tab as a React component - * @constructor - */ -export default function OpenToscaTab() { - - const [opentoscaEndpoint, setOpentoscaEndpoint] = useState(config.getOpenTOSCAEndpoint()); - const [wineryEndpoint, setWineryEndpoint] = useState(config.getWineryEndpoint()); - - const modeler = getModeler(); - - const editorActions = modeler.get('editorActions'); - const eventBus = modeler.get('eventBus'); - - // register editor action listener for changes in config entries - if (!editorActions._actions.hasOwnProperty('opentoscaEndpointChanged')) { - editorActions.register({ - opentoscaEndpointChanged: function (opentoscaEndpoint) { - self.modeler.config.opentoscaEndpoint = opentoscaEndpoint; - } - }); - } - if (!editorActions._actions.hasOwnProperty('wineryEndpointChanged')) { - editorActions.register({ - wineryEndpointChanged: function (wineryEndpoint) { - self.modeler.config.wineryEndpoint = wineryEndpoint; - eventBus.fire('config.updated', self.modeler.config); - } - }); - } - - // save changed config entries on close - OpenToscaTab.prototype.onClose = () => { - modeler.config.opentoscaEndpoint = opentoscaEndpoint; - modeler.config.wineryEndpoint = wineryEndpoint; - config.setOpenTOSCAEndpoint(opentoscaEndpoint); - config.setWineryEndpoint(wineryEndpoint); - }; - - return <> -

OpenTOSCA

- - - - - - - - - - - -
OpenTOSCA Endpoint: - setOpentoscaEndpoint(event.target.value)}/> -
Winery Endpoint: - setWineryEndpoint(event.target.value)}/> -
- ; -} - -OpenToscaTab.prototype.config = () => { - const modeler = getModeler(); - - modeler.config.opentoscaEndpoint = config.getOpenTOSCAEndpoint(); - modeler.config.wineryEndpoint = config.getWineryEndpoint(); -}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QrmDataTab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QrmDataTab.js deleted file mode 100644 index 6a2b7068..00000000 --- a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QrmDataTab.js +++ /dev/null @@ -1,126 +0,0 @@ -import React, {useState} from 'react'; -import {getModeler} from "../../../editor/ModelerHandler"; -import * as config from "../framework-config/config-manager"; - -/** - * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change the - * QRM data. - * - * @return {JSX.Element} The tab as a React component - * @constructor - */ -export default function QrmDataTab() { - - const [githubRepositoryName, setGithubRepositoryName] = useState(config.getQRMRepositoryName()); - const [githubUsername, setGithubUsername] = useState(config.getQRMRepositoryUserName()); - const [githubRepositoryPath, setGithubRepositoryPath] = useState(config.getQRMRepositoryPath()); - const [githubToken, setGitHubToken] = useState(config.getGitHubToken()); - const modeler = getModeler(); - - const editorActions = modeler.get('editorActions'); - - // register editor action listener for changes in config entries - if (!editorActions._actions.hasOwnProperty('qrmRepoNameChanged')) { - editorActions.register({ - qrmRepoNameChanged: function (qrmRepoName) { - self.modeler.config.githubRepositoryName = qrmRepoName; - } - }); - } - if (!editorActions._actions.hasOwnProperty('qrmUserNameChanged')) { - editorActions.register({ - qrmUserNameChanged: function (qrmUserName) { - self.modeler.config.githubUsername = qrmUserName; - } - }); - } - if (!editorActions._actions.hasOwnProperty('qrmRepoPathChanged')) { - editorActions.register({ - qrmRepoPathChanged: function (qrmRepoPath) { - self.modeler.config.githubRepositoryPath = qrmRepoPath; - } - }); - } - if (!editorActions._actions.hasOwnProperty('githubTokenChanged')) { - editorActions.register({ - githubTokenChanged: function (githubToken) { - self.modeler.config.githubToken = githubToken; - } - }); - } - - // save changed config entries on close - QrmDataTab.prototype.onClose = () => { - modeler.config.githubRepositoryName = githubRepositoryName; - modeler.config.githubUsername = githubUsername; - modeler.config.githubRepositoryPath = githubRepositoryPath; - modeler.config.githubToken = githubToken; - config.setQRMRepositoryName(githubRepositoryName); - config.setQRMUserName(githubUsername); - config.setQRMRepositoryPath(githubRepositoryPath); - config.setGitHubToken(githubToken); - }; - - return <> -

QRM Data

- - - - - - - - - - - - - - - -
QRM Repository User: - setGithubUsername(event.target.value)}/> -
QRM Repository Name: - setGithubRepositoryName(event.target.value)}/> -
QRM Repository Path: - setGithubRepositoryPath(event.target.value)}/> -
-

GitHub Authentication

- - - - - - - -
GitHub Token [1]: - setGitHubToken(event.target.value)}/> -
- ; -} - -QrmDataTab.prototype.config = () => { - const modeler = getModeler(); - - modeler.config.githubRepositoryName = config.getQRMRepositoryName(); - modeler.config.githubUsername = config.getQRMRepositoryUserName(); - modeler.config.githubRepositoryPath = config.getQRMRepositoryPath(); - modeler.config.githubToken = config.getGitHubToken(); - -}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QuantMETab.js b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QuantMETab.js new file mode 100644 index 00000000..dbd5cc07 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/quantme/configTabs/QuantMETab.js @@ -0,0 +1,273 @@ +import React, { useState } from 'react'; +import { getModeler } from '../../../editor/ModelerHandler'; +import * as config from '../framework-config/config-manager'; + +/** + * React component specifying a tab for the configuration dialog of the modeler. The tab allows the user to change workflow + * related configuration entries of the QuantME configs. + * + * @return {JSX.Element} The tab as a React component + * @constructor + */ +export default function BPMNConfigTab() { + const [dataConfigurationsEndpoint, setDataConfigurationsEndpoint] = useState(config.getQuantMEDataConfigurationsEndpoint()); + + const [opentoscaEndpoint, setOpentoscaEndpoint] = useState(config.getOpenTOSCAEndpoint()); + const [wineryEndpoint, setWineryEndpoint] = useState(config.getWineryEndpoint()); + const [nisqAnalyzerEndpoint, setNisqAnalyzerEndpoint] = useState(config.getNisqAnalyzerEndpoint()); + const [qiskitRuntimeHandlerEndpoint, setQiskitRuntimeHandlerEndpoint] = useState(config.getQiskitRuntimeHandlerEndpoint()); + const [hybridRuntimeProvenance, setHybridRuntimeProvenance] = useState(config.getHybridRuntimeProvenance()); + const [awsRuntimeHandlerEndpoint, setAWSRuntimeHandlerEndpoint] = useState(config.getAWSRuntimeHandlerEndpoint()); + const [transformationFrameworkEndpoint, setTransformationFrameworkEndpoint] = useState(config.getTransformationFrameworkEndpoint()); + const [scriptSplitterEndpoint, setScriptSplitterEndpoint] = useState(config.getScriptSplitterEndpoint()); + const [scriptSplitterThreshold, setScriptSplitterThreshold] = useState(config.getScriptSplitterThreshold()); + let hybridRuntimeProvenanceBoolean = hybridRuntimeProvenance; + + const modeler = getModeler(); + + const editorActions = modeler.get('editorActions'); + const eventBus = modeler.get('eventBus'); + + // register editor action listener for changes in config entries + if (!editorActions._actions.hasOwnProperty('qiskitRuntimeHandlerEndpointChanged')) { + editorActions.register({ + qiskitRuntimeHandlerEndpointChanged: function (qiskitRuntimeHandlerEndpoint) { + self.modeler.config.qiskitRuntimeHandlerEndpoint = qiskitRuntimeHandlerEndpoint; + eventBus.fire('config.updated', self.modeler.config); + } + }); + } + if (!editorActions._actions.hasOwnProperty('awsRuntimeHandlerEndpointChanged')) { + editorActions.register({ + awsRuntimeHandlerEndpointChanged: function (awsRuntimeHandlerEndpoint) { + self.modeler.config.awsRuntimeHandlerEndpoint = awsRuntimeHandlerEndpoint; + eventBus.fire('config.updated', self.modeler.config); + } + }); + } + if (!editorActions._actions.hasOwnProperty('hybridRuntimeProvenanceChanged')) { + editorActions.register({ + hybridRuntimeProvenanceChanged: function (hybridRuntimeProvenance) { + self.modeler.config.hybridRuntimeProvenance = hybridRuntimeProvenance; + eventBus.fire('config.updated', self.modeler.config); + } + }); + } + if (!editorActions._actions.hasOwnProperty('opentoscaEndpointChanged')) { + editorActions.register({ + opentoscaEndpointChanged: function (opentoscaEndpoint) { + self.modeler.config.opentoscaEndpoint = opentoscaEndpoint; + } + }); + } + if (!editorActions._actions.hasOwnProperty('wineryEndpointChanged')) { + editorActions.register({ + wineryEndpointChanged: function (wineryEndpoint) { + self.modeler.config.wineryEndpoint = wineryEndpoint; + eventBus.fire('config.updated', self.modeler.config); + } + }); + } + if (!editorActions._actions.hasOwnProperty('nisqAnalyzerEndpointChanged')) { + editorActions.register({ + nisqAnalyzerEndpointChanged: function (nisqAnalyzerEndpoint) { + self.modeler.config.nisqAnalyzerEndpoint = nisqAnalyzerEndpoint; + } + }); + } + if (!editorActions._actions.hasOwnProperty('transformationFrameworkEndpointChanged')) { + editorActions.register({ + transformationFrameworkEndpointChanged: function (transformationFrameworkEndpoint) { + modeler.config.transformationFrameworkEndpoint = transformationFrameworkEndpoint; + } + }); + } + if (!editorActions._actions.hasOwnProperty('scriptSplitterEndpointChanged')) { + editorActions.register({ + scriptSplitterEndpointChanged: function (scriptSplitterEndpoint) { + modeler.config.scriptSplitterEndpoint = scriptSplitterEndpoint; + eventBus.fire('config.updated', self.modeler.config); + } + }); + } + if (!editorActions._actions.hasOwnProperty('scriptSplitterThresholdChanged')) { + editorActions.register({ + scriptSplitterThresholdChanged: function (scriptSplitterEndpoint) { + modeler.config.scriptSplitterThreshold = scriptSplitterEndpoint; + } + }); + } + + // save changed config entries on close + BPMNConfigTab.prototype.onClose = () => { + modeler.config.dataConfigurationsEndpoint = dataConfigurationsEndpoint; + modeler.config.opentoscaEndpoint = opentoscaEndpoint; + modeler.config.wineryEndpoint = wineryEndpoint; + modeler.config.nisqAnalyzerEndpoint = nisqAnalyzerEndpoint; + modeler.config.transformationFrameworkEndpoint = transformationFrameworkEndpoint; + modeler.config.scriptSplitterEndpoint = scriptSplitterEndpoint; + modeler.config.scriptSplitterThreshold = scriptSplitterThreshold; + modeler.config.qiskitRuntimeHandlerEndpoint = qiskitRuntimeHandlerEndpoint; + modeler.config.hybridRuntimeProvenance = hybridRuntimeProvenance; + modeler.config.awsRuntimeHandlerEndpoint = awsRuntimeHandlerEndpoint; + config.setQuantMEDataConfigurationsEndpoint(dataConfigurationsEndpoint); + config.setOpenTOSCAEndpoint(opentoscaEndpoint); + config.setWineryEndpoint(wineryEndpoint); + config.setNisqAnalyzerEndpoint(nisqAnalyzerEndpoint); + config.setTransformationFrameworkEndpoint(transformationFrameworkEndpoint); + config.setScriptSplitterEndpoint(scriptSplitterEndpoint); + config.setScriptSplitterThreshold(scriptSplitterThreshold); + config.setQiskitRuntimeHandlerEndpoint(qiskitRuntimeHandlerEndpoint); + config.setAWSRuntimeHandlerEndpoint(awsRuntimeHandlerEndpoint); + config.setHybridRuntimeProvenance(hybridRuntimeProvenance); + }; + + return <> +

QuantME data configuration endpoint:

+ + + + + + + +
Data Configurations Endpoint + setDataConfigurationsEndpoint(event.target.value)} /> +
+

OpenTOSCA

+ + + + + + + + + + + +
OpenTOSCA Endpoint: + setOpentoscaEndpoint(event.target.value)} /> +
Winery Endpoint: + setWineryEndpoint(event.target.value)} /> +
+

BPMN related configurations:

+ + + + + + + +
QuantME Framework Endpoint + setTransformationFrameworkEndpoint(event.target.value)} /> +
+

NISQ Analyzer

+ + + + + + + +
NISQ Analyzer Endpoint: + setNisqAnalyzerEndpoint(event.target.value)} /> +
+

Workflow generation:

+ + + + + + + + + + + +
Script Splitter Endpoint + setScriptSplitterEndpoint(event.target.value)} /> +
Script Splitter Threshold + setScriptSplitterThreshold(event.target.value)} /> +
+

Hybrid Runtime Handler Endpoints

+ + + + + + + + + + + +
Qiskit Runtime Handler Endpoint: + setQiskitRuntimeHandlerEndpoint(event.target.value)} /> +
AWS Runtime Handler Endpoint: + setAWSRuntimeHandlerEndpoint(event.target.value)} /> +
+

Provenance Collection for Hybrid Runtime

+ + + + + + + +
Retrieve Intermediate Results: + { + hybridRuntimeProvenanceBoolean = !hybridRuntimeProvenanceBoolean; + setHybridRuntimeProvenance(hybridRuntimeProvenanceBoolean); + }} /> +
+ ; +} + +BPMNConfigTab.prototype.config = () => { + const modeler = getModeler(); + + modeler.config.transformationFrameworkEndpoint = config.getTransformationFrameworkEndpoint(); + modeler.config.scriptSplitterEndpoint = config.getScriptSplitterEndpoint(); + modeler.config.scriptSplitterThreshold = config.getScriptSplitterThreshold(); +}; \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/quantme/framework-config/config.js b/components/bpmn-q/modeler-component/extensions/quantme/framework-config/config.js index 10fba564..6bd1d91c 100644 --- a/components/bpmn-q/modeler-component/extensions/quantme/framework-config/config.js +++ b/components/bpmn-q/modeler-component/extensions/quantme/framework-config/config.js @@ -9,7 +9,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -// takes either the environment variables or the default values definded in webpack.config +// takes either the environment variables or the default values defined in webpack.config +// TODO: On change ALWAYS UPDATE corresponding doc: doc/quantum-workflow-modeler/modeler-configuration.md const defaultConfig = { quantmeDataConfigurationsEndpoint: process.env.DATA_CONFIG, opentoscaEndpoint: process.env.OPENTOSCA_ENDPOINT, diff --git a/components/bpmn-q/test/tests/editor/plugin.spec.js b/components/bpmn-q/test/tests/editor/plugin.spec.js index 271ea7c8..dfc50c1a 100644 --- a/components/bpmn-q/test/tests/editor/plugin.spec.js +++ b/components/bpmn-q/test/tests/editor/plugin.spec.js @@ -54,7 +54,7 @@ describe('Test plugins', function () { expect(extensions['planqk']).to.not.be.undefined; expect(transfButtons.length).to.equal(3); expect(buttons.length).to.equal(2); - expect(tabs.length).to.equal(9); + expect(tabs.length).to.equal(4); expect(styles.length).to.equal(3); }); }); diff --git a/components/bpmn-q/webpack.config.js b/components/bpmn-q/webpack.config.js index 85d9aaa8..d4037330 100644 --- a/components/bpmn-q/webpack.config.js +++ b/components/bpmn-q/webpack.config.js @@ -62,21 +62,22 @@ module.exports = { }), // use the default values if environment variable does not exist new webpack.EnvironmentPlugin({ + AUTOSAVE_INTERVAL: 300000, AWS_RUNTIME_HANDLER_ENDPOINT: 'http://localhost:8890', CAMUNDA_ENDPOINT: 'http://localhost:8080/engine-rest', DATA_CONFIG: 'http://localhost:8100/data-objects', - GITHUB_TOKEN: '', - NISQ_ANALYZER_ENDPOINT: 'http://localhost:8098/nisq-analyzer', - OPENTOSCA_ENDPOINT: 'http://localhost:1337/csars', - PROVENANCE_COLLECTION: false, DOWNLOAD_FILE_NAME: 'quantum-workflow-model', ENABLE_DATA_FLOW_PLUGIN: true, ENABLE_PLANQK_PLUGIN: true, ENABLE_QHANA_PLUGIN: true, ENABLE_QUANTME_PLUGIN: true, - QISKIT_RUNTIME_HANDLER_ENDPOINT: 'http://localhost:8889', + GITHUB_TOKEN: '', + OPENTOSCA_ENDPOINT: 'http://localhost:1337/csars', + NISQ_ANALYZER_ENDPOINT: 'http://localhost:8098/nisq-analyzer', + PROVENANCE_COLLECTION: false, QHANA_GET_PLUGIN_URL: 'http://localhost:5006/api/plugins/', QHANA_LIST_PLUGINS_URL: 'http://localhost:5006/api/plugins/?item-count=100', + QISKIT_RUNTIME_HANDLER_ENDPOINT: 'http://localhost:8889', QRM_USERNAME: '', QRM_REPONAME: '', QRM_REPOPATH: '', diff --git a/doc/quantum-workflow-modeler/extensions/plugins.md b/doc/quantum-workflow-modeler/extensions/plugins.md new file mode 100644 index 00000000..bc9462c5 --- /dev/null +++ b/doc/quantum-workflow-modeler/extensions/plugins.md @@ -0,0 +1,57 @@ +# Plugin Dependencies +Plugin dependencies are a way to establish relationships between different plugins. +A plugin dependency indicates that one plugin relies on another plugin to function properly. By defining plugin dependencies, you ensure that the required plugins are loaded and available before using a particular plugin. + +To add plugin dependencies, you typically need to follow these steps: + +1. Identify the plugins: Determine which plugins in your system have dependencies. Identify the plugins that require other plugins to be present and functional. + +2. Define & update the dependencies: For each plugin with dependencies, specify the required plugins. This can be done by associating the dependent plugin with the required plugins, i.e., by adding the plugin id to the dependency attribute. + +The following code snippet demonstrates how to define plugin dependencies using an array of plugins. +Exemplarily, we specify that the `QuantMEPlugin` depends on the `QHAanaPlugin`. + +```javascript +const PLUGINS = [ + { + plugin: DataFlowPlugin, + dependencies: [] + }, + { + plugin: QHAnaPlugin, + dependencies: [] + }, + { + plugin: PlanQKPlugin, + dependencies: [] + }, + { + plugin: QuantMEPlugin, + dependencies: ['QHAnaPlugin'] + } +]; +``` + +## Dependency resolution +The provided [code](../../../components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js#L38) handles transitive dependencies by using a recursive approach to load plugins and their dependencies. +Here is a breakdown of how the code handles transitive dependencies: + +1. Check if active plugins have already been determined: The function first checks if the `activePlugins` array has already been populated. If it contains plugins, indicating that the active plugins have already been determined, the function simply returns the `activePlugins` array. + +2. Determine active plugins and their dependencies: If the `activePlugins` array is empty, the function proceeds to determine the active plugins and their dependencies. + +3. Recursive loading of plugins and dependencies: The `loadPlugin` function is defined as a recursive function that takes a plugin as an argument. It checks if the plugin is already included in the `activePlugins` array. If it is not, it iterates over the plugin's `dependencies` array. + +4. Recursive dependency resolution: For each dependency, the function finds the corresponding plugin object from the `PLUGINS` array based on the dependency's name. If the dependency plugin is found, the `loadPlugin` function is recursively called with the dependency plugin as the argument. This allows the function to resolve dependencies at multiple levels, handling transitive dependencies. + +5. Add plugin to activePlugins: After resolving all dependencies, the plugin object is added to the `activePlugins` array. + +6. Iterate over plugin configurations: The function then iterates over the plugin configurations obtained from `getAllConfigs()`. + +7. Find enabled plugins: For each plugin configuration, the function finds the corresponding plugin object from the `PLUGINS` array based on the plugin's name. It also checks if the plugin is enabled by calling the `checkEnabledStatus` function. + +8. Load plugins and dependencies: If a plugin object is found, and it is enabled, the `loadPlugin` function is called with the plugin as the argument. This initiates the loading of the plugin and its dependencies. + +9. Return active plugins: Finally, the function returns the `activePlugins` array, which contains all the active plugins and their resolved dependencies. + +By recursively loading plugins and their dependencies, the code handles transitive dependencies, ensuring that all required plugins are loaded and added to the `activePlugins` array in the correct order. \ No newline at end of file diff --git a/doc/quantum-workflow-modeler/modeler-configuration.md b/doc/quantum-workflow-modeler/modeler-configuration.md new file mode 100644 index 00000000..958eab5c --- /dev/null +++ b/doc/quantum-workflow-modeler/modeler-configuration.md @@ -0,0 +1,53 @@ +# Environment Variables + +In the following, all environment variables that can be used to customize the workflow modeler are summarized. + +### Overview + +* ```AWS_RUNTIME_HANDLER_ENDPOINT``` (default 'http://localhost:8890'): Defines the endpoint of the [Amazon Braket Hybrid Jobs Handler](https://github.com/UST-QuAntiL/amazon-braket-hybrid-jobs-handler) which enables the automatic generation of hybrid programs from Amazon Braket programs. + +* ```CAMUNDA_ENDPOINT``` (default: 'http://localhost:8080/engine-rest'): Defines the endpoint of the Camunda engine to deploy workflows to. + +* ```DATA_CONFIG``` (default: 'http://localhost:8100/data-objects'): Defines the configuration of data objects. + +* ```ENABLE_DATA_FLOW_PLUGIN``` (default: 'true'): Defines if the Data Flow plugin is enabled. + +* ```ENABLE_PLANQK_PLUGIN``` (default: 'true'): Defines if the PlanQK plugin is enabled. + +* ```ENABLE_QHANA_PLUGIN``` (default: 'true'): Defines if the QHAna plugin is enabled. + +* ```ENABLE_QUANTME_PLUGIN``` (default: 'true'): Defines if the QuantME plugin is enabled. + +* ```GITHUB_TOKEN``` (default: ''): Defines the GitHub Token which can be used to make authorized requests. For more information take a look at [GitHub Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). + +* ```AUTOSAVE_INTERVAL``` (default ms: '300000'): Defines the interval of the auto save feature. If changes are applied to the workflow then it get saved after `5` minutes. + +* ```NISQ_ANALYZER_ENDPOINT``` (default: 'http://localhost:8098/nisq-analyzer'): Defines the endpoint of the [NISQ Analyzer](https://github.com/UST-QuAntiL/nisq-analyzer) to enable an automated hardware selection. + +* ```OPENTOSCA_ENDPOINT``` (default: 'http://localhost:1337/csars'): Defines the endpoint of the OpenTOSCA container to deploy services with. + +* ```QISKIT_RUNTIME_HANDLER_ENDPOINT``` (default: 'http://localhost:8889'): Defines the endpoint of the [Qiskit Runtime Handler](https://github.com/UST-QuAntiL/qiskit-runtime-handler) which enables the automatic generation of hybrid programs from Qiskit programs. + +* ```QHANA_GET_PLUGIN_URL``` (default: 'http://localhost:5006/api/plugins/'): Defines the plugin url for QHAna. + +* ```QHANA_LIST_PLUGINS_URL``` (default: 'http://localhost:5006/api/plugins/?item-count=100'): Defines the plugin list url for QHAna. + +* ```QRM_USERNAME``` (default: ' '): Defines the GitHub username to access the [QRM-Repository](../QRM-Repository) + +* ```QRM_REPONAME``` (default: ' '): Defines the GitHub repository name to access the [QRM-Repository](../QRM-Repository) + +* ```QRM_REPOPATH``` (default: ' '): Defines the local path in the GitHub repository to the folder containing the [QRM-Repository](../QRM-Repository). This parameter is optional and if it is not set, the root folder of the repository is used. + +* ```SERVICE_DATA_CONFIG``` (default: 'http://localhost:8000/service-task'): Defines the configuration for the service task. + +* ```SCRIPT_SPLITTER_EDNPOINT``` (default: 'http://localhost:8891'): Defines the endpoint of the Script Splitter. + +* ```SCRIPT_SPLITTER_THRESHOLD``` (default: '5'): Defines the splitting threshold for the Script Splitter. + +* ```TRANSFORMATION_FRAMEWORK_ENDPOINT``` (default: 'http://localhost:8888'): Defines the endpoint of the QuantME Transformation Framework to use for the automated hardware selection. + +* ```WINERY_ENDPOINT``` (default: 'http://localhost:8081/winery'): Defines the endpoint of the Winery to retrieve deployment models for services from. + +* ```PROVENANCE_COLLECTION``` (default: 'false'): Defines if the intermediate results of the workflow executed should be collected. + +The value of an environment variable is accessed using `process.env.ENV_NAME`. If you want to add a new environment variable, add it to the [webpack.config](../../../../../components/bpmn-q/webpack.config.js) file and restart the application. \ No newline at end of file