trestle 0.8.2 → 0.8.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1da0a5de448522e343cd8c8f25e58f14533b7ea
4
- data.tar.gz: f52dc44dba3f0abc4f1d89c655f0c21c677a9dd1
3
+ metadata.gz: 64b62775f02866abaf0937d6a4e0bec5d86a1a31
4
+ data.tar.gz: 7707fa64f42e4c771721b9c306c143ce2614e18f
5
5
  SHA512:
6
- metadata.gz: 5c9e0a7742fb539291bec72dee7621a12a49fc84f46f60e8a864dc9ce67bfa0003b4e30a52e5e2d9c9b6507303b2f58c901faa8a36cf2a052225a0ffc061392e
7
- data.tar.gz: aa7b9b0cd797638546ad2bbdbc479950bdf4d9576871a1c8b72232eee753dd6fad01e24044bf7a9d5f81426e70a67903542afd8db6b29788ee4c771f3b96b69a
6
+ metadata.gz: a7bed2fddf9f950463693e7ec502aaf08439240a27075e61d2fc575381e165da4b0c407406d4a02990524c37ea9ce730a76886bea2c57ebee03b0ab935d34b51
7
+ data.tar.gz: c0dcd718a1bb3ac020924d09bd99f1658da42c7b53122af829822837a1a0c1631bfc942bb6a274d4301e7de5b4e90d00ad32cb242c30485abf88450ba3186dab
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  > A modern, responsive admin framework for Ruby on Rails
13
13
 
14
- <img src="https://trestle.io/images/Trestle-Screenshot-1.png?" width="50%" /><img src="https://trestle.io/images/Trestle-Screenshot-2.png?" width="50%" />
14
+ <img src="https://trestle.io/images/Trestle-Screenshot-1-1x.png?" width="50%" /><img src="https://trestle.io/images/Trestle-Screenshot-2-1x.png?" width="50%" />
15
15
 
16
16
 
17
17
  ## Getting Started
@@ -43,10 +43,10 @@ $headings-font-weight: 400 !default;
43
43
  $btn-default-bg: #dbdbdb !default;
44
44
  $btn-default-color: white !default;
45
45
 
46
- $state-success-bg: lighten(#dff0d8, 2.5%) !default;
47
- $state-info-bg: lighten(#d9edf7, 2.5%) !default;
48
- $state-warning-bg: lighten(#fcf8e3, 2.5%) !default;
49
- $state-danger-bg: lighten(#f2dede, 2.5%) !default;
46
+ $state-success-bg: lighten(#dff0d8, 5%) !default;
47
+ $state-info-bg: lighten(#d9edf7, 5%) !default;
48
+ $state-warning-bg: lighten(#fcf8e3, 5%) !default;
49
+ $state-danger-bg: lighten(#f2dede, 5%) !default;
50
50
 
51
51
  $alert-padding: 20px !default;
52
52
  $alert-border-radius: 2px !default;
@@ -3,6 +3,24 @@ class Trestle::ApplicationController < ActionController::Base
3
3
 
4
4
  layout 'trestle/admin'
5
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
+
6
24
  protected
7
25
  def breadcrumbs
8
26
  @breadcrumbs ||= Trestle::Breadcrumb::Trail.new(Trestle.config.root_breadcrumbs)
@@ -0,0 +1,24 @@
1
+ module Trestle
2
+ module ContainerHelper
3
+ def container(&block)
4
+ context = Context.new(self)
5
+ content = capture(context, &block)
6
+
7
+ content_tag(:div, class: "main-content-container") do
8
+ concat content_tag(:div, content, class: "main-content")
9
+ concat content_tag(:aside, context.sidebar, class: "main-content-sidebar") unless context.sidebar.blank?
10
+ end
11
+ end
12
+
13
+ class Context
14
+ def initialize(template)
15
+ @template = template
16
+ end
17
+
18
+ def sidebar(&block)
19
+ @sidebar = @template.capture(&block) if block_given?
20
+ @sidebar
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,7 +1,7 @@
1
1
  module Trestle
2
2
  module GridHelper
3
3
  def row
4
- content_tag(:div, class: 'row') { yield }
4
+ content_tag(:div, class: "row") { yield }
5
5
  end
6
6
 
7
7
  def col(columns)
@@ -1,8 +1,6 @@
1
1
  module Trestle
2
2
  module TableHelper
3
3
  def table(collection, options={}, &block)
4
- options = options.reverse_merge(admin: admin) if defined?(admin)
5
-
6
4
  table = Table::Builder.build(options, &block)
7
5
  render "trestle/table/table", table: table, collection: collection
8
6
  end
@@ -13,14 +13,15 @@ module Trestle
13
13
  end
14
14
 
15
15
  if admin
16
- link_to(content, admin_url_for(instance, admin), options)
16
+ link_to(content, admin_url_for(instance, admin: admin), options)
17
17
  else
18
18
  content
19
19
  end
20
20
  end
21
21
 
22
- def admin_url_for(instance, admin=self.admin)
23
- admin.path(:show, id: admin.to_param(instance)) if admin
22
+ def admin_url_for(instance, options={})
23
+ admin = Trestle.lookup(options[:admin] || self.admin)
24
+ admin.path(options[:action] || :show, id: admin.to_param(instance)) if admin
24
25
  end
25
26
 
26
27
  def admin_for(instance)
@@ -15,6 +15,7 @@
15
15
  <%= content_for(:title) %>
16
16
  </h1>
17
17
 
18
+ <% unless local_assigns.fetch(:hide_breadcrumbs, false) %>
18
19
  <ol class="breadcrumb">
19
20
  <% breadcrumbs.each do |breadcrumb| %>
20
21
  <li class="breadcrumb-item<% if breadcrumb == breadcrumbs.last %> active<% end %>">
@@ -22,4 +23,5 @@
22
23
  </li>
23
24
  <% end %>
24
25
  </ol>
26
+ <% end %>
25
27
  </header>
@@ -1,19 +1,19 @@
1
- <%= render "header" %>
1
+ <%= render "header", hide_breadcrumbs: local_assigns.fetch(:hide_breadcrumbs, false) if local_assigns.fetch(:header, true) %>
2
2
 
3
3
  <div class="main-content-area">
4
4
  <%= render "flash" %>
5
5
  <%= render "utilities" %>
6
6
  <%= render "tabs" %>
7
7
 
8
- <div class="main-content-container">
9
- <div class="main-content">
8
+ <% if local_assigns.fetch(:wrapper, true) %>
9
+ <%= container do |c| %>
10
10
  <%= yield %>
11
- </div>
12
11
 
13
- <% if content_for?(:sidebar) %>
14
- <aside class="main-content-sidebar">
12
+ <% c.sidebar do %>
15
13
  <%= content_for(:sidebar) %>
16
- </aside>
14
+ <% end if content_for?(:sidebar) %>
17
15
  <% end %>
18
- </div>
16
+ <% else %>
17
+ <%= yield %>
18
+ <% end %>
19
19
  </div>
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  Trestle::Engine.routes.draw do
2
- root to: "trestle/dashboard#index"
3
-
4
2
  Trestle.admins.each do |name, admin|
5
3
  instance_eval(&admin.routes)
6
4
  end
5
+
6
+ root to: "trestle/dashboard#index"
7
7
  end
@@ -0,0 +1,26 @@
1
+ module Trestle
2
+ module Generators
3
+ class AdminGenerator < ::Rails::Generators::NamedBase
4
+ desc "Creates a non-resourceful Trestle admin"
5
+
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def create_admin
9
+ template "admin.rb.erb", File.join("app/admin", class_path, "#{singular_name}_admin.rb")
10
+ end
11
+
12
+ def create_template
13
+ template "index.html.erb", File.join("app/views/admin", class_path, singular_name, "index.html.erb")
14
+ end
15
+
16
+ protected
17
+ def module_name
18
+ class_name.deconstantize
19
+ end
20
+
21
+ def module?
22
+ module_name.present?
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ Trestle.admin(:<%= singular_name %><% if module? %>, scope: <%= module_name %><% end %>) do
2
+ menu do
3
+ item :<%= singular_name %>, icon: "fa fa-star"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ <%% content_for(:title, "<%= singular_name.titleize %>") %>
2
+
3
+ <%%= render layout: "layout", locals: { wrapper: true, sidebar: false, hide_breadcrumbs: false } do %>
4
+ To customize this template, please edit <code><%= File.join("app/views/admin", class_path, singular_name, "index.html.erb") %></code>.
5
+ <%% end %>
@@ -53,6 +53,26 @@ Trestle.configure do |config|
53
53
 
54
54
  # == Extension Options
55
55
  #
56
+ # Specify helper modules to expose to the admin.
57
+ #
58
+ # config.helper :all
59
+
60
+ # Register callbacks to run before, after or around all Trestle actions.
61
+ #
62
+ # config.before_action do |controller|
63
+ # Rails.logger.debug("Before action")
64
+ # end
65
+ #
66
+ # config.after_action do |controller|
67
+ # Rails.logger.debug("After action")
68
+ # end
69
+ #
70
+ # config.around_action do |controller, block|
71
+ # Rails.logger.debug("Around action (before)")
72
+ # block.call
73
+ # Rails.logger.debug("Around ation (after)")
74
+ # end
75
+
56
76
  # Specify a custom hook to be injected into the admin.
57
77
  #
58
78
  # config.hook(:stylesheets) do
@@ -6,7 +6,7 @@ module Trestle
6
6
  source_root File.expand_path("../templates", __FILE__)
7
7
 
8
8
  def create_admin
9
- template "admin.rb.erb", File.join('app/admin', class_path, "#{plural_name}_admin.rb")
9
+ template "admin.rb.erb", File.join("app/admin", class_path, "#{plural_name}_admin.rb")
10
10
  end
11
11
 
12
12
  protected
@@ -37,12 +37,8 @@ module Trestle
37
37
  scope.merge(other)
38
38
  end
39
39
 
40
- def sort(collection, params)
41
- if params[:sort]
42
- collection.reorder(params[:sort] => params[:order] || "asc")
43
- else
44
- collection
45
- end
40
+ def sort(collection, field, order)
41
+ collection.reorder(field => order)
46
42
  end
47
43
 
48
44
  def paginate(collection, params)
@@ -9,6 +9,8 @@ module Trestle
9
9
  class_attribute :controller
10
10
  self.controller = Controller
11
11
 
12
+ delegate :helper, :before_action, :after_action, :around_action, to: :@controller
13
+
12
14
  def initialize(name, options={})
13
15
  # Create admin subclass
14
16
  @admin = Class.new(admin_class)
@@ -37,7 +39,7 @@ module Trestle
37
39
  end
38
40
 
39
41
  def table(options={}, &block)
40
- admin.table = Table::Builder.build(options.reverse_merge(sortable: true, admin: admin), &block)
42
+ admin.table = Table::Builder.build(options.reverse_merge(admin: admin, sortable: true), &block)
41
43
  end
42
44
 
43
45
  def form(&block)
@@ -50,18 +52,13 @@ module Trestle
50
52
  end
51
53
 
52
54
  def controller(&block)
53
- @controller.class_eval(&block)
55
+ @controller.class_eval(&block) if block_given?
56
+ @controller
54
57
  end
55
58
 
56
59
  def routes(&block)
57
60
  @admin.additional_routes = block
58
61
  end
59
-
60
- def helper(*helpers)
61
- controller do
62
- helper *helpers
63
- end
64
- end
65
62
  end
66
63
  end
67
64
  end
@@ -2,43 +2,116 @@ module Trestle
2
2
  class Configuration
3
3
  include Configurable
4
4
 
5
+ ## Customization Options
6
+
7
+ # Page title shown in the main admin header and <title> tag
5
8
  option :site_title, -> { I18n.t("trestle.title", default: "Trestle") }
6
- option :footer, -> { I18n.t("trestle.footer", default: "Powered by Trestle") }
7
9
 
10
+ # Custom image in place of the site title for mobile and expanded/desktop navigation
8
11
  option :site_logo
12
+
13
+ # Custom image for the collapsed/tablet navigation
9
14
  option :site_logo_small
10
15
 
11
- option :path, "/admin"
12
- option :automount, true
16
+ # Text shown in the admin page footer
17
+ option :footer, -> { I18n.t("trestle.footer", default: "Powered by Trestle") }
13
18
 
14
- option :turbolinks, defined?(Turbolinks)
15
19
 
16
- option :display_methods, [:display_name, :full_name, :name, :title, :username, :login, :email, :to_s]
20
+ ## Mounting Options
17
21
 
18
- option :persistent_params, [:sort, :order, :scope]
22
+ # Path at which to mount the Trestle admin
23
+ option :path, "/admin"
19
24
 
20
- option :default_adapter, Adapters::Adapter.compose(Adapters::ActiveRecordAdapter, Adapters::DraperAdapter)
25
+ # Automatically mount the admin within the Rails application's routes
26
+ option :automount, true
21
27
 
28
+
29
+ ## Navigation Options
30
+
31
+ # Initial breadcrumbs to display in the breadcrumb trail
22
32
  option :root_breadcrumbs, -> { [Trestle::Breadcrumb.new(I18n.t("admin.breadcrumbs.home", default: "Home"), Trestle.config.path)] }
23
33
 
34
+ # Default icon class to use when it is not explicitly provided
24
35
  option :default_navigation_icon, "fa fa-arrow-circle-o-right"
25
36
 
26
- option :javascript_i18n_keys, ["admin.confirmation.title", "admin.confirmation.delete", "admin.confirmation.cancel"]
27
-
37
+ # [Internal] List of navigation menu blocks
28
38
  option :menus, []
29
39
 
40
+ # Register a global navigation menu block
30
41
  def menu(&block)
31
42
  menus << Navigation::Block.new(&block)
32
43
  end
33
44
 
45
+
46
+ ## Extension Options
47
+
48
+ # [Internal] List of helper modules to include in all Trestle controllers
49
+ option :helpers, []
50
+
51
+ # [Internal] Container module for block-defined helpers
52
+ option :helper_module, Module.new
53
+
54
+ # Register global helpers available to all Trestle admins
55
+ def helper(*helpers, &block)
56
+ self.helpers += helpers
57
+ self.helper_module.module_eval(&block) if block_given?
58
+ end
59
+
60
+ # Enable or disable Turbolinks within the Trestle admin
61
+ option :turbolinks, defined?(Turbolinks)
62
+
63
+ # List of parameters that should persist across requests when paginating or reordering
64
+ option :persistent_params, [:sort, :order, :scope]
65
+
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, :to_s]
68
+
69
+ # Default adapter class used by all admin resources
70
+ option :default_adapter, Adapters::Adapter.compose(Adapters::ActiveRecordAdapter, Adapters::DraperAdapter)
71
+
72
+ # Register a custom form field class
73
+ def form_field(name, klass)
74
+ Form::Builder.register(name, klass)
75
+ end
76
+
77
+ # [Internal] List of registered hooks
34
78
  option :hooks, Hash.new { |h, k| h[k] = [] }
35
79
 
80
+ # Register an extension hook
36
81
  def hook(name, &block)
37
82
  hooks[name.to_s] << block
38
83
  end
39
84
 
40
- def form_field(name, klass)
41
- Form::Builder.register(name, klass)
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"]
87
+
88
+
89
+ ## Callbacks
90
+
91
+ Action = Struct.new(:options, :block)
92
+
93
+ # [Internal] List of global before actions
94
+ option :before_actions, []
95
+
96
+ # Register a global before action
97
+ def before_action(options={}, &block)
98
+ before_actions << Action.new(options, block)
99
+ end
100
+
101
+ # [Internal] List of global after actions
102
+ option :after_actions, []
103
+
104
+ # Register a global after action
105
+ def after_action(options={}, &block)
106
+ after_actions << Action.new(options, block)
107
+ end
108
+
109
+ # [Internal] List of global around actions
110
+ option :around_actions, []
111
+
112
+ # Register a global around action
113
+ def around_action(options={}, &block)
114
+ around_actions << Action.new(options, block)
42
115
  end
43
116
  end
44
117
  end
@@ -62,6 +62,10 @@ module Trestle
62
62
  admin.sort = block
63
63
  end
64
64
 
65
+ def sort_column(column, &block)
66
+ admin.column_sorts[column.to_sym] = block
67
+ end
68
+
65
69
  def paginate(&block)
66
70
  admin.paginate = block
67
71
  end
@@ -49,7 +49,7 @@ module Trestle
49
49
  def prepare_collection(params)
50
50
  collection = initialize_collection(params)
51
51
  collection = apply_scopes(collection, params)
52
- collection = sort(collection, params)
52
+ collection = apply_sorting(collection, params)
53
53
  collection = paginate(collection, params)
54
54
  collection = decorate_collection(collection)
55
55
  collection
@@ -87,6 +87,25 @@ module Trestle
87
87
  result
88
88
  end
89
89
 
90
+ def column_sorts
91
+ @column_sorts ||= {}
92
+ end
93
+
94
+ def apply_sorting(collection, params)
95
+ return collection unless params[:sort]
96
+
97
+ field = params[:sort].to_sym
98
+
99
+ order = params[:order].downcase
100
+ order = "asc" unless %w(asc desc).include?(order)
101
+
102
+ if column_sorts.has_key?(field)
103
+ instance_exec(collection, order, &column_sorts[field])
104
+ else
105
+ sort(collection, field, order)
106
+ end
107
+ end
108
+
90
109
  def table
91
110
  super || Table::Automatic.new(self)
92
111
  end
@@ -129,7 +148,7 @@ module Trestle
129
148
  def infer_model_class
130
149
  parent.const_get(admin_name.classify)
131
150
  rescue NameError
132
- nil
151
+ raise NameError, "Unable to find model #{admin_name.classify}. Specify a different model using Trestle.resource(:#{admin_name}, model: MyModel)"
133
152
  end
134
153
 
135
154
  def default_model_name
@@ -19,22 +19,25 @@ module Trestle
19
19
  end
20
20
 
21
21
  class ActionsBuilder
22
- attr_reader :template, :instance
22
+ attr_reader :instance
23
23
 
24
- def initialize(template, instance)
25
- @template, @instance = template, instance
24
+ delegate :table, to: :@column
25
+
26
+ def initialize(column, template, instance)
27
+ @column, @template, @instance = column, template, instance
28
+ end
29
+
30
+ def delete
31
+ button(@template.icon("fa fa-trash"), @template.admin_url_for(instance, admin: table.options[:admin], action: :destroy), method: :delete, class: "btn-danger", data: { toggle: "confirm-delete", placement: "left" })
26
32
  end
27
33
 
28
34
  def button(content, url, options={})
29
35
  options[:class] = Array(options[:class])
30
36
  options[:class] << "btn" unless options[:class].include?("btn")
31
37
 
32
- template.concat template.link_to(content, url, options)
33
- end
34
-
35
- def delete
36
- button(template.icon("fa fa-trash"), template.admin.path(:destroy, id: template.admin.to_param(instance)), method: :delete, class: "btn-danger", data: { toggle: "confirm-delete", placement: "left" })
38
+ @template.concat @template.link_to(content, url, options)
37
39
  end
40
+ alias_method :link, :button
38
41
  end
39
42
 
40
43
  class Renderer < Column::Renderer
@@ -54,7 +57,7 @@ module Trestle
54
57
  end
55
58
 
56
59
  def content(instance)
57
- builder = ActionsBuilder.new(@template, instance)
60
+ builder = ActionsBuilder.new(@column, @template, instance)
58
61
 
59
62
  @template.with_output_buffer do
60
63
  @template.instance_exec(builder, &@column.block)
@@ -8,7 +8,7 @@ module Trestle
8
8
  end
9
9
 
10
10
  def row(options={}, &block)
11
- table.row = Row.new(options, &block)
11
+ table.row = Row.new(table, options, &block)
12
12
  end
13
13
 
14
14
  def selectable_column
@@ -1,10 +1,10 @@
1
1
  module Trestle
2
2
  class Table
3
3
  class Row
4
- attr_reader :options, :block
4
+ attr_reader :table, :options, :block
5
5
 
6
- def initialize(options={}, &block)
7
- @options = options
6
+ def initialize(table, options={}, &block)
7
+ @table, @options = table, options
8
8
  @block = block if block_given?
9
9
  end
10
10
 
@@ -13,16 +13,24 @@ module Trestle
13
13
  end
14
14
 
15
15
  class Renderer
16
+ delegate :table, to: :@row
17
+
16
18
  def initialize(row, template)
17
19
  @row, @template = row, template
18
20
  end
19
21
 
20
22
  def options(instance)
21
- options = Trestle::Options.new(data: { url: @template.admin_url_for(instance) })
23
+ options = Trestle::Options.new
24
+ options.merge!(data: { url: admin_url_for(instance) }) if table.options[:admin]
22
25
  options.merge!(@row.options)
23
26
  options.merge!(@template.instance_exec(instance, &@row.block)) if @row.block
24
27
  options
25
28
  end
29
+
30
+ protected
31
+ def admin_url_for(instance)
32
+ @template.admin_url_for(instance, admin: table.options[:admin])
33
+ end
26
34
  end
27
35
  end
28
36
  end
data/lib/trestle/table.rb CHANGED
@@ -26,7 +26,7 @@ module Trestle
26
26
  end
27
27
 
28
28
  def row
29
- @row || Row.new
29
+ @row || Row.new(self)
30
30
  end
31
31
 
32
32
  class Renderer
@@ -1,3 +1,3 @@
1
1
  module Trestle
2
- VERSION = "0.8.2"
2
+ VERSION = "0.8.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trestle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Pohlenz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-31 00:00:00.000000000 Z
11
+ date: 2017-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -230,6 +230,7 @@ files:
230
230
  - app/controllers/trestle/application_controller.rb
231
231
  - app/controllers/trestle/dashboard_controller.rb
232
232
  - app/helpers/trestle/avatar_helper.rb
233
+ - app/helpers/trestle/container_helper.rb
233
234
  - app/helpers/trestle/display_helper.rb
234
235
  - app/helpers/trestle/form_helper.rb
235
236
  - app/helpers/trestle/grid_helper.rb
@@ -277,6 +278,9 @@ files:
277
278
  - config/locales/en.rb
278
279
  - config/locales/en.yml
279
280
  - config/routes.rb
281
+ - lib/generators/trestle/admin/admin_generator.rb
282
+ - lib/generators/trestle/admin/templates/admin.rb.erb
283
+ - lib/generators/trestle/admin/templates/index.html.erb
280
284
  - lib/generators/trestle/install/install_generator.rb
281
285
  - lib/generators/trestle/install/templates/_custom.scss
282
286
  - lib/generators/trestle/install/templates/_variables.scss