Blame SOURCES/bz1281391-01-web-UI-add-possibility-to-change-order-of-resources-.patch

15f218
From 0a96fde9b1d691268948091442c2f0075e81ab95 Mon Sep 17 00:00:00 2001
15f218
From: Ondrej Mular <omular@redhat.com>
15f218
Date: Thu, 28 Jul 2016 15:21:18 +0200
15f218
Subject: [PATCH] web UI: add possibility to change order of resources in group
15f218
15f218
---
15f218
 pcsd/pcs.rb                   |   1 +
15f218
 pcsd/public/css/style.css     |  10 +++
15f218
 pcsd/public/js/nodes-ember.js | 167 ++++++++++++++++++++++++++++++++++++++----
15f218
 pcsd/public/js/pcsd.js        | 117 +++++++++++++++++------------
15f218
 pcsd/remote.rb                |  47 ++++++++----
15f218
 pcsd/views/_dialogs.erb       |  21 ++++++
15f218
 pcsd/views/_resource.erb      |   6 --
15f218
 pcsd/views/main.erb           |  51 +++++++++++--
15f218
 8 files changed, 334 insertions(+), 86 deletions(-)
15f218
15f218
diff --git a/pcsd/pcs.rb b/pcsd/pcs.rb
15f218
index ad54a75..1eb9e9e 100644
15f218
--- a/pcsd/pcs.rb
15f218
+++ b/pcsd/pcs.rb
15f218
@@ -1702,6 +1702,7 @@ def get_node_status(auth_user, cib_dom)
15f218
         'constraint_colocation_set',
15f218
         'sbd',
15f218
         'ticket_constraints',
15f218
+        'moving_resource_in_group',
15f218
       ]
15f218
   }
15f218
 
