Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature plugin dependency & auto save #57

Merged
merged 30 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fedf03a
reorganize config, add option to specify plugin dependencies
LaviniaStiliadou May 30, 2023
6b822f1
integrate auto save
LaviniaStiliadou May 31, 2023
2685b69
set interval size with environment variable
LaviniaStiliadou May 31, 2023
0a7282d
restore transformation button
LaviniaStiliadou May 31, 2023
7d05b06
add missing imports
LaviniaStiliadou May 31, 2023
eefa1f9
adapt test
LaviniaStiliadou May 31, 2023
1d6a489
Merge branch 'master' of https://github.com/PlanQK/workflow-modeler i…
LaviniaStiliadou May 31, 2023
3fbe171
add doc for plugin dependencies
LaviniaStiliadou Jun 19, 2023
d01ef54
add overview to env variables
SharonNaemi Jun 19, 2023
fd566e4
add doc for auto save
LaviniaStiliadou Jun 19, 2023
a4b77e1
Merge branch 'master' of https://github.com/PlanQK/workflow-modeler i…
LaviniaStiliadou Jun 19, 2023
da998ea
Merge branch 'master' of https://github.com/PlanQK/workflow-modeler i…
LaviniaStiliadou Jun 20, 2023
a95cc4e
fix test
LaviniaStiliadou Jun 20, 2023
d66811c
integrate upload into github tab
LaviniaStiliadou Jun 20, 2023
7a769e1
Merge branch 'master' of https://github.com/PlanQK/workflow-modeler i…
LaviniaStiliadou Jun 21, 2023
bd6445c
Merge remote-tracking branch 'origin/master' into feature/plugin-depe…
wederbn Jul 21, 2023
2e3d210
Small fixes
wederbn Jul 21, 2023
dd2c3a6
Remove redundant declaration
wederbn Jul 21, 2023
9739ce2
Small readme fixes
wederbn Jul 21, 2023
47538ab
Rename timeout interval environment variable
wederbn Jul 21, 2023
b65624b
Refactor QuantMETab
wederbn Jul 25, 2023
14fdb41
Remove deployment plugin
wederbn Jul 25, 2023
aaf4899
Rename QrmTab to GitHubTab
wederbn Jul 25, 2023
52e9bd4
enable config of auto save interval size
LaviniaStiliadou Jul 25, 2023
8cdef3d
Merge remote-tracking branch 'origin/master' into feature/plugin-depe…
wederbn Jul 25, 2023
5aeb69f
fix interval implementation
LaviniaStiliadou Jul 26, 2023
842ceaa
only save xml in interval if xml changed
LaviniaStiliadou Aug 21, 2023
95fe338
fix test
LaviniaStiliadou Aug 21, 2023
28f8eb9
adjust autosave filename
mbeisel Aug 21, 2023
5334300
reference doc in config
mbeisel Aug 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ export const workflowEventTypes = {
SAVED: 'quantum-workflow-saved', // Workflow saved
TRANSFORMED: 'quantum-workflow-transformed', // Workflow transformed
DEPLOYED: 'quantum-workflow-deployed', // Workflow deployed to workflow engine
};
};

export const autoSaveFile = {
INTERVAL: 'Interval',
ON_ACTION: 'On Action'
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {getPluginConfig} from '../plugin/PluginConfigHandler';
import {transformedWorkflowHandlers} from '../EditorConstants';
import {autoSaveFile, transformedWorkflowHandlers} from '../EditorConstants';

// default configurations of the editor
const defaultConfig = {
camundaEndpoint: process.env.CAMUNDA_ENDPOINT,
fileName: 'quantum-workflow-model.bpmn',
transformedWorkflowHandler: transformedWorkflowHandlers.NEW_TAB,
autoSaveFileOption: autoSaveFile.INTERVAL
};

let config = {};
Expand Down Expand Up @@ -88,6 +89,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;
}
}

