trestle 0.8.3 → 0.8.6
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/.gitignore +4 -0
- data/.travis.yml +10 -1
- data/Gemfile +4 -0
- data/README.md +1 -0
- data/app/assets/javascripts/trestle/admin.js +24 -0
- data/app/assets/javascripts/trestle/components/_confirmation.js +23 -0
- data/app/assets/javascripts/trestle/components/_datepicker.js +22 -0
- data/app/assets/javascripts/trestle/components/_dialog.js +107 -0
- data/app/assets/javascripts/trestle/components/_errors.js +11 -0
- data/app/assets/javascripts/trestle/components/_form.js +48 -0
- data/app/assets/javascripts/trestle/components/_gallery.js +27 -0
- data/app/assets/javascripts/trestle/components/_select.js +11 -0
- data/app/assets/javascripts/trestle/components/_sidebar.js +75 -0
- data/app/assets/javascripts/trestle/components/_table.js +21 -0
- data/app/assets/javascripts/trestle/components/_tabs.js +24 -0
- data/app/assets/javascripts/trestle/components/_tooltips.js +3 -0
- data/app/assets/javascripts/trestle/core/_contexts.js +13 -0
- data/app/assets/javascripts/trestle/core/_cookies.js +24 -0
- data/app/assets/javascripts/trestle/core/_events.js +39 -0
- data/app/assets/javascripts/trestle/core/_visit.js +10 -0
- data/app/assets/javascripts/trestle/custom.js +4 -0
- data/app/assets/stylesheets/trestle/components/_alerts.scss +28 -0
- data/app/assets/stylesheets/trestle/components/_buttons.scss +9 -0
- data/app/assets/stylesheets/trestle/components/_modal.scss +92 -0
- data/app/assets/stylesheets/trestle/components/_navigation.scss +80 -10
- data/app/assets/stylesheets/trestle/components/_sidebar.scss +1 -0
- data/app/assets/stylesheets/trestle/components/_table.scss +6 -0
- data/app/assets/stylesheets/trestle/core/_defaults.scss +5 -1
- data/app/controllers/trestle/application_controller.rb +5 -1
- data/app/helpers/trestle/dialog_helper.rb +7 -0
- data/app/helpers/trestle/form_helper.rb +8 -1
- data/app/helpers/trestle/format_helper.rb +48 -0
- data/app/helpers/trestle/hook_helper.rb +8 -3
- data/app/helpers/trestle/url_helper.rb +33 -11
- data/app/views/layouts/trestle/admin.html.erb +4 -4
- data/app/views/trestle/admin/index.html.erb +1 -1
- data/app/views/trestle/application/_alert.html.erb +2 -0
- data/app/views/trestle/application/_dialog.html.erb +36 -0
- data/app/views/trestle/application/_flash.html.erb +18 -4
- data/app/views/trestle/application/_tabs.html.erb +7 -1
- data/app/views/trestle/dashboard/index.html.erb +2 -2
- data/app/views/trestle/resource/_form.html.erb +1 -1
- data/app/views/trestle/resource/edit.html.erb +6 -6
- data/app/views/trestle/resource/index.html.erb +5 -2
- data/app/views/trestle/resource/new.html.erb +4 -4
- data/app/views/trestle/resource/show.html.erb +6 -6
- data/app/views/trestle/shared/_sidebar.html.erb +7 -4
- data/bower.json +2 -2
- data/config/locales/en.yml +38 -18
- data/config/locales/fr.rb +18 -0
- data/config/locales/fr.yml +69 -0
- data/config/locales/nl.rb +18 -0
- data/config/locales/nl.yml +67 -0
- data/config/locales/pl.rb +18 -0
- data/config/locales/pl.yml +70 -0
- data/config/locales/pt-BR.rb +18 -0
- data/config/locales/pt-BR.yml +69 -0
- data/gemfiles/rails-4.2.gemfile +14 -0
- data/gemfiles/rails-5.0.gemfile +14 -0
- data/gemfiles/rails-5.1.gemfile +14 -0
- data/gemfiles/rails-edge.gemfile +15 -0
- data/lib/generators/trestle/install/install_generator.rb +3 -3
- data/lib/generators/trestle/install/templates/custom.js +7 -0
- data/lib/generators/trestle/install/templates/trestle.rb.erb +9 -2
- data/lib/generators/trestle/resource/templates/admin.rb.erb +1 -1
- data/lib/trestle/adapters/active_record_adapter.rb +46 -20
- data/lib/trestle/adapters/adapter.rb +176 -0
- data/lib/trestle/adapters/sequel_adapter.rb +85 -0
- data/lib/trestle/adapters.rb +7 -64
- data/lib/trestle/admin/builder.rb +10 -2
- data/lib/trestle/admin.rb +14 -1
- data/lib/trestle/attribute.rb +14 -37
- data/lib/trestle/breadcrumb.rb +19 -0
- data/lib/trestle/configuration.rb +14 -3
- data/lib/trestle/display.rb +1 -1
- data/lib/trestle/form/automatic.rb +29 -21
- data/lib/trestle/form/builder.rb +4 -0
- data/lib/trestle/form/field.rb +2 -2
- data/lib/trestle/form/fields/check_box.rb +1 -1
- data/lib/trestle/form/fields/collection_select.rb +1 -1
- data/lib/trestle/form/fields/date_select.rb +1 -1
- data/lib/trestle/form/fields/datetime_select.rb +1 -1
- data/lib/trestle/form/fields/grouped_collection_select.rb +1 -1
- data/lib/trestle/form/fields/select.rb +2 -2
- data/lib/trestle/form/fields/tag_select.rb +1 -2
- data/lib/trestle/form/fields/time_select.rb +1 -1
- data/lib/trestle/form/fields/time_zone_select.rb +1 -1
- data/lib/trestle/form.rb +7 -3
- data/lib/trestle/model_name.rb +64 -0
- data/lib/trestle/navigation/group.rb +8 -0
- data/lib/trestle/navigation/item.rb +1 -1
- data/lib/trestle/options.rb +7 -5
- data/lib/trestle/reloader.rb +1 -1
- data/lib/trestle/resource/builder.rb +17 -1
- data/lib/trestle/resource/controller.rb +80 -18
- data/lib/trestle/resource.rb +26 -16
- data/lib/trestle/scope.rb +1 -1
- data/lib/trestle/table/actions_column.rb +21 -16
- data/lib/trestle/table/automatic.rb +5 -12
- data/lib/trestle/table/builder.rb +3 -2
- data/lib/trestle/table/column.rb +27 -45
- data/lib/trestle/table/row.rb +8 -2
- data/lib/trestle/table.rb +7 -1
- data/lib/trestle/version.rb +1 -1
- data/lib/trestle.rb +1 -0
- data/trestle.gemspec +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.css +51 -26
- data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.js +349 -299
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ar.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bg.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bn.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cat.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cs.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cy.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/da.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/de.js +10 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/eo.js +11 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/es.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/et.js +11 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fa.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fi.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fr.js +11 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/gr.js +13 -13
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/he.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hi.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hr.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hu.js +10 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/id.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/index.js +97 -0
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/it.js +10 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ja.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ko.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lt.js +10 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lv.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/mk.js +8 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ms.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/my.js +7 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/nl.js +11 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/no.js +11 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pa.js +5 -5
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pl.js +6 -6
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pt.js +6 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ro.js +7 -9
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ru.js +6 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/si.js +5 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sk.js +8 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sl.js +8 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sq.js +5 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sr.js +9 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sv.js +8 -10
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/th.js +10 -11
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/tr.js +6 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/uk.js +6 -7
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/vn.js +6 -8
- data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/zh.js +9 -11
- data/vendor/assets/bower_components/trestle/select2/dist/js/select2.full.js +90 -69
- metadata +58 -33
- data/app/assets/javascripts/trestle/_confirmation.js.coffee +0 -18
- data/app/assets/javascripts/trestle/_datepicker.js.coffee +0 -18
- data/app/assets/javascripts/trestle/_errors.js.coffee +0 -8
- data/app/assets/javascripts/trestle/_form.js.coffee +0 -4
- data/app/assets/javascripts/trestle/_gallery.js.coffee +0 -21
- data/app/assets/javascripts/trestle/_select.js.coffee +0 -7
- data/app/assets/javascripts/trestle/_sidebar.js.coffee +0 -45
- data/app/assets/javascripts/trestle/_table.js.coffee +0 -16
- data/app/assets/javascripts/trestle/_tabs.js.coffee +0 -9
- data/app/assets/javascripts/trestle/_tooltips.js.coffee +0 -2
- data/app/assets/javascripts/trestle/admin.js.coffee +0 -22
- data/app/assets/javascripts/trestle/custom.js.coffee +0 -4
- data/lib/generators/trestle/install/templates/custom.js.coffee +0 -7
|
@@ -2,19 +2,19 @@ module Trestle
|
|
|
2
2
|
module Adapters
|
|
3
3
|
module ActiveRecordAdapter
|
|
4
4
|
def collection(params={})
|
|
5
|
-
|
|
5
|
+
model.all
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def find_instance(params)
|
|
9
|
-
|
|
9
|
+
model.find(params[:id])
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def build_instance(params={})
|
|
13
|
-
|
|
12
|
+
def build_instance(attrs={}, params={})
|
|
13
|
+
model.new(attrs)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def update_instance(instance, params)
|
|
17
|
-
instance.assign_attributes(
|
|
16
|
+
def update_instance(instance, attrs, params={})
|
|
17
|
+
instance.assign_attributes(attrs)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def save_instance(instance)
|
|
@@ -25,10 +25,6 @@ module Trestle
|
|
|
25
25
|
instance.destroy
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def to_param(instance)
|
|
29
|
-
instance
|
|
30
|
-
end
|
|
31
|
-
|
|
32
28
|
def unscope(scope)
|
|
33
29
|
scope.unscoped
|
|
34
30
|
end
|
|
@@ -37,27 +33,57 @@ module Trestle
|
|
|
37
33
|
scope.merge(other)
|
|
38
34
|
end
|
|
39
35
|
|
|
36
|
+
def count(collection)
|
|
37
|
+
collection.count
|
|
38
|
+
end
|
|
39
|
+
|
|
40
40
|
def sort(collection, field, order)
|
|
41
41
|
collection.reorder(field => order)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
collection.page(params[:page])
|
|
44
|
+
def human_attribute_name(attribute, options={})
|
|
45
|
+
model.human_attribute_name(attribute, options)
|
|
47
46
|
end
|
|
48
47
|
|
|
49
|
-
def
|
|
50
|
-
|
|
48
|
+
def default_table_attributes
|
|
49
|
+
default_attributes.reject do |attribute|
|
|
50
|
+
inheritance_column?(attribute) || counter_cache_column?(attribute)
|
|
51
|
+
end
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
def default_form_attributes
|
|
55
|
+
default_attributes.reject do |attribute|
|
|
56
|
+
primary_key?(attribute) || inheritance_column?(attribute) || counter_cache_column?(attribute)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
53
61
|
def default_attributes
|
|
54
|
-
|
|
55
|
-
if column.name.end_with?("_id") && (
|
|
56
|
-
Attribute::Association.new(
|
|
62
|
+
model.columns.map do |column|
|
|
63
|
+
if column.name.end_with?("_id") && (name = column.name.sub(/_id$/, '')) && (reflection = model.reflections[name])
|
|
64
|
+
Attribute::Association.new(column.name, class: -> { reflection.klass }, name: name, polymorphic: reflection.polymorphic?, type_column: reflection.foreign_type)
|
|
65
|
+
elsif column.name.end_with?("_type") && (name = column.name.sub(/_type$/, '')) && (reflection = model.reflections[name])
|
|
66
|
+
# Ignore type columns for polymorphic associations
|
|
57
67
|
else
|
|
58
|
-
Attribute.new(
|
|
68
|
+
Attribute.new(column.name, column.type, array_column?(column) ? { array: true } : {})
|
|
59
69
|
end
|
|
60
|
-
end
|
|
70
|
+
end.compact
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def primary_key?(attribute)
|
|
74
|
+
attribute.name.to_s == model.primary_key
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def inheritance_column?(attribute)
|
|
78
|
+
attribute.name.to_s == model.inheritance_column
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def counter_cache_column?(attribute)
|
|
82
|
+
attribute.name.to_s.end_with?("_count")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def array_column?(column)
|
|
86
|
+
column.respond_to?(:array?) && column.array?
|
|
61
87
|
end
|
|
62
88
|
end
|
|
63
89
|
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
module Trestle
|
|
2
|
+
module Adapters
|
|
3
|
+
class Adapter
|
|
4
|
+
attr_reader :admin
|
|
5
|
+
delegate :model, to: :admin
|
|
6
|
+
|
|
7
|
+
def initialize(admin)
|
|
8
|
+
@admin = admin
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Loads the initial collection for use by the index action.
|
|
12
|
+
#
|
|
13
|
+
# params - Unfiltered params hash from the controller
|
|
14
|
+
#
|
|
15
|
+
# Returns a scope object that can be chained with other methods (e.g. sort, paginate, count, etc).
|
|
16
|
+
def collection(params={})
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Finds (and returns) an individual instance for use by the show, edit, update, destroy actions.
|
|
21
|
+
#
|
|
22
|
+
# params - Unfiltered params hash from the controller
|
|
23
|
+
def find_instance(params)
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Builds (and returns) a new instance for new/create actions.
|
|
28
|
+
#
|
|
29
|
+
# attrs - Permitted attributes to set on the new instance
|
|
30
|
+
# params - Unfiltered params hash from the controller
|
|
31
|
+
def build_instance(attrs={}, params={})
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Updates (but does not save) a given resource's attributes.
|
|
36
|
+
#
|
|
37
|
+
# instance - The instance to update
|
|
38
|
+
# attrs - Permitted attributes to update on the instance
|
|
39
|
+
# params - Unfiltered params hash from the controller
|
|
40
|
+
#
|
|
41
|
+
# The return value is ignored.
|
|
42
|
+
def update_instance(instance, attrs, params={})
|
|
43
|
+
raise NotImplementedError
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Saves an instance (used by the create and update actions).
|
|
47
|
+
#
|
|
48
|
+
# instance - The instance to save
|
|
49
|
+
#
|
|
50
|
+
# Returns a boolean indicating the success/fail status of the save.
|
|
51
|
+
def save_instance(instance)
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Deletes an instance (used by the destroy action).
|
|
56
|
+
#
|
|
57
|
+
# instance - The instance to delete
|
|
58
|
+
#
|
|
59
|
+
# Returns a boolean indicating the success/fail status of the deletion.
|
|
60
|
+
def delete_instance(instance)
|
|
61
|
+
raise NotImplementedError
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Decorates a collection for rendering by the index view.
|
|
65
|
+
# Decorating is the final step in preparing the collection for the view.
|
|
66
|
+
#
|
|
67
|
+
# collection - The collection to decorate
|
|
68
|
+
#
|
|
69
|
+
# Returns an enumerable collection of instances.
|
|
70
|
+
def decorate_collection(collection)
|
|
71
|
+
collection
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Converts an instance to a URL parameter. The result of this method is passed to the #find_instance
|
|
75
|
+
# adapter method as params[:id]. It is recommended to simply use the instance's #id, as other potential options
|
|
76
|
+
# such as a permalink/slug could potentially be changed during editing.
|
|
77
|
+
#
|
|
78
|
+
# instance - The instance to convert
|
|
79
|
+
#
|
|
80
|
+
# Returns the URL representation of the instance.
|
|
81
|
+
def to_param(instance)
|
|
82
|
+
instance.id
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Unscopes a collection so that it can be merged with other scopes without duplication or interference.
|
|
86
|
+
#
|
|
87
|
+
# scope - The scope to unscope
|
|
88
|
+
#
|
|
89
|
+
# Returns a scope object.
|
|
90
|
+
def unscope(scope)
|
|
91
|
+
scope
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Merges scopes together for Trestle scope application and counting.
|
|
95
|
+
#
|
|
96
|
+
# scope - The first scope
|
|
97
|
+
# other - The second scope
|
|
98
|
+
#
|
|
99
|
+
# Returns a scope object representing the combination of the two given scopes.
|
|
100
|
+
def merge_scopes(scope, other)
|
|
101
|
+
raise NotImplementedError
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Counts the number of objects in a collection for use by scope links.
|
|
105
|
+
#
|
|
106
|
+
# collection - The collection to count
|
|
107
|
+
#
|
|
108
|
+
# Returns the total number (integer) of objects in the collection.
|
|
109
|
+
def count(collection)
|
|
110
|
+
raise NotImplementedError
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Sorts the collection by the given field and order.
|
|
114
|
+
# This method is called when an explicit sort column for the given field is not defined.
|
|
115
|
+
#
|
|
116
|
+
# collection - The collection to sort
|
|
117
|
+
# field - The field to sort by
|
|
118
|
+
# order - Symbol (:asc or :desc) representing the sort order (ascending or descending)
|
|
119
|
+
#
|
|
120
|
+
# Returns a scope object
|
|
121
|
+
def sort(collection, field, order)
|
|
122
|
+
raise NotImplementedError
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Paginates a collection for use by the index action.
|
|
126
|
+
#
|
|
127
|
+
# collection - The collection to paginate
|
|
128
|
+
# params - Unfiltered params hash from the controller:
|
|
129
|
+
# :page - current page number
|
|
130
|
+
#
|
|
131
|
+
# Returns a Kaminari-compatible scope corresponding to a single page.
|
|
132
|
+
def paginate(collection, params)
|
|
133
|
+
collection = Kaminari.paginate_array(collection.to_a) unless collection.respond_to?(:page)
|
|
134
|
+
collection.page(params[:page])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Filters the submitted form parameters and returns a whitelisted attributes 'hash'
|
|
138
|
+
# that can be set or updated on a model instance.
|
|
139
|
+
#
|
|
140
|
+
# IMPORTANT: By default, all params are permitted, which assumes a trusted administrator. If this is not the
|
|
141
|
+
# case, a `params` block should be individually declared for each admin with the set of permitted parameters.
|
|
142
|
+
#
|
|
143
|
+
# params - Unfiltered params hash from the controller
|
|
144
|
+
#
|
|
145
|
+
# Returns the permitted set of parameters as a ActionController::Parameters object.
|
|
146
|
+
def permitted_params(params)
|
|
147
|
+
params.require(admin.admin_name.singularize).permit!
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Produces a human-readable name for a given attribute, applying I18n where appropriate.
|
|
151
|
+
# See ActiveModel::Translation for an implementation of this method.
|
|
152
|
+
#
|
|
153
|
+
# attribute - Attribute name (Symbol)
|
|
154
|
+
# options - Hash of options [not currently used]
|
|
155
|
+
#
|
|
156
|
+
# Returns the human-readable name of the given attribute as a String.
|
|
157
|
+
def human_attribute_name(attribute, options={})
|
|
158
|
+
attribute.to_s.titleize
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Generates a list of attributes that should be rendered by the index (table) view.
|
|
162
|
+
#
|
|
163
|
+
# Returns an Array of Trestle::Attribute and/or Trestle::Attribute::Association objects.
|
|
164
|
+
def default_table_attributes
|
|
165
|
+
raise NotImplementedError
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Generates a list of attributes that should be rendered by the new/show/edit (form) views.
|
|
169
|
+
#
|
|
170
|
+
# Returns an Array of Trestle::Attribute and/or Trestle::Attribute::Association objects.
|
|
171
|
+
def default_form_attributes
|
|
172
|
+
raise NotImplementedError
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require "sequel"
|
|
3
|
+
rescue LoadError
|
|
4
|
+
$stderr.puts "You don't have sequel installed in your application. Please add it to your Gemfile and run bundle install"
|
|
5
|
+
raise
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
Sequel::Model.plugin :active_model
|
|
9
|
+
|
|
10
|
+
module Trestle
|
|
11
|
+
module Adapters
|
|
12
|
+
module SequelAdapter
|
|
13
|
+
def collection(params={})
|
|
14
|
+
model.dataset
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def find_instance(params)
|
|
18
|
+
model[params[:id]]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_instance(attrs={}, params={})
|
|
22
|
+
model.new(attrs)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def update_instance(instance, attrs, params={})
|
|
26
|
+
instance.set(attrs)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def save_instance(instance)
|
|
30
|
+
instance.save
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def delete_instance(instance)
|
|
34
|
+
instance.destroy
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unscope(scope)
|
|
38
|
+
scope.unfiltered
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def merge_scopes(scope, other)
|
|
42
|
+
scope.intersect(other)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def count(collection)
|
|
46
|
+
collection.count
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def sort(collection, field, order)
|
|
50
|
+
collection.order(Sequel.send(order, field))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def default_table_attributes
|
|
54
|
+
default_attributes.reject do |attribute|
|
|
55
|
+
inheritance_column?(attribute)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def default_form_attributes
|
|
60
|
+
default_attributes.reject do |attribute|
|
|
61
|
+
primary_key?(attribute) || inheritance_column?(attribute)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
protected
|
|
66
|
+
def default_attributes
|
|
67
|
+
model.db_schema.map do |column_name, column_attrs|
|
|
68
|
+
if column_name.to_s.end_with?("_id") && (name = column_name.to_s.sub(/_id$/, '')) && (reflection = model.association_reflection(name.to_sym))
|
|
69
|
+
Attribute::Association.new(column_name, class: -> { reflection.associated_class }, name: name)
|
|
70
|
+
else
|
|
71
|
+
Attribute.new(column_name, column_attrs[:type])
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def primary_key?(attribute)
|
|
77
|
+
attribute.name.to_s == model.primary_key.to_s
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def inheritance_column?(attribute)
|
|
81
|
+
model.respond_to?(:sti_key) && attribute.name.to_s == model.sti_key.to_s
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/trestle/adapters.rb
CHANGED
|
@@ -2,73 +2,16 @@ module Trestle
|
|
|
2
2
|
module Adapters
|
|
3
3
|
extend ActiveSupport::Autoload
|
|
4
4
|
|
|
5
|
+
autoload :Adapter
|
|
6
|
+
|
|
5
7
|
autoload :ActiveRecordAdapter
|
|
6
8
|
autoload :DraperAdapter
|
|
9
|
+
autoload :SequelAdapter
|
|
7
10
|
|
|
8
|
-
class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@admin = admin
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def collection(params={})
|
|
16
|
-
raise NotImplementedError
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def find_instance(params)
|
|
20
|
-
raise NotImplementedError
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def build_instance(params={})
|
|
24
|
-
raise NotImplementedError
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def update_instance(instance, params)
|
|
28
|
-
raise NotImplementedError
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def save_instance(instance)
|
|
32
|
-
raise NotImplementedError
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def delete_instance(instance)
|
|
36
|
-
raise NotImplementedError
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def decorate_collection(collection)
|
|
40
|
-
collection
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def merge_scopes(scope, other)
|
|
44
|
-
raise NotImplementedError
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def sort(collection, params)
|
|
48
|
-
raise NotImplementedError
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def paginate(collection, params)
|
|
52
|
-
raise NotImplementedError
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def count(collection)
|
|
56
|
-
raise NotImplementedError
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def permitted_params(params)
|
|
60
|
-
params.require(admin.admin_name.singularize).permit!
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def default_attributes
|
|
64
|
-
raise NotImplementedError
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Creates a new Adapter class with the given modules mixed in
|
|
68
|
-
def self.compose(*modules)
|
|
69
|
-
Class.new(self) do
|
|
70
|
-
modules.each { |mod| include(mod) }
|
|
71
|
-
end
|
|
11
|
+
# Creates a new Adapter class with the given modules mixed in
|
|
12
|
+
def self.compose(*modules)
|
|
13
|
+
Class.new(Adapter) do
|
|
14
|
+
modules.each { |mod| include(mod) }
|
|
72
15
|
end
|
|
73
16
|
end
|
|
74
17
|
end
|
|
@@ -42,8 +42,8 @@ module Trestle
|
|
|
42
42
|
admin.table = Table::Builder.build(options.reverse_merge(admin: admin, sortable: true), &block)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
def form(&block)
|
|
46
|
-
admin.form = Form.new(&block)
|
|
45
|
+
def form(options={}, &block)
|
|
46
|
+
admin.form = Form.new(options, &block)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def admin(&block)
|
|
@@ -59,6 +59,14 @@ module Trestle
|
|
|
59
59
|
def routes(&block)
|
|
60
60
|
@admin.additional_routes = block
|
|
61
61
|
end
|
|
62
|
+
|
|
63
|
+
def breadcrumb(label=nil, path=nil, &block)
|
|
64
|
+
if block_given?
|
|
65
|
+
@admin.breadcrumb = block
|
|
66
|
+
else
|
|
67
|
+
@admin.breadcrumb = -> { Breadcrumb.new(label, path) }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
62
70
|
end
|
|
63
71
|
end
|
|
64
72
|
end
|
data/lib/trestle/admin.rb
CHANGED
|
@@ -14,6 +14,7 @@ module Trestle
|
|
|
14
14
|
attr_accessor :additional_routes
|
|
15
15
|
|
|
16
16
|
attr_writer :options
|
|
17
|
+
attr_writer :breadcrumb
|
|
17
18
|
|
|
18
19
|
def options
|
|
19
20
|
@options ||= {}
|
|
@@ -24,7 +25,15 @@ module Trestle
|
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def breadcrumb
|
|
27
|
-
|
|
28
|
+
if @breadcrumb
|
|
29
|
+
Breadcrumb.cast(@breadcrumb.call)
|
|
30
|
+
else
|
|
31
|
+
default_breadcrumb
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def default_breadcrumb
|
|
36
|
+
Breadcrumb.new(I18n.t("admin.breadcrumbs.#{admin_name}", default: admin_name.titleize), path)
|
|
28
37
|
end
|
|
29
38
|
|
|
30
39
|
def admin_name
|
|
@@ -47,6 +56,10 @@ module Trestle
|
|
|
47
56
|
Engine.routes.url_for(options.merge(controller: controller_namespace, action: action, only_path: true))
|
|
48
57
|
end
|
|
49
58
|
|
|
59
|
+
def actions
|
|
60
|
+
[:index]
|
|
61
|
+
end
|
|
62
|
+
|
|
50
63
|
def routes
|
|
51
64
|
admin = self
|
|
52
65
|
|
data/lib/trestle/attribute.rb
CHANGED
|
@@ -1,53 +1,30 @@
|
|
|
1
1
|
module Trestle
|
|
2
2
|
class Attribute
|
|
3
|
-
attr_reader :
|
|
3
|
+
attr_reader :name, :type, :options
|
|
4
4
|
|
|
5
|
-
def initialize(
|
|
6
|
-
@
|
|
5
|
+
def initialize(name, type, options={})
|
|
6
|
+
@name, @type, @options = name.to_sym, type, options
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def boolean?
|
|
14
|
-
type == :boolean
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def text?
|
|
18
|
-
type == :text
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def datetime?
|
|
22
|
-
[:datetime, :time, :date].include?(type)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def primary_key?
|
|
26
|
-
name.to_s == admin.model.primary_key
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def inheritance_column?
|
|
30
|
-
name.to_s == admin.model.inheritance_column
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def counter_cache?
|
|
34
|
-
name.to_s.end_with?("_count")
|
|
9
|
+
def array?
|
|
10
|
+
options[:array] == true
|
|
35
11
|
end
|
|
36
12
|
|
|
37
13
|
class Association < Attribute
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def initialize(admin, name, association_class)
|
|
41
|
-
super(admin, name, :association)
|
|
42
|
-
@association_class = association_class
|
|
14
|
+
def initialize(name, options={})
|
|
15
|
+
super(name, :association, options)
|
|
43
16
|
end
|
|
44
17
|
|
|
45
18
|
def association_name
|
|
46
|
-
name.to_s.sub(/_id$/, "")
|
|
19
|
+
options[:name] || name.to_s.sub(/_id$/, "")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def association_class
|
|
23
|
+
options[:class].respond_to?(:call) ? options[:class].call : options[:class]
|
|
47
24
|
end
|
|
48
25
|
|
|
49
|
-
def
|
|
50
|
-
|
|
26
|
+
def polymorphic?
|
|
27
|
+
options[:polymorphic] == true
|
|
51
28
|
end
|
|
52
29
|
end
|
|
53
30
|
end
|
data/lib/trestle/breadcrumb.rb
CHANGED
|
@@ -10,11 +10,30 @@ module Trestle
|
|
|
10
10
|
label == other.label && path == other.path
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def self.cast(obj)
|
|
14
|
+
case obj
|
|
15
|
+
when Breadcrumb
|
|
16
|
+
obj
|
|
17
|
+
when String
|
|
18
|
+
new(obj)
|
|
19
|
+
when Array
|
|
20
|
+
new(*obj)
|
|
21
|
+
else
|
|
22
|
+
raise ArgumentError, "Unable to cast #{obj.inspect} to Breadcrumb"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
13
26
|
class Trail
|
|
27
|
+
include Enumerable
|
|
28
|
+
|
|
14
29
|
def initialize(breadcrumbs=[])
|
|
15
30
|
@breadcrumbs = Array(breadcrumbs)
|
|
16
31
|
end
|
|
17
32
|
|
|
33
|
+
def ==(other)
|
|
34
|
+
to_a == other.to_a
|
|
35
|
+
end
|
|
36
|
+
|
|
18
37
|
def dup
|
|
19
38
|
self.class.new(@breadcrumbs.dup)
|
|
20
39
|
end
|
|
@@ -64,10 +64,10 @@ module Trestle
|
|
|
64
64
|
option :persistent_params, [:sort, :order, :scope]
|
|
65
65
|
|
|
66
66
|
# List of methods to try calling on an instance when displayed by the `display` helper
|
|
67
|
-
option :display_methods, [:display_name, :full_name, :name, :title, :username, :login, :email
|
|
67
|
+
option :display_methods, [:display_name, :full_name, :name, :title, :username, :login, :email]
|
|
68
68
|
|
|
69
69
|
# Default adapter class used by all admin resources
|
|
70
|
-
option :default_adapter, Adapters
|
|
70
|
+
option :default_adapter, Adapters.compose(Adapters::ActiveRecordAdapter, Adapters::DraperAdapter)
|
|
71
71
|
|
|
72
72
|
# Register a custom form field class
|
|
73
73
|
def form_field(name, klass)
|
|
@@ -83,7 +83,18 @@ module Trestle
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
# List of i18n keys to pass into the Trestle.i18n JavaScript object
|
|
86
|
-
option :javascript_i18n_keys, ["admin.confirmation.title", "admin.confirmation.delete", "admin.confirmation.cancel"]
|
|
86
|
+
option :javascript_i18n_keys, ["admin.confirmation.title", "admin.confirmation.delete", "admin.confirmation.cancel", "trestle.dialog.error", "admin.buttons.ok"]
|
|
87
|
+
|
|
88
|
+
# List of load paths for where to find admin definitions
|
|
89
|
+
option :load_paths, [
|
|
90
|
+
-> { ActiveSupport::Dependencies.autoload_paths.grep(/\/app\/admin\Z/) }
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## Debugging
|
|
95
|
+
|
|
96
|
+
# Enable debugging of form errors
|
|
97
|
+
option :debug_form_errors, Rails.env.development?
|
|
87
98
|
|
|
88
99
|
|
|
89
100
|
## Callbacks
|
data/lib/trestle/display.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Trestle
|
|
|
14
14
|
|
|
15
15
|
private
|
|
16
16
|
def display_method
|
|
17
|
-
@display_method ||= Trestle.config.display_methods.find { |m| @instance.respond_to?(m) }
|
|
17
|
+
@display_method ||= Trestle.config.display_methods.find { |m| @instance.respond_to?(m) } || :to_s
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
end
|