madmin 0.1.1 → 1.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ae907c78952efd333b7151ef50818dc6b171017239a11152c129c17bb45af10
4
- data.tar.gz: 923a8e6ecb3e84bffd6973a511845cc16cc599e36adc5116525ab01e46bc1c16
3
+ metadata.gz: 25bf67586811ced1dc2612fe0382c517f656895261e5b24b6c90c0cd6d9f21f6
4
+ data.tar.gz: a41bbd0a7be385b1aad8fef678ee61a56f90964fc1dc749cf728d3cc52739d54
5
5
  SHA512:
6
- metadata.gz: c696a1782666fdcc4a113d7709775c41e245a9f92ef298c93a6fb98a1c1f2db4f5a34f36d59a1c3da476a6db44bfcc864f5b37c8136ef8f8a155415344b74660
7
- data.tar.gz: d7eef669f0b0366ccaf73f3cd68f85525067172ade70c55397b9cd27e7132c3008a067d68d5bc3d073e94441f1cbf8a9e893a11a2b91fbfd0dbdd6a695487230
6
+ metadata.gz: 99bdd270af3258778d08d0b7ec69f1cbb3406d7f14fe29a10892afaf09f3857c0fa114287f6aaa4f253aefc40f2bad5d626109caa0340638ed091e8c9f7fdeef
7
+ data.tar.gz: 21a2fb128bcc6e2e89e443694d4bceac0e9b94838da425333845539eef99ae1696bdf1d385ed530b1262ccdaa6746d10ab864424796be193192165996d4352f2
data/README.md CHANGED
@@ -1,11 +1,14 @@
1
1
  # Madmin
2
2
 
3
- ### A robust admin interface for Ruby on Rails apps
3
+ ### 🛠 A robust Admin Interface for Ruby on Rails apps
4
4
 
