mirror of
https://github.com/Evolix/chexpire.git
synced 2024-04-27 14:30:49 +02:00
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 'octicons'
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
|
gem 'has_scope'
|
||||||
|
|
||||||
# Reduces boot times through caching; required in config/boot.rb
|
# Reduces boot times through caching; required in config/boot.rb
|
||||||
gem 'bootsnap', '>= 1.1.0', require: false
|
gem 'bootsnap', '>= 1.1.0', require: false
|
||||||
|
|
|
@ -131,6 +131,9 @@ GEM
|
||||||
guard-minitest (2.4.6)
|
guard-minitest (2.4.6)
|
||||||
guard-compat (~> 1.2)
|
guard-compat (~> 1.2)
|
||||||
minitest (>= 3.0)
|
minitest (>= 3.0)
|
||||||
|
has_scope (0.7.2)
|
||||||
|
actionpack (>= 4.1)
|
||||||
|
activesupport (>= 4.1)
|
||||||
i18n (1.0.1)
|
i18n (1.0.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
io-like (0.3.0)
|
io-like (0.3.0)
|
||||||
|
@ -350,6 +353,7 @@ DEPENDENCIES
|
||||||
factory_bot_rails
|
factory_bot_rails
|
||||||
guard
|
guard
|
||||||
guard-minitest
|
guard-minitest
|
||||||
|
has_scope
|
||||||
jbuilder (~> 2.5)
|
jbuilder (~> 2.5)
|
||||||
kaminari
|
kaminari
|
||||||
launchy
|
launchy
|
||||||
|
|
|
@ -4,8 +4,11 @@ class ChecksController < ApplicationController
|
||||||
after_action :verify_authorized, except: :index
|
after_action :verify_authorized, except: :index
|
||||||
after_action :verify_policy_scoped, only: :index
|
after_action :verify_policy_scoped, only: :index
|
||||||
|
|
||||||
|
has_scope :kind
|
||||||
|
has_scope :by_domain
|
||||||
|
|
||||||
def index
|
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
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@ -79,4 +82,22 @@ class ChecksController < ApplicationController
|
||||||
def build_empty_notification
|
def build_empty_notification
|
||||||
@check.notifications.build
|
@check.notifications.build
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -11,4 +11,22 @@ module ChecksHelper
|
||||||
return "table-danger" if expiry_date <= 2.weeks.from_now
|
return "table-danger" if expiry_date <= 2.weeks.from_now
|
||||||
return "table-warning" if expiry_date <= 30.days.from_now
|
return "table-warning" if expiry_date <= 30.days.from_now
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -58,6 +58,13 @@ class Check < ApplicationRecord
|
||||||
OR (last_success_at <= DATE_SUB(last_run_at, INTERVAL 5 MINUTE))")
|
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
|
private
|
||||||
|
|
||||||
def domain_created_at_past
|
def domain_created_at_past
|
||||||
|
|
|
@ -3,9 +3,15 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
<th scope="col">Domain</th>
|
<th scope="col">
|
||||||
<th scope="col">Expiry date</th>
|
<%= t(".domain") %>
|
||||||
<th scope="col">Edit</th>
|
<%== 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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-lg-10">
|
<div class="col-12 col-lg-10">
|
||||||
<% if @checks.empty? %>
|
<% if @checks.empty? && current_scopes.blank? %>
|
||||||
<div class="alert alert-info">
|
<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)) %>
|
<%= t(".no_check_yet_html", new_domain_path: new_check_path(kind: :domain), new_ssl_path: new_check_path(kind: :ssl)) %>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<h1><%= t(".title") %></h1>
|
<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 %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
7
test/controllers/.rubocop.yml
Normal file
7
test/controllers/.rubocop.yml
Normal file
|
@ -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)
|
get new_check_path(kind: :invalid)
|
||||||
assert_response :not_found
|
assert_response :not_found
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue