tiny_admin 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3ac2be067ca35c35f40c677c5f9461c5f83e366488a48e6ab50a888f0f22317
4
- data.tar.gz: 2289dd33940174e8e614260f96273967ade51f75dc67a04d5e639415c984e65b
3
+ metadata.gz: 0dfe9b2fef29073201e228daf3a7d89003902f8d98108e58cb8245fdb9a533e3
4
+ data.tar.gz: 6634891a9bbc2585549a759cd061a25234b834ebdcc0b77fbbb9bd2297b0a626
5
5
  SHA512:
6
- metadata.gz: f4f80d86ac6b30bc29cf8e2f1efe480edefe84907bf5e9b7a3a8c3b3c3750ff59a1f9e609c87090105c0cd31fa22df7aa913858911a455d918633269c27317e7
7
- data.tar.gz: 4fe8a75d9e3c0cc3bd756ab247fecb7575049dcec58559bdb7cdb1c58ecb4b6e7de3f8be96c396b0b304134cc75c6058b3cbeafce92cd027413971a99a812c02
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,7 +16,7 @@ Please ⭐ if you like it.
16
16
 
17
17
  ## Install
18
18
 
19
- - Add to your Gemfile: `gem 'tiny_admin', '~> 0.5'`
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
22
  - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` with a YAML config file (see [configuration](#configuration) below):
@@ -51,6 +51,7 @@ Plugin available:
51
51
  Pages available:
52
52
 
53
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;
54
55
  - **PageNotFound**: define how to present pages not found;
55
56
  - **RecordNotFound**: define how to present record not found page;
56
57
  - **SimpleAuthLogin**: define how to present the login form for SimpleAuth plugin;
@@ -122,9 +123,24 @@ authentication:
122
123
 
123
124
  - `slug` (String): section reference identifier;
124
125
  - `name` (String): section's title;
125
- - `type` (String): the type of section: `url`, `page` or `resource`;
126
+ - `type` (String): the type of section: `content`, `page`, `resource` or `url`;
126
127
  - other properties depends on the section's type.
127
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
+ ```
143
+
128
144
  For _url_ sections:
129
145
 
130
146
  - `url` (String): the URL to load when clicking on the section's menu item;
@@ -21,7 +21,7 @@ module TinyAdmin
21
21
  records, total_count = repository.list(page: current_page, limit: pagination, filters: filters, sort: sort)
22
22
 
23
23
  prepare_page(Views::Actions::Index) do |page|
24
- setup_pagination(page, settings.components[:pagination], total_count: total_count)
24
+ setup_pagination(page, TinyAdmin.settings.components[:pagination], total_count: total_count)
25
25
  page.update_attributes(
26
26
  actions: context.actions,
27
27
  fields: fields,
@@ -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
@@ -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 collection
46
+ model.all
47
+ end
48
+
45
49
  def list(page: 1, limit: 10, sort: nil, filters: nil)
46
- query = sort ? model.all.order(sort) : model.all
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,11 +27,11 @@ 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.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
37
  context.resources.each do |slug, options|
@@ -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
 
@@ -100,7 +103,7 @@ module TinyAdmin
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
@@ -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,25 +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
- :page_not_found,
29
- :record_not_found,
30
- :repository,
31
- :root,
32
- :root_path,
33
- :sections,
34
- :scripts,
35
- :style_links
36
-
37
- def [](key)
38
- 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]
39
54
  end
40
55
 
41
- def []=(key, value)
42
- send("#{key}=", value)
56
+ def []=(*path, value)
57
+ key, option = fetch_setting(path)
58
+ option[key] = value
43
59
  convert_value(key, value)
44
60
  end
45
61
 
@@ -56,17 +72,27 @@ module TinyAdmin
56
72
 
57
73
  context.pages ||= {}
58
74
  context.resources ||= {}
59
- @sections ||= []
60
- @root_path = '/' if @root_path == ''
75
+ self.sections ||= []
76
+ self.root_path = '/' if root_path == ''
61
77
 
62
- if @authentication[:plugin] <= Plugins::SimpleAuth
63
- @authentication[:logout] ||= { name: 'logout', path: "#{root_path}/auth/logout" }
78
+ if authentication[:plugin] <= Plugins::SimpleAuth
79
+ authentication[:logout] ||= { name: 'logout', path: "#{root_path}/auth/logout" }
64
80
  end
65
81
  context.navbar = prepare_navbar(sections, logout: authentication[:logout])
66
82
  end
67
83
 
84
+ def reset!
85
+ @options = {}
86
+ end
87
+
68
88
  private
69
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
+
70
96
  def convert_value(key, value)
71
97
  if value.is_a?(Hash)
72
98
  value.each_key do |key2|
@@ -83,7 +109,7 @@ module TinyAdmin
83
109
  def prepare_navbar(sections, logout:)
84
110
  items = sections.each_with_object({}) do |section, list|
85
111
  unless section.is_a?(Hash)
86
- section_class = Object.const_get(section)
112
+ section_class = section.is_a?(String) ? Object.const_get(section) : section
87
113
  next unless section_class.respond_to?(:to_h)
88
114
 
89
115
  section = section_class.to_h
@@ -91,33 +117,37 @@ module TinyAdmin
91
117
 