5
5
  [![Build Status](https://github.com/excid3/madmin/workflows/Tests/badge.svg)](https://github.com/excid3/madmin/actions) [![Gem Version](https://badge.fury.io/rb/madmin.svg)](https://badge.fury.io/rb/madmin)
6
6
 
7
- ## Usage
8
- How to use my plugin.
7
+ Why another Ruby on Rails admin? We wanted an admin that was:
8
+
9
+ * Familiar and customizable like Rails scaffolds (less DSL)
10
+ * Supports all the Rails features out of the box (ActionText, ActionMailbox, etc)
11
+ * Stimulus / Turbolinks / Hotwire ready
9
12
 
10
13
  ## Installation
11
14
  Add `madmin` to your application's Gemfile:
@@ -20,8 +23,23 @@ Then run the madmin generator:
20
23
  rails g madmin:install
21
24
  ```
22
25
 
23
- ## Contributing
24
- Contribution directions go here.
26
+ This will install Madmin and generate resources for each of the models it finds.
27
+
28
+ ## Resources
29
+
30
+ Madmin uses `Resource` classes to add models to the admin area.
31
+
32
+ ### Generate a Resource
33
+
34
+ To generate a resource for a model, you can run:
35
+
36
+ ```bash
37
+ rails g madmin:resource ActionText::RichText
38
+ ```
39
+
40
+ ## 🙏 Contributing
41
+
42
+ This project uses Standard for formatting Ruby code. Please make sure to run standardrb before submitting pull requests.
25
43
 
26
- ## License
44
+ ## 📝 License
27
45
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -18,6 +18,10 @@ require "bundler/gem_tasks"
18
18
 
19
19
  require "rake/testtask"
20
20
 
21
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
22
+ load "rails/tasks/engine.rake"
23
+ load "rails/tasks/statistics.rake"
24
+
21
25
  Rake::TestTask.new(:test) do |t|
22
26
  t.libs << "test"
23
27
  t.pattern = "test/**/*_test.rb"
@@ -1,5 +1,5 @@
1
1
  module Madmin
2
- class ApplicationController < ActionController::Base
2
+ class BaseController < ActionController::Base
3
3
  include Pagy::Backend
4
4
 
5
5
  protect_from_forgery with: :exception
@@ -3,7 +3,7 @@ module Madmin
3
3
  before_action :set_record, except: [:index, :new, :create]
4
4
 
5
5
  def index
6
- @pagy, @records = pagy(resource.model.all)
6
+ @pagy, @records = pagy(scoped_resources)
7
7
  end
8
8
 
9
9
  def show
@@ -18,7 +18,7 @@ module Madmin
18
18
  if @record.save
19
19
  redirect_to resource.show_path(@record)
20
20
  else
21
- render :new
21
+ render :new, status: :unprocessable_entity
22
22
  end
23
23
  end
24
24
 
@@ -29,7 +29,7 @@ module Madmin
29
29
  if @record.update(resource_params)
30
30
  redirect_to resource.show_path(@record)
31
31
  else
32
- render :edit
32
+ render :edit, status: :unprocessable_entity
33
33
  end
34
34
  end
35
35
 
@@ -53,6 +53,15 @@ module Madmin
53
53
  "#{controller_path.singularize}_resource".delete_prefix("madmin/").classify
54
54
  end
55
55
 
56
+ def scoped_resources
57
+ resource.model.send(valid_scope)
58
+ end
59
+
60
+ def valid_scope
61
+ scope = params.fetch(:scope, "all")
62
+ resource.scopes.include?(scope.to_sym) ? scope : :all
63
+ end
64
+
56
65
  def resource_params
57
66
  params.require(resource.param_key)
58
67
  .permit(*resource.permitted_params)
@@ -1,5 +1,17 @@
1
1
  module Madmin
2
2
  module ApplicationHelper
3
3
  include Pagy::Frontend
4
+
5
+ # Converts a Rails version to a NPM version
6
+ def npm_rails_version
7
+ version = [
8
+ Rails::VERSION::MAJOR,
9
+ Rails::VERSION::MINOR,
10
+ Rails::VERSION::TINY
11
+ ].join(".")
12
+
13
+ version += "-#{Rails::VERSION::PRE}" if Rails::VERSION::PRE
14
+ version
15
+ end
4
16
  end
5
17
  end
@@ -10,9 +10,9 @@
10
10
  <link href="https://unpkg.com/tailwindcss@^2.0/dist/tailwind.min.css" rel="stylesheet" />
11
11
  <link href="https://unpkg.com/@tailwindcss/forms/dist/forms.min.css" rel="stylesheet" />
12
12
  <link href="https://unpkg.com/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet" />
13
- <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
14
- <%= javascript_pack_tag "madmin", "data-turbo-track": "reload" %>
15
13
  <%= csrf_meta_tags %>
14
+
15
+ <%= render "javascript" %>
16
16
  </head>
17
17
  <body class="prose" style="max-width:none">
18
18
  <div class="flex w-full p-4">
@@ -24,6 +24,5 @@
24
24
  <%= yield %>
25
25
  </main>
26
26
  </div>
27
- <%#= render "javascript" %>
28
27
  </body>
29
28
  </html>
@@ -0,0 +1,24 @@
1
+ <%= stylesheet_link_tag "https://cdn.skypack.dev/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
2
+ <%= stylesheet_link_tag "https://cdn.skypack.dev/slim-select/dist/slimselect.min.css", "data-turbo-track": "reload" %>
3
+ <%= stylesheet_link_tag "https://cdn.skypack.dev/trix/dist/trix.css", "data-turbo-track": "reload" %>
4
+
5
+ <script type="module">
6
+ import { Application } from 'https://cdn.skypack.dev/stimulus'
7
+ const application = Application.start()
8
+
9
+ import stimulusFlatpickr from 'https://cdn.skypack.dev/stimulus-flatpickr'
10
+ application.register("flatpickr", stimulusFlatpickr)
11
+
12
+ import stimulusSlimselect from 'https://cdn.skypack.dev/stimulus-slimselect'
13
+ application.register("slimselect", stimulusSlimselect)
14
+
15
+ import Rails from 'https://cdn.skypack.dev/@rails/ujs@<%= npm_rails_version %>'
16
+ import * as ActiveStorage from 'https://cdn.skypack.dev/@rails/activestorage@<%= npm_rails_version %>'
17
+ import 'https://cdn.skypack.dev/trix'
18
+ import 'https://cdn.skypack.dev/@rails/actiontext@<%= npm_rails_version %>'
19
+
20
+ Rails.start()
21
+ ActiveStorage.start()
22
+
23
+ import * as Turbo from "https://cdn.skypack.dev/@hotwired/turbo"
24
+ </script>
@@ -1,5 +1,5 @@
1
1
  <div class="text-sm">
2
- <%= link_to "← Back to App", main_app.root_url, class: "block p-1" if main_app.respond_to?(:root_url) %>
2
+ <%= link_to "← Back to App", main_app.root_url, class: "block p-1", data: { turbo: false } if main_app.respond_to?(:root_url) %>
3
3
  <% Madmin.resources.each do |resource| %>
4
4
  <%= link_to resource.friendly_name.pluralize, resource.index_path, class: "block p-1" %>
5
5
  <% end %>
@@ -1,5 +1,17 @@
1
- <h1><%= resource.friendly_name.pluralize %></h1>
2
- <%= link_to "New #{resource.friendly_name}", resource.new_path %>
1
+ <div class="flex justify-between">
2
+ <h1><%= resource.friendly_name.pluralize %></h1>
3
+ <%= link_to "New #{resource.friendly_name}", resource.new_path %>
4
+ </div>
5
+
6
+ <div>
7
+ <% if resource.scopes.any? %>
8
+ <%= link_to "All", resource.index_path %>
9
+ <% end %>
10
+
11
+ <% resource.scopes.each do |scope| %>
12
+ <%= link_to scope.to_s.humanize, resource.index_path(scope: scope) %>
13
+ <% end %>
14
+ </div>
3
15
 
4
16
  <table class="table-auto">
5
17
  <thead>
@@ -1,2 +1,2 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { class: "form-select" } %>
2
+ <%= form.select field.to_param, field.options_for_select(record), { prompt: true }, { class: "form-select", data: { controller: "slimselect", data: { controller: "slimselect" } } } %>
@@ -1,2 +1,2 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <%= form.date_select field.attribute_name, {}, { class: "form-select" } %>
2
+ <%= form.text_field field.attribute_name, { class: "form-select", data: { controller: "flatpickr" } } %>
@@ -1,2 +1,2 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <%= form.datetime_select field.attribute_name, {}, { class: "form-select" } %>
2
+ <%= form.text_field field.attribute_name, data: { controller: "flatpickr", flatpickr_enable_time: true } %>
@@ -0,0 +1,2 @@
1
+ <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
+ <%= form.number_field field.attribute_name, step: :any, class: "form-input" %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -0,0 +1 @@
1
+ <%= field.value(record) %>
@@ -1,2 +1,2 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <%= form.number_field field.attribute_name, class: "form-input" %>
2
+ <%= form.number_field field.attribute_name, step: :any, class: "form-input" %>
@@ -1,2 +1,2 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <%= form.select "#{field.attribute_name.to_s.singularize}_ids", field.options_for_select(record), { prompt: true }, { multiple: true, class: "form-select" } %>
2
+ <%= form.select "#{field.attribute_name.to_s.singularize}_ids", field.options_for_select(record), { prompt: true }, { multiple: true, class: "form-select", data: { controller: "slimselect" } } %>
@@ -1,5 +1,5 @@
1
1
  <%= form.fields_for field.attribute_name do |pf| %>
2
2
  <%= pf.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
3
- <%= pf.select :value, field.options_for_select(record).map(&:to_global_id), { selected: field.value(record)&.to_global_id, prompt: true }, { class: "form-select" } %>
3
+ <%= pf.select :value, field.options_for_select(record).map(&:to_global_id), { selected: field.value(record)&.to_global_id, prompt: true }, { class: "form-select", data: { controller: "slimselect" } } %>
4
4
  <%= pf.hidden_field :type, value: "polymorphic" %>
5
5
  <% end %>
@@ -1,4 +1,4 @@
1
1
  <%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
2
- <div>
3
- <%= form.rich_text_area field.attribute_name, class: "form-input" %>
2
+ <div class="flex-1">
3
+ <%= form.rich_text_area field.attribute_name, class: "form-input block" %>
4
4
  </div>
@@ -5,10 +5,16 @@ module Madmin
5
5
  class InstallGenerator < Rails::Generators::Base
6
6
  include Madmin::GeneratorHelpers
7
7
 
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
8
10
  def eager_load
9
11
  Rails.application.eager_load!
10
12
  end
11
13
 
14
+ def copy_controller
15
+ template("controller.rb.tt", "app/controllers/madmin/application_controller.rb")
16
+ end
17
+
12
18
  def generate_routes
13
19
  if route_namespace_exists?
14
20
  route "root to: \"dashboard#show\"", indentation: 4, sentinel: /namespace :madmin do\s*\n/m
@@ -0,0 +1,22 @@
1
+ module Madmin
2
+ class ApplicationController < Madmin::BaseController
3
+ before_action :authenticate_admin_user
4
+
5
+ def authenticate_admin_user
6
+ # TODO: Add your authentication logic here
7
+
8
+ # For example, we could redirect if the user isn't an admin
9
+ # redirect_to "/", alert: "Not authorized." unless user_signed_in? && current_user.admin?
10
+ end
11
+
12
+ # Authenticate with Clearance
13
+ # include Clearance::Controller
14
+ # before_action :require_login
15
+
16
+ # Authenticate with Devise
17
+ # before_action :authenticate_user!
18
+
19
+ # Authenticate with Basic Auth
20
+ # http_basic_authenticate_with(name: Rails.application.credentials.admin_username, password: Rails.application.credentials.admin_password)
21
+ end
22
+ end
data/lib/madmin.rb CHANGED
@@ -14,6 +14,7 @@ module Madmin
14
14
  autoload :Text, "madmin/fields/text"
15
15
  autoload :Date, "madmin/fields/date"
16
16
  autoload :DateTime, "madmin/fields/date_time"
17
+ autoload :Decimal, "madmin/fields/decimal"
17
18
  autoload :Json, "madmin/fields/json"
18
19
  autoload :Enum, "madmin/fields/enum"
19
20
  autoload :Float, "madmin/fields/float"
data/lib/madmin/field.rb CHANGED
@@ -1,13 +1,14 @@
1
1
  module Madmin
2
2
  class Field
3
- attr_reader :attribute_name, :options
3
+ attr_reader :attribute_name, :model, :options
4
4
 
5
5
  def self.field_type
6
6
  to_s.split("::").last.underscore
7
7
  end
8
8
 
9
- def initialize(attribute_name:, **options)
9
+ def initialize(attribute_name:, model:, **options)
10
10
  @attribute_name = attribute_name
11
+ @model = model
11
12
  @options = options
12
13
  end
13
14
 
@@ -31,5 +32,9 @@ module Madmin
31
32
  def visible?(action, default: true)
32
33
  options.fetch(action.to_sym, default)
33
34
  end
35
+
36
+ def required?
37
+ model.validators_on(attribute_name).any? { |v| v.is_a? ActiveModel::Validations::PresenceValidator }
38
+ end
34
39
  end
35
40
  end
@@ -0,0 +1,6 @@
1
+ module Madmin
2
+ module Fields
3
+ class Decimal < Field
4
+ end
5
+ end
6
+ end
@@ -29,7 +29,7 @@ module Madmin
29
29
  def attribute(name, type = nil, **options)
30
30
  attributes << {
31
31
  name: name,
32
- field: field_for_type(name, type).new(**options.merge(attribute_name: name))
32
+ field: field_for_type(name, type).new(**options.merge(attribute_name: name, model: model))
33
33
  }
34
34
  end
35
35
 
@@ -37,8 +37,10 @@ module Madmin
37
37
  model_name.gsub("::", " / ")
38
38
  end
39
39
 
40
- def index_path
41
- "/madmin/#{model.model_name.collection}"
40
+ def index_path(options = {})
41
+ path = "/madmin/#{model.model_name.collection}"
42
+ path += "?#{options.to_param}" if options.any?
43
+ path
42
44
  end
43
45
 
44
46
  def new_path
@@ -71,16 +73,51 @@ module Madmin
71
73
  type ||= infer_type(name)
72
74
 
73
75
  {
76
+ binary: Fields::String,
77
+ blob: Fields::Text,
78
+ boolean: Fields::Boolean,
74
79
  date: Fields::Date,
75
80
  datetime: Fields::DateTime,
81
+ decimal: Fields::Decimal,
76
82
  enum: Fields::Enum,
77
83
  float: Fields::Float,
84
+ hstore: Fields::Json,
78
85
  integer: Fields::Integer,
79
86
  json: Fields::Json,
87
+ jsonb: Fields::Json,
88
+ primary_key: Fields::String,
80
89
  string: Fields::String,
81
90
  text: Fields::Text,
82
91
  time: Fields::Time,
83
- boolean: Fields::Boolean,
92
+ timestamp: Fields::Time,
93
+
94
+ # Postgres specific types
95
+ bit: Fields::String,
96
+ bit_varying: Fields::String,
97
+ box: Fields::String,
98
+ cidr: Fields::String,
99
+ circle: Fields::String,
100
+ citext: Fields::Text,
101
+ daterange: Fields::String,
102
+ inet: Fields::String,
103
+ int4range: Fields::String,
104
+ int8range: Fields::String,
105
+ interval: Fields::String,
106
+ line: Fields::String,
107
+ lseg: Fields::String,
108
+ ltree: Fields::String,
109
+ macaddr: Fields::String,
110
+ money: Fields::String,
111
+ numrange: Fields::String,
112
+ oid: Fields::String,
113
+ path: Fields::String,
114
+ point: Fields::String,
115
+ polygon: Fields::String,
116
+ tsrange: Fields::String,
117
+ tstzrange: Fields::String,
118
+ tsvector: Fields::String,
119
+ uuid: Fields::String,
120
+ xml: Fields::Text,
84
121
 
85
122
  # Associations
86
123
  attachment: Fields::Attachment,
@@ -91,6 +128,15 @@ module Madmin
91
128
  has_one: Fields::HasOne,
92
129
  rich_text: Fields::RichText
93
130
  }.fetch(type)
131
+ rescue
132
+ raise ArgumentError, <<~MESSAGE
133
+ Couldn't find attribute or association '#{name}' with type '#{type}' on #{model} model
134
+
135
+ To fix this, either:
136
+
137
+ 1. Remove 'attribute #{name}' from app/madmin/resources/#{model.to_s.underscore}_resource.rb
138
+ 2. Or add the missing attribute or association to the #{model} model
139
+ MESSAGE
94
140
  end
95
141
 
96
142
  def infer_type(name)
@@ -1,3 +1,3 @@
1
1
  module Madmin
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0.beta1"
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  - Andrea Fomera
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-01-15 00:00:00.000000000 Z
12
+ date: 2021-02-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -45,20 +45,6 @@ dependencies:
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '4.0'
48
- - !ruby/object:Gem::Dependency
49
- name: sqlite3
50
- requirement: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :development
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
48
  description: It's an admin, obviously.
63
49
  email:
64
50
  - excid3@gmail.com
@@ -73,12 +59,13 @@ files:
73
59
  - app/assets/config/manifest.js
74
60
  - app/assets/stylesheets/actiontext.scss
75
61
  - app/assets/stylesheets/application.css
76
- - app/controllers/madmin/application_controller.rb
62
+ - app/controllers/madmin/base_controller.rb
77
63
  - app/controllers/madmin/dashboard_controller.rb
78
64
  - app/controllers/madmin/resource_controller.rb
79
65
  - app/helpers/madmin/application_helper.rb
80
66
  - app/views/layouts/madmin/application.html.erb
81
67
  - app/views/madmin/application/_form.html.erb
68
+ - app/views/madmin/application/_javascript.html.erb
82
69
  - app/views/madmin/application/_navigation.html.erb
83
70
  - app/views/madmin/application/edit.html.erb
84
71
  - app/views/madmin/application/index.html.erb
@@ -103,6 +90,9 @@ files:
103
90
  - app/views/madmin/fields/date_time/_form.html.erb
104
91
  - app/views/madmin/fields/date_time/_index.html.erb
105
92
  - app/views/madmin/fields/date_time/_show.html.erb
93
+ - app/views/madmin/fields/decimal/_form.html.erb
94
+ - app/views/madmin/fields/decimal/_index.html.erb
95
+ - app/views/madmin/fields/decimal/_show.html.erb
106
96
  - app/views/madmin/fields/enum/_form.html.erb
107
97
  - app/views/madmin/fields/enum/_index.html.erb
108
98
  - app/views/madmin/fields/enum/_show.html.erb
@@ -137,6 +127,7 @@ files:
137
127
  - app/views/madmin/fields/time/_index.html.erb
138
128
  - app/views/madmin/fields/time/_show.html.erb
139
129
  - lib/generators/madmin/install/install_generator.rb
130
+ - lib/generators/madmin/install/templates/controller.rb.tt
140
131
  - lib/generators/madmin/resource/resource_generator.rb
141
132
  - lib/generators/madmin/resource/templates/controller.rb.tt
142
133
  - lib/generators/madmin/resource/templates/resource.rb.tt
@@ -149,6 +140,7 @@ files:
149
140
  - lib/madmin/fields/boolean.rb
150
141
  - lib/madmin/fields/date.rb
151
142
  - lib/madmin/fields/date_time.rb
143
+ - lib/madmin/fields/decimal.rb
152
144
  - lib/madmin/fields/enum.rb
153
145
  - lib/madmin/fields/float.rb
154
146
  - lib/madmin/fields/has_many.rb
@@ -168,7 +160,7 @@ homepage: https://github.com/excid3/madmin
168
160
  licenses:
169
161
  - MIT
170
162
  metadata: {}
171
- post_install_message:
163
+ post_install_message:
172
164
  rdoc_options: []
173
165
  require_paths:
174
166
  - lib
@@ -179,12 +171,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
171
  version: 2.5.0
180
172
  required_rubygems_version: !ruby/object:Gem::Requirement
181
173
  requirements:
182
- - - ">="
174
+ - - ">"
183
175
  - !ruby/object:Gem::Version
184
- version: '0'
176
+ version: 1.3.1
185
177
  requirements: []
186
- rubygems_version: 3.1.4
187
- signing_key:
178
+ rubygems_version: 3.2.3
179
+ signing_key:
188
180
  specification_version: 4
189
181
  summary: A modern admin for Ruby on Rails apps
190
182
  test_files: []