tiny_admin 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d203e48b821f195f95847a646e32787c9ffd953212326f64e65ca09d563ed55e
4
- data.tar.gz: a133ad428942d240ec8852e4885e12a51bc6a96f9a4bcf426470180671dddf6f
3
+ metadata.gz: 6eb4a218cc1a4ff6acc940c402d74202582d2092b39f920e6551e5b395da752e
4
+ data.tar.gz: fb137625f9f5faa5b33dd5c7633a68eec7a4a2d2bb31db6f70758d6ed9ec3750
5
5
  SHA512:
6
- metadata.gz: 8955bf003179333debcf4c43dd7091b4d81fc9c1e90a6116119dc33f51b4ab7dca394d90f6f8aa6bb0385339dc5eb07b64bd546f0a92e02497d5c000cc835769
7
- data.tar.gz: 5cabb3dc010e73b416068cca3afda56dc07ac7b024c70d734b9409298d2082798a8e5e276d892be81e82dcbfa68bad20360f0d99e4c8e7199a7bdb5067f72124
6
+ metadata.gz: fd7800ab65bd0e92ce5646210f08823d031fdd217f5230bc99207a0e00375b068ad2337805ddce196ca317fe6f0df60ad3e209fc885e31c765c68c125f83d900
7
+ data.tar.gz: f1df2bd938781a04c4af36c9653a7efffcc075cf72accd8f9fbaedbcc74286d860a1953bab159ec833c6a2cf5851a00633f555966b915fedec625af9ef2f85fa
data/README.md CHANGED
@@ -16,7 +16,7 @@ Please ⭐ if you like it.
16
16
 
17
17
  ## Install
18
18
 
19
- - Add to your Gemfile: `gem 'tiny_admin', '~> 0.3'`
19
+ - Add to your Gemfile: `gem 'tiny_admin', '~> 0.4'`
20
20
  - Mount the app in a route (check some examples with: Hanami, Rails, Roda and standalone in [extra](extra))
21
21
  + in Rails, update _config/routes.rb_: `mount TinyAdmin::Router => '/admin'`
22
22
  - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` (see [configuration](#configuration) below):
@@ -82,6 +82,12 @@ root:
82
82
  redirect: posts
83
83
  ```
84
84
 
85
+ `helper_class` (String): class or module with helper methods, used for attributes' formatters.
86
+
87
+ `page_not_found` (String): a view object to render when a missing page is requested.
88
+
89
+ `record_not_found` (String): a view object to render when a missing record is requested.
90
+
85
91
  `authentication` (Hash): define the authentication method, properties:
86
92
  - `plugin` (String): a plugin class to use (ex. `TinyAdmin::Plugins::SimpleAuth`);
87
93
  - `password` (String): a password hash used by _SimpleAuth_ plugin (generated with `Digest::SHA512.hexdigest("some password")`).
@@ -175,65 +181,64 @@ end
175
181
  ---
176
182
  authentication:
177
183
  plugin: TinyAdmin::Plugins::SimpleAuth
178
- # password: 'f1891cea80fc05e433c943254c6bdabc159577a02a7395df...' <= SHA512
179
- page_not_found: Admin::PageNotFound
180
- record_not_found: Admin::RecordNotFound
184
+ # password: 'f1891cea80fc05e433c943254c6bdabc159577a02a7395dfebbfbc4f7661d4af56f2d372131a45936de40160007368a56ef216a30cb202c66d3145fd24380906'
181
185
  root:
182
- title: 'Tiny Admin'
183
- page: Admin::PageRoot
184
- # redirect: posts
186
+ title: Test Admin
187
+ # page: RootPage
188
+ helper_class: AdminHelper
189
+ page_not_found: PageNotFound
190
+ record_not_found: RecordNotFound
185
191
  sections:
186
192
  - slug: google
187
193
  name: Google.it
188
194
  type: url
189
195
  url: https://www.google.it
190
196
  options:
191
- target: '_blank'
192
- - slug: stats
193
- name: Stats
197
+ target: _blank
198
+ - slug: sample
199
+ name: Sample page
194
200
  type: page
