[Ovirt-devel] [PATCH] finished smart pools implementation.

Jason Guiditta jguiditt at redhat.com
Thu Sep 18 19:43:41 UTC 2008


As discussed in irc, there are a couple pieces to be updated in here.
Additionally, I have some comments/questions sprinkled throughout the
patch.

-j

On Wed, 2008-09-17 at 17:23 -0400, Scott Seago wrote:
> Nav now works for smart pools (but Jay's going to do some tweaking). All of the smart pool tabs work properly with add/remove functions, although summary is stubbed out.
> search results are not yet integrated with smart pools.
> 
> Signed-off-by: Scott Seago <sseago at redhat.com>
> ---
>  src/app/controllers/application.rb                 |    8 +-
>  src/app/controllers/hardware_controller.rb         |  122 +++--------
>  src/app/controllers/host_controller.rb             |    5 +
>  src/app/controllers/pool_controller.rb             |   31 +++-
>  src/app/controllers/resources_controller.rb        |    4 +-
>  src/app/controllers/smart_pool_controller.rb       |   22 --
>  src/app/controllers/smart_pools_controller.rb      |  239 ++++++++++++++++++++
>  src/app/controllers/storage_controller.rb          |    5 +
>  src/app/controllers/tree_controller.rb             |   14 +-
>  src/app/controllers/vm_controller.rb               |    5 +
>  src/app/models/directory_pool.rb                   |    1 +
>  src/app/models/pool.rb                             |   42 +++-
>  src/app/models/smart_pool.rb                       |   23 ++
>  src/app/views/hardware/_move_menu.rhtml            |   17 --
>  src/app/views/hardware/show_hosts.rhtml            |   12 +-
>  src/app/views/hardware/show_storage.rhtml          |    4 +-
>  src/app/views/host/_grid.rhtml                     |   14 +-
>  src/app/views/host/add_to_smart_pool.rhtml         |   28 +++
>  src/app/views/host/addhost.html.erb                |    2 +-
>  src/app/views/layouts/_navigation_tabs.rhtml       |   17 ++
>  src/app/views/layouts/_side_toolbar.rhtml          |    5 +
>  src/app/views/layouts/_tree.rhtml                  |    6 +-
>  src/app/views/resources/show_vms.rhtml             |    1 +
>  src/app/views/smart_pools/_form.rhtml              |    6 +
>  src/app/views/smart_pools/_pools_grid.rhtml        |   39 ++++
>  src/app/views/smart_pools/add_pool_dialog.rhtml    |   52 +++++
>  src/app/views/smart_pools/new.rhtml                |   26 ++
>  src/app/views/smart_pools/show.rhtml               |   17 ++
>  .../{hardware => smart_pools}/show_hosts.rhtml     |   64 ++---
>  src/app/views/smart_pools/show_pools.rhtml         |   74 ++++++
>  src/app/views/smart_pools/show_storage.rhtml       |   72 ++++++
>  src/app/views/smart_pools/show_users.rhtml         |    2 +
>  src/app/views/smart_pools/show_vms.rhtml           |   77 +++++++
>  src/app/views/storage/_grid.rhtml                  |   19 ++-
>  src/app/views/storage/add_to_smart_pool.rhtml      |   22 ++
>  src/app/views/vm/_grid.rhtml                       |   70 ++++---
>  src/app/views/vm/add_to_smart_pool.rhtml           |   27 +++
>  src/db/migrate/017_add_smart_pools.rb              |    2 +-
>  .../jquery-treeview/jquery.treeview.async.js       |    2 +-
>  src/public/javascripts/jquery.ovirt.treeview.js    |   12 +-
>  src/public/javascripts/ovirt.js                    |   66 ++++++
>  version                                            |    2 +-
>  42 files changed, 1043 insertions(+), 235 deletions(-)
>  delete mode 100644 src/app/controllers/smart_pool_controller.rb
>  create mode 100644 src/app/controllers/smart_pools_controller.rb
>  delete mode 100644 src/app/views/hardware/_move_menu.rhtml
>  create mode 100644 src/app/views/host/add_to_smart_pool.rhtml
>  create mode 100644 src/app/views/smart_pools/_form.rhtml
>  create mode 100644 src/app/views/smart_pools/_pools_grid.rhtml
>  create mode 100644 src/app/views/smart_pools/add_pool_dialog.rhtml
>  create mode 100644 src/app/views/smart_pools/new.rhtml
>  create mode 100644 src/app/views/smart_pools/show.rhtml
>  copy src/app/views/{hardware => smart_pools}/show_hosts.rhtml (50%)
>  create mode 100644 src/app/views/smart_pools/show_pools.rhtml
>  create mode 100644 src/app/views/smart_pools/show_storage.rhtml
>  create mode 100644 src/app/views/smart_pools/show_users.rhtml
>  create mode 100644 src/app/views/smart_pools/show_vms.rhtml
>  create mode 100644 src/app/views/storage/add_to_smart_pool.rhtml
>  create mode 100644 src/app/views/vm/add_to_smart_pool.rhtml
> 
> diff --git a/src/app/controllers/application.rb b/src/app/controllers/application.rb
> index 3126748..5753613 100644
> --- a/src/app/controllers/application.rb
> +++ b/src/app/controllers/application.rb
> @@ -89,7 +89,7 @@ class ApplicationController < ActionController::Base
>    end
>  
>    # don't define find_opts for array inputs
> -  def json_hash(full_items, attributes, arg_list=[], find_opts={})
> +  def json_hash(full_items, attributes, arg_list=[], find_opts={}, id_method=:id)
>      page = params[:page].to_i
>      paginate_opts = {:page => page, 
>                       :order => "#{params[:sortname]} #{params[:sortorder]}", 
> @@ -101,7 +101,7 @@ class ApplicationController < ActionController::Base
>      json_hash[:total] = item_list.total_entries
>      json_hash[:rows] = item_list.collect do |item|
>        item_hash = {}
> -      item_hash[:id] = item.id
> +      item_hash[:id] = item.send(id_method)
>        item_hash[:cell] = attributes.collect do |attr| 
>          if attr.is_a? Array
>            value = item
> @@ -116,8 +116,8 @@ class ApplicationController < ActionController::Base
>      json_hash
>    end
>    # don't define find_opts for array inputs
> -  def json_list(full_items, attributes, arg_list=[], find_opts={})
> -    render :json => json_hash(full_items, attributes, arg_list, find_opts).to_json
> +  def json_list(full_items, attributes, arg_list=[], find_opts={}, id_method=:id)
> +    render :json => json_hash(full_items, attributes, arg_list, find_opts, id_method).to_json
>    end
>  
General comment, doesn't have to be done now, but we need to get better
names for these json methods.  We started down a bad path naming thing
json_[x], where [x] is not terribly descriptive of what it is for.  I
for one am finding it increasingly difficult to keep track of which of
these methods we are using where.  At the very least, I think a comment
saying something like 'this list is used for all flexigrids' for each
json function would be extremely helpful.  
> 
> diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb
> index a366e4c..9695cfb 100644
> --- a/src/app/controllers/hardware_controller.rb
> +++ b/src/app/controllers/hardware_controller.rb
> @@ -1,4 +1,4 @@
> -# 
> +#
>  # Copyright (C) 2008 Red Hat, Inc.
>  # Written by Scott Seago <sseago at redhat.com>
>  #
> @@ -20,10 +20,6 @@
>  
>  class HardwareController < PoolController
>  
> -  XML_OPTS  = {
> -    :include => [ :storage_pools, :hosts, :quota ]
> -  }
> -
>    EQ_ATTRIBUTES = [ :name, :parent_id ]
>  
>    verify :method => [:post, :put], :only => [ :create, :update ],
> @@ -59,12 +55,12 @@ class HardwareController < PoolController
>    end
>  
>    def json_view_tree
> -    json_tree_internal(Permission::PRIV_VIEW, false)
> +    json_tree_internal(Permission::PRIV_VIEW, :select_hardware_and_vm_pools)
>    end
>    def json_move_tree
> -    json_tree_internal(Permission::PRIV_MODIFY, true)
> +    json_tree_internal(Permission::PRIV_MODIFY, :select_hardware_pools)
>    end
> -  def json_tree_internal(privilege, filter_vm_pools)
> +  def json_tree_internal(privilege, filter_method)
>      id = params[:id]
>      if id
>        @pool = Pool.find(id)
> @@ -77,11 +73,9 @@ class HardwareController < PoolController
>      end
>      if @pool
>        pools = @pool.children
> -      pools = Pool.select_hardware_pools(pools) if filter_vm_pools
>        open_list = []
>      else
>        pools = Pool.list_for_user(get_login_user,Permission::PRIV_VIEW)
> -      pools = Pool.select_hardware_pools(pools) if filter_vm_pools
>        current_id = params[:current_id]
>        if current_id
>          current_pool = Pool.find(current_id)
> @@ -90,26 +84,26 @@ class HardwareController < PoolController
>          open_list = []
>        end
>      end
> +    pools = Pool.send(filter_method, pools)
>  
> -    render :json => Pool.nav_json(pools, open_list, filter_vm_pools)
> +    render :json => Pool.nav_json(pools, open_list,
> +                                  (filter_method==:select_hardware_pools))
>    end
>  
>    def show_vms
>      show
>    end
>  
> -  def show_hosts    
> -    @hardware_pools = HardwarePool.find :all
> +  def show_hosts
>      show
>    end
> -  
> +
>    def show_graphs
>      show
>    end
>  
>    def show_storage
>      show
> -    @hardware_pools = HardwarePool.find :all
>    end
>  
>    def show_tasks
> @@ -142,21 +136,16 @@ class HardwareController < PoolController
>        # filtering on which pool to exclude
>        id = params[:exclude_pool]
>        hosts = Host
> -      find_opts = {:include => :hardware_pool, 
> +      find_opts = {:include => :hardware_pool,
>          :conditions => ["pools.id != ?", id]}
>        include_pool = true
>      end
> -    attr_list = []
> -    attr_list << :id if params[:checkboxes]
> -    attr_list << :hostname
> -    attr_list << [:hardware_pool, :name] if include_pool
> -    attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :load_average]
> -    json_list(hosts, attr_list, [:all], find_opts)
> +    super(:full_items => hosts,:include_pool => include_pool,:find_opts => find_opts)
>    end
>  
>    def vm_pools_json
> -    json_list(Pool, 
> -              [:id, :name, :id], 
> +    json_list(Pool,
> +              [:id, :name, :id],
>                [@pool, :children],
>                {:finder => 'call_finder', :conditions => ["type = 'VmResourcePool'"]})
>    end
> @@ -172,24 +161,22 @@ class HardwareController < PoolController
>        # filtering on which pool to exclude
>        id = params[:exclude_pool]
>        storage_pools = StoragePool
> -      find_opts = {:include => :hardware_pool, 
> +      find_opts = {:include => :hardware_pool,
>          :conditions => ["pools.id != ?", id]}
>        include_pool = true
>      end
> -    attr_list = [:id, :display_name, :ip_addr, :get_type_label]
> -    attr_list.insert(2, [:hardware_pool, :name]) if include_pool
> -    json_list(storage_pools, attr_list, [:all], find_opts)
> +    super(:full_items => storage_pools,:include_pool => include_pool,:find_opts => find_opts)
>    end
>  
>    def storage_volumes_json
> -    json_list(@pool.all_storage_volumes, 
> +    json_list(@pool.all_storage_volumes,
>                [:display_name, :size_in_gb, :get_type_label])
>    end
>  
>    def move
>      pre_modify
>      @resource_type = params[:resource_type]
> -    render :layout => 'popup'    
> +    render :layout => 'popup'
>    end
>  
>    def new
> @@ -279,87 +266,44 @@ class HardwareController < PoolController
>      end
>    end
>  
> -  #FIXME: we need permissions checks. user must have permission on src pool
> -  # in addition to the current pool (which is checked). We also need to fail
> -  # for hosts that aren't currently empty
>    def add_hosts
> -    host_ids_str = params[:resource_ids]
> -    host_ids = host_ids_str.split(",").collect {|x| x.to_i}
> -
> -    begin
> -      @pool.transaction do
> -        @pool.move_hosts(host_ids, @pool.id)
> -      end
> -      render :json => { :object => "host", :success => true, 
> -        :alert => "Hosts were successfully added to this Hardware pool." }
> -    rescue
> -      render :json => { :object => "host", :success => false, 
> -        :alert => "Error adding Hosts to this Hardware pool." }
> -    end
> +    edit_items(Host, :move_hosts, @pool.id, :add)
>    end
>  
> -  #FIXME: we need permissions checks. user must have permission on src pool
> -  # in addition to the current pool (which is checked). We also need to fail
> -  # for hosts that aren't currently empty
>    def move_hosts
> -    target_pool_id = params[:target_pool_id]
> -    host_ids_str = params[:resource_ids]
> -    host_ids = host_ids_str.split(",").collect {|x| x.to_i}
> -    
> -    begin
> -      @pool.transaction do
> -        @pool.move_hosts(host_ids, target_pool_id)
> -      end
> -      render :json => { :object => "host", :success => true, 
> -        :alert => "Hosts were successfully moved." }
> -    rescue
> -      render :json => { :object => "host", :success => false, 
> -        :alert => "Error moving hosts." }
> -    end
> +    edit_items(Host, :move_hosts, params[:target_pool_id], :move)
>    end
>  
> -  #FIXME: we need permissions checks. user must have permission on src pool
> -  # in addition to the current pool (which is checked). We also need to fail
> -  # for storage that aren't currently empty
>    def add_storage
> -    storage_pool_ids_str = params[:resource_ids]
> -    storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i}
> -    
> -    begin
> -      @pool.transaction do
> -        @pool.move_storage(storage_pool_ids, @pool.id)
> -      end
> -      render :json => { :object => "storage_pool", :success => true, 
> -        :alert => "Storage Pools were successfully added to this Hardware pool." }
> -    rescue
> -      render :json => { :object => "storage_pool", :success => false, 
> -        :alert => "Error adding storage pools to this Hardware pool." }
> -    end
> +    edit_items(StoragePool, :move_storage, @pool.id, :add)
> +  end
> +
> +  def move_storage
> +    edit_items(StoragePool, :move_storage, params[:target_pool_id], :move)
>    end
>  
>    #FIXME: we need permissions checks. user must have permission on src pool
>    # in addition to the current pool (which is checked). We also need to fail
>    # for storage that aren't currently empty
> -  def move_storage
> -    target_pool_id = params[:target_pool_id]
> -    storage_pool_ids_str = params[:resource_ids]
> -    storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i}
> +  def edit_items(item_class, item_method, target_pool_id, action)
> +    resource_ids_str = params[:resource_ids]
> +    resource_ids = resource_ids_str.split(",").collect {|x| x.to_i}
>  
>      begin
>        @pool.transaction do
> -        @pool.move_storage(storage_pool_ids, target_pool_id)
> +        @pool.send(item_method, resource_ids, target_pool_id)
>        end
> -      render :json => { :object => "storage_pool", :success => true, 
> -        :alert => "Storage Pools were successfully moved." }
> +      render :json => { :success => true,
> +        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." }
>      rescue
> -      render :json => { :object => "storage_pool", :success => false, 
> -        :alert => "Error moving storage pools." }
> +      render :json => { :success => false,
> +        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." }
>      end
>    end
>  
>    def removestorage
>      pre_modify
> -    render :layout => 'popup'    
> +    render :layout => 'popup'
>    end
>  
>    def destroy
> diff --git a/src/app/controllers/host_controller.rb b/src/app/controllers/host_controller.rb
> index 5174c88..417d11f 100644
> --- a/src/app/controllers/host_controller.rb
> +++ b/src/app/controllers/host_controller.rb
> @@ -84,6 +84,11 @@ class HostController < ApplicationController
>      render :layout => 'popup'    
>    end
>  
> +  def add_to_smart_pool
> +    @pool = SmartPool.find(params[:smart_pool_id])
> +    render :layout => 'popup'
> +  end
> +
>    def new
>    end
>  
> diff --git a/src/app/controllers/pool_controller.rb b/src/app/controllers/pool_controller.rb
> index ce41701..02ef290 100644
> --- a/src/app/controllers/pool_controller.rb
> +++ b/src/app/controllers/pool_controller.rb
> @@ -23,9 +23,14 @@ class PoolController < ApplicationController
>    before_filter :pre_show_pool, :only => [:show_vms, :show_users,
>                                            :show_hosts, :show_storage,
>                                            :users_json, :show_tasks, :tasks,
> -                                          :vms_json, :vm_pools_json,
> +                                          :vm_pools_json,
> +                                          :pools_json, :show_pools,
>                                            :storage_volumes_json, :quick_summary]
>  
> +  XML_OPTS  = {
> +    :include => [ :storage_pools, :hosts, :quota ]
> +  }
> +
>    def show
>      respond_to do |format|
>        format.html {
> @@ -86,6 +91,28 @@ class PoolController < ApplicationController
>      json_hash(@pool.tasks, attr_list, [:all], find_opts)
>    end
>  
> +  def hosts_json(args)
> +    attr_list = []
> +    attr_list << :id if params[:checkboxes]
> +    attr_list << :hostname
> +    attr_list << [:hardware_pool, :name] if args[:include_pool]
> +    attr_list += [:uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :status_str, :load_average]
> +    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
> +  end
> +
> +  def storage_pools_json(args)
> +    attr_list = [:id, :display_name, :ip_addr, :get_type_label]
> +    attr_list.insert(2, [:hardware_pool, :name]) if args[:include_pool]
> +    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
> +  end
> +
> +  def vms_json(args)
> +    attr_list = [:id, :description, :uuid,
> +                 :num_vcpus_allocated, :memory_allocated_in_mb,
> +                 :vnic_mac_addr, :state, :id]
> +    json_list(args[:full_items], attr_list, [:all], args[:find_opts])
> +  end
> +
>    def new
>      render :layout => 'popup'
>    end
> @@ -120,7 +147,7 @@ class PoolController < ApplicationController
>      @current_pool_id=@pool.id
>      set_perms(@perm_obj)
>      unless @can_view
> -      flash[:notice] = 'You do not have permission to view this pool pool: redirecting to top level'
> +      flash[:notice] = 'You do not have permission to view this pool: redirecting to top level'
>        respond_to do |format|
>          format.html { redirect_to :controller => "dashboard" }
>          format.xml { head :forbidden }
> diff --git a/src/app/controllers/resources_controller.rb b/src/app/controllers/resources_controller.rb
> index a0a65a6..4e1daba 100644
> --- a/src/app/controllers/resources_controller.rb
> +++ b/src/app/controllers/resources_controller.rb
> @@ -68,8 +68,8 @@ class ResourcesController < PoolController
>    end
>  
>    def vms_json
> -    json_list(@pool.vms,
> -              [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state, :id])
> +    pre_show
> +    super(:full_items => @pool.vms, :find_opts => find_opts, :include_pool => :true)
>    end
>  
>    def create
> diff --git a/src/app/controllers/smart_pool_controller.rb b/src/app/controllers/smart_pool_controller.rb
> deleted file mode 100644
> index eb087a6..0000000
> --- a/src/app/controllers/smart_pool_controller.rb
> +++ /dev/null
> @@ -1,22 +0,0 @@
> -#
> -# Copyright (C) 2008 Red Hat, Inc.
> -# Written by Scott Seago <sseago at redhat.com>
> -#
> -# This program is free software; you can redistribute it and/or modify
> -# it under the terms of the GNU General Public License as published by
> -# the Free Software Foundation; version 2 of the License.
> -#
> -# This program is distributed in the hope that it will be useful,
> -# but WITHOUT ANY WARRANTY; without even the implied warranty of
> -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -# GNU General Public License for more details.
> -#
> -# You should have received a copy of the GNU General Public License
> -# along with this program; if not, write to the Free Software
> -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> -# MA  02110-1301, USA.  A copy of the GNU General Public License is
> -# also available at http://www.gnu.org/copyleft/gpl.html.
> -#
> -
> -class SmartPoolController < ApplicationController
> -end
> diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb
> new file mode 100644
> index 0000000..99ae8b8
> --- /dev/null
> +++ b/src/app/controllers/smart_pools_controller.rb
> @@ -0,0 +1,239 @@
> +#
> +# Copyright (C) 2008 Red Hat, Inc.
> +# Written by Scott Seago <sseago at redhat.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; version 2 of the License.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA  02110-1301, USA.  A copy of the GNU General Public License is
> +# also available at http://www.gnu.org/copyleft/gpl.html.
> +#
> +
> +class SmartPoolsController < PoolController
> +
> +  before_filter :pre_modify, :only => [:add_hosts, :remove_hosts,
> +                                       :add_storage, :remove_storage,
> +                                       :add_vms, :remove_vms,
> +                                       :add_pools, :remove_pools]
> +  def show_vms
> +    show
> +  end
> +
> +  def show_hosts
> +    show
> +  end
> +
> +  def show_pools
> +    show
> +  end
> +
> +  def show_storage
> +    show
> +  end
> +
> +  def create
> +    begin
> +      @pool.create_with_parent(@parent)
> +      render :json => { :object => "smart_pool", :success => true,
> +                        :alert => "Smart Pool was successfully created." }
> +    rescue
> +      render :json => { :object => "smart_pool", :success => false,
> +                        :errors => @pool.errors.localize_error_messages.to_a}
> +    end
> +  end
> +
> +  def update
> +    begin
> +      @pool.update_attributes!(params[:smart_pool])
> +      render :json => { :object => "smart_pool", :success => true,
> +                        :alert => "Smart Pool was successfully modified." }
> +    rescue
> +      render :json => { :object => "smart_pool", :success => false,
> +                        :errors => @pool.errors.localize_error_messages.to_a}
> +    end
> +  end
> +
> +  def add_pool_dialog
> +    pre_modify
> +    @selected_pools = @pool.tagged_pools.collect {|pool| pool.id}
> +    render :layout => 'popup'
> +  end
> +
> +  def hosts_json
> +    super(items_json_internal(Host, :tagged_hosts))
> +  end
> +
> +  def storage_pools_json
> +    super(items_json_internal(StoragePool, :tagged_storage_pools))
> +  end
> +
> +  def vms_json
> +    super(items_json_internal(Vm, :tagged_vms))
> +  end
> +
> +  def pools_json
> +    args = items_json_internal(Pool, :tagged_pools)
> +    attr_list = [:id, :name, :get_type_label]
> +    json_list(args[:full_items], attr_list, [:all], args[:find_opts], :class_and_id)
> +
> +  end
> +
> +  def items_json_internal(item_class, item_assoc)
> +    if params[:id]
> +      pre_show
> +      full_items = @pool.send(item_assoc)
> +      find_opts = {}
> +    else
> +      # FIXME: no permissions or usage checks here yet
> +      # filtering on which pool to exclude
> +      id = params[:exclude_pool]
> +      full_items = item_class
> +      pool_items = SmartPool.find(id,
> +                   :include => item_assoc).send(item_assoc).collect {|x| x.id}
> +      if pool_items.empty?
> +        conditions = []
> +      else
> +        conditions = ["#{item_class.table_name}.id not in (?)", pool_items]
> +      end
> +      find_opts = {:conditions => conditions}
> +    end
> +    { :full_items => full_items, :find_opts => find_opts, :include_pool => :true}
> +  end
> +
> +  def add_hosts
> +    edit_items(Host, :add_items, :add)
> +  end
> +
> +  def remove_hosts
> +    edit_items(Host, :remove_items, :remove)
> +  end
> +
> +  def add_storage
> +    edit_items(StoragePool, :add_items, :add)
> +  end
> +
> +  def remove_storage
> +    edit_items(StoragePool, :remove_items, :remove)
> +  end
> +
> +  def add_vms
> +    edit_items(Vm, :add_items, :add)
> +  end
> +
> +  def remove_vms
> +    edit_items(Vm, :remove_items, :remove)
> +  end
> +
> +  def add_pools
> +    edit_items(Pool, :add_items, :add)
> +  end
> +
> +  def remove_pools
> +    edit_items(Pool, :remove_items, :remove)
> +  end
> +
> +  def edit_items(item_class, item_method, item_action)
> +    resource_ids_str = params[:resource_ids]
> +    resource_ids = resource_ids_str.split(",").collect {|x| x.to_i}
> +    begin
> +      @pool.send(item_method,item_class, resource_ids)
> +      render :json => { :success => true,
> +        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} successful." }
> +    rescue
> +      render :json => { :success => false,
> +        :alert => "#{item_action.to_s} #{item_class.table_name.humanize} failed." }
> +    end
> +  end
> +
> +  def destroy
> +    if @pool.destroy
> +      alert="Smart Pool was successfully deleted."
> +      success=true
> +    else
> +      alert="Failed to delete Smart pool."
> +      success=false
> +    end
> +    render :json => { :object => "smart_pool", :success => success, :alert => alert }
> +  end
> +
Is this block of comments intentionally still in here?  If so, could you
clarify what it is referring to?

> +  # handled
> +  #  show_hosts
> +  #  show_graphs
> +  #  show_storage
> +  #  show
> +  #  show_vms
> +  #  show_tasks
> +  #  new   xxx
> +  #  create xxx
> +  #  hosts_json
> +  #  storage_pools_json
> +  #  add_hosts
> +  #  move_hosts
> +  #  add_storage
> +  #  move_storage
> +  #  removestorage
> +
> +  #HW only
> +  #  json_view_tree
> +  #  json_move_tree
> +  #  vm_pools_json
> +  #  move
> +  #VM only
> +  #  vms_json
> +  #  delete
> +  #  vm_actions
> +  #both
> +  #  move
> +  #  update
> +  #  destroy
> +
> +  #inherited
> +  #  used
> +  #    new
> +  #    edit
> +  #    show_users
> +  #    users_json
> +  #  unneeded
> +  #    tasks
> +  #    show_tasks
> +  #    quick_summary
> +
> +  protected
> +  #filter methods
> +  def pre_new
> +    @pool = SmartPool.new
> +    @parent = DirectoryPool.get_or_create_user_root(get_login_user)
> +    @perm_obj = @parent
> +    @current_pool_id=@parent.id
> +  end
> +  def pre_create
> +    @pool = SmartPool.new(params[:smart_pool])
> +    @parent = DirectoryPool.get_or_create_user_root(get_login_user)
> +    @perm_obj = @parent
> +    @current_pool_id=@parent.id
> +  end
> +  def pre_edit
> +    @pool = SmartPool.find(params[:id])
> +    @parent = @pool.parent
> +    @perm_obj = @pool
> +    @current_pool_id=@pool.id
> +  end
> +  def pre_show
> +    @pool = SmartPool.find(params[:id])
> +    super
> +  end
> +  def pre_modify
> +    pre_edit
> +    authorize_admin
> +  end
> +
> +end
> diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb
> index 7e97764..7eec618 100644
> --- a/src/app/controllers/storage_controller.rb
> +++ b/src/app/controllers/storage_controller.rb
> @@ -199,6 +199,11 @@ class StorageController < ApplicationController
>      render :layout => false
>    end
>  
> +  def add_to_smart_pool
> +    @pool = SmartPool.find(params[:smart_pool_id])
> +    render :layout => 'popup'
> +  end
> +
>    #FIXME: we need permissions checks. user must have permission on src pool
>    # in addition to the current pool (which is checked). We also need to fail
>    # for storage that aren't currently empty
> diff --git a/src/app/controllers/tree_controller.rb b/src/app/controllers/tree_controller.rb
> index 5ad8426..1aed544 100644
> --- a/src/app/controllers/tree_controller.rb
> +++ b/src/app/controllers/tree_controller.rb
> @@ -1,10 +1,18 @@
>  class TreeController < ApplicationController
> -  
> +
> +  def get_pools
> +    # TODO: split these into separate hash elements for HW and smart pools
> +    pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element,
> +                       :privilege => Permission::PRIV_VIEW, :user => get_login_user)
> +    pools += DirectoryPool.get_smart_root.full_set_nested(:method => :json_hash_element,
> +                       :privilege => Permission::PRIV_VIEW, :user => get_login_user,
> +                       :smart_pool_set => true)
> +  end
>    def fetch_nav
> -    @pools = HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element)
> +    @pools = get_pools
>    end
>    
>    def fetch_json
> -    render :json => HardwarePool.get_default_pool.full_set_nested(:method => :json_hash_element).to_json
> +    render :json => get_pools.to_json
>    end
>  end
> diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb
> index d3f16b6..6d06b48 100644
> --- a/src/app/controllers/vm_controller.rb
> +++ b/src/app/controllers/vm_controller.rb
> @@ -35,6 +35,11 @@ class VmController < ApplicationController
>      render :layout => 'selection'    
>    end
>  
> +  def add_to_smart_pool
> +    @pool = SmartPool.find(params[:smart_pool_id])
> +    render :layout => 'popup'
> +  end
> +
>    def new
>      render :layout => 'popup'    
>    end
> diff --git a/src/app/models/directory_pool.rb b/src/app/models/directory_pool.rb
> index f62d980..82486af 100644
> --- a/src/app/models/directory_pool.rb
> +++ b/src/app/models/directory_pool.rb
> @@ -55,6 +55,7 @@ class DirectoryPool < Pool
>          permission.save!
>        end
>      end
> +    user_root
>    end
>  
>  end
> diff --git a/src/app/models/pool.rb b/src/app/models/pool.rb
> index 9d71fa5..eb71be8 100644
> --- a/src/app/models/pool.rb
> +++ b/src/app/models/pool.rb
> @@ -111,6 +111,9 @@ class Pool < ActiveRecord::Base
>    def self.select_vm_pools(pools)
>      pools.select {|pool| pool[:type] == "VmResourcePool"}
>    end
> +  def self.select_hardware_and_vm_pools(pools)
> +    pools.select {|pool| ["HardwarePool", "VmResourcePool"].include?(pool[:type])}
> +  end
>  
>    def sub_hardware_pools
>      children({:conditions => "type='HardwarePool'"})
> @@ -225,22 +228,44 @@ class Pool < ActiveRecord::Base
>    # or :current_id to specify which pool gets ":selected => true" set
>    def full_set_nested(opts={})
>      method = opts.delete(:method) {:hash_element}
> +    privilege = opts.delete(:privilege)
> +    user = opts.delete(:user)
> +    smart_pool_set = opts.delete(:smart_pool_set)
> +    if privilege and user
> +      opts[:include] = "permissions"
> +      opts[:conditions] = "permissions.uid='#{user}' and
> +                       permissions.user_role in
> +                       ('#{Permission.roles_for_privilege(privilege).join("', '")}')"
> +    end
>      current_id = opts.delete(:current_id)
>      opts.delete(:order)
>      subtree_list = full_set(opts)
> -    return_tree = send(method)
> -    ref_hash = { id => return_tree}
> +    subtree_list -= [self] if smart_pool_set
> +    return_tree_list = []
> +    ref_hash = {}
>      subtree_list.each do |pool|
> -      unless pool.id==return_tree[:id]
> -        new_element = pool.send(method)
> -        ref_hash[pool.id] = new_element
> -        parent = ref_hash[pool.parent_id]
> +      new_element = pool.send(method)
> +      ref_hash[pool.id] = new_element
> +      parent = ref_hash[pool.parent_id]
> +      if parent
>          parent[:children] ||= []
>          parent[:children] << new_element
> +      else
> +        # for smart pools include the parent DirectoryPool
> +        if smart_pool_set and pool[:type]=="SmartPool"
> +          pool_parent = pool.parent
> +          parent_element = pool_parent.send(method)
> +          ref_hash[pool_parent.id] = parent_element
> +          return_tree_list << parent_element
> +          parent_element[:children] ||= []
> +          parent_element[:children] << new_element
> +        else
> +          return_tree_list << new_element
> +        end
>        end
>      end
>      ref_hash[current_id][:selected] = true if current_id
> -    return_tree
> +    return_tree_list
>    end
>  
>    def self.call_finder(*args)
> @@ -273,6 +298,9 @@ class Pool < ActiveRecord::Base
>      end
>    end
>  
> +  def class_and_id
> +    self.class.name + "_" + self.id.to_s
> +  end
>    protected
>    def traverse_parents
>      if id
> diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb
> index e672c5b..9104ee5 100644
> --- a/src/app/models/smart_pool.rb
> +++ b/src/app/models/smart_pool.rb
> @@ -30,6 +30,10 @@ class SmartPool < Pool
>                     :conditions => "smart_pool_tags.tagged_type = 'Vm'"
>  
> 
> +  def get_type_label
> +    "Smart Pool"
> +  end
> +
>    def create_for_user(user)
>      create_with_parent(DirectoryPool.get_or_create_user_root(user))
>    end
> @@ -44,4 +48,23 @@ class SmartPool < Pool
>                                    :tagged_id=>item.id}).destroy
>    end
>  
> +  def add_items(item_class, item_ids)
> +    items = item_class.find(:all, :conditions => "id in (#{item_ids.join(', ')})")
> +    transaction do
> +      items.each { |item| add_item(item)}
> +    end
> +  end
> +
> +  def remove_items(item_class, item_ids)
> +      tags = smart_pool_tags.find(:all,
> +                                  :conditions => "tagged_id in
> +                                                  (#{item_ids.join(', ')})
> +                                                  and tagged_type='#{item_class.name}'")
> +      transaction do
> +        tags.each do |tag|
> +          tag.destroy
> +        end
> +      end
> +  end
> +
>  end
> diff --git a/src/app/views/hardware/_move_menu.rhtml b/src/app/views/hardware/_move_menu.rhtml
> deleted file mode 100644
> index cc7ed73..0000000
> --- a/src/app/views/hardware/_move_menu.rhtml
> +++ /dev/null
> @@ -1,17 +0,0 @@
> -<%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Move    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
> -<ul>
> -   <% @hardware_pools.each { |hw_pool| %>
> -      <% if @pool.parent_id != hw_pool.id  and @pool.id != hw_pool.id %>
> -         <li onclick="window.location='<%= url_for :controller => :hardware, :action => 'foobar' %>'">  <!-- FIXME point me at the right place -->
> -      <% else %>
> -         <li style="color: #CCCCCC; cursor: default;">
> -      <% end %>
> -            <%= image_tag "icon_hdwarepool.png" %>
> -              <%= hw_pool.name %></a>
> -         </li>
> -   <% } %>
> -
> -   <li style="border-top: 1px solid black; border-bottom: 1px solid black;">
> -       Move to New Resource Group...
> -   </li>
> -</ul>
> diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/hardware/show_hosts.rhtml
> index 31c575d..5c34af3 100644
> --- a/src/app/views/hardware/show_hosts.rhtml
> +++ b/src/app/views/hardware/show_hosts.rhtml
> @@ -26,7 +26,7 @@
>    {
>      hosts = get_selected_hosts()
>      if (validate_selected(hosts, "host")) {
> -      $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>',
> +      $.post('<%= url_for :controller => "hardware", :action => "remove_hosts", :id => @pool %>',
>               { resource_ids: hosts.toString(), target_pool_id: <%= HardwarePool.get_default_pool.id %> },
>                function(data,status){
>                  $tabs.tabs("load",$tabs.data('selected.tabs'));
> @@ -35,15 +35,15 @@
>                  }
>  		if (hosts.indexOf($('#hosts_selection_id').html()) != -1){
>  		  empty_summary('hosts_selection', 'Host')
> -		}   
> +		}
>  
>                 }, 'json');
>      }
>    }
>    function hosts_select(selected_rows)
>    {
Please add semicolons where appropriate to the javascript (pretty much
any line that is not a conditional or loop).  While browsers will let us
get away without them, they really are supposed to be there.
Additionally, not having them can make debugging tricky, as the browser
can sometimes guess your intent incorrectly. Just mentioning this in one
spot rather than all over the patch
> -    var selected_ids = new Array() 
> -    for(i=0; i<selected_rows.length; i++) { 
> +    var selected_ids = new Array()
> +    for(i=0; i<selected_rows.length; i++) {
>        load_widget_select(selected_rows[i]);
>        selected_ids[i] = selected_rows[i].id;
>      }
> @@ -63,7 +63,7 @@
>                                                          :exclude_host => nil,
>                                                          :show_pool => false,
>                                                          :checkboxes => true,
> -                                                        :on_select => "hosts_select", 
> +                                                        :on_select => "hosts_select",
>                                                          :on_deselect => "load_widget_deselect",
>                                                          :on_hover => "load_widget_hover",
>                                                          :on_unhover => "load_widget_unhover",
> @@ -79,7 +79,7 @@
>     <div class="data_section">
>         <div class="no-grid-items">
>            <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> -          
> +
>            <div class="no-grid-items-text">
>              No hosts found in this pool. <br/><br/>
>              <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
> diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml
> index 564b9ed..973478a 100644
> --- a/src/app/views/hardware/show_storage.rhtml
> +++ b/src/app/views/hardware/show_storage.rhtml
> @@ -50,7 +50,7 @@
>    function storage_select(selected_rows)
>    {
>      var selected_ids = new Array() ;
> -    for(i=0; i<selected_rows.length; i++) { 
> +    for(i=0; i<selected_rows.length; i++) {
>        selected_ids[i] = selected_rows[i].id;
>      }
>      if (selected_ids.length == 1)
> @@ -80,7 +80,7 @@
>     <div class="data_section">
>         <div class="no-grid-items">
>            <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> -          
> +
>            <div class="no-grid-items-text">
>              No storage Volumes found in this pool. <br/><br/>
>              <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
> diff --git a/src/app/views/host/_grid.rhtml b/src/app/views/host/_grid.rhtml
> index 553adf9..be47011 100644
> --- a/src/app/views/host/_grid.rhtml
> +++ b/src/app/views/host/_grid.rhtml
> @@ -1,6 +1,13 @@
>  <%= render :partial => 'graph/load_graph.rhtml' %>
>  
>  <% hosts_per_page.nil? ? hosts_per_page = 40: hosts_per_page = hosts_per_page %>
> +<% if (hwpool.nil? or
> +       ((hwpool.is_a? HardwarePool) and (hwpool.hosts.size > hosts_per_page)) or
> +       ((hwpool.is_a? SmartPool) and (hwpool.tagged_hosts.size > hosts_per_page)))
> +     usepager = 'true'
> +   else
> +     usepager = 'false'
> +   end %>
>  <div id="<%= table_id %>_div">
>  <%= "<form id=\"#{table_id}_form\">" if checkboxes %>
>  <table id="<%= table_id %>" style="display:none"></table>
> @@ -10,7 +17,8 @@
>      $("#<%= table_id %>").flexigrid
>      (
>      {
> -    url: '<%=  url_for :controller => "hardware",
> +    url: '<%=  url_for :controller => (defined? pool_controller) ?
> +                                      pool_controller : "hardware",
>                         :action => "hosts_json",
>                         :escape => false,
>                         :id => (hwpool.nil? ? nil : hwpool.id),
> @@ -38,8 +46,8 @@
>  	],
>      sortname: "hostname",
>      sortorder: "asc",
> -    usepager: <%= (hwpool.nil? or hwpool.hosts.size > hosts_per_page) ? 'true' : 'false' %>,
> -    useRp: <%= (hwpool.nil? or hwpool.hosts.size > hosts_per_page) ? 'true' : 'false' %>,
> +    usepager: <%= usepager %>,
> +    useRp: <%= usepager %>,
>      rp: <%= hosts_per_page %>,
>      showTableToggleBtn: true,
>      onSelect: <%= on_select %>,
> diff --git a/src/app/views/host/add_to_smart_pool.rhtml b/src/app/views/host/add_to_smart_pool.rhtml
> new file mode 100644
> index 0000000..a89f8de
> --- /dev/null
> +++ b/src/app/views/host/add_to_smart_pool.rhtml
> @@ -0,0 +1,28 @@
> +<%- content_for :title do -%>
> +  <%= _("Add Host to Smart Pool") %>
> +<%- end -%>
> +<%- content_for :description do -%>
> +  Select hosts from the list below to add to the <%= @pool.name %> smart pool.</a>
> +<%- end -%>
> +<div id="dialog-content-area">
> +<div class="dialog_body_small">
> +<div class="panel_header"></div>
> +  <%= render :partial => "/host/grid", :locals => { :table_id => "add_smart_hosts_grid",
> +             :hwpool => nil,
> +             :pool_controller => "smart_pools",
> +             :exclude_pool => @pool.id,
> +             :exclude_host => nil,
> +             :checkboxes => true,
> +             :on_select => false,
> +             :on_deselect => false,
> +             :on_hover => false,
> +             :on_unhover => false,
> +             :is_popup => true,
> +             :hosts_per_page => 10} %>
> +</div>
> +
> +<%= popup_footer("add_hosts_to_smart_pool('#{url_for :controller => "smart_pools",
> +                                                     :action => "add_hosts",
> +                                                     :id => @pool}')",
> +                 "Add Hosts") %>
> +</div>
> diff --git a/src/app/views/host/addhost.html.erb b/src/app/views/host/addhost.html.erb
> index 7edd4c5..967643e 100644
> --- a/src/app/views/host/addhost.html.erb
> +++ b/src/app/views/host/addhost.html.erb
> @@ -24,4 +24,4 @@
>                                        :action => "add_hosts", 
>                                        :id => @hardware_pool}')", 
>                   "Add Hosts") %>
> -</div>
> \ No newline at end of file
> +</div>
> diff --git a/src/app/views/layouts/_navigation_tabs.rhtml b/src/app/views/layouts/_navigation_tabs.rhtml
> index 4b0f18d..af3fa61 100644
> --- a/src/app/views/layouts/_navigation_tabs.rhtml
> +++ b/src/app/views/layouts/_navigation_tabs.rhtml
> @@ -30,6 +30,23 @@
>      <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
>      <li id="nav_tasks">  <%= link_to "Tasks", {:action => 'show_tasks', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
>    </ul>
> +<% elsif controller.controller_name == "smart_pools"  %>
> +  <script>
> +    $(document).ready(function(){
> +      $tabs = $("#smart_pools_nav_tabs").tabs({
> +          pool_type: "smart_pools",
> +          selected: <%if params[:tab]%><%=params[:tab]%><%else%>1<%end%>
> +      });
> +    });
> +  </script>
> +  <ul id="smart_pools_nav_tabs" class="ui-tabs-nav">
> +    <li id="nav_summary" class="ui-tabs-selected"><%= link_to "Summary", {:action => 'show', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +    <li id="nav_hosts">  <%= link_to "Hosts", {:action => 'show_hosts', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +    <li id="nav_storage"><%= link_to "Storage", {:action => 'show_storage', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +    <li id="nav_pools"> <%= link_to "Pools", {:action => 'show_pools', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +    <li id="nav_vms"> <%= link_to "Virtual Machines", {:action => 'show_vms', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +    <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li>
> +  </ul>
>  <% elsif controller.controller_name == "search"  %>
>    <ul id="resources_nav_tabs" class="ui-tabs-nav">
>      <li id="nav_search" class="ui-tabs-selected"><a href="#">Search Results</a></li>
> diff --git a/src/app/views/layouts/_side_toolbar.rhtml b/src/app/views/layouts/_side_toolbar.rhtml
> index 763f4a2..29ed542 100644
> --- a/src/app/views/layouts/_side_toolbar.rhtml
> +++ b/src/app/views/layouts/_side_toolbar.rhtml
> @@ -21,4 +21,9 @@
>    <%= confirmation_dialog("conf_nav_delete_pool", "Are you sure?", "delete_#{pool[:type]=='HardwarePool' ? 'hw' : 'vm'}_pool(#{pool.id})") %>
>  </div>
>  <% end -%>
> +<div class="toolbar" style="float:left;">
> +   <a href="<%= url_for :controller => :smart_pools, :action => 'new' %>" rel="facebox[.bolder]">
> +     <%=image_tag "icon_add_hardwarepool.png", :title=>"Add Smart Pool"  %>
> +   </a>
> +</div>
>  <div class="toolbar"></div>
> diff --git a/src/app/views/layouts/_tree.rhtml b/src/app/views/layouts/_tree.rhtml
> index eb15676..0e6e138 100644
> --- a/src/app/views/layouts/_tree.rhtml
> +++ b/src/app/views/layouts/_tree.rhtml
> @@ -12,12 +12,14 @@
>              //animated: "normal",
>              url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
>              hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
> -            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
> +            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>",
> +            smart_url: "<%=  url_for :controller =>'/smart_pools', :action => 'show' %>"
>  	});
>          var tree_reload = {
>              url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
>              hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
> -            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
> +            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>",
> +            smart_url: "<%=  url_for :controller =>'/smart_pools', :action => 'show' %>"
>          }
>          $('#test-tree').everyTime(15000,function(){
>            load(tree_reload, {}, this, this);
> diff --git a/src/app/views/resources/show_vms.rhtml b/src/app/views/resources/show_vms.rhtml
> index 857f56b..2895c6b 100644
> --- a/src/app/views/resources/show_vms.rhtml
> +++ b/src/app/views/resources/show_vms.rhtml
> @@ -70,6 +70,7 @@
>    <div class="data_section">
>         <%= render :partial => "/vm/grid", :locals => { :table_id => "vms_grid",
>                                                         :pool => @pool,
> +                                                       :exclude_pool => nil,
>                                                         :on_select => "vms_select",
>                                                         :on_deselect => "load_widget_deselect",
>                                                         :on_hover => "load_widget_hover",
> diff --git a/src/app/views/smart_pools/_form.rhtml b/src/app/views/smart_pools/_form.rhtml
> new file mode 100644
> index 0000000..2f2156a
> --- /dev/null
> +++ b/src/app/views/smart_pools/_form.rhtml
> @@ -0,0 +1,6 @@
> +<%= error_messages_for 'vm_resource_pool' %>
> +
> +<!--[form:vm_resource_pool]-->
> +<%= text_field_with_label "Name", 'smart_pool', 'name'  %>
> +<!--[eoform:vm_resource_pool]-->
> +
> diff --git a/src/app/views/smart_pools/_pools_grid.rhtml b/src/app/views/smart_pools/_pools_grid.rhtml
> new file mode 100644
> index 0000000..a5f1a99
> --- /dev/null
> +++ b/src/app/views/smart_pools/_pools_grid.rhtml
> @@ -0,0 +1,39 @@
> +<% resources_per_page = 40 %>
> +<div id="<%= table_id %>_div">
> +<form id="<%= table_id %>_form">
> +<table id="<%= table_id %>" style="display:none"></table>
> +</form>
> +</div>
> +<script type="text/javascript">
> +    $("#<%= table_id %>").flexigrid
> +    (
> +    {
> +    url: '<%=  url_for :controller => "smart_pools", :action => "pools_json", :id => pool.id %>',
> +    dataType: 'json',
> +    colModel : [
> +        {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox},
> +        {display: 'Name', name : 'name', width : 160, sortable : true, align: 'left'},
> +        {display: 'Type', width : 160, sortable : true, align: 'left'}
> +        ],
> +    sortname: "name",
> +    sortorder: "asc",
> +    usepager: <%= pool.tagged_pools.size > resources_per_page ? 'true' : 'false' %>,
> +    useRp: <%= pool.tagged_pools.size > resources_per_page ? 'true' : 'false' %>,
> +    rp: <%= resources_per_page %>,
> +    showTableToggleBtn: true,
> +    onSelect: <%= on_select %>,
> +    onDeselect: <%= on_deselect %>,
> +    onHover: <%= on_hover %>,
> +    onUnhover: <%= on_unhover %>
> +    }
> +    );
> +    function <%= table_id %>checkbox(celDiv)
> +    {
> +       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
> +    }
> +    function <%= table_id %>_load_widget(celDiv)
> +    {
> +        load_widget(celDiv, "resource");
> +    };
> +
> +</script>
> diff --git a/src/app/views/smart_pools/add_pool_dialog.rhtml b/src/app/views/smart_pools/add_pool_dialog.rhtml
> new file mode 100644
> index 0000000..0d8cea6
> --- /dev/null
> +++ b/src/app/views/smart_pools/add_pool_dialog.rhtml
> @@ -0,0 +1,52 @@
> +<%- content_for :title do -%>
> +  Add a Hardware or Virtual Machine Pool
> +<%- end -%>
> +<%- content_for :description do -%>
> +  Choose a Hardware or Virtual Machine Pool to add to this Smart Pool
> +<%- end -%>
> +
> +<script type="text/javascript">
> +      $(document).ready(function(){
> +        $("#add_tree").asynch_treeview({
> +            //animated: "normal",
> +            current_pool_id:  <%=@current_pool_id%>,
> +            disabled_pools: [<%=@selected_pools.join(',')%>],
> +            url: "<%=  url_for :controller =>'/hardware', :action => 'json_view_tree' %>",
> +            current: "disabled",
> +            hardware_url: "#",
> +            resource_url: "#",
> +            onclick: "add_pool_to_smart_pool",
> +            action_type: "javascript"
> +	    })
> +	});
> +  function add_pool_to_smart_pool(added_pool_id)
> +  {
> +    $.post('<%= url_for :controller => "smart_pools", :action => "add_pools", :id => @pool %>',
> +           { resource_ids: added_pool_id },
> +            function(data,status){
> +              grid = $("#smart_pools_grid");
> +              if (grid.size()>0 && grid != null) {
> +                grid.flexReload();
> +              } else {
> +                $tabs.tabs("load",$tabs.data('selected.tabs'));
> +              }
> +              $("smart_pools_grid").flexReload()
> +	      jQuery(document).trigger('close.facebox');
> +	      if (data.alert) {
> +	        $.jGrowl(data.alert);
> +              }
> +             }, 'json');
> +  }
> +</script>
> +
> +<div class="dialog_tree">
> +  <ul id="add_tree" class="filetree treeview-famfamfam treeview"></ul>
> +</div>
> +
> +<div class="facebox_timfooter">
> +  <div class="button">
> +    <div class="button_left_grey"></div>
> +    <div class="button_middle_grey"><a href="#" onclick="jQuery(document).trigger('close.facebox')">Cancel</a></div>
> +    <div class="button_right_grey"></div>
> +  </div>
> +</div>
> diff --git a/src/app/views/smart_pools/new.rhtml b/src/app/views/smart_pools/new.rhtml
> new file mode 100644
> index 0000000..7d488af
> --- /dev/null
> +++ b/src/app/views/smart_pools/new.rhtml
> @@ -0,0 +1,26 @@
> +<%- content_for :title do -%>
> +  <%= _("Add New Smart Pool") %>
> +<%- end -%>
> +<%- content_for :description do -%>
> +  Add a new Smart Pool.
> +<%- end -%>
> +
> +<form method="POST" action="<%= url_for :action => 'create' %>" id="smart_pool_form" >
> +  <div class="dialog_form">
> +    <%= render :partial => 'form' %>
> +  </div>
> +  <%= popup_footer("$('#smart_pool_form').submit()", "Create Smart Pool") %>
> +</form>
> +
> +<script type="text/javascript">
> +$(function() {
> +    var hwpooloptions = {
> +        target:        '<%= url_for :action => 'create' %>',   // target element to update
> +	dataType:      'json',
> +        success:       afterSmartPool  // post-submit callback
> +    };
> +
> +    // bind form using 'ajaxForm'
> +    $('#smart_pool_form').ajaxForm(hwpooloptions);
> +});
> +</script>
> diff --git a/src/app/views/smart_pools/show.rhtml b/src/app/views/smart_pools/show.rhtml
> new file mode 100644
> index 0000000..45b1753
> --- /dev/null
> +++ b/src/app/views/smart_pools/show.rhtml
> @@ -0,0 +1,17 @@
> +<div class="data_section_summary">
> +
> +   <div class="summary_title"><%= image_tag "icon_hdwarepool.png", :style=>"vertical-align:middle;" %> <%= @pool.name %></div><br/><br/>
> +
> +   <div class="summary_subtitle"><%= image_tag "icon_smry_res.png", :style=>"vertical-align:middle;" %> Resources</div><br/>
> +   <div id="availability_graphs">
> +      What do we show here for Smart Pools?
> +   </div>
> +
> +   <br/><br/>
> +   <div class="summary_subtitle"><%= image_tag "icon_smry_his.png", :style=>"vertical-align:middle;" %> History</div><br/>
> +      What do we show here for Smart Pools?
> +
> +   <div class="summary_subtitle"><%= image_tag "icon_smry_perf.png", :style=>"vertical-align:middle;" %> Performance</div><br/>
> +      What do we show here for Smart Pools?
> +</div>
> +
> diff --git a/src/app/views/hardware/show_hosts.rhtml b/src/app/views/smart_pools/show_hosts.rhtml
> similarity index 50%
> copy from src/app/views/hardware/show_hosts.rhtml
> copy to src/app/views/smart_pools/show_hosts.rhtml
> index 31c575d..706c84f 100644
> --- a/src/app/views/hardware/show_hosts.rhtml
> +++ b/src/app/views/smart_pools/show_hosts.rhtml
> @@ -1,89 +1,77 @@
>  <div id="toolbar_nav">
>   <ul>
> -    <li><a href="<%= url_for :controller => 'host', :action => 'addhost', :hardware_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Host</a></li>
> -    <li>
> -      <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>
> -    <% if @pool.id != HardwarePool.get_default_pool.id %>
> -      <li><a href="#" onClick="remove_hosts()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
> -    <% end %>
> +    <li><a href="<%= url_for :controller => 'host', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Host</a></li>
> +    <li><a href="#" onClick="remove_hosts_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
>   </ul>
>  </div>
>  
>  <script type="text/javascript">
> -  function get_selected_hosts()
> +  function get_selected_hosts_for_smart_pool()
>    {
> -    return get_selected_checkboxes("hosts_grid_form")
> +    return get_selected_checkboxes("smart_hosts_grid_form")
>    }
> -  function validate_for_move()
> +  function remove_hosts_from_smart_pool()
>    {
> -    if (validate_selected(get_selected_hosts(), 'host')) {
> -      $('#move_link_hidden').click()
> -    }
> -  }
> -  function remove_hosts()
> -  {
unless 'hosts' is declared somewhere I am not seeing, this line should
start with 'var hosts'
> -    hosts = get_selected_hosts()
> +    hosts = get_selected_hosts_for_smart_pool()
>      if (validate_selected(hosts, "host")) {
> -      $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>',
> -             { resource_ids: hosts.toString(), target_pool_id: <%= HardwarePool.get_default_pool.id %> },
> +      $.post('<%= url_for :controller => "smart_pools", :action => "remove_hosts", :id => @pool %>',
> +             { resource_ids: hosts.toString() },
>                function(data,status){
>                  $tabs.tabs("load",$tabs.data('selected.tabs'));
>  		if (data.alert) {
>  		  $.jGrowl(data.alert);
>                  }
> -		if (hosts.indexOf($('#hosts_selection_id').html()) != -1){
> -		  empty_summary('hosts_selection', 'Host')
> -		}   
> +		if (hosts.indexOf($('#smart_hosts_selection_id').html()) != -1){
> +		  empty_summary('smart_hosts_selection', 'Host')
> +		}
>  
>                 }, 'json');
>      }
>    }
> -  function hosts_select(selected_rows)
> +  function smart_hosts_select(selected_rows)
>    {
> -    var selected_ids = new Array() 
> -    for(i=0; i<selected_rows.length; i++) { 
> -      load_widget_select(selected_rows[i]);
> +    var selected_ids = new Array()
> +    for(i=0; i<selected_rows.length; i++) {
>        selected_ids[i] = selected_rows[i].id;
>      }
>      if (selected_ids.length == 1)
>      {
> -      $('#hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)))
> +      $('#smart_hosts_selection').load('<%= url_for :controller => "host", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)))
>      }
>    }
>  </script>
>  
>  <div class="panel_header"></div>
> -<% if @pool.hosts.size != 0 %>
> +<% if @pool.tagged_hosts.size != 0 %>
>     <div class="data_section">
> -      <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid",
> +      <%= render :partial => "/host/grid", :locals => { :table_id => "smart_hosts_grid",
>                                                          :hwpool => @pool,
> +                                                        :pool_controller => "smart_pools",
>                                                          :exclude_pool => nil,
>                                                          :exclude_host => nil,
> -                                                        :show_pool => false,
> +                                                        :show_pool => true,
>                                                          :checkboxes => true,
> -                                                        :on_select => "hosts_select", 
> +                                                        :on_select => "smart_hosts_select",
>                                                          :on_deselect => "load_widget_deselect",
>                                                          :on_hover => "load_widget_hover",
>                                                          :on_unhover => "load_widget_unhover",
>                                                          :is_popup => false,
>                                                          :hosts_per_page => 40} %>
>     </div>
> -   <div class="selection_detail" id="hosts_selection">
> -   	<div class="selection_left">
> -	     <div>Select a host above.</div>
> -        </div>
> +   <div class="selection_detail" id="smart_hosts_selection">
> +     <div class="selection_left">
> +       <div>Select a host above.</div>
> +     </div>
>     </div>
>  <% else %>
>     <div class="data_section">
>         <div class="no-grid-items">
>            <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> -          
> +
>            <div class="no-grid-items-text">
>              No hosts found in this pool. <br/><br/>
>              <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  
> -            <a href="<%= url_for :controller => 'host', :action => 'addhost', :hardware_pool_id => @pool %>" rel="facebox[.bolder]">Add first host to this hardware pool</a>
> +            <a href="<%= url_for :controller => 'host', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first host to this smart pool</a>
>            </div>
>         </div>
>     </div>
> diff --git a/src/app/views/smart_pools/show_pools.rhtml b/src/app/views/smart_pools/show_pools.rhtml
> new file mode 100644
> index 0000000..f9d4b19
> --- /dev/null
> +++ b/src/app/views/smart_pools/show_pools.rhtml
> @@ -0,0 +1,74 @@
> +<div id="toolbar_nav">
> + <ul>
> +    <li><a href="<%= url_for :controller => 'smart_pools', :action => 'add_pool_dialog', :id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Pool</a></li>
> +    <li><a href="#" onClick="remove_pools_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
> + </ul>
> +</div>
> +
> +<script type="text/javascript">
> +  function get_selected_pools_for_smart_pool()
> +  {
> +    return get_selected_checkboxes("smart_pools_grid_form")
> +  }
> +  function remove_pools_from_smart_pool()
> +  {
Same as with 'hosts', should be 'var pools'
> +    pools = get_selected_pools_for_smart_pool()
> +    if (validate_selected(pools, "pool")) {
> +      $.post('<%= url_for :controller => "smart_pools", :action => "remove_pools", :id => @pool %>',
> +             { resource_ids: pools.toString() },
> +              function(data,status){
> +                $tabs.tabs("load",$tabs.data('selected.tabs'));
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +		if (pools.indexOf($('#smart_pools_selection_id').html()) != -1){
> +		  empty_summary('smart_pools_selection', 'Pool')
> +		}
> +
> +               }, 'json');
> +    }
> +  }
> +  function smart_pools_select(selected_rows)
> +  {
> +    var selected_ids = new Array()
> +    for(i=0; i<selected_rows.length; i++) {
> +      selected_ids[i] = selected_rows[i].id;
> +    }
> +    if (selected_ids.length == 1)
> +    {
> +      $('#smart_pools_selection').load('<%= url_for :controller => "search", :action => "single_result" %>',
> +                { class_and_id: selected_ids[0].substring(3)})
> +    }
> +  }
> +</script>
> +
> +<div class="panel_header"></div>
> +<% if @pool.tagged_pools.size != 0 %>
> +   <div class="data_section">
> +      <%= render :partial => "/smart_pools/pools_grid", :locals => { :table_id => "smart_pools_grid",
> +                                                        :pool => @pool,
> +                                                        :pool_controller => "smart_pools",
> +                                                        :checkboxes => true,
> +                                                        :on_select => "smart_pools_select",
> +                                                        :on_deselect => false,
> +                                                        :on_hover => false,
> +                                                        :on_unhover => false} %>
> +   </div>
> +   <div class="selection_detail" id="smart_pools_selection">
> +     <div class="selection_left">
> +       <div>Select a pool above.</div>
> +     </div>
> +   </div>
> +<% else %>
> +   <div class="data_section">
> +       <div class="no-grid-items">
> +          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> +
> +          <div class="no-grid-items-text">
> +            No pools found in this pool. <br/><br/>
> +            <%= image_tag "icon_addpool.png", :style=>"vertical-align:middle;" %>  
> +            <a href="<%= url_for :controller => 'pool', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first Pool to this smart pool</a>
> +          </div>
> +       </div>
> +   </div>
> +<% end %>
> diff --git a/src/app/views/smart_pools/show_storage.rhtml b/src/app/views/smart_pools/show_storage.rhtml
> new file mode 100644
> index 0000000..89e5e14
> --- /dev/null
> +++ b/src/app/views/smart_pools/show_storage.rhtml
> @@ -0,0 +1,72 @@
> +<div id="toolbar_nav">
> +<ul>
> +    <li><a href="<%= url_for :controller => 'storage', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>  Add Storage Pool</a></li>
> +    <li><a href="#" onClick="remove_storage_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
> +  </ul>
> +</div>
> +
> +<script type="text/javascript">
> +  function get_selected_storage_for_smart_pool()
> +  {
> +    return get_selected_checkboxes("smart_storage_grid_form")
> +  }
> +  function remove_storage_from_smart_pool()
> +  {
> +    storage = get_selected_storage_for_smart_pool()
> +    if (validate_selected(storage, "storage pool")) {
> +      $.post('<%= url_for :controller => "smart_pools", :action => "remove_storage", :id => @pool %>',
> +             { resource_ids: storage.toString() },
> +              function(data,status){
> +                $tabs.tabs("load",$tabs.data('selected.tabs'));
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +		if (storage.indexOf($('#smart_storage_selection_id').html()) != -1){
> +		  empty_summary('smart_storage_selection', 'Storage Pool')
> +		}
> +               }, 'json');
> +    }
> +  }
> +  function smart_storage_select(selected_rows)
> +  {
> +    var selected_ids = new Array() ;
> +    for(i=0; i<selected_rows.length; i++) {
> +      selected_ids[i] = selected_rows[i].id;
> +    }
> +    if (selected_ids.length == 1)
> +    {
> +      $('#smart_storage_selection').load('<%= url_for :controller => "storage", :action => "show" %>',
> +                { id: parseInt(selected_ids[0].substring(3))});
> +    }
> +  }
> +
> +</script>
> +<div class="panel_header"></div>
> +<% if @pool.tagged_storage_pools.size != 0 %>
> +  <div class="data_section">
> +       <%= render :partial => "/storage/grid", :locals => { :table_id => "smart_storage_grid",
> +                                                            :hwpool => @pool,
> +                                                            :pool_controller => "smart_pools",
> +                                                            :exclude_pool => nil,
> +                                                            :on_select => "smart_storage_select",
> +                                                            :is_popup => false} %>
> +  </div>
> +
> +  <div class="selection_detail" id="smart_storage_selection">
> +    <div class="selection_left">
> +      <div>Select a storage pool.</div>
> +    </div>
> +  </div>
> +<% else %>
> +   <div class="data_section">
> +       <div class="no-grid-items">
> +          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> +
> +          <div class="no-grid-items-text">
> +            No storage Pools found in this pool. <br/><br/>
> +            <%= image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>  
> +            <a href="<%= url_for :controller => 'storage', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first storage volume to this smart pool</a>
> +          </div>
> +       </div>
> +   </div>
> +<% end %>
> diff --git a/src/app/views/smart_pools/show_users.rhtml b/src/app/views/smart_pools/show_users.rhtml
> new file mode 100644
> index 0000000..7d1efb8
> --- /dev/null
> +++ b/src/app/views/smart_pools/show_users.rhtml
> @@ -0,0 +1,2 @@
> +  <%= render :partial => "/user/show", :locals => { :parent_controller => "smart_pools",
> +                                                    :pool => @pool } %>
> diff --git a/src/app/views/smart_pools/show_vms.rhtml b/src/app/views/smart_pools/show_vms.rhtml
> new file mode 100644
> index 0000000..990e4ab
> --- /dev/null
> +++ b/src/app/views/smart_pools/show_vms.rhtml
> @@ -0,0 +1,77 @@
> +<div id="toolbar_nav">
> + <ul>
> +    <li><a href="<%= url_for :controller => 'vm', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %>  Add Virtual Machine</a></li>
> +    <li><a href="#" onClick="remove_vms_from_smart_pool()"><%= image_tag "icon_remove.png" %>  Remove</a></li>
> + </ul>
> +</div>
> +
> +<script type="text/javascript">
> +  function get_selected_vms_for_smart_pool()
> +  {
> +    return get_selected_checkboxes("smart_vms_grid_form")
> +  }
> +  function remove_vms_from_smart_pool()
> +  {
var vms
> +    vms = get_selected_vms_for_smart_pool()
> +    if (validate_selected(vms, "vm")) {
> +      $.post('<%= url_for :controller => "smart_pools", :action => "remove_vms", :id => @pool %>',
> +             { resource_ids: vms.toString() },
> +              function(data,status){
> +                $tabs.tabs("load",$tabs.data('selected.tabs'));
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +		if (vms.indexOf($('#smart_vms_selection_id').html()) != -1){
> +		  empty_summary('smart_vms_selection', 'Vm')
> +		}
> +
> +               }, 'json');
> +    }
> +  }
> +  function smart_vms_select(selected_rows)
> +  {
> +    var selected_ids = new Array()
> +    for(i=0; i<selected_rows.length; i++) {
> +      selected_ids[i] = selected_rows[i].id;
> +    }
> +    if (selected_ids.length == 1)
> +    {
> +      $('#smart_vms_selection').load('<%= url_for :controller => "vm", :action => "show", :id => nil %>/' + parseInt(selected_ids[0].substring(3)))
> +    }
> +  }
> +</script>
> +
> +<div class="panel_header"></div>
> +<% if @pool.tagged_vms.size != 0 %>
> +   <div class="data_section">
> +      <%= render :partial => "/vm/grid", :locals => { :table_id => "smart_vms_grid",
> +                                                        :pool => @pool,
> +                                                        :pool_controller => "smart_pools",
> +                                                        :exclude_pool => nil,
> +                                                        :show_pool => true,
> +                                                        :checkboxes => true,
> +                                                        :on_select => "smart_vms_select",
> +                                                        :on_deselect => "load_widget_deselect",
> +                                                        :on_hover => "load_widget_hover",
> +                                                        :on_unhover => "load_widget_unhover",
> +                                                        :is_popup => false,
> +                                                        :vms_per_page => 40} %>
> +   </div>
> +   <div class="selection_detail" id="smart_vms_selection">
> +     <div class="selection_left">
> +       <div>Select a vm above.</div>
> +     </div>
> +   </div>
> +<% else %>
> +   <div class="data_section">
> +       <div class="no-grid-items">
> +          <%= image_tag 'no-grid-items.png', :style => 'float: left;' %>
> +
> +          <div class="no-grid-items-text">
> +            No vms found in this pool. <br/><br/>
> +            <%= image_tag "icon_addvm.png", :style=>"vertical-align:middle;" %>  
> +            <a href="<%= url_for :controller => 'vm', :action => 'add_to_smart_pool', :smart_pool_id => @pool %>" rel="facebox[.bolder]">Add first VM to this smart pool</a>
> +          </div>
> +       </div>
> +   </div>
> +<% end %>
> diff --git a/src/app/views/storage/_grid.rhtml b/src/app/views/storage/_grid.rhtml
> index c36f4d3..21ca109 100644
> --- a/src/app/views/storage/_grid.rhtml
> +++ b/src/app/views/storage/_grid.rhtml
> @@ -1,4 +1,11 @@
> -<% storage_per_page = 40 %>
> +<% storage_per_page = 40 unless (defined? storage_per_page) and !(storage_per_page.nil?) %>
> +<% if (hwpool.nil? or
> +       ((hwpool.is_a? HardwarePool) and (hwpool.storage_pools.size > storage_per_page)) or
> +       ((hwpool.is_a? SmartPool) and (hwpool.tagged_storage_pools.size > storage_per_page)))
> +     usepager = 'true'
> +   else
> +     usepager = 'false'
> +   end %>
>  
>  <div id="<%= table_id %>_div">
>  <form id="<%= table_id %>_form">
> @@ -9,7 +16,11 @@
>      $("#<%= table_id %>").flexigrid
>      (
>      {
> -    url: '<%=  url_for :controller => "hardware", :action => "storage_pools_json", :id => (hwpool.nil? ? nil : hwpool.id), :exclude_pool => exclude_pool %>',
> +    url: '<%=  url_for :controller => (defined? pool_controller) ?
> +                                      pool_controller : "hardware",
> +                       :action => "storage_pools_json",
> +                       :id => (hwpool.nil? ? nil : hwpool.id),
> +                       :exclude_pool => exclude_pool %>',
>      dataType: 'json',
>      <% if is_popup %>
>          width: 700,
> @@ -23,8 +34,8 @@
>          ],
>      sortname: "ip_addr",
>      sortorder: "asc",
> -    usepager: <%= (hwpool.nil? or hwpool.storage_pools.size > storage_per_page) ? 'true' : 'false' %>,
> -    useRp: <%= (hwpool.nil? or hwpool.storage_pools.size > storage_per_page) ? 'true' : 'false' %>,
> +    usepager: <%= usepager %>,
> +    useRp: <%= usepager %>,
>      rp: <%= storage_per_page %>,
>      showTableToggleBtn: true,
>      onSelect: <%= on_select %>
> diff --git a/src/app/views/storage/add_to_smart_pool.rhtml b/src/app/views/storage/add_to_smart_pool.rhtml
> new file mode 100644
> index 0000000..2eedae3
> --- /dev/null
> +++ b/src/app/views/storage/add_to_smart_pool.rhtml
> @@ -0,0 +1,22 @@
> +<%- content_for :title do -%>
> +  <%= _("Add Storage Pool to Smart Pool") %>
> +<%- end -%>
> +<%- content_for :description do -%>
> +  Select storage pools from the list below to add to the <%= @pool.name %> smart pool.</a>
> +<%- end -%>
> +<div id="dialog-content-area">
> +<div class="dialog_body_small">
> +<div class="panel_header"></div>
> +  <%= render :partial => "/storage/grid", :locals => { :table_id => "add_smart_storage_grid",
> +             :hwpool => nil,
> +             :pool_controller => "smart_pools",
> +             :exclude_pool => @pool.id,
> +             :on_select => false,
> +             :is_popup => true} %>
> +</div>
> +
> +<%= popup_footer("add_storage_to_smart_pool('#{url_for :controller => "smart_pools",
> +                                                     :action => "add_storage",
> +                                                     :id => @pool}')",
> +                 "Add Storage Pools") %>
> +</div>
> diff --git a/src/app/views/vm/_grid.rhtml b/src/app/views/vm/_grid.rhtml
> index c56e6b8..a538824 100644
> --- a/src/app/views/vm/_grid.rhtml
> +++ b/src/app/views/vm/_grid.rhtml
> @@ -1,42 +1,56 @@
>  <%= render :partial => 'graph/load_graph.rhtml' %>
> -<% vms_per_page = 10 %>
> +<% vms_per_page = 40 unless (defined? vms_per_page) and !(vms_per_page.nil?) %>
> +<% if (pool.nil? or
> +       ((pool.is_a? VmResourcePool) and (pool.vms.size > vms_per_page)) or
> +       ((pool.is_a? SmartPool) and (pool.tagged_vms.size > vms_per_page)))
> +     usepager = 'true'
> +   else
> +     usepager = 'false'
> +   end %>
>  <div id="<%= table_id %>_div">
>  <form id="<%= table_id %>_form">
>  <table id="<%= table_id %>" style="display:none"></table>
>  </form>
>  </div>
>  <script type="text/javascript">
> -	$("#<%= table_id %>").flexigrid
> -	(
> -	{
> -	url: '<%=  url_for :controller => "resources", :action => "vms_json", :id => pool.id %>',
> -	dataType: 'json',
> -	colModel : [
> -		{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'},
> -		{display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'},
> -		{display: 'Memory (MB)', name : 'memory_allocated', width : 60, sortable : true, align: 'right'},
> -		{display: 'vNIC Mac Addr', name : 'vnic_mac_addr', width : 60, sortable : true, align: 'right'},
> -		{display: 'State', name : 'state', width : 50, sortable : true, align: 'right'},
> +    $("#<%= table_id %>").flexigrid
> +    (
> +    {
> +    url: '<%=  url_for :controller => (defined? pool_controller) ?
> +                                       pool_controller : "resources",
> +                       :action => "vms_json",
> +                       :id => (pool.nil? ? nil : pool.id),
> +                       :exclude_pool => exclude_pool %>',
> +    dataType: 'json',
> +    <% if is_popup %>
> +        width: 700,
> +    <% end %>
> +    colModel : [
> +        {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'},
> +        {display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'},
> +        {display: 'Memory (MB)', name : 'memory_allocated', width : 60, sortable : true, align: 'right'},
> +        {display: 'vNIC Mac Addr', name : 'vnic_mac_addr', width : 60, sortable : true, align: 'right'},
> +        {display: 'State', name : 'state', width : 50, sortable : true, align: 'right'},
>          {display: 'Load', name : 'load', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget }
> -		],
> -	sortname: "description",
> -	sortorder: "asc",
> -	usepager: <%= pool.vms.size > vms_per_page ? 'true' : 'false' %>,
> -    useRp: <%= pool.vms.size > vms_per_page ? 'true' : 'false' %>,
> -	rp: <%= vms_per_page %>,
> -	showTableToggleBtn: true,
> -	onSelect: <%= on_select %>,
> +        ],
> +    sortname: "description",
> +    sortorder: "asc",
> +    usepager: <%= usepager %>,
> +    useRp: <%= usepager %>,
> +    rp: <%= vms_per_page %>,
> +    showTableToggleBtn: true,
> +    onSelect: <%= on_select %>,
>      onDeselect: <%= on_deselect %>,
>      onHover: <%= on_hover %>,
>      onUnhover: <%= on_unhover %>
> -	}
> -	);   
> -	function <%= table_id %>checkbox(celDiv)
> -	{
> -	       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
> -	} 
> +    }
> +    );
> +    function <%= table_id %>checkbox(celDiv)
> +    {
> +       $(celDiv).html('<input type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" class="grid_checkbox" value="'+$(celDiv).html()+'"/>');
> +    }
>      function <%= table_id %>_load_widget(celDiv)
>      {
>          load_widget(celDiv, "vm");
> diff --git a/src/app/views/vm/add_to_smart_pool.rhtml b/src/app/views/vm/add_to_smart_pool.rhtml
> new file mode 100644
> index 0000000..cdfe92d
> --- /dev/null
> +++ b/src/app/views/vm/add_to_smart_pool.rhtml
> @@ -0,0 +1,27 @@
> +<%- content_for :title do -%>
> +  <%= _("Add Vm to Smart Pool") %>
> +<%- end -%>
> +<%- content_for :description do -%>
> +  Select vms from the list below to add to the <%= @pool.name %> smart pool.</a>
> +<%- end -%>
> +<div id="dialog-content-area">
> +<div class="dialog_body_small">
> +<div class="panel_header"></div>
> +  <%= render :partial => "/vm/grid", :locals => { :table_id => "add_smart_vms_grid",
> +             :pool => nil,
> +             :pool_controller => "smart_pools",
> +             :exclude_pool => @pool.id,
> +             :checkboxes => true,
> +             :on_select => false,
> +             :on_deselect => false,
> +             :on_hover => false,
> +             :on_unhover => false,
> +             :is_popup => true,
> +             :vms_per_page => 40} %>
> +</div>
> +
> +<%= popup_footer("add_vms_to_smart_pool('#{url_for :controller => "smart_pools",
> +                                                     :action => "add_vms",
> +                                                     :id => @pool}')",
> +                 "Add Vms") %>
> +</div>
> diff --git a/src/db/migrate/017_add_smart_pools.rb b/src/db/migrate/017_add_smart_pools.rb
> index 6d83c02..5550a89 100644
> --- a/src/db/migrate/017_add_smart_pools.rb
> +++ b/src/db/migrate/017_add_smart_pools.rb
> @@ -47,7 +47,7 @@ class AddSmartPools < ActiveRecord::Migration
>              new_permission = Permission.new({:pool_id     => dir_root.id,
>                                               :uid         => permission.uid,
>                                               :user_role   => permission.user_role})
> -            new_permission.save!
> +            new_permission.save_with_new_children
>            end
>          end
>        end
> diff --git a/src/public/javascripts/jquery-treeview/jquery.treeview.async.js b/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> index b10a130..4dacda6 100644
> --- a/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> +++ b/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> @@ -43,7 +43,7 @@ function load(settings, params, child, container) {
>     		        } else {
>  			    span_onclick = ""
>  		        }
> -                        if (settings.current_pool_id==this.id) {
> +                        if (settings.current_pool_id==this.id || !((settings.disabled_pools == undefined) || ($.inArray(this.id,settings.disabled_pools)==-1))) {
>                            current.html("<span class=\"" + settings.current_class + ">" + this.text  + "</span>")
>                              .appendTo(parent);
>                          } else {
> diff --git a/src/public/javascripts/jquery.ovirt.treeview.js b/src/public/javascripts/jquery.ovirt.treeview.js
> index 16cf260..bb41667 100644
> --- a/src/public/javascripts/jquery.ovirt.treeview.js
> +++ b/src/public/javascripts/jquery.ovirt.treeview.js
> @@ -21,10 +21,18 @@ function load(settings, params, child, container) {
>                              settings.link_to=settings.hardware_url 
>                              settings.span_class="folder";
>                              settings.current_class = settings.current + "_folder";
> -                        } else {
> +                        } else if (this.type=="VmResourcePool") {
>                              settings.link_to=settings.resource_url;
>                              settings.span_class="file";
>                              settings.current_class = settings.current + "_file";
> +                        } else if (this.type=="SmartPool") {
> +                            settings.link_to=settings.smart_url;
> +                            settings.span_class="file";
> +                            settings.current_class = settings.current + "_file";
> +                        } else {
> +                            settings.link_to="";
> +                            settings.span_class="file";
> +                            settings.current_class = settings.current + "_file";
>                          }   
>  			var span_onclick;
>  			var current = $("<li/>").attr("id", this.id || "");
> @@ -64,7 +72,7 @@ function load(settings, params, child, container) {
>  			}
>  		} 
>                  $(container).find('li').remove();
> -                createNode.call(response, child);                
> +                $.each(response, createNode, [child]);
>                  $(container).ovirt_treeview({add: child});
>                  for (var i = 0; i < selectedNodes.length; i++){
>                    $('#test-tree li#' + selectedNodes[i] +' > div').click();
> diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js
> index af0b9f6..06de67e 100644
> --- a/src/public/javascripts/ovirt.js
> +++ b/src/public/javascripts/ovirt.js
> @@ -75,6 +75,66 @@ function add_storage(url)
>                 }, 'json');
>      }
>  }
> +function add_hosts_to_smart_pool(url)
> +{
> +    hosts= get_selected_checkboxes("add_smart_hosts_grid_form");
> +    if (validate_selected(hosts, "host")) {
> +      $.post(url,
> +             { resource_ids: hosts.toString() },
> +              function(data,status){
> +                jQuery(document).trigger('close.facebox');
> +	        grid = $("#smart_hosts_grid");
> +                if (grid.size()>0 && grid != null) {
> +                  grid.flexReload();
> +                } else {
> +		  $tabs.tabs("load",$tabs.data('selected.tabs'));
> +                }
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +               }, 'json');
> +    }
> +}
> +function add_storage_to_smart_pool(url)
> +{
> +    storage= get_selected_checkboxes("add_smart_storage_grid_form");
> +    if (validate_selected(storage, "storage pool")) {
> +      $.post(url,
> +             { resource_ids: storage.toString() },
> +              function(data,status){
> +                jQuery(document).trigger('close.facebox');
> +	        grid = $("#smart_storage_grid");
> +                if (grid.size()>0 && grid != null) {
> +                  grid.flexReload();
> +                } else {
> +		  $tabs.tabs("load",$tabs.data('selected.tabs'));
> +                }
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +               }, 'json');
> +    }
> +}
> +function add_vms_to_smart_pool(url)
> +{
> +    vms= get_selected_checkboxes("add_smart_vms_grid_form");
> +    if (validate_selected(vms, "vm")) {
> +      $.post(url,
> +             { resource_ids: vms.toString() },
> +              function(data,status){
> +                jQuery(document).trigger('close.facebox');
> +	        grid = $("#smart_vms_grid");
> +                if (grid.size()>0 && grid != null) {
> +                  grid.flexReload();
> +                } else {
> +		  $tabs.tabs("load",$tabs.data('selected.tabs'));
> +                }
> +		if (data.alert) {
> +		  $.jGrowl(data.alert);
> +                }
> +               }, 'json');
> +    }
> +}
>  // deal with ajax form response, filling in validation messages where required.
>  function ajax_validation(response, status)
>  {
> @@ -137,6 +197,12 @@ function afterVmPool(response, status){
>        }
>      }
>  }
> +function afterSmartPool(response, status){
> +    ajax_validation(response, status);
> +    if (response.success) {
for code consistency, this should be $(document).trigger
> +      jQuery(document).trigger('close.facebox');
> +    }
> +}
>  function afterStoragePool(response, status){
>      ajax_validation(response, status);
>      if (response.success) {
> diff --git a/version b/version
> index 187ac7a..6e07c08 100644
> --- a/version
> +++ b/version
> @@ -1 +1 @@
> -0.92 1
> +0.92 1.1.200809051657gitea651e5




More information about the ovirt-devel mailing list