crud_components 0.2.1 → 0.3.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/README.md +39 -2
  4. data/app/assets/stylesheets/crud_components_admin.css +13 -0
  5. data/app/controllers/crud_components/admin/application_controller.rb +100 -0
  6. data/app/controllers/crud_components/admin/dashboard_controller.rb +10 -0
  7. data/app/controllers/crud_components/admin/resources_controller.rb +184 -0
  8. data/app/views/crud_components/admin/_sidebar.html.erb +20 -0
  9. data/app/views/crud_components/admin/dashboard/show.html.erb +22 -0
  10. data/app/views/crud_components/admin/resources/_dependent_records.html.erb +16 -0
  11. data/app/views/crud_components/admin/resources/delete.html.erb +98 -0
  12. data/app/views/crud_components/admin/resources/edit.html.erb +14 -0
  13. data/app/views/crud_components/admin/resources/index.html.erb +26 -0
  14. data/app/views/crud_components/admin/resources/new.html.erb +14 -0
  15. data/app/views/crud_components/admin/resources/show.html.erb +16 -0
  16. data/app/views/layouts/crud_components/admin.html.erb +41 -0
  17. data/config/locales/crud_components.de.yml +31 -0
  18. data/config/locales/crud_components.en.yml +31 -0
  19. data/docs/admin.md +321 -0
  20. data/docs/fields.md +1 -1
  21. data/docs/views.md +14 -0
  22. data/lib/crud_components/admin/configuration.rb +122 -0
  23. data/lib/crud_components/admin/dependents.rb +138 -0
  24. data/lib/crud_components/admin/engine.rb +22 -0
  25. data/lib/crud_components/admin/entry.rb +123 -0
  26. data/lib/crud_components/admin/gate.rb +40 -0
  27. data/lib/crud_components/admin/registry.rb +176 -0
  28. data/lib/crud_components/admin/routes.rb +37 -0
  29. data/lib/crud_components/admin/view_helpers.rb +156 -0
  30. data/lib/crud_components/admin.rb +92 -0
  31. data/lib/crud_components/builder.rb +56 -1
  32. data/lib/crud_components/helpers.rb +35 -4
  33. data/lib/crud_components/presenters/collection.rb +16 -4
  34. data/lib/crud_components/presenters/record.rb +14 -2
  35. data/lib/crud_components/route_resolver.rb +37 -7
  36. data/lib/crud_components/structure.rb +8 -1
  37. data/lib/crud_components/version.rb +1 -1
  38. data/lib/crud_components.rb +2 -0
  39. metadata +24 -1
@@ -0,0 +1,92 @@
1
+ require_relative 'admin/configuration'
2
+ require_relative 'admin/dependents'
3
+ require_relative 'admin/entry'
4
+ require_relative 'admin/gate'
5
+ require_relative 'admin/registry'
6
+ require_relative 'admin/view_helpers'
7
+
8
+ module CrudComponents
9
+ # The optional, mountable admin UI:
10
+ #
11
+ # mount CrudComponents::Admin::Engine => '/admin'
12
+ #
13
+ # See docs/admin.md.
14
+ module Admin
15
+ class Error < CrudComponents::Error; end
16
+
17
+ # Raised when the admin has no way to tell who may in: `auth_with :cancan`
18
+ # and nothing that answers `can?`.
19
+ class UnauthorizedError < Error; end
20
+
21
+ # Raised when the ability denies the action behind the request. Rendered as
22
+ # 403 by the engine's controllers.
23
+ class ForbiddenError < Error; end
24
+
25
+ class << self
26
+ def config
27
+ @config ||= Configuration.new
28
+ end
29
+
30
+ def configure
31
+ yield config
32
+ registry.reload!
33
+ config
34
+ end
35
+
36
+ def registry
37
+ @registry ||= Registry.new(config)
38
+ end
39
+
40
+ # Drops both the configuration and the resolved registry.
41
+ def reset!
42
+ @config = nil
43
+ @registry = nil
44
+ @mount_path = nil
45
+ end
46
+
47
+ # The admin layout's own stylesheet, read once from the packaged file.
48
+ def bundled_css
49
+ @bundled_css ||= File.read(
50
+ File.expand_path('../../app/assets/stylesheets/crud_components_admin.css', __dir__)
51
+ )
52
+ end
53
+
54
+ # Where the host mounted the engine, or nil when it did not.
55
+ def mount_path
56
+ return @mount_path if @mount_path
57
+ return nil unless defined?(Engine) && defined?(Rails) && Rails.application
58
+
59
+ route = Rails.application.routes.routes.find do |candidate|
60
+ candidate.app.respond_to?(:app) && candidate.app.app == Engine
61
+ end
62
+ path = route&.path&.spec.to_s
63
+ @mount_path = path == '/' ? '' : path.presence
64
+ end
65
+
66
+ # The admin's path for a record (or a model class, for its index), or nil
67
+ # when the admin isn't mounted, the model isn't registered, or the action
68
+ # is not enabled for it.
69
+ def path_for(subject, action = :show)
70
+ model = subject.is_a?(Class) ? subject : subject.class
71
+ entry = registry[model]
72
+ return nil unless entry&.allows?(action) && mount_path
73
+
74
+ helper, args = helper_for(entry, action, subject)
75
+ return nil unless Engine.routes.url_helpers.respond_to?(helper)
76
+
77
+ Engine.routes.url_helpers.public_send(helper, *args, script_name: mount_path)
78
+ end
79
+
80
+ private
81
+
82
+ def helper_for(entry, action, subject)
83
+ case action.to_sym
84
+ when :index then ["#{entry.route_key}_path", []]
85
+ when :new then ["new_#{entry.singular_route_key}_path", []]
86
+ when :edit then ["edit_#{entry.singular_route_key}_path", [subject]]
87
+ else ["#{entry.singular_route_key}_path", [subject]]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -18,7 +18,8 @@ module CrudComponents
18
18
  class Builder
