trestle 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
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'