mirror of https://github.com/MISP/MISP
chg: [workflow] Continued deleting unused code and improved UI
parent
d180c2cc17
commit
52fc9c08c5
|
@ -253,37 +253,6 @@ class WorkflowsController extends AppController
|
|||
return $this->response;
|
||||
}
|
||||
|
||||
public function rearrangeExecutionOrder($trigger_id)
|
||||
{
|
||||
$trigger = $this->Workflow->getModuleByID($trigger_id);
|
||||
if (empty($trigger)) {
|
||||
throw new NotFoundException(__('Invalid trigger ID'));
|
||||
}
|
||||
$trigger = $this->Workflow->attachWorkflowToTriggers([$trigger])[0];
|
||||
$workflow_order = [];
|
||||
if (!empty($trigger['Workflows']['blocking'])) {
|
||||
$workflow_order = Hash::extract($trigger['Workflows']['blocking'], '{n}.Workflow.id');
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$workflow_order = array_unique(JsonTool::decode($this->request->data['Workflow']['workflow_order']));
|
||||
$saved = $this->Workflow->saveBlockingWorkflowExecutionOrder($trigger['id'], $workflow_order);
|
||||
$redirectTarget = ['action' => 'moduleView', $trigger_id];
|
||||
if (empty($saved)) {
|
||||
return $this->__getFailResponseBasedOnContext([__('Could not save workflow execution order.')], null, 'rearrangeExecutionOrder', $trigger_id, $redirectTarget);
|
||||
} else {
|
||||
$successMessage = __('Workflow execution order saved.');
|
||||
return $this->__getSuccessResponseBasedOnContext($successMessage, $workflow_order, 'rearrangeExecutionOrder', false, $redirectTarget);
|
||||
}
|
||||
} else {
|
||||
$this->request->data = [
|
||||
'Workflow' => [
|
||||
'workflow_order' => JsonTool::encode($workflow_order),
|
||||
]
|
||||
];
|
||||
}
|
||||
$this->set('trigger', $trigger);
|
||||
}
|
||||
|
||||
private function __getSuccessResponseBasedOnContext($message, $data = null, $action = '', $id = false, $redirect = array())
|
||||
{
|
||||
if ($this->_isRest()) {
|
||||
|
|
|
@ -39,9 +39,9 @@ class Workflow extends AppModel
|
|||
'rule' => ['hasAcyclicGraph'],
|
||||
'message' => 'Cannot save a workflow containing a cycle',
|
||||
],
|
||||
'MoreThanOneTriggerInstance' => [
|
||||
'rule' => ['MoreThanOneTriggerInstance'],
|
||||
'message' => 'Cannot save a workflow containing more than one instance of the same trigger',
|
||||
'hasOneTrigger' => [
|
||||
'rule' => ['hasOneTrigger'],
|
||||
'message' => 'Cannot save a workflow containing more than one trigger',
|
||||
]
|
||||
]
|
||||
];
|
||||
|
@ -59,7 +59,6 @@ class Workflow extends AppModel
|
|||
const MODULE_ROOT_PATH = APP . 'Model/WorkflowModules/';
|
||||
const REDIS_KEY_WORKFLOW_NAMESPACE = 'workflow';
|
||||
const REDIS_KEY_WORKFLOW_PER_TRIGGER = 'workflow:workflow_list:%s';
|
||||
const REDIS_KEY_WORKFLOW_ORDER_PER_BLOCKING_TRIGGER = 'workflow:workflow_blocking_order_list:%s';
|
||||
const REDIS_KEY_TRIGGER_PER_WORKFLOW = 'workflow:trigger_list:%s';
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null)
|
||||
|
@ -183,7 +182,6 @@ class Workflow extends AppModel
|
|||
foreach ($trigger_to_remove as $trigger_id) {
|
||||
$pipeline->sRem(sprintf(Workflow::REDIS_KEY_WORKFLOW_PER_TRIGGER, $trigger_id), $workflow['Workflow']['id']);
|
||||
$pipeline->sRem(sprintf(Workflow::REDIS_KEY_TRIGGER_PER_WORKFLOW, $workflow['Workflow']['id']), $trigger_id);
|
||||
$pipeline->lRem(sprintf(Workflow::REDIS_KEY_WORKFLOW_ORDER_PER_BLOCKING_TRIGGER, $trigger_id), $workflow['Workflow']['id'], 0);
|
||||
}
|
||||
$pipeline->exec();
|
||||
}
|
||||
|
@ -191,14 +189,11 @@ class Workflow extends AppModel
|
|||
$pipeline = $redis->multi();
|
||||
foreach ($trigger_to_add as $trigger_id) {
|
||||
if (
|
||||
$this->workflowGraphTool->triggerHasNonBlockingPath($new_node_trigger_list_per_id[$trigger_id])
|
||||
|| $this->workflowGraphTool->triggerHasBlockingPath($new_node_trigger_list_per_id[$trigger_id])
|
||||
$this->workflowGraphTool->triggerHasNonBlockingPath($new_node_trigger_list_per_id[$trigger_id]) ||
|
||||
$this->workflowGraphTool->triggerHasBlockingPath($new_node_trigger_list_per_id[$trigger_id])
|
||||
) {
|
||||
$pipeline->sAdd(sprintf(Workflow::REDIS_KEY_WORKFLOW_PER_TRIGGER, $trigger_id), $workflow['Workflow']['id']);
|
||||
$pipeline->sAdd(sprintf(Workflow::REDIS_KEY_TRIGGER_PER_WORKFLOW, $workflow['Workflow']['id']), $trigger_id);
|
||||
if ($this->workflowGraphTool->triggerHasBlockingPath($new_node_trigger_list_per_id[$trigger_id])) {
|
||||
$pipeline->rPush(sprintf(Workflow::REDIS_KEY_WORKFLOW_ORDER_PER_BLOCKING_TRIGGER, $trigger_id), $workflow['Workflow']['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
$pipeline->exec();
|
||||
|
@ -222,22 +217,6 @@ class Workflow extends AppModel
|
|||
return !empty($list) ? $list : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* __getOrderedWorkflowsPerTrigger Get list of workflow IDs in the execution order for the specified trigger
|
||||
*
|
||||
* @param string $trigger_id
|
||||
* @return bool|array
|
||||
*/
|
||||
private function __getOrderedWorkflowsPerTrigger($trigger_id)
|
||||
{
|
||||
try {
|
||||
$redis = $this->setupRedisWithException();
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return $redis->lRange(sprintf(Workflow::REDIS_KEY_WORKFLOW_ORDER_PER_BLOCKING_TRIGGER, $trigger_id), 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* __getTriggersIDPerWorkflow Get list of trigger name running to the specified workflow
|
||||
*
|
||||
|
@ -254,31 +233,6 @@ class Workflow extends AppModel
|
|||
return $redis->sMembers(sprintf(Workflow::REDIS_KEY_TRIGGER_PER_WORKFLOW, $workflow_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* saveBlockingWorkflowExecutionOrder Save the workflow execution order for the provided trigger
|
||||
*
|
||||
* @param string $trigger_id
|
||||
* @param array $workflows List of workflow IDs in priority order
|
||||
* @return bool
|
||||
*/
|
||||
public function saveBlockingWorkflowExecutionOrder($trigger_id, array $workflow_order): bool
|
||||
{
|
||||
try {
|
||||
$redis = $this->setupRedisWithException();
|
||||
} catch (Exception $e) {
|
||||
$this->logException('Failed to setup redis ', $e);
|
||||
return false;
|
||||
}
|
||||
$key = sprintf(Workflow::REDIS_KEY_WORKFLOW_ORDER_PER_BLOCKING_TRIGGER, $trigger_id);
|
||||
$pipeline = $redis->multi();
|
||||
$pipeline->del($key);
|
||||
foreach ($workflow_order as $workflow_id) {
|
||||
$pipeline->rpush($key, (string)$workflow_id);
|
||||
}
|
||||
$pipeline->exec();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* attachWorkflowToTriggers Collect the workflows listening to this trigger
|
||||
*
|
||||
|
@ -287,37 +241,6 @@ class Workflow extends AppModel
|
|||
*/
|
||||
public function attachWorkflowToTriggers(array $triggers): array
|
||||
{
|
||||
// $all_workflow_ids = [];
|
||||
// $workflows_per_trigger = [];
|
||||
// $ordered_workflows_per_trigger = [];
|
||||
// foreach ($triggers as $trigger) {
|
||||
// $workflow_ids_for_trigger = $this->__getWorkflowsIDPerTrigger($trigger['id']);
|
||||
// $workflows_per_trigger[$trigger['id']] = $workflow_ids_for_trigger;
|
||||
// $ordered_workflows_per_trigger[$trigger['id']] = $this->__getOrderedWorkflowsPerTrigger($trigger['id']);
|
||||
// foreach ($workflow_ids_for_trigger as $id) {
|
||||
// $all_workflow_ids[$id] = true;
|
||||
// }
|
||||
// }
|
||||
// $all_workflow_ids = array_keys($all_workflow_ids);
|
||||
// $workflows = $this->fetchWorkflows([
|
||||
// 'conditions' => [
|
||||
// 'Workflow.id' => $all_workflow_ids,
|
||||
// ],
|
||||
// 'fields' => ['*'],
|
||||
// ]);
|
||||
// $workflows = Hash::combine($workflows, '{n}.Workflow.id', '{n}');
|
||||
// foreach ($triggers as $i => $trigger) {
|
||||
// $workflow_ids = $workflows_per_trigger[$trigger['id']];
|
||||
// $ordered_workflow_ids = $ordered_workflows_per_trigger[$trigger['id']];
|
||||
// $triggers[$i]['Workflows'] = [];
|
||||
// foreach ($workflow_ids as $workflow_id) {
|
||||
// $triggers[$i]['Workflows'][] = $workflows[$workflow_id];
|
||||
// }
|
||||
// if (!empty($group_per_blocking)) {
|
||||
// $triggers[$i]['GroupedWorkflows'] = $this->groupWorkflowsPerBlockingType($triggers[$i]['Workflows'], $trigger['id'], $ordered_workflow_ids);
|
||||
// }
|
||||
// }
|
||||
// return $triggers;
|
||||
$workflows = $this->fetchWorkflows([
|
||||
'conditions' => [
|
||||
'Workflow.trigger_id' => Hash::extract($triggers, '{n}.id'),
|
||||
|
@ -333,69 +256,6 @@ class Workflow extends AppModel
|
|||
return $triggers;
|
||||
}
|
||||
|
||||
public function fetchWorkflowsForTrigger($trigger_id, $filterDisabled=false): array
|
||||
{
|
||||
$workflow_ids_for_trigger = $this->__getWorkflowsIDPerTrigger($trigger_id);
|
||||
$conditions = [
|
||||
'Workflow.id' => $workflow_ids_for_trigger,
|
||||
];
|
||||
if (!empty($filterDisabled)) {
|
||||
$conditions['Workflow.enabled'] = true;
|
||||
}
|
||||
$workflows = $this->fetchWorkflows([
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['*'],
|
||||
]);
|
||||
return $workflows;
|
||||
}
|
||||
|
||||
/**
|
||||
* getExecutionOrderForTrigger Generate the execution order for the provided trigger
|
||||
*
|
||||
* @param array $trigger
|
||||
* @return array
|
||||
*/
|
||||
public function getExecutionOrderForTrigger(array $trigger, $filterDisabled=false): array
|
||||
{
|
||||
if (empty($trigger)) {
|
||||
return ['blocking' => [], 'non-blocking' => [] ];
|
||||
}
|
||||
$workflows = $this->fetchWorkflowsForTrigger($trigger['id'], $filterDisabled);
|
||||
$ordered_workflow_ids = $this->__getOrderedWorkflowsPerTrigger($trigger['id']);
|
||||
return $this->groupWorkflowsPerBlockingType($workflows, $trigger['id'], $ordered_workflow_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* groupWorkflowsPerBlockingType Group workflows together if they have a blocking path set or not. Also, sort the blocking list based on execution order
|
||||
*
|
||||
* @param array $workflows
|
||||
* @param string $trigger_id The trigger for which we should decide if it's blocking or not
|
||||
* @param array $ordered_workflow_ids If provided, will sort the blocking workflows based on the workflow_id order in of the provided list
|
||||
* @return array
|
||||
*/
|
||||
public function groupWorkflowsPerBlockingType(array $workflows, $trigger_id, $ordered_workflow_ids=false): array
|
||||
{
|
||||
$groupedWorkflows = [
|
||||
'blocking' => [],
|
||||
'non-blocking' => [],
|
||||
];
|
||||
foreach ($workflows as $workflow) {
|
||||
foreach ($workflow['Workflow']['data'] as $block) {
|
||||
if ($block['data']['id'] == $trigger_id) {
|
||||
if ($this->workflowGraphTool->triggerHasBlockingPath($block)) {
|
||||
$order_index = array_search($workflow['Workflow']['id'], $ordered_workflow_ids);
|
||||
$groupedWorkflows['blocking'][$order_index] = $workflow;
|
||||
}
|
||||
if ($this->workflowGraphTool->triggerHasNonBlockingPath($block)) {
|
||||
$groupedWorkflows['non-blocking'][] = $workflow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($groupedWorkflows['blocking']);
|
||||
return $groupedWorkflows;
|
||||
}
|
||||
|
||||
/**
|
||||
* isGraphAcyclic Return if the graph is acyclic or not
|
||||
*
|
||||
|
@ -411,23 +271,16 @@ class Workflow extends AppModel
|
|||
}
|
||||
|
||||
/**
|
||||
* MoreThanOneTriggerInstance Return if the graph contain more than one instance of the same trigger
|
||||
* hasOneTrigger Return if the graph contain more than one instance of the same trigger
|
||||
*
|
||||
* @param array $graphData
|
||||
* @return boolean
|
||||
*/
|
||||
public function MoreThanOneTriggerInstance(array $workflow): bool
|
||||
public function hasOneTrigger(array $workflow): bool
|
||||
{
|
||||
$graphData = !empty($workflow['Workflow']) ? $workflow['Workflow']['data'] : $workflow['data'];
|
||||
$triggers = $this->workflowGraphTool->extractTriggersFromWorkflow($graphData, true);
|
||||
$visitedTriggerIDs = [];
|
||||
foreach ($triggers as $trigger) {
|
||||
if (!empty($visitedTriggerIDs[$trigger['data']['id']])) {
|
||||
return false;
|
||||
}
|
||||
$visitedTriggerIDs[$trigger['data']['id']] = true;
|
||||
}
|
||||
return true;
|
||||
return count($triggers) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -452,24 +305,9 @@ class Workflow extends AppModel
|
|||
}
|
||||
|
||||
$blockingPathExecutionSuccess = true;
|
||||
$workflowExecutionOrder = $this->getExecutionOrderForTrigger($trigger, true);
|
||||
$orderedBlockingWorkflows = $workflowExecutionOrder['blocking'];
|
||||
$orderedDeferredWorkflows = $workflowExecutionOrder['non-blocking'];
|
||||
foreach ($orderedBlockingWorkflows as $workflow) {
|
||||
$walkResult = [];
|
||||
$continueExecution = $this->walkGraph($workflow, $trigger_id, 'blocking', $data, $blockingErrors, $walkResult);
|
||||
// $this->loadLog()->createLogEntry($this->User->getAuthUser($workflow['User']['id']), 'walkGraph', 'Workflow', $workflow['Workflow']['id'], __('Executed blocking path for trigger `%s`', $trigger_id), $this->digestExecutionResult($walkResult));
|
||||
if (!$continueExecution) {
|
||||
$blockingPathExecutionSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($orderedDeferredWorkflows as $workflow) {
|
||||
$deferredErrors = [];
|
||||
$walkResult = [];
|
||||
$this->walkGraph($workflow, $trigger_id, 'non-blocking', $data, $deferredErrors, $walkResult);
|
||||
// $this->loadLog()->createLogEntry($this->User->getAuthUser($workflow['User']['id']), 'walkGraph', 'Workflow', $workflow['Workflow']['id'], __('Executed non-blocking path for trigger `%s`', $trigger_id), $this->digestExecutionResult($walkResult));
|
||||
}
|
||||
$workflow = $this->fetchWorkflowByTrigger($trigger, true);
|
||||
$walkResult = [];
|
||||
$this->walkGraph($workflow, $trigger_id, 'all', $data, $blockingErrors, $walkResult);
|
||||
return $blockingPathExecutionSuccess;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class Module_parallel_task extends WorkflowBaseModule
|
|||
public $description = 'Allow breaking the execution process and running parallel tasks. You can connect multiple blocks the `parallel` output.';
|
||||
public $icon = 'random';
|
||||
public $inputs = 1;
|
||||
public $outputs = 2;
|
||||
public $outputs = 1;
|
||||
public $html_template = 'parallel';
|
||||
public $params = [];
|
||||
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
<div>
|
||||
<h3 class="bold">
|
||||
<i class="bold fa-fw <?= $this->FontAwesome->getClass('hourglass-start') ?>" style="font-size: larger;" title="<?= __('Blocking execution path') ?>"></i>
|
||||
<?= __('Blocking Execution order') ?>
|
||||
</h3>
|
||||
<?php if (empty($trigger['GroupedWorkflows']['blocking'])) : ?>
|
||||
<div class="alert alert-info">
|
||||
<strong><?= __('No blocking workflows!') ?></strong>
|
||||
<div><?= __('The trigger <strong>%s</strong> has no blocking workflows listening to it.', h($trigger['name'])) ?></div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div id="container-unsaved-change" class="alert alert-info hidden">
|
||||
<strong><?= __('Unsaved changes!') ?></strong>
|
||||
<div><?= __('The execution order has changed and hasn\'t been saved.') ?></div>
|
||||
<div style="margin-top: 1em;">
|
||||
<button id="btn-save" class="btn btn-success">
|
||||
<i class="fa-fw <?= $this->FontAwesome->getClass('save') ?>"></i> <?= __('Save') ?>
|
||||
<span class="fa-fw fas fa-spin fa-spinner loading-icon hidden"></span>
|
||||
</button>
|
||||
<button id="btn-reset" class="btn btn-default"><?= __('Reset order') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 2em 1em;">
|
||||
<ul id="workflows-sortable" class="unstyled">
|
||||
<?php foreach ($trigger['GroupedWorkflows']['blocking'] as $i => $workflow) : ?>
|
||||
<?= $this->element('Workflows/executionOrderWidgetLI', ['workflow' => $workflow]) ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo $this->element('genericElements/assetLoader', [
|
||||
'js' => ['jquery-ui'],
|
||||
]);
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$(document).ready(function() {
|
||||
initialHtmlState = $('#workflows-sortable').html()
|
||||
initialState = collectWorklowOrder()
|
||||
initSortable()
|
||||
$('#btn-reset').click(function() {
|
||||
resetOrder(this)
|
||||
})
|
||||
$('#btn-save').click(function() {
|
||||
saveOrder(this)
|
||||
})
|
||||
})
|
||||
|
||||
var initialHtmlState = false
|
||||
var initialState = false
|
||||
|
||||
function initSortable() {
|
||||
$('#workflows-sortable').sortable({
|
||||
cursor: 'grabbing',
|
||||
scroll: false,
|
||||
update: function(event, ui) {
|
||||
toggleUnsaveWarning()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function resetOrder(clicked) {
|
||||
$('#workflows-sortable').html(initialHtmlState)
|
||||
initSortable()
|
||||
toggleUnsaveWarning()
|
||||
}
|
||||
|
||||
function saveOrder(clicked) {
|
||||
var workflow_order = collectWorklowOrder()
|
||||
var url = "<?= $baseurl . '/workflows/rearrangeExecutionOrder/' . h($trigger['id']) ?>"
|
||||
fetchFormDataAjax(url, function(formHTML) {
|
||||
var $tmpForm = $(formHTML).find('form')
|
||||
var formUrl = $tmpForm.attr('action')
|
||||
$tmpForm.find('[name="data[Workflow][workflow_order]"]').val(JSON.stringify(workflow_order))
|
||||
|
||||
$.ajax({
|
||||
data: $tmpForm.serialize(),
|
||||
beforeSend: function() {
|
||||
toggleLoadingInSaveButton(true)
|
||||
},
|
||||
success: function(result, textStatus) {
|
||||
if (result) {
|
||||
showMessage('success', result.message);
|
||||
if (result.data !== undefined) {
|
||||
initialState = result.data
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
showMessage('fail', textStatus + ': ' + errorThrown);
|
||||
},
|
||||
complete: function() {
|
||||
toggleLoadingInSaveButton(false)
|
||||
window.location.reload()
|
||||
},
|
||||
type: "post",
|
||||
url: formUrl
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function collectWorklowOrder() {
|
||||
var order = []
|
||||
$('#workflows-sortable > li').each(function() {
|
||||
var $li = $(this)
|
||||
order.push($li.data('workflowid'))
|
||||
})
|
||||
return order;
|
||||
}
|
||||
|
||||
function toggleUnsaveWarning() {
|
||||
if (JSON.stringify(initialState) !== JSON.stringify(collectWorklowOrder())) {
|
||||
$('#container-unsaved-change').show()
|
||||
} else {
|
||||
$('#container-unsaved-change').hide()
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLoadingInSaveButton(saving) {
|
||||
var $saveButton = $('#btn-save')
|
||||
$saveButton.prop('disabled', saving)
|
||||
if (saving) {
|
||||
$saveButton.find('.loading-icon').show();
|
||||
} else {
|
||||
$saveButton.find('.loading-icon').hide();
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#workflows-sortable > li {
|
||||
display: flex;
|
||||
width: 30%;
|
||||
min-width: 350px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
padding: 0.25em 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
cursor: grab;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
#workflows-sortable > li > i.fas {
|
||||
margin-right: 10px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
#workflows-sortable > li > div {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
|
@ -424,7 +424,7 @@
|
|||
),
|
||||
array(
|
||||
'text' => __('Workflows'),
|
||||
'url' => $baseurl . '/workflows/index',
|
||||
'url' => $baseurl . '/workflows/triggers',
|
||||
'requirement' => $isSiteAdmin
|
||||
),
|
||||
array(
|
||||
|
|
|
@ -9,9 +9,9 @@ $triggerModules = $modules['blocks_trigger'];
|
|||
<div class="root-container">
|
||||
<div class="main-container">
|
||||
<div class="side-panel">
|
||||
<a href="<?= $baseurl . '/workflows/index' ?>">
|
||||
<a href="<?= $baseurl . '/workflows/triggers' ?>">
|
||||
<i class="fa-fw <?= $this->FontAwesome->getClass('caret-left') ?>"></i>
|
||||
<?= __('Workflow index') ?>
|
||||
<?= __('Trigger index') ?>
|
||||
</a>
|
||||
<h3>
|
||||
<span style="font-weight:normal;"><?= __('Workflows:') ?></span>
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
$modelForForm = 'Workflow';
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'form' => $this->Form,
|
||||
'data' => [
|
||||
'title' => __('Rearrange Execution Order'),
|
||||
'model' => $modelForForm,
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'workflow_order',
|
||||
'class' => 'span6',
|
||||
'type' => 'textarea'
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action'],
|
||||
'ajaxSubmit' => sprintf('submitPopoverForm(\'%s\', \'rearrangeExecutionOrder\', 0, 1)', h($trigger['id']))
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
if (empty($ajax)) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'workflows', 'menuItem' => $this->request->params['action']));
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
'data_path' => 'description',
|
||||
],
|
||||
[
|
||||
'name' => __('Module Enabled'),
|
||||
'name' => __('Trigger Enabled'),
|
||||
'sort' => 'disabled',
|
||||
'class' => 'short',
|
||||
'data_path' => 'disabled',
|
||||
|
|
|
@ -244,17 +244,21 @@
|
|||
display: block;
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output::after {
|
||||
color: white;
|
||||
color: black;
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-weight: 900;
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
width: 12px;
|
||||
top: -3px;
|
||||
width: 14px;
|
||||
font-size: x-small;
|
||||
text-align: center;
|
||||
transition-property: width,top,font-size;
|
||||
transition-duration: .1s
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output:hover {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output:hover::after {
|
||||
font-size: larger;
|
||||
width: 18px;
|
||||
|
@ -262,18 +266,20 @@
|
|||
}
|
||||
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output_1 {
|
||||
background-color: #73a2c9;
|
||||
background-color: #fff;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output_1::before {
|
||||
content: 'Listen';
|
||||
content: 'Listen to this trigger';
|
||||
top: -26px;
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output_1::after {
|
||||
content: "\f025";
|
||||
font-size: 9px;
|
||||
content: "\f024";
|
||||
font-size: 11px;
|
||||
}
|
||||
.drawflow .drawflow-node.block-type-trigger > .outputs > .output_1:hover::after {
|
||||
font-size: 14px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.drawflow .drawflow-node.block-type-IF > .outputs > .output::before {
|
||||
|
|
Loading…
Reference in New Issue