From a0ac7d51c7a9acd3481656f708a39b1ccc3f8a07 Mon Sep 17 00:00:00 2001
From: Sebastian Listl <s.listl@adito.de>
Date: Tue, 27 Oct 2020 11:26:18 +0100
Subject: [PATCH] Marketing Workflow

---
 .../DocumentTemplatePlaceOfUse_entity.aod     |  4 +
 .../children/blacklist_param/valueProcess.js  |  2 +-
 .../getallcontexts_param/valueProcess.js      |  3 +
 .../MarketingWorkflowLauncher_entity.aod      | 85 +++++++++++++++++
 .../children/comingfrom_param/valueProcess.js |  4 +
 .../valueProcess.js                           |  4 +
 .../processvariables_param/valueProcess.js    |  7 ++
 .../targetcontext_param/valueProcess.js       |  4 +
 .../children/targets_param/valueProcess.js    | 13 +++
 .../validationerrors_param/valueProcess.js    |  4 +
 entity/Person_entity/Person_entity.aod        |  6 ++
 .../onActionProcess.js                        |  8 ++
 .../WorkflowDefinition_entity.aod             |  6 ++
 .../WorkflowInstance_entity.aod               |  6 +-
 .../recordcontainers/jdito/contentProcess.js  | 33 ++-----
 .../recordcontainers/jdito/onInsert.js        | 74 +++------------
 .../WorkflowLauncher_entity.aod               | 93 +++++++++++++++++++
 .../launchworkflows/onActionProcess.js        | 33 +++++++
 .../launchworkflows/stateProcess.js           |  8 ++
 .../processdefinition_id/valueProcess.js      |  7 ++
 .../startformdefinition/valueProcess.js       |  7 ++
 .../children/context_param/valueProcess.js    |  4 +
 .../workflowtargets/valueProcess.js           | 20 ++++
 .../WorkflowStartConfig_entity.aod            |  4 +
 .../getallcontexts_param/valueProcess.js      |  3 +
 .../MarketingWorkflowLauncher.aod             | 13 +++
 .../WorkflowLauncher/WorkflowLauncher.aod     | 12 +++
 .../MarketingWorkflowLauncherEdit_view.aod    | 30 ++++++
 .../PersonDuplicateEditview_view.aod          |  2 +
 .../PersonFilter_view/PersonFilter_view.aod   |  3 +
 .../PersonLookup_view/PersonLookup_view.aod   |  2 +
 .../PersonPreview_view/PersonPreview_view.aod |  1 +
 .../PersonSimpleList_view.aod                 |  5 +
 .../WorkflowInstancePreview_view.aod          |  1 +
 .../WorkflowLauncherEdit_view.aod             | 43 +++++++++
 process/Workflow_lib/process.js               | 62 ++++++++++---
 36 files changed, 508 insertions(+), 108 deletions(-)
 create mode 100644 entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/getallcontexts_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/comingfrom_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/documenttemplatetype_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targetcontext_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js
 create mode 100644 entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/validationerrors_param/valueProcess.js
 create mode 100644 entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/launchworkflows/onActionProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/launchworkflows/stateProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/processdefinition_id/valueProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/startformdefinition/valueProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/workflowdefinitions/children/context_param/valueProcess.js
 create mode 100644 entity/WorkflowLauncher_entity/entityfields/workflowtargets/valueProcess.js
 create mode 100644 entity/WorkflowStartConfig_entity/entityfields/contexts/children/getallcontexts_param/valueProcess.js
 create mode 100644 neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod
 create mode 100644 neonContext/WorkflowLauncher/WorkflowLauncher.aod
 create mode 100644 neonView/MarketingWorkflowLauncherEdit_view/MarketingWorkflowLauncherEdit_view.aod
 create mode 100644 neonView/WorkflowLauncherEdit_view/WorkflowLauncherEdit_view.aod

diff --git a/entity/DocumentTemplatePlaceOfUse_entity/DocumentTemplatePlaceOfUse_entity.aod b/entity/DocumentTemplatePlaceOfUse_entity/DocumentTemplatePlaceOfUse_entity.aod
index 3e77638a51c..6db556011a3 100644
--- a/entity/DocumentTemplatePlaceOfUse_entity/DocumentTemplatePlaceOfUse_entity.aod
+++ b/entity/DocumentTemplatePlaceOfUse_entity/DocumentTemplatePlaceOfUse_entity.aod
@@ -43,6 +43,10 @@
           <name>Blacklist_param</name>
           <valueProcess>%aditoprj%/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/blacklist_param/valueProcess.js</valueProcess>
         </entityParameter>
+        <entityParameter>
+          <name>GetAllContexts_param</name>
+          <valueProcess>%aditoprj%/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/getallcontexts_param/valueProcess.js</valueProcess>
+        </entityParameter>
       </children>
     </entityConsumer>
     <entityProvider>
diff --git a/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/blacklist_param/valueProcess.js b/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/blacklist_param/valueProcess.js
index 8f454703def..9d5b64bb873 100644
--- a/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/blacklist_param/valueProcess.js
+++ b/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/blacklist_param/valueProcess.js
@@ -1,3 +1,3 @@
 import("system.result");
 
