Scott Seago
2008-Oct-22 22:16 UTC
[Ovirt-devel] [PATCH] added smart pool UI bits to search results and other flexigrids
Search results now show what smart pools the items belong to. There's also a pulldown selection to add selected results to a smart pool. 'Add to smart pool' pulldown is also available for the single-type tab pages for hosts, storage, vm pools, and vms. Signed-off-by: Scott Seago <sseago at redhat.com> --- src/app/controllers/pool_controller.rb | 4 ++- src/app/controllers/search_controller.rb | 6 +++- src/app/controllers/smart_pools_controller.rb | 24 ++++++++++++++- src/app/models/host.rb | 3 +- src/app/models/pool.rb | 3 +- src/app/models/smart_pool.rb | 32 +++++++++++++++++++- src/app/models/storage_pool.rb | 3 +- src/app/models/vm.rb | 3 +- src/app/views/hardware/show_hosts.rhtml | 29 +++++++++++++++++++ src/app/views/hardware/show_storage.rhtml | 29 +++++++++++++++++++ src/app/views/hardware/show_vms.rhtml | 29 +++++++++++++++++++ src/app/views/resources/show_vms.rhtml | 29 +++++++++++++++++++ src/app/views/search/_grid.rhtml | 3 +- src/app/views/search/results.rhtml | 38 +++++++++++++++++++++++- src/app/views/vm/_grid.rhtml | 2 +- 15 files changed, 223 insertions(+), 14 deletions(-) diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb index 063cc43..03d1316 100644 --- a/src/app/controllers/pool_controller.rb +++ b/src/app/controllers/pool_controller.rb @@ -110,7 +110,9 @@ class PoolController < ApplicationController attr_list = [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state, :id] - attr_list.insert(3, [:host, :hostname]) if @pool.get_hardware_pool.can_view(@user) + if (@pool.is_a? VmResourcePool) and @pool.get_hardware_pool.can_view(@user) + attr_list.insert(3, [:host, :hostname]) + end json_list(args[:full_items], attr_list, [:all], args[:find_opts]) end diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb index cc7e527..3789309 100644 --- a/src/app/controllers/search_controller.rb +++ b/src/app/controllers/search_controller.rb @@ -96,7 +96,9 @@ class SearchController < ApplicationController item_hash = {} item = result[:model] item_hash[:id] = item.class.name+"_"+item.id.to_s - item_hash[:cell] = ["display_name", "display_class"].collect do |attr| + item_hash[:cell] = [] + item_hash[:cell] << item_hash[:id] if params[:checkboxes] + item_hash[:cell] += ["display_name", "display_class"].collect do |attr| if attr.is_a? Array value = item attr.each { |attr_item| value = value.send(attr_item)} @@ -106,6 +108,8 @@ class SearchController < ApplicationController end end item_hash[:cell] << result[:percent] + item_hash[:cell] << item.smart_pools.collect {|pool| pool.name}.join(', ') + item_hash end render :json => json_hash.to_json diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb index 6bfe367..90b1419 100644 --- a/src/app/controllers/smart_pools_controller.rb +++ b/src/app/controllers/smart_pools_controller.rb @@ -23,7 +23,8 @@ class SmartPoolsController < PoolController before_filter :pre_modify, :only => [:add_hosts, :remove_hosts, :add_storage, :remove_storage, :add_vms, :remove_vms, - :add_pools, :remove_pools] + :add_pools, :remove_pools, + :add_items] def show_vms show end @@ -106,7 +107,7 @@ class SmartPoolsController < PoolController end find_opts = {:conditions => conditions} end - { :full_items => full_items, :find_opts => find_opts, :include_pool => :true} + { :full_items => full_items, :find_opts => find_opts, :include_pool => false} end def add_hosts @@ -154,6 +155,25 @@ class SmartPoolsController < PoolController end end + def add_items + class_and_ids_str = params[:class_and_ids] + class_and_ids = class_and_ids_str.split(",").collect {|x| x.split("_")} + + begin + @pool.transaction do + class_and_ids.each do |class_and_id| + @pool.add_item(class_and_id[0].constantize.find(class_and_id[1].to_i)) + end + end + render :json => { :success => true, + :alert => "Add items to smart pool successful." } + rescue => ex + render :json => { :success => false, + :alert => "Add items to smart pool failed: " + ex.message } + end + + end + def destroy if @pool.destroy alert="Smart Pool was successfully deleted." diff --git a/src/app/models/host.rb b/src/app/models/host.rb index 546da19..429f0c0 100644 --- a/src/app/models/host.rb +++ b/src/app/models/host.rb @@ -48,7 +48,8 @@ class Host < ActiveRecord::Base :values => [ [ :created_at, 0, "created_at", :date ], [ :updated_at, 1, "updated_at", :date ] ], :terms => [ [ :hostname, 'H', "hostname" ], - [ :search_users, 'U', "search_users" ] ] + [ :search_users, 'U', "search_users" ] ], + :eager_load => :smart_pools KVM_HYPERVISOR_TYPE = "KVM" diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb index d189649..b25fa55 100644 --- a/src/app/models/pool.rb +++ b/src/app/models/pool.rb @@ -89,7 +89,8 @@ class Pool < ActiveRecord::Base end acts_as_xapian :texts => [ :name ], - :terms => [ [ :search_users, 'U', "search_users" ] ] + :terms => [ [ :search_users, 'U', "search_users" ] ], + :eager_load => :smart_pools # this method lists pools with direct permission grants, but by default does # not include implied permissions (i.e. subtrees) diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb index 9104ee5..0ecbe05 100644 --- a/src/app/models/smart_pool.rb +++ b/src/app/models/smart_pool.rb @@ -39,8 +39,13 @@ class SmartPool < Pool end def add_item(item) - tag = SmartPoolTag.new(:smart_pool => self, :tagged => item) - tag.save! + begin + tag = SmartPoolTag.new(:smart_pool => self, :tagged => item) + tag.save! + rescue ActiveRecord::RecordInvalid + # this is thrown if the tagged item already belongs to the smart pool + # this operation should be a no-op rather than an error + end end def remove_item(item) smart_pool_tags.find(:first, :conditions=> { @@ -67,4 +72,27 @@ class SmartPool < Pool end end + def self.smart_pools_for_user(user) + nested_pools = DirectoryPool.get_smart_root.full_set_nested( + :privilege => Permission::PRIV_MODIFY, :user => user, + :smart_pool_set => true) + user_pools = [] + other_pools = [] + nested_pools.each do |pool_element| + pool = pool_element[:obj] + if pool.name == user + pool_element[:children].each do |child_element| + child_pool = child_element[:obj] + user_pools <<[child_pool.name, child_pool.id] + end + else + pool_element[:children].each do |child_element| + child_pool = child_element[:obj] + other_pools << [pool.name + " > " + child_pool.name, child_pool.id] + end + end + end + user_pools[-1] << "break" + user_pools + other_pools + end end diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb index aed2902..9c550b8 100644 --- a/src/app/models/storage_pool.rb +++ b/src/app/models/storage_pool.rb @@ -40,7 +40,8 @@ class StoragePool < ActiveRecord::Base validates_presence_of :hardware_pool_id acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], - :terms => [ [ :search_users, 'U', "search_users" ] ] + :terms => [ [ :search_users, 'U', "search_users" ] ], + :eager_load => :smart_pools ISCSI = "iSCSI" NFS = "NFS" LVM = "LVM" diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb index 2eff87a..61c407c 100644 --- a/src/app/models/vm.rb +++ b/src/app/models/vm.rb @@ -37,7 +37,8 @@ class Vm < ActiveRecord::Base :memory_allocated, :vnic_mac_addr acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], - :terms => [ [ :search_users, 'U', "search_users" ] ] + :terms => [ [ :search_users, 'U', "search_users" ] ], + :eager_load => :smart_pools BOOT_DEV_HD = "hd" BOOT_DEV_NETWORK = "network" diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml index d33c920..2fd29bc 100644 --- a/src/app/views/hardware/show_hosts.rhtml +++ b/src/app/views/hardware/show_hosts.rhtml @@ -5,6 +5,21 @@ <a id="move_link" href="#" onClick="return validate_for_move();"><%= image_tag "icon_move.png", :style=>"vertical-align:middle;" %> Move</a> <a id="move_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'move', :id => @pool, :resource_type=>'hosts' %>" rel="facebox[.bolder]" style="display:none" ></a> </li> + <li> + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> + <% smart_pools.each_index { |index| %> + <li onClick="add_hosts_to_smart_pool(<%=smart_pools[index][1]%>)" + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + <%=smart_pools[index][0]%> + </li> + <% } %> + </ul> + </li> <% if @pool.id != HardwarePool.get_default_pool.id %> <li><a href="#" onClick="remove_hosts()"><%= image_tag "icon_remove.png" %> Remove</a></li> <% end %> @@ -22,6 +37,20 @@ $('#move_link_hidden').click(); } } + function add_hosts_to_smart_pool(smart_pool) + { + var hosts = get_selected_hosts(); + if (validate_selected(hosts, "host")) { + $.post('<%= url_for :controller => "smart_pools", :action => "add_hosts" %>', + { resource_ids: hosts.toString(), id: smart_pool }, + function(data,status){ + $('#hosts_grid').flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); + } + } function remove_hosts() { var hosts = get_selected_hosts(); diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml index 6466f9b..5ade456 100644 --- a/src/app/views/hardware/show_storage.rhtml +++ b/src/app/views/hardware/show_storage.rhtml @@ -6,6 +6,21 @@ <a id="move_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'move', :id => @pool, :resource_type=>'storage' %>" rel="facebox[.bolder]" style="display:none" ></a> </li> <li> + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> + <% smart_pools.each_index { |index| %> + <li onClick="add_storage_to_smart_pool(<%=smart_pools[index][1]%>)" + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + <%=smart_pools[index][0]%> + </li> + <% } %> + </ul> + </li> + <li> <a href="#" onClick="return validate_storage_for_remove();" ><%= image_tag "icon_remove.png", :style=>"vertical-align:middle;" %> Remove</a> <a id="remove_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'removestorage', :id => @pool %>" rel="facebox[.bolder]" style="display:none" ></a> </li> @@ -13,6 +28,20 @@ </div> <script type="text/javascript"> + function add_storage_to_smart_pool(smart_pool) + { + var storage = get_selected_storage(); + if (validate_selected(storage, "storage pool")) { + $.post('<%= url_for :controller => "smart_pools", :action => "add_storage" %>', + { resource_ids: storage.toString(), id: smart_pool }, + function(data,status){ + $('#storage_grid').flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); + } + } function remove_storage() { var storage = get_selected_storage(); diff --git a/src/app/views/hardware/show_vms.rhtml b/src/app/views/hardware/show_vms.rhtml index ee14758..6a8ded5 100644 --- a/src/app/views/hardware/show_vms.rhtml +++ b/src/app/views/hardware/show_vms.rhtml @@ -1,6 +1,21 @@ <div id="toolbar_nav"> <ul> <li><a href="<%= url_for :controller => 'resources', :action => 'new', :parent_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_add_vmpool.png", :style => "vertical-align:middle;" %> New Virtual Machine Pool</a></li> + <li> + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> + <% smart_pools.each_index { |index| %> + <li onClick="add_vm_pools_to_smart_pool(<%=smart_pools[index][1]%>)" + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + <%=smart_pools[index][0]%> + </li> + <% } %> + </ul> + </li> <li><a href="#" onClick="delete_vm_pools()"><%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %> Delete</a></li> </ul> </div> @@ -9,6 +24,20 @@ { return get_selected_checkboxes("vmpools_grid_form"); } + function add_vm_pools_to_smart_pool(smart_pool) + { + var vm_pools = get_selected_vm_pools(); + if (validate_selected(vm_pools, "vm pool")) { + $.post('<%= url_for :controller => "smart_pools", :action => "add_pools" %>', + { resource_ids: vm_pools.toString(), id: smart_pool }, + function(data,status){ + $('#vmpools_grid').flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); + } + } function delete_vm_pools() { var vm_pools = get_selected_vm_pools(); diff --git a/src/app/views/resources/show_vms.rhtml b/src/app/views/resources/show_vms.rhtml index beca048..6f757f9 100644 --- a/src/app/views/resources/show_vms.rhtml +++ b/src/app/views/resources/show_vms.rhtml @@ -16,6 +16,21 @@ <% } %> </ul> </li> + <li> + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> + <% smart_pools.each_index { |index| %> + <li onClick="add_vms_to_smart_pool(<%=smart_pools[index][1]%>)" + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + <%=smart_pools[index][0]%> + </li> + <% } %> + </ul> + </li> <li><a href="#" onClick="delete_vms()"><%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %> Delete</a></li> </ul> </div> @@ -24,6 +39,20 @@ { return get_selected_checkboxes("vms_grid_form"); } + function add_vms_to_smart_pool(smart_pool) + { + var vms = get_selected_vms(); + if (validate_selected(vms, "vm")) { + $.post('<%= url_for :controller => "smart_pools", :action => "add_vms" %>', + { resource_ids: vms.toString(), id: smart_pool }, + function(data,status){ + $('#vms_grid').flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); + } + } function delete_vms() { var vms = get_selected_vms(); diff --git a/src/app/views/search/_grid.rhtml b/src/app/views/search/_grid.rhtml index 2e60646..fca1ba0 100644 --- a/src/app/views/search/_grid.rhtml +++ b/src/app/views/search/_grid.rhtml @@ -18,7 +18,8 @@ <%= "{display: '', width : 20, align: 'left', process: #{table_id}checkbox}," if checkboxes %> {display: 'Name', width : 200, align: 'left'}, {display: 'Type', width : 120, align: 'left'}, - {display: '% Match', width : 60, align: 'left'} + {display: '% Match', width : 60, align: 'left'}, + {display: 'Smart Pools', width : 200, align: 'left'} ], //sortname: "hostname", //sortorder: "asc", diff --git a/src/app/views/search/results.rhtml b/src/app/views/search/results.rhtml index a7641b7..1989054 100644 --- a/src/app/views/search/results.rhtml +++ b/src/app/views/search/results.rhtml @@ -5,9 +5,25 @@ <input id="searchform-field" name="terms" value="<%=@terms%>" onkeypress="" type="text"> <input id="searchform-button" src="<%= image_path "icon_search.png"%>" title="Search" type="image"> <input id="searchform-model" type="hidden" name="model" value="<%=@model_param%>"> + Search </li> <li> - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> Actions <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> + <% smart_pools.each_index { |index| %> + <li onClick="add_results_to_smart_pool(<%=smart_pools[index][1]%>)" + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > + <%=smart_pools[index][0]%> + </li> + <% } %> + </ul> + </li> + <li> + Show All <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> <ul> <% @types.each_index { |index| %> <!-- for each button we need to submit current form with "model" set to @types[index][1] --!> @@ -40,6 +56,24 @@ { class_and_id: selected_ids[0].substring(3)}) } } + function get_selected_results() + { + return get_selected_checkboxes("search_grid_form") + } + function add_results_to_smart_pool(smart_pool) + { + var results = get_selected_results(); + if (validate_selected(results, "search result")) { + $.post('<%= url_for :controller => "smart_pools", :action => "add_items" %>', + { class_and_ids: results.toString(), id: smart_pool }, + function(data,status){ + $('#search_grid').flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + }, 'json'); + } + } </script> <div class="panel_header"></div> @@ -48,7 +82,7 @@ <%= render :partial => "/search/grid", :locals => { :table_id => "search_grid", :terms => @terms, :model => @model_param, - :checkboxes => false, + :checkboxes => true, :on_select => "results_select" } %> </div> <div class="selection_detail" id="results_selection"> diff --git a/src/app/views/vm/_grid.rhtml b/src/app/views/vm/_grid.rhtml index 85bf094..b137de6 100644 --- a/src/app/views/vm/_grid.rhtml +++ b/src/app/views/vm/_grid.rhtml @@ -29,7 +29,7 @@ {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, {display: 'Description', name : 'description', width : 180, sortable : true, align: 'left'}, {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'}, - <% if @pool.get_hardware_pool.can_view(@user) %> + <% if (pool.is_a? VmResourcePool) and pool.get_hardware_pool.can_view(@user) %> {display: 'Host', name : 'host', width: 180, sortable : true, align: 'left' }, <% end %> {display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'}, -- 1.5.5.1
Jason Guiditta
2008-Oct-28 16:58 UTC
[Ovirt-devel] [PATCH] added smart pool UI bits to search results and other flexigrids
On Wed, 2008-10-22 at 22:16 +0000, Scott Seago wrote:> Search results now show what smart pools the items belong to. There's also a pulldown selection to add selected results to a smart pool. > > 'Add to smart pool' pulldown is also available for the single-type tab pages for hosts, storage, vm pools, and vms. > > Signed-off-by: Scott Seago <sseago at redhat.com> > --- > src/app/controllers/pool_controller.rb | 4 ++- > src/app/controllers/search_controller.rb | 6 +++- > src/app/controllers/smart_pools_controller.rb | 24 ++++++++++++++- > src/app/models/host.rb | 3 +- > src/app/models/pool.rb | 3 +- > src/app/models/smart_pool.rb | 32 +++++++++++++++++++- > src/app/models/storage_pool.rb | 3 +- > src/app/models/vm.rb | 3 +- > src/app/views/hardware/show_hosts.rhtml | 29 +++++++++++++++++++ > src/app/views/hardware/show_storage.rhtml | 29 +++++++++++++++++++ > src/app/views/hardware/show_vms.rhtml | 29 +++++++++++++++++++ > src/app/views/resources/show_vms.rhtml | 29 +++++++++++++++++++ > src/app/views/search/_grid.rhtml | 3 +- > src/app/views/search/results.rhtml | 38 +++++++++++++++++++++++- > src/app/views/vm/_grid.rhtml | 2 +- > 15 files changed, 223 insertions(+), 14 deletions(-) > > diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb > index 063cc43..03d1316 100644 > --- a/src/app/controllers/pool_controller.rb > +++ b/src/app/controllers/pool_controller.rb > @@ -110,7 +110,9 @@ class PoolController < ApplicationController > attr_list = [:id, :description, :uuid, > :num_vcpus_allocated, :memory_allocated_in_mb, > :vnic_mac_addr, :state, :id] > - attr_list.insert(3, [:host, :hostname]) if @pool.get_hardware_pool.can_view(@user) > + if (@pool.is_a? VmResourcePool) and @pool.get_hardware_pool.can_view(@user) > + attr_list.insert(3, [:host, :hostname]) > + end > json_list(args[:full_items], attr_list, [:all], args[:find_opts]) > end > > diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb > index cc7e527..3789309 100644 > --- a/src/app/controllers/search_controller.rb > +++ b/src/app/controllers/search_controller.rb > @@ -96,7 +96,9 @@ class SearchController < ApplicationController > item_hash = {} > item = result[:model] > item_hash[:id] = item.class.name+"_"+item.id.to_s > - item_hash[:cell] = ["display_name", "display_class"].collect do |attr| > + item_hash[:cell] = [] > + item_hash[:cell] << item_hash[:id] if params[:checkboxes] > + item_hash[:cell] += ["display_name", "display_class"].collect do |attr| > if attr.is_a? Array > value = item > attr.each { |attr_item| value = value.send(attr_item)} > @@ -106,6 +108,8 @@ class SearchController < ApplicationController > end > end > item_hash[:cell] << result[:percent] > + item_hash[:cell] << item.smart_pools.collect {|pool| pool.name}.join(', ') > + > item_hash > end > render :json => json_hash.to_json > diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb > index 6bfe367..90b1419 100644 > --- a/src/app/controllers/smart_pools_controller.rb > +++ b/src/app/controllers/smart_pools_controller.rbAs discussed in irc, line 101 needs to be changed to: pool_items = SmartPool.find(id).send(item_assoc).collect {|x| x.id}> @@ -23,7 +23,8 @@ class SmartPoolsController < PoolController > before_filter :pre_modify, :only => [:add_hosts, :remove_hosts, > :add_storage, :remove_storage, > :add_vms, :remove_vms, > - :add_pools, :remove_pools] > + :add_pools, :remove_pools, > + :add_items] > def show_vms > show > end > @@ -106,7 +107,7 @@ class SmartPoolsController < PoolController > end > find_opts = {:conditions => conditions} > end > - { :full_items => full_items, :find_opts => find_opts, :include_pool => :true} > + { :full_items => full_items, :find_opts => find_opts, :include_pool => false} > end > > def add_hosts > @@ -154,6 +155,25 @@ class SmartPoolsController < PoolController > end > end > > + def add_items > + class_and_ids_str = params[:class_and_ids] > + class_and_ids = class_and_ids_str.split(",").collect {|x| x.split("_")} > + > + begin > + @pool.transaction do > + class_and_ids.each do |class_and_id| > + @pool.add_item(class_and_id[0].constantize.find(class_and_id[1].to_i)) > + end > + end > + render :json => { :success => true, > + :alert => "Add items to smart pool successful." } > + rescue => ex > + render :json => { :success => false, > + :alert => "Add items to smart pool failed: " + ex.message } > + end > + > + end > + > def destroy > if @pool.destroy > alert="Smart Pool was successfully deleted." > diff --git a/src/app/models/host.rb b/src/app/models/host.rb > index 546da19..429f0c0 100644 > --- a/src/app/models/host.rb > +++ b/src/app/models/host.rb > @@ -48,7 +48,8 @@ class Host < ActiveRecord::Base > :values => [ [ :created_at, 0, "created_at", :date ], > [ :updated_at, 1, "updated_at", :date ] ], > :terms => [ [ :hostname, 'H', "hostname" ], > - [ :search_users, 'U', "search_users" ] ] > + [ :search_users, 'U', "search_users" ] ], > + :eager_load => :smart_pools > > > KVM_HYPERVISOR_TYPE = "KVM" > diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb > index d189649..b25fa55 100644 > --- a/src/app/models/pool.rb > +++ b/src/app/models/pool.rb > @@ -89,7 +89,8 @@ class Pool < ActiveRecord::Base > end > > acts_as_xapian :texts => [ :name ], > - :terms => [ [ :search_users, 'U', "search_users" ] ] > + :terms => [ [ :search_users, 'U', "search_users" ] ], > + :eager_load => :smart_pools > > # this method lists pools with direct permission grants, but by default does > # not include implied permissions (i.e. subtrees) > diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb > index 9104ee5..0ecbe05 100644 > --- a/src/app/models/smart_pool.rb > +++ b/src/app/models/smart_pool.rb > @@ -39,8 +39,13 @@ class SmartPool < Pool > end > > def add_item(item) > - tag = SmartPoolTag.new(:smart_pool => self, :tagged => item) > - tag.save! > + begin > + tag = SmartPoolTag.new(:smart_pool => self, :tagged => item) > + tag.save! > + rescue ActiveRecord::RecordInvalid > + # this is thrown if the tagged item already belongs to the smart pool > + # this operation should be a no-op rather than an error > + end > end > def remove_item(item) > smart_pool_tags.find(:first, :conditions=> { > @@ -67,4 +72,27 @@ class SmartPool < Pool > end > end > > + def self.smart_pools_for_user(user) > + nested_pools = DirectoryPool.get_smart_root.full_set_nested( > + :privilege => Permission::PRIV_MODIFY, :user => user, > + :smart_pool_set => true) > + user_pools = [] > + other_pools = [] > + nested_pools.each do |pool_element| > + pool = pool_element[:obj] > + if pool.name == user > + pool_element[:children].each do |child_element| > + child_pool = child_element[:obj] > + user_pools <<[child_pool.name, child_pool.id] > + end > + else > + pool_element[:children].each do |child_element| > + child_pool = child_element[:obj] > + other_pools << [pool.name + " > " + child_pool.name, child_pool.id] > + end > + end > + end > + user_pools[-1] << "break" > + user_pools + other_pools > + end > end > diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb > index aed2902..9c550b8 100644 > --- a/src/app/models/storage_pool.rb > +++ b/src/app/models/storage_pool.rb > @@ -40,7 +40,8 @@ class StoragePool < ActiveRecord::Base > validates_presence_of :hardware_pool_id > > acts_as_xapian :texts => [ :ip_addr, :target, :export_path, :type ], > - :terms => [ [ :search_users, 'U', "search_users" ] ] > + :terms => [ [ :search_users, 'U', "search_users" ] ], > + :eager_load => :smart_pools > ISCSI = "iSCSI" > NFS = "NFS" > LVM = "LVM" > diff --git a/src/app/models/vm.rb b/src/app/models/vm.rb > index 2eff87a..61c407c 100644 > --- a/src/app/models/vm.rb > +++ b/src/app/models/vm.rb > @@ -37,7 +37,8 @@ class Vm < ActiveRecord::Base > :memory_allocated, :vnic_mac_addr > > acts_as_xapian :texts => [ :uuid, :description, :vnic_mac_addr, :state ], > - :terms => [ [ :search_users, 'U', "search_users" ] ] > + :terms => [ [ :search_users, 'U', "search_users" ] ], > + :eager_load => :smart_pools > > BOOT_DEV_HD = "hd" > BOOT_DEV_NETWORK = "network" > diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml > index d33c920..2fd29bc 100644 > --- a/src/app/views/hardware/show_hosts.rhtml > +++ b/src/app/views/hardware/show_hosts.rhtml > @@ -5,6 +5,21 @@ > <a id="move_link" href="#" onClick="return validate_for_move();"><%= image_tag "icon_move.png", :style=>"vertical-align:middle;" %> Move</a> > <a id="move_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'move', :id => @pool, :resource_type=>'hosts' %>" rel="facebox[.bolder]" style="display:none" ></a> > </li> > + <li> > + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> > + <% smart_pools.each_index { |index| %> > + <li onClick="add_hosts_to_smart_pool(<%=smart_pools[index][1]%>)" > + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > + <%=smart_pools[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > <% if @pool.id != HardwarePool.get_default_pool.id %> > <li><a href="#" onClick="remove_hosts()"><%= image_tag "icon_remove.png" %> Remove</a></li> > <% end %> > @@ -22,6 +37,20 @@ > $('#move_link_hidden').click(); > } > } > + function add_hosts_to_smart_pool(smart_pool) > + { > + var hosts = get_selected_hosts(); > + if (validate_selected(hosts, "host")) { > + $.post('<%= url_for :controller => "smart_pools", :action => "add_hosts" %>', > + { resource_ids: hosts.toString(), id: smart_pool }, > + function(data,status){ > + $('#hosts_grid').flexReload(); > + if (data.alert) { > + $.jGrowl(data.alert); > + } > + }, 'json'); > + } > + } > function remove_hosts() > { > var hosts = get_selected_hosts(); > diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml > index 6466f9b..5ade456 100644 > --- a/src/app/views/hardware/show_storage.rhtml > +++ b/src/app/views/hardware/show_storage.rhtml > @@ -6,6 +6,21 @@ > <a id="move_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'move', :id => @pool, :resource_type=>'storage' %>" rel="facebox[.bolder]" style="display:none" ></a> > </li> > <li> > + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> > + <% smart_pools.each_index { |index| %> > + <li onClick="add_storage_to_smart_pool(<%=smart_pools[index][1]%>)" > + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > + <%=smart_pools[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > + <li> > <a href="#" onClick="return validate_storage_for_remove();" ><%= image_tag "icon_remove.png", :style=>"vertical-align:middle;" %> Remove</a> > <a id="remove_link_hidden" href="<%= url_for :controller => 'hardware', :action => 'removestorage', :id => @pool %>" rel="facebox[.bolder]" style="display:none" ></a> > </li> > @@ -13,6 +28,20 @@ > </div> > > <script type="text/javascript"> > + function add_storage_to_smart_pool(smart_pool) > + { > + var storage = get_selected_storage(); > + if (validate_selected(storage, "storage pool")) { > + $.post('<%= url_for :controller => "smart_pools", :action => "add_storage" %>', > + { resource_ids: storage.toString(), id: smart_pool }, > + function(data,status){ > + $('#storage_grid').flexReload(); > + if (data.alert) { > + $.jGrowl(data.alert); > + } > + }, 'json'); > + } > + } > function remove_storage() > { > var storage = get_selected_storage(); > diff --git a/src/app/views/hardware/show_vms.rhtml b/src/app/views/hardware/show_vms.rhtml > index ee14758..6a8ded5 100644 > --- a/src/app/views/hardware/show_vms.rhtml > +++ b/src/app/views/hardware/show_vms.rhtml > @@ -1,6 +1,21 @@ > <div id="toolbar_nav"> > <ul> > <li><a href="<%= url_for :controller => 'resources', :action => 'new', :parent_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_add_vmpool.png", :style => "vertical-align:middle;" %> New Virtual Machine Pool</a></li> > + <li> > + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> > + <% smart_pools.each_index { |index| %> > + <li onClick="add_vm_pools_to_smart_pool(<%=smart_pools[index][1]%>)" > + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > + <%=smart_pools[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > <li><a href="#" onClick="delete_vm_pools()"><%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %> Delete</a></li> > </ul> > </div> > @@ -9,6 +24,20 @@ > { > return get_selected_checkboxes("vmpools_grid_form"); > } > + function add_vm_pools_to_smart_pool(smart_pool) > + { > + var vm_pools = get_selected_vm_pools(); > + if (validate_selected(vm_pools, "vm pool")) { > + $.post('<%= url_for :controller => "smart_pools", :action => "add_pools" %>', > + { resource_ids: vm_pools.toString(), id: smart_pool }, > + function(data,status){ > + $('#vmpools_grid').flexReload(); > + if (data.alert) { > + $.jGrowl(data.alert); > + } > + }, 'json'); > + } > + } > function delete_vm_pools() > { > var vm_pools = get_selected_vm_pools(); > diff --git a/src/app/views/resources/show_vms.rhtml b/src/app/views/resources/show_vms.rhtml > index beca048..6f757f9 100644 > --- a/src/app/views/resources/show_vms.rhtml > +++ b/src/app/views/resources/show_vms.rhtml > @@ -16,6 +16,21 @@ > <% } %> > </ul> > </li> > + <li> > + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> > + <% smart_pools.each_index { |index| %> > + <li onClick="add_vms_to_smart_pool(<%=smart_pools[index][1]%>)" > + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > + <%=smart_pools[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > <li><a href="#" onClick="delete_vms()"><%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %> Delete</a></li> > </ul> > </div> > @@ -24,6 +39,20 @@ > { > return get_selected_checkboxes("vms_grid_form"); > } > + function add_vms_to_smart_pool(smart_pool) > + { > + var vms = get_selected_vms(); > + if (validate_selected(vms, "vm")) { > + $.post('<%= url_for :controller => "smart_pools", :action => "add_vms" %>', > + { resource_ids: vms.toString(), id: smart_pool }, > + function(data,status){ > + $('#vms_grid').flexReload(); > + if (data.alert) { > + $.jGrowl(data.alert); > + } > + }, 'json'); > + } > + } > function delete_vms() > { > var vms = get_selected_vms(); > diff --git a/src/app/views/search/_grid.rhtml b/src/app/views/search/_grid.rhtml > index 2e60646..fca1ba0 100644 > --- a/src/app/views/search/_grid.rhtml > +++ b/src/app/views/search/_grid.rhtml > @@ -18,7 +18,8 @@ > <%= "{display: '', width : 20, align: 'left', process: #{table_id}checkbox}," if checkboxes %> > {display: 'Name', width : 200, align: 'left'}, > {display: 'Type', width : 120, align: 'left'}, > - {display: '% Match', width : 60, align: 'left'} > + {display: '% Match', width : 60, align: 'left'}, > + {display: 'Smart Pools', width : 200, align: 'left'} > ], > //sortname: "hostname", > //sortorder: "asc", > diff --git a/src/app/views/search/results.rhtml b/src/app/views/search/results.rhtml > index a7641b7..1989054 100644 > --- a/src/app/views/search/results.rhtml > +++ b/src/app/views/search/results.rhtml > @@ -5,9 +5,25 @@ > <input id="searchform-field" name="terms" value="<%=@terms%>" onkeypress="" type="text"> > <input id="searchform-button" src="<%= image_path "icon_search.png"%>" title="Search" type="image"> > <input id="searchform-model" type="hidden" name="model" value="<%=@model_param%>"> > + Search > </li> > <li> > - <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> Actions <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <%= image_tag "icon_smartpool.png", :style => "vertical-align:middle;" %> Add to Smart Pool <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% smart_pools = SmartPool.smart_pools_for_user(@user) %> > + <% smart_pools.each_index { |index| %> > + <li onClick="add_results_to_smart_pool(<%=smart_pools[index][1]%>)" > + <% if (index == smart_pools.length - 1) or smart_pools[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > + <%=smart_pools[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > + <li> > + Show All <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > <ul> > <% @types.each_index { |index| %> > <!-- for each button we need to submit current form with "model" set to @types[index][1] --!> > @@ -40,6 +56,24 @@ > { class_and_id: selected_ids[0].substring(3)}) > } > }Not for this patch, but I would like to see us consolidate all these get_selected_* functions into one that takes the id, seems like we have a lot of functions doing almost the same thing now. /me puts that on his cleanup todo list..> + function get_selected_results() > + { > + return get_selected_checkboxes("search_grid_form") > + } > + function add_results_to_smart_pool(smart_pool) > + { > + var results = get_selected_results(); > + if (validate_selected(results, "search result")) { > + $.post('<%= url_for :controller => "smart_pools", :action => "add_items" %>', > + { class_and_ids: results.toString(), id: smart_pool }, > + function(data,status){ > + $('#search_grid').flexReload(); > + if (data.alert) { > + $.jGrowl(data.alert); > + } > + }, 'json'); > + } > + } > </script> > > <div class="panel_header"></div> > @@ -48,7 +82,7 @@ > <%= render :partial => "/search/grid", :locals => { :table_id => "search_grid", > :terms => @terms, > :model => @model_param, > - :checkboxes => false, > + :checkboxes => true, > :on_select => "results_select" } %> > </div> > <div class="selection_detail" id="results_selection"> > diff --git a/src/app/views/vm/_grid.rhtml b/src/app/views/vm/_grid.rhtml > index 85bf094..b137de6 100644 > --- a/src/app/views/vm/_grid.rhtml > +++ b/src/app/views/vm/_grid.rhtml > @@ -29,7 +29,7 @@ > {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, > {display: 'Description', name : 'description', width : 180, sortable : true, align: 'left'}, > {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'}, > - <% if @pool.get_hardware_pool.can_view(@user) %> > + <% if (pool.is_a? VmResourcePool) and pool.get_hardware_pool.can_view(@user) %> > {display: 'Host', name : 'host', width: 180, sortable : true, align: 'left' }, > <% end %> > {display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'}, >ACK, pending the change mentioned above. All functionality works for me.