/**
* Resets the current editor configs
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useState} from 'react';
import {getModeler} from "../ModelerHandler";
import * as editorConfig from "./EditorConfigManager";
import {transformedWorkflowHandlers} from '../EditorConstants';
import {autoSaveFile, transformedWorkflowHandlers} from '../EditorConstants';

/**
* Tab for the ConfigModal. Used to allow the configurations of the editor configs, namely the camunda endpoint and the
Expand All @@ -14,6 +14,7 @@ export default function EditorTab() {

const [camundaEndpoint, setCamundaEndpoint] = useState(editorConfig.getCamundaEndpoint());
const [workflowHandler, setWorkflowHandler] = useState(editorConfig.getTransformedWorkflowHandler());
const [autoSaveFileOption, setAutoSaveFileOption] = useState(editorConfig.getAutoSaveFileOption());

const modeler = getModeler();

Expand All @@ -33,6 +34,7 @@ export default function EditorTab() {
modeler.config.camundaEndpoint = camundaEndpoint;
editorConfig.setCamundaEndpoint(camundaEndpoint);
editorConfig.setTransformedWorkflowHandler(workflowHandler);
editorConfig.setAutoSaveFileOption(autoSaveFileOption);
};

// return tab which contains entries to change the camunda endpoint and the workflow handler
Expand Down Expand Up @@ -73,6 +75,26 @@ export default function EditorTab() {
</tr>
</tbody>
</table>
<h3>Auto save file:</h3>
<table>
<tbody>
<tr className="spaceUnder">
<td align="right">Auto save file option:</td>
<td align="left">
<select
name="autoSaveFileOption"
value={autoSaveFileOption}
onChange={event => setAutoSaveFileOption(event.target.value)}>
{Object.entries(autoSaveFile).map(([key, value]) => (
<option key={value} value={value}>
{value}
</option>
))}
</select>
</td>
</tr>
</tbody>
</table>
</>);
}

Expand Down
80 changes: 50 additions & 30 deletions components/bpmn-q/modeler-component/editor/plugin/PluginHandler.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,76 @@
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
* get the extensions the plugins define.
*/

// 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':
Expand Down Expand Up @@ -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: 'QRMDataTab',
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);
}
}
Expand Down
57 changes: 47 additions & 10 deletions components/bpmn-q/modeler-component/editor/util/IoUtilities.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {transformedWorkflowHandlers, workflowEventTypes} from '../EditorConstants';
import {dispatchWorkflowEvent} from '../events/EditorEventHandler';
import { autoSaveFile, transformedWorkflowHandlers, workflowEventTypes } from '../EditorConstants';
import { getModeler } from '../ModelerHandler';
import { dispatchWorkflowEvent } from '../events/EditorEventHandler';

const editorConfig = require('../config/EditorConfigManager');

Expand Down Expand Up @@ -29,7 +30,7 @@ const NEW_DIAGRAM_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
* @returns {Promise<void>}
*/
export async function saveXmlAsLocalFile(xml, fileName = editorConfig.getFileName()) {
const bpmnFile = await new File([xml], fileName, {type: 'text/xml'});
const bpmnFile = await new File([xml], fileName, { type: 'text/xml' });

const link = document.createElement('a');
link.download = fileName;
Expand Down Expand Up @@ -58,7 +59,7 @@ export async function saveModelerAsLocalFile(modeler, fileName = editorConfig.ge
* @returns {Promise<*>} The xml diagram.
*/
export async function getXml(modeler) {
const {xml} = await modeler.saveXML({format: true});
const { xml } = await modeler.saveXML({ format: true });
return xml;
}

Expand All @@ -83,7 +84,7 @@ export async function loadDiagram(xml, modeler, dispatchEvent = true) {
} catch (err) {
console.error(err);

return {error: err};
return { error: err };
}
}

Expand Down Expand Up @@ -120,7 +121,7 @@ export async function deployWorkflowToCamunda(workflowName, workflowXml, viewMap
}

// add diagram to the body
const bpmnFile = new File([workflowXml], fileName, {type: 'text/xml'});
const bpmnFile = new File([workflowXml], fileName, { type: 'text/xml' });
form.append('data', bpmnFile);

// upload all provided views
Expand Down Expand Up @@ -151,7 +152,7 @@ export async function deployWorkflowToCamunda(workflowName, workflowXml, viewMap
// abort if there is not exactly one deployed process definition
if (Object.values(result['deployedProcessDefinitions'] || {}).length !== 1) {
console.error('Invalid size of deployed process definitions list: ' + Object.values(result['deployedProcessDefinitions'] || {}).length);
return {status: 'failed'};
return { status: 'failed' };
}

dispatchWorkflowEvent(workflowEventTypes.DEPLOYED, workflowXml, workflowName);
Expand All @@ -162,11 +163,11 @@ export async function deployWorkflowToCamunda(workflowName, workflowXml, viewMap
};
} else {
console.error('Deployment of workflow returned invalid status code: %s', response.status);
return {status: 'failed'};
return { status: 'failed' };
}
} catch (error) {
console.error('Error while executing post to deploy workflow: ' + error);
return {status: 'failed'};
return { status: 'failed' };
}
}