-result.object(["Person", "Organisation", "Offer"]);
\ No newline at end of file
+result.object(["Person", "Organisation", "Offer", "MarketingWorkflowLauncher"]);
\ No newline at end of file
diff --git a/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/getallcontexts_param/valueProcess.js b/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/getallcontexts_param/valueProcess.js
new file mode 100644
index 00000000000..40effa01784
--- /dev/null
+++ b/entity/DocumentTemplatePlaceOfUse_entity/entityfields/contextdocumenttemplateplaceofuse/children/getallcontexts_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.result");
+
+result.string(true);
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod b/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod
new file mode 100644
index 00000000000..40b9b39c899
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/MarketingWorkflowLauncher_entity.aod
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.17" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.17">
+  <name>MarketingWorkflowLauncher_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <title>Marketing workflow</title>
+  <recordContainer>dataLess</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityProvider>
+      <name>#PROVIDER_AGGREGATES</name>
+      <useAggregates v="true" />
+    </entityProvider>
+    <entityField>
+      <name>DOCUMENTTEMPLATE_ID</name>
+      <title>Document template</title>
+      <consumer>EmailTemplates</consumer>
+      <mandatory v="true" />
+      <state>EDITABLE</state>
+    </entityField>
+    <entityConsumer>
+      <name>WorkflowLauncherIntegration</name>
+      <isOneToOneRelationship v="true" />
+      <dependency>
+        <name>dependency</name>
+        <entityName>WorkflowLauncher_entity</entityName>
+        <fieldName>Integration</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>Validationerrors_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/validationerrors_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>ProcessVariables_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>Targets_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>TargetContext_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targetcontext_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityParameter>
+      <name>ObjectType_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>ObjectIds_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>ObjectFilter_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityConsumer>
+      <name>EmailTemplates</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>DocumentTemplate_entity</entityName>
+        <fieldName>DocumentTemplateProvider</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>DocumentTemplateType_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/documenttemplatetype_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>ComingFrom_param</name>
+          <valueProcess>%aditoprj%/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/comingfrom_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+  </entityFields>
+  <recordContainers>
+    <datalessRecordContainer>
+      <name>dataLess</name>
+    </datalessRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/comingfrom_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/comingfrom_param/valueProcess.js
new file mode 100644
index 00000000000..cc6924394ae
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/comingfrom_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("Context_lib");
+import("system.result");
+
+result.string(ContextUtils.getCurrentContextId());
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/documenttemplatetype_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/documenttemplatetype_param/valueProcess.js
new file mode 100644
index 00000000000..28aacde92d6
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/emailtemplates/children/documenttemplatetype_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.result");
+import("KeywordRegistry_basic");
+
+result.string($KeywordRegistry.documentTemplateType$mail());
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js
new file mode 100644
index 00000000000..b81df3d4fb9
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/processvariables_param/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.vars");
+import("system.result");
+
+var variables = {
+    documentTemplate: vars.get("$field.DOCUMENTTEMPLATE_ID")
+};
+result.string(JSON.stringify(variables));
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targetcontext_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targetcontext_param/valueProcess.js
new file mode 100644
index 00000000000..cc6924394ae
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targetcontext_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("Context_lib");
+import("system.result");
+
+result.string(ContextUtils.getCurrentContextId());
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js
new file mode 100644
index 00000000000..6a28aafa528
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/targets_param/valueProcess.js
@@ -0,0 +1,13 @@
+import("Util_lib");
+import("system.vars");
+import("system.result");
+
+var context = vars.get("$param.ObjectType_param");
+var targets = Utils.parseJSON(vars.get("$param.ObjectIds_param")) || [];
+targets = targets.map(function (targetId)
+{
+    if (Utils.isString(targetId))
+        return [targetId, context]; //todo: context dynamic (eg for participants)
+    return targetId;
+});
+result.string(JSON.stringify(targets));
\ No newline at end of file
diff --git a/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/validationerrors_param/valueProcess.js b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/validationerrors_param/valueProcess.js
new file mode 100644
index 00000000000..30356844f1b
--- /dev/null
+++ b/entity/MarketingWorkflowLauncher_entity/entityfields/workflowlauncherintegration/children/validationerrors_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$sys.validationerrors"));
\ No newline at end of file
diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod
index 58638d3e713..c66ce949329 100644
--- a/entity/Person_entity/Person_entity.aod
+++ b/entity/Person_entity/Person_entity.aod
@@ -1097,6 +1097,12 @@
           <iconId>VAADIN:PLAY</iconId>
           <stateProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/startmultipleworkflows/stateProcess.js</stateProcess>
         </entityActionField>
+        <entityActionField>
+          <name>startMarketingWorkflows</name>
+          <title>Marketing Workflow</title>
+          <onActionProcess>%aditoprj%/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js</onActionProcess>
+          <isObjectAction v="false" />
+        </entityActionField>
       </children>
     </entityActionGroup>
     <entityActionGroup>
diff --git a/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js b/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js
new file mode 100644
index 00000000000..3e462ab4498
--- /dev/null
+++ b/entity/Person_entity/entityfields/filterviewactiongroup/children/startmarketingworkflows/onActionProcess.js
@@ -0,0 +1,8 @@
+import("Context_lib");
+import("system.vars");
+import("system.neon");
+
+neon.openContext("MarketingWorkflowLauncher", "MarketingWorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, {
+    "ObjectIds_param": JSON.stringify(vars.get("$sys.selection")),
+    "ObjectType_param": ContextUtils.getCurrentContextId()
+});
\ No newline at end of file
diff --git a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
index 6b03a4c7d18..ab10357478f 100644
--- a/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
+++ b/entity/WorkflowDefinition_entity/WorkflowDefinition_entity.aod
@@ -22,6 +22,12 @@
           <fieldName>WorkflowDefinitions</fieldName>
           <isConsumer v="false" />
         </entityDependency>
+        <entityDependency>
+          <name>8c60efea-5fa1-4df0-a6bb-9fadcc88554c</name>
+          <entityName>WorkflowLauncher_entity</entityName>
+          <fieldName>WorkflowDefinitions</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
       </dependencies>
     </entityProvider>
     <entityField>
diff --git a/entity/WorkflowInstance_entity/WorkflowInstance_entity.aod b/entity/WorkflowInstance_entity/WorkflowInstance_entity.aod
index a582194e6d2..566506952d1 100644
--- a/entity/WorkflowInstance_entity/WorkflowInstance_entity.aod
+++ b/entity/WorkflowInstance_entity/WorkflowInstance_entity.aod
@@ -120,10 +120,6 @@
       <name>TargetContext_param</name>
       <expose v="true" />
     </entityParameter>
-    <entityParameter>
-      <name>TargetIdFilter_param</name>
-      <expose v="true" />
-    </entityParameter>
     <entityActionField>
       <name>toggleActive</name>
       <title>${WORKFLOW_SUSPEND}</title>
@@ -211,7 +207,7 @@
     <jDitoRecordContainer>
       <name>jdito</name>
       <isFilterable v="true" />
-      <isSortable v="true" />
+      <isSortable v="false" />
       <contentProcess>%aditoprj%/entity/WorkflowInstance_entity/recordcontainers/jdito/contentProcess.js</contentProcess>
       <onInsert>%aditoprj%/entity/WorkflowInstance_entity/recordcontainers/jdito/onInsert.js</onInsert>
       <onUpdate>%aditoprj%/entity/WorkflowInstance_entity/recordcontainers/jdito/onUpdate.js</onUpdate>
diff --git a/entity/WorkflowInstance_entity/recordcontainers/jdito/contentProcess.js b/entity/WorkflowInstance_entity/recordcontainers/jdito/contentProcess.js
index 9c9bcb74769..4dd46c30f7a 100644
--- a/entity/WorkflowInstance_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/WorkflowInstance_entity/recordcontainers/jdito/contentProcess.js
@@ -27,12 +27,6 @@ if (idvalues)
         loadHistoricConfig.processInstanceIds(idvalues);
         historicInstances = JSON.parse(workflow.getHistoricProcessInstances(loadHistoricConfig));
     }
-    
-    //TODO: find a way the id can be gotten here
-    //after new-mode, only the workflow key is known, that means if with the given id
-    //no instance could be found, search with the key and use the item with the latest startTime
-    if (instances.length === 0 && historicInstances.length === 0)
-        instances = _getNewestInstanceForKey(idvalues[0]);
 }
 else
 {
@@ -78,25 +72,10 @@ historicInstances = historicInstances.map(function (instance)
     return row;
 });
 
-instances = JditoFilterUtils.filterRecords(["UID", "NAME", "KEY", "ISACTIVE", "PROCESSDEFINITIONNAME", "PROCESSDEFINITION_ID", "START_TIME", "ISFINISHED"], 
-    instances.concat(historicInstances), vars.get("$local.filter").filter);
-
-result.object(instances);
-
-
-function _getNewestInstanceForKey (pWorkflowKey)
-{
-    var loadConfig = workflow.createConfigForLoadingProcessInstances()
-        .processDefinitionKey(pWorkflowKey);
+var recordFilter = new JditoFilter()
+    .filter(vars.get("$local.filter"))
+    .fieldOrder(["UID", "NAME", "KEY", "ISACTIVE", "PROCESSDEFINITIONNAME", "PROCESSDEFINITION_ID", "START_TIME", "ISFINISHED"]);
     
-    var instances = JSON.parse(workflow.getProcessInstances(loadConfig));
-    if (instances.length === 0)
-        return [];
-    
-    return [instances.reduce(function (prev, curr)
-    {
-        if (Date.parse(prev.startTime) > Date.parse(curr.startTime))
-            return prev;
-        return curr;
-    })];
-}
\ No newline at end of file
+instances = recordFilter.filterRecords(instances.concat(historicInstances));
+
+result.object(instances);
\ No newline at end of file
diff --git a/entity/WorkflowInstance_entity/recordcontainers/jdito/onInsert.js b/entity/WorkflowInstance_entity/recordcontainers/jdito/onInsert.js
index 231b0214263..ad02408259c 100644
--- a/entity/WorkflowInstance_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/WorkflowInstance_entity/recordcontainers/jdito/onInsert.js
@@ -1,14 +1,12 @@
+import("system.neon");
 import("Util_lib");
-import("Employee_lib");
 import("system.entities");
 import("Context_lib");
 import("Workflow_lib");
 import("system.vars");
 import("system.workflow");
-import("system.process");
 
 var variables = Utils.parseJSON(vars.getString("$param.ProcessVariables_param")) || {};
-var targetIdFilter = Utils.parseJSON(vars.get("$param.TargetIdFilter_param"));
 var rowdata = vars.get("$local.rowdata");
 var processKey = rowdata["KEY.value"];
 var instanceName = rowdata["NAME.value"];
@@ -17,69 +15,23 @@ var startFormResult = Utils.parseJSON(rowdata["STARTFORMRESULT.value"]);
 if (!Utils.isNullOrEmpty(startFormResult))
     Object.assign(variables, startFormResult);
 
-//a placeholder that can be used for individual instance names, will be replaced by the content title
-var titlePlaceholder = "{title}";
-var fetchContentTitle = instanceName && instanceName.includes(titlePlaceholder);
-
 var targetId = variables[WorkflowVariables.TARGET_ID()];
-var targetContext = variables[WorkflowVariables.TARGET_CONTEXT()];
-var targetIds = [];
-if (Array.isArray(targetId) && targetId.length !== 0)
-{
-    targetIds = targetId.slice();
-    targetIdFilter = null;
-}
-else if (!Array.isArray(targetId) && targetId)
-{
-    targetIds = [targetId];
-    targetIdFilter = null;
-}    
+var targetContext = variables[WorkflowVariables.TARGET_CONTEXT()] || vars.get("$param.TargetContext_param");
 
-if (targetIdFilter || fetchContentTitle)
+//a placeholder that can be used for individual instance names, will be replaced by the content title
+instanceName = instanceName.replace("{title}", function ()
 {
     var entity = ContextUtils.getEntity(targetContext);
     var loadConfig = entities.createConfigForLoadingRows()
         .entity(entity)
-        .fields(["#UID", "#CONTENTTITLE"]);
-
-    if (targetIdFilter && targetIdFilter.filter)
-        loadConfig.filter(JSON.stringify(targetIdFilter.filter));
-    else if (targetIds.length !== 0)
-        loadConfig.uids(targetIds);
-    
-    var rowCount = entities.getRowCount(loadConfig);
-    var pageSize = 1000;
-    for (let startRow = 0; startRow < rowCount; startRow += pageSize)
-    {
-        loadConfig.startrow(startRow).count(pageSize);
-        let targetIdsAndNames = entities.getRows(loadConfig).map(function (row) 
-        {
-            var name = instanceName;
-            if (fetchContentTitle)
-                name = name.replace(titlePlaceholder, row["#CONTENTTITLE"]);
-            return [row["#UID"], name];
-        });
-        _startForIds(targetIdsAndNames, variables);
-    }
+        .fields(["#CONTENTTITLE"])
+        .uid(targetId);
+    var row = entities.getRow(loadConfig);
     
-//TODO: entities.getRows currently doesn't work on the server
-//    process.executeAsync("startWorkflowInstances_serverProcess", {
-//        processVariables : JSON.stringify(variables),
-//        processKey : processKey,
-//        entityFilter : targetIdFilter.filter ? JSON.stringify(targetIdFilter.filter) : ""
-//    },  false, EmployeeUtils.getCurrentUserName(), process.THREADPRIORITY_NORM, process.TIMERTYPE_SERVER);
-}
-else
-    _startForIds(targetIds.map(function (id) {return [id, instanceName];}), variables);
-
-function _startForIds (pTargets, pVariables)
-{
-    pTargets.forEach(function ([id, name]) 
-    {
-        pVariables[WorkflowVariables.TARGET_ID()] = id;
-        var instanceId = workflow.startProcessByKey(processKey, pVariables);
-        if (name)
-            workflow.setProcessInstanceName(instanceId, name);
-    });
-}
+    return row && row["#CONTENTTITLE"] || "";
+});
 