19
19
  attr_reader :model, :declarations, :actions, :fieldsets,
20
20
  :label_decl, :identify_by_decl, :search_decl,
21
- :label_preload_decl, :preload_decl, :icon_decl
21
+ :label_preload_decl, :preload_decl, :icon_decl, :admin_decl,
22
+ :app_path_decl
22
23
 
23
24
  # @param model [Class] the ActiveRecord model being described.
24
25
  # @yield the `crud_structure` block, evaluated against this Builder.
@@ -151,8 +152,62 @@ module CrudComponents
151
152
  @fieldsets[name] = Fieldset.new(name, fields, actions: actions, filters: filters)
152
153
  end
153
154
 
155
+ # The host application's own page for a record, when it is not the
156
+ # conventional route (`main_app.book_path(book)`). Runs in the view
157
+ # context; return nil to suppress the link for a record.
158
+ # app_path { |book| main_app.publisher_book_path(book.publisher, book) }
159
+ # @yield [record] the record to link to.
160
+ # @return [void]
161
+ def app_path(&block)
162
+ raise DefinitionError, "#{model}: app_path requires a block" unless block
163
+ raise DefinitionError, "#{model}: app_path declared twice" if defined?(@app_path_decl) && @app_path_decl
164
+
165
+ @app_path_decl = block
166
+ end
167
+
168
+ # How this model appears in the mounted admin UI (inert without it).
169
+ # @param enabled [Boolean] `false` keeps the model out of the admin entirely.
170
+ # @param options [Hash] `actions:` (a subset of
171
+ # `%i[index show new create edit update destroy]`), `group:`, `label:`,
172
+ # `fieldset:`, `scope:` (a callable narrowing the base relation).
173
+ # @return [void]
174
+ def admin(enabled = true, **options)
175
+ raise DefinitionError, "#{model}: admin declared twice" if defined?(@admin_decl) && !@admin_decl.nil?
176
+
177
+ unless [true, false].include?(enabled)
178
+ raise DefinitionError, "#{model}: admin takes true or false, got #{enabled.inspect}"
179
+ end
180
+
181
+ if enabled == false && options.any?
182
+ raise DefinitionError, "#{model}: `admin false` takes no options — #{options.keys.map(&:inspect).join(', ')} " \
183
+ 'would never apply'
184
+ end
185
+
186
+ validate_admin_options!(options)
187
+ @admin_decl = enabled ? options : false
188
+ end
189
+
154
190
  private
155
191
 
192
+ ADMIN_OPTIONS = %i[actions group label fieldset scope].freeze
193
+
194
+ def validate_admin_options!(options)
195
+ unknown = options.keys - ADMIN_OPTIONS
196
+ unless unknown.empty?
197
+ raise DefinitionError, "#{model}: admin got unknown option(s) #{unknown.map(&:inspect).join(', ')} — " \
198
+ "known: #{ADMIN_OPTIONS.map(&:inspect).join(', ')}"
199
+ end
200
+
201
+ actions = options[:actions]
202
+ return if actions.nil?
203
+
204
+ bad = Array(actions).map(&:to_sym) - Admin::Entry::ALL_ACTIONS
205
+ return if bad.empty?
206
+
207
+ raise DefinitionError, "#{model}: admin actions #{bad.map(&:inspect).join(', ')} are not RESTful actions — " \
208
+ "known: #{Admin::Entry::ALL_ACTIONS.map(&:inspect).join(', ')}"
209
+ end
210
+
156
211
  # Normalize a preload value to an array of includes-specs, leaving a nested
