/*
* Copyright 2016 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.
*/
/**
* This class controls a ribbon button for adding a task.
* @private
*/
Ext.define('Ametys.plugins.coreui.schedule.AddTaskButtonController', {
extend: 'Ametys.ribbon.element.ui.ButtonController',
/**
* @cfg {String} [taskLabel] The label of the task which will be created. Default to the controller label.
*/
/**
* @cfg {String} [taskDescription] The description of the task which will be created. Default to the controller description.
*/
/**
* @cfg {String} schedulable The id of the schedulable to create
*/
/**
* @cfg {Object} [schedulable-parameters] The parameters of the schedulable
*/
/**
* @cfg {String} [fire-process="NOW"] The way to fire the runnable. If equals to "CRON", then {@link #cfg-cron} must be non-null
*/
/**
* @cfg {String} [cron] The cron expression, only needed if {@link #cfg-fire-process} equals to "CRON"
*/
/**
* @cfg {Boolean} [log-tool-active=true] true to open the log tool when scheduling the task
*/
/**
* @cfg {String} [log-title] The title of the log tool to open when scheduling the task
*/
/**
* @cfg {String/String[]} [log-category] The logging categories for the ServerLog tool
*/
/**
* @cfg {String} [confirm-title] The title of the confirm dialog box. Must be non-null if {@link #cfg-confirm-msg} is non-null. If one is null, there will be no confirm dialog box.
*/
/**
* @cfg {String} [confirm-msg] The message content of the confirm dialog box. Must be non-null if {@link #cfg-confirm-title} is non-null. If one is null, there will be no confirm dialog box.
*/
/**
* @cfg {Boolean} [check-job-state=false] true to check te job state and send message bus when the task ends
*/
/**
* @cfg {Number} [check-job-state-delay=1000] time between 2 checks of the job state
*/
/**
* @property {Object} allParameters The declared parameters (already prefixed) of the associated schedulable
*/
inheritableStatics: {
/**
* Add the configured task
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
*/
act: function(controller)
{
// If some params of the schedulable are not given from the configuration, display a dialog box to the user
var fromConfSchedulableParameters = {},
schedulableId = controller.schedulable;
Ext.Object.each(controller['schedulable-parameters'] || {}, function(key, value) {
fromConfSchedulableParameters[schedulableId + "$" + key] = value;
});
// Params already set in Ametys app-parameters
var appParams = Ametys.getAppParameters();
for (var key in appParams)
{
if (!fromConfSchedulableParameters[schedulableId + "$" + key])
{
fromConfSchedulableParameters[schedulableId + "$" + key] = appParams[key];
}
}
var nonGivenParamNames = Ext.Array.difference(Ext.Object.getKeys(controller.allParameters), Ext.Object.getKeys(fromConfSchedulableParameters));
if (nonGivenParamNames.length == 0)
{
this._scheduleTask(controller, fromConfSchedulableParameters);
}
else
{
var data = {};
Ext.Array.forEach(nonGivenParamNames, function(paramName) {
data[paramName] = controller.allParameters[paramName];
});
var formPanel = Ext.create('Ametys.form.ConfigurableFormPanel', {
itemId: 'form',
defaultFieldConfig: {
labelWidth: 180
},
defaultPathSeparator: this._separator,
scrollable: true,
flex: 1
});
formPanel.configure(data);
formPanel.setValues(); // setValues must always be called for configurable form panel in order to complete its initialization
Ext.create('Ametys.window.DialogBox', {
title: controller['get-parameters-title'] || controller.taskLabel || controller.label,
iconCls: controller['icon-glyph'],
width: 550,
layout: {
type: "vbox",
align: "stretch"
},
defaultFocus: 'form',
items: [{
xtype: 'component',
html: controller['get-parameters-msg'] || controller.taskDescription || '{{i18n PLUGINS_CORE_UI_TASKS_ADD_TASK_BUTTON_CONTROLLER_DIALOG_GET_PARAMETERS_MSG}}'
}, formPanel],
referenceHolder: true,
defaultButton: 'validate',
closeAction: 'destroy',
buttons: [{
reference: 'validate',
itemId: 'button-validate',
text: "{{i18n PLUGINS_CORE_UI_TASKS_ADD_TASK_BUTTON_CONTROLLER_DIALOG_GET_PARAMETERS_BTN_OK}}",
handler: validate,
scope: this
}, {
itemId: 'button-cancel',
text: "{{i18n PLUGINS_CORE_UI_TASKS_ADD_TASK_BUTTON_CONTROLLER_DIALOG_GET_PARAMETERS_BTN_CANCEL}}",
handler: cancel
}]
})
.show();
function validate(button)
{
if (formPanel.isValid())
{
var fromUserSchedulableParameters = formPanel.getValues();
this._scheduleTask(controller, Ext.apply(fromUserSchedulableParameters, fromConfSchedulableParameters));
button.up('[xtype=dialog]').close();
}
else
{
var invalidFields = Ext.Array.filter(formPanel.getFieldNames(), function(fieldName) {
return !formPanel.getField(fieldName).isValid();
});
if (invalidFields.length > 0)
{
formPanel.getField(invalidFields[0]).focus();
}
}
}
function cancel(button)
{
button.up('[xtype=dialog]').close();
}
}
},
/**
* @protected
* Launch the scheduling of the task (possibly with a confirm dialog box)
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling this function
* @param {Object} params The parameters to pass to the scheduler (prefixed)
*/
_scheduleTask: function(controller, params)
{
var confirmTitle = controller['confirm-title'];
var confirmMsg = controller['confirm-msg'];
function callback(answer)
{
if (answer == 'yes')
{
var taskLabel = controller.taskLabel || controller.label;
var fireProcess = controller.fireProcess || "NOW";
controller.serverCall(
"add",
[taskLabel, controller.taskDescription || controller.description, fireProcess, controller.cron, controller.schedulable, params],
this._scheduleTaskCb,
{
errorMessage: true,
arguments:
{
categories: Ext.Array.from(controller['log-category']),
title: controller['log-title'],
logToolActive: controller['log-tool-active'] != false && controller['log-tool-active'] != "false",
checkState: controller['check-job-state'] == true || controller['check-job-state'] == "true",
checkStateDelay: controller['check-job-state-delay'] || 1000,
fireProcess: fireProcess,
taskLabel: taskLabel
}
}
);
}
}
if (confirmTitle != null && confirmMsg != null)
{
Ametys.Msg.confirm(
confirmTitle,
confirmMsg,
callback,
this
);
}
else
{
callback.call(this, 'yes');
}
},
/**
* @protected
* Callback method for schedule task
* @param {Object} response The server response
* @param {Object} arguments The callback arguments
* @param {String[]} arguments.categories The logging categories
* @param {String} arguments.title The title of the log tool
* @param {Boolean} arguments.logToolActive true to open the log tool
* @param {Boolean} arguments.checkState true to check the state of the scheduled task
* @param {Number} arguments.checkStateDelay The time between 2 checks of the state
* @param {String} arguments.fireProcess The way used to fire the runnable
* @param {String} arguments.taskLabel The label of the task
*/
_scheduleTaskCb: function(response, arguments)
{
this._openTools(response, arguments);
if (arguments.checkState && arguments.fireProcess == "NOW")
{
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.TASK_STARTED,
targets: [{
id: Ametys.message.MessageTarget.TASK,
parameters: {
id: response.id
}
}]
});
this._checkTaskState(response.id, arguments);
}
},
},
/**
* @protected
* Open the tools in callback
* @param {Object} response The server response
* @param {Object} arguments The callback arguments
* @param {String[]} arguments.categories The logging categories
* @param {String} arguments.title The title of the log tool
* @param {Boolean} arguments.logToolActive true to open the log tool
*/
_openTools: function(response, arguments)
{
function select(store, records, tool, recordId)
{
var record = store.getById(recordId);
if (record != null)
{
tool.getGrid().getSelectionModel().select([record]);
}
}
if (arguments.logToolActive)
{
Ametys.tool.ToolsManager.openTool('uitool-server-logs', {id: arguments.category, serverId: this.getId(), category: arguments.categories, title: arguments.title}, "cr");
}
if (Ametys.tool.ToolsManager.getFactory("uitool-scheduled-tasks") != null) // May have no right on scheduler
{
var scheduledTasksTool = Ametys.tool.ToolsManager.openTool('uitool-scheduled-tasks', {}, "cl");
if (scheduledTasksTool)
{
scheduledTasksTool.getGrid().getStore().on("load", Ext.bind(select, this, [scheduledTasksTool, response.id], 2), this, {single: true});
}
}
},
/**
* @protected
* Checks the state of the task and send appropriate events on message bus
* @param {String} taskId the tesk identifier
* @param {Object} arguments The callback arguments
* @param {Number} arguments.checkStateDelay The time between 2 checks of the state
* @param {String} arguments.taskLabel The label of the task
*/
_checkTaskState: function(taskId, arguments)
{
Ametys.plugins.core.schedule.Scheduler.getTasksInformation(
[[taskId]],
this._checkTaskStateCb,
{
errorMessage: Ext.String.format("{{i18n PLUGINS_CORE_UI_TASKS_ADD_TASK_BUTTON_CONTROLLER_CHECK_STATE_ERROR}}", arguments.taskLabel),
scope: this,
arguments: arguments
}
);
},
/**
* @protected
* Callback method for checking the task state
* @param {Object} response The server response
* @param {Object} arguments The callback arguments
* @param {Number} arguments.checkStateDelay The time between 2 checks of the state
* @param {String} arguments.taskLabel The label of the task
*/
_checkTaskStateCb: function(response, arguments)
{
if (response.length > 0)
{
var task = response[0];
if (task.getState() == "running")
{
Ext.defer(this._checkTaskState, arguments.checkStateDelay, this, [task.getId(), arguments]);
}
else if (task.getState() == "success" || task.getState() == "failure")
{
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.TASK_ENDED,
parameters: {
state: task.getState()
},
targets: [{
id: Ametys.message.MessageTarget.TASK,
parameters: {
tasks: [task]
}
}]
});
}
else if (task.getState() == "waiting")
{
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.TASK_AWAITING,
targets: [{
id: Ametys.message.MessageTarget.TASK,
parameters: {
tasks: [task]
}
}]
});
}
// We do not add a message bus for disabled tasks because it should not happen here
}
},
constructor: function(config)
{
this.callParent(arguments);
this._configureSchedulerParameters(config);
},
/**
* @protected
* Method to configure scheduler parameters.
* @param {Object} config The constructor configuration
*/
_configureSchedulerParameters: function(config)
{
this.serverCall("getParameters", [config.schedulable], function(parameters) {
this.allParameters = parameters;
}, {scope: this, errorMessage: true});
},
getServerId: function()
{
// When used as a generated menu, get the server id from the primary menu item itself for callable methods.
// Indeed the client side element of a generated menu is a org.ametys.core.ui.SimpleMenu
// instead of a org.ametys.core.ui.AddTaskClientSideElement
return this.getInitialConfig("primary-menu-item-id") || this.callParent(arguments);
}
});