195
- page: Admin::Stats
201
+ page: SamplePage
196
202
  - slug: authors
197
203
  name: Authors
198
204
  type: resource
199
205
  model: Author
200
- repository: Admin::AuthorsRepo
201
206
  collection_actions:
202
- - latests: Admin::LatestAuthorsAction
207
+ - sample_col: SampleCollectionAction
203
208
  member_actions:
204
- - csv_export: Admin::CsvExportAuthorAction
205
- # only:
206
- # - index
207
- # options:
208
- # - hidden
209
+ - sample_mem: SampleMemberAction
209
210
  - slug: posts
210
211
  name: Posts
211
212
  type: resource
212
213
  model: Post
213
214
  index:
214
- sort:
215
- - author_id DESC
216
- pagination: 15
215
+ pagination: 5
217
216
  attributes:
218
217
  - id
219
218
  - title
220
219
  - field: author_id
221
220
  link_to: authors
222
- - state
221
+ - category: upcase
222
+ - state: downcase
223
223
  - published
224
- - dt
224
+ - position: round, 1
225
+ - dt: to_date
225
226
  - field: created_at
226
- converter: Admin::Utils
227
+ converter: AdminUtils
227
228
  method: datetime_formatter
229
+ - updated_at: strftime, %Y%m%d %H:%M
228
230
  filters:
229
231
  - title
230
- - field: state
232
+ - author_id
233
+ - field: category
231
234
  type: select
232
235
  values:
233
- - available
234
- - unavailable
235
- - arriving
236
+ - news
237
+ - sport
238
+ - tech
236
239
  - published
240
+ - dt
241
+ - created_at
237
242
  show:
238
243
  attributes:
239
244
  - id
@@ -243,7 +248,8 @@ sections:
243
248
  link_to: authors
244
249
  - category
245
250
  - published
246
- - state
251
+ - position: format, %f
252
+ - dt
247
253
  - created_at
248
254
  style_links:
249
255
  - href: /bootstrap.min.css
@@ -5,12 +5,21 @@ module TinyAdmin
5
5
  class BasicAction
6
6
  include Utils
7
7
 
8
- attr_reader :params, :path, :repository
9
-
10
- def initialize(repository, path:, params:)
11
- @repository = repository
12
- @path = path
13
- @params = params
8
+ def attribute_options(options)
9
+ options&.each_with_object({}) do |field, result|
10
+ field_data =
11
+ if field.is_a?(Hash)
12
+ if field.one?
13
+ field, method = field.first
14
+ { field.to_s => { field: field.to_s, method: method } }
15
+ else
16
+ { field[:field] => field }
17
+ end
18
+ else
19
+ { field => { field: field } }
20
+ end
21
+ result.merge!(field_data)
22
+ end
14
23
  end
15
24
  end
16
25
  end
@@ -3,7 +3,15 @@
3
3
  module TinyAdmin
4
4
  module Actions
5
5
  class Index < BasicAction
6
- attr_reader :current_page, :fields_options, :filters_list, :pagination, :pages, :query_string, :sort
6
+ attr_reader :current_page,
7
+ :fields_options,
8
+ :filters_list,
9
+ :pagination,
10
+ :pages,
11
+ :params,
12
+ :query_string,
13
+ :repository,
14
+ :sort
7
15
 
8
16
  def call(app:, context:, options:, actions:)
9
17
  evaluate_options(options)
@@ -27,9 +35,9 @@ module TinyAdmin
27
35
  private
28
36
 
29
37
  def evaluate_options(options)
30
- @fields_options = options[:attributes]&.each_with_object({}) do |field, result|
31
- result.merge!(field.is_a?(Hash) ? { field[:field] => field } : { field => { field: field } })
32
- end
38
+ @fields_options = attribute_options(options[:attributes])
39
+ @params = context.request.params
40
+ @repository = context.repository
33
41
  @filters_list = options[:filters]
34
42
  @pagination = options[:pagination] || 10
35
43
  @sort = options[:sort] || ['id']
@@ -42,8 +50,8 @@ module TinyAdmin
42
50
  filters = (filters_list || []).map { _1.is_a?(Hash) ? _1 : { field: _1 } }
43
51
  filters = filters.each_with_object({}) { |filter, result| result[filter[:field]] = filter }
44
52
  values = (params['q'] || {})
45
- fields.each_with_object({}) do |field, result|
46
- result[field] = { value: values[field.name], filter: filters[field.name] } if filters.key?(field.name)
53
+ fields.each_with_object({}) do |(name, field), result|
54
+ result[field] = { value: values[name], filter: filters[name] } if filters.key?(name)
47
55
  end
48
56
  end
49
57
 
@@ -3,17 +3,21 @@
3
3
  module TinyAdmin
4
4
  module Actions
5
5
  class Show < BasicAction
6
+ attr_reader :repository
7
+
6
8
  def call(app:, context:, options:, actions:)
7
- fields_options = (options[:attributes] || []).each_with_object({}) do |field, result|
8
- result.merge!(field.is_a?(Hash) ? { field[:field] => field } : { field => { field: field } })
9
- end
9
+ @repository = context.repository
10
+ fields_options = attribute_options(options[:attributes])
10
11
  record = repository.find(context.reference)
11
- prepare_record = ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) }
12
- fields = repository.fields(options: fields_options)
13
12
 
14
13
  prepare_page(Views::Actions::Show) do |page|
15
- page.setup_record(record: record, fields: fields, prepare_record: prepare_record)
16
- page.update_attributes(actions: actions, title: repository.show_title(record))
14
+ page.update_attributes(
15
+ actions: actions,
16
+ fields: repository.fields(options: fields_options),
17
+ prepare_record: ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) },
18
+ record: record,
19
+ title: repository.show_title(record)
20
+ )
17
21
  end
18
22
  rescue Plugins::BaseRepository::RecordNotFound => _e
19
23
  prepare_page(options[:record_not_found_page] || Views::Pages::RecordNotFound)
@@ -4,6 +4,6 @@ module TinyAdmin
4
4
  class Context
5
5
  include Singleton
6
6
 
7
- attr_accessor :reference, :slug
7
+ attr_accessor :reference, :repository, :request, :router, :settings, :slug
8
8
  end
9
9
  end
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  class Field
5
5
  attr_reader :name, :options, :title, :type
6
6
 
7
- def initialize(type:, name:, title:, options: {})
7
+ def initialize(name:, title:, type:, options: {})
8
8
  @type = type
9
9
  @name = name
10
10
  @title = title || name
@@ -12,8 +12,14 @@ module TinyAdmin
12
12
  end
13
13
 
14
14
  class << self
15
- def create_field(name:, title:, type: nil, options: {})
16
- new(type: type, name: name, title: title, options: options)
15
+ def create_field(name:, title: nil, type: nil, options: {})
16
+ field_name = name.to_s
17
+ new(
18
+ name: field_name,
19
+ title: title || field_name.respond_to?(:humanize) ? field_name.humanize : field_name.tr('_', ' ').capitalize,
20
+ type: type || :string,
21
+ options: options
22
+ )
17
23
  end
18
24
  end
19
25
  end
@@ -4,17 +4,11 @@ module TinyAdmin
4
4
  module Plugins
5
5
  class ActiveRecordRepository < BaseRepository
6
6
  def index_record_attrs(record, fields: nil)
7
- return record.attributes.transform_values(&:to_s) if !fields || fields.empty?
7
+ return record.attributes.transform_values(&:to_s) unless fields
8
8
 
9
- record.attributes.slice(*fields.keys).each_with_object({}) do |(key, value), result|
10
- field_data = fields[key]
11
- result[key] =
12
- if field_data[:converter] && field_data[:method]
13
- converter = Object.const_get(field_data[:converter])
14
- converter.send(field_data[:method], value)
15
- else
16
- value&.to_s
17
- end
9
+ fields.to_h do |name, field|
10
+ value = record.send(name)
11
+ [name, translate_value(value, field)]
18
12
  end
