trestle 0.8.6 → 0.8.7

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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +10 -9
  3. data/app/assets/javascripts/trestle/components/_dialog.js +29 -8
  4. data/app/assets/javascripts/trestle/components/_form.js +28 -7
  5. data/app/assets/javascripts/trestle/components/_sidebar.js +10 -8
  6. data/app/assets/javascripts/trestle/components/_tabs.js +2 -1
  7. data/app/assets/javascripts/trestle/components/_tooltips.js +16 -0
  8. data/app/assets/stylesheets/trestle/components/_modal.scss +4 -0
  9. data/app/assets/stylesheets/trestle/components/_navigation.scss +31 -11
  10. data/app/assets/stylesheets/trestle/components/_sidebar.scss +2 -2
  11. data/app/assets/stylesheets/trestle/components/_tags.scss +9 -0
  12. data/app/assets/stylesheets/trestle/components/_wells.scss +9 -1
  13. data/app/assets/stylesheets/trestle/core/_defaults.scss +4 -4
  14. data/app/assets/stylesheets/trestle/core/_layout.scss +8 -0
  15. data/app/assets/stylesheets/trestle/core/_typography.scss +39 -0
  16. data/app/controllers/concerns/trestle/controller/breadcrumbs.rb +21 -0
  17. data/app/controllers/concerns/trestle/controller/callbacks.rb +21 -0
  18. data/app/controllers/concerns/trestle/controller/dialog.rb +16 -0
  19. data/app/controllers/concerns/trestle/controller/helpers.rb +18 -0
  20. data/app/controllers/concerns/trestle/controller/layout.rb +16 -0
  21. data/app/controllers/concerns/trestle/controller/location.rb +15 -0
  22. data/app/controllers/trestle/application_controller.rb +6 -34
  23. data/app/helpers/trestle/debug_helper.rb +11 -0
  24. data/app/helpers/trestle/format_helper.rb +7 -3
  25. data/app/helpers/trestle/headings_helper.rb +27 -0
  26. data/app/helpers/trestle/panel_helper.rb +24 -0
  27. data/app/helpers/trestle/table_helper.rb +41 -2
  28. data/app/helpers/trestle/url_helper.rb +3 -1
  29. data/app/views/layouts/trestle/admin.html.erb +1 -1
  30. data/app/views/trestle/application/_flash.html.erb +1 -1
  31. data/app/views/trestle/shared/_sidebar.html.erb +2 -2
  32. data/app/views/trestle/table/_table.html.erb +2 -6
  33. data/lib/generators/trestle/resource/templates/admin.rb.erb +2 -2
  34. data/lib/trestle.rb +6 -4
  35. data/lib/trestle/adapters/active_record_adapter.rb +0 -4
  36. data/lib/trestle/adapters/adapter.rb +15 -10
  37. data/lib/trestle/adapters/sequel_adapter.rb +0 -4
  38. data/lib/trestle/admin.rb +18 -1
  39. data/lib/trestle/admin/builder.rb +22 -10
  40. data/lib/trestle/form/automatic.rb +5 -2
  41. data/lib/trestle/form/builder.rb +5 -1
  42. data/lib/trestle/form/field.rb +1 -1
  43. data/lib/trestle/form/fields/form_group.rb +3 -1
  44. data/lib/trestle/form/fields/select.rb +5 -1
  45. data/lib/trestle/form/fields/tag_select.rb +1 -1
  46. data/lib/trestle/form/renderer.rb +1 -1
  47. data/lib/trestle/navigation.rb +11 -5
  48. data/lib/trestle/navigation/item.rb +10 -0
  49. data/lib/trestle/resource.rb +27 -61
  50. data/lib/trestle/resource/builder.rb +15 -14
  51. data/lib/trestle/resource/collection.rb +48 -0
  52. data/lib/trestle/resource/controller.rb +36 -23
  53. data/lib/trestle/scope.rb +13 -3
  54. data/lib/trestle/table.rb +10 -4
  55. data/lib/trestle/table/column.rb +13 -2
  56. data/lib/trestle/table/row.rb +10 -0
  57. data/lib/trestle/version.rb +1 -1
  58. data/trestle.gemspec +1 -0
  59. data/vendor/assets/stylesheets/trestle/magnific-popup.scss +13 -1
  60. metadata +27 -4
  61. data/app/helpers/trestle/dialog_helper.rb +0 -7