157
212
  # hash (`{ publisher: :books }`) intact (Array() would split it).
158
213
  def preload_list(value)
@@ -40,15 +40,22 @@ module CrudComponents
40
40
  # it (from a persisted preference, or from the param via
41
41
  # {CrudComponents.selected_columns}). A forged/stale name can only hide or
42
42
  # reorder, never reveal a column the `if:` gate forbids.
43
+ # @param extra_actions [Array<CrudComponents::Action>, nil] row actions to append
44
+ # beyond the model's own — for a button that belongs to this surface rather
45
+ # than to the model. Subject to the same permission and route resolution.
46
+ # @param except_actions [Array<Symbol>, nil] action names this render drops,
47
+ # whatever the model declares (e.g. replacing `:destroy` with a button of
48
+ # your own). Applies to row, collection and selection actions.
43
49
  # @return [ActiveSupport::SafeBuffer] the rendered HTML.
44
50
  def crud_collection(records, fieldset: nil, layout: :table, query: :auto, param_prefix: nil,
45
51
  actions: true, search_bar: true, group_by: nil, extra_columns: nil,
46
- picker: false, picked_columns: :auto)
52
+ picker: false, picked_columns: :auto, extra_actions: nil, except_actions: nil)
47
53
  presenter = Presenters::Collection.new(view: self, records: records, fieldset: fieldset,
48
54
  query: query, layout: layout, param_prefix: param_prefix,
49
55
  actions: actions, search_bar: search_bar, group_by: group_by,
50
56
  extra_columns: extra_columns,
51
- picker: picker, picked_columns: picked_columns)
57
+ picker: picker, picked_columns: picked_columns,
58
+ extra_actions: extra_actions, except_actions: except_actions)
52
59
  render "crud_components/layouts/#{presenter.layout}", collection: presenter
53
60
  end
54
61
 
@@ -71,12 +78,17 @@ module CrudComponents
71
78
  # @param extra_columns [Array<CrudComponents::DynamicColumn>, nil] user-defined
72
79
  # columns whose data lives outside the model's table, shown as extra rows
73
80
  # (same as {#crud_collection}'s `extra_columns:`, for a detail view).
81
+ # @param extra_actions [Array<CrudComponents::Action>, nil] actions to append
82
+ # beyond the model's own (same as {#crud_collection}'s `extra_actions:`).
83
+ # @param except_actions [Array<Symbol>, nil] action names this render drops
84
+ # (same as {#crud_collection}'s `except_actions:`).
74
85
  # @return [ActiveSupport::SafeBuffer] the rendered HTML.
75
86
  def crud_record(record, fieldset: nil, actions: true, layout: :record, picked_columns: :auto,
76
- param_prefix: nil, extra_columns: nil)
87
+ param_prefix: nil, extra_columns: nil, extra_actions: nil, except_actions: nil)
77
88
  presenter = Presenters::Record.new(view: self, record: record, fieldset: fieldset, actions: actions,
78
89
  picked_columns: picked_columns, param_prefix: param_prefix,
79
- extra_columns: extra_columns)
90
+ extra_columns: extra_columns, extra_actions: extra_actions,
91
+ except_actions: except_actions)
80
92
  render "crud_components/#{layout}", record_presenter: presenter
81
93
  end
82
94
 
@@ -178,6 +190,25 @@ module CrudComponents
178
190
 
179
191
  # ── utilities (used by the gem's partials; useful in apps too) ─────────
180
192
 
193
+ # The host application's own page for a record — its `app_path` block, else
194
+ # the conventional route resolved against `main_app`. nil when there is
195
+ # none, so guard the link rather than assuming it resolves.
196
+ # @param record [ActiveRecord::Base]
197
+ # @return [String, nil]
198
+ def crud_app_path(record)
199
+ RouteResolver.app_path(self, record)
200
+ end
201
+
202
+ # The mounted admin's page for a record (or for a model class, its index).
203
+ # nil when the admin isn't mounted, the model isn't registered, or the
204
+ # action isn't enabled for it.
205
+ # @param subject [ActiveRecord::Base, Class]
206
+ # @param action [Symbol] `:show` (default), `:index`, `:edit` or `:new`.
207
+ # @return [String, nil]
208
+ def crud_admin_path(subject, action = :show)
209
+ Admin.path_for(subject, action)
210
+ end
211
+
181
212
  # The display label for a record — its declared `label`, else a humanized guess.
182
213
  # @param record [ActiveRecord::Base]
183
214
  # @return [String]
@@ -16,7 +16,8 @@ module CrudComponents
16
16
 
17
17
  def initialize(view:, records:, fieldset: nil, query: :auto, layout: :table,
18
18
  param_prefix: nil, actions: true, search_bar: true, group_by: nil,
19
- extra_columns: nil, picker: false, picked_columns: :auto)
19
+ extra_columns: nil, picker: false, picked_columns: :auto, extra_actions: nil,
20
+ except_actions: nil)
20
21
  super(view: view)
21
22
  unless records.respond_to?(:klass)
22
23
  raise ArgumentError,
@@ -31,6 +32,8 @@ module CrudComponents
31
32
  @layout = layout
32
33
  @param_prefix = param_prefix
33
34
  @actions_enabled = actions
35
+ @extra_actions = Array(extra_actions)
36
+ @except_actions = Array(except_actions).map(&:to_sym)
34
37
  @search_bar_enabled = search_bar
35
38
  # Two orthogonal column-picker knobs (see ColumnSelection): the gear is on
36
39
  # iff `picker`; the selection comes from the param (`:auto`) or verbatim
@@ -385,7 +388,7 @@ module CrudComponents
385
388
  return nil unless @actions_enabled
386
389
 
387
390
  @collection_actions ||= Actions.new(view: view, subject: model, structure: structure,
388
- actions: structure.fieldset_actions(fieldset, on: :collection),
391
+ actions: keep(structure.fieldset_actions(fieldset, on: :collection)),
389
392
  owner: owner)
390
393
  end
391
394
 
@@ -398,7 +401,8 @@ module CrudComponents
398
401
  return nil unless @actions_enabled
399
402
 
400
403
  @selection_actions ||= Actions.new(view: view, subject: model, structure: structure,
401
- actions: structure.fieldset_actions(fieldset, on: :selection),
404
+ actions: keep(structure.fieldset_actions(fieldset, on: :selection)) +
405
+ @extra_actions.select { |action| action.on == :selection },
402
406
  owner: owner)
403
407
  end
404
408
 
@@ -489,7 +493,15 @@ module CrudComponents
489
493
  end
490
494
 
491
495
  def row_action_definitions
492
- @row_action_definitions ||= structure.fieldset_actions(fieldset, on: :row)
496
+ @row_action_definitions ||= keep(structure.fieldset_actions(fieldset, on: :row)) +
497
+ @extra_actions.select { |action| action.on == :row }
498
+ end
499
+
500
+ # Actions this render drops, whatever the model declares.
501
+ def keep(actions)
502
+ return actions if @except_actions.empty?
503
+
504
+ actions.reject { |action| @except_actions.include?(action.name) }
493
505
  end
494
506
 
495
507
  def pn(key)
@@ -7,13 +7,15 @@ module CrudComponents
7
7
  attr_reader :record, :model, :structure, :fieldset, :param_prefix
8
8
 
9
9
  def initialize(view:, record:, fieldset: nil, actions: true, picked_columns: :auto,
10
- param_prefix: nil, extra_columns: nil)
10
+ param_prefix: nil, extra_columns: nil, extra_actions: nil, except_actions: nil)
11
11
  super(view: view)
12
12
  @record = record
13
13
  @model = record.class
14
14
  @structure = Structure.for(@model)
15
15
  @fieldset = @structure.fieldset(fieldset || :show)
16
16
  @actions_enabled = actions
17
+ @extra_actions = Array(extra_actions).select { |action| action.on == :row }
18
+ @except_actions = Array(except_actions).map(&:to_sym)
17
19
  @param_prefix = param_prefix
18
20
  # Dynamic columns work on a detail view too — user-defined properties
19
21
  # whose data lives outside the model's table, shown as extra rows.
@@ -49,9 +51,19 @@ module CrudComponents
49
51
  return nil unless @actions_enabled
50
52
 
51
53
  @actions ||= Actions.new(view: view, subject: record, structure: structure,
52
- actions: structure.fieldset_actions(fieldset, on: :row),
54
+ actions: declared_row_actions + @extra_actions,
53
55
  suppress_show: true)