92
118
  slug = section[:slug].to_s
93
119
  case section[:type]&.to_sym
94
- when :url
95
- list[slug] = add_url_section(slug, section)
120
+ when :content
121
+ list[slug] = add_content_section(slug, section)
96
122
  when :page
97
123
  list[slug] = add_page_section(slug, section)
98
124
  when :resource
99
125
  list[slug] = add_resource_section(slug, section)
126
+ when :url
127
+ list[slug] = add_url_section(slug, section)
100
128
  end
101
129
  end
102
130
  items['auth/logout'] = logout if logout
103
131
  items
104
132
  end
105
133
 
106
- def add_url_section(_slug, section)
107
- section.slice(:name, :options).tap { _1[:path] = section[:url] }
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 }
108
137
  end
109
138
 
110
139
  def add_page_section(slug, section)
111
140
  page = section[:page]
112
- context.pages[slug] = page.is_a?(String) ? Object.const_get(page) : page
113
- { name: section[:name], path: route_for(slug), class: context.pages[slug] }
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 }
114
144
  end
115
145
 
116
146
  def add_resource_section(slug, section)
117
- repository = section[:repository] || settings.repository
147
+ repo = section[:repository] || repository
118
148
  context.resources[slug] = {
119
149
  model: section[:model].is_a?(String) ? Object.const_get(section[:model]) : section[:model],
120
- repository: repository.is_a?(String) ? Object.const_get(repository) : repository
150
+ repository: repo.is_a?(String) ? Object.const_get(repo) : repo
121
151
  }
122
152
  resource_options = section.slice(:resource, :only, :index, :show, :collection_actions, :member_actions)
123
153
  resource_options[:only] ||= %i[index show]
@@ -125,5 +155,9 @@ module TinyAdmin
125
155
  hidden = section[:options] && (section[:options].include?(:hidden) || section[:options].include?('hidden'))
126
156
  { name: section[:name], path: route_for(slug) } unless hidden
127
157
  end
158
+
159
+ def add_url_section(_slug, section)
160
+ section.slice(:name, :options).tap { _1[:path] = section[:url] }
161
+ end
128
162
  end
129
163
  end
@@ -17,13 +17,13 @@ module TinyAdmin
17
17
  def prepare_page(page_class, options: nil)
18
18
  page_class.new.tap do |page|
19
19
  page.options = options
20
- page.head_component = settings.components[:head]&.new
21
- page.flash_component = settings.components[:flash]&.new
22
- 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
23
  page.navbar_component&.update_attributes(
24
24
  current_slug: context&.slug,
25
- root_path: settings.root_path,
26
- root_title: settings.root[:title],
25
+ root_path: TinyAdmin.settings.root_path,
26
+ root_title: TinyAdmin.settings.root[:title],
27
27
  items: options&.include?(:no_menu) ? [] : context&.navbar
28
28
  )
29
29
  yield(page) if block_given?
@@ -31,7 +31,7 @@ module TinyAdmin
31
31
  end
32
32
 
33
33
  def route_for(section, reference: nil, action: nil, query: nil)
34
- root_path = settings.root_path == '/' ? nil : settings.root_path
34
+ root_path = TinyAdmin.settings.root_path == '/' ? nil : TinyAdmin.settings.root_path
35
35
  route = [root_path, section, reference, action].compact.join("/")
36
36
  route << "?#{query}" if query
37
37
  route[0] == '/' ? route : route.prepend('/')
@@ -46,9 +46,5 @@ module TinyAdmin
46
46
  def context
47
47
  TinyAdmin::Context.instance
48
48
  end
49
-
50
- def settings
51
- TinyAdmin::Settings.instance
52
- end
53
49
  end
54
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
@@ -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)
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  attr_accessor :flash_component, :head_component, :messages, :navbar_component, :options, :title
7
7
 
8
8
  def template(&block)
9
- extra_styles = settings.extra_styles
9
+ extra_styles = TinyAdmin.settings.extra_styles
10
10
  flash_component&.messages = messages
11
11
  head_component&.update_attributes(page_title: title, style_links: style_links, extra_styles: extra_styles)
12
12
 
@@ -49,7 +49,7 @@ module TinyAdmin
49
49
  end
50
50
 
51
51
  def style_links
52
- settings.style_links || [
52
+ TinyAdmin.settings.style_links || [
53
53
  # Bootstrap CDN
54
54
  {
55
55
  href: 'https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css',
@@ -61,7 +61,7 @@ module TinyAdmin
61
61
  end
62
62
 
63
63
  def render_scripts
64
- (settings.scripts || []).each do |script_attrs|
64
+ (TinyAdmin.settings.scripts || []).each do |script_attrs|
65
65
  script(**script_attrs)
66
66
  end
67
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.5.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-24 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
@@ -101,6 +101,7 @@ files:
101
101
  - lib/tiny_admin/views/components/navbar.rb
102
102
  - lib/tiny_admin/views/components/pagination.rb
103
103
  - lib/tiny_admin/views/default_layout.rb
104
+ - lib/tiny_admin/views/pages/content.rb
104
105
  - lib/tiny_admin/views/pages/page_not_found.rb
105
106
  - lib/tiny_admin/views/pages/record_not_found.rb
106
107
  - lib/tiny_admin/views/pages/root.rb