trestle 0.8.6 → 0.8.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +10 -9
- data/app/assets/javascripts/trestle/components/_dialog.js +29 -8
- data/app/assets/javascripts/trestle/components/_form.js +28 -7
- data/app/assets/javascripts/trestle/components/_sidebar.js +10 -8
- data/app/assets/javascripts/trestle/components/_tabs.js +2 -1
- data/app/assets/javascripts/trestle/components/_tooltips.js +16 -0
- data/app/assets/stylesheets/trestle/components/_modal.scss +4 -0
- data/app/assets/stylesheets/trestle/components/_navigation.scss +31 -11
- data/app/assets/stylesheets/trestle/components/_sidebar.scss +2 -2
- data/app/assets/stylesheets/trestle/components/_tags.scss +9 -0
- data/app/assets/stylesheets/trestle/components/_wells.scss +9 -1
- data/app/assets/stylesheets/trestle/core/_defaults.scss +4 -4
- data/app/assets/stylesheets/trestle/core/_layout.scss +8 -0
- data/app/assets/stylesheets/trestle/core/_typography.scss +39 -0
- data/app/controllers/concerns/trestle/controller/breadcrumbs.rb +21 -0
- data/app/controllers/concerns/trestle/controller/callbacks.rb +21 -0
- data/app/controllers/concerns/trestle/controller/dialog.rb +16 -0
- data/app/controllers/concerns/trestle/controller/helpers.rb +18 -0
- data/app/controllers/concerns/trestle/controller/layout.rb +16 -0
- data/app/controllers/concerns/trestle/controller/location.rb +15 -0
- data/app/controllers/trestle/application_controller.rb +6 -34
- data/app/helpers/trestle/debug_helper.rb +11 -0
- data/app/helpers/trestle/format_helper.rb +7 -3
- data/app/helpers/trestle/headings_helper.rb +27 -0
- data/app/helpers/trestle/panel_helper.rb +24 -0
- data/app/helpers/trestle/table_helper.rb +41 -2
- data/app/helpers/trestle/url_helper.rb +3 -1
- data/app/views/layouts/trestle/admin.html.erb +1 -1
- data/app/views/trestle/application/_flash.html.erb +1 -1
- data/app/views/trestle/shared/_sidebar.html.erb +2 -2
- data/app/views/trestle/table/_table.html.erb +2 -6
- data/lib/generators/trestle/resource/templates/admin.rb.erb +2 -2
- data/lib/trestle.rb +6 -4
- data/lib/trestle/adapters/active_record_adapter.rb +0 -4
- data/lib/trestle/adapters/adapter.rb +15 -10
- data/lib/trestle/adapters/sequel_adapter.rb +0 -4
- data/lib/trestle/admin.rb +18 -1
- data/lib/trestle/admin/builder.rb +22 -10
- data/lib/trestle/form/automatic.rb +5 -2
- data/lib/trestle/form/builder.rb +5 -1
- data/lib/trestle/form/field.rb +1 -1
- data/lib/trestle/form/fields/form_group.rb +3 -1
- data/lib/trestle/form/fields/select.rb +5 -1
- data/lib/trestle/form/fields/tag_select.rb +1 -1
- data/lib/trestle/form/renderer.rb +1 -1
- data/lib/trestle/navigation.rb +11 -5
- data/lib/trestle/navigation/item.rb +10 -0
- data/lib/trestle/resource.rb +27 -61
- data/lib/trestle/resource/builder.rb +15 -14
- data/lib/trestle/resource/collection.rb +48 -0
- data/lib/trestle/resource/controller.rb +36 -23
- data/lib/trestle/scope.rb +13 -3
- data/lib/trestle/table.rb +10 -4
- data/lib/trestle/table/column.rb +13 -2
- data/lib/trestle/table/row.rb +10 -0
- data/lib/trestle/version.rb +1 -1
- data/trestle.gemspec +1 -0
- data/vendor/assets/stylesheets/trestle/magnific-popup.scss +13 -1
- metadata +27 -4
- data/app/helpers/trestle/dialog_helper.rb +0 -7
data/lib/trestle/admin.rb
CHANGED
@@ -8,7 +8,6 @@ module Trestle
|
|
8
8
|
class << self
|
9
9
|
attr_accessor :menu
|
10
10
|
|
11
|
-
attr_accessor :table
|
12
11
|
attr_accessor :form
|
13
12
|
|
14
13
|
attr_accessor :additional_routes
|
@@ -20,6 +19,20 @@ module Trestle
|
|
20
19
|
@options ||= {}
|
21
20
|
end
|
22
21
|
|
22
|
+
def tables
|
23
|
+
@tables ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Deprecated: Use `tables[:index]` instead
|
27
|
+
def table
|
28
|
+
tables[:index]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Deprecated: Use `tables[:index]=` instead
|
32
|
+
def table=(table)
|
33
|
+
tables[:index] = table
|
34
|
+
end
|
35
|
+
|
23
36
|
def breadcrumbs
|
24
37
|
Breadcrumb::Trail.new(Array(Trestle.config.root_breadcrumbs) + [breadcrumb])
|
25
38
|
end
|
@@ -75,6 +88,10 @@ module Trestle
|
|
75
88
|
def railtie_routes_url_helpers(include_path_helpers=true)
|
76
89
|
Trestle.railtie_routes_url_helpers(include_path_helpers)
|
77
90
|
end
|
91
|
+
|
92
|
+
def build(&block)
|
93
|
+
Admin::Builder.build(self, &block)
|
94
|
+
end
|
78
95
|
end
|
79
96
|
end
|
80
97
|
end
|
@@ -11,23 +11,29 @@ module Trestle
|
|
11
11
|
|
12
12
|
delegate :helper, :before_action, :after_action, :around_action, to: :@controller
|
13
13
|
|
14
|
-
def initialize(
|
14
|
+
def initialize(admin)
|
15
|
+
@admin, @controller = admin, admin.const_get(:AdminController)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.create(name, options={}, &block)
|
15
19
|
# Create admin subclass
|
16
|
-
|
17
|
-
|
20
|
+
admin = Class.new(admin_class)
|
21
|
+
admin.options = options
|
18
22
|
|
19
23
|
# Define a constant based on the admin name
|
20
24
|
scope = options[:scope] || Object
|
21
|
-
scope.const_set("#{name.to_s.camelize}Admin",
|
25
|
+
scope.const_set("#{name.to_s.camelize}Admin", admin)
|
22
26
|
|
23
27
|
# Define admin controller class
|
24
28
|
# This is done using class_eval rather than Class.new so that the full
|
25
29
|
# class name and parent chain is set when Rails' inherited hooks are called.
|
26
|
-
|
30
|
+
admin.class_eval("class AdminController < #{controller.name}; end")
|
27
31
|
|
28
32
|
# Set a reference on the controller class to the admin class
|
29
|
-
|
30
|
-
|
33
|
+
controller = admin.const_get(:AdminController)
|
34
|
+
controller.instance_variable_set("@admin", admin)
|
35
|
+
|
36
|
+
admin.build(&block)
|
31
37
|
end
|
32
38
|
|
33
39
|
def menu(*args, &block)
|
@@ -38,8 +44,14 @@ module Trestle
|
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
41
|
-
def table(options={}, &block)
|
42
|
-
|
47
|
+
def table(name_or_options={}, options={}, &block)
|
48
|
+
if name_or_options.is_a?(Hash)
|
49
|
+
name, options = :index, name_or_options.reverse_merge(admin: admin, sortable: true)
|
50
|
+
else
|
51
|
+
name = name_or_options
|
52
|
+
end
|
53
|
+
|
54
|
+
admin.tables[name] = Table::Builder.build(options, &block)
|
43
55
|
end
|
44
56
|
|
45
57
|
def form(options={}, &block)
|
@@ -47,7 +59,7 @@ module Trestle
|
|
47
59
|
end
|
48
60
|
|
49
61
|
def admin(&block)
|
50
|
-
@admin.
|
62
|
+
@admin.instance_eval(&block) if block_given?
|
51
63
|
@admin
|
52
64
|
end
|
53
65
|
|
@@ -13,8 +13,11 @@ module Trestle
|
|
13
13
|
when :association
|
14
14
|
if attribute.polymorphic?
|
15
15
|
static_field attribute.name do
|
16
|
-
associated_instance = instance.public_send(attribute.association_name)
|
17
|
-
|
16
|
+
if associated_instance = instance.public_send(attribute.association_name)
|
17
|
+
admin_link_to format_value(associated_instance), associated_instance
|
18
|
+
else
|
19
|
+
content_tag(:span, I18n.t("admin.format.blank"), class: "blank")
|
20
|
+
end
|
18
21
|
end
|
19
22
|
else
|
20
23
|
prompt = I18n.t("admin.form.select.prompt", default: "- Select %{attribute_name} -", attribute_name: admin.human_attribute_name(attribute.association_name))
|
data/lib/trestle/form/builder.rb
CHANGED
data/lib/trestle/form/field.rb
CHANGED
@@ -39,7 +39,7 @@ module Trestle
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def extract_options!
|
42
|
-
@wrapper = extract_wrapper_options(
|
42
|
+
@wrapper = extract_wrapper_options(*Fields::FormGroup::WRAPPER_OPTIONS).merge(options.delete(:wrapper))
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
@@ -2,10 +2,12 @@ module Trestle
|
|
2
2
|
class Form
|
3
3
|
module Fields
|
4
4
|
class FormGroup < Field
|
5
|
+
WRAPPER_OPTIONS = [:help, :label, :hide_label]
|
6
|
+
|
5
7
|
def render
|
6
8
|
options[:class] << 'has-error' if errors.any?
|
7
9
|
|
8
|
-
content_tag(:div, options) do
|
10
|
+
content_tag(:div, options.except(*WRAPPER_OPTIONS)) do
|
9
11
|
concat label unless options[:label] == false
|
10
12
|
concat block.call if block
|
11
13
|
concat help_message if options[:help]
|
@@ -7,7 +7,7 @@ module Trestle
|
|
7
7
|
def initialize(builder, template, name, choices=nil, options={}, html_options={}, &block)
|
8
8
|
super(builder, template, name, options, &block)
|
9
9
|
|
10
|
-
@choices = Choices.new(choices ||
|
10
|
+
@choices = Choices.new(choices || default_choices)
|
11
11
|
@html_options = default_html_options.merge(html_options)
|
12
12
|
end
|
13
13
|
|
@@ -19,6 +19,10 @@ module Trestle
|
|
19
19
|
Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
|
20
20
|
end
|
21
21
|
|
22
|
+
def default_choices
|
23
|
+
builder.object.send(name) if builder.object
|
24
|
+
end
|
25
|
+
|
22
26
|
# Allows an array of model instances (or a scope) to be
|
23
27
|
# passed to the select field as the list of choices.
|
24
28
|
class Choices
|
@@ -5,7 +5,7 @@ module Trestle
|
|
5
5
|
include ::ActionView::Helpers::CaptureHelper
|
6
6
|
|
7
7
|
# Whitelisted helpers will concatenate their result to the output buffer when called.
|
8
|
-
WHITELISTED_HELPERS = [:row, :col, :render, :tab, :toolbar, :table, :divider]
|
8
|
+
WHITELISTED_HELPERS = [:row, :col, :render, :tab, :toolbar, :table, :divider, :h1, :h2, :h3, :h4, :h5, :h6, :panel, :well]
|
9
9
|
|
10
10
|
# Raw block helpers will pass their block argument directly to the method
|
11
11
|
# without wrapping it in a new output buffer.
|
data/lib/trestle/navigation.rb
CHANGED
@@ -7,12 +7,10 @@ module Trestle
|
|
7
7
|
autoload :Group
|
8
8
|
autoload :NullGroup, "trestle/navigation/group"
|
9
9
|
|
10
|
-
|
11
|
-
@blocks = blocks
|
12
|
-
end
|
10
|
+
attr_reader :items
|
13
11
|
|
14
|
-
def items
|
15
|
-
@
|
12
|
+
def initialize(items)
|
13
|
+
@items = items
|
16
14
|
end
|
17
15
|
|
18
16
|
def by_group
|
@@ -28,6 +26,14 @@ module Trestle
|
|
28
26
|
sorted.first.first if sorted.any?
|
29
27
|
end
|
30
28
|
|
29
|
+
def visible(context)
|
30
|
+
self.class.new(items.select { |item| item.visible?(context) })
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.build(blocks)
|
34
|
+
new(blocks.map(&:items).flatten)
|
35
|
+
end
|
36
|
+
|
31
37
|
private
|
32
38
|
def stable_sort(items)
|
33
39
|
items.sort_by.with_index { |item, i| [item, i] }
|
@@ -55,6 +55,16 @@ module Trestle
|
|
55
55
|
Badge.new(options[:badge]) if badge?
|
56
56
|
end
|
57
57
|
|
58
|
+
def visible?(context)
|
59
|
+
if options[:if]
|
60
|
+
context.instance_exec(&options[:if])
|
61
|
+
elsif options[:unless]
|
62
|
+
!context.instance_exec(&options[:unless])
|
63
|
+
else
|
64
|
+
true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
58
68
|
class Badge
|
59
69
|
attr_reader :text
|
60
70
|
|
data/lib/trestle/resource.rb
CHANGED
@@ -3,11 +3,17 @@ module Trestle
|
|
3
3
|
extend ActiveSupport::Autoload
|
4
4
|
|
5
5
|
autoload :Builder
|
6
|
+
autoload :Collection
|
6
7
|
autoload :Controller
|
7
8
|
|
8
9
|
RESOURCE_ACTIONS = [:index, :show, :new, :create, :edit, :update, :destroy]
|
9
10
|
READONLY_ACTIONS = [:index, :show]
|
10
11
|
|
12
|
+
class_attribute :decorator
|
13
|
+
|
14
|
+
class_attribute :pagination_options
|
15
|
+
self.pagination_options = {}
|
16
|
+
|
11
17
|
class << self
|
12
18
|
def adapter
|
13
19
|
@adapter ||= Trestle.config.default_adapter.new(self)
|
@@ -20,10 +26,11 @@ module Trestle
|
|
20
26
|
# Defines a method that can be overridden with a custom block,
|
21
27
|
# but is otherwise delegated to the adapter instance.
|
22
28
|
def self.adapter_method(name)
|
23
|
-
|
29
|
+
block_method = :"#{name}_block"
|
30
|
+
attr_accessor block_method
|
24
31
|
|
25
32
|
define_method(name) do |*args|
|
26
|
-
if override =
|
33
|
+
if override = public_send(block_method)
|
27
34
|
instance_exec(*args, &override)
|
28
35
|
else
|
29
36
|
adapter.public_send(name, *args)
|
@@ -31,33 +38,33 @@ module Trestle
|
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
41
|
+
# Collection-focused adapter methods
|
34
42
|
adapter_method :collection
|
43
|
+
adapter_method :merge_scopes
|
44
|
+
adapter_method :sort
|
45
|
+
adapter_method :paginate
|
46
|
+
adapter_method :finalize_collection
|
47
|
+
adapter_method :decorate_collection
|
48
|
+
adapter_method :count
|
49
|
+
|
50
|
+
# Instance-focused adapter methods
|
35
51
|
adapter_method :find_instance
|
36
52
|
adapter_method :build_instance
|
37
53
|
adapter_method :update_instance
|
38
54
|
adapter_method :save_instance
|
39
55
|
adapter_method :delete_instance
|
40
|
-
adapter_method :to_param
|
41
56
|
adapter_method :permitted_params
|
42
|
-
|
43
|
-
|
44
|
-
adapter_method :
|
45
|
-
adapter_method :count
|
46
|
-
adapter_method :sort
|
47
|
-
adapter_method :paginate
|
57
|
+
|
58
|
+
# Common adapter methods
|
59
|
+
adapter_method :to_param
|
48
60
|
adapter_method :human_attribute_name
|
61
|
+
|
62
|
+
# Automatic tables and forms adapter methods
|
49
63
|
adapter_method :default_table_attributes
|
50
64
|
adapter_method :default_form_attributes
|
51
65
|
|
52
|
-
attr_accessor :decorator
|
53
|
-
|
54
66
|
def prepare_collection(params)
|
55
|
-
|
56
|
-
collection = apply_scopes(collection, params)
|
57
|
-
collection = apply_sorting(collection, params)
|
58
|
-
collection = paginate(collection, params)
|
59
|
-
collection = decorate_collection(collection)
|
60
|
-
collection
|
67
|
+
Collection.new(self).prepare(params)
|
61
68
|
end
|
62
69
|
|
63
70
|
def initialize_collection(params)
|
@@ -68,47 +75,10 @@ module Trestle
|
|
68
75
|
@scopes ||= {}
|
69
76
|
end
|
70
77
|
|
71
|
-
def apply_scopes(collection, params)
|
72
|
-
unscoped = unscope(collection)
|
73
|
-
|
74
|
-
scopes_for(params).each do |scope|
|
75
|
-
collection = merge_scopes(collection, scope.apply(unscoped))
|
76
|
-
end
|
77
|
-
|
78
|
-
collection
|
79
|
-
end
|
80
|
-
|
81
|
-
def scopes_for(params)
|
82
|
-
result = []
|
83
|
-
|
84
|
-
if params[:scope] && scopes.has_key?(params[:scope].to_sym)
|
85
|
-
result << scopes[params[:scope].to_sym]
|
86
|
-
end
|
87
|
-
|
88
|
-
if result.empty? && default_scope = scopes.values.find(&:default?)
|
89
|
-
result << default_scope
|
90
|
-
end
|
91
|
-
|
92
|
-
result
|
93
|
-
end
|
94
|
-
|
95
78
|
def column_sorts
|
96
79
|
@column_sorts ||= {}
|
97
80
|
end
|
98
81
|
|
99
|
-
def apply_sorting(collection, params)
|
100
|
-
return collection unless params[:sort]
|
101
|
-
|
102
|
-
field = params[:sort].to_sym
|
103
|
-
order = params[:order].to_s.downcase == "desc" ? :desc : :asc
|
104
|
-
|
105
|
-
if column_sorts.has_key?(field)
|
106
|
-
instance_exec(collection, order, &column_sorts[field])
|
107
|
-
else
|
108
|
-
sort(collection, field, order)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
82
|
def table
|
113
83
|
super || Table::Automatic.new(self)
|
114
84
|
end
|
@@ -148,15 +118,11 @@ module Trestle
|
|
148
118
|
end
|
149
119
|
|
150
120
|
def return_locations
|
151
|
-
@return_locations ||= {
|
152
|
-
create: Proc.new { |instance| path(:show, id: to_param(instance)) },
|
153
|
-
update: Proc.new { |instance| path(:show, id: to_param(instance)) },
|
154
|
-
destroy: Proc.new { path(:index) }
|
155
|
-
}
|
121
|
+
@return_locations ||= {}
|
156
122
|
end
|
157
123
|
|
158
|
-
def
|
159
|
-
|
124
|
+
def build(&block)
|
125
|
+
Resource::Builder.build(self, &block)
|
160
126
|
end
|
161
127
|
|
162
128
|
private
|
@@ -22,36 +22,36 @@ module Trestle
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def collection(&block)
|
25
|
-
admin.
|
25
|
+
admin.collection_block = block
|
26
26
|
end
|
27
27
|
|
28
28
|
def find_instance(&block)
|
29
|
-
admin.
|
29
|
+
admin.find_instance_block = block
|
30
30
|
end
|
31
31
|
alias instance find_instance
|
32
32
|
|
33
33
|
def build_instance(&block)
|
34
|
-
admin.
|
34
|
+
admin.build_instance_block = block
|
35
35
|
end
|
36
36
|
|
37
37
|
def update_instance(&block)
|
38
|
-
admin.
|
38
|
+
admin.update_instance_block = block
|
39
39
|
end
|
40
40
|
|
41
41
|
def save_instance(&block)
|
42
|
-
admin.
|
42
|
+
admin.save_instance_block = block
|
43
43
|
end
|
44
44
|
|
45
45
|
def delete_instance(&block)
|
46
|
-
admin.
|
46
|
+
admin.delete_instance_block = block
|
47
47
|
end
|
48
48
|
|
49
49
|
def to_param(&block)
|
50
|
-
admin.
|
50
|
+
admin.to_param_block = block
|
51
51
|
end
|
52
52
|
|
53
53
|
def params(&block)
|
54
|
-
admin.
|
54
|
+
admin.permitted_params_block = block
|
55
55
|
end
|
56
56
|
|
57
57
|
def decorator(decorator)
|
@@ -59,27 +59,28 @@ module Trestle
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def decorate_collection(&block)
|
62
|
-
admin.
|
62
|
+
admin.decorate_collection_block = block
|
63
63
|
end
|
64
64
|
|
65
65
|
def merge_scopes(&block)
|
66
|
-
admin.
|
66
|
+
admin.merge_scopes_block = block
|
67
67
|
end
|
68
68
|
|
69
69
|
def sort(&block)
|
70
|
-
admin.
|
70
|
+
admin.sort_block = block
|
71
71
|
end
|
72
72
|
|
73
73
|
def sort_column(column, &block)
|
74
74
|
admin.column_sorts[column.to_sym] = block
|
75
75
|
end
|
76
76
|
|
77
|
-
def paginate(&block)
|
78
|
-
admin.
|
77
|
+
def paginate(options={}, &block)
|
78
|
+
admin.pagination_options = admin.pagination_options.merge(options)
|
79
|
+
admin.paginate_block = block
|
79
80
|
end
|
80
81
|
|
81
82
|
def count(&block)
|
82
|
-
admin.
|
83
|
+
admin.count_block = block
|
83
84
|
end
|
84
85
|
|
85
86
|
def scope(name, scope=nil, options={}, &block)
|