mirror of https://github.com/Evolix/chexpire.git
Checks list: filters & sort
This commit is contained in:
parent
a8ff639257
commit
380960fa75
1
Gemfile
1
Gemfile
|
@ -43,6 +43,7 @@ gem 'whenever', require: false
|
|||
|
||||
gem 'octicons'
|
||||
gem 'kaminari'
|
||||
gem 'has_scope'
|
||||
|
||||
# Reduces boot times through caching; required in config/boot.rb
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
|
|
|
@ -131,6 +131,9 @@ GEM
|
|||
guard-minitest (2.4.6)
|
||||
guard-compat (~> 1.2)
|
||||
minitest (>= 3.0)
|
||||
has_scope (0.7.2)
|
||||
actionpack (>= 4.1)
|
||||
activesupport (>= 4.1)
|
||||
i18n (1.0.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-like (0.3.0)
|
||||
|
@ -350,6 +353,7 @@ DEPENDENCIES
|
|||
factory_bot_rails
|
||||
guard
|
||||
guard-minitest
|
||||
has_scope
|
||||
jbuilder (~> 2.5)
|
||||
kaminari
|
||||
launchy
|
||||
|
|
|
@ -4,8 +4,11 @@ class ChecksController < ApplicationController
|
|||
after_action :verify_authorized, except: :index
|
||||
after_action :verify_policy_scoped, only: :index
|
||||
|
||||
has_scope :kind
|
||||
has_scope :by_domain
|
||||
|
||||
def index
|
||||
@checks = policy_scope(Check).order(:domain_expires_at).page(params[:page])
|
||||
@checks = apply_scopes(policy_scope(Check)).order(current_sort).page(params[:page])
|
||||
end
|
||||
|
||||
def new
|
||||
|
@ -79,4 +82,22 @@ class ChecksController < ApplicationController
|
|||
def build_empty_notification
|
||||
@check.notifications.build
|
||||
end
|
||||
|
||||
def current_sort
|
||||
@current_sort ||= clean_sort || Check.default_sort
|
||||
end
|
||||
helper_method :current_sort
|
||||
|
||||
def clean_sort
|
||||
return unless params[:sort].present?
|
||||
field, _, direction = params[:sort].rpartition("_").map(&:to_sym)
|
||||
|
||||
valid_fields = [:domain, :domain_expires_at]
|
||||
valid_directions = [:asc, :desc]
|
||||
|
||||
return unless valid_fields.include?(field)
|
||||
return unless valid_directions.include?(direction)
|
||||
|
||||
{ field => direction }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,4 +11,22 @@ module ChecksHelper
|
|||
return "table-danger" if expiry_date <= 2.weeks.from_now
|
||||
return "table-warning" if expiry_date <= 30.days.from_now
|
||||
end
|
||||
|
||||
def checks_sort_links(field)
|
||||
current_sort_str = current_sort.to_a.join("_")
|
||||
|
||||
%i[asc desc].map { |direction|
|
||||
sort = "#{field}_#{direction}"
|
||||
|
||||
icon = direction == :asc ? "chevron-up" : "chevron-down"
|
||||
html = Octicons::Octicon.new(icon).to_svg.html_safe
|
||||
|
||||
filter_params = current_criterias.merge(sort: sort)
|
||||
link_to_unless sort == current_sort_str, html, checks_path(filter_params)
|
||||
}.join
|
||||
end
|
||||
|
||||
def current_criterias
|
||||
current_scopes.merge(sort: params[:sort])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,6 +58,13 @@ class Check < ApplicationRecord
|
|||
OR (last_success_at <= DATE_SUB(last_run_at, INTERVAL 5 MINUTE))")
|
||||
}
|
||||
|
||||
scope :kind, ->(kind) { where(kind: kind) }
|
||||
scope :by_domain, ->(domain) { where("domain LIKE ?", "%#{domain}%") }
|
||||
|
||||
def self.default_sort
|
||||
{ domain_expires_at: :asc }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def domain_created_at_past
|
||||
|
|
|
@ -3,9 +3,15 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">Domain</th>
|
||||
<th scope="col">Expiry date</th>
|
||||
<th scope="col">Edit</th>
|
||||
<th scope="col">
|
||||
<%= t(".domain") %>
|
||||
<%== checks_sort_links(:domain) %>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<%= t(".expiry_date") %>
|
||||
<%== checks_sort_links(:domain_expires_at) %>
|
||||
</th>
|
||||
<th scope="col"><%= t(".edit") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-lg-10">
|
||||
<% if @checks.empty? %>
|
||||
<% if @checks.empty? && current_scopes.blank? %>
|
||||
<div class="alert alert-info">
|
||||
<%= t(".no_check_yet_html", new_domain_path: new_check_path(kind: :domain), new_ssl_path: new_check_path(kind: :ssl)) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h1><%= t(".title") %></h1>
|
||||
<%= render "table", checks: @checks %>
|
||||
<%= link_to("Domains", checks_path(current_criterias.merge(kind: :domain))) %>
|
||||
<%= link_to("SSL", checks_path(current_criterias.merge(kind: :ssl))) %>
|
||||
<%= form_tag(checks_path(current_scopes), method: :get) do %>
|
||||
<%= search_field_tag :by_domain, current_scopes[:by_domain] %>
|
||||
<%= button_tag t(".filter") %>
|
||||
<% end %>
|
||||
|
||||
<% if @checks.any? %>
|
||||
<%= render "table", checks: @checks %>
|
||||
<% else %>
|
||||
<div class="alert alert-warning"><%= t(".no_matching_check") %></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
inherit_from: ../../.rubocop.yml
|
||||
|
||||
Metrics/ClassLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/BlockLength:
|
||||
Enabled: false
|
|
@ -31,4 +31,112 @@ class ChecksControllerTest < ActionDispatch::IntegrationTest
|
|||
get new_check_path(kind: :invalid)
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
test "checks are ordered by default by expiry date sort" do
|
||||
c1 = create(:check, user: @user, domain_expires_at: 20.days.from_now)
|
||||
c2 = create(:check, user: @user, domain_expires_at: 10.days.from_now)
|
||||
c3 = create(:check, user: @user, domain_expires_at: 1.day.from_now)
|
||||
|
||||
get checks_path
|
||||
assert_equal [c3, c2, c1], current_checks
|
||||
end
|
||||
|
||||
test "checks are ordered by expiry date asc" do
|
||||
c1 = create(:check, user: @user, domain_expires_at: 20.days.from_now)
|
||||
c2 = create(:check, user: @user, domain_expires_at: 10.days.from_now)
|
||||
c3 = create(:check, user: @user, domain_expires_at: 1.day.from_now)
|
||||
|
||||
get checks_path(sort: :domain_expires_at_asc)
|
||||
assert_equal [c3, c2, c1], current_checks
|
||||
end
|
||||
|
||||
test "checks are ordered by reverse expiring date" do
|
||||
c1 = create(:check, user: @user, domain_expires_at: 1.day.from_now)
|
||||
c2 = create(:check, user: @user, domain_expires_at: 10.days.from_now)
|
||||
c3 = create(:check, user: @user, domain_expires_at: 20.days.from_now)
|
||||
|
||||
get checks_path(sort: :domain_expires_at_desc)
|
||||
assert_equal [c3, c2, c1], current_checks
|
||||
end
|
||||
|
||||
test "checks are ordered by domain name asc" do
|
||||
c1 = create(:check, user: @user, domain: "a")
|
||||
c2 = create(:check, user: @user, domain: "b")
|
||||
c3 = create(:check, user: @user, domain: "c")
|
||||
|
||||
get checks_path(sort: :domain_asc)
|
||||
assert_equal [c1, c2, c3], current_checks
|
||||
end
|
||||
|
||||
test "checks are ordered by domain name desc" do
|
||||
c1 = create(:check, user: @user, domain: "a")
|
||||
c2 = create(:check, user: @user, domain: "b")
|
||||
c3 = create(:check, user: @user, domain: "c")
|
||||
|
||||
get checks_path(sort: :domain_desc)
|
||||
assert_equal [c3, c2, c1], current_checks
|
||||
end
|
||||
|
||||
test "invalid sort fallback to default sort" do
|
||||
c1 = create(:check, user: @user, domain_expires_at: 20.days.from_now)
|
||||
c2 = create(:check, user: @user, domain_expires_at: 10.days.from_now)
|
||||
c3 = create(:check, user: @user, domain_expires_at: 1.day.from_now)
|
||||
|
||||
get checks_path(sort: :invalid_sort_asc)
|
||||
assert_equal [c3, c2, c1], current_checks
|
||||
end
|
||||
|
||||
test "checks are filtered by domain kind" do
|
||||
c1 = create(:check, :domain, user: @user)
|
||||
c2 = create(:check, :domain, user: @user)
|
||||
create(:check, :ssl, user: @user)
|
||||
|
||||
get checks_path(kind: :domain)
|
||||
assert_equal [c1, c2], current_checks
|
||||
end
|
||||
|
||||
test "checks are filtered by ssl kind" do
|
||||
create(:check, :domain, user: @user)
|
||||
create(:check, :domain, user: @user)
|
||||
c3 = create(:check, :ssl, user: @user)
|
||||
|
||||
get checks_path(kind: :ssl)
|
||||
assert_equal [c3], current_checks
|
||||
end
|
||||
|
||||
test "checks are filtered by domain name" do
|
||||
c1 = create(:check, user: @user, domain: "abc")
|
||||
c2 = create(:check, user: @user, domain: "bcde")
|
||||
create(:check, user: @user, domain: "hijk")
|
||||
|
||||
get checks_path(by_domain: "bc")
|
||||
assert_equal [c1, c2], current_checks
|
||||
|
||||
get checks_path(by_domain: "klm")
|
||||
assert_empty current_checks
|
||||
end
|
||||
|
||||
test "checks are paginated" do
|
||||
create_list(:check, 40, user: @user)
|
||||
|
||||
get checks_path
|
||||
assert_equal 1, current_checks.current_page
|
||||
first_page = current_checks
|
||||
|
||||
get checks_path(page: 2)
|
||||
assert_equal 2, current_checks.current_page
|
||||
assert_not_equal first_page, current_checks
|
||||
end
|
||||
|
||||
test "checks are scoped to current user" do
|
||||
c1 = create(:check, user: @user)
|
||||
create(:check)
|
||||
|
||||
get checks_path
|
||||
assert_equal [c1], current_checks
|
||||
end
|
||||
|
||||
def current_checks
|
||||
@controller.instance_variable_get("@checks")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue