madmin 0.1.1 → 1.0.2
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 +4 -4
- data/README.md +68 -6
- data/Rakefile +4 -0
- data/app/controllers/madmin/{application_controller.rb → base_controller.rb} +1 -1
- data/app/controllers/madmin/resource_controller.rb +12 -3
- data/app/helpers/madmin/application_helper.rb +12 -0
- data/app/views/layouts/madmin/application.html.erb +2 -3
- data/app/views/madmin/application/_javascript.html.erb +24 -0
- data/app/views/madmin/application/_navigation.html.erb +1 -1
- data/app/views/madmin/application/index.html.erb +14 -2
- data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -1
- data/app/views/madmin/fields/belongs_to/_index.html.erb +3 -2
- data/app/views/madmin/fields/belongs_to/_show.html.erb +3 -2
- data/app/views/madmin/fields/date/_form.html.erb +1 -1
- data/app/views/madmin/fields/date_time/_form.html.erb +1 -1
- data/app/views/madmin/fields/decimal/_form.html.erb +2 -0
- data/app/views/madmin/fields/decimal/_index.html.erb +1 -0
- data/app/views/madmin/fields/decimal/_show.html.erb +1 -0
- data/app/views/madmin/fields/enum/_form.html.erb +1 -2
- data/app/views/madmin/fields/float/_form.html.erb +1 -1
- data/app/views/madmin/fields/has_many/_form.html.erb +1 -1
- data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -1
- data/app/views/madmin/fields/rich_text/_form.html.erb +2 -2
- data/lib/generators/madmin/install/install_generator.rb +8 -1
- data/lib/generators/madmin/install/templates/controller.rb.tt +22 -0
- data/lib/generators/madmin/views/edit_generator.rb +16 -0
- data/lib/generators/madmin/views/form_generator.rb +15 -0
- data/lib/generators/madmin/views/index_generator.rb +15 -0
- data/lib/generators/madmin/views/layout_generator.rb +21 -0
- data/lib/generators/madmin/views/navigation_generator.rb +15 -0
- data/lib/generators/madmin/views/new_generator.rb +16 -0
- data/lib/generators/madmin/views/show_generator.rb +15 -0
- data/lib/generators/madmin/views/views_generator.rb +15 -0
- data/lib/madmin.rb +1 -0
- data/lib/madmin/field.rb +7 -2
- data/lib/madmin/fields/decimal.rb +6 -0
- data/lib/madmin/fields/enum.rb +3 -0
- data/lib/madmin/namespace.rb +35 -0
- data/lib/madmin/resource.rb +56 -5
- data/lib/madmin/version.rb +1 -1
- data/lib/madmin/view_generator.rb +42 -0
- metadata +23 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19d2f645bfcae060a5a925b945892a2a196790a2d6c3b296ec0fe5118aeaf186
|
4
|
+
data.tar.gz: 4310e5b0fb00744f6098032799d6df7368890b736382a9bad466d328662f4da4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4d157858da05695020064ef9aa636079298cdc7bb1937bc3a4cb13faf71087d31ac0df3d1f3027414112aae61e97f9bfd099a1cf8bbf6bf8380532e654fe844
|
7
|
+
data.tar.gz: 2969bdf7c7e419290cff1db31f1d22befdb2eb7b0591cc60a00a328dd7e024991825547cae8404a98abdfd309c3308bc7c46332bf154fd6765f48372785baddd
|
data/README.md
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
# Madmin
|
2
2
|
|
3
|
-
### A robust
|
3
|
+
### 🛠 A robust Admin Interface for Ruby on Rails apps
|
4
4
|
|
5
5
|
[](https://github.com/excid3/madmin/actions) [](https://badge.fury.io/rb/madmin)
|
6
6
|
|
7
|
-
|
8
|
-
|
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,67 @@ Then run the madmin generator:
|
|
20
23
|
rails g madmin:install
|
21
24
|
```
|
22
25
|
|
23
|
-
|
24
|
-
|
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
|
+
## Configuring Views
|
41
|
+
|
42
|
+
The views packaged within the gem are a great starting point, but inevitably people will need to be able to customize those views.
|
43
|
+
|
44
|
+
You can use the included generator to create the appropriate view files, which can then be customized.
|
45
|
+
|
46
|
+
For example, running the following will copy over all of the views into your application that will be used for every resource:
|
47
|
+
```bash
|
48
|
+
rails generate madmin:views
|
49
|
+
```
|
50
|
+
|
51
|
+
The view files that are copied over in this case includes all of the standard Rails action views (index, new, edit, show, and _form), as well as:
|
52
|
+
* `application.html.erb` (layout file)
|
53
|
+
* `_javascript.html.erb` (default JavaScript setup)
|
54
|
+
* `_navigation.html.erb` (renders the navigation/sidebar menu)
|
55
|
+
|
56
|
+
As with the other views, you can specifically run the views generator for only the navigation or application layout views:
|
57
|
+
```bash
|
58
|
+
rails g madmin:views:navigation
|
59
|
+
# -> app/views/madmin/_navigation.html.erb
|
60
|
+
|
61
|
+
rails g madmin:views:layout # Note the layout generator includes the layout, javascript, and navigation files.
|
62
|
+
# -> app/views/madmin/application.html.erb
|
63
|
+
# -> app/views/madmin/_javascript.html.erb
|
64
|
+
# -> app/views/madmin/_navigation.html.erb
|
65
|
+
```
|
66
|
+
|
67
|
+
If you only need to customize specific views, you can restrict which views are copied by the generator:
|
68
|
+
```bash
|
69
|
+
rails g madmin:views:index
|
70
|
+
# -> app/views/madmin/application/index.html.erb
|
71
|
+
```
|
72
|
+
|
73
|
+
You can also scope the copied view(s) to a specific Resource/Model:
|
74
|
+
```bash
|
75
|
+
rails generate madmin:views:index Book
|
76
|
+
# -> app/views/madmin/books/index.html.erb
|
77
|
+
```
|
78
|
+
|
79
|
+
## Authentication
|
80
|
+
|
81
|
+
You can use a couple of strategies to authenticate users who are trying to
|
82
|
+
access your madmin panel: [Authentication Docs](docs/authentication.md)
|
83
|
+
|
84
|
+
## 🙏 Contributing
|
85
|
+
|
86
|
+
This project uses Standard for formatting Ruby code. Please make sure to run standardrb before submitting pull requests.
|
25
87
|
|
26
|
-
## License
|
88
|
+
## 📝 License
|
27
89
|
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"
|
@@ -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(
|
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://unpkg.com/flatpickr/dist/flatpickr.min.css", "data-turbo-track": "reload" %>
|
2
|
+
<%= stylesheet_link_tag "https://unpkg.com/trix/dist/trix.css", "data-turbo-track": "reload" %>
|
3
|
+
<%= stylesheet_link_tag "https://unpkg.com/slim-select@1.27.0/dist/slimselect.min.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
|
+
if (!window._rails_loaded) { 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
|
-
<
|
2
|
-
|
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,3 @@
|
|
1
|
-
<% object = field.value(record) %>
|
2
|
-
<%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
|
1
|
+
<% if (object = field.value(record)) %>
|
2
|
+
<%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
|
3
|
+
<% end %>
|
@@ -1,2 +1,3 @@
|
|
1
|
-
<% object = field.value(record) %>
|
2
|
-
<%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
|
1
|
+
<% if (object = field.value(record)) %>
|
2
|
+
<%= link_to Madmin.resource_for(object).display_name(object), Madmin.resource_for(object).show_path(object) %>
|
3
|
+
<% end %>
|
@@ -1,2 +1,2 @@
|
|
1
1
|
<%= form.label field.attribute_name, class: "inline-block w-32 flex-shrink-0" %>
|
2
|
-
<%= form.
|
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.
|
2
|
+
<%= form.text_field field.attribute_name, data: { controller: "flatpickr", flatpickr_enable_time: true } %>
|
@@ -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 %>
|
@@ -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
|
@@ -29,9 +35,10 @@ module Madmin
|
|
29
35
|
|
30
36
|
private
|
31
37
|
|
38
|
+
# Skip Abstract classes, ActiveRecord::Base, and auto-generated HABTM models
|
32
39
|
def generateable_models
|
33
40
|
active_record_models.reject do |model|
|
34
|
-
model.abstract_class? || model == ActiveRecord::Base
|
41
|
+
model.abstract_class? || model == ActiveRecord::Base || model.name.start_with?("HABTM_")
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
@@ -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
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class EditGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_edit
|
10
|
+
copy_resource_template("edit")
|
11
|
+
copy_resource_template("_form")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class FormGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_form
|
10
|
+
copy_resource_template("_form")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class IndexGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_template
|
10
|
+
copy_resource_template("index")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class LayoutGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_template
|
10
|
+
copy_file(
|
11
|
+
"../../layouts/madmin/application.html.erb",
|
12
|
+
"app/views/layouts/madmin/application.html.erb"
|
13
|
+
)
|
14
|
+
|
15
|
+
call_generator("madmin:views:navigation")
|
16
|
+
copy_resource_template("_javascript")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class NavigationGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_navigation
|
10
|
+
copy_resource_template("_navigation")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class NewGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_new
|
10
|
+
copy_resource_template("new")
|
11
|
+
copy_resource_template("_form")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
module Views
|
6
|
+
class ShowGenerator < Madmin::ViewGenerator
|
7
|
+
source_root template_source_path
|
8
|
+
|
9
|
+
def copy_template
|
10
|
+
copy_resource_template("show")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "madmin/view_generator"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Madmin::ViewGenerator
|
6
|
+
def copy_templates
|
7
|
+
view = "madmin:views:"
|
8
|
+
call_generator("#{view}index", resource_path, "--namespace", namespace)
|
9
|
+
call_generator("#{view}show", resource_path, "--namespace", namespace)
|
10
|
+
call_generator("#{view}new", resource_path, "--namespace", namespace)
|
11
|
+
call_generator("#{view}edit", resource_path, "--namespace", namespace)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
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
|
data/lib/madmin/fields/enum.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Madmin
|
2
|
+
class Namespace
|
3
|
+
def initialize(namespace)
|
4
|
+
@namespace = namespace
|
5
|
+
end
|
6
|
+
|
7
|
+
def resources
|
8
|
+
@resources ||= routes.map(&:first).uniq.map { |path|
|
9
|
+
Resource.new(namespace, path)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def routes
|
14
|
+
@routes ||= all_routes.select { |controller, _action|
|
15
|
+
controller.starts_with?("#{namespace}/")
|
16
|
+
}.map { |controller, action|
|
17
|
+
[controller.gsub(/^#{namespace}\//, ""), action]
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def resources_with_index_route
|
22
|
+
routes.select { |_resource, route| route == "index" }.map(&:first).uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :namespace
|
28
|
+
|
29
|
+
def all_routes
|
30
|
+
Rails.application.routes.routes.map do |route|
|
31
|
+
route.defaults.values_at(:controller, :action).map(&:to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/madmin/resource.rb
CHANGED
@@ -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
|
-
|
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,13 +128,27 @@ 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)
|
97
143
|
name_string = name.to_s
|
98
144
|
|
99
145
|
if model.attribute_types.include?(name_string)
|
100
|
-
model.attribute_types[name_string]
|
146
|
+
column_type = model.attribute_types[name_string]
|
147
|
+
if column_type.is_a? ActiveRecord::Enum::EnumType
|
148
|
+
:enum
|
149
|
+
else
|
150
|
+
column_type.type || :string
|
151
|
+
end
|
101
152
|
elsif (association = model.reflect_on_association(name))
|
102
153
|
type_for_association(association)
|
103
154
|
elsif model.reflect_on_association(:"rich_text_#{name_string}")
|
data/lib/madmin/version.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "madmin/generator_helpers"
|
3
|
+
require "madmin/namespace"
|
4
|
+
|
5
|
+
module Madmin
|
6
|
+
class ViewGenerator < Rails::Generators::Base
|
7
|
+
include Madmin::GeneratorHelpers
|
8
|
+
class_option :namespace, type: :string, default: "madmin"
|
9
|
+
|
10
|
+
def self.template_source_path
|
11
|
+
File.expand_path(
|
12
|
+
"../../../app/views/madmin/application",
|
13
|
+
__FILE__
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def namespace
|
20
|
+
options[:namespace]
|
21
|
+
end
|
22
|
+
|
23
|
+
def copy_resource_template(template_name)
|
24
|
+
template_file = "#{template_name}.html.erb"
|
25
|
+
|
26
|
+
copy_file(
|
27
|
+
template_file,
|
28
|
+
"app/views/#{namespace}/#{resource_path}/#{template_file}"
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource_path
|
33
|
+
args.first.try(:underscore).try(:pluralize) || BaseResourcePath.new
|
34
|
+
end
|
35
|
+
|
36
|
+
class BaseResourcePath
|
37
|
+
def to_s
|
38
|
+
"application"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
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.
|
4
|
+
version: 1.0.2
|
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-
|
12
|
+
date: 2021-03-04 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/
|
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,9 +127,18 @@ 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
|
134
|
+
- lib/generators/madmin/views/edit_generator.rb
|
135
|
+
- lib/generators/madmin/views/form_generator.rb
|
136
|
+
- lib/generators/madmin/views/index_generator.rb
|
137
|
+
- lib/generators/madmin/views/layout_generator.rb
|
138
|
+
- lib/generators/madmin/views/navigation_generator.rb
|
139
|
+
- lib/generators/madmin/views/new_generator.rb
|
140
|
+
- lib/generators/madmin/views/show_generator.rb
|
141
|
+
- lib/generators/madmin/views/views_generator.rb
|
143
142
|
- lib/madmin.rb
|
144
143
|
- lib/madmin/engine.rb
|
145
144
|
- lib/madmin/field.rb
|
@@ -149,6 +148,7 @@ files:
|
|
149
148
|
- lib/madmin/fields/boolean.rb
|
150
149
|
- lib/madmin/fields/date.rb
|
151
150
|
- lib/madmin/fields/date_time.rb
|
151
|
+
- lib/madmin/fields/decimal.rb
|
152
152
|
- lib/madmin/fields/enum.rb
|
153
153
|
- lib/madmin/fields/float.rb
|
154
154
|
- lib/madmin/fields/has_many.rb
|
@@ -161,14 +161,16 @@ files:
|
|
161
161
|
- lib/madmin/fields/text.rb
|
162
162
|
- lib/madmin/fields/time.rb
|
163
163
|
- lib/madmin/generator_helpers.rb
|
164
|
+
- lib/madmin/namespace.rb
|
164
165
|
- lib/madmin/resource.rb
|
165
166
|
- lib/madmin/version.rb
|
167
|
+
- lib/madmin/view_generator.rb
|
166
168
|
- lib/tasks/madmin_tasks.rake
|
167
169
|
homepage: https://github.com/excid3/madmin
|
168
170
|
licenses:
|
169
171
|
- MIT
|
170
172
|
metadata: {}
|
171
|
-
post_install_message:
|
173
|
+
post_install_message:
|
172
174
|
rdoc_options: []
|
173
175
|
require_paths:
|
174
176
|
- lib
|
@@ -183,8 +185,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
185
|
- !ruby/object:Gem::Version
|
184
186
|
version: '0'
|
185
187
|
requirements: []
|
186
|
-
rubygems_version: 3.
|
187
|
-
signing_key:
|
188
|
+
rubygems_version: 3.2.3
|
189
|
+
signing_key:
|
188
190
|
specification_version: 4
|
189
191
|
summary: A modern admin for Ruby on Rails apps
|
190
192
|
test_files: []
|