Scott Seago
2008-Nov-18 05:35 UTC
[Ovirt-devel] [PATCH] replaced flexigrid-based display for HW and smart pool storage with tree component.
Signed-off-by: Scott Seago <sseago at redhat.com> --- src/app/controllers/hardware_controller.rb | 3 +- src/app/controllers/search_controller.rb | 41 ++++++--- src/app/controllers/smart_pools_controller.rb | 1 + src/app/controllers/storage_controller.rb | 2 +- src/app/models/smart_pool.rb | 20 ++++ src/app/models/storage_pool.rb | 3 +- src/app/models/storage_volume.rb | 7 +- src/app/views/hardware/show_storage.rhtml | 64 +++++++++---- src/app/views/smart_pools/show_storage.rhtml | 63 +++++++++---- src/app/views/storage/show.rhtml | 40 -------- src/app/views/storage/show_volume.rhtml | 127 +++++++++---------------- src/public/javascripts/ovirt.js | 3 +- 12 files changed, 200 insertions(+), 174 deletions(-) diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb index 8c26184..4dda736 100644 --- a/src/app/controllers/hardware_controller.rb +++ b/src/app/controllers/hardware_controller.rb @@ -111,6 +111,7 @@ class HardwareController < PoolController end def show_storage + @storage_tree = @pool.storage_tree(:filter_unavailable => false, :include_used => true).to_json show end @@ -171,7 +172,7 @@ class HardwareController < PoolController id = params[:exclude_pool] storage_pools = StoragePool find_opts = {:include => :hardware_pool, - :conditions => ["pools.id != ?", id]} + :conditions => ["(storage_pools.type != 'LvmStoragePool') and (pools.id != ?)", id]} include_pool = true end super(:full_items => storage_pools,:include_pool => include_pool,:find_opts => find_opts) diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb index 3789309..7551242 100644 --- a/src/app/controllers/search_controller.rb +++ b/src/app/controllers/search_controller.rb @@ -19,18 +19,33 @@ class SearchController < ApplicationController - MODELS = {"HardwarePool" => {:controller => "hardware", - :show_action => "quick_summary"}, - "VmResourcePool" => {:controller => "resources", - :show_action => "quick_summary"}, - "Host" => {:controller => "host", - :show_action => "show"}, - "Vm" => {:controller => "vm", - :show_action => "show"}, - "IscsiStoragePool" => {:controller => "storage", - :show_action => "show"}, - "NfsStoragePool" => {:controller => "storage", - :show_action => "show"}} + MODELS = {"HardwarePool" => {:controller => "hardware", + :show_action => "quick_summary", + :searched => true}, + "VmResourcePool" => {:controller => "resources", + :show_action => "quick_summary", + :searched => true}, + "Host" => {:controller => "host", + :show_action => "show", + :searched => true}, + "Vm" => {:controller => "vm", + :show_action => "show", + :searched => true}, + "IscsiStoragePool" => {:controller => "storage", + :show_action => "show", + :searched => true}, + "NfsStoragePool" => {:controller => "storage", + :show_action => "show", + :searched => true}, + "IscsiStorageVolume" => {:controller => "storage", + :show_action => "show_volume", + :searched => false}, + "NfsStorageVolume" => {:controller => "storage", + :show_action => "show_volume", + :searched => false}, + "LvmStorageVolume" => {:controller => "storage", + :show_action => "show_volume", + :searched => false}} MULTI_TYPE_MODELS = {"StoragePool" => ["IscsiStoragePool", "NfsStoragePool"]} @@ -50,7 +65,7 @@ class SearchController < ApplicationController @model_param ||= "" if @model_param == "" - @models = MODELS.keys + @models = MODELS.keys.select {|model| MODELS[model][:searched]} else @models = MULTI_TYPE_MODELS[@model_param] @models ||= [@model_param] diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb index 0295b63..37ccdad 100644 --- a/src/app/controllers/smart_pools_controller.rb +++ b/src/app/controllers/smart_pools_controller.rb @@ -38,6 +38,7 @@ class SmartPoolsController < PoolController end def show_storage + @storage_tree = @pool.storage_tree(:filter_unavailable => false, :include_used => true).to_json show end diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb index e3e5522..6e6e3c2 100644 --- a/src/app/controllers/storage_controller.rb +++ b/src/app/controllers/storage_controller.rb @@ -107,7 +107,7 @@ class StorageController < ApplicationController end else respond_to do |format| - format.html { render :layout => 'popup' } + format.html { render :layout => 'selection' } format.xml { render :xml => @storage_volume.to_xml } end end diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb index ac6db5e..772ffef 100644 --- a/src/app/models/smart_pool.rb +++ b/src/app/models/smart_pool.rb @@ -97,4 +97,24 @@ class SmartPool < Pool user_pools[-1] << "break" unless user_pools.empty? user_pools + other_pools end + + # params accepted: + # :vm_to_include - if specified, storage used by this VM is included in the tree + # :filter_unavailable - if true, don't include Storage not currently available + # :include_used - include all storage pools/volumes, even those in use + # for smart pools, filter_unavailable defaults to false and include_used to true + def storage_tree(params = {}) + vm_to_include=params.fetch(:vm_to_include, nil) + filter_unavailable = params.fetch(:filter_unavailable, false) + include_used = params.fetch(:include_used, true) + conditions = "type != 'LvmStoragePool'" + if filter_unavailable + conditions = "(#{conditions}) and (storage_pools.state = '#{StoragePool::STATE_AVAILABLE}')" + end + tagged_storage_pools.find(:all, + :conditions => conditions).collect do |pool| + pool.storage_tree_element(params) + end + end + end diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb index 9c80f54..bab7031 100644 --- a/src/app/models/storage_pool.rb +++ b/src/app/models/storage_pool.rb @@ -97,7 +97,8 @@ class StoragePool < ActiveRecord::Base :name => display_name, :available => false, :create_volume => user_subdividable, - :selected => false} + :selected => false, + :is_pool => true} conditions = nil unless include_used conditions = "vms.id is null" diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb index 56cdcef..39b72d5 100644 --- a/src/app/models/storage_volume.rb +++ b/src/app/models/storage_volume.rb @@ -80,6 +80,10 @@ class StorageVolume < ActiveRecord::Base return false end + def deletable + storage_pool.user_subdividable and vms.empty? and (lvm_storage_pool.nil? or lvm_storage_pool.storage_volumes.empty?) + end + def storage_tree_element(params = {}) vm_to_include=params.fetch(:vm_to_include, nil) filter_unavailable = params.fetch(:filter_unavailable, true) @@ -95,7 +99,8 @@ class StorageVolume < ActiveRecord::Base vm_ids.include?(vm_to_include.id))), :create_volume => supports_lvm_subdivision, :selected => (!vm_ids.empty? and vm_to_include and vm_to_include.id and - (vm_ids.include?(vm_to_include.id)))} + (vm_ids.include?(vm_to_include.id))), + :is_pool => false} if lvm_storage_pool if return_hash[:available] return_hash[:available] = lvm_storage_pool.storage_volumes.full_vm_list.empty? diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml index 5ade456..6a91161 100644 --- a/src/app/views/hardware/show_storage.rhtml +++ b/src/app/views/hardware/show_storage.rhtml @@ -1,5 +1,5 @@ <div id="toolbar_nav"> -<ul> + <ul> <li><a href="<%= url_for :controller => 'storage', :action => 'addstorage', :hardware_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addstorage.png", :style => "vertical-align:middle;" %> Add Storage Server</a></li> <li> <a href="#" onClick="return validate_storage_for_move();" ><%= image_tag "icon_move.png", :style=>"vertical-align:middle;" %> Move</a> @@ -27,7 +27,40 @@ </ul> </div> +<textarea id="tree_template" style="display:none;"> +{macro htmlList(list, isFullList)} + {if isFullList} + <ul style="display:none;"> + {/if} + {for item in list} + <li> + <span class="hitarea {if item.children.length > 0} expandable{/if}"> </span> + <div id="tree-${item.type}_${item.id}"> + <input class="grid_checkbox" type="checkbox" + name="grid_checkbox${item.type}_${item.id}" + value="${item.id}" + {if !item.is_pool}disabled="disabled" style="display:none"{/if} + {if item.selected}checked="checked"{/if}/> ${item.name} {if item.size}(${item.size} GB){/if} + </div> + {if item.children.length > 0} + ${htmlList(item.children, true)} + {/if} + </li> + {/for} + {if isFullList} + </ul> + {/if} +{/macro} + +${htmlList(pools)} +</textarea> <script type="text/javascript"> + $(document).ready(function(){ + $('#storage_tree').tree({ + content: {"pools" : <%= @storage_tree%>}, + clickHandler: storage_select + }); + }); function add_storage_to_smart_pool(smart_pool) { var storage = get_selected_storage(); @@ -35,7 +68,8 @@ $.post('<%= url_for :controller => "smart_pools", :action => "add_storage" %>', { resource_ids: storage.toString(), id: smart_pool }, function(data,status){ - $('#storage_grid').flexReload(); + // FIXME: reload #storage_tree + //$('#storage_grid').flexReload(); if (data.alert) { $.jGrowl(data.alert); } @@ -76,28 +110,24 @@ }, 'json'); } } - function storage_select(selected_rows) + function storage_select(e, elem) { - 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) - { - $('#storage_selection').load('<%= url_for :controller => "storage", :action => "show" %>', - { id: parseInt(selected_ids[0].substring(3))}); - } + $('#storage_tree_form ul.ovirt-tree li div').removeClass('current'); + $(elem) + .addClass('current'); + $('#storage_selection').load('<%= url_for :controller => "search", :action => "single_result" %>', + { class_and_id: elem.id.substring(5)}); } </script> <div class="panel_header"></div> <% if @pool.storage_pools.size != 0 %> <div class="data_section"> - <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", - :hwpool => @pool, - :exclude_pool => nil, - :on_select => "storage_select", - :is_popup => false} %> + <div style="overflow:auto; border:#CCCCCC solid 1px;"> + <form id="storage_tree_form"> + <ul id="storage_tree" class="ovirt-tree"></ul> + </form> + </div> </div> <div class="selection_detail" id="storage_selection"> diff --git a/src/app/views/smart_pools/show_storage.rhtml b/src/app/views/smart_pools/show_storage.rhtml index 7cf425a..9a9b78e 100644 --- a/src/app/views/smart_pools/show_storage.rhtml +++ b/src/app/views/smart_pools/show_storage.rhtml @@ -5,10 +5,44 @@ </ul> </div> +<textarea id="tree_template" style="display:none;"> +{macro htmlList(list, isFullList)} + {if isFullList} + <ul style="display:none;"> + {/if} + {for item in list} + <li> + <span class="hitarea {if item.children.length > 0} expandable{/if}"> </span> + <div id="tree-${item.type}_${item.id}"> + <input class="grid_checkbox" type="checkbox" + name="grid_checkbox${item.type}_${item.id}" + value="${item.id}" + {if !item.is_pool}disabled="disabled" style="display:none"{/if} + {if item.selected}checked="checked"{/if}/> ${item.name} {if item.size}(${item.size} GB){/if} + </div> + {if item.children.length > 0} + ${htmlList(item.children, true)} + {/if} + </li> + {/for} + {if isFullList} + </ul> + {/if} +{/macro} + +${htmlList(pools)} +</textarea> + <script type="text/javascript"> + $(document).ready(function(){ + $('#smart_storage_tree').tree({ + content: {"pools" : <%= @storage_tree%>}, + clickHandler: smart_storage_select + }); + }); function get_selected_storage_for_smart_pool() { - return get_selected_checkboxes("smart_storage_grid_form"); + return get_selected_checkboxes("smart_storage_tree_form"); } function remove_storage_from_smart_pool() { @@ -27,29 +61,24 @@ }, 'json'); } } - function smart_storage_select(selected_rows) + function smart_storage_select(e, elem) { - 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))}); - } + $('#smart_storage_tree_form ul.ovirt-tree li div').removeClass('current'); + $(elem) + .addClass('current'); + $('#smart_storage_selection').load('<%= url_for :controller => "search", :action => "single_result" %>', + { class_and_id: elem.id.substring(5)}); } </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 style="overflow:auto; border:#CCCCCC solid 1px;"> + <form id="smart_storage_tree_form"> + <ul id="smart_storage_tree" class="ovirt-tree"></ul> + </form> + </div> </div> <div class="selection_detail" id="smart_storage_selection"> diff --git a/src/app/views/storage/show.rhtml b/src/app/views/storage/show.rhtml index 123cf20..a4cc1c2 100644 --- a/src/app/views/storage/show.rhtml +++ b/src/app/views/storage/show.rhtml @@ -40,51 +40,11 @@ <%=h @storage_pool.state %><br/> </div> <%- content_for :right do -%> - <div class="selection_right_title">Volumes</div> -<!-- hide for now - <ul class="selection_tab_nav"> - <li><a href="#"><%=image_tag "icon_selection_add.gif", :style=>"vertical-align:middle;" %>Add</a></li> - <li><a href="#"><%=image_tag "icon_selection_showdetail.gif", :style=>"vertical-align:middle;" %>Show Detail</a></li> - <li><a href="#"><%=image_tag "icon_selection_remove.gif", :style=>"vertical-align:middle;" %>Remove</a></li> - </ul> ---> - <div class="selection_right_table"> - <table id="storage_volumes_grid" style="display:none"></table> - </div> <%- end -%> <%= confirmation_dialog("confirm_delete_storage", "Are you sure?", "delete_storage_pool()") %> <script type="text/javascript"> - $("#storage_volumes_grid").flexigrid - ( - { - url: '<%= url_for :action => "storage_volumes_json", :id => @storage_pool.id %>', - dataType: 'json', - colModel : [ - <%= "{display: '', width : 20, align: 'left', process: storage_volumes_gridcheckbox}," if (@storage_pool.user_subdividable and @can_modify) %> - {display: 'Alias', width : 180, sortable : false, align: 'left', process: storage_volume_details_link}, - {display: 'Size (Gb)', name : 'size', width : 80, sortable : true, align: 'left'}, - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} - ], - sortname: "size", - sortorder: "desc", - usepager: false, - useRp: true, - rp: 40, - showTableToggleBtn: true, - } - ); - function storage_volumes_gridcheckbox(celDiv) - { - $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); - } - function storage_volume_details_link(celDiv,pid) - { - $(celDiv).html('<a href="<%= url_for :controller => 'storage', :action => 'show_volume' %>/'+ pid +'" rel="facebox[.bolder]">' + $(celDiv).html() + '</a>'); - } -</script> -<script type="text/javascript"> function refresh_storage_pool() { diff --git a/src/app/views/storage/show_volume.rhtml b/src/app/views/storage/show_volume.rhtml index c1cb66a..c1138f4 100644 --- a/src/app/views/storage/show_volume.rhtml +++ b/src/app/views/storage/show_volume.rhtml @@ -1,26 +1,27 @@ <%- content_for :title do -%> <%=h @storage_volume.display_name %> <%- end -%> -<%- content_for :description do -%> - Details for Storage Volume <%=h @storage_volume.display_name %> + +<%- content_for :action_links do -%> + <%if @can_modify -%> + <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> + <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", + {:controller => 'storage', :action => 'new_lvm_volume', :source_volume_id => @storage_volume.id}, + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> + <% end %> + <%if @storage_volume.deletable -%> + <a href="#confirm_delete" rel="facebox[.bolder]"> + <%= image_tag "icon_x.png" %> Delete + </a> + <%- end -%> + <%- end -%> <%- end -%> +<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> -<% if @storage_volume.supports_lvm_subdivision %> - <div id="dialog-content-area"> - <div id="toolbar_nav"> - <ul> - <li><a href="#" id="new_lvm_volume_button"><%=image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>Add</a></li> - <% if (@storage_volume.lvm_storage_pool and - !@storage_volume.lvm_storage_pool.storage_volumes.empty?) %> - <li><a href="#" onClick="return remove_lvm_volumes();"><%=image_tag "icon_remove.png" %> Remove</a></li> - <% end %> - </ul> - </div> - </div> -<% end %> -<div class="panel_header"></div> <div class="selection_key"> - IP address:<br/> + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + IP address:<br/> + <% end %> <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> Port:<br/> Target:<br/> @@ -34,12 +35,18 @@ LUN:<br/> <% elsif @storage_volume[:type] == "NfsStorageVolume" %> Filename:<br/> + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + Volume Group:<br/> + Logical Volume:<br/> + Permissions (owner/group/mode):<br/> <% end %> Size:<br/> </div> <div class="selection_value"> - <%=h @storage_volume.storage_pool.ip_addr %><br/> - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> + <%=h @storage_volume.storage_pool.ip_addr %><br/> + <% end %> + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> <%=h @storage_volume.storage_pool.port %><br/> <%=h @storage_volume.storage_pool[:target] %><br/> <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> @@ -52,74 +59,30 @@ <%=h @storage_volume.lun %><br/> <% elsif @storage_volume[:type] == "NfsStorageVolume" %> <%=h @storage_volume.filename %><br/> + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> + <%=h @storage_volume.storage_pool.vg_name %><br/> + <%=h @storage_volume.lv_name %><br/> + <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %><br/> <% end %> <%=h @storage_volume.size_in_gb %> GB<br/> </div> -<% if @storage_volume.supports_lvm_subdivision %> - <div class="dialog_form"> - <div class="form_heading">LVM Volumes</div> - <% if @storage_volume.lvm_storage_pool %> - <form id="lvm_storage_volumes_grid_form"> - <table id="lvm_storage_volumes_grid" style="display:none"></table> - </form> - <% end %> - </div> -<% end %> +<%- content_for :right do -%> + +<%- end -%> -<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')">Close</a></div> - <div class="button_right_grey"></div> - </div> -</div> <script type="text/javascript"> - $("#lvm_storage_volumes_grid").flexigrid - ( - { - url: '<%= url_for :action => "storage_volumes_json", :id => @storage_volume.lvm_storage_pool.id %>', - dataType: 'json', - colModel : [ - <%= "{display: '', width : 20, align: 'left', process: lvm_storage_volumes_gridcheckbox}," if @can_modify %> - {display: 'Alias', width : 180, sortable : false, align: 'left'}, - {display: 'Size (Gb)', name : 'size', width : 80, sortable : true, align: 'left'}, - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} - ], - sortname: "size", - sortorder: "desc", - usepager: false, - useRp: true, - rp: 40, - showTableToggleBtn: true, - } - ); - function lvm_storage_volumes_gridcheckbox(celDiv) - { - $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); - } - function get_selected_lvm_volumes() - { - return get_selected_checkboxes("lvm_storage_volumes_grid_form"); - } - function remove_lvm_volumes() + function delete_volume() { - var volumes = get_selected_lvm_volumes(); - if (validate_selected(volumes, "storage volume")) { - $.post('<%= url_for :controller => "storage", :action => "delete_volumes" %>', - { storage_volume_ids: volumes.toString() }, - function(data,status){ - $("#lvm_storage_volumes_grid").flexReload(); - if (data.alert) { - $.jGrowl(data.alert); - } - }, 'json'); - } + $(document).trigger('close.facebox'); + $.post('<%= url_for :controller => "storage", :action => "delete_volumes" %>', + { storage_volume_ids: <%= @storage_volume.id %> }, + function(data,status) { + // FIXME: reload tree + //$("#vms_grid").flexReload(); + if (data.alert) { + $.jGrowl(data.alert); + } + empty_summary('storage_selection', 'Storage Pool or Volume'); + }, 'json'); } -$('#new_lvm_volume_button').click(function(){ - $('#window').fadeOut('fast'); - $("#window").empty().load("<%= url_for :controller => 'storage', :action => 'new_lvm_volume' %>", - { source_volume_id: <%=@storage_volume.id%>, - return_facebox: '<%= url_for :controller => 'storage', :action => 'show_volume', :id => @storage_volume.id %>' }); - $('#window').fadeIn('fast'); -}); </script> diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js index d84b3d9..e0e3dc8 100644 --- a/src/public/javascripts/ovirt.js +++ b/src/public/javascripts/ovirt.js @@ -62,6 +62,7 @@ function add_storage(url) { resource_ids: storage.toString() }, function(data,status){; $(document).trigger('close.facebox'); + // FIXME: this always reloads the tab for now grid = $("#storage_grid"); if (grid.size()>0 && grid != null) { grid.flexReload(); @@ -256,7 +257,7 @@ function empty_summary(element_id, label){ function get_selected_storage() { - return get_selected_checkboxes("storage_grid_form"); + return get_selected_checkboxes("storage_tree_form"); } function validate_storage_for_move() { -- 1.5.6.5
Jason Guiditta
2008-Nov-18 21:39 UTC
[Ovirt-devel] [PATCH] replaced flexigrid-based display for HW and smart pool storage with tree component.
Overall works well for me, some comments inline, plus that bit of filtering we discussed in irc - lvm volumes should be filtered from add storage list. On Tue, 2008-11-18 at 05:35 +0000, Scott Seago wrote:> Signed-off-by: Scott Seago <sseago at redhat.com> > --- > src/app/controllers/hardware_controller.rb | 3 +- > src/app/controllers/search_controller.rb | 41 ++++++--- > src/app/controllers/smart_pools_controller.rb | 1 + > src/app/controllers/storage_controller.rb | 2 +- > src/app/models/smart_pool.rb | 20 ++++ > src/app/models/storage_pool.rb | 3 +- > src/app/models/storage_volume.rb | 7 +- > src/app/views/hardware/show_storage.rhtml | 64 +++++++++---- > src/app/views/smart_pools/show_storage.rhtml | 63 +++++++++---- > src/app/views/storage/show.rhtml | 40 -------- > src/app/views/storage/show_volume.rhtml | 127 +++++++++---------------- > src/public/javascripts/ovirt.js | 3 +- > 12 files changed, 200 insertions(+), 174 deletions(-) > > diff --git a/src/app/controllers/hardware_controller.rb b/src/app/controllers/hardware_controller.rb > index 8c26184..4dda736 100644 > --- a/src/app/controllers/hardware_controller.rb > +++ b/src/app/controllers/hardware_controller.rb > @@ -111,6 +111,7 @@ class HardwareController < PoolController > end > > def show_storage > + @storage_tree = @pool.storage_tree(:filter_unavailable => false, :include_used => true).to_json > show > end > > @@ -171,7 +172,7 @@ class HardwareController < PoolController > id = params[:exclude_pool] > storage_pools = StoragePool > find_opts = {:include => :hardware_pool, > - :conditions => ["pools.id != ?", id]} > + :conditions => ["(storage_pools.type != 'LvmStoragePool') and (pools.id != ?)", id]} > include_pool = true > end > super(:full_items => storage_pools,:include_pool => include_pool,:find_opts => find_opts) > diff --git a/src/app/controllers/search_controller.rb b/src/app/controllers/search_controller.rb > index 3789309..7551242 100644 > --- a/src/app/controllers/search_controller.rb > +++ b/src/app/controllers/search_controller.rb > @@ -19,18 +19,33 @@ > > class SearchController < ApplicationController > > - MODELS = {"HardwarePool" => {:controller => "hardware", > - :show_action => "quick_summary"}, > - "VmResourcePool" => {:controller => "resources", > - :show_action => "quick_summary"}, > - "Host" => {:controller => "host", > - :show_action => "show"}, > - "Vm" => {:controller => "vm", > - :show_action => "show"}, > - "IscsiStoragePool" => {:controller => "storage", > - :show_action => "show"}, > - "NfsStoragePool" => {:controller => "storage", > - :show_action => "show"}} > + MODELS = {"HardwarePool" => {:controller => "hardware", > + :show_action => "quick_summary", > + :searched => true}, > + "VmResourcePool" => {:controller => "resources", > + :show_action => "quick_summary", > + :searched => true}, > + "Host" => {:controller => "host", > + :show_action => "show", > + :searched => true}, > + "Vm" => {:controller => "vm", > + :show_action => "show", > + :searched => true}, > + "IscsiStoragePool" => {:controller => "storage", > + :show_action => "show", > + :searched => true}, > + "NfsStoragePool" => {:controller => "storage", > + :show_action => "show", > + :searched => true}, > + "IscsiStorageVolume" => {:controller => "storage", > + :show_action => "show_volume", > + :searched => false}, > + "NfsStorageVolume" => {:controller => "storage", > + :show_action => "show_volume", > + :searched => false}, > + "LvmStorageVolume" => {:controller => "storage", > + :show_action => "show_volume", > + :searched => false}} > > MULTI_TYPE_MODELS = {"StoragePool" => ["IscsiStoragePool", "NfsStoragePool"]} > > @@ -50,7 +65,7 @@ class SearchController < ApplicationController > @model_param ||= "" > > if @model_param == "" > - @models = MODELS.keys > + @models = MODELS.keys.select {|model| MODELS[model][:searched]} > else > @models = MULTI_TYPE_MODELS[@model_param] > @models ||= [@model_param] > diff --git a/src/app/controllers/smart_pools_controller.rb b/src/app/controllers/smart_pools_controller.rb > index 0295b63..37ccdad 100644 > --- a/src/app/controllers/smart_pools_controller.rb > +++ b/src/app/controllers/smart_pools_controller.rb > @@ -38,6 +38,7 @@ class SmartPoolsController < PoolController > end > > def show_storage > + @storage_tree = @pool.storage_tree(:filter_unavailable => false, :include_used => true).to_json > show > end > > diff --git a/src/app/controllers/storage_controller.rb b/src/app/controllers/storage_controller.rb > index e3e5522..6e6e3c2 100644 > --- a/src/app/controllers/storage_controller.rb > +++ b/src/app/controllers/storage_controller.rb > @@ -107,7 +107,7 @@ class StorageController < ApplicationController > end > else > respond_to do |format| > - format.html { render :layout => 'popup' } > + format.html { render :layout => 'selection' } > format.xml { render :xml => @storage_volume.to_xml } > end > end > diff --git a/src/app/models/smart_pool.rb b/src/app/models/smart_pool.rb > index ac6db5e..772ffef 100644 > --- a/src/app/models/smart_pool.rb > +++ b/src/app/models/smart_pool.rb > @@ -97,4 +97,24 @@ class SmartPool < Pool > user_pools[-1] << "break" unless user_pools.empty? > user_pools + other_pools > endExcellent to see documentation of code, makes it so much easier to understand> + > + # params accepted: > + # :vm_to_include - if specified, storage used by this VM is included in the tree > + # :filter_unavailable - if true, don't include Storage not currently available > + # :include_used - include all storage pools/volumes, even those in use > + # for smart pools, filter_unavailable defaults to false and include_used to true > + def storage_tree(params = {}) > + vm_to_include=params.fetch(:vm_to_include, nil) > + filter_unavailable = params.fetch(:filter_unavailable, false) > + include_used = params.fetch(:include_used, true) > + conditions = "type != 'LvmStoragePool'" > + if filter_unavailable > + conditions = "(#{conditions}) and (storage_pools.state = '#{StoragePool::STATE_AVAILABLE}')" > + end > + tagged_storage_pools.find(:all, > + :conditions => conditions).collect do |pool| > + pool.storage_tree_element(params) > + end > + end > + > end > diff --git a/src/app/models/storage_pool.rb b/src/app/models/storage_pool.rb > index 9c80f54..bab7031 100644 > --- a/src/app/models/storage_pool.rb > +++ b/src/app/models/storage_pool.rb > @@ -97,7 +97,8 @@ class StoragePool < ActiveRecord::Base > :name => display_name, > :available => false, > :create_volume => user_subdividable, > - :selected => false} > + :selected => false, > + :is_pool => true} > conditions = nil > unless include_used > conditions = "vms.id is null" > diff --git a/src/app/models/storage_volume.rb b/src/app/models/storage_volume.rb > index 56cdcef..39b72d5 100644 > --- a/src/app/models/storage_volume.rb > +++ b/src/app/models/storage_volume.rb > @@ -80,6 +80,10 @@ class StorageVolume < ActiveRecord::Base > return false > end > > + def deletable > + storage_pool.user_subdividable and vms.empty? and (lvm_storage_pool.nil? or lvm_storage_pool.storage_volumes.empty?) > + end > + > def storage_tree_element(params = {}) > vm_to_include=params.fetch(:vm_to_include, nil) > filter_unavailable = params.fetch(:filter_unavailable, true) > @@ -95,7 +99,8 @@ class StorageVolume < ActiveRecord::Base > vm_ids.include?(vm_to_include.id))), > :create_volume => supports_lvm_subdivision, > :selected => (!vm_ids.empty? and vm_to_include and vm_to_include.id and > - (vm_ids.include?(vm_to_include.id)))} > + (vm_ids.include?(vm_to_include.id))), > + :is_pool => false} > if lvm_storage_pool > if return_hash[:available] > return_hash[:available] = lvm_storage_pool.storage_volumes.full_vm_list.empty? > diff --git a/src/app/views/hardware/show_storage.rhtml b/src/app/views/hardware/show_storage.rhtml > index 5ade456..6a91161 100644 > --- a/src/app/views/hardware/show_storage.rhtml > +++ b/src/app/views/hardware/show_storage.rhtml > @@ -1,5 +1,5 @@ > <div id="toolbar_nav"> > -<ul> > + <ul> > <li><a href="<%= url_for :controller => 'storage', :action => 'addstorage', :hardware_pool_id => @pool %>" rel="facebox[.bolder]"><%= image_tag "icon_addstorage.png", :style => "vertical-align:middle;" %> Add Storage Server</a></li> > <li> > <a href="#" onClick="return validate_storage_for_move();" ><%= image_tag "icon_move.png", :style=>"vertical-align:middle;" %> Move</a> > @@ -27,7 +27,40 @@ > </ul> > </div> > > +<textarea id="tree_template" style="display:none;"> > +{macro htmlList(list, isFullList)} > + {if isFullList} > + <ul style="display:none;"> > + {/if} > + {for item in list} > + <li> > + <span class="hitarea {if item.children.length > 0} expandable{/if}"> </span> > + <div id="tree-${item.type}_${item.id}"> > + <input class="grid_checkbox" type="checkbox" > + name="grid_checkbox${item.type}_${item.id}" > + value="${item.id}" > + {if !item.is_pool}disabled="disabled" style="display:none"{/if} > + {if item.selected}checked="checked"{/if}/> ${item.name} {if item.size}(${item.size} GB){/if} > + </div> > + {if item.children.length > 0} > + ${htmlList(item.children, true)} > + {/if} > + </li> > + {/for} > + {if isFullList} > + </ul> > + {/if} > +{/macro} > + > +${htmlList(pools)} > +</textarea> > <script type="text/javascript"> > + $(document).ready(function(){ > + $('#storage_tree').tree({ > + content: {"pools" : <%= @storage_tree%>}, > + clickHandler: storage_select > + }); > + }); > function add_storage_to_smart_pool(smart_pool) > { > var storage = get_selected_storage(); > @@ -35,7 +68,8 @@ > $.post('<%= url_for :controller => "smart_pools", :action => "add_storage" %>', > { resource_ids: storage.toString(), id: smart_pool }, > function(data,status){ > - $('#storage_grid').flexReload(); > + // FIXME: reload #storage_tree > + //$('#storage_grid').flexReload();I don't think we really need to keep this line ^^> if (data.alert) { > $.jGrowl(data.alert); > } > @@ -76,28 +110,24 @@ > }, 'json'); > } > } > - function storage_select(selected_rows) > + function storage_select(e, elem) > { > - 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) > - { > - $('#storage_selection').load('<%= url_for :controller => "storage", :action => "show" %>', > - { id: parseInt(selected_ids[0].substring(3))}); > - } > + $('#storage_tree_form ul.ovirt-tree li div').removeClass('current'); > + $(elem) > + .addClass('current'); > + $('#storage_selection').load('<%= url_for :controller => "search", :action => "single_result" %>', > + { class_and_id: elem.id.substring(5)});As discussed in irc, let's switch any #s here to use indexOf(char) as the endpoint.> } > > </script> > <div class="panel_header"></div> > <% if @pool.storage_pools.size != 0 %> > <div class="data_section"> > - <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", > - :hwpool => @pool, > - :exclude_pool => nil, > - :on_select => "storage_select", > - :is_popup => false} %> > + <div style="overflow:auto; border:#CCCCCC solid 1px;">Please extract this style into a class> + <form id="storage_tree_form"> > + <ul id="storage_tree" class="ovirt-tree"></ul> > + </form> > + </div> > </div> > > <div class="selection_detail" id="storage_selection"> > diff --git a/src/app/views/smart_pools/show_storage.rhtml b/src/app/views/smart_pools/show_storage.rhtml > index 7cf425a..9a9b78e 100644 > --- a/src/app/views/smart_pools/show_storage.rhtml > +++ b/src/app/views/smart_pools/show_storage.rhtml > @@ -5,10 +5,44 @@ > </ul> > </div> > > +<textarea id="tree_template" style="display:none;"> > +{macro htmlList(list, isFullList)} > + {if isFullList} > + <ul style="display:none;"> > + {/if} > + {for item in list} > + <li> > + <span class="hitarea {if item.children.length > 0} expandable{/if}"> </span> > + <div id="tree-${item.type}_${item.id}"> > + <input class="grid_checkbox" type="checkbox" > + name="grid_checkbox${item.type}_${item.id}" > + value="${item.id}" > + {if !item.is_pool}disabled="disabled" style="display:none"{/if} > + {if item.selected}checked="checked"{/if}/> ${item.name} {if item.size}(${item.size} GB){/if} > + </div> > + {if item.children.length > 0} > + ${htmlList(item.children, true)} > + {/if} > + </li> > + {/for} > + {if isFullList} > + </ul> > + {/if} > +{/macro} > + > +${htmlList(pools)} > +</textarea> > + > <script type="text/javascript"> > + $(document).ready(function(){ > + $('#smart_storage_tree').tree({ > + content: {"pools" : <%= @storage_tree%>}, > + clickHandler: smart_storage_select > + }); > + }); > function get_selected_storage_for_smart_pool() > { > - return get_selected_checkboxes("smart_storage_grid_form"); > + return get_selected_checkboxes("smart_storage_tree_form"); > } > function remove_storage_from_smart_pool() > { > @@ -27,29 +61,24 @@ > }, 'json'); > } > } > - function smart_storage_select(selected_rows) > + function smart_storage_select(e, elem) > { > - 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))}); > - } > + $('#smart_storage_tree_form ul.ovirt-tree li div').removeClass('current'); > + $(elem) > + .addClass('current'); > + $('#smart_storage_selection').load('<%= url_for :controller => "search", :action => "single_result" %>', > + { class_and_id: elem.id.substring(5)});Switch to indexOf, same as above> } > > </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 style="overflow:auto; border:#CCCCCC solid 1px;">css class> + <form id="smart_storage_tree_form"> > + <ul id="smart_storage_tree" class="ovirt-tree"></ul> > + </form> > + </div> > </div> > > <div class="selection_detail" id="smart_storage_selection"> > diff --git a/src/app/views/storage/show.rhtml b/src/app/views/storage/show.rhtml > index 123cf20..a4cc1c2 100644 > --- a/src/app/views/storage/show.rhtml > +++ b/src/app/views/storage/show.rhtml > @@ -40,51 +40,11 @@ > <%=h @storage_pool.state %><br/> > </div> > <%- content_for :right do -%> > - <div class="selection_right_title">Volumes</div> > -<!-- hide for now > - <ul class="selection_tab_nav"> > - <li><a href="#"><%=image_tag "icon_selection_add.gif", :style=>"vertical-align:middle;" %>Add</a></li> > - <li><a href="#"><%=image_tag "icon_selection_showdetail.gif", :style=>"vertical-align:middle;" %>Show Detail</a></li> > - <li><a href="#"><%=image_tag "icon_selection_remove.gif", :style=>"vertical-align:middle;" %>Remove</a></li> > - </ul> > ---> > - <div class="selection_right_table"> > - <table id="storage_volumes_grid" style="display:none"></table> > - </div> > > <%- end -%> > > <%= confirmation_dialog("confirm_delete_storage", "Are you sure?", "delete_storage_pool()") %> > <script type="text/javascript"> > - $("#storage_volumes_grid").flexigrid > - ( > - { > - url: '<%= url_for :action => "storage_volumes_json", :id => @storage_pool.id %>', > - dataType: 'json', > - colModel : [ > - <%= "{display: '', width : 20, align: 'left', process: storage_volumes_gridcheckbox}," if (@storage_pool.user_subdividable and @can_modify) %> > - {display: 'Alias', width : 180, sortable : false, align: 'left', process: storage_volume_details_link}, > - {display: 'Size (Gb)', name : 'size', width : 80, sortable : true, align: 'left'}, > - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} > - ], > - sortname: "size", > - sortorder: "desc", > - usepager: false, > - useRp: true, > - rp: 40, > - showTableToggleBtn: true, > - } > - ); > - function storage_volumes_gridcheckbox(celDiv) > - { > - $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); > - } > - function storage_volume_details_link(celDiv,pid) > - { > - $(celDiv).html('<a href="<%= url_for :controller => 'storage', :action => 'show_volume' %>/'+ pid +'" rel="facebox[.bolder]">' + $(celDiv).html() + '</a>'); > - } > -</script> > -<script type="text/javascript"> > > function refresh_storage_pool() > { > diff --git a/src/app/views/storage/show_volume.rhtml b/src/app/views/storage/show_volume.rhtml > index c1cb66a..c1138f4 100644 > --- a/src/app/views/storage/show_volume.rhtml > +++ b/src/app/views/storage/show_volume.rhtml > @@ -1,26 +1,27 @@ > <%- content_for :title do -%> > <%=h @storage_volume.display_name %> > <%- end -%> > -<%- content_for :description do -%> > - Details for Storage Volume <%=h @storage_volume.display_name %> > + > +<%- content_for :action_links do -%> > + <%if @can_modify -%> > + <%if @storage_volume.supports_lvm_subdivision and @storage_volume.vms.empty? -%> > + <%= link_to image_tag("icon_addstorage.png") + " Add new Volume", > + {:controller => 'storage', :action => 'new_lvm_volume', :source_volume_id => @storage_volume.id}, > + :rel=>"facebox[.bolder]", :class=>"selection_facebox" %> > + <% end %> > + <%if @storage_volume.deletable -%> > + <a href="#confirm_delete" rel="facebox[.bolder]"> > + <%= image_tag "icon_x.png" %> Delete > + </a> > + <%- end -%> > + <%- end -%> > <%- end -%> > +<%= confirmation_dialog("confirm_delete", "Are you sure?", "delete_volume()") %> > > -<% if @storage_volume.supports_lvm_subdivision %> > - <div id="dialog-content-area"> > - <div id="toolbar_nav"> > - <ul> > - <li><a href="#" id="new_lvm_volume_button"><%=image_tag "icon_addstorage.png", :style=>"vertical-align:middle;" %>Add</a></li> > - <% if (@storage_volume.lvm_storage_pool and > - !@storage_volume.lvm_storage_pool.storage_volumes.empty?) %> > - <li><a href="#" onClick="return remove_lvm_volumes();"><%=image_tag "icon_remove.png" %> Remove</a></li> > - <% end %> > - </ul> > - </div> > - </div> > -<% end %> > -<div class="panel_header"></div> > <div class="selection_key"> > - IP address:<br/> > + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> > + IP address:<br/> > + <% end %> > <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> > Port:<br/> > Target:<br/> > @@ -34,12 +35,18 @@ > LUN:<br/> > <% elsif @storage_volume[:type] == "NfsStorageVolume" %> > Filename:<br/> > + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> > + Volume Group:<br/> > + Logical Volume:<br/> > + Permissions (owner/group/mode):<br/> > <% end %> > Size:<br/> > </div> > <div class="selection_value"> > - <%=h @storage_volume.storage_pool.ip_addr %><br/> > - <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> > + <% unless @storage_volume.storage_pool[:type] == "LvmStoragePool" %> > + <%=h @storage_volume.storage_pool.ip_addr %><br/> > + <% end %> > + <% if @storage_volume.storage_pool[:type] == "IscsiStoragePool" %> > <%=h @storage_volume.storage_pool.port %><br/> > <%=h @storage_volume.storage_pool[:target] %><br/> > <% elsif @storage_volume.storage_pool[:type] == "NfsStoragePool" %> > @@ -52,74 +59,30 @@ > <%=h @storage_volume.lun %><br/> > <% elsif @storage_volume[:type] == "NfsStorageVolume" %> > <%=h @storage_volume.filename %><br/> > + <% elsif @storage_volume[:type] == "LvmStorageVolume" %> > + <%=h @storage_volume.storage_pool.vg_name %><br/> > + <%=h @storage_volume.lv_name %><br/> > + <%=h @storage_volume.lv_owner_perms %>/<%=h @storage_volume.lv_group_perms %>/<%=h @storage_volume.lv_mode_perms %><br/> > <% end %> > <%=h @storage_volume.size_in_gb %> GB<br/> > </div> > -<% if @storage_volume.supports_lvm_subdivision %> > - <div class="dialog_form"> > - <div class="form_heading">LVM Volumes</div> > - <% if @storage_volume.lvm_storage_pool %> > - <form id="lvm_storage_volumes_grid_form"> > - <table id="lvm_storage_volumes_grid" style="display:none"></table> > - </form> > - <% end %> > - </div> > -<% end %> > +<%- content_for :right do -%> > + > +<%- end -%> > > -<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')">Close</a></div> > - <div class="button_right_grey"></div> > - </div> > -</div> > <script type="text/javascript"> > - $("#lvm_storage_volumes_grid").flexigrid > - ( > - { > - url: '<%= url_for :action => "storage_volumes_json", :id => @storage_volume.lvm_storage_pool.id %>', > - dataType: 'json', > - colModel : [ > - <%= "{display: '', width : 20, align: 'left', process: lvm_storage_volumes_gridcheckbox}," if @can_modify %> > - {display: 'Alias', width : 180, sortable : false, align: 'left'}, > - {display: 'Size (Gb)', name : 'size', width : 80, sortable : true, align: 'left'}, > - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} > - ], > - sortname: "size", > - sortorder: "desc", > - usepager: false, > - useRp: true, > - rp: 40, > - showTableToggleBtn: true, > - } > - ); > - function lvm_storage_volumes_gridcheckbox(celDiv) > - { > - $(celDiv).html('<input class="grid_checkbox" type="checkbox" name="grid_checkbox'+$(celDiv).html()+'" value="'+$(celDiv).html()+'"/>'); > - } > - function get_selected_lvm_volumes() > - { > - return get_selected_checkboxes("lvm_storage_volumes_grid_form"); > - } > - function remove_lvm_volumes() > + function delete_volume() > { > - var volumes = get_selected_lvm_volumes(); > - if (validate_selected(volumes, "storage volume")) { > - $.post('<%= url_for :controller => "storage", :action => "delete_volumes" %>', > - { storage_volume_ids: volumes.toString() }, > - function(data,status){ > - $("#lvm_storage_volumes_grid").flexReload(); > - if (data.alert) { > - $.jGrowl(data.alert); > - } > - }, 'json'); > - } > + $(document).trigger('close.facebox'); > + $.post('<%= url_for :controller => "storage", :action => "delete_volumes" %>', > + { storage_volume_ids: <%= @storage_volume.id %> }, > + function(data,status) { > + // FIXME: reload tree > + //$("#vms_grid").flexReload();I don't think we really need to keep this line ^^> + if (data.alert) { > + $.jGrowl(data.alert); > + } > + empty_summary('storage_selection', 'Storage Pool or Volume'); > + }, 'json'); > } > -$('#new_lvm_volume_button').click(function(){ > - $('#window').fadeOut('fast'); > - $("#window").empty().load("<%= url_for :controller => 'storage', :action => 'new_lvm_volume' %>", > - { source_volume_id: <%=@storage_volume.id%>, > - return_facebox: '<%= url_for :controller => 'storage', :action => 'show_volume', :id => @storage_volume.id %>' }); > - $('#window').fadeIn('fast'); > -}); > </script> > diff --git a/src/public/javascripts/ovirt.js b/src/public/javascripts/ovirt.js > index d84b3d9..e0e3dc8 100644 > --- a/src/public/javascripts/ovirt.js > +++ b/src/public/javascripts/ovirt.js > @@ -62,6 +62,7 @@ function add_storage(url) > { resource_ids: storage.toString() }, > function(data,status){; > $(document).trigger('close.facebox'); > + // FIXME: this always reloads the tab for now > grid = $("#storage_grid"); > if (grid.size()>0 && grid != null) { > grid.flexReload(); > @@ -256,7 +257,7 @@ function empty_summary(element_id, label){ > > function get_selected_storage() > { > - return get_selected_checkboxes("storage_grid_form"); > + return get_selected_checkboxes("storage_tree_form"); > } > function validate_storage_for_move() > {