tiny_admin 0.2.0 → 0.3.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: 10d229ad7389d1fe4392d6f96ec993550470ba67d1b4e140df21b9d247ae3657
4
- data.tar.gz: 3f625daa624cdff4e7fe4f13618ac753cce120995daa9140dac17e55d79ef1ba
3
+ metadata.gz: d203e48b821f195f95847a646e32787c9ffd953212326f64e65ca09d563ed55e
4
+ data.tar.gz: a133ad428942d240ec8852e4885e12a51bc6a96f9a4bcf426470180671dddf6f
5
5
  SHA512:
6
- metadata.gz: 7078779b3478f2e28f5864b43839a69ee918a452a97c0851b3be45a75802fd01600f2df6d771f093032e021f98c408b40fcaffac0b4ba5fca61e5e92693bfe86
7
- data.tar.gz: c120746d7363cbda9dd39f9de6910181645da4d63bf8325c0e4d8619b2892b008c882a32e4e8b50f63ec9fc6486837843e920f4e4c917424390346fb5af67877
6
+ metadata.gz: 8955bf003179333debcf4c43dd7091b4d81fc9c1e90a6116119dc33f51b4ab7dca394d90f6f8aa6bb0385339dc5eb07b64bd546f0a92e02497d5c000cc835769
7
+ data.tar.gz: 5cabb3dc010e73b416068cca3afda56dc07ac7b024c70d734b9409298d2082798a8e5e276d892be81e82dcbfa68bad20360f0d99e4c8e7199a7bdb5067f72124
data/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  A compact and composable dashboard component for Ruby.
6
6
 
7
- The main features are:
8
- - a Rack app that can be mounted in any Rack-enabled framework, it can even work standalone;
7
+ Main features:
8
+ - a Rack app that can be mounted in any Rack-enabled framework or used standalone;
9
9
  - structured with plugins also for main components that can be replaced with little effort;
10
- - routing is provided by Roda, which is small and performant;
11
- - views are Phlex components, so plain Ruby objects for views and no assets are needed.
10
+ - routing is provided by Roda which is small and performant;
11
+ - views are Phlex components, so plain Ruby objects for views, no assets are needed.
12
12
 
13
13
  Please ⭐ if you like it.
14
14
 
@@ -16,9 +16,19 @@ Please ⭐ if you like it.
16
16
 
17
17
  ## Install
18
18
 
19
- - Add to your Gemfile: `gem 'tiny_admin', '~> 0.1'`
19
+ - Add to your Gemfile: `gem 'tiny_admin', '~> 0.3'`
20
20
  - Mount the app in a route (check some examples with: Hanami, Rails, Roda and standalone in [extra](extra))
