madmin 0.1.1 → 1.0.0.beta1

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: 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: []