/*
* Copyright 2023 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Class defining the editor tool for workflows
*/
Ext.define('Ametys.plugins.workflow.tools.WorkflowEditorTool', {
extend: "Ametys.tool.Tool",
statics:
{
/**
* @readonly
* @property {String} WORKFLOW_SAVED Event sent when the changes on a workflow have been saved
*/
WORKFLOW_SAVED: "workflowSaved",
},
displayWorkflowDetails: true,
constructor: function(config)
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.SELECTION_CHANGED, this._onSelectionChanged, this);
Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onMessageCreatedOrModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onMessageCreatedOrModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
Ametys.message.MessageBus.on(Ametys.plugins.workflow.tools.WorkflowEditorTool.WORKFLOW_SAVED, this._onWorkflowSaved, this);
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
setParams: function (params)
{
this.callParent(arguments);
this._workflowName = params.id;
Ametys.plugins.workflow.dao.WorkflowsDAO.getWorkflowRootProperties(
[this._workflowName],
Ext.bind(this._setParamCb, this)
);
},
/**
* @private
* Callback function of setParams
* @param {Object} response The server response
* @param {String} response.label title of the workflow
*/
_setParamCb: function (response)
{
var data = response.getConfig();
if (response.error && (response.error == "workflow-unknown" || response.error == "cant-read"))
{
this.close();
}
else
{
this.setTitle(data.label);
this._tree.initRootNodeParameter(this._workflowName, data.label, data.hasChanges);
this.showOutOfDate();
}
},
refresh: function()
{
this.showRefreshing();
this._tree.getStore().load({
scope: this,
callback: function() {
this._tree.expandAll();
this.showRefreshed();
this._tree.getSelectionModel().select(0);
}
});
},
sendCurrentSelection: function()
{
var selection = this._tree.getSelectionModel().getSelection();
if (selection.length > 0)
{
var currentRecord = selection[0]; // multiselection is not supported
var realTarget =[];
if (currentRecord.isRoot())
{
realTarget = this._getMessageRootTargetConfiguration(currentRecord);
}
else if (currentRecord.getData().elementType == "step")
{
var workflowNode = this._tree.getStore().getNodeById(currentRecord.get('parentId'));
realTarget = this._getMessageRootTargetConfiguration(workflowNode);
realTarget.subtargets = this._getMessageStepTargetConfiguration(currentRecord);
}
else if (currentRecord.getData().elementType == "action")
{
var stepNode = this._tree.getStore().getNodeById(currentRecord.get('parentId'));
var workflowNode = this._tree.getStore().getNodeById(stepNode.get('parentId'));
realTarget = this._getMessageRootTargetConfiguration(workflowNode);
var subtarget = this._getMessageStepTargetConfiguration(stepNode);
subtarget.subtargets = this._getMessageActionTargetConfiguration(currentRecord, stepNode);
realTarget.subtargets = subtarget;
}
}
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: realTarget,
parameters: {}
});
},
/**
* @private
* Get the target configuration object for root record
* @param {Ext.data.Model} record The tree root record to convert to its Ametys.message.MessageTarget configuration
* @return {Object} The configuration to create a Ametys.message.MessageTarget.
*/
_getMessageRootTargetConfiguration: function (record)
{
return {
id: Ametys.message.MessageTarget.WORKFLOW_OBJECT,
parameters: {
id: this._workflowName
}
};
},
/**
* @private
* Get the target configuration object for given step record
* @param {Ext.data.Model} record The tree step record to convert to its Ametys.message.MessageTarget configuration
* @return {Object} The configuration to create a Ametys.message.MessageTarget.
*/
_getMessageStepTargetConfiguration: function (record)
{
return {
id: Ametys.message.MessageTarget.WORKFLOW_STEP,
parameters: {
id: record.get("elementId"),
label: record.get("label"),
workflowId: this._workflowName
},
};
},
/**
* @private
* Get the target configuration object for given action record
* @param {Ext.data.Model} record The tree action record to convert to its Ametys.message.MessageTarget configuration
* @return {Object} The configuration to create a Ametys.message.MessageTarget.
*/
_getMessageActionTargetConfiguration: function (record, stepNode)
{
return {
id: Ametys.message.MessageTarget.WORKFLOW_ACTION,
parameters: {
id: record.get('elementId'),
label: record.get("label"),
stepId: stepNode.get('elementId'),
workflowId: this._workflowName
}
};
},
/**
* Listener on selection messages, update tree selection
* @param {Ametys.message.Message} message The selection message.
* @private
*/
_onSelectionChanged: function (message)
{
var target = message.getTarget(Ametys.message.MessageTarget.WORKFLOW_OBJECT);
if (target != null)
{
if (target.getParameters().id == this._workflowName)
{
var targetStep = target.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_STEP});
var nodeId = "root";
if (targetStep != null)
{
var stepId = targetStep.getParameters().id;
nodeId = stepId =="step0" ? stepId : "step" + stepId;
var targetAction = targetStep.getSubtarget(function(target){return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION});
if (targetAction != null)
{
nodeId = nodeId + "-action" + targetAction.getParameters().id;
}
}
this._tree.onWorkflowElementSelected(nodeId);
}
}
},
/**
* Listener on created and modified messages, select the new element
* @param {Ametys.message.Message} message The selection message.
* @private
*/
_onMessageCreatedOrModified: function(message)
{
var targets = message.getTargets(function(target) {
return target.getId() == Ametys.message.MessageTarget.WORKFLOW_OBJECT
});
if (targets.length)
{
if (targets[0].getParameters().id == this._workflowName)
{
this.setDirty(true);
if (!this._tree.getRootNode().get("hasChanges") && targets[0].getParameters().hasChanges)
{
this._tree.getRootNode().set('hasChanges', true);
}
var targetStep = targets[0].getSubtarget(function(target) {
return target.getId() == Ametys.message.MessageTarget.WORKFLOW_STEP
});
if (targetStep != null)
{
var parentId = "root"
var stepId = targetStep.getParameters().id;
var createdId = stepId.toString().includes("step")? stepId : "step" + stepId;
var targetAction = targetStep.getSubtarget(function(target) {
return target.getId() == Ametys.message.MessageTarget.WORKFLOW_ACTION
});
if (targetAction != null)
{
parentId = createdId;
createdId = createdId + "-action" + targetAction.getParameters().id;
}
this._tree.onWorkflowElementModified(createdId, parentId, message.getType() == "created");
}
else
{
this.showOutOfDate();
}
}
}
},
/**
* Listener on workflow saved messages, set the tool clean
* @param {Ametys.message.Message} message The selection message.
* @private
*/
_onWorkflowSaved: function(message)
{
this._tree.getRootNode().set('hasChanges', false);
this.setDirty(false);
},
/**
* Listener on deleted messages, set the tool dirty
* @param {Ametys.message.Message} message The selection message.
* @private
*/
_onMessageDeleted: function(message)
{
var targets = message.getTargets();
if (targets.length)
{
if (targets[0].getParameters().id == this._workflowName || targets[0].getParameters().id ==this._workflowName)
{
if (!this._tree.getRootNode().get("hasChanges"))
{
this.setDirty(true);
this._tree.getRootNode().set('hasChanges', true);
}
}
}
},
createPanel: function()
{
this._tree = Ext.create("Ametys.plugins.workflow.trees.WorkflowEditorTree", {
rootVisible: true,
stateful: true,
stateId: this.self.getName() + "$tree&" + this._workflowName ,
scrollable: true,
allowEdition: true,
cls: 'uitool-workflow-editor',
columns: [
{
xtype: 'treecolumn',
header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_LABEL}}",
flex: 0.6,
sortable: true,
dataIndex: 'label',
editor: {
xtype: 'textfield',
allowBlank: false,
selectOnFocus: true
},
renderer: Ametys.plugins.workflow.trees.WorkflowEditorTree.renderLabels
},
{
header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_ID}}",
sortable: true,
flex : 0.1,
hidden: true,
dataIndex: 'elementId',
align: 'left',
},
{
header: "{{i18n PLUGINS_WORKFLOW_UITOOL_WORKFLOW_EDITOR_COLUMN_FINAL_STEP}}",
sortable: false,
flex : 0.3,
multiple: true,
dataIndex: 'targetedStep',
align: 'left',
renderer: Ametys.plugins.workflow.trees.WorkflowEditorTree.renderTargets
}
],
listeners: {
selectionchange: this.sendCurrentSelection,
itemdblclick: function(view, record)
{
var data = record.getData();
if (record.isRoot())
{
Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {workflowId: this._workflowName, elementType: "workflow"});
}
else if (data.elementType == "action")
{
var stepNode = this._tree.getStore().getNodeById(data.parentId);
Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {
workflowId: this._workflowName,
elementType: "action",
stepId: stepNode.getData().elementId,
stepLabel: stepNode.getData().label,
actionId: data.elementId,
actionLabel: data.label
});
}
else if (data.elementType == "step")
{
Ametys.tool.ToolsManager.openTool("uitool-workflow-preview", {workflowId: this._workflowName, elementType: "step", stepId: data.elementId, stepLabel: data.label});
}
},
scope: this
}
});
return this._tree;
}
});