19
13
  end
20
14
 
@@ -24,25 +18,19 @@ module TinyAdmin
24
18
  end
25
19
 
26
20
  def fields(options: nil)
27
- opts = options || {}
28
- columns = model.columns
29
- if !opts.empty?
30
- extra_fields = opts.keys - model.column_names
31
- raise "Some requested fields are not available: #{extra_fields.join(', ')}" if extra_fields.any?
32
-
33
- columns = opts.keys.map { |field| columns.find { _1.name == field } }
34
- end
35
- columns.map do |column|
36
- name = column.name
37
- type = opts.dig(column.name, :type) || column.type
38
- TinyAdmin::Field.create_field(name: name, title: name.humanize, type: type, options: opts[name])
21
+ if options
22
+ types = model.columns.to_h { [_1.name, _1.type] }
23
+ options.each_with_object({}) do |(name, field_options), result|
24
+ result[name] = TinyAdmin::Field.create_field(name: name, type: types[name], options: field_options)
25
+ end
26
+ else
27
+ model.columns.each_with_object({}) do |column, result|
28
+ result[column.name] = TinyAdmin::Field.create_field(name: column.name, type: column.type)
29
+ end
39
30
  end
40
31
  end
41
32
 
42
- def show_record_attrs(record, fields: nil)
43
- attrs = !fields || fields.empty? ? record.attributes : record.attributes.slice(*fields.keys)
44
- attrs.transform_values(&:to_s)
45
- end
33
+ alias show_record_attrs index_record_attrs
46
34
 
47
35
  def show_title(record)
48
36
  "#{model} ##{record.id}"
@@ -54,10 +42,10 @@ module TinyAdmin
54
42
  raise BaseRepository::RecordNotFound, e.message
55
43
  end
56
44
 
57
- def list(page: 1, limit: 10, filters: nil, sort: ['id'])
58
- page_offset = page.positive? ? (page - 1) * limit : 0
45
+ def list(page: 1, limit: 10, sort: ['id'], filters: nil)
59
46
  query = model.all.order(sort)
60
47
  query = apply_filters(query, filters) if filters
48
+ page_offset = page.positive? ? (page - 1) * limit : 0
61
49
  records = query.offset(page_offset).limit(limit).to_a
62
50
  [records, query.count]
63
51
  end
@@ -10,6 +10,20 @@ module TinyAdmin
10
10
  def initialize(model)
11
11
  @model = model
12
12
  end
13
+
14
+ def translate_value(value, field)
15
+ if field[:method]
16
+ method, *options = field[:method].split(',').map(&:strip)
17
+ if field[:converter]
18
+ converter = Object.const_get(field[:converter])
19
+ converter.send(method, value, options: options || [])
20
+ else
21
+ Settings.instance.helper_class.send(method, value, options: options || [])
22
+ end
23
+ else
24
+ value&.to_s
25
+ end
26
+ end
13
27
  end
14
28
  end
15
29
  end
@@ -2,9 +2,11 @@
2
2
 
3
3
  module TinyAdmin
4
4
  class Router < BasicApp
5
- TinyAdmin::Settings.instance.load_settings
6
-
7
5
  route do |r|
6
+ context.settings = TinyAdmin::Settings.instance
7
+ context.settings.load_settings
8
+ context.router = r
9
+
8
10
  r.on 'auth' do
9
11
  context.slug = nil
10
12
  r.run Authentication
@@ -27,11 +29,11 @@ module TinyAdmin
27
29
  r.redirect settings.root_path
28
30
  end
29
31
 
30
- TinyAdmin::Settings.instance.pages.each do |slug, data|
32
+ context.settings.pages.each do |slug, data|
31
33
  setup_page_route(r, slug, data)
32
34
  end
33
35
 
34
- TinyAdmin::Settings.instance.resources.each do |slug, options|
36
+ context.settings.resources.each do |slug, options|
35
37
  setup_resource_routes(r, slug, options: options || {})
36
38
  end
37
39
 
@@ -74,14 +76,14 @@ module TinyAdmin
74
76
  end
75
77
 
76
78
  def setup_collection_routes(router, options:)
77
- repository = options[:repository].new(options[:model])
79
+ context.repository = options[:repository].new(options[:model])
78
80
  action_options = options[:index] || {}
79
81
 
80
82
  # Custom actions
81
83
  custom_actions = setup_custom_actions(
82
84
  router,
83
85
  options[:collection_actions],
84
- repository: repository,
86
+ repository: context.repository,
85
87
  options: action_options
86
88
  )
87
89
 
@@ -89,14 +91,15 @@ module TinyAdmin
89
91
  actions = options[:only]
90
92
  if !actions || actions.include?(:index) || actions.include?('index')
91
93
  router.is do
92
- index_action = TinyAdmin::Actions::Index.new(repository, path: request.path, params: request.params)
94
+ context.request = request
95
+ index_action = TinyAdmin::Actions::Index.new
93
96
  render_page index_action.call(app: self, context: context, options: action_options, actions: custom_actions)
94
97
  end
95
98
  end
96
99
  end
97
100
 
98
101
  def setup_member_routes(router, options:)
99
- repository = options[:repository].new(options[:model])
102
+ context.repository = options[:repository].new(options[:model])
100
103
  action_options = (options[:show] || {}).merge(record_not_found_page: settings.record_not_found)
101
104
 
102
105
  router.on String do |reference|
@@ -106,7 +109,7 @@ module TinyAdmin
106
109
  custom_actions = setup_custom_actions(
107
110
  router,
108
111
  options[:member_actions],
109
- repository: repository,
112
+ repository: context.repository,
110
113
  options: action_options
111
114
  )
112
115
 
@@ -114,7 +117,8 @@ module TinyAdmin
114
117
  actions = options[:only]
115
118
  if !actions || actions.include?(:show) || actions.include?('show')
116
119
  router.is do
117
- show_action = TinyAdmin::Actions::Show.new(repository, path: request.path, params: request.params)
120
+ context.request = request
121
+ show_action = TinyAdmin::Actions::Show.new
118
122
  render_page show_action.call(app: self, context: context, options: action_options, actions: custom_actions)
119
123
  end
120
124
  end
@@ -122,16 +126,18 @@ module TinyAdmin
122
126
  end
123
127
 
124
128
  def setup_custom_actions(router, custom_actions, repository:, options:)
125
- (custom_actions || []).map do |custom_action|
129
+ context.repository = repository
130
+ (custom_actions || []).each_with_object({}) do |custom_action, result|
126
131
  action_slug, action = custom_action.first
127
132
  action_class = action.is_a?(String) ? Object.const_get(action) : action
128
133
 
129
134
  router.get action_slug.to_s do
130
- custom_action = action_class.new(repository, path: request.path, params: request.params)
135
+ context.request = request
136
+ custom_action = action_class.new
131
137
  render_page custom_action.call(app: self, context: context, options: options)
132
138
  end
133
139
 
134
- action_slug.to_s
140
+ result[action_slug.to_s] = action_class
135
141
  end
136
142
  end
137
143
  end
@@ -5,9 +5,26 @@ module TinyAdmin
5
5
  include Singleton
6
6
  include Utils
7
7
 
8
+ DEFAULTS = {
9
+ %i[authentication plugin] => Plugins::NoAuth,
10
+ %i[authentication login] => Views::Pages::SimpleAuthLogin,
11
+ %i[components flash] => Views::Components::Flash,
12
+ %i[components head] => Views::Components::Head,
13
+ %i[components navbar] => Views::Components::Navbar,
14
+ %i[components pagination] => Views::Components::Pagination,
15
+ %i[helper_class] => Support,
16
+ %i[page_not_found] => Views::Pages::PageNotFound,
17
+ %i[record_not_found] => Views::Pages::RecordNotFound,
18
+ %i[repository] => Plugins::ActiveRecordRepository,
19
+ %i[root_path] => '/admin',
20
+ %i[root page] => Views::Pages::Root,
21
+ %i[root title] => 'TinyAdmin'
22
+ }.freeze
23
+
8
24
  attr_accessor :authentication,
9
25
  :components,
10
26
  :extra_styles,
27
+ :helper_class,
11
28
  :navbar,
12
29
  :page_not_found,
13
30
  :record_not_found,
@@ -20,38 +37,33 @@ module TinyAdmin
20
37
 
21
38
  attr_reader :pages, :resources
22
39
 
23
- def load_settings
24
- @authentication ||= {}
25
- @authentication[:plugin] ||= Plugins::NoAuth
26
- @authentication[:login] ||= Views::Pages::SimpleAuthLogin
27
- @authentication[:plugin] = Object.const_get(authentication[:plugin]) if authentication[:plugin].is_a?(String)
40
+ def [](key)
41
+ send(key)
42
+ end
43
+
44
+ def []=(key, value)
45
+ send("#{key}=", value)
46
+ convert_value(key, value)
47
+ end
28
48
 
29
- @page_not_found ||= Views::Pages::PageNotFound
30
- @page_not_found = Object.const_get(@page_not_found) if @page_not_found.is_a?(String)
31
- @record_not_found ||= Views::Pages::RecordNotFound
32
- @record_not_found = Object.const_get(@record_not_found) if @record_not_found.is_a?(String)
49
+ def load_settings
50
+ # default values
51
+ DEFAULTS.each do |(option, param), default|
52
+ if param
53
+ self[option] ||= {}
54
+ self[option][param] ||= default
55
+ else
56
+ self[option] ||= default
57
+ end
58
+ end
33
59
 
34
60
  @pages ||= {}
35
- @repository ||= Plugins::ActiveRecordRepository
36
61
  @resources ||= {}
37
- @root_path ||= '/admin'
38
- @root_path = '/' if @root_path == ''
39
62
  @sections ||= []
40
-
41
- @root ||= {}
42
- @root[:title] ||= 'TinyAdmin'
43
- @root[:page] ||= Views::Pages::Root
44
-
63
+ @root_path = '/' if @root_path == ''
45
64
  if @authentication[:plugin] == Plugins::SimpleAuth
46
65
  @authentication[:logout] ||= ['logout', "#{root_path}/auth/logout"]
47
66
  end
48
-
49
- @components ||= {}
50
- @components[:flash] ||= Views::Components::Flash
51
- @components[:head] ||= Views::Components::Head
52
- @components[:navbar] ||= Views::Components::Navbar
53
- @components[:pagination] ||= Views::Components::Pagination
54
-
55
67
  @navbar = prepare_navbar(sections, logout: authentication[:logout])
56
68
  end
57
69
 
@@ -79,5 +91,20 @@ module TinyAdmin
79
91
  items['auth/logout'] = logout if logout
80
92
  items
81
93
  end
94
+
95
+ private
96
+
97
+ def convert_value(key, value)
98
+ if value.is_a?(Hash)
99
+ value.each_key do |key2|
100
+ path = [key, key2]
101
+ if DEFAULTS[path].is_a?(Class) || DEFAULTS[path].is_a?(Module)
102
+ self[key][key2] = Object.const_get(self[key][key2])
103
+ end
104
+ end
105
+ elsif value.is_a?(String) && (DEFAULTS[[key]].is_a?(Class) || DEFAULTS[[key]].is_a?(Module))
106
+ self[key] = Object.const_get(self[key])
107
+ end
108
+ end
82
109
  end