@@ -0,0 +1,21 @@
1
+ module Trestle
2
+ module Controller
3
+ module Breadcrumbs
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :breadcrumbs
8
+ helper_method :breadcrumb
9
+ end
10
+
11
+ protected
12
+ def breadcrumbs
13
+ @breadcrumbs ||= Trestle::Breadcrumb::Trail.new(Trestle.config.root_breadcrumbs)
14
+ end
15
+
16
+ def breadcrumb(label, path=nil)
17
+ breadcrumbs.append(label, path)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Trestle
2
+ module Controller
3
+ module Callbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ Trestle.config.before_actions.each do |action|
8
+ before_action(action.options, &action.block)
9
+ end
10
+
11
+ Trestle.config.after_actions.each do |action|
12
+ after_action(action.options, &action.block)
13
+ end
14
+
15
+ Trestle.config.around_actions.each do |action|
16
+ around_action(action.options, &action.block)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Trestle
2
+ module Controller
3
+ module Dialog
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :dialog_request?
8
+ end
9
+
10
+ protected
11
+ def dialog_request?
12
+ request.headers["X-Trestle-Dialog"]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Trestle
2
+ module Controller
3
+ module Helpers
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Allow inclusion of helpers from Rails application
8
+ self.helpers_path += Rails.application.helpers_paths
9
+
10
+ # Add helpers declared from configuration as blocks
11
+ helper Trestle.config.helper_module
12
+
13
+ # Add helpers declared from configuration as module references
14
+ helper *Trestle.config.helpers
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module Trestle
2
+ module Controller
3
+ module Layout
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ layout :choose_layout
8
+ end
9
+
10
+ protected
11
+ def choose_layout
12
+ request.xhr? ? false : "trestle/admin"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Trestle
2
+ module Controller
3
+ module Location
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ after_action :set_trestle_location_header, unless: :dialog_request?
8
+ end
9
+
10
+ def set_trestle_location_header
11
+ headers["X-Trestle-Location"] = request.path
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,38 +1,10 @@
1
1
  class Trestle::ApplicationController < ActionController::Base
2
2
  protect_from_forgery
3
3
 
4
- layout :choose_layout
5
-
6
- # Global helpers
7
- self.helpers_path += Rails.application.helpers_paths
8
- helper Trestle.config.helper_module
9
- helper *Trestle.config.helpers
10
-
11
- # Global callbacks
12
- Trestle.config.before_actions.each do |action|
13
- before_action(action.options, &action.block)
14
- end
15
-
16
- Trestle.config.after_actions.each do |action|
17
- after_action(action.options, &action.block)
18
- end
19
-
20
- Trestle.config.around_actions.each do |action|
21
- around_action(action.options, &action.block)
22
- end
23
-
24
- protected
25
- def breadcrumbs
26
- @breadcrumbs ||= Trestle::Breadcrumb::Trail.new(Trestle.config.root_breadcrumbs)
27
- end
28
- helper_method :breadcrumbs
29
-
30
- def breadcrumb(label, path=nil)
31
- breadcrumbs.append(label, path)
32
- end
33
- helper_method :breadcrumb
34
-
35
- def choose_layout
36
- request.xhr? ? false : "trestle/admin"
37
- end
4
+ include Trestle::Controller::Breadcrumbs
5
+ include Trestle::Controller::Callbacks
6
+ include Trestle::Controller::Dialog
7
+ include Trestle::Controller::Helpers
8
+ include Trestle::Controller::Layout
9
+ include Trestle::Controller::Location
38
10
  end
@@ -0,0 +1,11 @@
1
+ module Trestle
2
+ module DebugHelper
3
+ def debug_form_errors?
4
+ Trestle.config.debug_form_errors && instance_has_errors?
5
+ end
6
+
7
+ def instance_has_errors?
8
+ @instance && @instance.respond_to?(:errors) && @instance.errors.any?
9
+ end
10
+ end
11
+ end
@@ -13,7 +13,7 @@ module Trestle
13
13
  when :currency
14
14
  number_to_currency(value)
15
15
  when :tags
16
- safe_join(value.map { |tag| content_tag(:span, tag, class: "tag") })
16
+ safe_join(Array(value).map { |tag| content_tag(:span, tag, class: "tag") })
17
17
  else
18
18
  value
19
19
  end
@@ -30,8 +30,12 @@ module Trestle
30
30
  when TrueClass, FalseClass
31
31
  status_tag(icon("fa fa-check"), :success) if value
32
32
  when NilClass
33
- text = options.key?(:blank) ? options[:blank] : I18n.t("admin.format.blank")
34
- content_tag(:span, text, class: "blank")
33
+ blank = options.key?(:blank) ? options[:blank] : I18n.t("admin.format.blank")
34
+ if blank.respond_to?(:call)
35
+ instance_exec(&blank)
36
+ else
37
+ content_tag(:span, blank, class: "blank")
38
+ end
35
39
  when String
36
40
  if value.html_safe? || options[:truncate] == false
37
41
  value
@@ -0,0 +1,27 @@
1
+ module Trestle
2
+ module HeadingsHelper
3
+ def h1(text, options={})
4
+ content_tag(:h1, text, options)
5
+ end
6
+
7
+ def h2(text, options={})
8
+ content_tag(:h2, text, options)
9
+ end
10
+
11
+ def h3(text, options={})
12
+ content_tag(:h3, text, options)
13
+ end
14
+
15
+ def h4(text, options={})
16
+ content_tag(:h4, text, options)
17
+ end
18
+
19
+ def h5(text, options={})
20
+ content_tag(:h5, text, options)
21
+ end
22
+
23
+ def h6(text, options={})
24
+ content_tag(:h6, text, options)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ module Trestle
2
+ module PanelHelper
3
+ def panel(options={}, &block)
4
+ html_class = options.fetch(:class) { "panel-default" }
5
+
6
+ content_tag(:div, class: ["panel", html_class]) do
7
+ if options[:title]
8
+ concat content_tag(:div, options[:title], class: "panel-heading")
9
+ end
10
+
11
+ concat content_tag(:div, class: "panel-body", &block)
12
+
13
+ if options[:footer]
14
+ concat content_tag(:div, options[:footer], class: "panel-footer")
15
+ end
16
+ end
17
+ end
18
+
19
+ def well(options={}, &block)
20
+ html_class = ["well", options[:class]].compact
21
+ content_tag(:div, options.merge(class: html_class), &block)
22
+ end
23
+ end
24
+ end
@@ -1,7 +1,46 @@
1
1
  module Trestle
2
2
  module TableHelper
3
- def table(collection, options={}, &block)
4
- table = Table::Builder.build(options, &block)
3
+ # Renders an existing named table or builds and renders a custom table if a block is provided.
4
+ #
5
+ # name - The (optional) name of the table to render (as a Symbol), or the actual Trestle::Table instance itself.
6
+ # options - Hash of options that will be passed to the table builder (default: {}):
7
+ # :collection - The collection that should be rendered within the table. It should be an
8
+ # Array-like object, but will most likely be an ActiveRecord scope. It can
9
+ # also be a callable object (i.e. a Proc) in which case the result of calling
10
+ # the block will be used as the collection.
11
+ # See Trestle::Table::Builder for additional options.
12
+ # block - An optional block that is passed to Trestle::Table::Builder to define a custom table.
13
+ # One of either the name or block must be provided, but not both.
14
+ #
15
+ # Examples
16
+ #
17
+ # <%= table collection: -> { Account.all }, admin: :accounts do %>
18
+ # <% column(:name) %>
19
+ # <% column(:balance) { |account| account.balance.format } %>
20
+ # <% column(:created_at, align: :center)
21
+ # <% end %>
22
+ #
23
+ # <%= table :accounts %>
24
+ #
25
+ # Returns the HTML representation of the table as a HTML-safe String.
26
+ def table(name=nil, options={}, &block)
27
+ if block_given?
28
+ if name.is_a?(Hash)
29
+ options = name
30
+ else
31
+ collection = name
32
+ end
33
+
34
+ table = Table::Builder.build(options, &block)
35
+ elsif name.is_a?(Trestle::Table)
36
+ table = name
37
+ else
38
+ table = admin.tables.fetch(name) { raise ArgumentError, "Unable to find table named #{name.inspect}" }
39
+ end
40
+
41
+ collection ||= options[:collection] || table.options[:collection]
42
+ collection = collection.call if collection.respond_to?(:call)
43
+
5
44
  render "trestle/table/table", table: table, collection: collection
6
45
  end
7
46
  end
@@ -1,5 +1,7 @@
1
1
  module Trestle
2
2
  module UrlHelper
3
+ DIALOG_ACTIONS = [:new, :show, :edit]
4
+
3
5
  def admin_link_to(content, instance_or_url=nil, options={}, &block)
4
6
  if block_given?
5
7
  instance_or_url, options = content, instance_or_url || {}
@@ -27,7 +29,7 @@ module Trestle
27
29
  params = options.delete(:params) || {}
28
30
  params[:id] ||= admin.to_param(instance_or_url) if instance_or_url
29
31
 
30
- if [:show, :edit].include?(action) && admin.form.dialog?
32
+ if DIALOG_ACTIONS.include?(action) && admin.form.dialog?
31
33
  options[:data] ||= {}
32
34
  options[:data][:behavior] ||= "dialog"
33
35
  end
@@ -38,7 +38,7 @@
38
38
  <%= hook :head %>
39
39
  </head>
40
40
 
41
- <body>
41
+ <body<%= " class=\"sidebar-#{cookies["trestle:sidebar"]}\"" if cookies["trestle:sidebar"] %>>
42
42
  <div class="app-wrapper">
43
43
  <%= render "trestle/shared/sidebar" %>
44
44
 
@@ -11,7 +11,7 @@
11
11
  title: t("trestle.flash.failure.title", default: "Warning!"),
12
12
  message: flash[:error]
13
13
  } do %>
14
- <%- if Trestle.config.debug_form_errors && instance && instance.errors.any? -%>
14
+ <%- if debug_form_errors? -%>
15
15
  <%= link_to "Debug errors", "#debug-errors", class: "toggle-debug-errors small", data: { toggle: "collapse" } %>
16
16
  <div id="debug-errors" class="debug-errors collapse">
17
17
  <ul>
@@ -1,4 +1,4 @@
1
- <aside class="app-sidebar<%= " #{cookies["trestle:sidebar"]}" if cookies["trestle:sidebar"] %>">
1
+ <aside class="app-sidebar">
2
2
  <header class="app-sidebar-header">
3
3
  <button class="navbar-toggle">
4
4
  <span class="sr-only"><%= t("admin.ui.toggle_navigation", default: "Toggle navigation") %></span>
@@ -13,7 +13,7 @@
13
13
  <div class="app-sidebar-inner">
14
14
  <nav class="app-nav">
15
15
  <% collapsed = cookies["trestle:navigation:collapsed"].try(:split, ",") || [] %>
16
- <% Trestle.navigation.each do |group, items| %>
16
+ <% Trestle.navigation.visible(self).each do |group, items| %>
17
17
  <ul<% if group.present? && collapsed.include?(group.id) %> class="collapsed"<% end %>>
18
18
  <% if group.present? %>
19
19
  <li class="nav-header"><%= link_to group.label, "##{group.id}" %></li>
@@ -1,7 +1,7 @@
1
1
  <% table = table.renderer(self) %>
2
2
 
3
3
  <div class="table-container">
4
- <%= content_tag(:table, class: table.classes, data: table.data) do %>
4
+ <%= content_tag(:table, id: table.id, class: table.classes, data: table.data) do %>
5
5
  <thead>
6
6
  <tr>
7
7
  <% table.columns.each do |column| %>
@@ -12,11 +12,7 @@
12
12
 
13
13
  <tbody>
