tiny_admin 0.6.0 → 0.8.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 +33 -2
- data/lib/tiny_admin/actions/index.rb +23 -23
- data/lib/tiny_admin/actions/show.rb +11 -9
- data/lib/tiny_admin/authentication.rb +9 -2
- data/lib/tiny_admin/context.rb +9 -14
- data/lib/tiny_admin/field.rb +13 -0
- data/lib/tiny_admin/plugins/active_record_repository.rb +1 -4
- data/lib/tiny_admin/plugins/base_repository.rb +0 -14
- data/lib/tiny_admin/router.rb +52 -37
- data/lib/tiny_admin/section.rb +14 -0
- data/lib/tiny_admin/settings.rb +10 -62
- data/lib/tiny_admin/store.rb +67 -0
- data/lib/tiny_admin/support.rb +4 -0
- data/lib/tiny_admin/utils.rb +9 -13
- data/lib/tiny_admin/version.rb +1 -1
- data/lib/tiny_admin/views/actions/index.rb +18 -15
- data/lib/tiny_admin/views/actions/show.rb +5 -9
- data/lib/tiny_admin/views/basic_layout.rb +5 -1
- data/lib/tiny_admin/views/basic_widget.rb +8 -0
- data/lib/tiny_admin/views/components/field_value.rb +33 -0
- data/lib/tiny_admin/views/components/filters_form.rb +12 -4
- data/lib/tiny_admin/views/components/navbar.rb +5 -5
- data/lib/tiny_admin/views/components/widgets.rb +35 -0
- data/lib/tiny_admin/views/pages/content.rb +5 -1
- data/lib/tiny_admin/views/pages/root.rb +1 -1
- data/lib/tiny_admin/views/pages/simple_auth_login.rb +6 -2
- data/lib/tiny_admin.rb +9 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71d42ca63e3a410de95780d584cdfb61dd94feb95b503f5f55379efabec9477e
|
4
|
+
data.tar.gz: 96c4b375cb65327635199296d11f54335e6c5266dacce39a7316e0eb2844046c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d377537524247253a871e016d3d5e688e47ab07d40c6d33814c5dfc0be761e734d3de3c8c23d3e3981d3f949ce15d230312b4c71fb2d7d6f33aeb45cc352223f
|
7
|
+
data.tar.gz: 4ddb16c2f1fbfefced95deb426cf369d28201866f800eee1f4b14895bd938233f6f67bf51d784a7edf340b48d7a75230a86b679db9ec71c07f18b726c23971a4
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# Tiny Admin
|
2
2
|
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin)
|
4
|
+
[![Gem Downloads](https://badgen.net/rubygems/dt/tiny_admin)](https://rubygems.org/gems/tiny_admin)
|
5
|
+
[![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml)
|
6
|
+
[![Specs](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml)
|
4
7
|
|
5
8
|
A compact and composable dashboard component for Ruby.
|
6
9
|
|
@@ -16,7 +19,7 @@ Please ⭐ if you like it.
|
|
16
19
|
|
17
20
|
## Install
|
18
21
|
|
19
|
-
- Add to your Gemfile: `gem 'tiny_admin', '~> 0.
|
22
|
+
- Add to your Gemfile: `gem 'tiny_admin', '~> 0.8'`
|
20
23
|
- Mount the app in a route (check some examples with: Hanami, Rails, Roda and standalone in [extra](extra))
|
21
24
|
+ in Rails, update _config/routes.rb_: `mount TinyAdmin::Router => '/admin'`
|
22
25
|
- Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` with a YAML config file (see [configuration](#configuration) below):
|
@@ -80,6 +83,9 @@ The following options are supported:
|
|
80
83
|
- `title` (String): root section's title;
|
81
84
|
- `page` (String): a view object to render;
|
82
85
|
- `redirect` (String): alternative to _page_ option - redirects to a specific slug;
|
86
|
+
- `widgets` (Array): list of widgets (as View components) to present.
|
87
|
+
|
88
|
+
> 📚 [Wiki Root page](https://github.com/blocknotes/tiny_admin/wiki/Root) available
|
83
89
|
|
84
90
|
Example:
|
85
91
|
|
@@ -87,10 +93,15 @@ Example:
|
|
87
93
|
root:
|
88
94
|
title: MyAdmin
|
89
95
|
redirect: posts
|
96
|
+
widgets:
|
97
|
+
- LatestAuthorsWidget
|
98
|
+
- LatestPostsWidget
|
90
99
|
```
|
91
100
|
|
92
101
|
`helper_class` (String): class or module with helper methods, used for attributes' formatters.
|
93
102
|
|
103
|
+
> 📚 [Wiki Helper methods page](https://github.com/blocknotes/tiny_admin/wiki/Helper-methods) available
|
104
|
+
|
94
105
|
`page_not_found` (String): a view object to render when a missing page is requested.
|
95
106
|
|
96
107
|
`record_not_found` (String): a view object to render when a missing record is requested.
|
@@ -106,11 +117,15 @@ root:
|
|
106
117
|
|
107
118
|
`extra_styles` (String): inline CSS styles.
|
108
119
|
|
120
|
+
> 📚 [Wiki Styles and scripts page](https://github.com/blocknotes/tiny_admin/wiki/Styles-and-scripts) available
|
121
|
+
|
109
122
|
`authentication` (Hash): define the authentication method, properties:
|
110
123
|
|
111
124
|
- `plugin` (String): a plugin class to use (ex. `TinyAdmin::Plugins::SimpleAuth`);
|
112
125
|
- `password` (String): a password hash used by _SimpleAuth_ plugin (generated with `Digest::SHA512.hexdigest("some password")`).
|
113
126
|
|
127
|
+
> 📚 [Wiki Authentication page](https://github.com/blocknotes/tiny_admin/wiki/Authentication) available
|
128
|
+
|
114
129
|
Example:
|
115
130
|
|
116
131
|
```yml
|
@@ -124,8 +139,11 @@ authentication:
|
|
124
139
|
- `slug` (String): section reference identifier;
|
125
140
|
- `name` (String): section's title;
|
126
141
|
- `type` (String): the type of section: `content`, `page`, `resource` or `url`;
|
142
|
+
- `widgets` (Array): list of widgets (as View components) to present;
|
127
143
|
- other properties depends on the section's type.
|
128
144
|
|
145
|
+
> 📚 [Wiki Pages page](https://github.com/blocknotes/tiny_admin/wiki/Pages) available
|
146
|
+
|
129
147
|
For _content_ sections:
|
130
148
|
|
131
149
|
- `content` (String): the HTML content to present.
|
@@ -139,6 +157,9 @@ type: content
|
|
139
157
|
content: >
|
140
158
|
<h1>Test content!</h1>
|
141
159
|
<p>Some test content</p>
|
160
|
+
widgets:
|
161
|
+
- LatestAuthorsWidget
|
162
|
+
- LatestPostsWidget
|
142
163
|
```
|
143
164
|
|
144
165
|
For _url_ sections:
|
@@ -175,10 +196,14 @@ For _resource_ sections:
|
|
175
196
|
|
176
197
|
- `model` (String): the class to use to fetch the data on an item of a collection;
|
177
198
|
- `repository` (String): the class to get the properties related to the model;
|
199
|
+
|
200
|
+
> 📚 [Wiki Repository page](https://github.com/blocknotes/tiny_admin/wiki/Repository) available
|
201
|
+
|
178
202
|
- `index` (Hash): collection's action options (see below);
|
179
203
|
- `show` (Hash): detail's action options (see below);
|
180
204
|
- `collection_actions` (Array of hashes): custom collection's actions;
|
181
205
|
- `member_actions` (Array of hashes): custom details's actions;
|
206
|
+
- `widgets` (Array): list of widgets (as View components) to present;
|
182
207
|
- `only` (Array of strings): list of supported actions (ex. `index`);
|
183
208
|
- `options` (Array of strings): resource options (ex. `hidden`).
|
184
209
|
|
@@ -256,6 +281,9 @@ Example:
|
|
256
281
|
header: The author
|
257
282
|
link_to: authors
|
258
283
|
call: author, name
|
284
|
+
widgets:
|
285
|
+
- LatestAuthorsWidget
|
286
|
+
- LatestPostsWidget
|
259
287
|
```
|
260
288
|
|
261
289
|
### Sample
|
@@ -280,6 +308,9 @@ authentication:
|
|
280
308
|
# password: 'f1891cea80fc05e433c943254c6bdabc159577a02a7395dfebbfbc4f7661d4af56f2d372131a45936de40160007368a56ef216a30cb202c66d3145fd24380906'
|
281
309
|
root:
|
282
310
|
title: Test Admin
|
311
|
+
widgets:
|
312
|
+
- LatestAuthorsWidget
|
313
|
+
- LatestPostsWidget
|
283
314
|
# page: RootPage
|
284
315
|
helper_class: AdminHelper
|
285
316
|
page_not_found: PageNotFound
|
@@ -3,34 +3,38 @@
|
|
3
3
|
module TinyAdmin
|
4
4
|
module Actions
|
5
5
|
class Index < BasicAction
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :context,
|
7
|
+
:current_page,
|
7
8
|
:fields_options,
|
8
|
-
:filters_list,
|
9
9
|
:links,
|
10
|
+
:options,
|
10
11
|
:pagination,
|
11
12
|
:pages,
|
12
13
|
:params,
|
13
14
|
:query_string,
|
14
|
-
:repository
|
15
|
-
:sort
|
15
|
+
:repository
|
16
16
|
|
17
17
|
def call(app:, context:, options:)
|
18
|
+
@context = context
|
19
|
+
@options = options || {}
|
18
20
|
evaluate_options(options)
|
19
21
|
fields = repository.fields(options: fields_options)
|
20
|
-
filters = prepare_filters(fields
|
21
|
-
records,
|
22
|
+
filters = prepare_filters(fields)
|
23
|
+
records, count = repository.list(page: current_page, limit: pagination, filters: filters, sort: options[:sort])
|
24
|
+
attributes = {
|
25
|
+
actions: context.actions,
|
26
|
+
fields: fields,
|
27
|
+
filters: filters,
|
28
|
+
links: options[:links],
|
29
|
+
prepare_record: ->(record) { repository.index_record_attrs(record, fields: fields_options) },
|
30
|
+
records: records,
|
31
|
+
slug: context.slug,
|
32
|
+
title: repository.index_title,
|
33
|
+
widgets: options[:widgets]
|
34
|
+
}
|
22
35
|
|
23
|
-
prepare_page(Views::Actions::Index) do |page|
|
24
|
-
setup_pagination(page, TinyAdmin.settings.components[:pagination], total_count:
|
25
|
-
page.update_attributes(
|
26
|
-
actions: context.actions,
|
27
|
-
fields: fields,
|
28
|
-
filters: filters,
|
29
|
-
links: links,
|
30
|
-
prepare_record: ->(record) { repository.index_record_attrs(record, fields: fields_options) },
|
31
|
-
records: records,
|
32
|
-
title: repository.index_title
|
33
|
-
)
|
36
|
+
prepare_page(Views::Actions::Index, slug: context.slug, attributes: attributes) do |page|
|
37
|
+
setup_pagination(page, TinyAdmin.settings.components[:pagination], total_count: count)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
@@ -40,17 +44,13 @@ module TinyAdmin
|
|
40
44
|
@fields_options = attribute_options(options[:attributes])
|
41
45
|
@params = context.request.params
|
42
46
|
@repository = context.repository
|
43
|
-
@filters_list = options[:filters]
|
44
47
|
@pagination = options[:pagination] || 10
|
45
|
-
@sort = options[:sort]
|
46
|
-
@links = options[:links]
|
47
|
-
|
48
48
|
@current_page = (params['p'] || 1).to_i
|
49
49
|
@query_string = params_to_s(params.except('p'))
|
50
50
|
end
|
51
51
|
|
52
|
-
def prepare_filters(fields
|
53
|
-
filters = (
|
52
|
+
def prepare_filters(fields)
|
53
|
+
filters = (options[:filters] || []).map { _1.is_a?(Hash) ? _1 : { field: _1 } }
|
54
54
|
filters = filters.each_with_object({}) { |filter, result| result[filter[:field]] = filter }
|
55
55
|
values = (params['q'] || {})
|
56
56
|
fields.each_with_object({}) do |(name, field), result|
|
@@ -8,16 +8,18 @@ module TinyAdmin
|
|
8
8
|
repository = context.repository
|
9
9
|
record = repository.find(context.reference)
|
10
10
|
prepare_record = ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) }
|
11
|
+
attributes = {
|
12
|
+
actions: context.actions,
|
13
|
+
fields: repository.fields(options: fields_options),
|
14
|
+
prepare_record: prepare_record,
|
15
|
+
record: record,
|
16
|
+
reference: context.reference,
|
17
|
+
slug: context.slug,
|
18
|
+
title: repository.show_title(record),
|
19
|
+
widgets: options[:widgets]
|
20
|
+
}
|
11
21
|
|
12
|
-
prepare_page(Views::Actions::Show
|
13
|
-
page.update_attributes(
|
14
|
-
actions: context.actions,
|
15
|
-
fields: repository.fields(options: fields_options),
|
16
|
-
prepare_record: prepare_record,
|
17
|
-
record: record,
|
18
|
-
title: repository.show_title(record)
|
19
|
-
)
|
20
|
-
end
|
22
|
+
prepare_page(Views::Actions::Show, slug: context.slug, attributes: attributes)
|
21
23
|
rescue Plugins::BaseRepository::RecordNotFound => _e
|
22
24
|
prepare_page(options[:record_not_found_page] || Views::Pages::RecordNotFound)
|
23
25
|
end
|
@@ -12,7 +12,11 @@ module TinyAdmin
|
|
12
12
|
end
|
13
13
|
|
14
14
|
r.post 'unauthenticated' do
|
15
|
-
|
15
|
+
warning = TinyAdmin.settings.helper_class.label_for(
|
16
|
+
'Failed to authenticate',
|
17
|
+
options: ['authentication.unauthenticated']
|
18
|
+
)
|
19
|
+
render_login(warnings: [warning])
|
16
20
|
end
|
17
21
|
|
18
22
|
r.get 'logout' do
|
@@ -24,7 +28,10 @@ module TinyAdmin
|
|
24
28
|
private
|
25
29
|
|
26
30
|
def render_login(notices: nil, warnings: nil, errors: nil)
|
27
|
-
|
31
|
+
login = TinyAdmin.settings.authentication[:login]
|
32
|
+
return unless login
|
33
|
+
|
34
|
+
page = prepare_page(login, options: %i[no_menu compact_layout])
|
28
35
|
page.messages = {
|
29
36
|
notices: notices || flash['notices'],
|
30
37
|
warnings: warnings || flash['warnings'],
|
data/lib/tiny_admin/context.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TinyAdmin
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
:resources,
|
14
|
-
:router,
|
15
|
-
:settings,
|
16
|
-
:slug
|
17
|
-
end
|
4
|
+
Context = Struct.new(
|
5
|
+
:actions,
|
6
|
+
:reference,
|
7
|
+
:repository,
|
8
|
+
:request,
|
9
|
+
:router,
|
10
|
+
:slug,
|
11
|
+
keyword_init: true
|
12
|
+
)
|
18
13
|
end
|
data/lib/tiny_admin/field.rb
CHANGED
@@ -16,6 +16,19 @@ module TinyAdmin
|
|
16
16
|
messages.inject(target) { |result, msg| result&.send(msg) } if messages.any?
|
17
17
|
end
|
18
18
|
|
19
|
+
def translate_value(value)
|
20
|
+
if options && options[:method]
|
21
|
+
method, *args = options[:method].split(',').map(&:strip)
|
22
|
+
if options[:converter]
|
23
|
+
Object.const_get(options[:converter]).send(method, value, options: args || [])
|
24
|
+
else
|
25
|
+
TinyAdmin.settings.helper_class.send(method, value, options: args || [])
|
26
|
+
end
|
27
|
+
else
|
28
|
+
value&.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
19
32
|
class << self
|
20
33
|
def create_field(name:, title: nil, type: nil, options: {})
|
21
34
|
field_name = name.to_s
|
@@ -6,10 +6,7 @@ module TinyAdmin
|
|
6
6
|
def index_record_attrs(record, fields: nil)
|
7
7
|
return record.attributes.transform_values(&:to_s) unless fields
|
8
8
|
|
9
|
-
fields.to_h
|
10
|
-
value = record.send(name)
|
11
|
-
[name, translate_value(value, field)]
|
12
|
-
end
|
9
|
+
fields.to_h { [_1, record.send(_1)] }
|
13
10
|
end
|
14
11
|
|
15
12
|
def index_title
|
@@ -10,20 +10,6 @@ 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
|
-
TinyAdmin.settings.helper_class.send(method, value, options: options || [])
|
22
|
-
end
|
23
|
-
else
|
24
|
-
value&.to_s
|
25
|
-
end
|
26
|
-
end
|
27
13
|
end
|
28
14
|
end
|
29
15
|
end
|
data/lib/tiny_admin/router.rb
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
module TinyAdmin
|
4
4
|
class Router < BasicApp
|
5
|
-
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegator TinyAdmin, :route_for
|
6
8
|
|
7
9
|
route do |r|
|
8
|
-
|
9
|
-
context.settings = TinyAdmin.settings
|
10
|
+
TinyAdmin.settings.load_settings
|
10
11
|
|
11
12
|
r.on 'auth' do
|
12
|
-
context.slug = nil
|
13
13
|
r.run Authentication
|
14
14
|
end
|
15
15
|
|
@@ -26,15 +26,14 @@ module TinyAdmin
|
|
26
26
|
end
|
27
27
|
|
28
28
|
r.post '' do
|
29
|
-
context.slug = nil
|
30
29
|
r.redirect TinyAdmin.settings.root_path
|
31
30
|
end
|
32
31
|
|
33
|
-
|
32
|
+
store.pages.each do |slug, page_data|
|
34
33
|
setup_page_route(r, slug, page_data)
|
35
34
|
end
|
36
35
|
|
37
|
-
|
36
|
+
store.resources.each do |slug, options|
|
38
37
|
setup_resource_routes(r, slug, options: options || {})
|
39
38
|
end
|
40
39
|
|
@@ -43,6 +42,10 @@ module TinyAdmin
|
|
43
42
|
|
44
43
|
private
|
45
44
|
|
45
|
+
def store
|
46
|
+
@store ||= TinyAdmin.settings.store
|
47
|
+
end
|
48
|
+
|
46
49
|
def render_page(page)
|
47
50
|
if page.respond_to?(:messages=)
|
48
51
|
page.messages = { notices: flash['notices'], warnings: flash['warnings'], errors: flash['errors'] }
|
@@ -51,76 +54,83 @@ module TinyAdmin
|
|
51
54
|
end
|
52
55
|
|
53
56
|
def root_route(router)
|
54
|
-
context.slug = nil
|
55
57
|
if TinyAdmin.settings.root[:redirect]
|
56
58
|
router.redirect route_for(TinyAdmin.settings.root[:redirect])
|
57
59
|
else
|
58
|
-
|
59
|
-
|
60
|
-
render_page prepare_page(page_class)
|
60
|
+
page_class = to_class(TinyAdmin.settings.root[:page])
|
61
|
+
render_page prepare_page(page_class, attributes: TinyAdmin.settings.root.slice(:content, :title, :widgets))
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
65
|
def setup_page_route(router, slug, page_data)
|
65
66
|
router.get slug do
|
66
|
-
|
67
|
-
|
68
|
-
page.update_attributes(content: page_data[:content]) if page_data[:content]
|
69
|
-
render_page page
|
67
|
+
attributes = page_data.slice(:content, :title, :widgets)
|
68
|
+
render_page prepare_page(page_data[:class], slug: slug, attributes: attributes)
|
70
69
|
end
|
71
70
|
end
|
72
71
|
|
73
72
|
def setup_resource_routes(router, slug, options:)
|
74
73
|
router.on slug do
|
75
|
-
|
76
|
-
|
77
|
-
setup_member_routes(router, options: options)
|
74
|
+
setup_collection_routes(router, slug, options: options)
|
75
|
+
setup_member_routes(router, slug, options: options)
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
81
|
-
def setup_collection_routes(router, options:)
|
82
|
-
|
79
|
+
def setup_collection_routes(router, slug, options:)
|
80
|
+
repository = options[:repository].new(options[:model])
|
83
81
|
action_options = options[:index] || {}
|
84
82
|
|
85
83
|
# Custom actions
|
86
84
|
custom_actions = setup_custom_actions(
|
87
85
|
router,
|
88
86
|
options[:collection_actions],
|
89
|
-
|
90
|
-
|
87
|
+
options: action_options,
|
88
|
+
repository: repository,
|
89
|
+
slug: slug
|
91
90
|
)
|
92
91
|
|
93
92
|
# Index
|
94
93
|
if options[:only].include?(:index) || options[:only].include?('index')
|
95
94
|
router.is do
|
96
|
-
context
|
97
|
-
|
95
|
+
context = Context.new(
|
96
|
+
actions: custom_actions,
|
97
|
+
repository: repository,
|
98
|
+
request: request,
|
99
|
+
router: router,
|
100
|
+
slug: slug
|
101
|
+
)
|
98
102
|
index_action = TinyAdmin::Actions::Index.new
|
99
103
|
render_page index_action.call(app: self, context: context, options: action_options)
|
100
104
|
end
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
104
|
-
def setup_member_routes(router, options:)
|
105
|
-
|
108
|
+
def setup_member_routes(router, slug, options:)
|
109
|
+
repository = options[:repository].new(options[:model])
|
106
110
|
action_options = (options[:show] || {}).merge(record_not_found_page: TinyAdmin.settings.record_not_found)
|
107
111
|
|
108
112
|
router.on String do |reference|
|
109
|
-
context.reference = reference
|
110
|
-
|
111
113
|
# Custom actions
|
112
114
|
custom_actions = setup_custom_actions(
|
113
115
|
router,
|
114
116
|
options[:member_actions],
|
115
|
-
|
116
|
-
|
117
|
+
options: action_options,
|
118
|
+
repository: repository,
|
119
|
+
slug: slug,
|
120
|
+
reference: reference
|
117
121
|
)
|
118
122
|
|
119
123
|
# Show
|
120
124
|
if options[:only].include?(:show) || options[:only].include?('show')
|
121
125
|
router.is do
|
122
|
-
context
|
123
|
-
|
126
|
+
context = Context.new(
|
127
|
+
actions: custom_actions,
|
128
|
+
reference: reference,
|
129
|
+
repository: repository,
|
130
|
+
request: request,
|
131
|
+
router: router,
|
132
|
+
slug: slug
|
133
|
+
)
|
124
134
|
show_action = TinyAdmin::Actions::Show.new
|
125
135
|
render_page show_action.call(app: self, context: context, options: action_options)
|
126
136
|
end
|
@@ -128,15 +138,20 @@ module TinyAdmin
|
|
128
138
|
end
|
129
139
|
end
|
130
140
|
|
131
|
-
def setup_custom_actions(router, custom_actions, repository:,
|
132
|
-
context.repository = repository
|
141
|
+
def setup_custom_actions(router, custom_actions, options:, repository:, slug:, reference: nil)
|
133
142
|
(custom_actions || []).each_with_object({}) do |custom_action, result|
|
134
143
|
action_slug, action = custom_action.first
|
135
|
-
action_class =
|
144
|
+
action_class = to_class(action)
|
136
145
|
|
137
146
|
router.get action_slug.to_s do
|
138
|
-
context
|
139
|
-
|
147
|
+
context = Context.new(
|
148
|
+
actions: {},
|
149
|
+
reference: reference,
|
150
|
+
repository: repository,
|
151
|
+
request: request,
|
152
|
+
router: router,
|
153
|
+
slug: slug
|
154
|
+
)
|
140
155
|
custom_action = action_class.new
|
141
156
|
render_page custom_action.call(app: self, context: context, options: options)
|
142
157
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinyAdmin
|
4
|
+
class Section
|
5
|
+
attr_reader :name, :options, :path, :slug
|
6
|
+
|
7
|
+
def initialize(name:, slug: nil, path: nil, options: {})
|
8
|
+
@name = name
|
9
|
+
@options = options
|
10
|
+
@path = path || TinyAdmin.route_for(slug)
|
11
|
+
@slug = slug
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/tiny_admin/settings.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
module TinyAdmin
|
4
4
|
class Settings
|
5
5
|
include Singleton
|
6
|
-
include Utils
|
7
6
|
|
8
7
|
DEFAULTS = {
|
9
8
|
%i[authentication plugin] => Plugins::NoAuth,
|
10
9
|
%i[authentication login] => Views::Pages::SimpleAuthLogin,
|
10
|
+
%i[components field_value] => Views::Components::FieldValue,
|
11
11
|
%i[components flash] => Views::Components::Flash,
|
12
12
|
%i[components head] => Views::Components::Head,
|
13
13
|
%i[components navbar] => Views::Components::Navbar,
|
@@ -19,7 +19,8 @@ module TinyAdmin
|
|
19
19
|
%i[repository] => Plugins::ActiveRecordRepository,
|
20
20
|
%i[root_path] => '/admin',
|
21
21
|
%i[root page] => Views::Pages::Root,
|
22
|
-
%i[root title] => 'TinyAdmin'
|
22
|
+
%i[root title] => 'TinyAdmin',
|
23
|
+
%i[sections] => []
|
23
24
|
}.freeze
|
24
25
|
|
25
26
|
OPTIONS = %i[
|
@@ -38,6 +39,8 @@ module TinyAdmin
|
|
38
39
|
style_links
|
39
40
|
].freeze
|
40
41
|
|
42
|
+
attr_reader :store
|
43
|
+
|
41
44
|
OPTIONS.each do |option|
|
42
45
|
define_method(option) do
|
43
46
|
self[option]
|
@@ -70,15 +73,14 @@ module TinyAdmin
|
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
73
|
-
|
74
|
-
context.resources ||= {}
|
75
|
-
self.sections ||= []
|
76
|
+
@store ||= TinyAdmin::Store.new(self)
|
76
77
|
self.root_path = '/' if root_path == ''
|
77
78
|
|
78
79
|
if authentication[:plugin] <= Plugins::SimpleAuth
|
79
|
-
|
80
|
+
logout_path = "#{root_path}/auth/logout"
|
81
|
+
authentication[:logout] ||= TinyAdmin::Section.new(name: 'logout', slug: 'logout', path: logout_path)
|
80
82
|
end
|
81
|
-
|
83
|
+
store.prepare_sections(sections, logout: authentication[:logout])
|
82
84
|
end
|
83
85
|
|
84
86
|
def reset!
|
@@ -97,7 +99,7 @@ module TinyAdmin
|
|
97
99
|
if value.is_a?(Hash)
|
98
100
|
value.each_key do |key2|
|
99
101
|
path = [key, key2]
|
100
|
-
if DEFAULTS[path].is_a?(Class) || DEFAULTS[path].is_a?(Module)
|
102
|
+
if (DEFAULTS[path].is_a?(Class) || DEFAULTS[path].is_a?(Module)) && self[key][key2].is_a?(String)
|
101
103
|
self[key][key2] = Object.const_get(self[key][key2])
|
102
104
|
end
|
103
105
|
end
|
@@ -105,59 +107,5 @@ module TinyAdmin
|
|
105
107
|
self[key] = Object.const_get(self[key])
|
106
108
|
end
|
107
109
|
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
|
162
110
|
end
|
163
111
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinyAdmin
|
4
|
+
class Store
|
5
|
+
include Utils
|
6
|
+
|
7
|
+
attr_reader :navbar, :pages, :resources, :settings
|
8
|
+
|
9
|
+
def initialize(settings)
|
10
|
+
@pages = {}
|
11
|
+
@resources = {}
|
12
|
+
@settings = settings
|
13
|
+
end
|
14
|
+
|
15
|
+
def prepare_sections(sections, logout:)
|
16
|
+
@navbar = sections.each_with_object([]) do |section, list|
|
17
|
+
unless section.is_a?(Hash)
|
18
|
+
section_class = to_class(section)
|
19
|
+
next unless section_class.respond_to?(:to_h)
|
20
|
+
|
21
|
+
section = section_class.to_h
|
22
|
+
end
|
23
|
+
|
24
|
+
slug = section[:slug].to_s
|
25
|
+
case section[:type]&.to_sym
|
26
|
+
when :content
|
27
|
+
list << add_content_section(slug, section)
|
28
|
+
when :page
|
29
|
+
list << add_page_section(slug, section)
|
30
|
+
when :resource
|
31
|
+
list << add_resource_section(slug, section)
|
32
|
+
when :url
|
33
|
+
list << add_url_section(slug, section)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
navbar << logout if logout
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def add_content_section(slug, section)
|
42
|
+
pages[slug] = { class: settings.content_page, content: section[:content], widgets: section[:widgets] }
|
43
|
+
TinyAdmin::Section.new(name: section[:name], slug: slug)
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_page_section(slug, section)
|
47
|
+
pages[slug] = { class: to_class(section[:page]) }
|
48
|
+
TinyAdmin::Section.new(name: section[:name], slug: slug)
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_resource_section(slug, section)
|
52
|
+
resource = section.slice(:resource, :only, :index, :show, :collection_actions, :member_actions)
|
53
|
+
resource[:only] ||= %i[index show]
|
54
|
+
resources[slug] = resource.merge(
|
55
|
+
model: to_class(section[:model]),
|
56
|
+
repository: to_class(section[:repository] || settings.repository)
|
57
|
+
)
|
58
|
+
|
59
|
+
hidden = section[:options] && (section[:options].include?(:hidden) || section[:options].include?('hidden'))
|
60
|
+
TinyAdmin::Section.new(name: section[:name], slug: slug) unless hidden
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_url_section(slug, section)
|
64
|
+
TinyAdmin::Section.new(name: section[:name], options: section[:options], path: section[:url], slug: slug)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/tiny_admin/support.rb
CHANGED
data/lib/tiny_admin/utils.rb
CHANGED
@@ -14,37 +14,33 @@ module TinyAdmin
|
|
14
14
|
list.join('&')
|
15
15
|
end
|
16
16
|
|
17
|
-
def prepare_page(page_class, options: nil)
|
17
|
+
def prepare_page(page_class, slug: nil, attributes: nil, options: nil)
|
18
18
|
page_class.new.tap do |page|
|
19
19
|
page.options = options
|
20
20
|
page.head_component = TinyAdmin.settings.components[:head]&.new
|
21
21
|
page.flash_component = TinyAdmin.settings.components[:flash]&.new
|
22
22
|
page.navbar_component = TinyAdmin.settings.components[:navbar]&.new
|
23
23
|
page.navbar_component&.update_attributes(
|
24
|
-
current_slug:
|
24
|
+
current_slug: slug,
|
25
25
|
root_path: TinyAdmin.settings.root_path,
|
26
26
|
root_title: TinyAdmin.settings.root[:title],
|
27
|
-
items: options&.include?(:no_menu) ? [] :
|
27
|
+
items: options&.include?(:no_menu) ? [] : TinyAdmin.settings.store&.navbar
|
28
28
|
)
|
29
|
+
attrs = attributes || {}
|
30
|
+
attrs[:widgets] = attrs[:widgets].map { to_class(_1) } if attrs[:widgets]
|
31
|
+
page.update_attributes(attrs) unless attrs.empty?
|
29
32
|
yield(page) if block_given?
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
|
-
def
|
34
|
-
|
35
|
-
route = [root_path, section, reference, action].compact.join("/")
|
36
|
-
route << "?#{query}" if query
|
37
|
-
route[0] == '/' ? route : route.prepend('/')
|
36
|
+
def to_class(klass)
|
37
|
+
klass.is_a?(String) ? Object.const_get(klass) : klass
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
40
|
+
def humanize(string)
|
41
41
|
return '' unless string
|
42
42
|
|
43
43
|
string.respond_to?(:humanize) ? string.humanize : string.tr('_', ' ').capitalize
|
44
44
|
end
|
45
|
-
|
46
|
-
def context
|
47
|
-
TinyAdmin::Context.instance
|
48
|
-
end
|
49
45
|
end
|
50
46
|
end
|
data/lib/tiny_admin/version.rb
CHANGED
@@ -4,14 +4,16 @@ module TinyAdmin
|
|
4
4
|
module Views
|
5
5
|
module Actions
|
6
6
|
class Index < DefaultLayout
|
7
|
-
attr_accessor :actions, :fields, :filters, :links, :pagination_component, :prepare_record, :records
|
7
|
+
attr_accessor :actions, :fields, :filters, :links, :pagination_component, :prepare_record, :records, :slug
|
8
8
|
|
9
9
|
def template
|
10
10
|
super do
|
11
11
|
div(class: 'index') {
|
12
12
|
div(class: 'row') {
|
13
13
|
div(class: 'col-4') {
|
14
|
-
h1(class: 'title') {
|
14
|
+
h1(class: 'title') {
|
15
|
+
title
|
16
|
+
}
|
15
17
|
}
|
16
18
|
div(class: 'col-8') {
|
17
19
|
actions_buttons
|
@@ -31,13 +33,15 @@ module TinyAdmin
|
|
31
33
|
if filters&.any?
|
32
34
|
div(class: 'col-3') {
|
33
35
|
filters_form = TinyAdmin::Views::Components::FiltersForm.new
|
34
|
-
filters_form.update_attributes(section_path: route_for(
|
36
|
+
filters_form.update_attributes(section_path: TinyAdmin.route_for(slug), filters: filters)
|
35
37
|
render filters_form
|
36
38
|
}
|
37
39
|
end
|
38
40
|
}
|
39
41
|
|
40
42
|
render pagination_component if pagination_component
|
43
|
+
|
44
|
+
render TinyAdmin::Views::Components::Widgets.new(widgets)
|
41
45
|
}
|
42
46
|
end
|
43
47
|
end
|
@@ -65,13 +69,7 @@ module TinyAdmin
|
|
65
69
|
attributes.each do |key, value|
|
66
70
|
field = fields[key]
|
67
71
|
td(class: "field-value-#{field.name} field-value-type-#{field.type}") {
|
68
|
-
|
69
|
-
a(href: route_for(field.options[:link_to], reference: value)) {
|
70
|
-
field.apply_call_option(record) || value
|
71
|
-
}
|
72
|
-
else
|
73
|
-
value
|
74
|
-
end
|
72
|
+
render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
|
75
73
|
}
|
76
74
|
end
|
77
75
|
|
@@ -82,15 +80,20 @@ module TinyAdmin
|
|
82
80
|
links.each do |link|
|
83
81
|
whitespace
|
84
82
|
if link == 'show'
|
85
|
-
a(href: route_for(
|
83
|
+
a(href: TinyAdmin.route_for(slug, reference: record.id), class: link_class) {
|
84
|
+
label_for('Show', options: ['actions.index.links.show'])
|
85
|
+
}
|
86
86
|
else
|
87
|
-
a(href: route_for(
|
88
|
-
|
87
|
+
a(href: TinyAdmin.route_for(slug, reference: record.id, action: link), class: link_class) {
|
88
|
+
fallback = humanize(link)
|
89
|
+
label_for(fallback, options: ["actions.index.links.#{link}"])
|
89
90
|
}
|
90
91
|
end
|
91
92
|
end
|
92
93
|
else
|
93
|
-
a(href: route_for(
|
94
|
+
a(href: TinyAdmin.route_for(slug, reference: record.id), class: link_class) {
|
95
|
+
label_for('Show', options: ['actions.index.links.show'])
|
96
|
+
}
|
94
97
|
end
|
95
98
|
}
|
96
99
|
}
|
@@ -103,7 +106,7 @@ module TinyAdmin
|
|
103
106
|
ul(class: 'nav justify-content-end') {
|
104
107
|
(actions || {}).each do |action, action_class|
|
105
108
|
li(class: 'nav-item mx-1') {
|
106
|
-
href = route_for(
|
109
|
+
href = TinyAdmin.route_for(slug, action: action)
|
107
110
|
a(href: href, class: 'nav-link btn btn-outline-secondary') {
|
108
111
|
action_class.respond_to?(:title) ? action_class.title : action
|
109
112
|
}
|
@@ -4,7 +4,7 @@ module TinyAdmin
|
|
4
4
|
module Views
|
5
5
|
module Actions
|
6
6
|
class Show < DefaultLayout
|
7
|
-
attr_accessor :actions, :fields, :prepare_record, :record
|
7
|
+
attr_accessor :actions, :fields, :prepare_record, :record, :reference, :slug
|
8
8
|
|
9
9
|
def template
|
10
10
|
super do
|
@@ -25,16 +25,12 @@ 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
|
-
|
29
|
-
a(href: route_for(field.options[:link_to], reference: value)) {
|
30
|
-
field.apply_call_option(record) || value
|
31
|
-
}
|
32
|
-
else
|
33
|
-
value
|
34
|
-
end
|
28
|
+
render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
|
35
29
|
}
|
36
30
|
}
|
37
31
|
end
|
32
|
+
|
33
|
+
render TinyAdmin::Views::Components::Widgets.new(widgets)
|
38
34
|
}
|
39
35
|
end
|
40
36
|
end
|
@@ -45,7 +41,7 @@ module TinyAdmin
|
|
45
41
|
ul(class: 'nav justify-content-end') {
|
46
42
|
(actions || {}).each do |action, action_class|
|
47
43
|
li(class: 'nav-item mx-1') {
|
48
|
-
href = route_for(
|
44
|
+
href = TinyAdmin.route_for(slug, reference: reference, action: action)
|
49
45
|
a(href: href, class: 'nav-link btn btn-outline-secondary') {
|
50
46
|
action_class.respond_to?(:title) ? action_class.title : action
|
51
47
|
}
|
@@ -5,7 +5,11 @@ module TinyAdmin
|
|
5
5
|
class BasicLayout < Phlex::HTML
|
6
6
|
include Utils
|
7
7
|
|
8
|
-
attr_accessor :content
|
8
|
+
attr_accessor :content, :widgets
|
9
|
+
|
10
|
+
def label_for(value, options: [])
|
11
|
+
TinyAdmin.settings.helper_class.label_for(value, options: options)
|
12
|
+
end
|
9
13
|
|
10
14
|
def update_attributes(attributes)
|
11
15
|
attributes.each do |key, value|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinyAdmin
|
4
|
+
module Views
|
5
|
+
module Components
|
6
|
+
class FieldValue < BasicComponent
|
7
|
+
attr_reader :field, :value, :record
|
8
|
+
|
9
|
+
def initialize(field, value, record:)
|
10
|
+
@field = field
|
11
|
+
@value = value
|
12
|
+
@record = record
|
13
|
+
end
|
14
|
+
|
15
|
+
def template
|
16
|
+
translated_value = field.translate_value(value)
|
17
|
+
value_class = field.options[:options]&.include?('value_class') ? "value-#{value}" : nil
|
18
|
+
if field.options[:link_to]
|
19
|
+
a(href: TinyAdmin.route_for(field.options[:link_to], reference: translated_value)) {
|
20
|
+
span(class: value_class) {
|
21
|
+
field.apply_call_option(record) || translated_value
|
22
|
+
}
|
23
|
+
}
|
24
|
+
else
|
25
|
+
span(class: value_class) {
|
26
|
+
translated_value
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -17,8 +17,12 @@ module TinyAdmin
|
|
17
17
|
when :boolean
|
18
18
|
select(class: 'form-select', id: "filter-#{name}", name: "q[#{name}]") {
|
19
19
|
option(value: '') { '-' }
|
20
|
-
option(value: '0', selected: filter[:value] == '0') {
|
21
|
-
|
20
|
+
option(value: '0', selected: filter[:value] == '0') {
|
21
|
+
TinyAdmin.settings.helper_class.label_for('false', options: ['components.filters_form.boolean.false'])
|
22
|
+
}
|
23
|
+
option(value: '1', selected: filter[:value] == '1') {
|
24
|
+
TinyAdmin.settings.helper_class.label_for('true', options: ['components.filters_form.boolean.true'])
|
25
|
+
}
|
22
26
|
}
|
23
27
|
when :date
|
24
28
|
input(type: 'date', class: 'form-control', id: "filter-#{name}", name: "q[#{name}]", value: filter[:value])
|
@@ -40,9 +44,13 @@ module TinyAdmin
|
|
40
44
|
end
|
41
45
|
|
42
46
|
div(class: 'mt-3') {
|
43
|
-
a(href: section_path, class: 'button_clear btn btn-secondary text-white') {
|
47
|
+
a(href: section_path, class: 'button_clear btn btn-secondary text-white') {
|
48
|
+
TinyAdmin.settings.helper_class.label_for('Clear', options: ['components.filters_form.buttons.clear'])
|
49
|
+
}
|
44
50
|
whitespace
|
45
|
-
button(type: 'submit', class: 'button_filter btn btn-secondary') {
|
51
|
+
button(type: 'submit', class: 'button_filter btn btn-secondary') {
|
52
|
+
TinyAdmin.settings.helper_class.label_for('Filter', options: ['components.filters_form.buttons.submit'])
|
53
|
+
}
|
46
54
|
}
|
47
55
|
}
|
48
56
|
end
|
@@ -23,14 +23,14 @@ module TinyAdmin
|
|
23
23
|
}
|
24
24
|
div(class: 'collapse navbar-collapse', id: 'navbarNav') {
|
25
25
|
ul(class: 'navbar-nav') {
|
26
|
-
items.each do |
|
26
|
+
items.each do |item|
|
27
27
|
classes = %w[nav-link]
|
28
|
-
classes << 'active' if slug == current_slug
|
29
|
-
link_attributes = { class: classes.join(' '), href: item
|
30
|
-
link_attributes.merge!(item
|
28
|
+
classes << 'active' if item.slug == current_slug
|
29
|
+
link_attributes = { class: classes.join(' '), href: item.path, 'aria-current' => 'page' }
|
30
|
+
link_attributes.merge!(item.options) if item.options
|
31
31
|
|
32
32
|
li(class: 'nav-item') {
|
33
|
-
a(**link_attributes) { item
|
33
|
+
a(**link_attributes) { item.name }
|
34
34
|
}
|
35
35
|
end
|
36
36
|
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinyAdmin
|
4
|
+
module Views
|
5
|
+
module Components
|
6
|
+
class Widgets < BasicComponent
|
7
|
+
def initialize(widgets)
|
8
|
+
@widgets = widgets
|
9
|
+
end
|
10
|
+
|
11
|
+
def template
|
12
|
+
return if @widgets.nil? || @widgets.empty?
|
13
|
+
|
14
|
+
div(class: 'container widgets') {
|
15
|
+
@widgets.each_slice(2).each do |row|
|
16
|
+
div(class: 'row') {
|
17
|
+
row.each do |widget|
|
18
|
+
next unless widget < Phlex::HTML
|
19
|
+
|
20
|
+
div(class: 'col') {
|
21
|
+
div(class: 'card') {
|
22
|
+
div(class: 'card-body') {
|
23
|
+
render widget.new
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -11,12 +11,16 @@ module TinyAdmin
|
|
11
11
|
|
12
12
|
form(class: 'form_login', method: 'post') {
|
13
13
|
div(class: 'mt-3') {
|
14
|
-
label(for: 'secret', class: 'form-label') {
|
14
|
+
label(for: 'secret', class: 'form-label') {
|
15
|
+
label_for('Password', options: ['pages.simple_auth_login.inputs.password'])
|
16
|
+
}
|
15
17
|
input(type: 'password', name: 'secret', class: 'form-control', id: 'secret')
|
16
18
|
}
|
17
19
|
|
18
20
|
div(class: 'mt-3') {
|
19
|
-
button(type: 'submit', class: 'button_login btn btn-primary') {
|
21
|
+
button(type: 'submit', class: 'button_login btn btn-primary') {
|
22
|
+
label_for('Login', options: ['pages.simple_auth_login.buttons.submit'])
|
23
|
+
}
|
20
24
|
}
|
21
25
|
}
|
22
26
|
}
|
data/lib/tiny_admin.rb
CHANGED
@@ -4,6 +4,7 @@ require 'phlex'
|
|
4
4
|
require 'roda'
|
5
5
|
require 'zeitwerk'
|
6
6
|
|
7
|
+
require 'forwardable'
|
7
8
|
require 'singleton'
|
8
9
|
require 'yaml'
|
9
10
|
|
@@ -23,9 +24,16 @@ module TinyAdmin
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
def route_for(section, reference: nil, action: nil, query: nil)
|
28
|
+
root_path = settings.root_path == '/' ? nil : settings.root_path
|
29
|
+
route = [root_path, section, reference, action].compact.join("/")
|
30
|
+
route << "?#{query}" if query
|
31
|
+
route[0] == '/' ? route : route.prepend('/')
|
32
|
+
end
|
33
|
+
|
26
34
|
def settings
|
27
35
|
TinyAdmin::Settings.instance
|
28
36
|
end
|
29
37
|
|
30
|
-
module_function :configure, :configure_from_file, :settings
|
38
|
+
module_function :configure, :configure_from_file, :route_for, :settings
|
31
39
|
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.8.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-
|
11
|
+
date: 2023-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: phlex
|
@@ -87,19 +87,24 @@ files:
|
|
87
87
|
- lib/tiny_admin/plugins/no_auth.rb
|
88
88
|
- lib/tiny_admin/plugins/simple_auth.rb
|
89
89
|
- lib/tiny_admin/router.rb
|
90
|
+
- lib/tiny_admin/section.rb
|
90
91
|
- lib/tiny_admin/settings.rb
|
92
|
+
- lib/tiny_admin/store.rb
|
91
93
|
- lib/tiny_admin/support.rb
|
92
94
|
- lib/tiny_admin/utils.rb
|
93
95
|
- lib/tiny_admin/version.rb
|
94
96
|
- lib/tiny_admin/views/actions/index.rb
|
95
97
|
- lib/tiny_admin/views/actions/show.rb
|
96
98
|
- lib/tiny_admin/views/basic_layout.rb
|
99
|
+
- lib/tiny_admin/views/basic_widget.rb
|
97
100
|
- lib/tiny_admin/views/components/basic_component.rb
|
101
|
+
- lib/tiny_admin/views/components/field_value.rb
|
98
102
|
- lib/tiny_admin/views/components/filters_form.rb
|
99
103
|
- lib/tiny_admin/views/components/flash.rb
|
100
104
|
- lib/tiny_admin/views/components/head.rb
|
101
105
|
- lib/tiny_admin/views/components/navbar.rb
|
102
106
|
- lib/tiny_admin/views/components/pagination.rb
|
107
|
+
- lib/tiny_admin/views/components/widgets.rb
|
103
108
|
- lib/tiny_admin/views/default_layout.rb
|
104
109
|
- lib/tiny_admin/views/pages/content.rb
|
105
110
|
- lib/tiny_admin/views/pages/page_not_found.rb
|