15f218
diff --git a/pcsd/public/css/style.css b/pcsd/public/css/style.css
15f218
index d41b164..0d744d5 100644
15f218
--- a/pcsd/public/css/style.css
15f218
+++ b/pcsd/public/css/style.css
15f218
@@ -848,3 +848,13 @@ table.args-table td.reg {
15f218
 .constraint-ticket-add-attribute {
15f218
   vertical-align: top;
15f218
 }
15f218
+
15f218
+.cursor-move {
15f218
+  cursor: move;
15f218
+}
15f218
+
15f218
+.sortable-table td {
15f218
+  height: 1.5em;
15f218
+  line-height: 1.2em;
15f218
+  background: black;
15f218
+}
15f218
diff --git a/pcsd/public/js/nodes-ember.js b/pcsd/public/js/nodes-ember.js
15f218
index efc0192..3d4fe79 100644
15f218
--- a/pcsd/public/js/nodes-ember.js
15f218
+++ b/pcsd/public/js/nodes-ember.js
15f218
@@ -52,6 +52,11 @@ Pcs = Ember.Application.createWithMixins({
15f218
       this.get("available_features").indexOf("constraint_colocation_set") != -1
15f218
     );
15f218
   }.property("available_features"),
15f218
+  is_supported_moving_resource_in_group: function() {
15f218
+    return (
15f218
+      this.get("available_features").indexOf("moving_resource_in_group") != -1
15f218
+    );
15f218
+  }.property("available_features"),
15f218
   is_sbd_running: false,
15f218
   is_sbd_enabled: false,
15f218
   is_sbd_enabled_or_running: function() {
15f218
@@ -245,6 +250,154 @@ Pcs = Ember.Application.createWithMixins({
15f218
   }
15f218
 });
15f218
 
15f218
+Pcs.GroupSelectorComponent = Ember.Component.extend({
15f218
+  resource_id: null,
15f218
+  resource: function() {
15f218
+    var id = this.get("resource_id");
15f218
+    if (id) {
15f218
+      var resource = Pcs.resourcesContainer.get_resource_by_id(id);
15f218
+      if (resource) {
15f218
+        return resource;
15f218
+      }
15f218
+    }
15f218
+    return null;
15f218
+  }.property("resource_id"),
15f218
+  resource_change: function() {
15f218
+    this._refresh_fn();
15f218
+    this._update_resource_select_content();
15f218
+    this._update_resource_select_value();
15f218
+  }.observes("resource", "resource_id"),
15f218
+  group_list: [],
15f218
+  group_select_content: function() {
15f218
+    var list = [];
15f218
+    $.each(this.get("group_list"), function(_, group) {
15f218
+      list.push({
15f218
+        name: group,
15f218
+        value: group
15f218
+      });
15f218
+    });
15f218
+    return list;
15f218
+  }.property("group_list"),
15f218
+  group_select_value: null,
15f218
+  group: function() {
15f218
+    var id = this.get("group_select_value");
15f218
+    if (id) {
15f218
+      var group = Pcs.resourcesContainer.get_resource_by_id(id);
15f218
+      if (group) {
15f218
+        return group;
15f218
+      }
15f218
+    }
15f218
+    return null;
15f218
+  }.property("group_select_value"),
15f218
+  position_select_content: [
15f218
+    {
15f218
+      name: "before",
15f218
+      value: "before"
15f218
+    },
15f218
+    {
15f218
+      name: "after",
15f218
+      value: "after"
15f218
+    }
15f218
+  ],
15f218
+  position_select_value: null,
15f218
+  position_select_value_changed: function() {
15f218
+  }.observes("position_select_value"),
15f218
+  resource_select_content: [],
15f218
+  resource_select_value: null,
15f218
+  group_select_value_changed: function () {
15f218
+    this._update_resource_select_content();
15f218
+    this._update_resource_select_value();
15f218
+  }.observes("group_select_value"),
15f218
+  actions: {
15f218
+    refresh: function() {
15f218
+      this.set("group_list", Pcs.resourcesContainer.get("group_list"));
15f218
+      this._refresh_fn();
15f218
+      this._update_resource_select_content();
15f218
+      this._update_resource_select_value();
15f218
+    }
15f218
+  },
15f218
+  _refresh_fn: function() {
15f218
+    var id = this.get("resource_id");
15f218
+    if (id) {
15f218
+      var resource = Pcs.resourcesContainer.get_resource_by_id(id);
15f218
+      if (resource) {
15f218
+        var parent = resource.get("parent");
15f218
+        if (parent && parent.get("is_group")) {
15f218
+          this.set("group_select_value", parent.get("id"));
15f218
+          return;
15f218
+        }
15f218
+      }
15f218
+    }
15f218
+    this.set("group_select_value", null);
15f218
+  },
15f218
+  _update_resource_select_content: function() {
15f218
+    var self = this;
15f218
+    var group = self.get("group");
15f218
+    if (!group) {
15f218
+      self.set("resource_select_content", []);
15f218
+      return;
15f218
+    }
15f218
+    var list = [];
15f218
+    var resource_id;
15f218
+    $.each(group.get("members"), function(_, resource) {
15f218
+      resource_id = resource.get("id");
15f218
+      if (resource_id != self.get("resource_id")) {
15f218
+        list.push({
15f218
+          name: resource_id,
15f218
+          value: resource_id
15f218
+        });
15f218
+      }
15f218
+    });
15f218
+    self.set("resource_select_content", list);
15f218
+  },
15f218
+  _update_resource_select_value: function() {
15f218
+    var self = this;
15f218
+    var group = self.get("group");
15f218
+    var resource = self.get("resource");
15f218
+    if (!group) {
15f218
+      self.set("resource_select_value", null);
15f218
+      return;
15f218
+    }
15f218
+    var resource_list = group.get("members");
15f218
+    if (
15f218
+      !resource ||
15f218
+      !resource.get("parent") ||
15f218
+      resource.get("parent").get("id") != group.get("id")
15f218
+    ) {
15f218
+      self.set("position_select_value", "after");
15f218
+      self.set("resource_select_value", resource_list.slice(-1)[0].get("id"));
15f218
+    } else {
15f218
+      var index = resource_list.findIndex(function(item) {
15f218
+        return item.get("id") == resource.get("id");
15f218
+      });
15f218
+      if (index == 0) {
15f218
+        self.set("position_select_value", "before");
15f218
+        self.set(
15f218
+          "resource_select_value",
15f218
+          (resource_list[1]) ? resource_list[1].get("id") : null // second
15f218
+        );
15f218
+      } else if (index == -1) {
15f218
+        self.set("position_select_value", "after");
15f218
+        self.set("resource_select_value", resource_list.slice(-1)[0].get("id"));
15f218
+      } else {
15f218
+        self.set("position_select_value", "after");
15f218
+        self.set("resource_select_value", resource_list[index-1].get("id"));
15f218
+      }
15f218
+    }
15f218
+  },
15f218
+  group_input_name: "group_id",
15f218
+  classNames: "group-selector",
15f218
+  init: function() {
15f218
+    this._super();
15f218
+    if (this.get("resource_id")) {
15f218
+      this.set("group_list", Pcs.resourcesContainer.get("group_list"));
15f218
+    }
15f218
+    this._refresh_fn();
15f218
+    this._update_resource_select_content();
15f218
+    this._update_resource_select_value();
15f218
+  }
15f218
+});
15f218
+
15f218
 Pcs.ValueSelectorComponent = Ember.Component.extend({
15f218
   tagName: 'select',
15f218
   attributeBindings: ['name'],
15f218
@@ -682,20 +835,6 @@ Pcs.ResourceObj = Ember.Object.extend({
15f218
     }
15f218
     return null;
15f218
   }.property('parent'),
15f218
-  group_selector: function() {
15f218
-    var self = this;
15f218
-    var cur_group = self.get('get_group_id');
15f218
-    var html = '<select>\n<option value="">None</option>\n';
15f218
-    $.each(self.get('group_list'), function(_, group) {
15f218
-      html += '
15f218
-      if (cur_group === group) {
15f218
-        html += 'selected';
15f218
-      }
15f218
-      html += '>' + group + '</option>\n';
15f218
-    });
15f218
-    html += '</select><input type="button" value="Change group" onclick="resource_change_group(curResource(), $(this).prev().prop(\'value\'));">';
15f218
-    return html;
15f218
-  }.property('group_list', 'get_group_id'),
15f218
   status: "unknown",
15f218
   class_type: null, // property to determine type of the resource
15f218
   resource_type: function() { // this property is just for displaying resource type in GUI
15f218
diff --git a/pcsd/public/js/pcsd.js b/pcsd/public/js/pcsd.js
15f218
index a646bed..82187ef 100644
15f218
--- a/pcsd/public/js/pcsd.js
15f218
+++ b/pcsd/public/js/pcsd.js
15f218
@@ -96,50 +96,77 @@ function select_menu(menu, item, initial) {
15f218
 }
15f218
 
15f218
 function create_group() {
15f218
-  var num_nodes = 0;
15f218
-  var node_names = "";
15f218
-  $("#resource_list :checked").parent().parent().each(function (index,element) {
15f218
-    if (element.getAttribute("nodeID")) {
15f218
-      num_nodes++;
15f218
-      node_names += element.getAttribute("nodeID") + " "
15f218
-    }
15f218
-  });
15f218
-
15f218
-  if (num_nodes == 0) {
15f218
+  var resource_list = get_checked_ids_from_nodelist("resource_list");
15f218
+  if (resource_list.length == 0) {
15f218
     alert("You must select at least one resource to add to a group");
15f218
     return;
15f218
   }
15f218
-
15f218
-  $("#resources_to_add_to_group").val(node_names);
15f218
+  var not_primitives = resource_list.filter(function(resource_id) {
15f218
+    return !Pcs.resourcesContainer.get_resource_by_id(resource_id).get(
15f218
+      "is_primitive"
15f218
+    );
15f218
+  });
15f218
+  if (not_primitives.length != 0) {
15f218
+    alert("Members of group have to be primitive resources. These resources" +
15f218
+      " are not primitives: " + not_primitives.join(", "));
15f218
+    return;
15f218
+  }
15f218
+  var order_el = $("#new_group_resource_list tbody");
15f218
+  order_el.empty();
15f218
+  order_el.append(resource_list.map(function (item) {
15f218
+    return `${item}`;
15f218
+  }));
15f218
+  var order_obj = order_el.sortable();
15f218
+  order_el.disableSelection();
15f218
   $("#add_group").dialog({
15f218
     title: 'Create Group',
15f218
+    width: 'auto',
15f218
     modal: true,
15f218
     resizable: false,
15f218
-    buttons: {
15f218
-      Cancel: function() {
15f218
-        $(this).dialog("close");
15f218
+    buttons: [
15f218
+      {
15f218
+        text: "Cancel",
15f218
+        click: function() {
15f218
+          $(this).dialog("close");
15f218
+        }
15f218
       },
15f218
-      "Create Group": function() {
15f218
-        var data = $('#add_group > form').serialize();
15f218
-        var url = get_cluster_remote_url() + "add_group";
15f218
-        ajax_wrapper({
15f218
-          type: "POST",
15f218
-          url: url,
15f218
-          data: data,
15f218
-          success: function() {
15f218
-            Pcs.update();
15f218
-            $("#add_group").dialog("close");
15f218
-          },
15f218
-          error: function (xhr, status, error) {
15f218
-            alert(
15f218
-              "Error creating group "
15f218
-              + ajax_simple_error(xhr, status, error)
15f218
-            );
15f218
-            $("#add_group").dialog("close");
15f218
-          }
15f218
-        });
15f218
+      {
15f218
+        text: "Create Group",
15f218
+        id: "add_group_submit_btn",
15f218
+        click: function() {
15f218
+          var dialog_obj = $(this);
15f218
+          var submit_btn_obj = dialog_obj.parent().find(
15f218
+            "#add_group_submit_btn"
15f218
+          );
15f218
+          submit_btn_obj.button("option", "disabled", true);
15f218
+
15f218
+          ajax_wrapper({
15f218
+            type: "POST",
15f218
+            url: get_cluster_remote_url() + "add_group",
15f218
+            data: {
15f218
+              resource_group: $(
15f218
+                '#add_group:visible input[name=resource_group]'
15f218
+              ).val(),
15f218
+              resources: order_obj.sortable(
15f218
+                "toArray", {attribute: "value"}
15f218
+              ).join(" ")
15f218
+            },
15f218
+            success: function() {
15f218
+              submit_btn_obj.button("option", "disabled", false);
15f218
+              Pcs.update();
15f218
+              dialog_obj.dialog("close");
15f218
+            },
15f218
+            error: function (xhr, status, error) {
15f218
+              alert(
15f218
+                "Error creating group "
15f218
+                + ajax_simple_error(xhr, status, error)
15f218
+              );
15f218
+              submit_btn_obj.button("option", "disabled", false);
15f218
+            }
15f218
+          });
15f218
+        }
15f218
       }
15f218
-    }
15f218
+    ]
15f218
   });
15f218
 }
15f218
 
15f218
@@ -2257,24 +2284,24 @@ function resource_ungroup(group_id) {
15f218
   });
15f218
 }
15f218
 
15f218
-function resource_change_group(resource_id, group_id) {
15f218
+function resource_change_group(resource_id, form) {
15f218
   if (resource_id == null) {
15f218
     return;
15f218
   }
15f218
   show_loading_screen();
15f218
   var resource_obj = Pcs.resourcesContainer.get_resource_by_id(resource_id);
15f218
   var data = {
15f218
-    resource_id: resource_id,
15f218
-    group_id: group_id
15f218
+    resource_id: resource_id
15f218
   };
15f218
+  $.each($(form).serializeArray(), function(_, item) {
15f218
+    data[item.name] = item.value;
15f218
+  });
15f218
 
15f218
-  if (resource_obj.get('parent')) {
15f218
-    if (resource_obj.get('parent').get('id') == group_id) {
15f218
-      return;
15f218
-    }
15f218
-    if (resource_obj.get('parent').get('class_type') == 'group') {
15f218
-      data['old_group_id'] = resource_obj.get('parent').get('id');
15f218
-    }
15f218
+  if (
15f218
+    resource_obj.get('parent') &&
15f218
+    resource_obj.get('parent').get('class_type') == 'group'
15f218
+  ) {
15f218
+    data['old_group_id'] = resource_obj.get('parent').get('id');
15f218
   }
15f218
 
15f218
   ajax_wrapper({
15f218
diff --git a/pcsd/remote.rb b/pcsd/remote.rb
15f218
index 05a6d03..4844adf 100644
15f218
--- a/pcsd/remote.rb
15f218
+++ b/pcsd/remote.rb
15f218
@@ -1415,21 +1415,23 @@ def update_resource (params, request, auth_user)
15f218
 
15f218
   param_line = getParamList(params)
15f218
   if not params[:resource_id]
15f218
-    out, stderr, retval = run_cmd(
15f218
-      auth_user,
15f218
-      PCS, "resource", "create", params[:name], params[:resource_type],
15f218
-      *param_line
15f218
-    )
15f218
-    if retval != 0
15f218
-      return JSON.generate({"error" => "true", "stderr" => stderr, "stdout" => out})
15f218
-    end
15f218
+    cmd = [PCS, "resource", "create", params[:name], params[:resource_type]]
15f218
+    cmd += param_line
15f218
     if params[:resource_group] and params[:resource_group] != ""
15f218
-      run_cmd(
15f218
-        auth_user,
15f218
-        PCS, "resource","group", "add", params[:resource_group], params[:name]
15f218
+      cmd += ['--group', params[:resource_group]]
15f218
+      if (
15f218
+        ['before', 'after'].include?(params[:in_group_position]) and
15f218
+        params[:in_group_reference_resource_id]
15f218
       )
15f218
+        cmd << "--#{params[:in_group_position]}"
15f218
+        cmd << params[:in_group_reference_resource_id]
15f218
+      end
15f218
       resource_group = params[:resource_group]
15f218
     end
15f218
+    out, stderr, retval = run_cmd(auth_user, *cmd)
15f218
+    if retval != 0
15f218
+      return JSON.generate({"error" => "true", "stderr" => stderr, "stdout" => out})
15f218
+    end
15f218
 
15f218
     if params[:resource_clone] and params[:resource_clone] != ""
15f218
       name = resource_group ? resource_group : params[:name]
15f218
@@ -1461,10 +1463,18 @@ def update_resource (params, request, auth_user)
15f218
         )
15f218
       end
15f218
     else
15f218
-      run_cmd(
15f218
-        auth_user, PCS, "resource", "group", "add", params[:resource_group],
15f218
+      cmd = [
15f218
+        PCS, "resource", "group", "add", params[:resource_group],
15f218
         params[:resource_id]
15f218
+      ]
15f218
+      if (
15f218
+        ['before', 'after'].include?(params[:in_group_position]) and
15f218
+        params[:in_group_reference_resource_id]
15f218
       )
15f218
+        cmd << "--#{params[:in_group_position]}"
15f218
+        cmd << params[:in_group_reference_resource_id]
15f218
+      end
15f218
+      run_cmd(auth_user, *cmd)
15f218
     end
15f218
   end
15f218
 
15f218
@@ -2098,10 +2108,17 @@ def resource_change_group(params, request, auth_user)
15f218
     end
15f218
     return 200
15f218
   end
15f218
-  _, stderr, retval = run_cmd(
15f218
-    auth_user,
15f218
+  cmd = [
15f218
     PCS, 'resource', 'group', 'add', params[:group_id], params[:resource_id]
15f218
+  ]
15f218
+  if (
15f218
+  ['before', 'after'].include?(params[:in_group_position]) and
15f218
+    params[:in_group_reference_resource_id]
15f218
   )
15f218
+    cmd << "--#{params[:in_group_position]}"
15f218
+    cmd << params[:in_group_reference_resource_id]
15f218
+  end
15f218
+  _, stderr, retval = run_cmd(auth_user, *cmd)
15f218
   if retval != 0
15f218
     return [400, "Unable to add resource '#{params[:resource_id]}' to " +
15f218
       "group '#{params[:group_id]}': #{stderr.join('')}"
15f218
diff --git a/pcsd/views/_dialogs.erb b/pcsd/views/_dialogs.erb
15f218
index 46e7fdb..d18ac71 100644
15f218
--- a/pcsd/views/_dialogs.erb
15f218
+++ b/pcsd/views/_dialogs.erb
15f218
@@ -215,3 +215,24 @@
15f218
   
15f218
   {{/if}}
15f218
 
15f218
+
15f218
+
15f218
+  <form method=POST onkeypress="if (event.keyCode == 13) {$(this).parent().parent().find('.ui-dialog-buttonpane button:eq(1)').trigger('click');return false;} " action="/resource_group_add">
15f218
+    
15f218
+      
15f218
+        Group Name:
15f218
+        
15f218
+          <input name="resource_group" type="text" />
15f218
+        
15f218
+      
15f218
+      
15f218
+        Change order of resources:
15f218
+        
15f218
+          
15f218
+            
15f218
+          
15f218
+        
15f218
+      
15f218
+    
15f218
+  </form>
15f218
+
15f218
diff --git a/pcsd/views/_resource.erb b/pcsd/views/_resource.erb
15f218
index a337160..ad2251c 100644
15f218
--- a/pcsd/views/_resource.erb
15f218
+++ b/pcsd/views/_resource.erb
15f218
@@ -116,10 +116,4 @@
15f218
           table_id_suffix="_new"
15f218
       }}
15f218
     
15f218
-    
15f218
-      <form method=POST onkeypress="if (event.keyCode == 13) {$(this).parent().parent().find('.ui-dialog-buttonpane button:eq(1)').trigger('click');return false;} " action="/resource_group_add">
15f218
-	

Group Name:

<input name="resource_group" type=text>
15f218
-	<input id="resources_to_add_to_group"  type=hidden name="resources" value="">
15f218
-      </form>
15f218
-    
15f218
     <% end %>
15f218
diff --git a/pcsd/views/main.erb b/pcsd/views/main.erb
15f218
index 52c1900..1b21f92 100644
15f218
--- a/pcsd/views/main.erb
15f218
+++ b/pcsd/views/main.erb
15f218
@@ -237,7 +237,7 @@
15f218
             
15f218
               Group:
15f218
               
15f218
-                {{{resource.group_selector}}}
15f218
+                {{group-selector resource_id=resource._id}}
15f218
               
15f218
             
15f218
           {{else}}
15f218
@@ -245,7 +245,7 @@
15f218
             
15f218
               Group:
15f218
               
15f218
-                {{{resource.group_selector}}}
15f218
+                {{group-selector resource_id=resource._id}}
15f218
               
15f218
             
15f218
             {{/if}}
15f218
@@ -909,10 +909,9 @@ Use the 'Add' button to submit the form.">
15f218
                     
15f218
                   
15f218
                   
15f218
-                    {{value-selector
15f218
-                        prompt="None"
15f218
-                        content=groups
15f218
-                        name="resource_group"
15f218
+                    {{group-selector
15f218
+                        group_list=Pcs.resourcesContainer.group_list
15f218
+                        group_input_name="resource_group"
15f218
                     }}
15f218
                   
15f218
                 
15f218
@@ -1095,6 +1094,46 @@ Use the 'Add' button to submit the form.">
15f218
     
15f218
   </script>
15f218
 
15f218
+  <script type="text/x-handlebars" data-template-name="components/group-selector">
15f218
+    {{value-selector
15f218
+        name=group_input_name
15f218
+        content=group_select_content
15f218
+        value=group_select_value
15f218
+        prompt="None"
15f218
+    }}
15f218
+    {{#if Pcs.is_supported_moving_resource_in_group}}
15f218
+    {{#if group_select_value}}
15f218
+    {{#if resource_select_content}}
15f218
+      {{value-selector
15f218
+          name="in_group_position"
15f218
+          content=position_select_content
15f218
+          value=position_select_value
15f218
+          prompt=""
15f218
+      }}
15f218
+      {{value-selector
15f218
+          name="in_group_reference_resource_id"
15f218
+          content=resource_select_content
15f218
+          value=resource_select_value
15f218
+          prompt=""
15f218
+      }}
15f218
+    {{/if}}
15f218
+    {{/if}}
15f218
+    {{/if}}
15f218
+    {{#if resource_id}}
15f218
+      
15f218
+      
15f218
+        onclick="
15f218
+          resource_change_group(curResource(), $(this).parent().find('select'));
15f218
+          return false;
15f218
+        "
15f218
+      >
15f218
+        Update group
15f218
+      </button>
15f218
+      <button {{action refresh}}>Refresh</button>
15f218
+    {{/if}}
15f218
+
15f218
+  </script>
15f218
+
15f218
   <script type="text/x-handlebars">
15f218
 
15f218
 
15f218
-- 
15f218
1.8.3.1
15f218