21
- - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` (see [configuration](#configuration) below)
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):
23
+
24
+ ```rb
25
+ TinyAdmin.configure do |settings|
26
+ settings.root = {
27
+ title: 'Home',
28
+ page: Admin::PageRoot
29
+ }
30
+ end
31
+ ```
22
32
 
23
33
  ## Plugins and components
24
34
 
@@ -3,21 +3,24 @@
3
3
  module TinyAdmin
4
4
  module Actions
5
5
  class Index < BasicAction
6
- attr_reader :current_page, :fields_options, :filters_list, :pagination, :query_string, :sort
6
+ attr_reader :current_page, :fields_options, :filters_list, :pagination, :pages, :query_string, :sort
7
7
 
8
8
  def call(app:, context:, options:, actions:)
9
9
  evaluate_options(options)
10
10
  fields = repository.fields(options: fields_options)
11
11
  filters = prepare_filters(fields, filters_list)
12
12
  records, total_count = repository.list(page: current_page, limit: pagination, filters: filters, sort: sort)
13
- prepare_record = ->(record) { repository.index_record_attrs(record, fields: fields_options) }
14
- title = repository.index_title
15
- pages = (total_count / pagination) + 1
16
-
17
- prepare_page(Views::Actions::Index, context: context) do |page|
18
- page.setup_pagination(current_page: current_page, pages: pages > 1 ? pages : false)
19
- page.setup_records(records: records, fields: fields, prepare_record: prepare_record)
20
- page.update_attributes(actions: actions, filters: filters, query_string: query_string, title: title)
13
+
14
+ prepare_page(Views::Actions::Index) do |page|
15
+ setup_pagination(page, settings.components[:pagination], total_count: total_count)
16
+ page.update_attributes(
17
+ actions: actions,
18
+ fields: fields,
19
+ filters: filters,
20
+ prepare_record: ->(record) { repository.index_record_attrs(record, fields: fields_options) },
21
+ records: records,
22
+ title: repository.index_title
23
+ )
21
24
  end
22
25
  end
23
26
 
@@ -43,6 +46,14 @@ module TinyAdmin
43
46
  result[field] = { value: values[field.name], filter: filters[field.name] } if filters.key?(field.name)
44
47
  end
45
48
  end
49
+
50
+ def setup_pagination(page, pagination_component_class, total_count:)
51
+ @pages = (total_count / pagination.to_f).ceil
52
+ return if pages <= 1 || !pagination_component_class
53
+
54
+ page.pagination_component = pagination_component_class.new
55
+ page.pagination_component.update(current: current_page, pages: pages, query_string: query_string)
56
+ end
46
57
  end
47
58
  end
48
59
  end
@@ -11,7 +11,7 @@ module TinyAdmin
11
11
  prepare_record = ->(record_data) { repository.show_record_attrs(record_data, fields: fields_options) }
12
12
  fields = repository.fields(options: fields_options)
13
13
 
14
- prepare_page(Views::Actions::Show, context: context) do |page|
14
+ prepare_page(Views::Actions::Show) do |page|
15
15
  page.setup_record(record: record, fields: fields, prepare_record: prepare_record)
16
16
  page.update_attributes(actions: actions, title: repository.show_title(record))
17
17
  end
@@ -8,7 +8,7 @@ module TinyAdmin
8
8
  class << self
9
9
  def configure(app, opts = {})
10
10
  @@opts = opts || {} # rubocop:disable Style/ClassVars
11
- @@opts[:password] ||= ENV.fetch('ADMIN_PASSWORD_HASH') # NOTE: fallback value
11
+ @@opts[:password] ||= ENV.fetch('ADMIN_PASSWORD_HASH', nil) # NOTE: fallback value
12
12
 
13
13
  Warden::Strategies.add(:secret) do
14
14
  def authenticate!
@@ -54,14 +54,14 @@ module TinyAdmin
54
54
  else
55
55
  page = settings.root[:page]
56
56
  page_class = page.is_a?(String) ? Object.const_get(page) : page
57
- render_page prepare_page(page_class, context: context)
57
+ render_page prepare_page(page_class)
58
58
  end
59
59
  end
60
60
 
61
61
  def setup_page_route(router, slug, page_class)
62
62
  router.get slug do
63
63
  context.slug = slug
64
- render_page prepare_page(page_class, context: context)
64
+ render_page prepare_page(page_class)
65
65
  end
66
66
  end
67
67
 
@@ -13,10 +13,18 @@ module TinyAdmin
13
13
  list.join('&')
14
14
  end
15
15
 
16
- def prepare_page(page_class, context: nil, options: nil)
16
+ def prepare_page(page_class, options: nil)
17
17
  page_class.new.tap do |page|
18
- page.context = context
19
18
  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(
22
+ current_slug: context&.slug,
23
+ root_path: settings.root_path,
24
+ root_title: settings.root[:title],
25
+ items: options&.include?(:no_menu) ? [] : settings.navbar
26
+ )
27
+
20
28
  yield(page) if block_given?
21
29
  end
22
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -4,21 +4,10 @@ module TinyAdmin
4
4
  module Views
5
5
  module Actions
6
6
  class Index < DefaultLayout
7
- attr_reader :current_page, :fields, :pages, :prepare_record, :records
8
- attr_accessor :actions, :filters, :query_string
9
-
10
- def setup_pagination(current_page:, pages:)
11
- @current_page = current_page
12
- @pages = pages
13
- end
14
-
15
- def setup_records(records:, fields:, prepare_record:)
16
- @records = records
17
- @fields = fields.each_with_object({}) { |field, result| result[field.name] = field }
18
- @prepare_record = prepare_record
19
- end
7
+ attr_accessor :actions, :fields, :filters, :pagination_component, :prepare_record, :records
20
8
 
21
9
  def template
10
+ @fields = fields.each_with_object({}) { |field, result| result[field.name] = field }
22
11
  @filters ||= {}
23
12
 
24
13
  super do
@@ -57,9 +46,7 @@ module TinyAdmin
57
46
  end
58
47
  }
59
48
 
60
- if pages
61
- render components[:pagination].new(current: current_page, pages: pages, query_string: query_string)
62
- end
49
+ render pagination_component if pagination_component
63
50
  }
64
51
  end
65
52
  end
@@ -5,10 +5,6 @@ module TinyAdmin
5
5
  class BasicLayout < Phlex::HTML
6
6
  include Utils
7
7
 
8
- def components
9
- settings.components
10
- end
11
-
12
8
  def update_attributes(attributes)
13
9
  attributes.each do |key, value|
14
10
  send("#{key}=", value)
@@ -6,14 +6,6 @@ module TinyAdmin
6
6
  class Flash < Phlex::HTML
7
7
  attr_reader :errors, :notices, :warnings
8
8
 
9
- def initialize(messages:)
10
- return unless messages
11
-
12
- @notices = messages[:notices]
13
- @warnings = messages[:warnings]
14
- @errors = messages[:errors]
15
- end
16
-
17
9
  def template
18
10
  div(class: 'flash') {
19
11
  div(class: 'notices alert alert-success', role: 'alert') { notices.join(', ') } if notices&.any?
@@ -21,6 +13,14 @@ module TinyAdmin
21
13
  div(class: 'notices alert alert-danger', role: 'alert') { errors.join(', ') } if errors&.any?
22
14
  }
23
15
  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
24
  end
25
25
  end
26
26
  end
@@ -6,12 +6,6 @@ module TinyAdmin
6
6
  class Head < Phlex::HTML
7
7
  attr_reader :extra_styles, :page_title, :style_links
8
8
 
9
- def initialize(page_title, style_links: [], extra_styles: nil)
10
- @page_title = page_title
11
- @style_links = style_links
12
- @extra_styles = extra_styles
13
- end
14
-
15
9
  def template
16
10
  head {
17
11
  meta charset: 'utf-8'
@@ -25,6 +19,12 @@ module TinyAdmin
25
19
  style { extra_styles } if extra_styles
26
20
  }
27
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
28
  end
29
29
  end
30
30
  end
@@ -6,27 +6,48 @@ module TinyAdmin
6
6
  class Pagination < Phlex::HTML
7
7
  attr_reader :current, :pages, :query_string
8
8
 
9
- def initialize(current:, pages:, query_string:)
10
- @current = current
11
- @pages = pages
12
- @query_string = query_string
13
- end
14
-
15
9
  def template
16
10
  div(class: 'pagination-div') {
17
11
  nav('aria-label' => 'Pagination') {
18
12
  ul(class: 'pagination justify-content-center') {
19
- 1.upto(pages) do |i|
20
- li_class = (i == current ? 'page-item active' : 'page-item')
21
- li(class: li_class) {
22
- href = query_string.empty? ? "?p=#{i}" : "?#{query_string}&p=#{i}"
23
- a(class: 'page-link', href: href) { i }
24
- }
13
+ if pages <= 10
14
+ pages_range(1..pages)
15
+ elsif current <= 4 || current >= pages - 3
16
+ pages_range(1..(current <= 4 ? current + 2 : 4), with_dots: true)
17
+ pages_range((current > pages - 4 ? current - 2 : pages - 2)..pages)
18
+ else
19
+ pages_range(1..1, with_dots: true)
20
+ pages_range(current - 2..current + 2, with_dots: true)
21
+ pages_range(pages..pages)
25
22
  end
26
23
  }
27
24
  }
28
25
  }
29
26
  end
27
+
28
+ def update(current:, pages:, query_string:)
29
+ @current = current
30
+ @pages = pages
31
+ @query_string = query_string
32
+ end
33
+
34
+ private
35
+
36
+ def pages_range(range, with_dots: false)
37
+ range.each do |page|
38
+ li(class: page == current ? 'page-item active' : 'page-item') {
39
+ href = query_string.empty? ? "?p=#{page}" : "?#{query_string}&p=#{page}"
40
+ a(class: 'page-link', href: href) { page }
41
+ }
42
+ end
43
+ dots if with_dots
44
+ end
45
+
46
+ def dots
47
+ li(class: 'page-item disabled') {
48
+ a(class: 'page-link') { '...' }
49
+ }
50
+ end
30
51
  end
31
52
  end
32
53
  end
@@ -3,24 +3,22 @@
3
3
  module TinyAdmin
4
4
  module Views
5
5
  class DefaultLayout < BasicLayout
6
- attr_accessor :context, :messages, :options, :title
6
+ attr_accessor :flash_component, :head_component, :messages, :navbar_component, :options, :title
7
7
 
8
8
  def template(&block)
9
+ flash_component&.update(messages: messages)
10
+ head_component&.update(title, style_links: style_links, extra_styles: settings.extra_styles)
11
+
9
12
  doctype
10
13
  html {
11
- render components[:head].new(title, style_links: style_links, extra_styles: settings.extra_styles)
14
+ render head_component if head_component
12
15
 
13
16
  body(class: body_class) {
14
- navbar_attrs = {
15
- current_slug: context&.slug,
16
- root_path: settings.root_path,
17
- root_title: settings.root[:title],
18
- items: navbar_items
19
- }
20
- render components[:navbar].new(**navbar_attrs)
17
+ render navbar_component if navbar_component
21
18
 
22
19
  main_content {
23
- render components[:flash].new(messages: messages || {})
20
+ render flash_component if flash_component
21
+
24
22
  yield_content(&block)
25
23
  }
26
24
 
@@ -35,10 +33,6 @@ module TinyAdmin
35
33
  "module-#{self.class.to_s.split('::').last.downcase}"
36
34
  end
37
35
 
38
- def navbar_items
39
- options&.include?(:no_menu) ? [] : settings.navbar
40
- end
41
-
42
36
  def main_content
43
37
  div(class: 'container main-content py-4') do
44
38
  if options&.include?(:compact_layout)
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.2.0
4
+ version: 0.3.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-10 00:00:00.000000000 Z
11
+ date: 2023-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex