Scott Seago
2008-Aug-26 15:24 UTC
[Ovirt-devel] [PATCH] Added Tasks tab/pane to HW and VM pools pages
A tasks pane is now available on both VM and HW pools page. In both cases, the tasks show up as a flexigrid panel showing tasks for the pool. By default, tasks are filtered for 'pending' state, but they may be filtered on any state (or to show all). For the VM page, all tasks for all VMs in the VM pool are available. For the HW pool page, there are 3 types of tasks available: 1) VM tasks: tasks for all VMs contained in VM pools within this HW pool 2) Host tasks: tasks for all hosts in this pool 3) storage tasks: tasks for all storage pools in this HW pool. By default all task types are shown, but the pulldown menu lets the user filter on task type as well. Signed-off-by: Scott Seago <sseago at redhat.com> --- wui/src/app/controllers/application.rb | 8 ++- wui/src/app/controllers/hardware_controller.rb | 61 +++++++++++++---- wui/src/app/controllers/resources_controller.rb | 54 +++++++++++---- wui/src/app/models/hardware_pool.rb | 3 +- wui/src/app/models/host_task.rb | 6 ++- wui/src/app/models/storage_task.rb | 5 +- wui/src/app/models/task.rb | 14 ++++ wui/src/app/models/vm_resource_pool.rb | 2 +- wui/src/app/models/vm_task.rb | 5 +- wui/src/app/views/hardware/show_tasks.rhtml | 77 ++++++++++++++++++++++ wui/src/app/views/layouts/_navigation_tabs.rhtml | 2 + wui/src/app/views/resources/show_tasks.rhtml | 61 +++++++++++++++++ wui/src/app/views/task/_grid.rhtml | 50 ++++++++++++++ 13 files changed, 313 insertions(+), 35 deletions(-) create mode 100644 wui/src/app/views/hardware/show_tasks.rhtml create mode 100644 wui/src/app/views/resources/show_tasks.rhtml create mode 100644 wui/src/app/views/task/_grid.rhtml diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb index b27ddbe..b95577a 100644 --- a/wui/src/app/controllers/application.rb +++ b/wui/src/app/controllers/application.rb @@ -90,7 +90,7 @@ class ApplicationController < ActionController::Base end # don't define find_opts for array inputs - def json_list(full_items, attributes, arg_list=[], find_opts={}) + def json_hash(full_items, attributes, arg_list=[], find_opts={}) page = params[:page].to_i paginate_opts = {:page => page, :order => "#{params[:sortname]} #{params[:sortorder]}", @@ -114,7 +114,11 @@ class ApplicationController < ActionController::Base end item_hash end - render :json => json_hash.to_json + 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 end diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 019fdd8..00fe06b 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -24,19 +24,13 @@ class HardwareController < ApplicationController :redirect_to => { :action => :list } before_filter :pre_json, :only => [:vm_pools_json, :users_json, - :storage_volumes_json] + :storage_volumes_json, :show_tasks, :tasks] before_filter :pre_modify, :only => [:add_hosts, :move_hosts, :add_storage, :move_storage, :create_storage, :delete_storage] def show - set_perms(@perm_obj) - unless @can_view - flash[:notice] = 'You do not have permission to view this hardware pool: redirecting to top level' - redirect_to :controller => "dashboard" - return - end if params[:ajax] render :layout => 'tabs-and-content' end @@ -104,14 +98,47 @@ class HardwareController < ApplicationController @hardware_pools = HardwarePool.find :all end + def show_tasks + @task_types = [["VM Task", "VmTask"], + ["Host Task", "HostTask"], + ["Storage Task", "StorageTask", "break"], + ["Show All", ""]] + @task_states = [["Queued", Task::STATE_QUEUED], + ["Running", Task::STATE_RUNNING], + ["Paused", Task::STATE_PAUSED], + ["Finished", Task::STATE_FINISHED], + ["Failed", Task::STATE_FAILED], + ["Canceled", Task::STATE_CANCELED, "break"], + ["Show All", ""]] + params[:page]=1 + params[:sortname]="tasks.created_at" + params[:sortorder]="desc" + @tasks = tasks_internal + show + end + + def tasks + render :json => tasks_internal.to_json + end + + def tasks_internal + @task_type = params[:task_type] + @task_type ||="" + @task_state = params[:task_state] + @task_state ||=Task::STATE_QUEUED + conditions = {} + conditions[:type] = @task_type unless @task_type.empty? + conditions[:state] = @task_state unless @task_state.empty? + find_opts = {:include => [:storage_pool, :host, :vm]} + find_opts[:conditions] = conditions unless conditions.empty? + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] + json_hash(@pool.tasks, attr_list, [:all], find_opts) + end + def quick_summary pre_show - set_perms(@perm_obj) - unless @can_view - flash[:notice] = 'You do not have permission to view this Hardware Pool: redirecting to top level' - redirect_to :action => 'list' - return - end render :layout => 'selection' end @@ -352,10 +379,16 @@ class HardwareController < ApplicationController @pool = HardwarePool.find(params[:id]) @perm_obj = @pool @current_pool_id=@pool.id + set_perms(@perm_obj) + unless @can_view + flash[:notice] = 'You do not have permission to view this Hardware Pool: redirecting to top level' + # FIXME: figure out the return type and render appropriately + redirect_to :action => 'list' + return + end end def pre_json pre_show - show end def pre_modify pre_edit diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb index 20defca..5a8276c 100644 --- a/wui/src/app/controllers/resources_controller.rb +++ b/wui/src/app/controllers/resources_controller.rb @@ -23,7 +23,8 @@ class ResourcesController < ApplicationController render :action => 'list' end - before_filter :pre_json, :only => [:vms_json, :users_json] + before_filter :pre_json, :only => [:vms_json, :users_json, + :show_tasks, :tasks] before_filter :pre_vm_actions, :only => [:vm_actions] # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) @@ -44,16 +45,10 @@ class ResourcesController < ApplicationController # resource's summary page def show - set_perms(@perm_obj) - @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) @action_values = [["Suspend", VmTask::ACTION_SUSPEND_VM], ["Resume", VmTask::ACTION_RESUME_VM], ["Save", VmTask::ACTION_SAVE_VM], ["Restore", VmTask::ACTION_RESTORE_VM]] - unless @can_view - flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' - redirect_to :action => 'list' - end if params[:ajax] render :layout => 'tabs-and-content' end @@ -64,12 +59,6 @@ class ResourcesController < ApplicationController def quick_summary pre_show - set_perms(@perm_obj) - @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) - unless @can_view - flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' - redirect_to :action => 'list' - end render :layout => 'selection' end @@ -90,6 +79,38 @@ class ResourcesController < ApplicationController show end + def show_tasks + @task_states = [["Queued", Task::STATE_QUEUED], + ["Running", Task::STATE_RUNNING], + ["Paused", Task::STATE_PAUSED], + ["Finished", Task::STATE_FINISHED], + ["Failed", Task::STATE_FAILED], + ["Canceled", Task::STATE_CANCELED, "break"], + ["Show All", ""]] + params[:page]=1 + params[:sortname]="tasks.created_at" + params[:sortorder]="desc" + @tasks = tasks_internal + show + end + + def tasks + render :json => tasks_internal.to_json + end + + def tasks_internal + @task_state = params[:task_state] + @task_state ||=Task::STATE_QUEUED + conditions = {} + conditions[:state] = @task_state unless @task_state.empty? + find_opts = {:include => [:storage_pool, :host, :vm]} + find_opts[:conditions] = conditions unless conditions.empty? + attr_list = [] + attr_list << :id if params[:checkboxes] + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] + json_hash(@vm_resource_pool.tasks, attr_list, [:all], find_opts) + end + def vms_json json_list(@vm_resource_pool.vms, [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state, :id]) @@ -208,6 +229,12 @@ class ResourcesController < ApplicationController @vm_resource_pool = VmResourcePool.find(params[:id]) @perm_obj = @vm_resource_pool @current_pool_id=@vm_resource_pool.id + set_perms(@perm_obj) + @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) + unless @can_view + flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' + redirect_to :action => 'dashboard' + end end def pre_edit @vm_resource_pool = VmResourcePool.find(params[:id]) @@ -218,7 +245,6 @@ class ResourcesController < ApplicationController end def pre_json pre_show - show end def pre_vm_actions @vm_resource_pool = VmResourcePool.find(params[:id]) diff --git a/wui/src/app/models/hardware_pool.rb b/wui/src/app/models/hardware_pool.rb index 3678420..a4c921b 100644 --- a/wui/src/app/models/hardware_pool.rb +++ b/wui/src/app/models/hardware_pool.rb @@ -19,7 +19,7 @@ class HardwarePool < Pool - has_many :tasks, :dependent => :nullify, :order => "id ASC" + has_many :tasks, :dependent => :nullify def all_storage_volumes StorageVolume.find(:all, :include => {:storage_pool => :hardware_pool}, :conditions => "pools.id = #{id}") end @@ -98,4 +98,5 @@ class HardwarePool < Pool return {:total => total, :labels => labels} end + end diff --git a/wui/src/app/models/host_task.rb b/wui/src/app/models/host_task.rb index ae597b0..0aea41b 100644 --- a/wui/src/app/models/host_task.rb +++ b/wui/src/app/models/host_task.rb @@ -18,11 +18,15 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class HostTask < Task - belongs_to :host ACTION_CLEAR_VMS = "clear_vms" def after_initialize self.hardware_pool = host.hardware_pool if self.host end + + def task_obj + "Host;;;#{self.host.id};;;#{self.host.hostname}" + end + end diff --git a/wui/src/app/models/storage_task.rb b/wui/src/app/models/storage_task.rb index e57b6de..db604d5 100644 --- a/wui/src/app/models/storage_task.rb +++ b/wui/src/app/models/storage_task.rb @@ -18,11 +18,14 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class StorageTask < Task - belongs_to :storage_pool ACTION_REFRESH_POOL = "refresh_pool" def after_initialize self.hardware_pool = storage_pool.hardware_pool if self.storage_pool end + + def task_obj + "StoragePool;;;#{self.storage_pool.id};;;#{self.storage_pool.display_name}" + end end diff --git a/wui/src/app/models/task.rb b/wui/src/app/models/task.rb index a7faaf0..efbed64 100644 --- a/wui/src/app/models/task.rb +++ b/wui/src/app/models/task.rb @@ -20,6 +20,13 @@ class Task < ActiveRecord::Base belongs_to :hardware_pool belongs_to :vm_resource_pool + # moved associations here so that nested set :include directives work + # StorageTask association + belongs_to :storage_pool + # HostTask association + belongs_to :host + # VmTask association + belongs_to :vm STATE_QUEUED = "queued" STATE_RUNNING = "running" @@ -50,4 +57,11 @@ class Task < ActiveRecord::Base Task.find(:all, :conditions => conditions) end + def type_label + self.class.name[0..-5] + end + def task_obj + "" + end + end diff --git a/wui/src/app/models/vm_resource_pool.rb b/wui/src/app/models/vm_resource_pool.rb index fff6dac..d6acf80 100644 --- a/wui/src/app/models/vm_resource_pool.rb +++ b/wui/src/app/models/vm_resource_pool.rb @@ -19,7 +19,7 @@ class VmResourcePool < Pool - has_many :tasks, :dependent => :nullify, :order => "id ASC" + has_many :tasks, :dependent => :nullify def get_type_label "Virtual Machine Pool" end diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb index ab96e6f..31c4ac8 100644 --- a/wui/src/app/models/vm_task.rb +++ b/wui/src/app/models/vm_task.rb @@ -18,7 +18,6 @@ # also available at http://www.gnu.org/copyleft/gpl.html. class VmTask < Task - belongs_to :vm ACTION_CREATE_VM = "create_vm" @@ -114,6 +113,10 @@ class VmTask < Task end end + def task_obj + "Vm;;;#{self.vm.id};;;#{self.vm.description}" + end + def self.valid_actions_for_vm_state(state, vm=nil, user=nil) actions = [] ACTIONS.each do |action, hash| diff --git a/wui/src/app/views/hardware/show_tasks.rhtml b/wui/src/app/views/hardware/show_tasks.rhtml new file mode 100644 index 0000000..e49086c --- /dev/null +++ b/wui/src/app/views/hardware/show_tasks.rhtml @@ -0,0 +1,77 @@ +<div id="toolbar_nav"> + <ul> + <li> + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> Type <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% @task_types.each_index { |index| %> + <li onclick="apply_task_filter('<%=@task_types[index][1]%>','<%=@task_state%>');";" + <% if (index == @task_types.length - 1) or @task_types[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > +<!-- < % = image_tag ... --> + <%= @task_type == @task_types[index][1] ? "X" : " " %> + <%=@task_types[index][0]%> + </li> + <% } %> + </ul> + </li> + <li> + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> State <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% @task_states.each_index { |index| %> + <li onclick="apply_task_filter('<%=@task_type%>','<%=@task_states[index][1]%>');";" + <% if (index == @task_states.length - 1) or @task_states[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > +<!-- < % = image_tag ... --> + <%= @task_state == @task_states[index][1] ? "X" : " " %> + <%=@task_states[index][0]%> + </li> + <% } %> + </ul> + </li> + </ul> +</div> + +<script type="text/javascript"> + var $tabs + function apply_task_filter(task_type, task_state) + { + $tabs.tabs("url", $tabs.data("selected.tabs"), + "<%= url_for :action => 'show_tasks', :id => @pool.id, + :nolayout => :true %>" + + "&task_type=" + task_type + "&task_state=" + task_state); + $tabs.tabs("load", $tabs.data("selected.tabs")); + } +</script> + +<div class="panel_header"></div> +<% if @tasks[:rows].size != 0 %> + <div class="data_section"> + <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", + :task_type => @task_type, + :task_state => @task_state, + :pool => @pool, + :checkboxes => false, + :on_select => "tasks_grid_select" } %> + </div> +<!-- do we have a selection here? + <div class="selection_detail" id="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 tasks found. <br/><br/> + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %> + </div> + </div> + </div> +<% end %> diff --git a/wui/src/app/views/layouts/_navigation_tabs.rhtml b/wui/src/app/views/layouts/_navigation_tabs.rhtml index 771958c..629ab93 100644 --- a/wui/src/app/views/layouts/_navigation_tabs.rhtml +++ b/wui/src/app/views/layouts/_navigation_tabs.rhtml @@ -13,6 +13,7 @@ <li id="nav_storage"><%= link_to "Storage", {:action => 'show_storage', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li> <li id="nav_vmpool"> <%= link_to "Virtual Machine Pools", {: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> + <li id="nav_tasks"> <%= link_to "Tasks", {:action => 'show_tasks', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li> </ul> <% elsif controller.controller_name == "resources" and @vm_resource_pool != nil %> <script> @@ -27,6 +28,7 @@ <li id="nav_summary" class="ui-tabs-selected"><%= link_to "Summary", {:action => 'show', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> <li id="nav_vmpool"> <%= link_to "Virtual Machines", {:action => 'show_vms', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> + <li id="nav_tasks"> <%= link_to "Tasks", {:action => 'show_tasks', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> </ul> <% elsif controller.controller_name == "search" %> <ul id="resources_nav_tabs" class="ui-tabs-nav"> diff --git a/wui/src/app/views/resources/show_tasks.rhtml b/wui/src/app/views/resources/show_tasks.rhtml new file mode 100644 index 0000000..493264b --- /dev/null +++ b/wui/src/app/views/resources/show_tasks.rhtml @@ -0,0 +1,61 @@ +<div id="toolbar_nav"> + <ul> + <li> + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> State <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> + <ul> + <% @task_states.each_index { |index| %> + <li onclick="apply_task_state_filter('<%=@task_states[index][1]%>');";" + <% if (index == @task_states.length - 1) or @task_states[index].length == 3 %> + style="border-bottom: 1px solid #CCCCCC;" + <% end %> + > +<!-- < % = image_tag ... --> + <%= @task_state == @task_states[index][1] ? "X" : " " %> + <%=@task_states[index][0]%> + </li> + <% } %> + </ul> + </li> + </ul> +</div> + +<script type="text/javascript"> + var $tabs + function apply_task_state_filter(task_state) + { + $tabs.tabs("url", $tabs.data("selected.tabs"), + "<%= url_for :action => 'show_tasks', :id => @vm_resource_pool.id, + :nolayout => :true %>" + + "&task_state=" + task_state); + $tabs.tabs("load", $tabs.data("selected.tabs")); + } +</script> + +<div class="panel_header"></div> +<% if @tasks[:rows].size != 0 %> + <div class="data_section"> + <%= render :partial => "/task/grid", :locals => { :table_id => "vm_tasks_grid", + :task_type => nil, + :task_state => @task_state, + :pool => @vm_resource_pool, + :checkboxes => false, + :on_select => "vm_tasks_grid_select" } %> + </div> +<!-- do we have a selection here? + <div class="selection_detail" id="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 tasks found. <br/><br/> + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %> + </div> + </div> + </div> +<% end %> diff --git a/wui/src/app/views/task/_grid.rhtml b/wui/src/app/views/task/_grid.rhtml new file mode 100644 index 0000000..cab99e5 --- /dev/null +++ b/wui/src/app/views/task/_grid.rhtml @@ -0,0 +1,50 @@ +<% tasks_per_page = 40 %> +<div id="<%= table_id %>_div"> +<%= "<form id=\"#{table_id}_form\">" if checkboxes %> +<table id="<%= table_id %>" style="display:none"></table> +<%= '</form>' if checkboxes %> +</div> +<script type="text/javascript"> + $("#<%= table_id %>").flexigrid + ( + { + url: '<%= url_for :action => "tasks", + :id => pool.id %>', + params: [{name: "task_type", value: '<%=task_type%>'}, + {name: "task_state", value: '<%=task_state%>'} + <%=", {name: 'checkboxes', value: #{checkboxes}}" if checkboxes%>], + dataType: 'json', + colModel : [ + <%= "{display: '', width : 20, align: 'left', process: #{table_id}checkbox}," if checkboxes %> + {display: 'Type', width : 80, align: 'left'}, + {display: 'Item', width : 120, align: 'right', process: <%= table_id%>item}, + {display: 'Action', name : 'action', width : 80, align: 'left'}, + {display: 'State', name : 'state', width : 60, align: 'left'}, + {display: 'User', name : 'user', width : 60, align: 'right'}, + {display: 'Created', name : 'tasks.created_at', width : 140, align: 'right'}, + {display: 'Args', name : 'args', width : 180, align: 'left'}, + {display: 'Message', name : 'message', width : 180, align: 'left'} + ], + sortname: "tasks.created_at", + sortorder: "desc", + usepager: true, + useRp: true, + rp: <%= tasks_per_page %>, + showTableToggleBtn: true, + onSelect: <%= on_select %> + } + ); + function <%= table_id %>checkbox(celDiv) + { + $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); + } + function <%= table_id %>item(celDiv) + { + $(celDiv).html($(celDiv).html().split(";;;")[2]); + } + function <%= table_id %>_select(celDiv) + { + //nothing now + }; + +</script> -- 1.5.5.1
Steve Linabery
2008-Aug-27 19:17 UTC
[Ovirt-devel] [PATCH] Added Tasks tab/pane to HW and VM pools pages
On Tue, Aug 26, 2008 at 11:24:45AM -0400, Scott Seago wrote:> A tasks pane is now available on both VM and HW pools page. In both cases, the tasks show up as a flexigrid panel showing tasks for the pool. By default, tasks are filtered for 'pending' state, but they may be filtered on any state (or to show all). For the VM page, all tasks for all VMs in the VM pool are available. For the HW pool page, there are 3 types of tasks available: > 1) VM tasks: tasks for all VMs contained in VM pools within this HW pool > 2) Host tasks: tasks for all hosts in this pool > 3) storage tasks: tasks for all storage pools in this HW pool. > By default all task types are shown, but the pulldown menu lets the user filter on task type as well. > > Signed-off-by: Scott Seago <sseago at redhat.com> > --- > wui/src/app/controllers/application.rb | 8 ++- > wui/src/app/controllers/hardware_controller.rb | 61 +++++++++++++---- > wui/src/app/controllers/resources_controller.rb | 54 +++++++++++---- > wui/src/app/models/hardware_pool.rb | 3 +- > wui/src/app/models/host_task.rb | 6 ++- > wui/src/app/models/storage_task.rb | 5 +- > wui/src/app/models/task.rb | 14 ++++ > wui/src/app/models/vm_resource_pool.rb | 2 +- > wui/src/app/models/vm_task.rb | 5 +- > wui/src/app/views/hardware/show_tasks.rhtml | 77 ++++++++++++++++++++++ > wui/src/app/views/layouts/_navigation_tabs.rhtml | 2 + > wui/src/app/views/resources/show_tasks.rhtml | 61 +++++++++++++++++ > wui/src/app/views/task/_grid.rhtml | 50 ++++++++++++++ > 13 files changed, 313 insertions(+), 35 deletions(-) > create mode 100644 wui/src/app/views/hardware/show_tasks.rhtml > create mode 100644 wui/src/app/views/resources/show_tasks.rhtml > create mode 100644 wui/src/app/views/task/_grid.rhtml > > diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb > index b27ddbe..b95577a 100644 > --- a/wui/src/app/controllers/application.rb > +++ b/wui/src/app/controllers/application.rb > @@ -90,7 +90,7 @@ class ApplicationController < ActionController::Base > end > > # don't define find_opts for array inputs > - def json_list(full_items, attributes, arg_list=[], find_opts={}) > + def json_hash(full_items, attributes, arg_list=[], find_opts={}) > page = params[:page].to_i > paginate_opts = {:page => page, > :order => "#{params[:sortname]} #{params[:sortorder]}", > @@ -114,7 +114,11 @@ class ApplicationController < ActionController::Base > end > item_hash > end > - render :json => json_hash.to_json > + 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 > end > > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 019fdd8..00fe06b 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -24,19 +24,13 @@ class HardwareController < ApplicationController > :redirect_to => { :action => :list } > > before_filter :pre_json, :only => [:vm_pools_json, :users_json, > - :storage_volumes_json] > + :storage_volumes_json, :show_tasks, :tasks] > before_filter :pre_modify, :only => [:add_hosts, :move_hosts, > :add_storage, :move_storage, > :create_storage, :delete_storage] > > > def show > - set_perms(@perm_obj) > - unless @can_view > - flash[:notice] = 'You do not have permission to view this hardware pool: redirecting to top level' > - redirect_to :controller => "dashboard" > - return > - end > if params[:ajax] > render :layout => 'tabs-and-content' > end > @@ -104,14 +98,47 @@ class HardwareController < ApplicationController > @hardware_pools = HardwarePool.find :all > end > > + def show_tasks > + @task_types = [["VM Task", "VmTask"], > + ["Host Task", "HostTask"], > + ["Storage Task", "StorageTask", "break"], > + ["Show All", ""]] > + @task_states = [["Queued", Task::STATE_QUEUED], > + ["Running", Task::STATE_RUNNING], > + ["Paused", Task::STATE_PAUSED], > + ["Finished", Task::STATE_FINISHED], > + ["Failed", Task::STATE_FAILED], > + ["Canceled", Task::STATE_CANCELED, "break"], > + ["Show All", ""]] > + params[:page]=1 > + params[:sortname]="tasks.created_at" > + params[:sortorder]="desc" > + @tasks = tasks_internal > + show > + end > + > + def tasks > + render :json => tasks_internal.to_json > + end > + > + def tasks_internal > + @task_type = params[:task_type] > + @task_type ||="" > + @task_state = params[:task_state] > + @task_state ||=Task::STATE_QUEUED > + conditions = {} > + conditions[:type] = @task_type unless @task_type.empty? > + conditions[:state] = @task_state unless @task_state.empty? > + find_opts = {:include => [:storage_pool, :host, :vm]} > + find_opts[:conditions] = conditions unless conditions.empty? > + attr_list = [] > + attr_list << :id if params[:checkboxes] > + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] > + json_hash(@pool.tasks, attr_list, [:all], find_opts) > + end > + > def quick_summary > pre_show > - set_perms(@perm_obj) > - unless @can_view > - flash[:notice] = 'You do not have permission to view this Hardware Pool: redirecting to top level' > - redirect_to :action => 'list' > - return > - end > render :layout => 'selection' > end > > @@ -352,10 +379,16 @@ class HardwareController < ApplicationController > @pool = HardwarePool.find(params[:id]) > @perm_obj = @pool > @current_pool_id=@pool.id > + set_perms(@perm_obj) > + unless @can_view > + flash[:notice] = 'You do not have permission to view this Hardware Pool: redirecting to top level' > + # FIXME: figure out the return type and render appropriately > + redirect_to :action => 'list' > + return > + end > end > def pre_json > pre_show > - show > end > def pre_modify > pre_edit > diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb > index 20defca..5a8276c 100644 > --- a/wui/src/app/controllers/resources_controller.rb > +++ b/wui/src/app/controllers/resources_controller.rb > @@ -23,7 +23,8 @@ class ResourcesController < ApplicationController > render :action => 'list' > end > > - before_filter :pre_json, :only => [:vms_json, :users_json] > + before_filter :pre_json, :only => [:vms_json, :users_json, > + :show_tasks, :tasks] > before_filter :pre_vm_actions, :only => [:vm_actions] > > # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) > @@ -44,16 +45,10 @@ class ResourcesController < ApplicationController > > # resource's summary page > def show > - set_perms(@perm_obj) > - @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) > @action_values = [["Suspend", VmTask::ACTION_SUSPEND_VM], > ["Resume", VmTask::ACTION_RESUME_VM], > ["Save", VmTask::ACTION_SAVE_VM], > ["Restore", VmTask::ACTION_RESTORE_VM]] > - unless @can_view > - flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' > - redirect_to :action => 'list' > - end > if params[:ajax] > render :layout => 'tabs-and-content' > end > @@ -64,12 +59,6 @@ class ResourcesController < ApplicationController > > def quick_summary > pre_show > - set_perms(@perm_obj) > - @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) > - unless @can_view > - flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' > - redirect_to :action => 'list' > - end > render :layout => 'selection' > end > > @@ -90,6 +79,38 @@ class ResourcesController < ApplicationController > show > end > > + def show_tasks > + @task_states = [["Queued", Task::STATE_QUEUED], > + ["Running", Task::STATE_RUNNING], > + ["Paused", Task::STATE_PAUSED], > + ["Finished", Task::STATE_FINISHED], > + ["Failed", Task::STATE_FAILED], > + ["Canceled", Task::STATE_CANCELED, "break"], > + ["Show All", ""]] > + params[:page]=1 > + params[:sortname]="tasks.created_at" > + params[:sortorder]="desc" > + @tasks = tasks_internal > + show > + end > + > + def tasks > + render :json => tasks_internal.to_json > + end > + > + def tasks_internal > + @task_state = params[:task_state] > + @task_state ||=Task::STATE_QUEUED > + conditions = {} > + conditions[:state] = @task_state unless @task_state.empty? > + find_opts = {:include => [:storage_pool, :host, :vm]} > + find_opts[:conditions] = conditions unless conditions.empty? > + attr_list = [] > + attr_list << :id if params[:checkboxes] > + attr_list += [:type_label, :task_obj, :action, :state, :user, :created_at, :args, :message] > + json_hash(@vm_resource_pool.tasks, attr_list, [:all], find_opts) > + end > + > def vms_json > json_list(@vm_resource_pool.vms, > [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state, :id]) > @@ -208,6 +229,12 @@ class ResourcesController < ApplicationController > @vm_resource_pool = VmResourcePool.find(params[:id]) > @perm_obj = @vm_resource_pool > @current_pool_id=@vm_resource_pool.id > + set_perms(@perm_obj) > + @is_hwpool_admin = @vm_resource_pool.parent.can_modify(@user) > + unless @can_view > + flash[:notice] = 'You do not have permission to view this VM Resource Pool: redirecting to top level' > + redirect_to :action => 'dashboard' > + end > end > def pre_edit > @vm_resource_pool = VmResourcePool.find(params[:id]) > @@ -218,7 +245,6 @@ class ResourcesController < ApplicationController > end > def pre_json > pre_show > - show > end > def pre_vm_actions > @vm_resource_pool = VmResourcePool.find(params[:id]) > diff --git a/wui/src/app/models/hardware_pool.rb b/wui/src/app/models/hardware_pool.rb > index 3678420..a4c921b 100644 > --- a/wui/src/app/models/hardware_pool.rb > +++ b/wui/src/app/models/hardware_pool.rb > @@ -19,7 +19,7 @@ > > class HardwarePool < Pool > > - has_many :tasks, :dependent => :nullify, :order => "id ASC" > + has_many :tasks, :dependent => :nullify > def all_storage_volumes > StorageVolume.find(:all, :include => {:storage_pool => :hardware_pool}, :conditions => "pools.id = #{id}") > end > @@ -98,4 +98,5 @@ class HardwarePool < Pool > return {:total => total, :labels => labels} > end > > + > end > diff --git a/wui/src/app/models/host_task.rb b/wui/src/app/models/host_task.rb > index ae597b0..0aea41b 100644 > --- a/wui/src/app/models/host_task.rb > +++ b/wui/src/app/models/host_task.rb > @@ -18,11 +18,15 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class HostTask < Task > - belongs_to :host > > ACTION_CLEAR_VMS = "clear_vms" > > def after_initialize > self.hardware_pool = host.hardware_pool if self.host > end > + > + def task_obj > + "Host;;;#{self.host.id};;;#{self.host.hostname}" > + end > + > end > diff --git a/wui/src/app/models/storage_task.rb b/wui/src/app/models/storage_task.rb > index e57b6de..db604d5 100644 > --- a/wui/src/app/models/storage_task.rb > +++ b/wui/src/app/models/storage_task.rb > @@ -18,11 +18,14 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class StorageTask < Task > - belongs_to :storage_pool > > ACTION_REFRESH_POOL = "refresh_pool" > > def after_initialize > self.hardware_pool = storage_pool.hardware_pool if self.storage_pool > end > + > + def task_obj > + "StoragePool;;;#{self.storage_pool.id};;;#{self.storage_pool.display_name}" > + end > end > diff --git a/wui/src/app/models/task.rb b/wui/src/app/models/task.rb > index a7faaf0..efbed64 100644 > --- a/wui/src/app/models/task.rb > +++ b/wui/src/app/models/task.rb > @@ -20,6 +20,13 @@ > class Task < ActiveRecord::Base > belongs_to :hardware_pool > belongs_to :vm_resource_pool > + # moved associations here so that nested set :include directives work > + # StorageTask association > + belongs_to :storage_pool > + # HostTask association > + belongs_to :host > + # VmTask association > + belongs_to :vm > > STATE_QUEUED = "queued" > STATE_RUNNING = "running" > @@ -50,4 +57,11 @@ class Task < ActiveRecord::Base > Task.find(:all, :conditions => conditions) > end > > + def type_label > + self.class.name[0..-5] > + end > + def task_obj > + "" > + end > + > end > diff --git a/wui/src/app/models/vm_resource_pool.rb b/wui/src/app/models/vm_resource_pool.rb > index fff6dac..d6acf80 100644 > --- a/wui/src/app/models/vm_resource_pool.rb > +++ b/wui/src/app/models/vm_resource_pool.rb > @@ -19,7 +19,7 @@ > > class VmResourcePool < Pool > > - has_many :tasks, :dependent => :nullify, :order => "id ASC" > + has_many :tasks, :dependent => :nullify > def get_type_label > "Virtual Machine Pool" > end > diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb > index ab96e6f..31c4ac8 100644 > --- a/wui/src/app/models/vm_task.rb > +++ b/wui/src/app/models/vm_task.rb > @@ -18,7 +18,6 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class VmTask < Task > - belongs_to :vm > > ACTION_CREATE_VM = "create_vm" > > @@ -114,6 +113,10 @@ class VmTask < Task > end > end > > + def task_obj > + "Vm;;;#{self.vm.id};;;#{self.vm.description}" > + end > + > def self.valid_actions_for_vm_state(state, vm=nil, user=nil) > actions = [] > ACTIONS.each do |action, hash| > diff --git a/wui/src/app/views/hardware/show_tasks.rhtml b/wui/src/app/views/hardware/show_tasks.rhtml > new file mode 100644 > index 0000000..e49086c > --- /dev/null > +++ b/wui/src/app/views/hardware/show_tasks.rhtml > @@ -0,0 +1,77 @@ > +<div id="toolbar_nav"> > + <ul> > + <li> > + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> Type <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% @task_types.each_index { |index| %> > + <li onclick="apply_task_filter('<%=@task_types[index][1]%>','<%=@task_state%>');";" > + <% if (index == @task_types.length - 1) or @task_types[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > +<!-- < % = image_tag ... --> > + <%= @task_type == @task_types[index][1] ? "X" : " " %> > + <%=@task_types[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > + <li> > + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> State <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% @task_states.each_index { |index| %> > + <li onclick="apply_task_filter('<%=@task_type%>','<%=@task_states[index][1]%>');";" > + <% if (index == @task_states.length - 1) or @task_states[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > +<!-- < % = image_tag ... --> > + <%= @task_state == @task_states[index][1] ? "X" : " " %> > + <%=@task_states[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > + </ul> > +</div> > + > +<script type="text/javascript"> > + var $tabs > + function apply_task_filter(task_type, task_state) > + { > + $tabs.tabs("url", $tabs.data("selected.tabs"), > + "<%= url_for :action => 'show_tasks', :id => @pool.id, > + :nolayout => :true %>" + > + "&task_type=" + task_type + "&task_state=" + task_state); > + $tabs.tabs("load", $tabs.data("selected.tabs")); > + } > +</script> > + > +<div class="panel_header"></div> > +<% if @tasks[:rows].size != 0 %> > + <div class="data_section"> > + <%= render :partial => "/task/grid", :locals => { :table_id => "tasks_grid", > + :task_type => @task_type, > + :task_state => @task_state, > + :pool => @pool, > + :checkboxes => false, > + :on_select => "tasks_grid_select" } %> > + </div> > +<!-- do we have a selection here? > + <div class="selection_detail" id="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 tasks found. <br/><br/> > + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %> > + </div> > + </div> > + </div> > +<% end %> > diff --git a/wui/src/app/views/layouts/_navigation_tabs.rhtml b/wui/src/app/views/layouts/_navigation_tabs.rhtml > index 771958c..629ab93 100644 > --- a/wui/src/app/views/layouts/_navigation_tabs.rhtml > +++ b/wui/src/app/views/layouts/_navigation_tabs.rhtml > @@ -13,6 +13,7 @@ > <li id="nav_storage"><%= link_to "Storage", {:action => 'show_storage', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li> > <li id="nav_vmpool"> <%= link_to "Virtual Machine Pools", {: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> > + <li id="nav_tasks"> <%= link_to "Tasks", {:action => 'show_tasks', :id => @pool.id, :nolayout => :true}, :title => "content area" %></li> > </ul> > <% elsif controller.controller_name == "resources" and @vm_resource_pool != nil %> > <script> > @@ -27,6 +28,7 @@ > <li id="nav_summary" class="ui-tabs-selected"><%= link_to "Summary", {:action => 'show', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> > <li id="nav_vmpool"> <%= link_to "Virtual Machines", {:action => 'show_vms', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> > <li id="nav_access"> <%= link_to "User Access", {:action => 'show_users', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> > + <li id="nav_tasks"> <%= link_to "Tasks", {:action => 'show_tasks', :id => @vm_resource_pool.id, :nolayout => :true}, :title => "content area" %></li> > </ul> > <% elsif controller.controller_name == "search" %> > <ul id="resources_nav_tabs" class="ui-tabs-nav"> > diff --git a/wui/src/app/views/resources/show_tasks.rhtml b/wui/src/app/views/resources/show_tasks.rhtml > new file mode 100644 > index 0000000..493264b > --- /dev/null > +++ b/wui/src/app/views/resources/show_tasks.rhtml > @@ -0,0 +1,61 @@ > +<div id="toolbar_nav"> > + <ul> > + <li> > + <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %> State <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> > + <ul> > + <% @task_states.each_index { |index| %> > + <li onclick="apply_task_state_filter('<%=@task_states[index][1]%>');";" > + <% if (index == @task_states.length - 1) or @task_states[index].length == 3 %> > + style="border-bottom: 1px solid #CCCCCC;" > + <% end %> > + > > +<!-- < % = image_tag ... --> > + <%= @task_state == @task_states[index][1] ? "X" : " " %> > + <%=@task_states[index][0]%> > + </li> > + <% } %> > + </ul> > + </li> > + </ul> > +</div> > + > +<script type="text/javascript"> > + var $tabs > + function apply_task_state_filter(task_state) > + { > + $tabs.tabs("url", $tabs.data("selected.tabs"), > + "<%= url_for :action => 'show_tasks', :id => @vm_resource_pool.id, > + :nolayout => :true %>" + > + "&task_state=" + task_state); > + $tabs.tabs("load", $tabs.data("selected.tabs")); > + } > +</script> > + > +<div class="panel_header"></div> > +<% if @tasks[:rows].size != 0 %> > + <div class="data_section"> > + <%= render :partial => "/task/grid", :locals => { :table_id => "vm_tasks_grid", > + :task_type => nil, > + :task_state => @task_state, > + :pool => @vm_resource_pool, > + :checkboxes => false, > + :on_select => "vm_tasks_grid_select" } %> > + </div> > +<!-- do we have a selection here? > + <div class="selection_detail" id="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 tasks found. <br/><br/> > + <%= image_tag "icon_addhost.png", :style=>"vertical-align:middle;" %> > + </div> > + </div> > + </div> > +<% end %> > diff --git a/wui/src/app/views/task/_grid.rhtml b/wui/src/app/views/task/_grid.rhtml > new file mode 100644 > index 0000000..cab99e5 > --- /dev/null > +++ b/wui/src/app/views/task/_grid.rhtml > @@ -0,0 +1,50 @@ > +<% tasks_per_page = 40 %> > +<div id="<%= table_id %>_div"> > +<%= "<form id=\"#{table_id}_form\">" if checkboxes %> > +<table id="<%= table_id %>" style="display:none"></table> > +<%= '</form>' if checkboxes %> > +</div> > +<script type="text/javascript"> > + $("#<%= table_id %>").flexigrid > + ( > + { > + url: '<%= url_for :action => "tasks", > + :id => pool.id %>', > + params: [{name: "task_type", value: '<%=task_type%>'}, > + {name: "task_state", value: '<%=task_state%>'} > + <%=", {name: 'checkboxes', value: #{checkboxes}}" if checkboxes%>], > + dataType: 'json', > + colModel : [ > + <%= "{display: '', width : 20, align: 'left', process: #{table_id}checkbox}," if checkboxes %> > + {display: 'Type', width : 80, align: 'left'}, > + {display: 'Item', width : 120, align: 'right', process: <%= table_id%>item}, > + {display: 'Action', name : 'action', width : 80, align: 'left'}, > + {display: 'State', name : 'state', width : 60, align: 'left'}, > + {display: 'User', name : 'user', width : 60, align: 'right'}, > + {display: 'Created', name : 'tasks.created_at', width : 140, align: 'right'}, > + {display: 'Args', name : 'args', width : 180, align: 'left'}, > + {display: 'Message', name : 'message', width : 180, align: 'left'} > + ], > + sortname: "tasks.created_at", > + sortorder: "desc", > + usepager: true, > + useRp: true, > + rp: <%= tasks_per_page %>, > + showTableToggleBtn: true, > + onSelect: <%= on_select %> > + } > + ); > + function <%= table_id %>checkbox(celDiv) > + { > + $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); > + } > + function <%= table_id %>item(celDiv) > + { > + $(celDiv).html($(celDiv).html().split(";;;")[2]); > + } > + function <%= table_id %>_select(celDiv) > + { > + //nothing now > + }; > + > +</script> > -- > 1.5.5.1 > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-develTested and it works like a dream. ACK! --Steve