tiny_admin 0.4.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +140 -44
- data/lib/tiny_admin/actions/index.rb +8 -5
- data/lib/tiny_admin/actions/show.rb +5 -6
- data/lib/tiny_admin/authentication.rb +3 -3
- data/lib/tiny_admin/basic_app.rb +3 -3
- data/lib/tiny_admin/context.rb +10 -1
- data/lib/tiny_admin/field.rb +8 -7
- data/lib/tiny_admin/plugins/active_record_repository.rb +10 -6
- data/lib/tiny_admin/plugins/base_repository.rb +1 -1
- data/lib/tiny_admin/router.rb +22 -18
- data/lib/tiny_admin/settings.rb +103 -50
- data/lib/tiny_admin/support.rb +4 -4
- data/lib/tiny_admin/utils.rb +16 -13
- data/lib/tiny_admin/version.rb +1 -1
- data/lib/tiny_admin/views/actions/index.rb +29 -10
- data/lib/tiny_admin/views/actions/show.rb +7 -6
- data/lib/tiny_admin/views/basic_layout.rb +2 -0
- data/lib/tiny_admin/views/components/basic_component.rb +15 -0
- data/lib/tiny_admin/views/components/filters_form.rb +2 -7
- data/lib/tiny_admin/views/components/flash.rb +7 -10
- data/lib/tiny_admin/views/components/head.rb +2 -8
- data/lib/tiny_admin/views/components/navbar.rb +15 -14
- data/lib/tiny_admin/views/components/pagination.rb +2 -8
- data/lib/tiny_admin/views/default_layout.rb +5 -4
- data/lib/tiny_admin/views/pages/content.rb +17 -0
- data/lib/tiny_admin.rb +8 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dfe9b2fef29073201e228daf3a7d89003902f8d98108e58cb8245fdb9a533e3
|
4
|
+
data.tar.gz: 6634891a9bbc2585549a759cd061a25234b834ebdcc0b77fbbb9bd2297b0a626
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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.
|
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
|
-
|
39
|
-
-
|
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
|
-
|
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
|
-
|
50
|
-
-
|
51
|
-
-
|
52
|
-
-
|
53
|
-
-
|
54
|
-
-
|
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
|
-
|
60
|
-
-
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
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
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
157
|
-
- `href` (String): URL for the style file;
|
158
|
-
- `rel` (String): type of style file.
|
194
|
+
#### Resource index options
|
159
195
|
|
160
|
-
|
161
|
-
- `src` (String): source URL for the script.
|
196
|
+
The Index hash supports the following options:
|
162
197
|
|
163
|
-
`
|
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
|
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]
|
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.
|
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
|
-
|
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:
|
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'],
|
data/lib/tiny_admin/basic_app.rb
CHANGED
@@ -6,7 +6,7 @@ module TinyAdmin
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
def authentication_plugin
|
9
|
-
plugin = TinyAdmin
|
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
|
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
|
data/lib/tiny_admin/context.rb
CHANGED
@@ -4,6 +4,15 @@ module TinyAdmin
|
|
4
4
|
class Context
|
5
5
|
include Singleton
|
6
6
|
|
7
|
-
attr_accessor :
|
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
|
data/lib/tiny_admin/field.rb
CHANGED
@@ -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
|
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
|
-
|
18
|
-
|
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.
|
24
|
-
|
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.
|
28
|
-
|
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
|
46
|
-
|
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
|
-
|
21
|
+
TinyAdmin.settings.helper_class.send(method, value, options: options || [])
|
22
22
|
end
|
23
23
|
else
|
24
24
|
value&.to_s
|
data/lib/tiny_admin/router.rb
CHANGED
@@ -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.
|
33
|
-
setup_page_route(r, slug,
|
33
|
+
context.pages.each do |slug, page_data|
|
34
|
+
setup_page_route(r, slug, page_data)
|
34
35
|
end
|
35
36
|
|
36
|
-
context.
|
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,
|
64
|
+
def setup_page_route(router, slug, page_data)
|
64
65
|
router.get slug do
|
65
66
|
context.slug = slug
|
66
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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)
|
data/lib/tiny_admin/settings.rb
CHANGED
@@ -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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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 []=(
|
45
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
81
|
+
context.navbar = prepare_navbar(sections, logout: authentication[:logout])
|
68
82
|
end
|
69
83
|
|
70
|
-
def
|
71
|
-
|
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
|
data/lib/tiny_admin/support.rb
CHANGED
@@ -4,7 +4,7 @@ module TinyAdmin
|
|
4
4
|
class Support
|
5
5
|
class << self
|
6
6
|
def call(value, options: [])
|
7
|
-
|
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
|
-
|
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
|
23
|
+
value&.strftime(options&.first || '%Y-%m-%d %H:%M')
|
24
24
|
end
|
25
25
|
|
26
26
|
def to_date(value, options: [])
|
27
|
-
value
|
27
|
+
value.to_date.to_s if value
|
28
28
|
end
|
29
29
|
|
30
30
|
def upcase(value, options: [])
|
data/lib/tiny_admin/utils.rb
CHANGED
@@ -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
|
-
|
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) ? [] :
|
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
|
40
|
-
|
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
|
44
|
-
TinyAdmin::
|
46
|
+
def context
|
47
|
+
TinyAdmin::Context.instance
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
data/lib/tiny_admin/version.rb
CHANGED
@@ -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
|
-
|
34
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
77
|
-
|
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
|
-
|
90
|
-
|
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
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
50
|
-
|
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
|
}
|
@@ -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 <
|
7
|
-
|
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 <
|
7
|
-
|
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 <
|
7
|
-
|
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 <
|
7
|
-
|
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(
|
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,
|
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 <
|
7
|
-
|
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
|
-
|
10
|
-
|
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
|
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(
|
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
|
-
|
22
|
+
settings[key] = value
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
|
-
|
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
|
+
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-
|
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
|