54
56
  end
57
+
58
+ private
59
+
60
+ # Actions this render drops, whatever the model declares.
61
+ def declared_row_actions
62
+ actions = structure.fieldset_actions(fieldset, on: :row)
63
+ return actions if @except_actions.empty?
64
+
65
+ actions.reject { |action| @except_actions.include?(action.name) }
66
+ end
55
67
  end
56
68
  end
57
69
  end
@@ -7,10 +7,7 @@ module CrudComponents
7
7
  module_function
8
8
 
9
9
  def action_path(view, action, record: nil, model: nil, owner: nil)
10
- if action.path_block
11
- subject = record || model
12
- return view.instance_exec(subject, &action.path_block)
13
- end
10
+ return safe_block(view, record || model, action.path_block) if action.path_block
14
11
 
15
12
  if action.collection?
16
13
  collection_path(view, action, model, owner)
@@ -19,6 +16,20 @@ module CrudComponents
19
16
  end
20
17
  end
21
18
 
19
+ # The host application's own page for a record — the same candidate logic,
20
+ # resolved against `main_app` instead of the current route set. A declared
21
+ # `app_path` block wins. nil when nothing resolves.
22
+ def app_path(view, record)
23
+ structure = Structure.for(record.class)
24
+ if (block = structure.app_path_block)
25
+ return safe_block(view, record, block)
26
+ end
27
+
28
+ return nil unless view.respond_to?(:main_app)
29
+
30
+ try_helpers(view.main_app, member_candidates(nil, record, nil))
31
+ end
32
+
22
33
  # The plain link to a record (label cells, association cells):
23
34
  # show route, then edit. Returns [path, kind] or nil.
24
35
  def record_path(view, record, owner: nil)
@@ -79,6 +90,24 @@ module CrudComponents
79
90
  nil
80
91
  end
81
92
 
93
+ # A path block naming a route helper that does not exist here — the same
94
+ # page rendered under a mount that lacks it — yields nil, so the button is
95
+ # omitted. Anything else the block gets wrong is the app's own error and
96
+ # stays loud.
97
+ def safe_block(view, subject, block)
98
+ view.instance_exec(subject, &block)
99
+ rescue ActionController::UrlGenerationError
100
+ nil
101
+ rescue NameError => e
102
+ raise unless missing_route_helper?(e)
103
+
104
+ nil
105
+ end
106
+
107
+ def missing_route_helper?(error)
108
+ error.name.to_s.end_with?('_path', '_url')
109
+ end
110
+
82
111
  def safe_url(view, helper, *args, **kwargs)
83
112
  kwargs.empty? ? view.public_send(helper, *args) : view.public_send(helper, *args, **kwargs)
84
113
  rescue ActionController::UrlGenerationError, NoMethodError
@@ -107,12 +136,13 @@ module CrudComponents
107
136
  candidates
108
137
  end
109
138
 
110
- def try_helpers(view, candidates)
139
+ # `helpers` is anything exposing route helpers — the view, or `main_app`.
140
+ def try_helpers(helpers, candidates)
111
141
  candidates.each do |helper, args|
112
- next unless view.respond_to?(helper)
142
+ next unless helpers.respond_to?(helper)
113
143
 
114
144
  begin
115
- return view.public_send(helper, *args)
145
+ return helpers.public_send(helper, *args)
116
146
  rescue ActionController::UrlGenerationError, NoMethodError
117
147
  next
118
148
  end
@@ -42,7 +42,9 @@ module CrudComponents
42
42
  # identity_preloads: associations to eager-load whenever this model is shown
43
43
  # as another model's association cell (its label/render dependencies), from
44
44
  # `label …, preload:` and the standalone `preload` declaration.
45
- attr_reader :model, :identify_by, :identity_preloads
45
+ # admin_options: the `admin` declaration — a Hash of options, `false` when
46
+ # the model opted out, nil when it said nothing.
47
+ attr_reader :model, :identify_by, :identity_preloads, :admin_options, :app_path_block
46
48
 
47
49
  def initialize(model, builder = nil)
48
50
  @model = model
@@ -50,6 +52,8 @@ module CrudComponents
50
52
  @label_decl = builder&.label_decl
51
53
  @identify_by = builder&.identify_by_decl || :id
52
54
  @icon_decl = builder&.icon_decl
55
+ @admin_options = builder&.admin_decl
56
+ @app_path_block = builder&.app_path_decl
53
57
  @search_decl = builder&.search_decl
54
58
  @identity_preloads = ((builder&.label_preload_decl || []) + (builder&.preload_decl || [])).uniq
55
59
  @declared_actions = builder&.actions || {}
@@ -117,6 +121,9 @@ module CrudComponents
117
121
  @default_fieldset ||= Fieldset.new(:default, :all)
118
122
  end
119
123
 
124
+ # The fieldsets this model actually declared (no derived defaults).
125
+ def declared_fieldset_names = @declared_fieldsets.keys
126
+
120
127
  def fieldset_fields(fieldset)
121
128
  names = fieldset.all_fields? ? default_field_names : fieldset.field_names
122
129
  names.map { |name| field(name) }
@@ -1,3 +1,3 @@
1
1
  module CrudComponents
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -54,6 +54,7 @@ require_relative 'crud_components/builder'
54
54
  require_relative 'crud_components/structure'
55
55
  require_relative 'crud_components/model'
56
56
  require_relative 'crud_components/query'
57
+ require_relative 'crud_components/admin'
57
58
 
58
59
  module CrudComponents
59
60
  class << self
@@ -166,3 +167,4 @@ module CrudComponents
166
167
  end
167
168
 
168
169
  require_relative 'crud_components/engine' if defined?(Rails::Engine)
170
+ require_relative 'crud_components/admin/engine' if defined?(Rails::Engine)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crud_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anatoly Zelenin
@@ -82,6 +82,10 @@ files:
82
82
  - RELEASING.md
83
83
  - Rakefile
84
84
  - app/assets/stylesheets/crud_components.css
85
+ - app/assets/stylesheets/crud_components_admin.css
86
+ - app/controllers/crud_components/admin/application_controller.rb
87
+ - app/controllers/crud_components/admin/dashboard_controller.rb
88
+ - app/controllers/crud_components/admin/resources_controller.rb
85
89
  - app/views/crud_components/_action_button.html.erb
86
90
  - app/views/crud_components/_actions.html.erb
87
91
  - app/views/crud_components/_column_header.html.erb
@@ -94,6 +98,14 @@ files:
94
98
  - app/views/crud_components/_selection_action.html.erb
95
99
  - app/views/crud_components/_sort_link.html.erb
96
100
  - app/views/crud_components/_toolbar.html.erb
101
+ - app/views/crud_components/admin/_sidebar.html.erb
102
+ - app/views/crud_components/admin/dashboard/show.html.erb
103
+ - app/views/crud_components/admin/resources/_dependent_records.html.erb
104
+ - app/views/crud_components/admin/resources/delete.html.erb
105
+ - app/views/crud_components/admin/resources/edit.html.erb
106
+ - app/views/crud_components/admin/resources/index.html.erb
107
+ - app/views/crud_components/admin/resources/new.html.erb
108
+ - app/views/crud_components/admin/resources/show.html.erb
97
109
  - app/views/crud_components/fields/_asciidoc.html.erb
98
110
  - app/views/crud_components/fields/_association.html.erb
99
111
  - app/views/crud_components/fields/_association_list.html.erb
@@ -129,9 +141,11 @@ files:
129
141
  - app/views/crud_components/form_fields/_string.html.erb
130
142
  - app/views/crud_components/form_fields/_text.html.erb
131
143
  - app/views/crud_components/layouts/_table.html.erb
144
+ - app/views/layouts/crud_components/admin.html.erb
132
145
  - config/locales/crud_components.de.yml
133
146
  - config/locales/crud_components.en.yml
134
147
  - crud_components.gemspec
148
+ - docs/admin.md
135
149
  - docs/extending.md
136
150
  - docs/fields.md
137
151
  - docs/filtering.md
@@ -141,6 +155,15 @@ files:
141
155
  - docs/views.md
142
156
  - lib/crud_components.rb
143
157
  - lib/crud_components/action.rb
158
+ - lib/crud_components/admin.rb
159
+ - lib/crud_components/admin/configuration.rb
160
+ - lib/crud_components/admin/dependents.rb
161
+ - lib/crud_components/admin/engine.rb
162
+ - lib/crud_components/admin/entry.rb
163
+ - lib/crud_components/admin/gate.rb
164
+ - lib/crud_components/admin/registry.rb
165
+ - lib/crud_components/admin/routes.rb
166
+ - lib/crud_components/admin/view_helpers.rb
144
167
  - lib/crud_components/builder.rb
145
168
  - lib/crud_components/config.rb
146
169
  - lib/crud_components/dynamic_column.rb