83
110
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ class Support
5
+ class << self
6
+ def call(value, options: [])
7
+ value && options&.any? ? options.inject(value) { |result, message| result&.send(message) } : value
8
+ end
9
+
10
+ def downcase(value, options: [])
11
+ value&.downcase
12
+ end
13
+
14
+ def format(value, options: [])
15
+ value && options&.any? ? Kernel.format(options.first, value) : value
16
+ end
17
+
18
+ def round(value, options: [])
19
+ value&.round(options&.first&.to_i || 2)
20
+ end
21
+
22
+ def strftime(value, options: [])
23
+ value ? value.strftime(options&.first || '%Y-%m-%d %H:%M') : ''
24
+ end
25
+
26
+ def to_date(value, options: [])
27
+ value ? value.to_date.to_s : value
28
+ end
29
+
30
+ def upcase(value, options: [])
31
+ value&.upcase
32
+ end
33
+ end
34
+ end
35
+ end
@@ -29,9 +29,10 @@ module TinyAdmin
29
29
  end
30
30
  end
31
31
 
32
- def route_for(section, reference: nil, action: nil)
32
+ def route_for(section, reference: nil, action: nil, query: nil)
33
33
  root_path = settings.root_path == '/' ? nil : settings.root_path
34
34
  route = [root_path, section, reference, action].compact.join("/")
35
+ route << "?#{query}" if query
35
36
  route[0] == '/' ? route : route.prepend('/')
36
37
  end
37
38
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -7,9 +7,6 @@ module TinyAdmin
7
7
  attr_accessor :actions, :fields, :filters, :pagination_component, :prepare_record, :records
8
8
 
9
9
  def template
10
- @fields = fields.each_with_object({}) { |field, result| result[field.name] = field }
11
- @filters ||= {}
12
-
13
10
  super do
14
11
  div(class: 'index') {
15
12
  div(class: 'row') {
@@ -17,19 +14,12 @@ module TinyAdmin
17
14
  h1(class: 'title') { title }
18
15
  }
19
16
  div(class: 'col-8') {
20
- ul(class: 'nav justify-content-end') {
21
- (actions || []).each do |action|
22
- li(class: 'nav-item') {
23
- href = route_for(context.slug, action: action)
24
- a(href: href, class: 'nav-link btn btn-outline-secondary') { action }
25
- }
26
- end
27
- }
17
+ actions_buttons
28
18
  }
29
19
  }
30
20
 
31
21
  div(class: 'row') {
32
- div_class = filters.any? ? 'col-9' : 'col-12'
22
+ div_class = filters&.any? ? 'col-9' : 'col-12'
33
23
  div(class: div_class) {
34
24
  table(class: 'table') {
35
25
  table_header if fields.any?
@@ -38,7 +28,7 @@ module TinyAdmin
38
28
  }
39
29
  }
40
30
 
41
- if filters.any?
31
+ if filters&.any?
42
32
  div(class: 'col-3') {
43
33
  filters_form_attrs = { section_path: route_for(context.slug), filters: filters }
44
34
  render TinyAdmin::Views::Components::FiltersForm.new(**filters_form_attrs)
@@ -57,7 +47,9 @@ module TinyAdmin
57
47
  thead {
58
48
  tr {
59
49
  fields.each_value do |field|
60
- td(class: "field-header-#{field.name} field-header-type-#{field.type}") { field.title }
50
+ td(class: "field-header-#{field.name} field-header-type-#{field.type}") {
51
+ field.options[:header] || field.title
52
+ }
61
53
  end
62
54
  td { whitespace }
63
55
  }
@@ -73,8 +65,9 @@ module TinyAdmin
73
65
  field = fields[key]
74
66
  td(class: "field-value-#{field.name} field-value-type-#{field.type}") {
75
67
  if field.options && field.options[:link_to]
76
- reference = record.send(field.options[:field])
77
- a(href: route_for(field.options[:link_to], reference: reference)) { value }
68
+ messages = (field.options[:call] || '').split(',').map(&:strip)
69
+ label = messages.any? ? messages.inject(record) { |result, msg| result&.send(msg) } : value
70
+ a(href: route_for(field.options[:link_to], reference: value)) { label }
78
71
  else
79
72
  value
80
73
  end
@@ -87,6 +80,18 @@ module TinyAdmin
87
80
  end
88
81
  }
89
82
  end
83
+
84
+ def actions_buttons
85
+ ul(class: 'nav justify-content-end') {
86
+ (actions || {}).each do |action, action_class|
87
+ li(class: 'nav-item mx-1') {
88
+ href = route_for(context.slug, action: action)
89
+ title = action_class.respond_to?(:title) ? action_class.title : action
90
+ a(href: href, class: 'nav-link btn btn-outline-secondary') { title }
91
+ }
92
+ end
93
+ }
94
+ end
90
95
  end
91
96
  end
92
97
  end
@@ -4,14 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Actions
6
6
  class Show < DefaultLayout
7
- attr_reader :fields, :prepare_record, :record
8
- attr_accessor :actions
9
-
10
- def setup_record(record:, fields:, prepare_record:)
11
- @record = record
12
- @fields = fields
13
- @prepare_record = prepare_record
14
- end
7
+ attr_accessor :actions, :fields, :prepare_record, :record
15
8
 
16
9
  def template
17
10
  super do
@@ -21,27 +14,21 @@ module TinyAdmin
21
14
  h1(class: 'title') { title }
22
15
  }
23
16
  div(class: 'col-8') {
24
- ul(class: 'nav justify-content-end') {
25
- (actions || []).each do |action|
26
- li(class: 'nav-item') {
27
- href = route_for(context.slug, reference: context.reference, action: action)
28
- a(href: href, class: 'nav-link btn btn-outline-secondary') { action }
29
- }
30
- end
31
- }
17
+ actions_buttons
32
18
  }
33
19
  }
34
20
 
35
- prepare_record.call(record).each_with_index do |(_key, value), index|
36
- field = fields[index]
21
+ prepare_record.call(record).each do |key, value|
22
+ field = fields[key]
37
23
  div(class: "field-#{field.name} row lh-lg") {
38
24
  if field
39
- div(class: 'field-header col-2') { field.title }
25
+ div(class: 'field-header col-2') { field.options[:header] || field.title }
40
26
  end
41
27
  div(class: 'field-value col-10') {
42
28
  if field.options && field.options[:link_to]
43
- reference = record.send(field.options[:field])
44
- a(href: route_for(field.options[:link_to], reference: reference)) { value }
29
+ messages = (field.options[:call] || '').split(',').map(&:strip)
30
+ label = messages.any? ? messages.inject(record) { |result, msg| result&.send(msg) } : value
31
+ a(href: route_for(field.options[:link_to], reference: value)) { label }
45
32
  else
46
33
  value
47
34
  end
@@ -51,6 +38,20 @@ module TinyAdmin
51
38
  }
52
39
  end
53
40
  end
41
+
42
+ private
43
+
44
+ def actions_buttons
45
+ ul(class: 'nav justify-content-end') {
46
+ (actions || {}).each do |action, action_class|
47
+ li(class: 'nav-item mx-1') {
48
+ href = route_for(context.slug, reference: context.reference, action: action)
49
+ title = action_class.respond_to?(:title) ? action_class.title : action
50
+ a(href: href, class: 'nav-link btn btn-outline-secondary') { title }
51
+ }
52
+ end
53
+ }
54
+ end
54
55
  end
55
56
  end
56
57
  end
data/lib/tiny_admin.rb CHANGED
@@ -18,7 +18,7 @@ module TinyAdmin
18
18
  def configure_from_file(file)
19
19
  config = YAML.load_file(file, symbolize_names: true)
20
20
  config.each do |key, value|
21
- TinyAdmin::Settings.instance.send("#{key}=", value)
21
+ TinyAdmin::Settings.instance[key] = value
22
22
  end
23
23
  end
24
24
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tiny_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-14 00:00:00.000000000 Z
11
+ date: 2023-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -88,6 +88,7 @@ files:
88
88
  - lib/tiny_admin/plugins/simple_auth.rb
89
89
  - lib/tiny_admin/router.rb
90
90
  - lib/tiny_admin/settings.rb
91
+ - lib/tiny_admin/support.rb
91
92
  - lib/tiny_admin/utils.rb
92
93
  - lib/tiny_admin/version.rb
93
94
  - lib/tiny_admin/views/actions/index.rb