tb_core 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +34 -2
- data/app/assets/javascripts/admin/core/dashboard.js +19 -16
- data/app/assets/libs/sortable/sortable.js +1481 -0
- data/app/controllers/admin/application_controller.rb +2 -1
- data/app/controllers/admin/users_controller.rb +5 -1
- data/app/controllers/concerns/tb_core/error_handling.rb +49 -0
- data/app/controllers/concerns/tb_core/redirection.rb +23 -0
- data/app/controllers/concerns/tb_core/sortable_params.rb +80 -0
- data/app/controllers/concerns/tb_core/user_authentication.rb +57 -0
- data/app/controllers/spud/application_controller.rb +8 -136
- data/app/controllers/tb_core/application_controller.rb +16 -0
- data/app/helpers/admin/application_helper.rb +3 -1
- data/app/helpers/tb_core/application_helper.rb +32 -0
- data/app/views/admin/users/index.html.erb +6 -6
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +1 -1
- data/lib/generators/spud/templates/application_controller.rb +1 -1
- data/lib/spud_core/engine.rb +1 -1
- data/lib/spud_core/version.rb +1 -1
- data/lib/tb_core/form_builder.rb +1 -1
- data/lib/tb_core/table_header.rb +92 -0
- data/spec/controllers/admin/application_controller_spec.rb +1 -1
- data/spec/controllers/{spud → tb_core}/application_controller_spec.rb +1 -1
- data/spec/controllers/tb_core/sortable_params_spec.rb +64 -0
- data/spec/dummy/app/controllers/application_controller.rb +1 -1
- data/spec/helpers/tb_core/application_helper_spec.rb +39 -0
- data/spec/rails_helper.rb +3 -4
- data/spec/spec_helper.rb +2 -0
- metadata +18 -11
- data/app/assets/javascripts/admin/core/jquery_ui.js +0 -22
- data/app/assets/stylesheets/admin/core/jquery_ui.scss +0 -19
- data/app/controllers/spud/admin/application_controller.rb +0 -12
- data/app/helpers/spud/application_helper.rb +0 -36
@@ -7,8 +7,12 @@ class Admin::UsersController < Admin::ApplicationController
|
|
7
7
|
after_action :send_credentials_email, only: [:create, :update]
|
8
8
|
respond_to :html, :csv
|
9
9
|
|
10
|
+
sortable_by :email, :current_login_at,
|
11
|
+
name: [:last_name, :first_name],
|
12
|
+
default: :email
|
13
|
+
|
10
14
|
def index
|
11
|
-
@spud_users = SpudUser.
|
15
|
+
@spud_users = SpudUser.order(sortable_query).paginate(page: params[:page], per_page: 15)
|
12
16
|
if params[:search]
|
13
17
|
@spud_users = @spud_users.where_name_like(params[:search])
|
14
18
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module TbCore
|
2
|
+
module ErrorHandling
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
rescue_from Spud::RequestError, with: :handle_request_error
|
7
|
+
rescue_from ActiveRecord::RecordNotFound, with: :handle_record_not_found
|
8
|
+
rescue_from ActionController::UnknownFormat, with: :handle_unknown_format_error
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle_request_error(error)
|
12
|
+
error.request_url = request.original_url
|
13
|
+
error.template = template_for_request_error() if respond_to?(:template_for_request_error, true)
|
14
|
+
|
15
|
+
if error.is_a?(Spud::UnauthorizedError) && request.format.html?
|
16
|
+
redirect_to(login_path_for_require_user)
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
do_error_response(error)
|
21
|
+
end
|
22
|
+
|
23
|
+
def do_error_response(error)
|
24
|
+
respond_to do |format|
|
25
|
+
format.json { render json: { errors: error.message }, status: error.code }
|
26
|
+
format.xml { render xml: { errors: error.message }, status: error.code }
|
27
|
+
format.all do
|
28
|
+
@error = error
|
29
|
+
render template: error.template,
|
30
|
+
layout: nil,
|
31
|
+
formats: [:html],
|
32
|
+
status: error.code,
|
33
|
+
content_type: 'text/html'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_record_not_found(error)
|
39
|
+
error = Spud::NotFoundError.new('record')
|
40
|
+
handle_request_error(error)
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_unknown_format_error(error)
|
44
|
+
error = Spud::NotFoundError.new()
|
45
|
+
handle_request_error(error)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TbCore
|
2
|
+
module Redirection
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
helper_method :back_or_default
|
7
|
+
end
|
8
|
+
|
9
|
+
def redirect_back_or_default(default)
|
10
|
+
redirect_to(back_or_default(default))
|
11
|
+
end
|
12
|
+
|
13
|
+
def back_or_default(default = '/')
|
14
|
+
if params[:return_to]
|
15
|
+
uri = URI.parse(params[:return_to].to_s)
|
16
|
+
return "#{uri.path}?#{uri.query}" if uri.query
|
17
|
+
return uri.path
|
18
|
+
end
|
19
|
+
default
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module TbCore
|
2
|
+
module SortableParams
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
attr_accessor :default_sort_attribute
|
7
|
+
attr_accessor :sortable_mapping
|
8
|
+
|
9
|
+
# Define attributes you wish to sort by
|
10
|
+
#
|
11
|
+
# This optional configuration method tells the the sortable
|
12
|
+
# helpers how they should map attributes to queries. For
|
13
|
+
# example a "name" sort might need to sort on first and last
|
14
|
+
# name attributes
|
15
|
+
#
|
16
|
+
# The `default` argument, if passed, will determine the
|
17
|
+
# attribute used when no sort param has been passed
|
18
|
+
#
|
19
|
+
# Usage:
|
20
|
+
#
|
21
|
+
# sortable_by :email, name: [:last_name, :first_name]
|
22
|
+
# default: :email,
|
23
|
+
#
|
24
|
+
#
|
25
|
+
def sortable_by(*attributes, **options)
|
26
|
+
@default_sort_attribute = options.delete(:default)
|
27
|
+
@sortable_mapping = options.merge(attributes.map { |att| [att, att] }.to_h)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return the current sort direction
|
32
|
+
#
|
33
|
+
# Defaults to :asc for all values other than "desc"
|
34
|
+
#
|
35
|
+
def sort_direction
|
36
|
+
if params[:dir].present? && params[:dir] == 'desc'
|
37
|
+
:desc
|
38
|
+
else
|
39
|
+
:asc
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the current sort param
|
44
|
+
#
|
45
|
+
def sort_attribute
|
46
|
+
params[:sort].try(:to_sym) || self.class.default_sort_attribute
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a hash that can be used in an ActiveRecord order query
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
# MyModel.where(...).order(sortable_query).paginate(...)
|
53
|
+
#
|
54
|
+
def sortable_query
|
55
|
+
return unless sort_attribute
|
56
|
+
normalize_sort_value(
|
57
|
+
sort_attribute,
|
58
|
+
sort_direction
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Translate the sort_by and direction into a sortable hash
|
63
|
+
#
|
64
|
+
def normalize_sort_value(sort_by, direction)
|
65
|
+
mapping = self.class.sortable_mapping[sort_by]
|
66
|
+
if mapping.is_a? Symbol
|
67
|
+
{ mapping => sort_direction }
|
68
|
+
elsif mapping.is_a? String
|
69
|
+
mapping.gsub(':dir', sort_direction.to_s)
|
70
|
+
elsif mapping.is_a? Array
|
71
|
+
mapping.map { |att| [att, direction] }.to_h
|
72
|
+
elsif mapping.is_a? Proc
|
73
|
+
mapping.call(direction)
|
74
|
+
else
|
75
|
+
logger.debug("WARNING: Sort attribute '#{sort_by}' is not recognized. Did you mean to pass it to sortable_by?")
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module TbCore
|
2
|
+
module UserAuthentication
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
helper_method :current_user_session, :current_user, :current_user_id
|
7
|
+
before_action :check_requires_password_change
|
8
|
+
around_action :set_time_zone
|
9
|
+
end
|
10
|
+
|
11
|
+
def current_user_session
|
12
|
+
return @current_user_session if defined?(@current_user_session)
|
13
|
+
@current_user_session = SpudUserSession.find
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_user
|
17
|
+
return @current_user if defined?(@current_user)
|
18
|
+
@current_user = current_user_session && current_user_session.spud_user
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_user_id
|
22
|
+
return 0 unless @current_user
|
23
|
+
@current_user.id
|
24
|
+
end
|
25
|
+
|
26
|
+
def require_user
|
27
|
+
raise Spud::UnauthorizedError.new unless current_user
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def require_admin_user
|
32
|
+
raise Spud::UnauthorizedError.new unless current_user
|
33
|
+
raise Spud::AccessDeniedError.new unless current_user.has_admin_rights?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_requires_password_change
|
38
|
+
if current_user.present? && current_user.requires_password_change?
|
39
|
+
redirect_to(login_change_password_path(return_to: request.path))
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_time_zone
|
45
|
+
old_time_zone = Time.zone
|
46
|
+
Time.zone = current_user.time_zone if current_user && current_user.time_zone.present?
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
Time.zone = old_time_zone
|
50
|
+
end
|
51
|
+
|
52
|
+
def login_path_for_require_user
|
53
|
+
login_path(return_to: request.fullpath)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -1,138 +1,10 @@
|
|
1
|
-
class Spud::ApplicationController <
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
before_action :set_mailer_default_url
|
10
|
-
|
11
|
-
self.responder = TbCore::Responder
|
12
|
-
|
13
|
-
rescue_from Spud::RequestError, with: :handle_request_error
|
14
|
-
rescue_from ActiveRecord::RecordNotFound, with: :handle_record_not_found
|
15
|
-
rescue_from ActionController::UnknownFormat, with: :handle_unknown_format_error
|
16
|
-
|
17
|
-
def not_found
|
18
|
-
raise Spud::NotFoundError
|
1
|
+
class Spud::ApplicationController < TbCore::ApplicationController
|
2
|
+
def initialize
|
3
|
+
ActiveSupport::Deprecation.warn(
|
4
|
+
'Spud::ApplicationController is deprecated and may be removed from future releases,
|
5
|
+
use TbCore::ApplicationController instead.',
|
6
|
+
caller
|
7
|
+
)
|
8
|
+
super
|
19
9
|
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def set_mailer_default_url
|
24
|
-
ActionMailer::Base.default_url_options = {host: request.host_with_port}
|
25
|
-
end
|
26
|
-
|
27
|
-
def current_user_session
|
28
|
-
return @current_user_session if defined?(@current_user_session)
|
29
|
-
@current_user_session = SpudUserSession.find
|
30
|
-
end
|
31
|
-
|
32
|
-
def current_user
|
33
|
-
return @current_user if defined?(@current_user)
|
34
|
-
@current_user = current_user_session && current_user_session.spud_user
|
35
|
-
end
|
36
|
-
|
37
|
-
def current_user_id
|
38
|
-
if @current_user
|
39
|
-
return @current_user.id
|
40
|
-
else
|
41
|
-
0
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def require_user
|
46
|
-
unless current_user
|
47
|
-
raise Spud::UnauthorizedError.new()
|
48
|
-
end
|
49
|
-
return true
|
50
|
-
end
|
51
|
-
|
52
|
-
# Override this in a controller to redifine where the login form is
|
53
|
-
#
|
54
|
-
def login_path_for_require_user
|
55
|
-
login_path(return_to: request.fullpath)
|
56
|
-
end
|
57
|
-
|
58
|
-
def require_admin_user
|
59
|
-
if current_user.blank?
|
60
|
-
raise Spud::UnauthorizedError.new()
|
61
|
-
elsif !current_user.has_admin_rights?
|
62
|
-
raise Spud::AccessDeniedError.new()
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def redirect_back_or_default(default)
|
67
|
-
redirect_to(back_or_default(default))
|
68
|
-
end
|
69
|
-
|
70
|
-
def back_or_default(default='/')
|
71
|
-
if params[:return_to]
|
72
|
-
uri = URI.parse(params[:return_to].to_s)
|
73
|
-
return "#{uri.path}?#{uri.query}" if uri.query
|
74
|
-
return uri.path
|
75
|
-
else
|
76
|
-
return default
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def check_requires_password_change
|
81
|
-
if current_user.present? && current_user.requires_password_change?
|
82
|
-
redirect_to(login_change_password_path(return_to: request.path))
|
83
|
-
return false
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def set_time_zone
|
88
|
-
old_time_zone = Time.zone
|
89
|
-
Time.zone = current_user.time_zone if current_user and current_user.time_zone.blank? == false
|
90
|
-
yield
|
91
|
-
ensure
|
92
|
-
Time.zone = old_time_zone
|
93
|
-
end
|
94
|
-
|
95
|
-
def handle_request_error(error)
|
96
|
-
error.request_url = request.original_url
|
97
|
-
error.template = template_for_request_error() if respond_to?(:template_for_request_error, true)
|
98
|
-
|
99
|
-
if error.is_a?(Spud::UnauthorizedError)
|
100
|
-
if should_present_basic_auth?
|
101
|
-
headers['WWW-Authenticate'] = "Basic realm=\"#{Spud::Core.config.site_name}\""
|
102
|
-
elsif request.format.html?
|
103
|
-
redirect_to(login_path_for_require_user)
|
104
|
-
return false
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
do_error_response(error)
|
109
|
-
end
|
110
|
-
|
111
|
-
def do_error_response(error)
|
112
|
-
respond_to do |format|
|
113
|
-
format.json { render json: { errors: error.message }, status: error.code }
|
114
|
-
format.xml { render xml: { errors: error.message }, status: error.code }
|
115
|
-
format.all {
|
116
|
-
@error = error
|
117
|
-
render template: error.template, layout: nil, formats: [:html], status: error.code, content_type: 'text/html'
|
118
|
-
}
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def should_present_basic_auth?
|
123
|
-
return request.headers['X-TWICE-BAKED-BASIC-AUTH'].present?
|
124
|
-
end
|
125
|
-
|
126
|
-
def handle_record_not_found(error)
|
127
|
-
error = Spud::NotFoundError.new('record')
|
128
|
-
handle_request_error(error)
|
129
|
-
end
|
130
|
-
|
131
|
-
def handle_unknown_format_error(error)
|
132
|
-
error = Spud::NotFoundError.new()
|
133
|
-
handle_request_error(error)
|
134
|
-
end
|
135
|
-
|
136
|
-
ActiveSupport.run_load_hooks(:spud_application_controller, self)
|
137
|
-
|
138
10
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module TbCore
|
2
|
+
class ApplicationController < ActionController::Base
|
3
|
+
protect_from_forgery
|
4
|
+
|
5
|
+
include TbCore::ErrorHandling
|
6
|
+
include TbCore::Redirection
|
7
|
+
include TbCore::UserAuthentication
|
8
|
+
self.responder = TbCore::Responder
|
9
|
+
|
10
|
+
def not_found
|
11
|
+
raise Spud::NotFoundError
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveSupport.run_load_hooks(:tb_core_application_controller, self)
|
15
|
+
end
|
16
|
+
end
|
@@ -35,7 +35,9 @@ module Admin::ApplicationHelper
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
# The following params will automatically be white listed for tabbed navigation
|
39
|
+
#
|
40
|
+
WHITE_LIST_PARAMS = [:tab, :sort, :direction, :dir, :search, :id].freeze
|
39
41
|
|
40
42
|
# Build a Bootstrap nav-tabs element
|
41
43
|
#
|
@@ -67,6 +67,38 @@ module TbCore::ApplicationHelper
|
|
67
67
|
return content_tag :title, title
|
68
68
|
end
|
69
69
|
|
70
|
+
# Build a table header for a model
|
71
|
+
#
|
72
|
+
# * path_helper: The helper method you want to use to generate URLs.
|
73
|
+
# * model: The class we should use for translations (optional)
|
74
|
+
# * permit: Array of request params that are forwarded to the sort links
|
75
|
+
#
|
76
|
+
# Example:
|
77
|
+
#
|
78
|
+
# <%= tb_table_header :admin_users_path, model: SpudUser do |t| %>
|
79
|
+
# <%= t.sortable :name %>
|
80
|
+
# <%= t.sortable :email %>
|
81
|
+
# <%= t.header :last_login %>
|
82
|
+
# <th></th>
|
83
|
+
# <% end %>
|
84
|
+
#
|
85
|
+
# Header labels will be pulled from en.yml. To provide a different
|
86
|
+
# label pass the label: option
|
87
|
+
#
|
88
|
+
# Example:
|
89
|
+
#
|
90
|
+
# <%= t.header :name, label: 'Full Name' %>
|
91
|
+
#
|
92
|
+
def tb_table_header(path_helper, model: nil, permit: [], &block)
|
93
|
+
header = TbCore::TableHeader.new(
|
94
|
+
path_helper: path_helper,
|
95
|
+
model: model,
|
96
|
+
params: params.permit(permit.concat([:sort, :dir, :search, :tab])),
|
97
|
+
context: self)
|
98
|
+
header.capture(block) if block
|
99
|
+
header.to_html
|
100
|
+
end
|
101
|
+
|
70
102
|
def current_site_name
|
71
103
|
return Spud::Core.config.site_name
|
72
104
|
end
|
@@ -8,12 +8,12 @@
|
|
8
8
|
<%= content_for :detail do %>
|
9
9
|
<div class="table-responsive">
|
10
10
|
<table class="table table-striped table-hover">
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
<th
|
16
|
-
|
11
|
+
<%= tb_table_header :admin_users_path, model: SpudUser do |t| %>
|
12
|
+
<%= t.sortable :name %>
|
13
|
+
<%= t.sortable :email %>
|
14
|
+
<%= t.sortable :current_login_at %>
|
15
|
+
<th></th>
|
16
|
+
<% end %>
|
17
17
|
<tbody>
|
18
18
|
<% @spud_users.each do |spud_user| %>
|
19
19
|
<tr>
|
data/config/locales/en.yml
CHANGED
@@ -20,6 +20,7 @@ en:
|
|
20
20
|
spud_role_id: 'Role'
|
21
21
|
password_confirmation: 'Confirm password'
|
22
22
|
requires_password_change: 'Require change'
|
23
|
+
current_login_at: 'Logged in at'
|
23
24
|
tb_core_mailer:
|
24
25
|
forgot_password_notification:
|
25
26
|
subject: 'Forgot Password Request from %{site_name}'
|
data/config/routes.rb
CHANGED
@@ -32,6 +32,6 @@ Rails.application.routes.draw do
|
|
32
32
|
resources :password_resets, :only => [:index, :create, :show, :update], :path => 'login/forgot'
|
33
33
|
|
34
34
|
get 'spud/admin' => 'admin/user_sessions#legacy_redirect'
|
35
|
-
get '
|
35
|
+
get 'tb_core/not_found' => 'tb_core/application#not_found', as: 'not_found' unless Rails.env.production?
|
36
36
|
|
37
37
|
end
|
data/lib/spud_core/engine.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'responders'
|
2
2
|
require 'jquery-rails'
|
3
|
-
require 'jquery-ui-rails'
|
4
3
|
require 'authlogic'
|
5
4
|
require 'bootstrap-sass'
|
6
5
|
require 'autoprefixer-rails'
|
@@ -18,6 +17,7 @@ module Spud
|
|
18
17
|
require "#{root}/lib/spud_core/errors"
|
19
18
|
require "#{root}/lib/spud_core/searchable"
|
20
19
|
require "#{root}/lib/tb_core/form_builder"
|
20
|
+
require "#{root}/lib/tb_core/table_header"
|
21
21
|
|
22
22
|
engine_name :tb_core
|
23
23
|
config.autoload_paths << "#{root}/lib"
|
data/lib/spud_core/version.rb
CHANGED
data/lib/tb_core/form_builder.rb
CHANGED
@@ -143,7 +143,7 @@ class TbCore::FormBuilder < ActionView::Helpers::FormBuilder
|
|
143
143
|
# ie, container div + label + input + error message
|
144
144
|
#
|
145
145
|
|
146
|
-
def tb_sub_title(text)
|
146
|
+
def tb_sub_title(text, options={})
|
147
147
|
content_tag :div, options.merge(class: 'form-group') do
|
148
148
|
content_tag :div, class: 'col-sm-offset-2 col-sm-10' do
|
149
149
|
content_tag :h4, text, class: 'form-sub-title'
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module TbCore
|
2
|
+
class TableHeader
|
3
|
+
attr_reader :context
|
4
|
+
attr_accessor :header_html
|
5
|
+
|
6
|
+
# Forward view helper methods to the view context
|
7
|
+
delegate :concat, :content_tag, :link_to, to: :context
|
8
|
+
|
9
|
+
def initialize(path_helper:, model: nil, params: {}, context:)
|
10
|
+
@path_helper = path_helper
|
11
|
+
@model = model
|
12
|
+
@params = params
|
13
|
+
@context = context
|
14
|
+
end
|
15
|
+
|
16
|
+
def capture(block)
|
17
|
+
@html = context.capture do
|
18
|
+
block.call(self)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def sortable(attribute, label: nil)
|
23
|
+
content_tag :th, class: classes_for_attribute(attribute) do
|
24
|
+
concat(link_to_for_attribute(attribute, label))
|
25
|
+
concat(sort_arrow_for_attribute(attribute))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def header(attribute, label: nil)
|
30
|
+
label ||= translated_attribute(attribute)
|
31
|
+
content_tag :th, label
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_row
|
35
|
+
content_tag(:tr, @html)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_html
|
39
|
+
content_tag :thead, to_row, class: 'tb-table-header'
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def translated_attribute(attribute)
|
45
|
+
if @model
|
46
|
+
@model.human_attribute_name(attribute)
|
47
|
+
else
|
48
|
+
context.t(attribute)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def current_direction
|
53
|
+
@params[:dir] || 'asc'
|
54
|
+
end
|
55
|
+
|
56
|
+
def inverted_direction
|
57
|
+
current_direction == 'asc' ? 'desc' : 'asc'
|
58
|
+
end
|
59
|
+
|
60
|
+
def determine_direction(attribute)
|
61
|
+
if @params[:sort].nil? || @params[:sort] != attribute.to_s
|
62
|
+
'asc'
|
63
|
+
else
|
64
|
+
inverted_direction
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def classes_for_attribute(attribute)
|
69
|
+
classes = ['sortable']
|
70
|
+
if @params[:sort] == attribute.to_s
|
71
|
+
classes << 'sortable-active'
|
72
|
+
classes << "sortable-#{current_direction}"
|
73
|
+
end
|
74
|
+
classes.join(' ')
|
75
|
+
end
|
76
|
+
|
77
|
+
def link_to_for_attribute(attribute, label)
|
78
|
+
label ||= translated_attribute(attribute)
|
79
|
+
path = context.send(
|
80
|
+
@path_helper,
|
81
|
+
@params.merge(sort: attribute, dir: determine_direction(attribute))
|
82
|
+
)
|
83
|
+
link_to(label, path)
|
84
|
+
end
|
85
|
+
|
86
|
+
def sort_arrow_for_attribute(attribute)
|
87
|
+
return '' unless @params[:sort] == attribute.to_s
|
88
|
+
arrow_class = current_direction == 'asc' ? 'up' : 'down'
|
89
|
+
content_tag(:span, '', class: "glyphicon glyphicon-arrow-#{arrow_class}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -16,7 +16,7 @@ RSpec.describe Admin::ApplicationController, type: :controller do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
it 'should respond successfully if the current user is a super admin' do
|
19
|
-
@user.
|
19
|
+
@user.update_attributes(super_admin: true)
|
20
20
|
get :index
|
21
21
|
expect(response).to be_success
|
22
22
|
end
|