tiny_admin 0.4.0 → 0.6.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: 6eb4a218cc1a4ff6acc940c402d74202582d2092b39f920e6551e5b395da752e
4
- data.tar.gz: fb137625f9f5faa5b33dd5c7633a68eec7a4a2d2bb31db6f70758d6ed9ec3750
3
+ metadata.gz: 0dfe9b2fef29073201e228daf3a7d89003902f8d98108e58cb8245fdb9a533e3
4
+ data.tar.gz: 6634891a9bbc2585549a759cd061a25234b834ebdcc0b77fbbb9bd2297b0a626
5
5
  SHA512:
6
- metadata.gz: fd7800ab65bd0e92ce5646210f08823d031fdd217f5230bc99207a0e00375b068ad2337805ddce196ca317fe6f0df60ad3e209fc885e31c765c68c125f83d900
7
- data.tar.gz: f1df2bd938781a04c4af36c9653a7efffcc075cf72accd8f9fbaedbcc74286d860a1953bab159ec833c6a2cf5851a00633f555966b915fedec625af9ef2f85fa
6
+ metadata.gz: 78b49e3f8b7efe941e24734692db4e4baaa2159f58a10f49ce0563f8c4cfa5950f3e155184016faff12c415ff1a6632d4ee06cd61659a466d170d4b7954becf7
7
+ data.tar.gz: 16c4fe68dca49b84c4c8ca834c9e3c2ce2304f5a78dc378cfdde837462a96a4e00030e5098083d025ad9ab28060ea2aa581725434ffeec1582715e5fa725ff28
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tiny Admin
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin) [![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml) [![Specs Rails 7.0](https://github.com/blocknotes/tiny_admin/actions/workflows/specs_rails_70.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs_rails_70.yml)
3
+ [![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin) [![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml) [![Specs](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml)
4
4
 
5
5
  A compact and composable dashboard component for Ruby.
6
6
 
@@ -16,10 +16,10 @@ Please ⭐ if you like it.
16
16
 
17
17
  ## Install
18
18
 
19
- - Add to your Gemfile: `gem 'tiny_admin', '~> 0.4'`
19
+ - Add to your Gemfile: `gem 'tiny_admin', '~> 0.6'`
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
- - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` (see [configuration](#configuration) below):
22
+ - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` with a YAML config file (see [configuration](#configuration) below):
23
23
 
24
24
  ```rb
25
25
  TinyAdmin.configure do |settings|
@@ -35,32 +35,38 @@ end
35
35
  ### Authentication
36
36
 
37
37
  Plugins available:
38
- - _SimpleAuth_: session authentication based on Warden (`warden` gem must be included in the Gemfile) using a password hash provided via config or via environment variable (`ADMIN_PASSWORD_HASH`);
39
- - _NoAuth_: no authentication.
38
+
39
+ - **SimpleAuth**: a session authentication based on Warden (`warden` gem must be included in the Gemfile) using a password hash provided via config or via environment variable (`ADMIN_PASSWORD_HASH`). _Disclaimer: this plugin is provided as example, if you need a secure authentication I suggest to create your own._
40
+
41
+ - **NoAuth**: no authentication.
40
42
 
41
43
  ### Repository
42
44
 
43
45
  Plugin available:
44
- - _ActiveRecordRepository_: isolates the query layer to expose the resources in the admin interface.
46
+
47
+ - **ActiveRecordRepository**: isolates the query layer to expose the resources in the admin interface.
45
48
 
46
49
  ### View pages
47
50
 
48
51
  Pages available:
49
- - _Root_: define how to present the content in the main page of the interface;
50
- - _PageNotFound_: define how to present pages not found;
51
- - _RecordNotFound_: define how to present record not found page;
52
- - _SimpleAuthLogin_: define how to present the login form for SimpleAuth plugin;
53
- - _Index_: define how to present a collection of items;
54
- - _Show_: define how to present the details of an item.
52
+
53
+ - **Root**: define how to present the content in the main page of the interface;
54
+ - **Content**: define how to present page with inline content;
55
+ - **PageNotFound**: define how to present pages not found;
56
+ - **RecordNotFound**: define how to present record not found page;
57
+ - **SimpleAuthLogin**: define how to present the login form for SimpleAuth plugin;
58
+ - **Index**: define how to present a collection of items;
59
+ - **Show**: define how to present the details of an item.
55
60
 
56
61
  ### View components
57
62
 
58
63
  Components available:
59
- - _FiltersForm_: define how to present the filters form in the resource collection pages;
60
- - _Flash_: define how to present the flash messages;
61
- - _Head_: define how to present the Head tag;
62
- - _Navbar_: define how to present the navbar (the default one uses the Bootstrap structure);
63
- - _Pagination_: define how to present the pagination of a collection.
64
+
65
+ - **FiltersForm**: define how to present the filters form in the resource collection pages;
66
+ - **Flash**: define how to present the flash messages;
67
+ - **Head**: define how to present the Head tag;
68
+ - **Navbar**: define how to present the navbar (the default one uses the Bootstrap structure);
69
+ - **Pagination**: define how to present the pagination of a collection.
64
70
 
65
71
  ## Configuration
66
72
 
@@ -70,9 +76,10 @@ See [extra](extra) folder for some usage examples.
70
76
  The following options are supported:
71
77
 
72
78
  `root` (Hash): define the root section of the admin, properties:
73
- - `title` (String): root section's title;
74
- - `page` (String): a view object to render;
75
- - `redirect` (String): alternative to _page_ option - redirects to a specific slug;
79
+
80
+ - `title` (String): root section's title;
81
+ - `page` (String): a view object to render;
82
+ - `redirect` (String): alternative to _page_ option - redirects to a specific slug;
76
83
 
77
84
  Example:
78
85
 
@@ -88,9 +95,21 @@ root:
88
95
 
89
96
  `record_not_found` (String): a view object to render when a missing record is requested.
90
97
 
98
+ `style_links` (Array of hashes): list of styles files to include, properties:
99
+
100
+ - `href` (String): URL for the style file;
101
+ - `rel` (String): type of style file.
102
+
103
+ `scripts` (Array of hashes): list of scripts to include, properties:
104
+
105
+ - `src` (String): source URL for the script.
106
+
107
+ `extra_styles` (String): inline CSS styles.
108
+
91
109
  `authentication` (Hash): define the authentication method, properties:
92
- - `plugin` (String): a plugin class to use (ex. `TinyAdmin::Plugins::SimpleAuth`);
93
- - `password` (String): a password hash used by _SimpleAuth_ plugin (generated with `Digest::SHA512.hexdigest("some password")`).
110
+
111
+ - `plugin` (String): a plugin class to use (ex. `TinyAdmin::Plugins::SimpleAuth`);
112
+ - `password` (String): a password hash used by _SimpleAuth_ plugin (generated with `Digest::SHA512.hexdigest("some password")`).
94
113
 
95
114
  Example:
96
115
 
@@ -101,15 +120,32 @@ authentication:
101
120
  ```
102
121
 
103
122
  `sections` (Array of hashes): define the admin sections, properties:
104
- - `slug` (String): section reference identifier;
105
- - `name` (String): section's title;
106
- - `type` (String): the type of section: `url`, `page` or `resource`;
107
- - other properties depends on the section's type.
123
+
124
+ - `slug` (String): section reference identifier;
125
+ - `name` (String): section's title;
126
+ - `type` (String): the type of section: `content`, `page`, `resource` or `url`;
127
+ - other properties depends on the section's type.
128
+
129
+ For _content_ sections:
130
+
131
+ - `content` (String): the HTML content to present.
132
+
133
+ Example:
134
+
135
+ ```yml
136
+ slug: test-content
137
+ name: Test content
138
+ type: content
139
+ content: >
140
+ <h1>Test content!</h1>
141
+ <p>Some test content</p>
142
+ ```
108
143
 
109
144
  For _url_ sections:
110
- - `url` (String): the URL to load when clicking on the section's menu item;
111
- - `options` (Hash): properties:
112
- + `target` (String): link _target_ attributes (ex. `_blank`).
145
+
146
+ - `url` (String): the URL to load when clicking on the section's menu item;
147
+ - `options` (Hash): properties:
148
+ + `target` (String): link _target_ attributes (ex. `_blank`).
113
149
 
114
150
  Example:
115
151
 
@@ -123,7 +159,8 @@ options:
123
159
  ```
124
160
 
125
161
  For _page_ sections:
126
- - `page` (String): a view object to render.
162
+
163
+ - `page` (String): a view object to render.
127
164
 
128
165
  Example:
129
166
 
@@ -135,14 +172,15 @@ page: Admin::Stats
135
172
  ```
136
173
 
137
174
  For _resource_ sections:
138
- - `model` (String): the class to use to fetch the data on an item of a collection;
139
- - `repository` (String): the class to get the properties related to the model;
140
- - `index` (Hash): collection's action options;
141
- - `show` (Hash): detail's action options;
142
- - `collection_actions` (Array of hashes): custom collection's actions;
143
- - `member_actions` (Array of hashes): custom details's actions;
144
- - `only` (Array of strings): list of supported actions (ex. `index`);
145
- - `options` (Array of strings): resource options (ex. `hidden`).
175
+
176
+ - `model` (String): the class to use to fetch the data on an item of a collection;
177
+ - `repository` (String): the class to get the properties related to the model;
178
+ - `index` (Hash): collection's action options (see below);
179
+ - `show` (Hash): detail's action options (see below);
180
+ - `collection_actions` (Array of hashes): custom collection's actions;
181
+ - `member_actions` (Array of hashes): custom details's actions;
182
+ - `only` (Array of strings): list of supported actions (ex. `index`);
183
+ - `options` (Array of strings): resource options (ex. `hidden`).
146
184
 
147
185
  Example:
148
186
 
@@ -153,14 +191,72 @@ type: resource
153
191
  model: Post
154
192
  ```
155
193
 
156
- `style_links` (Array of hashes): list of styles files to include, properties:
157
- - `href` (String): URL for the style file;
158
- - `rel` (String): type of style file.
194
+ #### Resource index options
159
195
 
160
- `scripts` (Array of hashes): list of scripts to include, properties:
161
- - `src` (String): source URL for the script.
196
+ The Index hash supports the following options:
162
197
 
163
- `extra_styles` (String): inline CSS styles.
198
+ - `attributes` (Array): fields to expose in the resource list page;
199
+ - `filters` (Array): filter the current listing;
200
+ - `links` (Array): custom member actions to expose for each list's entry (defined in _member_actions_);
201
+ - `pagination` (Integer): max pages size;
202
+ - `sort` (Array): sort options to pass to the listing query.
203
+
204
+ Example:
205
+
206
+ ```yml
207
+ index:
208
+ sort:
209
+ - id DESC
210
+ pagination: 10
211
+ attributes:
212
+ - id
213
+ - author: call, name
214
+ - position: round, 1
215
+ - field: author_id
216
+ header: The author
217
+ link_to: authors
218
+ call: author, name
219
+ filters:
220
+ - title
221
+ - field: state
222
+ type: select
223
+ values:
224
+ - published
225
+ - draft
226
+ - archived
227
+ links:
228
+ - show
229
+ - author_posts
230
+ - csv_export
231
+ ```
232
+
233
+ #### Resource show options
234
+
235
+ The Show hash supports the following options:
236
+
237
+ - `attributes` (Array): fields to expose in the resource details page.
238
+
239
+ Example:
240
+
241
+ ```yml
242
+ show:
243
+ attributes:
244
+ # Expose the id column
245
+ - id
246
+ # Expose the title column, calling `downcase` support method
247
+ - title: downcase
248
+ # Expose the category column, calling `upcase` support method
249
+ - category: upcase
250
+ # Expose the position column, calling `format` support method with argument %f
251
+ - position: format, %f
252
+ # Expose the position created_at, calling `strftime` support method with argument %Y%m%d %H:%M
253
+ - created_at: strftime, %Y%m%d %H:%M
254
+ # Expose the author_id column, with a custom header label, linked to authors section and calling author.name to get the value
255
+ - field: author_id
256
+ header: The author
257
+ link_to: authors
258
+ call: author, name
259
+ ```
164
260
 
165
261
  ### Sample
166
262
 
@@ -6,6 +6,7 @@ module TinyAdmin
6
6
  attr_reader :current_page,
7
7
  :fields_options,
8
8
  :filters_list,
9
+ :links,
9
10
  :pagination,
10
11
  :pages,
11
12
  :params,
@@ -13,18 +14,19 @@ module TinyAdmin
13
14
  :repository,
14
15
  :sort
15
16
 
16
- def call(app:, context:, options:, actions:)
17
+ def call(app:, context:, options:)
17
18
  evaluate_options(options)
18
19
  fields = repository.fields(options: fields_options)
19
20
  filters = prepare_filters(fields, filters_list)
20
21
  records, total_count = repository.list(page: current_page, limit: pagination, filters: filters, sort: sort)
21
22
 
22
23
  prepare_page(Views::Actions::Index) do |page|
23
- setup_pagination(page, settings.components[:pagination], total_count: total_count)
24
+ setup_pagination(page, TinyAdmin.settings.components[:pagination], total_count: total_count)
24
25
  page.update_attributes(
25
- actions: actions,
26
+ actions: context.actions,
26
27
  fields: fields,
27
28
  filters: filters,
29
+ links: links,
28
30
  prepare_record: ->(record) { repository.index_record_attrs(record, fields: fields_options) },
29
31
  records: records,
30
32
  title: repository.index_title
@@ -40,7 +42,8 @@ module TinyAdmin
40
42
  @repository = context.repository
41
43
  @filters_list = options[:filters]
42
44
  @pagination = options[:pagination] || 10
43
- @sort = options[:sort] || ['id']
45
+ @sort = options[:sort]
46
+ @links = options[:links]
44
47
 
45
48
  @current_page = (params['p'] || 1).to_i
46
49
  @query_string = params_to_s(params.except('p'))
@@ -60,7 +63,7 @@ module TinyAdmin
60
63
  return if pages <= 1 || !pagination_component_class
61
64
 
62
65
  page.pagination_component = pagination_component_class.new
63
- page.pagination_component.update(current: current_page, pages: pages, query_string: query_string)
66
+ page.pagination_component.update_attributes(current: current_page, pages: pages, query_string: query_string)
64
67
  end
65
68
  end
66
69
  end
@@ -3,18 +3,17 @@
3
3
  module TinyAdmin
4
4
  module Actions
5
5
  class Show < BasicAction
6
- attr_reader :repository
7
-
8
- def call(app:, context:, options:, actions:)
9
- @repository = context.repository
6
+ def call(app:, context:, options:)
10
7
  fields_options = attribute_options(options[:attributes])
8
+ repository = context.repository
11
9
  record = repository.find(context.reference)
10
+ prepare_record = ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) }
12
11
 
13
12
  prepare_page(Views::Actions::Show) do |page|
14
13
  page.update_attributes(
15
- actions: actions,
14
+ actions: context.actions,
16
15
  fields: repository.fields(options: fields_options),
17
- prepare_record: ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) },
16
+ prepare_record: prepare_record,
18
17
  record: record,
19
18
  title: repository.show_title(record)
20
19
  )
@@ -5,7 +5,7 @@ module TinyAdmin
5
5
  route do |r|
6
6
  r.get 'unauthenticated' do
7
7
  if current_user
8
- r.redirect settings.root_path
8
+ r.redirect TinyAdmin.settings.root_path
9
9
  else
10
10
  render_login
11
11
  end
@@ -17,14 +17,14 @@ module TinyAdmin
17
17
 
18
18
  r.get 'logout' do
19
19
  logout_user
20
- r.redirect settings.root_path
20
+ r.redirect TinyAdmin.settings.root_path
21
21
  end
22
22
  end
23
23
 
24
24
  private
25
25
 
26
26
  def render_login(notices: nil, warnings: nil, errors: nil)
27
- page = prepare_page(settings.authentication[:login], options: %i[no_menu compact_layout])
27
+ page = prepare_page(TinyAdmin.settings.authentication[:login], options: %i[no_menu compact_layout])
28
28
  page.messages = {
29
29
  notices: notices || flash['notices'],
30
30
  warnings: warnings || flash['warnings'],
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
 
7
7
  class << self
8
8
  def authentication_plugin
9
- plugin = TinyAdmin::Settings.instance.authentication&.dig(:plugin)
9
+ plugin = TinyAdmin.settings.authentication&.dig(:plugin)
10
10
  plugin_class = plugin.is_a?(String) ? Object.const_get(plugin) : plugin
11
11
  plugin_class || TinyAdmin::Plugins::NoAuth
12
12
  end
@@ -17,8 +17,8 @@ module TinyAdmin
17
17
  plugin :render, engine: 'html'
18
18
  plugin :sessions, secret: SecureRandom.hex(64)
19
19
 
20
- plugin authentication_plugin, TinyAdmin::Settings.instance.authentication
20
+ plugin authentication_plugin, TinyAdmin.settings.authentication
21
21
 
22
- not_found { prepare_page(settings.page_not_found).call }
22
+ not_found { prepare_page(TinyAdmin.settings.page_not_found).call }
23
23
  end
24
24
  end
@@ -4,6 +4,15 @@ module TinyAdmin
4
4
  class Context
5
5
  include Singleton
6
6
 
7
- attr_accessor :reference, :repository, :request, :router, :settings, :slug
7
+ attr_accessor :actions,
8
+ :navbar,
9
+ :pages,
10
+ :reference,
11
+ :repository,
12
+ :request,
13
+ :resources,
14
+ :router,
15
+ :settings,
16
+ :slug
8
17
  end
9
18
  end
@@ -7,19 +7,20 @@ module TinyAdmin
7
7
  def initialize(name:, title:, type:, options: {})
8
8
  @type = type
9
9
  @name = name
10
- @title = title || name
10
+ @title = title
11
11
  @options = options
12
12
  end
13
13
 
14
+ def apply_call_option(target)
15
+ messages = (options[:call] || '').split(',').map(&:strip)
16
+ messages.inject(target) { |result, msg| result&.send(msg) } if messages.any?
17
+ end
18
+
14
19
  class << self
15
20
  def create_field(name:, title: nil, type: nil, options: {})
16
21
  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
- )
22
+ field_title = field_name.respond_to?(:humanize) ? field_name.humanize : field_name.tr('_', ' ').capitalize
23
+ new(name: field_name, title: title || field_title, type: type || :string, options: options || {})
23
24
  end
24
25
  end
25
26
  end
@@ -20,12 +20,12 @@ module TinyAdmin
20
20
  def fields(options: nil)
21
21
  if options
22
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)
23
+ options.to_h do |name, field_options|
24
+ [name, TinyAdmin::Field.create_field(name: name, type: types[name], options: field_options)]
25
25
  end
26
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)
27
+ model.columns.to_h do |column|
28
+ [column.name, TinyAdmin::Field.create_field(name: column.name, type: column.type)]
29
29
  end
30
30
  end
31
31
  end
@@ -42,8 +42,12 @@ module TinyAdmin
42
42
  raise BaseRepository::RecordNotFound, e.message
43
43
  end
44
44
 
45
- def list(page: 1, limit: 10, sort: ['id'], filters: nil)
46
- query = model.all.order(sort)
45
+ def collection
46
+ model.all
47
+ end
48
+
49
+ def list(page: 1, limit: 10, sort: nil, filters: nil)
50
+ query = sort ? collection.order(sort) : collection
47
51
  query = apply_filters(query, filters) if filters
48
52
  page_offset = page.positive? ? (page - 1) * limit : 0
49
53
  records = query.offset(page_offset).limit(limit).to_a
@@ -18,7 +18,7 @@ module TinyAdmin
18
18
  converter = Object.const_get(field[:converter])
19
19
  converter.send(method, value, options: options || [])
20
20
  else
21
- Settings.instance.helper_class.send(method, value, options: options || [])
21
+ TinyAdmin.settings.helper_class.send(method, value, options: options || [])
22
22
  end
23
23
  else
24
24
  value&.to_s
@@ -2,10 +2,11 @@
2
2
 
3
3
  module TinyAdmin
4
4
  class Router < BasicApp
5
+ TinyAdmin.settings.load_settings
6
+
5
7
  route do |r|
6
- context.settings = TinyAdmin::Settings.instance
7
- context.settings.load_settings
8
8
  context.router = r
9
+ context.settings = TinyAdmin.settings
9
10
 
10
11
  r.on 'auth' do
11
12
  context.slug = nil
@@ -26,14 +27,14 @@ module TinyAdmin
26
27
 
27
28
  r.post '' do
28
29
  context.slug = nil
29
- r.redirect settings.root_path
30
+ r.redirect TinyAdmin.settings.root_path
30
31
  end
31
32
 
32
- context.settings.pages.each do |slug, data|
33
- setup_page_route(r, slug, data)
33
+ context.pages.each do |slug, page_data|
34
+ setup_page_route(r, slug, page_data)
34
35
  end
35
36
 
36
- context.settings.resources.each do |slug, options|
37
+ context.resources.each do |slug, options|
37
38
  setup_resource_routes(r, slug, options: options || {})
38
39
  end
39
40
 
@@ -51,19 +52,21 @@ module TinyAdmin
51
52
 
52
53
  def root_route(router)
53
54
  context.slug = nil
54
- if settings.root[:redirect]
55
- router.redirect route_for(settings.root[:redirect])
55
+ if TinyAdmin.settings.root[:redirect]
56
+ router.redirect route_for(TinyAdmin.settings.root[:redirect])
56
57
  else
57
- page = settings.root[:page]
58
+ page = TinyAdmin.settings.root[:page]
58
59
  page_class = page.is_a?(String) ? Object.const_get(page) : page
59
60
  render_page prepare_page(page_class)
60
61
  end
61
62
  end
62
63
 
63
- def setup_page_route(router, slug, page_class)
64
+ def setup_page_route(router, slug, page_data)
64
65
  router.get slug do
65
66
  context.slug = slug
66
- render_page prepare_page(page_class)
67
+ page = prepare_page(page_data[:class])
68
+ page.update_attributes(content: page_data[:content]) if page_data[:content]
69
+ render_page page
67
70
  end
68
71
  end
69
72
 
@@ -88,19 +91,19 @@ module TinyAdmin
88
91
  )
89
92
 
90
93
  # Index
91
- actions = options[:only]
92
- if !actions || actions.include?(:index) || actions.include?('index')
94
+ if options[:only].include?(:index) || options[:only].include?('index')
93
95
  router.is do
96
+ context.actions = custom_actions
94
97
  context.request = request
95
98
  index_action = TinyAdmin::Actions::Index.new
96
- render_page index_action.call(app: self, context: context, options: action_options, actions: custom_actions)
99
+ render_page index_action.call(app: self, context: context, options: action_options)
97
100
  end
98
101
  end
99
102
  end
100
103
 
101
104
  def setup_member_routes(router, options:)
102
105
  context.repository = options[:repository].new(options[:model])
103
- action_options = (options[:show] || {}).merge(record_not_found_page: settings.record_not_found)
106
+ action_options = (options[:show] || {}).merge(record_not_found_page: TinyAdmin.settings.record_not_found)
104
107
 
105
108
  router.on String do |reference|
106
109
  context.reference = reference
@@ -114,12 +117,12 @@ module TinyAdmin
114
117
  )
115
118
 
116
119
  # Show
117
- actions = options[:only]
118
- if !actions || actions.include?(:show) || actions.include?('show')
120
+ if options[:only].include?(:show) || options[:only].include?('show')
119
121
  router.is do
122
+ context.actions = custom_actions
120
123
  context.request = request
121
124
  show_action = TinyAdmin::Actions::Show.new
122
- render_page show_action.call(app: self, context: context, options: action_options, actions: custom_actions)
125
+ render_page show_action.call(app: self, context: context, options: action_options)
123
126
  end
124
127
  end
125
128
  end
@@ -132,6 +135,7 @@ module TinyAdmin
132
135
  action_class = action.is_a?(String) ? Object.const_get(action) : action
133
136
 
134
137
  router.get action_slug.to_s do
138
+ context.actions = {}
135
139
  context.request = request
136
140
  custom_action = action_class.new
137
141
  render_page custom_action.call(app: self, context: context, options: options)
@@ -12,6 +12,7 @@ module TinyAdmin
12
12
  %i[components head] => Views::Components::Head,
13
13
  %i[components navbar] => Views::Components::Navbar,
14
14
  %i[components pagination] => Views::Components::Pagination,
15
+ %i[content_page] => Views::Pages::Content,
15
16
  %i[helper_class] => Support,
16
17
  %i[page_not_found] => Views::Pages::PageNotFound,
17
18
  %i[record_not_found] => Views::Pages::RecordNotFound,
@@ -21,28 +22,40 @@ module TinyAdmin
21
22
  %i[root title] => 'TinyAdmin'
22
23
  }.freeze
23
24
 
24
- attr_accessor :authentication,
25
- :components,
26
- :extra_styles,
27
- :helper_class,
28
- :navbar,
29
- :page_not_found,
30
- :record_not_found,
31
- :repository,
32
- :root,
33
- :root_path,
34
- :sections,
35
- :scripts,
36
- :style_links
37
-
38
- attr_reader :pages, :resources
39
-
40
- def [](key)
41
- send(key)
25
+ OPTIONS = %i[
26
+ authentication
27
+ components
28
+ content_page
29
+ extra_styles
30
+ helper_class
31
+ page_not_found
32
+ record_not_found
33
+ repository
34
+ root
35
+ root_path
36
+ sections
37
+ scripts
38
+ style_links
39
+ ].freeze
40
+
41
+ OPTIONS.each do |option|
42
+ define_method(option) do
43
+ self[option]
44
+ end
45
+
46
+ define_method("#{option}=") do |value|
47
+ self[option] = value
48
+ end
49
+ end
50
+
51
+ def [](*path)
52
+ key, option = fetch_setting(path)
53
+ option[key]
42
54
  end
43
55
 
44
- def []=(key, value)
45
- send("#{key}=", value)
56
+ def []=(*path, value)
57
+ key, option = fetch_setting(path)
58
+ option[key] = value
46
59
  convert_value(key, value)
47
60
  end
48
61
 
@@ -57,43 +70,29 @@ module TinyAdmin
57
70
  end
58
71
  end
59
72
 
60
- @pages ||= {}
61
- @resources ||= {}
62
- @sections ||= []
63
- @root_path = '/' if @root_path == ''
64
- if @authentication[:plugin] == Plugins::SimpleAuth
65
- @authentication[:logout] ||= ['logout', "#{root_path}/auth/logout"]
73
+ context.pages ||= {}
74
+ context.resources ||= {}
75
+ self.sections ||= []
76
+ self.root_path = '/' if root_path == ''
77
+
78
+ if authentication[:plugin] <= Plugins::SimpleAuth
79
+ authentication[:logout] ||= { name: 'logout', path: "#{root_path}/auth/logout" }
66
80
  end
67
- @navbar = prepare_navbar(sections, logout: authentication[:logout])
81
+ context.navbar = prepare_navbar(sections, logout: authentication[:logout])
68
82
  end
69
83
 
70
- def prepare_navbar(sections, logout:)
71
- items = sections.each_with_object({}) do |section, list|
72
- slug = section[:slug]
73
- case section[:type]&.to_sym
74
- when :url
75
- list[slug] = [section[:name], section[:url], section[:options]]
76
- when :page
77
- page = section[:page]
78
- pages[slug] = page.is_a?(String) ? Object.const_get(page) : page
79
- list[slug] = [section[:name], route_for(slug)]
80
- when :resource
81
- repository = section[:repository] || settings.repository
82
- resources[slug] = {
83
- model: section[:model].is_a?(String) ? Object.const_get(section[:model]) : section[:model],
84
- repository: repository.is_a?(String) ? Object.const_get(repository) : repository
85
- }
86
- resources[slug].merge! section.slice(:resource, :only, :index, :show, :collection_actions, :member_actions)
87
- hidden = section[:options] && (section[:options].include?(:hidden) || section[:options].include?('hidden'))
88
- list[slug] = [section[:name], route_for(slug)] unless hidden
89
- end
90
- end
91
- items['auth/logout'] = logout if logout
92
- items
84
+ def reset!
85
+ @options = {}
93
86
  end
94
87
 
95
88
  private
96
89
 
90
+ def fetch_setting(path)
91
+ @options ||= {}
92
+ *parts, last = path.map(&:to_sym)
93
+ [last, parts.inject(@options) { |result, part| result[part] ||= {} }]
94
+ end
95
+
97
96
  def convert_value(key, value)
98
97
  if value.is_a?(Hash)
99
98
  value.each_key do |key2|
@@ -106,5 +105,59 @@ module TinyAdmin
106
105
  self[key] = Object.const_get(self[key])
107
106
  end
108
107
  end
108
+
109
+ def prepare_navbar(sections, logout:)
110
+ items = sections.each_with_object({}) do |section, list|
111
+ unless section.is_a?(Hash)
112
+ section_class = section.is_a?(String) ? Object.const_get(section) : section
113
+ next unless section_class.respond_to?(:to_h)
114
+
115
+ section = section_class.to_h
116
+ end
117
+
118
+ slug = section[:slug].to_s
119
+ case section[:type]&.to_sym
120
+ when :content
121
+ list[slug] = add_content_section(slug, section)
122
+ when :page
123
+ list[slug] = add_page_section(slug, section)
124
+ when :resource
125
+ list[slug] = add_resource_section(slug, section)
126
+ when :url
127
+ list[slug] = add_url_section(slug, section)
128
+ end
129
+ end
130
+ items['auth/logout'] = logout if logout
131
+ items
132
+ end
133
+
134
+ def add_content_section(slug, section)
135
+ context.pages[slug] = { class: content_page, content: section[:content] }
136
+ { name: section[:name], path: route_for(slug), class: content_page }
137
+ end
138
+
139
+ def add_page_section(slug, section)
140
+ page = section[:page]
141
+ page_class = page.is_a?(String) ? Object.const_get(page) : page
142
+ context.pages[slug] = { class: page_class }
143
+ { name: section[:name], path: route_for(slug), class: page_class }
144
+ end
145
+
146
+ def add_resource_section(slug, section)
147
+ repo = section[:repository] || repository
148
+ context.resources[slug] = {
149
+ model: section[:model].is_a?(String) ? Object.const_get(section[:model]) : section[:model],
150
+ repository: repo.is_a?(String) ? Object.const_get(repo) : repo
151
+ }
152
+ resource_options = section.slice(:resource, :only, :index, :show, :collection_actions, :member_actions)
153
+ resource_options[:only] ||= %i[index show]
154
+ context.resources[slug].merge!(resource_options)
155
+ hidden = section[:options] && (section[:options].include?(:hidden) || section[:options].include?('hidden'))
156
+ { name: section[:name], path: route_for(slug) } unless hidden
157
+ end
158
+
159
+ def add_url_section(_slug, section)
160
+ section.slice(:name, :options).tap { _1[:path] = section[:url] }
161
+ end
109
162
  end
110
163
  end
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  class Support
5
5
  class << self
6
6
  def call(value, options: [])
7
- value && options&.any? ? options.inject(value) { |result, message| result&.send(message) } : value
7
+ options.inject(value) { |result, message| result&.send(message) } if value && options&.any?
8
8
  end
9
9
 
10
10
  def downcase(value, options: [])
@@ -12,7 +12,7 @@ module TinyAdmin
12
12
  end
13
13
 
14
14
  def format(value, options: [])
15
- value && options&.any? ? Kernel.format(options.first, value) : value
15
+ Kernel.format(options.first, value) if value && options&.any?
16
16
  end
17
17
 
18
18
  def round(value, options: [])
@@ -20,11 +20,11 @@ module TinyAdmin
20
20
  end
21
21
 
22
22
  def strftime(value, options: [])
23
- value ? value.strftime(options&.first || '%Y-%m-%d %H:%M') : ''
23
+ value&.strftime(options&.first || '%Y-%m-%d %H:%M')
24
24
  end
25
25
 
26
26
  def to_date(value, options: [])
27
- value ? value.to_date.to_s : value
27
+ value.to_date.to_s if value
28
28
  end
29
29
 
30
30
  def upcase(value, options: [])
@@ -5,7 +5,8 @@ module TinyAdmin
5
5
  def params_to_s(params)
6
6
  list = params.each_with_object([]) do |(param, value), result|
7
7
  if value.is_a?(Hash)
8
- result.concat(value.map { |k, v| "#{param}[#{k}]=#{v}" })
8
+ values = value.map { |key, val| "#{param}[#{key}]=#{val}" }
9
+ result.concat(values)
9
10
  else
10
11
  result.push(["#{param}=#{value}"])
11
12
  end
@@ -16,32 +17,34 @@ module TinyAdmin
16
17
  def prepare_page(page_class, options: nil)
17
18
  page_class.new.tap do |page|
18
19
  page.options = options
19
- page.head_component = settings.components[:head]&.new
20
- page.flash_component = settings.components[:flash]&.new
21
- page.navbar_component = settings.components[:navbar]&.new(
20
+ page.head_component = TinyAdmin.settings.components[:head]&.new
21
+ page.flash_component = TinyAdmin.settings.components[:flash]&.new
22
+ page.navbar_component = TinyAdmin.settings.components[:navbar]&.new
23
+ page.navbar_component&.update_attributes(
22
24
  current_slug: context&.slug,
23
- root_path: settings.root_path,
24
- root_title: settings.root[:title],
25
- items: options&.include?(:no_menu) ? [] : settings.navbar
25
+ root_path: TinyAdmin.settings.root_path,
26
+ root_title: TinyAdmin.settings.root[:title],
27
+ items: options&.include?(:no_menu) ? [] : context&.navbar
26
28
  )
27
-
28
29
  yield(page) if block_given?
29
30
  end
30
31
  end
31
32
 
32
33
  def route_for(section, reference: nil, action: nil, query: nil)
33
- root_path = settings.root_path == '/' ? nil : settings.root_path
34
+ root_path = TinyAdmin.settings.root_path == '/' ? nil : TinyAdmin.settings.root_path
34
35
  route = [root_path, section, reference, action].compact.join("/")
35
36
  route << "?#{query}" if query
36
37
  route[0] == '/' ? route : route.prepend('/')
37
38
  end
38
39
 
39
- def context
40
- TinyAdmin::Context.instance
40
+ def to_label(string)
41
+ return '' unless string
42
+
43
+ string.respond_to?(:humanize) ? string.humanize : string.tr('_', ' ').capitalize
41
44
  end
42
45
 
43
- def settings
44
- TinyAdmin::Settings.instance
46
+ def context
47
+ TinyAdmin::Context.instance
45
48
  end
46
49
  end
47
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.4.0'
4
+ VERSION = '0.6.0'
5
5
  end
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Actions
6
6
  class Index < DefaultLayout
7
- attr_accessor :actions, :fields, :filters, :pagination_component, :prepare_record, :records
7
+ attr_accessor :actions, :fields, :filters, :links, :pagination_component, :prepare_record, :records
8
8
 
9
9
  def template
10
10
  super do
@@ -30,8 +30,9 @@ module TinyAdmin
30
30
 
31
31
  if filters&.any?
32
32
  div(class: 'col-3') {
33
- filters_form_attrs = { section_path: route_for(context.slug), filters: filters }
34
- render TinyAdmin::Views::Components::FiltersForm.new(**filters_form_attrs)
33
+ filters_form = TinyAdmin::Views::Components::FiltersForm.new
34
+ filters_form.update_attributes(section_path: route_for(context.slug), filters: filters)
35
+ render filters_form
35
36
  }
36
37
  end
37
38
  }
@@ -65,16 +66,33 @@ module TinyAdmin
65
66
  field = fields[key]
66
67
  td(class: "field-value-#{field.name} field-value-type-#{field.type}") {
67
68
  if field.options && field.options[:link_to]
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 }
69
+ a(href: route_for(field.options[:link_to], reference: value)) {
70
+ field.apply_call_option(record) || value
71
+ }
71
72
  else
72
73
  value
73
74
  end
74
75
  }
75
76
  end
76
- td(class: 'actions') {
77
- a(href: route_for(context.slug, reference: record.id)) { 'show' }
77
+
78
+ td(class: 'actions p-1') {
79
+ div(class: 'btn-group btn-group-sm') {
80
+ link_class = 'btn btn-outline-secondary'
81
+ if links
82
+ links.each do |link|
83
+ whitespace
84
+ if link == 'show'
85
+ a(href: route_for(context.slug, reference: record.id), class: link_class) { 'show' }
86
+ else
87
+ a(href: route_for(context.slug, reference: record.id, action: link), class: link_class) {
88
+ to_label(link)
89
+ }
90
+ end
91
+ end
92
+ else
93
+ a(href: route_for(context.slug, reference: record.id), class: link_class) { 'show' }
94
+ end
95
+ }
78
96
  }
79
97
  }
80
98
  end
@@ -86,8 +104,9 @@ module TinyAdmin
86
104
  (actions || {}).each do |action, action_class|
87
105
  li(class: 'nav-item mx-1') {
88
106
  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 }
107
+ a(href: href, class: 'nav-link btn btn-outline-secondary') {
108
+ action_class.respond_to?(:title) ? action_class.title : action
109
+ }
91
110
  }
92
111
  end
93
112
  }
@@ -25,10 +25,10 @@ module TinyAdmin
25
25
  div(class: 'field-header col-2') { field.options[:header] || field.title }
26
26
  end
27
27
  div(class: 'field-value col-10') {
28
- if field.options && field.options[:link_to]
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 }
28
+ if field.options[:link_to]
29
+ a(href: route_for(field.options[:link_to], reference: value)) {
30
+ field.apply_call_option(record) || value
31
+ }
32
32
  else
33
33
  value
34
34
  end
@@ -46,8 +46,9 @@ module TinyAdmin
46
46
  (actions || {}).each do |action, action_class|
47
47
  li(class: 'nav-item mx-1') {
48
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 }
49
+ a(href: href, class: 'nav-link btn btn-outline-secondary') {
50
+ action_class.respond_to?(:title) ? action_class.title : action
51
+ }
51
52
  }
52
53
  end
53
54
  }
@@ -5,6 +5,8 @@ module TinyAdmin
5
5
  class BasicLayout < Phlex::HTML
6
6
  include Utils
7
7
 
8
+ attr_accessor :content
9
+
8
10
  def update_attributes(attributes)
9
11
  attributes.each do |key, value|
10
12
  send("#{key}=", value)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Components
6
+ class BasicComponent < Phlex::HTML
7
+ def update_attributes(attributes)
8
+ attributes.each do |key, value|
9
+ send("#{key}=", value)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,13 +3,8 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Components
6
- class FiltersForm < Phlex::HTML
7
- attr_reader :filters, :section_path
8
-
9
- def initialize(section_path:, filters:)
10
- @section_path = section_path
11
- @filters = filters
12
- end
6
+ class FiltersForm < BasicComponent
7
+ attr_accessor :filters, :section_path
13
8
 
14
9
  def template
15
10
  form(class: 'form_filters', method: 'get') {
@@ -3,24 +3,21 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Components
6
- class Flash < Phlex::HTML
7
- attr_reader :errors, :notices, :warnings
6
+ class Flash < BasicComponent
7
+ attr_accessor :messages
8
8
 
9
9
  def template
10
+ @messages ||= {}
11
+ notices = messages[:notices]
12
+ warnings = messages[:warnings]
13
+ errors = messages[:errors]
14
+
10
15
  div(class: 'flash') {
11
16
  div(class: 'notices alert alert-success', role: 'alert') { notices.join(', ') } if notices&.any?
12
17
  div(class: 'notices alert alert-warning', role: 'alert') { warnings.join(', ') } if warnings&.any?
13
18
  div(class: 'notices alert alert-danger', role: 'alert') { errors.join(', ') } if errors&.any?
14
19
  }
15
20
  end
16
-
17
- def update(messages:)
18
- return unless messages
19
-
20
- @notices = messages[:notices]
21
- @warnings = messages[:warnings]
22
- @errors = messages[:errors]
23
- end
24
21
  end
25
22
  end
26
23
  end
@@ -3,8 +3,8 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Components
6
- class Head < Phlex::HTML
7
- attr_reader :extra_styles, :page_title, :style_links
6
+ class Head < BasicComponent
7
+ attr_accessor :extra_styles, :page_title, :style_links
8
8
 
9
9
  def template
10
10
  head {
@@ -19,12 +19,6 @@ module TinyAdmin
19
19
  style { extra_styles } if extra_styles
20
20
  }
21
21
  end
22
-
23
- def update(page_title, style_links: [], extra_styles: nil)
24
- @page_title = page_title
25
- @style_links = style_links
26
- @extra_styles = extra_styles
27
- end
28
22
  end
29
23
  end
30
24
  end
@@ -3,33 +3,34 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Components
6
- class Navbar < Phlex::HTML
7
- attr_reader :current_slug, :items, :root_path, :root_title
8
-
9
- def initialize(root_path:, root_title:, items: [], current_slug: nil)
10
- @root_path = root_path
11
- @root_title = root_title
12
- @items = items || []
13
- @current_slug = current_slug
14
- end
6
+ class Navbar < BasicComponent
7
+ attr_accessor :current_slug, :items, :root_path, :root_title
15
8
 
16
9
  def template
17
10
  nav(class: 'navbar navbar-expand-lg') {
18
11
  div(class: 'container') {
19
12
  a(class: 'navbar-brand', href: root_path) { root_title }
20
- button(class: 'navbar-toggler', type: 'button', 'data-bs-toggle' => 'collapse', 'data-bs-target' => '#navbarNav', 'aria-controls' => 'navbarNav', 'aria-expanded' => 'false', 'aria-label' => 'Toggle navigation') {
13
+ button(
14
+ class: 'navbar-toggler',
15
+ type: 'button',
16
+ 'data-bs-toggle' => 'collapse',
17
+ 'data-bs-target' => '#navbarNav',
18
+ 'aria-controls' => 'navbarNav',
19
+ 'aria-expanded' => 'false',
20
+ 'aria-label' => 'Toggle navigation'
21
+ ) {
21
22
  span(class: 'navbar-toggler-icon')
22
23
  }
23
24
  div(class: 'collapse navbar-collapse', id: 'navbarNav') {
24
25
  ul(class: 'navbar-nav') {
25
- items.each do |slug, (name, path, options)|
26
+ items.each do |slug, item|
26
27
  classes = %w[nav-link]
27
28
  classes << 'active' if slug == current_slug
28
- link_attributes = { class: classes.join(' '), href: path, 'aria-current' => 'page' }
29
- link_attributes.merge!(options) if options
29
+ link_attributes = { class: classes.join(' '), href: item[:path], 'aria-current' => 'page' }
30
+ link_attributes.merge!(item[:options]) if item[:options]
30
31
 
31
32
  li(class: 'nav-item') {
32
- a(**link_attributes) { name }
33
+ a(**link_attributes) { item[:name] }
33
34
  }
34
35
  end
35
36
  }
@@ -3,8 +3,8 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  module Components
6
- class Pagination < Phlex::HTML
7
- attr_reader :current, :pages, :query_string
6
+ class Pagination < BasicComponent
7
+ attr_accessor :current, :pages, :query_string
8
8
 
9
9
  def template
10
10
  div(class: 'pagination-div') {
@@ -25,12 +25,6 @@ module TinyAdmin
25
25
  }
26
26
  end
27
27
 
28
- def update(current:, pages:, query_string:)
29
- @current = current
30
- @pages = pages
31
- @query_string = query_string
32
- end
33
-
34
28
  private
35
29
 
36
30
  def pages_range(range, with_dots: false)
@@ -6,8 +6,9 @@ module TinyAdmin
6
6
  attr_accessor :flash_component, :head_component, :messages, :navbar_component, :options, :title
7
7
 
8
8
  def template(&block)
9
- flash_component&.update(messages: messages)
10
- head_component&.update(title, style_links: style_links, extra_styles: settings.extra_styles)
9
+ extra_styles = TinyAdmin.settings.extra_styles
10
+ flash_component&.messages = messages
11
+ head_component&.update_attributes(page_title: title, style_links: style_links, extra_styles: extra_styles)
11
12
 
12
13
  doctype
13
14
  html {
@@ -48,7 +49,7 @@ module TinyAdmin
48
49
  end
49
50
 
50
51
  def style_links
51
- settings.style_links || [
52
+ TinyAdmin.settings.style_links || [
52
53
  # Bootstrap CDN
53
54
  {
54
55
  href: 'https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css',
@@ -60,7 +61,7 @@ module TinyAdmin
60
61
  end
61
62
 
62
63
  def render_scripts
63
- (settings.scripts || []).each do |script_attrs|
64
+ (TinyAdmin.settings.scripts || []).each do |script_attrs|
64
65
  script(**script_attrs)
65
66
  end
66
67
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Pages
6
+ class Content < DefaultLayout
7
+ def template
8
+ super do
9
+ div(class: 'content') {
10
+ unsafe_raw(content)
11
+ }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/tiny_admin.rb CHANGED
@@ -12,15 +12,20 @@ loader.setup
12
12
 
13
13
  module TinyAdmin
14
14
  def configure(&block)
15
- block&.call(TinyAdmin::Settings.instance) || TinyAdmin::Settings.instance
15
+ block&.call(settings) || settings
16
16
  end
17
17
 
18
18
  def configure_from_file(file)
19
+ settings.reset!
19
20
  config = YAML.load_file(file, symbolize_names: true)
20
21
  config.each do |key, value|
21
- TinyAdmin::Settings.instance[key] = value
22
+ settings[key] = value
22
23
  end
23
24
  end
24
25
 
25
- module_function :configure, :configure_from_file
26
+ def settings
27
+ TinyAdmin::Settings.instance
28
+ end
29
+
30
+ module_function :configure, :configure_from_file, :settings
26
31
  end
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.4.0
4
+ version: 0.6.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-18 00:00:00.000000000 Z
11
+ date: 2023-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -94,12 +94,14 @@ files:
94
94
  - lib/tiny_admin/views/actions/index.rb
95
95
  - lib/tiny_admin/views/actions/show.rb
96
96
  - lib/tiny_admin/views/basic_layout.rb
97
+ - lib/tiny_admin/views/components/basic_component.rb
97
98
  - lib/tiny_admin/views/components/filters_form.rb
98
99
  - lib/tiny_admin/views/components/flash.rb
99
100
  - lib/tiny_admin/views/components/head.rb
100
101
  - lib/tiny_admin/views/components/navbar.rb
101
102
  - lib/tiny_admin/views/components/pagination.rb
102
103
  - lib/tiny_admin/views/default_layout.rb
104
+ - lib/tiny_admin/views/pages/content.rb
103
105
  - lib/tiny_admin/views/pages/page_not_found.rb
104
106
  - lib/tiny_admin/views/pages/record_not_found.rb
105
107
  - lib/tiny_admin/views/pages/root.rb