+var instanceId = workflow.startProcessByKey(processKey, pVariables);
+neon.setFieldValue("$field.UID", instanceId);
+if (name)
+    workflow.setProcessInstanceName(instanceId, name);
diff --git a/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod b/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod
new file mode 100644
index 00000000000..f1640dc1aac
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/WorkflowLauncher_entity.aod
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entity xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.3.17" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/entity/1.3.17">
+  <name>WorkflowLauncher_entity</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <recordContainer>dataLess</recordContainer>
+  <entityFields>
+    <entityProvider>
+      <name>#PROVIDER</name>
+    </entityProvider>
+    <entityProvider>
+      <name>#PROVIDER_AGGREGATES</name>
+      <useAggregates v="true" />
+    </entityProvider>
+    <entityField>
+      <name>PROCESSDEFINITION_ID</name>
+      <valueProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/processdefinition_id/valueProcess.js</valueProcess>
+    </entityField>
+    <entityField>
+      <name>STARTFORMDEFINITION</name>
+      <valueProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/startformdefinition/valueProcess.js</valueProcess>
+    </entityField>
+    <entityField>
+      <name>STARTFORMRESULT</name>
+    </entityField>
+    <entityField>
+      <name>NAME</name>
+      <title>Name</title>
+      <state>EDITABLE</state>
+    </entityField>
+    <entityField>
+      <name>KEY</name>
+      <title>Key</title>
+      <consumer>WorkflowDefinitions</consumer>
+      <state>EDITABLE</state>
+    </entityField>
+    <entityActionField>
+      <name>launchWorkflows</name>
+      <title>Start workflows</title>
+      <onActionProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/launchworkflows/onActionProcess.js</onActionProcess>
+      <iconId>VAADIN:PLAY</iconId>
+      <stateProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/launchworkflows/stateProcess.js</stateProcess>
+    </entityActionField>
+    <entityParameter>
+      <name>Targets_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>TargetFilter_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>ProcessVariables_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityParameter>
+      <name>TargetContext_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityProvider>
+      <name>Integration</name>
+    </entityProvider>
+    <entityConsumer>
+      <name>WorkflowDefinitions</name>
+      <dependency>
+        <name>dependency</name>
+        <entityName>WorkflowDefinition_entity</entityName>
+        <fieldName>#PROVIDER</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>Context_param</name>
+          <valueProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/workflowdefinitions/children/context_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityParameter>
+      <name>Validationerrors_param</name>
+      <expose v="true" />
+    </entityParameter>
+    <entityField>
+      <name>workflowCount</name>
+    </entityField>
+    <entityField>
+      <name>workflowTargets</name>
+      <valueProcess>%aditoprj%/entity/WorkflowLauncher_entity/entityfields/workflowtargets/valueProcess.js</valueProcess>
+    </entityField>
+  </entityFields>
+  <recordContainers>
+    <datalessRecordContainer>
+      <name>dataLess</name>
+    </datalessRecordContainer>
+  </recordContainers>
+</entity>
diff --git a/entity/WorkflowLauncher_entity/entityfields/launchworkflows/onActionProcess.js b/entity/WorkflowLauncher_entity/entityfields/launchworkflows/onActionProcess.js
new file mode 100644
index 00000000000..7e0756271a9
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/launchworkflows/onActionProcess.js
@@ -0,0 +1,33 @@
+import("system.neon");
+import("Util_lib");
+import("Workflow_lib");
+import("system.vars");
+import("system.workflow");
+
+var variables = Utils.parseJSON(vars.get("$param.ProcessVariables_param")) || {};
+var targets = Utils.parseJSON(vars.get("$field.workflowTargets")) || [];
+var context = vars.get("$param.TargetContext_param");
+var processKey = vars.get("$field.KEY");
+var instanceName = vars.get("$field.NAME");
+var startFormResult = Utils.parseJSON(vars.get("$field.STARTFORMRESULT"));
+var instanceId;
+
+if (!Utils.isNullOrEmpty(startFormResult))
+    Object.assign(variables, startFormResult);
+
+targets.forEach(function ([targetId, targetContext, processVariables])
+{
+    /* Caution: If 'variables' is used, then 'processVariables' is only a reference to 'variables'. 
+       Currently that's fine, but keep it in mind when you change this code. */
+    if (!processVariables)
+        processVariables = variables;
+    processVariables[WorkflowVariables.TARGET_ID()] = targetId;
+    processVariables[WorkflowVariables.TARGET_CONTEXT()] = targetContext || context;
+
+    instanceId = workflow.startProcessByKey(processKey, processVariables);
+    if (instanceName)
+        workflow.setProcessInstanceName(instanceId, instanceName);
+});
+    
+if (instanceId)
+    neon.openContext("WorkflowInstance", "WorkflowInstancePreview_view", [instanceId], neon.OPERATINGSTATE_VIEW, {});
\ No newline at end of file
diff --git a/entity/WorkflowLauncher_entity/entityfields/launchworkflows/stateProcess.js b/entity/WorkflowLauncher_entity/entityfields/launchworkflows/stateProcess.js
new file mode 100644
index 00000000000..568ebbfeb58
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/launchworkflows/stateProcess.js
@@ -0,0 +1,8 @@
+import("system.vars");
+import("system.result");
+import("system.neon");
+
+result.string(vars.get("$sys.validationerrors") || vars.get("$param.Validationerrors_param") 
+    ? neon.COMPONENTSTATE_DISABLED 
+    : neon.COMPONENTSTATE_EDITABLE
+);
\ No newline at end of file
diff --git a/entity/WorkflowLauncher_entity/entityfields/processdefinition_id/valueProcess.js b/entity/WorkflowLauncher_entity/entityfields/processdefinition_id/valueProcess.js
new file mode 100644
index 00000000000..53e733237be
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/processdefinition_id/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.vars");
+import("system.result");
+import("system.workflow"); 
+
+var processKey = vars.get("$field.KEY");
+if (processKey)
+    result.string(workflow.getLatestProcessDefinitionId(processKey));
\ No newline at end of file
diff --git a/entity/WorkflowLauncher_entity/entityfields/startformdefinition/valueProcess.js b/entity/WorkflowLauncher_entity/entityfields/startformdefinition/valueProcess.js
new file mode 100644
index 00000000000..cd86b1b2e71
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/startformdefinition/valueProcess.js
@@ -0,0 +1,7 @@
+import("system.vars");
+import("system.result");
+import("system.workflow");
+
+var processDefinitionId = vars.get("$field.PROCESSDEFINITION_ID");
+if (processDefinitionId)
+    result.string(workflow.getStartFormProperties(processDefinitionId));
\ No newline at end of file
diff --git a/entity/WorkflowLauncher_entity/entityfields/workflowdefinitions/children/context_param/valueProcess.js b/entity/WorkflowLauncher_entity/entityfields/workflowdefinitions/children/context_param/valueProcess.js
new file mode 100644
index 00000000000..f2a157dac50
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/workflowdefinitions/children/context_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$param.TargetContext_param"));
\ No newline at end of file
diff --git a/entity/WorkflowLauncher_entity/entityfields/workflowtargets/valueProcess.js b/entity/WorkflowLauncher_entity/entityfields/workflowtargets/valueProcess.js
new file mode 100644
index 00000000000..f8c799ec1b0
--- /dev/null
+++ b/entity/WorkflowLauncher_entity/entityfields/workflowtargets/valueProcess.js
@@ -0,0 +1,20 @@
+import("FilterViewAction_lib");
+import("system.result");
+import("Util_lib");
+import("system.vars");
+
+var targetFilter = Utils.parseJSON(vars.get("$param.TargetFilter_param"));
+var targets = Utils.parseJSON(vars.get("$param.Targets_param")) || [];
+var context = vars.get("$param.TargetContext_param");
+
+//when target ids are given, the targetFilter will be ignored
+if (targets.length === 0 && targetFilter)
+    targets = FilterViewActionUtils.getUidsByEntityFilter(context, targetFilter);
+
+var resTargets = targets.map(function (target)
+{
+    if (Utils.isString(target))
+        return [target];
+    return target;
+});
+result.string(JSON.stringify(resTargets));
\ No newline at end of file
diff --git a/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod b/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
index e57032a87e2..beafceffdfe 100644
--- a/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
+++ b/entity/WorkflowStartConfig_entity/WorkflowStartConfig_entity.aod
@@ -63,6 +63,10 @@
           <name>InvertBlacklist_param</name>
           <valueProcess>%aditoprj%/entity/WorkflowStartConfig_entity/entityfields/contexts/children/invertblacklist_param/valueProcess.js</valueProcess>
         </entityParameter>
+        <entityParameter>
+          <name>GetAllContexts_param</name>
+          <valueProcess>%aditoprj%/entity/WorkflowStartConfig_entity/entityfields/contexts/children/getallcontexts_param/valueProcess.js</valueProcess>
+        </entityParameter>
       </children>
     </entityConsumer>
     <entityConsumer>
diff --git a/entity/WorkflowStartConfig_entity/entityfields/contexts/children/getallcontexts_param/valueProcess.js b/entity/WorkflowStartConfig_entity/entityfields/contexts/children/getallcontexts_param/valueProcess.js
new file mode 100644
index 00000000000..40effa01784
--- /dev/null
+++ b/entity/WorkflowStartConfig_entity/entityfields/contexts/children/getallcontexts_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.result");
+
+result.string(true);
\ No newline at end of file
diff --git a/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod b/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod
new file mode 100644
index 00000000000..bad0c038509
--- /dev/null
+++ b/neonContext/MarketingWorkflowLauncher/MarketingWorkflowLauncher.aod
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.1">
+  <name>MarketingWorkflowLauncher</name>
+  <title>f</title>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <entity>MarketingWorkflowLauncher_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>39e62b1f-b27f-4f74-8521-d95e27748c6c</name>
+      <view>MarketingWorkflowLauncherEdit_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonContext/WorkflowLauncher/WorkflowLauncher.aod b/neonContext/WorkflowLauncher/WorkflowLauncher.aod
new file mode 100644
index 00000000000..e3e01733b87
--- /dev/null
+++ b/neonContext/WorkflowLauncher/WorkflowLauncher.aod
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonContext xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.1" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonContext/1.1.1">
+  <name>WorkflowLauncher</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <entity>WorkflowLauncher_entity</entity>
+  <references>
+    <neonViewReference>
+      <name>f3d227d8-73e9-4868-9f2d-a86e808f33e7</name>
+      <view>WorkflowLauncherEdit_view</view>
+    </neonViewReference>
+  </references>
+</neonContext>
diff --git a/neonView/MarketingWorkflowLauncherEdit_view/MarketingWorkflowLauncherEdit_view.aod b/neonView/MarketingWorkflowLauncherEdit_view/MarketingWorkflowLauncherEdit_view.aod
new file mode 100644
index 00000000000..8fe83127e05
--- /dev/null
+++ b/neonView/MarketingWorkflowLauncherEdit_view/MarketingWorkflowLauncherEdit_view.aod
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
+  <name>MarketingWorkflowLauncherEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <size>SMALL</size>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <genericViewTemplate>
+      <name>TemplateSelection</name>
+      <editMode v="true" />
+      <hideEmptyFields v="false" />
+      <entityField>#ENTITY</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>13b27604-86ee-41cb-80bd-7b0b4d834c8d</name>
+          <entityField>DOCUMENTTEMPLATE_ID</entityField>
+        </entityFieldLink>
+      </fields>
+    </genericViewTemplate>
+    <neonViewReference>
+      <name>e091c680-ee26-466a-a20e-52469dc28cfe</name>
+      <entityField>WorkflowLauncherIntegration</entityField>
+      <view>WorkflowLauncherEdit_view</view>
+    </neonViewReference>
+  </children>
+</neonView>
diff --git a/neonView/PersonDuplicateEditview_view/PersonDuplicateEditview_view.aod b/neonView/PersonDuplicateEditview_view/PersonDuplicateEditview_view.aod
index 25adc1c72ac..23c70461d00 100644
--- a/neonView/PersonDuplicateEditview_view/PersonDuplicateEditview_view.aod
+++ b/neonView/PersonDuplicateEditview_view/PersonDuplicateEditview_view.aod
@@ -14,6 +14,8 @@
       <hideContentSearch v="true" />
       <iconField></iconField>
       <entityField>#ENTITY</entityField>
+      <linkedColumns />
+      <fixedFilterFields />
       <hideHeader v="true" />
       <title>Duplicates</title>
       <columns>
diff --git a/neonView/PersonFilter_view/PersonFilter_view.aod b/neonView/PersonFilter_view/PersonFilter_view.aod
index 8eaea8f8294..721f83815ee 100644
--- a/neonView/PersonFilter_view/PersonFilter_view.aod
+++ b/neonView/PersonFilter_view/PersonFilter_view.aod
@@ -61,6 +61,7 @@
         <element>FIRSTNAME</element>
         <element>LASTNAME</element>
       </linkedColumns>
+      <fixedFilterFields />
       <columns>
         <neonTableColumn>
           <name>210cc6ab-5123-4d8a-8f2e-a6cd91d494ef</name>
@@ -109,6 +110,8 @@
         <element>FIRSTNAME</element>
         <element>LASTNAME</element>
       </linkedColumns>
+      <defaultGroupFields />
+      <fixedFilterFields />
       <columns>
         <neonTreeTableColumn>
           <name>ae9f20e2-8c64-43a7-b3ce-00c3af4974f7</name>
diff --git a/neonView/PersonLookup_view/PersonLookup_view.aod b/neonView/PersonLookup_view/PersonLookup_view.aod
index f3c036a9011..5877a1ee07a 100644
--- a/neonView/PersonLookup_view/PersonLookup_view.aod
+++ b/neonView/PersonLookup_view/PersonLookup_view.aod
@@ -11,6 +11,8 @@
     <tableViewTemplate>
       <name>Persons</name>
       <entityField>#ENTITY</entityField>
+      <linkedColumns />
+      <fixedFilterFields />
       <columns>
         <neonTableColumn>
           <name>9541c336-10e9-4767-b6e5-52b6108d967a</name>
diff --git a/neonView/PersonPreview_view/PersonPreview_view.aod b/neonView/PersonPreview_view/PersonPreview_view.aod
index b1717f65bcf..c0ecb2926bd 100644
--- a/neonView/PersonPreview_view/PersonPreview_view.aod
+++ b/neonView/PersonPreview_view/PersonPreview_view.aod
@@ -91,6 +91,7 @@
     </genericViewTemplate>
     <scoreCardViewTemplate>
       <name>Scores</name>
+      <fieldActions />
       <entityField>#ENTITY</entityField>
       <fields>
         <entityFieldLink>
diff --git a/neonView/PersonSimpleList_view/PersonSimpleList_view.aod b/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
index 63a4b1e6d2a..2f1efab3734 100644
--- a/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
+++ b/neonView/PersonSimpleList_view/PersonSimpleList_view.aod
@@ -17,6 +17,8 @@
       <subtitleField>LANGUAGE</subtitleField>
       <descriptionField>DEPARTMENT</descriptionField>
       <entityField>#ENTITY</entityField>
+      <linkedColumns />
+      <fixedFilterFields />
       <columns>
         <neonTableColumn>
           <name>cb441e57-dba4-49d6-a8f4-cea5db3187f2</name>
@@ -64,6 +66,9 @@
       <name>tree</name>
       <favoriteActionGroup1>filterViewActionGroup</favoriteActionGroup1>
       <entityField>#ENTITY</entityField>
+      <linkedColumns />
+      <defaultGroupFields />
+      <fixedFilterFields />
       <columns>
         <neonTreeTableColumn>
           <name>b18db709-56e9-4f7e-89a2-f0e2b81c75d0</name>
diff --git a/neonView/WorkflowInstancePreview_view/WorkflowInstancePreview_view.aod b/neonView/WorkflowInstancePreview_view/WorkflowInstancePreview_view.aod
index 9bfc1201ca8..6e02ae567d1 100644
--- a/neonView/WorkflowInstancePreview_view/WorkflowInstancePreview_view.aod
+++ b/neonView/WorkflowInstancePreview_view/WorkflowInstancePreview_view.aod
@@ -2,6 +2,7 @@
 <neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
   <name>WorkflowInstancePreview_view</name>
   <majorModelMode>DISTRIBUTED</majorModelMode>
+  <size>SMALL</size>
   <layout>
     <headerFooterLayout>
       <name>layout</name>
diff --git a/neonView/WorkflowLauncherEdit_view/WorkflowLauncherEdit_view.aod b/neonView/WorkflowLauncherEdit_view/WorkflowLauncherEdit_view.aod
new file mode 100644
index 00000000000..8445a151ff6
--- /dev/null
+++ b/neonView/WorkflowLauncherEdit_view/WorkflowLauncherEdit_view.aod
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
+  <name>WorkflowLauncherEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <size>SMALL</size>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <genericViewTemplate>
+      <name>selectWorkflow</name>
+      <editMode v="true" />
+      <hideEmptyFields v="false" />
+      <entityField>#ENTITY</entityField>
+      <fields>
+        <entityFieldLink>
+          <name>3150c50d-8d95-4891-9d53-7ab192bc124b</name>
+          <entityField>KEY</entityField>
+        </entityFieldLink>
+        <entityFieldLink>
+          <name>14de7f56-44cf-4c9e-89a7-59f84e482fd9</name>
+          <entityField>NAME</entityField>
+        </entityFieldLink>
+      </fields>
+    </genericViewTemplate>
+    <dynamicFormViewTemplate>
+      <name>startForm</name>
+      <formDefinition>STARTFORMDEFINITION</formDefinition>
+      <formResult>STARTFORMRESULT</formResult>
+      <editMode v="true" />
+      <entityField>#ENTITY</entityField>
+    </dynamicFormViewTemplate>
+    <actionsViewTemplate>
+      <name>startAction</name>
+      <actions>
+        <element>launchWorkflows</element>
+      </actions>
+      <entityField>#ENTITY</entityField>
+    </actionsViewTemplate>
+  </children>
+</neonView>
diff --git a/process/Workflow_lib/process.js b/process/Workflow_lib/process.js
index a876cd9f852..d8705a1e95f 100644
--- a/process/Workflow_lib/process.js
+++ b/process/Workflow_lib/process.js
@@ -38,23 +38,23 @@ WorkflowUtils.getPossibleWorkflowDefinitions = function (pContext)
  * opens the WorkflowInstance context in new-mode
  * 
  * @param {Object} [pVariables] variables for the process instance
- * @param {String} [pTargetId=$sys.uid] uid of the target object
+ * @param {String} [pTargetIds=$sys.uid] uid of the target object
  * @param {String} [pTargetContext=current context] target context 
  * @param {String} [pSelectionFilter] filter
  */
