diff --git a/src/sunstone/public/app/tabs/provision-tab/flows/list.js b/src/sunstone/public/app/tabs/provision-tab/flows/list.js
new file mode 100644
index 0000000000..b7d0366ab0
--- /dev/null
+++ b/src/sunstone/public/app/tabs/provision-tab/flows/list.js
@@ -0,0 +1,695 @@
+define(function(require) {
+ var OpenNebula = require('opennebula');
+ var Locale = require('utils/locale');
+ var Notifier = require('utils/notifier');
+ var Humanize = require('utils/humanize');
+ var ResourceSelect = require('utils/resource-select');
+
+ var ProvisionVmsList = require('tabs/provision-tab/vms/list');
+
+ var TemplateFlowsList = require('hbs!./list');
+
+ var _accordionId = 0;
+
+ return {
+ 'generate': generate_provision_flows_list,
+ 'show': show_provision_flow_list
+ };
+
+
+ function show_provision_flow_list(timeout) {
+ $(".section_content").hide();
+ $(".provision_flows_list_section").fadeIn();
+
+ $("dd:not(.active) .provision_back", $(".provision_flows_list_section")).trigger("click");
+ $(".provision_flows_list_refresh_button", $(".provision_flows_list_section")).trigger("click");
+ }
+
+ function generate_provision_flows_list(context, opts) {
+ context.off();
+ context.html(html(opts));
+ setup_provision_flows_list(context, opts);
+ setup_info_flow(context);
+ }
+
+ function html(opts_arg){
+ opts = $.extend({
+ title: Locale.tr("Services"),
+ active: true,
+ refresh: true,
+ create: true,
+ filter: true
+ },opts_arg)
+
+ _accordionId += 1;
+ return TemplateFlowsList({'accordionId': _accordionId, 'opts': opts});
+ }
+
+ function update_provision_flows_datatable(datatable, timeout) {
+ datatable.html('
'+
+ ''+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ''+
+ ' '+
+ '
');
+
+ setTimeout( function(){
+ OpenNebula.Service.list({
+ timeout: true,
+ success: function (request, item_list){
+ $(".flow_error_message").hide();
+ datatable.fnClearTable(true);
+ if (item_list.length == 0) {
+ datatable.html('
'+
+ ''+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ''+
+ Locale.tr("There are no Services")+
+ ' '+
+ ' '+
+ ' '+
+ '
');
+ } else {
+ datatable.fnAddData(item_list);
+ }
+ },
+ error: function(request, error_json) {
+ datatable.html('
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+Locale.tr("Cannot connect to OneFlow server")+'
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ ' '+
+ '
');
+
+ Notifier.onError(request, error_json, $(".flow_error_message"));
+ }
+ })
+ }, timeout );
+ }
+
+ function setup_provision_flows_list(context, opts){
+ //
+ // List Flows
+ //
+
+ provision_flows_datatable = $('.provision_flows_table', context).dataTable({
+ "iDisplayLength": 6,
+ "sDom" : '<"H">t<"F"lp>',
+ "aLengthMenu": [[6, 12, 36, 72], [6, 12, 36, 72]],
+ "aaSorting" : [[0, "desc"]],
+ "aoColumnDefs": [
+ { "bVisible": false, "aTargets": ["all"]}
+ ],
+ "aoColumns": [
+ { "mDataProp": "DOCUMENT.ID" },
+ { "mDataProp": "DOCUMENT.NAME" },
+ { "mDataProp": "DOCUMENT.UID" }
+ ],
+ "fnPreDrawCallback": function (oSettings) {
+ // create a thumbs container if it doesn't exist. put it in the dataTables_scrollbody div
+ if (this.$('tr', {"filter": "applied"} ).length == 0) {
+ this.html('
'+
+ '
'+
+ ' '+
+ ' '+
+ ' '+
+ '
'+
+ '
'+
+ '
'+
+ Locale.tr("Looks like you don't have any Service. Click the button below to get started")+
+ ' '+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
');
+ } else {
+ $(".provision_flows_table", context).html('
');
+ }
+
+ return true;
+ },
+ "fnDrawCallback": function (oSettings) {
+ $(".provision_flows_ul", context).foundation('reflow', 'tooltip');
+ },
+ "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
+ var data = aData.DOCUMENT;
+ var body = data.TEMPLATE.BODY;
+ var state = get_provision_flow_state(body);
+ var start_time = get_provision_flow_start_time(body);
+
+ var roles_li = "";
+ if (body.roles) {
+ $.each(body.roles, function(index, role) {
+ var role_state = get_provision_flow_state(role);
+ var rvms = {
+ str : (role.nodes ? role.nodes.length : 0) + " / " + role.cardinality ,
+ percentage : Math.floor((role.nodes ? role.nodes.length : 0) / role.cardinality)*100
+ }
+
+ roles_li +=
+ '
'+
+ ' '+
+ role.name+
+ ''+rvms.str+" VMs "+
+ ' ';
+ });
+ }
+
+ $(".provision_flows_ul", context).append('
'+
+ ''+
+ ' ');
+
+ return nRow;
+ }
+ });
+
+ $('.provision_list_flows_search', context).keyup(function(){
+ provision_flows_datatable.fnFilter( $(this).val() );
+ })
+
+ $('.provision_list_flows_search', context).change(function(){
+ provision_flows_datatable.fnFilter( $(this).val() );
+ })
+
+ context.on("click", ".provision_flows_list_refresh_button", function(){
+ OpenNebula.Action.clear_cache("SERVICE");
+ update_provision_flows_datatable(provision_flows_datatable, 0);
+ return false;
+ });
+
+ context.on("click", ".provision_flows_list_search_button", function(){
+ $(".provision_list_flows_search", context).fadeIn();
+ });
+
+ $(".provision_list_flows_filter", context).on("change", ".resource_list_select", function(){
+ if ($(this).val() != "-2"){
+ provision_flows_datatable.fnFilter("^" + $(this).val() + "$", 2, true, false);
+ } else {
+ provision_flows_datatable.fnFilter("", 2);
+ }
+ })
+
+ ResourceSelect.insert(
+ ".provision_list_flows_filter",
+ context,
+ "User",
+ (opts.filter_expression ? opts.filter_expression : "-2"),
+ false,
+ '
'+Locale.tr("ALL")+' ',
+ null,
+ null,
+ true,
+ true);
+
+ context.on("click", ".provision_flows_list_filter_button", function(){
+ $(".provision_list_flows_filter", context).fadeIn();
+ return false;
+ });
+
+ OpenNebula.Action.clear_cache("SERVICE");
+ update_provision_flows_datatable(provision_flows_datatable, 0);
+
+ $(document).foundation();
+ }
+
+ function setup_info_flow(context) {
+ function update_provision_flow_info(flow_id, context, role_id) {
+ $(".provision_info_flow_name", context).text("");
+ $(".provision_info_flow", context).css('visibility', 'hidden');
+ $(".provision_info_flow_loading", context).fadeIn();
+ $(".provision_role_vms_container").html("");
+
+ OpenNebula.Service.show({
+ data : {
+ id: flow_id
+ },
+ error: Notifier.onError,
+ success: function(request, response){
+ var data = response.DOCUMENT
+ var body = data.TEMPLATE.BODY;
+ var state = get_provision_flow_state(body);
+ var start_time = get_provision_flow_start_time(body);
+
+ switch (state.color) {
+ case "deploying":
+ $(".provision_recover_button", context).hide();
+ $(".provision_delete_confirm_button", context).show();
+ $(".provision_shutdown_confirm_button", context).show();
+ break;
+ case "running":
+ $(".provision_recover_button", context).hide();
+ $(".provision_delete_confirm_button", context).show();
+ $(".provision_shutdown_confirm_button", context).show();
+ break;
+ case "off":
+ $(".provision_recover_button", context).hide();
+ $(".provision_delete_confirm_button", context).show();
+ $(".provision_shutdown_confirm_button", context).hide();
+ break;
+ case "powering_off":
+ case "error":
+ $(".provision_recover_button", context).show();
+ $(".provision_delete_confirm_button", context).show();
+ $(".provision_shutdown_confirm_button", context).show();
+ break;
+ default:
+ $(".provision_recover_button", context).show();
+ $(".provision_delete_confirm_button", context).show();
+ $(".provision_shutdown_confirm_button", context).show();
+ break;
+ }
+
+ $(".provision_info_flow", context).attr("flow_id", data.ID);
+ $(".provision_info_flow_name", context).text(data.NAME);
+
+ $(".provision-pricing-table_flow_info", context).html(
+ '
'+
+ ''+
+ ' '+
+ state.str+
+ ' '+
+ ' '+
+ '
'+
+ ' '+
+ ' '+
+ '
'+
+ ''+
+ ' '+
+ data.UNAME+
+ ' '+
+ ''+
+ ' '+
+ (start_time ? Humanize.prettyTimeAgo(start_time) : "...") +
+ ' - '+
+ 'ID: '+
+ data.ID+
+ ' '+
+ ' '+
+ '');
+
+ $(".provision_roles_ul", context).html("");
+ if (body.roles) {
+ $.each(body.roles, function(index, role) {
+ var role_state = get_provision_flow_state(role);
+ var rvms = {
+ str : (role.nodes ? role.nodes.length : 0) + " / " + role.cardinality ,
+ percentage : Math.floor((role.nodes ? role.nodes.length : 0) / role.cardinality)*100
+ }
+
+ var li = $(
+ '
'+
+ ''+
+ ''+
+ ' '+
+ role.name+
+ ' '+
+ ''+
+ ''+
+ ' '+
+ '
'+
+ ' '+
+ ''+
+ ''+
+ role_state.str+
+ ' '+
+ ''+rvms.str+" VMs "+
+ ' '+
+ ''+
+ ' '+
+ ' '+
+ ''+
+ ''+
+ ' '+
+ ' '+
+ ''+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ' ').appendTo($(".provision_roles_ul", context));
+
+ $(".provision_role_ul", li).data("role", role);
+ if (role_id && role_id == role.name) {
+ $(".provision_role_vms_button", li).trigger("click");
+ }
+ });
+ }
+
+ $(".provision_info_flow_state_hr", context).html('
');
+
+ $(".provision_confirm_action:first", context).html("");
+
+ $(".provision_info_flow_loading", context).hide();
+ $(".provision_info_flow", context).css('visibility', 'visible');
+ }
+ })
+ }
+
+ context.on("click", ".provision_role_vms_button", function(){
+ $(".provision_role_vms_container", context).html('
'+
+ ''+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ' '+
+ ''+
+ ' '+
+ '
');
+
+ var role = $(this).closest(".provision_role_ul").data('role');
+ $(".provision_info_flow", context).data("role_id", role.name);
+ var vms = []
+
+ if (role.nodes && role.nodes.length > 0) {
+ $.each(role.nodes, function(index, node){
+ vms.push(node.vm_info);
+ })
+ }
+
+ ProvisionVmsList.generate(
+ $(".provision_role_vms_container", context),
+ {
+ title: role.name + ' ' + Locale.tr("VMs"),
+ active: true,
+ refresh: false,
+ create: false,
+ filter: false,
+ data: vms
+ });
+ })
+
+ context.on("click", ".provision_role_cardinality_button", function(){
+ var role = $(this).closest(".provision_role_ul").data('role');
+ var min_vms = (role.min_vms||1);
+ var max_vms = (role.max_vms||100);
+
+ $(".provision_confirm_action:first", context).html(
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ ''+role.cardinality+' '+
+ ' '+
+ ''+role.name + ' ' + Locale.tr("VMs")+' '+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ ' '+
+ ' '+
+ ''+Locale.tr("The cardinality for this role cannot be changed")+' '+
+ '
'+
+ '
'+
+ '
'+
+ '
'+
+ '
× '+
+ '
');
+
+
+ if (max_vms > min_vms) {
+ $( ".cardinality_slider_div", context).show();
+ $( ".cardinality_no_slider_div", context).hide();
+
+ var provision_cardinality_slider = $( ".cardinality_slider", context).noUiSlider({
+ handles: 1,
+ connect: "lower",
+ range: [min_vms, max_vms],
+ step: 1,
+ start: role.cardinality,
+ value: role.cardinality,
+ slide: function(type) {
+ if ( type != "move"){
+ if ($(this).val()) {
+ $(".cardinality_value", context).html($(this).val());
+ }
+ }
+ }
+ });
+
+ provision_cardinality_slider.val(role.cardinality)
+
+ provision_cardinality_slider.addClass("noUiSlider");
+ } else {
+ $( ".cardinality_slider_div", context).hide();
+ $( ".cardinality_no_slider_div", context).show();
+ }
+
+ return false;
+ });
+
+ context.on("click", ".provision_change_cardinality_button", function(){
+ var flow_id = $(".provision_info_flow", context).attr("flow_id");
+ var cardinality = $(".cardinality_slider", context).val()
+
+ OpenNebula.Role.update({
+ data : {
+ id: flow_id + '/role/' + $(this).attr("role_id"),
+ extra_param: {
+ cardinality: cardinality
+ }
+ },
+ success: function(request, response){
+ OpenNebula.Action.clear_cache("SERVICE");
+ $(".provision_refresh_info", context).trigger("click");
+ },
+ error: Notifier.onError
+ })
+ });
+
+ context.on("click", ".provision_delete_confirm_button", function(){
+ $(".provision_confirm_action:first", context).html(
+ '
'+
+ '
'+
+ '
'+
+ ''+
+ Locale.tr("Be careful, this action will inmediately destroy your Service")+
+ ' '+
+ Locale.tr("All the information will be lost!")+
+ ' '+
+ '
'+
+ '
'+
+ '
'+
+ '
× '+
+ '
');
+ });
+
+ context.on("click", ".provision_shutdown_confirm_button", function(){
+ $(".provision_confirm_action:first", context).html(
+ '
'+
+ '
'+
+ '
'+
+ ''+
+ Locale.tr("Be careful, this action will inmediately shutdown your Service")+
+ ' '+
+ Locale.tr("All the information will be lost!")+
+ ' '+
+ '
'+
+ '
'+
+ '
'+
+ '
× '+
+ '
');
+ });
+
+ context.on("click", ".provision_recover_button", function(){
+ var flow_id = $(".provision_info_flow", context).attr("flow_id");
+
+ OpenNebula.Service.recover({
+ data : {
+ id: flow_id
+ },
+ success: function(request, response){
+ update_provision_flow_info(flow_id, context);
+ },
+ error: Notifier.onError
+ })
+ });
+
+ context.on("click", ".provision_shutdown_button", function(){
+ var flow_id = $(".provision_info_flow", context).attr("flow_id");
+
+ OpenNebula.Service.shutdown({
+ data : {
+ id: flow_id
+ },
+ success: function(request, response){
+ update_provision_flow_info(flow_id, context);
+ },
+ error: Notifier.onError
+ })
+ });
+
+ context.on("click", ".provision_delete_button", function(){
+ var button = $(this);
+ button.attr("disabled", "disabled");
+ var flow_id = $(".provision_info_flow", context).attr("flow_id");
+
+ OpenNebula.Service.del({
+ data : {
+ id: flow_id
+ },
+ success: function(request, response){
+ $(".provision_back", context).click();
+ $(".provision_flows_list_refresh_button", context).click();
+ button.removeAttr("disabled");
+ },
+ error: function(request, response){
+ Notifier.onError(request, response);
+ button.removeAttr("disabled");
+ }
+ })
+ });
+
+ context.on("click", ".provision_refresh_info", function(){
+ var flow_id = $(".provision_info_flow", context).attr("flow_id");
+ var role_id = $(".provision_info_flow", context).data("role_id");
+ update_provision_flow_info(flow_id, context, role_id);
+ //$(".provision_flows_list_refresh_button", $(".provision_flows_list_section")).trigger("click");
+ return false;
+ });
+
+ //
+ // Info Flow
+ //
+
+ $(".provision_list_flows", context).on("click", ".provision_info_flow_button", function(){
+ $("a.provision_show_flow_accordion", context).trigger("click");
+
+ var flow_id = $(this).parents(".provision-pricing-table").attr("opennebula_id")
+ update_provision_flow_info(flow_id, context);
+ return false;
+ })
+ }
+
+ function get_provision_flow_start_time(data) {
+ if (data.log) {
+ return data.log[0].timestamp
+ } else {
+ return null;
+ }
+ }
+
+ // @params
+ // data: and BODY object of the Document representing the Service
+ // Example: data.ID
+ // @returns and object containing the following properties
+ // color: css class for this state.
+ // color + '-color' font color class
+ // color + '-bg' background class
+ // str: user friendly state string
+ function get_provision_flow_state(data) {
+ var state = OpenNebula.Service.state(data.state);
+ var state_color;
+ var state_str;
+
+ switch (state) {
+ case Locale.tr("PENDING"):
+ state_color = 'deploying';
+ state_str = Locale.tr("PENDING");
+ break;
+ case Locale.tr("DEPLOYING"):
+ state_color = 'deploying';
+ state_str = Locale.tr("DEPLOYING");
+ break;
+ case Locale.tr("UNDEPLOYING"):
+ state_color = 'powering_off';
+ state_str = Locale.tr("UNDEPLOYING");
+ break;
+ case Locale.tr("FAILED_UNDEPLOYING"):
+ state_color = 'error';
+ state_str = Locale.tr("FAILED UNDEPLOYING");
+ break;
+ case Locale.tr("FAILED_DEPLOYING"):
+ state_color = 'error';
+ state_str = Locale.tr("FAILED DEPLOYING");
+ break;
+ case Locale.tr("FAILED_SCALING"):
+ state_color = 'error';
+ state_str = Locale.tr("FAILED SCALING");
+ break;
+ case Locale.tr("WARNING"):
+ state_color = 'error';
+ state_str = Locale.tr("WARNING");
+ break;
+ case Locale.tr("RUNNING"):
+ state_color = 'running';
+ state_str = Locale.tr("RUNNING");
+ break;
+ case Locale.tr("SCALING"):
+ state_color = 'deploying';
+ state_str = Locale.tr("SCALING");
+ break;
+ case Locale.tr("COOLDOWN"):
+ state_color = 'error';
+ state_str = Locale.tr("COOLDOWN");
+ break;
+ case Locale.tr("DONE"):
+ state_color = 'off';
+ state_str = Locale.tr("DONE");
+ break;
+ default:
+ state_color = 'powering_off';
+ state_str = Locale.tr("UNKNOWN");
+ break;
+ }
+
+ return {
+ color: state_color,
+ str: state_str
+ }
+ }
+});