New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #16043 - add 'select all hosts' option into hosts page #4338
Conversation
@amirfefer, thanks for your PR! By analyzing the history of the files in this pull request, we identified @shlomizadok, @tbrisker and @ohadlevy to be potential reviewers. |
@@ -1,4 +1,6 @@ | |||
<div class="row"> | |||
<%= alert(:class => 'alert-info hide', :close => true, :header => '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this should be warning? @Rohoover ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ohadlevy For which part? The selection of all items or that all items are changing owners?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm looking for a way to say that you are seeing only the first 20 but you actually selected all of them, so if you take an action against them its the entire list not just he one you see (same workflow if you select all of your emails on gmail).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually like the way it's address in the gif. I don't think it should be a warning as nothing "wrong" happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few comments inline. Seeing the amount of changes to host_checkbox.js.erb, I wonder if it makes sense to just rewrite it in ES6? afaict the only reason for it to be an .erb is for the path to the spinner, which I think can be done with just a class anyways.
app/helpers/layout_helper.rb
Outdated
@@ -81,7 +81,7 @@ def page_entries_info(collection, options = {}) | |||
end | |||
|
|||
def will_paginate_with_info(collection = nil, options = {}) | |||
content_tag(:div, :id => "pagination", :class => "row") do | |||
content_tag(:div, :id => "pagination", :class => "row", 'data-meta-count' => collection.count) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use collection.total_entries
which caches to total count
app/controllers/hosts_controller.rb
Outdated
@@ -750,8 +750,9 @@ def load_vars_for_ajax | |||
|
|||
def find_multiple | |||
# Lets search by name or id and make sure one of them exists first | |||
if params[:host_names].present? || params[:host_ids].present? | |||
@hosts = resource_base.where("hosts.id IN (?) or hosts.name IN (?)", params[:host_ids], params[:host_names]) | |||
if params[:host_names].present? || params[:host_ids].present? || params.key?(:search) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mind turning all of these to .key?
?
$("#confirmation-modal form").submit(); | ||
$('#confirmation-modal').modal('hide'); | ||
} | ||
|
||
function build_modal(element, url) { | ||
var url = url + "?" + $.param({host_ids: $.foremanSelectedHosts}); | ||
if ($("#multiple-chosen").data('multiple')) { | ||
var query = $("<input>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to create an input here if the value is encoded directly to the query?
var query = $("<input>") | ||
.attr("type", "hidden") | ||
.attr("name", "search").val($("#search").val()); | ||
$("#confirmation-modal form").append($(query)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to wrap query
here, it is already a jquery object
rmHostId(cid); | ||
if ($(".alert").length){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might this be a different alert?
thanks @tbrisker for your review, I've followed your comments. |
In general this works well, however there is an issue when selecting a very large amount of hosts - loading the modal with the host list can take several minutes as it isn't paginated. |
Use the grey box if the action isn't particular serious. If it has strong consequences use the warning (orange) box. Remove the chevrons in both. It would be nice to have (but not required) if the messaging would read" Reminder: All 10 hosts are selected for query filter architecture=..." because the important part is not what query they searched but that they have them all selected. |
@Rohoover Thanks 👍 . I've kept the grey box, and changed the bold string. otherwise the user would think he made something wrong. The chevron mark notes that the string is translatable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting there, a few mostly minor inline comments.
<table class="<%= table_css_classes %>"> | ||
<thead> | ||
<%= alert(:class => 'alert-info hide', :id => 'multiple-modal-alert', :close => true, :header => '', | ||
:text => _("Reminder: <strong> All #{hosts.count.to_s} hosts are selected </strong> for query filter #{multiple_filter}").html_safe) %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app/helpers/layout_helper.rb
Outdated
@@ -81,7 +81,7 @@ def page_entries_info(collection, options = {}) | |||
end | |||
|
|||
def will_paginate_with_info(collection = nil, options = {}) | |||
content_tag(:div, :id => "pagination", :class => "row") do | |||
content_tag(:div, :id => "pagination", :class => "row", 'data-meta-count' => collection.total_entries) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also have a meta tag on the host list for number per page, it makes sense to me to use the same here as well using a <meta name="totalResults" content="#{collection.total_entries}"/>
tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tbrisker @amirfefer meta attribute was remove at ee7002f#diff-7eb571b855131f643240b7b93ddfd44dL4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the use of meta attribute, instead I've expanded will_paginate_with_info
with include_data_tag
flag.
app/views/hosts/index.html.erb
Outdated
@@ -1,2 +1,4 @@ | |||
<% title_actions multiple_actions_select, button_group(new_link(_("Create Host"))) %> | |||
<%= alert(:class => 'alert-info hide', :id => 'multiple-alert', :close => false, :header => '', | |||
:text => _("All #{Setting[:entries_per_page]} hosts on this page are selected. ").html_safe + link_to_function((_("Select all <b> #{@hosts.count.to_s} </b> hosts")).html_safe, "multiple_selection()")) %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also use the cached @hosts.total_entries
instead of @hosts.count
.
</tbody> | ||
</table> | ||
<%= check_box_tag "keep_selected", "", false, :title => _("Keep selected hosts for a future action") %> | ||
<%= _('Keep selected hosts for a future action') %><br/><br/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be possible also when selecting all? (i.e. outside the if block)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've thought at the beginning that it useless due to cookie implementation , but I've managed not to expand this cookie 😄
@@ -750,8 +761,9 @@ def load_vars_for_ajax | |||
|
|||
def find_multiple | |||
# Lets search by name or id and make sure one of them exists first | |||
if params[:host_names].present? || params[:host_ids].present? | |||
@hosts = resource_base.where("hosts.id IN (?) or hosts.name IN (?)", params[:host_ids], params[:host_names]) | |||
if params.key?(:host_names) || params.key?(:host_ids) || multiple_with_filter? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder - do we actually ever call this method with a host_names
parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found anything using host names
in params...
app/controllers/hosts_controller.rb
Outdated
if multiple_with_filter? | ||
params[:search].blank? ? _("Empty") : params[:search] | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should go in the helper instead of the controller.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
host_helper
is too large, hence I've extract this logic into hosts_and_hostgroup_helper
assert_equal users(:one).id_and_type, @host1.reload.is_owned_by | ||
assert_equal users(:one).id_and_type, @host2.reload.is_owned_by | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test that has an actual search query and make sure only the matching hosts are selected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added two additional tests
var count = $("#pagination").data("meta-count"); | ||
var per_page = $("meta[name='itemsPerPage']").attr("content"); | ||
var alert_text = Jed.sprintf(__("All %s hosts on this page are selected. "), per_page); | ||
var select_text = Jed.sprintf(__("Select all") + "<b> %s </b>" + __("hosts"), count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't translate correctly in all languages as the strings Select all
and hosts
will be translated separately and not as one sentence. Also above on line 96.
@tbrisker I've fixed most of your inline comments, I've left some inline comments. |
@tbrisker IMO the cookie is the problem here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
end | ||
|
||
def per_page(collection) | ||
collection.total_entries > Setting[:entries_per_page] ? Setting[:entries_per_page] : collection.total_entries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be in layout helper?
also, how about [Setting[:entries_per_page], collection.total_entries].min
?
|
||
function undo_multiple_selection(){ | ||
var count = $("#pagination").data("count"); | ||
var per_page = $("#pagination").data("per-page"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please cache $("#pagination")
to save dom lookups
var per_page = $("#pagination").data("per-page"); | ||
var alert_text = Jed.sprintf(__("All %s hosts on this page are selected. "), per_page); | ||
var select_text = Jed.sprintf(__("Select all<b> %s </b> hosts"), count); | ||
$(".text").html('<span id="multiple-chosen">' + alert_text + '<a href="#" onclick="multiple_selection();">' + select_text + '</a></span>'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't .text
a bit of a generic selector?
function toggleCheck() { | ||
var checked = $("#check_all").is(':checked'); | ||
$('.host_select_boxes').each(function(index, box) { | ||
box.checked = checked; | ||
hostChecked(box); | ||
}); | ||
if(!checked) | ||
var per_page = $("#pagination").data("per-page"); | ||
var total_host = $("#pagination").data("count"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
@tbrisker : From your screenshot It looks like the top number is presented correctly while the bottom does not. I've fixed the rest. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few more comments, please also note related tests seem to be failing intermittently.
@@ -56,6 +61,8 @@ function toggle_actions() { | |||
|
|||
// setups checkbox values upon document load | |||
$(function() { | |||
$.count = $("#pagination").data("count"); | |||
$.per_page = $("#pagination").data("per-page"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you adding these to the jQuery object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also please cache $("#pagination")
rmHostId(cid); | ||
if ($("#multiple-alert").length){ | ||
$("#multiple-alert").hide('slow'); | ||
$("#multiple-alert").data('multiple', false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$("#multiple-alert")
should be cached to reduce lookups
} | ||
else if (!checked) { | ||
$("#multiple-alert").hide('slow'); | ||
$("#multiple-alert").data('multiple', false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please cache these too
@tbrisker , thanks, I've added caching to reduce lookups. |
@amirfefer Following our talk, looks like you didn't push an updated version with correct caching for jquery objects? |
@tbrisker , You're right, now you can see caching for jquery objects |
Thanks @amirfefer ! I'd be happy to see all of this code rewritten in es6 or react, could you please open a refactor issue for that? |
Select all items
checkbox in hosts page selects only the hosts within the page. when the user wish to select all hosts for a bulk action, he has to select all hosts page after page.