-WorkflowUtils.openNewInstance = function (pVariables, pTargetId, pTargetContext, pSelectionFilter)
+WorkflowUtils.openNewInstance = function (pVariables, pTargetIds, pTargetContext, pSelectionFilter)
 {
-    if ((!pTargetId || pTargetId.length === 0) && pSelectionFilter)
-        pTargetId = [];
+    if ((!pTargetIds || pTargetIds.length === 0) && pSelectionFilter)
+        pTargetIds = [];
     if (!pVariables)
         pVariables = {};
     
-    Object.assign(pVariables, WorkflowVariables.getTargetVariables(pTargetId, pTargetContext));
+    Object.assign(pVariables, WorkflowVariables.getTargetVariables(pTargetIds, pTargetContext));
     
-    neon.openContext("WorkflowInstance", null, null, neon.OPERATINGSTATE_NEW, {
+    neon.openContext("WorkflowLauncher", "WorkflowLauncherEdit_view", null, neon.OPERATINGSTATE_VIEW, {
         "ProcessVariables_param" : JSON.stringify(pVariables),
         "TargetContext_param" : pVariables[WorkflowVariables.TARGET_CONTEXT()],
-        "TargetIdFilter_param" : pSelectionFilter ? JSON.stringify(pSelectionFilter) : ""
+        "TargetFilter_param" : pSelectionFilter ? JSON.stringify(pSelectionFilter) : ""
     });
 }
 
@@ -67,7 +67,8 @@ WorkflowUtils.getPossibleTargetContexts = function ()
         "Organisation",
         "Person",
         "Offer",
-        "Salesproject"
+        "Salesproject",
+        "MarketingWorkflowLauncher"
     ];
 }
 
@@ -76,7 +77,7 @@ WorkflowUtils.getPossibleTargetContexts = function ()
  */
 WorkflowUtils.engineIsEnabled = function ()
 {
-    return String(project.getInstanceConfigValue("workflowEngineEnabled", "false")) == "true";
+    return Utils.toBoolean(project.getInstanceConfigValue("workflowEngineEnabled", "false"));
 }
 
 /**
@@ -602,9 +603,16 @@ WorkflowModelerApiCall.prototype.importModel = function ()
     return WorkflowModel.fromObject(JSON.parse(modelJson));
 }
 
-
+/**
+ * Provides functionality to work with urls that trigger certain workflow actions
+ */
 function WorkflowLinkActions () {}
 
+/**
+ * Contains the different types of workflow actions that can be performed
+ * 
+ * @enum
+ */
 WorkflowLinkActions.types = {
     RECEIVE_TASK: function () {return "rec";},
     SIGNAL: function () {return "sig";},
@@ -612,29 +620,48 @@ WorkflowLinkActions.types = {
 };
 
 WorkflowLinkActions.types.RECEIVE_TASK.title = "Receive Task";
+WorkflowLinkActions.types.SIGNAL.title = "Signal";
+WorkflowLinkActions.types.MESSAGE.title = "Message";
+
+/**
+ * Callback-function that performs the action for the type RECEIVE_TASK. 
+ */
 WorkflowLinkActions.types.RECEIVE_TASK.execute = function (pParameters)
 {
     if (!pParameters.processInstanceId)
         return;
-    
     workflow.triggerReceiveTask(pParameters.processInstanceId, pParameters.receiveTask || null);
 }
 
-WorkflowLinkActions.types.SIGNAL.title = "Signal";
+/**
+ * Callback-function that performs the action for the type SIGNAL. 
+ */
 WorkflowLinkActions.types.SIGNAL.execute = function (pParameters)
 {
-    if (!pParameters.processInstanceId)
+    if (!pParameters.signal)
         return;
     workflow.signalEventReceived(pParameters.signal);
 }
 
-WorkflowLinkActions.types.MESSAGE.title = "Message";
+/**
+ * Callback-function that performs the action for the type MESSAGE. 
+ */
 WorkflowLinkActions.types.MESSAGE.execute = function (pParameters)
 {
     if (!pParameters.processInstanceId || !pParameters.message)
         return;
+    workflow.messageEventReceived(pParameters.message, pParameters.processInstanceId);
 }
 
+/**
+ * Encodes an action into a special string containing the data required to execute the action. 
+ * This string can be decoded with WorkflowLinkActions.parseAction.
+ * 
+ * @param {String} pType the action type, see WorkflowLinkActions.types
+ * @param {String} pLink the url to redirect to after the action has been executed
+ * @param {Object} pParams extra parameters required for the action
+ * @return {String} the encoded action-string
+ */
 WorkflowLinkActions.encodeAction = function (pType, pLink, pParams)
 {
     if (!pParams)
@@ -656,6 +683,7 @@ WorkflowLinkActions.encodeAction = function (pType, pLink, pParams)
     return encodeURIComponent(util.encodeBase64String(actionString));
 }
 
+
 WorkflowLinkActions.getActionLink = function (pBaseUrl, pType, pLink, pParams)
 {
     if (!pBaseUrl.endsWith("/"))
@@ -663,6 +691,12 @@ WorkflowLinkActions.getActionLink = function (pBaseUrl, pType, pLink, pParams)
     return pBaseUrl + "services/rest/redirect_rest?act=" + WorkflowLinkActions.encodeAction(pType, pLink, pParams);
 }
 
+/**
+ * Decodes the given action-string and gives back an object that can run the action.
+ * 
+ * @param {String} pEncodedAction the encoded action-string, see WorkflowLinkActions.encodeAction
+ * @return {Object} an object that contains the properties of the action and the function 'run' that can be called to execute the action
+ */
 WorkflowLinkActions.parseAction = function (pEncodedAction)
 {
     try 
-- 
GitLab