14
14
  <% collection.each do |instance| %>
15
- <%= content_tag(:tr, table.row.options(instance)) do %>
16
- <% table.columns.each do |column| %>
17
- <%= content_tag(:td, column.content(instance), class: column.classes, data: column.data) %>
18
- <% end %>
19
- <% end %>
15
+ <%= table.row.render(instance) %>
20
16
  <% end %>
21
17
  </tbody>
22
18
  <% end %>
@@ -13,7 +13,7 @@ Trestle.resource(:<%= plural_name %><% if module? %>, scope: <%= module_name %><
13
13
 
14
14
  # Customize the form fields shown on the new/edit views.
15
15
  #
16
- # form do |<%= singular_name %>|
16
+ # form do |<%= singular_table_name %>|
17
17
  # text_field :name
18
18
  #
19
19
  # row do
@@ -30,6 +30,6 @@ Trestle.resource(:<%= plural_name %><% if module? %>, scope: <%= module_name %><
30
30
  # http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
31
31
  #
32
32
  # params do |params|
33
- # params.require(:<%= singular_name %>).permit(:name, ...)
33
+ # params.require(:<%= singular_table_name %>).permit(:name, ...)
34
34
  # end
35
35
  end
data/lib/trestle.rb CHANGED
@@ -31,12 +31,14 @@ module Trestle
31
31
  self.admins = {}
32
32
 
33
33
  def self.admin(name, options={}, &block)
34
- admin = Admin::Builder.build(name, options, &block)
35
- self.admins[admin.admin_name] = admin
34
+ register(Admin::Builder.create(name, options, &block))
36
35
  end
37
36
 
38
37
  def self.resource(name, options={}, &block)
39
- admin = Resource::Builder.build(name, options, &block)
38
+ register(Resource::Builder.create(name, options, &block))
39
+ end
40
+
41
+ def self.register(admin)
40
42
  self.admins[admin.admin_name] = admin
41
43
  end
42
44
 
@@ -54,7 +56,7 @@ module Trestle
54
56
  end
55
57
 
56
58
  def self.navigation
57
- Navigation.new(config.menus + admins.values.map(&:menu).compact)
59
+ Navigation.build(config.menus + admins.values.map(&:menu).compact)
58
60
  end
59
61
  end
60
62
 
@@ -25,10 +25,6 @@ module Trestle
25
25
  instance.destroy
26
26
  end
27
27
 
28
- def unscope(scope)
29
- scope.unscoped
30
- end
31
-
32
28
  def merge_scopes(scope, other)
33
29
  scope.merge(other)
34
30
  end
@@ -61,6 +61,18 @@ module Trestle
61
61
  raise NotImplementedError
62
62
  end
63
63
 
64
+ # Finalizes a collection so that it can be rendered within the index view.
65
+ #
66
+ # In most cases (e.g. ActiveRecord), no finalization is required. However if you are using a search library then
67
+ # you may need to explicitly execute the search, or access the models via a #records or #objects method.
68
+ #
69
+ # collection - The collection to finalize
70
+ #
71
+ # Returns an enumerable collection of instances.
72
+ def finalize_collection(collection)
73
+ collection
74
+ end
75
+
64
76
  # Decorates a collection for rendering by the index view.
65
77
  # Decorating is the final step in preparing the collection for the view.
66
78
  #
@@ -82,15 +94,6 @@ module Trestle
82
94
  instance.id
83
95
  end
84
96
 
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
97
  # Merges scopes together for Trestle scope application and counting.
95
98
  #
96
99
  # scope - The first scope
@@ -131,7 +134,9 @@ module Trestle
131
134
  # Returns a Kaminari-compatible scope corresponding to a single page.
132
135
  def paginate(collection, params)
133
136
  collection = Kaminari.paginate_array(collection.to_a) unless collection.respond_to?(:page)
134
- collection.page(params[:page])
137
+ per_page = admin.pagination_options[:per]
138
+
139
+ collection.page(params[:page]).per(per_page)
135
140
  end
136
141
 
137
142
  # Filters the submitted form parameters and returns a whitelisted attributes 'hash'