Expand Down Expand Up @@ -215,6 +216,42 @@ export function openInNewTab(workflowXml, fileName) {
newWindow.onload = function () {

// Pass the XML string to the new window using postMessage
newWindow.postMessage({workflow: workflowXml, name: fileName}, window.location.href);
newWindow.postMessage({ workflow: workflowXml, name: fileName }, window.location.href);
};
}


export function resetAutosaveTimeout(autosaveTimeout, hasChanges, autoSaveFileOption = editorConfig.getAutoSaveFileOption()) {
clearTimeout(autosaveTimeout);
hasChanges = hasChanges;

if (autoSaveFileOption === autoSaveFile.INTERVAL) {
autosaveTimeout = setTimeout(() => autosave(hasChanges), process.env.INTERVAL);
} else {
const timestamp = getTimestamp();
saveModelerAsLocalFile(getModeler(), `autosave_${timestamp}_${editorConfig.getFileName()}`)
}
}

function autosave(hasChanges) {
if (hasChanges) {
// extract the xml and save it to a file
getModeler().saveXML({ format: true }, function (err, xml) {
if (!err) {
// Save the XML
console.log('Autosaved:', xml);
const timestamp = getTimestamp();
saveXmlAsLocalFile(xml, `autosave_${timestamp}_${editorConfig.getFileName()}`)
}
});
}

// Reset the timer after the autosave is completed
resetAutosaveTimeout();
}

function getTimestamp() {
const date = new Date();
const timestamp = date.toISOString().replace(/:/g, '-');
return timestamp;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default {
configTabs: [
{
tabId: 'DataEndpointsTab',
tabTitle: 'Data Endpoints',
tabTitle: 'Data Flow Plugin',
configTab: TransformationTaskConfigurationsTab,
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
isAny
} from 'bpmn-js/lib/features/modeling/util/ModelingUtil';
import * as consts from '../Constants';
import { isConnectedWith } from '../../../editor/util/ModellingUtilities';
import {isConnectedWith} from '../../../editor/util/ModellingUtilities';
import { resetAutosaveTimeout } from '../../../editor/util/IoUtilities';

/**
* Custom rules provider for the DataFlow elements. Extends the BpmnRules.
Expand All @@ -17,6 +18,7 @@ export default class CustomRulesProvider extends BpmnRules {
const canConnectDataExtension = this.canConnectDataExtension;
const canConnect = this.canConnect.bind(this);
const canCreate = this.canCreate.bind(this);
let autosaveTimeout = 0;

// persist into local storage whenever
// copy took place
Expand Down Expand Up @@ -65,6 +67,12 @@ export default class CustomRulesProvider extends BpmnRules {
context.position
);
});

eventBus.on("commandStack.changed", function() {

// Reset the timeout on any change event
resetAutosaveTimeout(autosaveTimeout, true);
});
}

/**
Expand Down
Loading