madmin 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +102 -0
- data/Rakefile +32 -0
- data/app/assets/config/madmin_manifest.js +2 -0
- data/app/assets/javascripts/madmin/application.js +15 -0
- data/app/assets/javascripts/madmin/dashboard.js +2 -0
- data/app/assets/javascripts/madmin/resources.js +36 -0
- data/app/assets/stylesheets/madmin/application.css +22 -0
- data/app/assets/stylesheets/madmin/dashboard.css +4 -0
- data/app/assets/stylesheets/madmin/resources.css +4 -0
- data/app/controllers/madmin/application_controller.rb +16 -0
- data/app/controllers/madmin/base_controller.rb +16 -0
- data/app/controllers/madmin/dashboard_controller.rb +8 -0
- data/app/controllers/madmin/resources_controller.rb +97 -0
- data/app/decorators/madmin/resource_decorator.rb +16 -0
- data/app/helpers/madmin/application_helper.rb +15 -0
- data/app/helpers/madmin/fields/polymorphic_helper.rb +25 -0
- data/app/jobs/madmin/application_job.rb +4 -0
- data/app/mailers/madmin/application_mailer.rb +6 -0
- data/app/models/madmin/application_record.rb +5 -0
- data/app/views/application/_navigation.html.erb +17 -0
- data/app/views/layouts/madmin/application.html.erb +30 -0
- data/app/views/madmin/dashboard/index.html.erb +6 -0
- data/app/views/madmin/fields/belongs_to/_form.html.erb +14 -0
- data/app/views/madmin/fields/belongs_to/_index.html.erb +7 -0
- data/app/views/madmin/fields/belongs_to/_show.html.erb +8 -0
- data/app/views/madmin/fields/check_box/_form.html.erb +4 -0
- data/app/views/madmin/fields/check_box/_index.html.erb +1 -0
- data/app/views/madmin/fields/check_box/_show.html.erb +8 -0
- data/app/views/madmin/fields/email/_form.html.erb +4 -0
- data/app/views/madmin/fields/email/_index.html.erb +1 -0
- data/app/views/madmin/fields/email/_show.html.erb +8 -0
- data/app/views/madmin/fields/has_many/_form.html.erb +0 -0
- data/app/views/madmin/fields/has_many/_show.html.erb +15 -0
- data/app/views/madmin/fields/has_one/_form.html.erb +0 -0
- data/app/views/madmin/fields/has_one/_show.html.erb +12 -0
- data/app/views/madmin/fields/number/_form.html.erb +4 -0
- data/app/views/madmin/fields/number/_index.html.erb +1 -0
- data/app/views/madmin/fields/number/_show.html.erb +8 -0
- data/app/views/madmin/fields/password/_form.html.erb +4 -0
- data/app/views/madmin/fields/password/_index.html.erb +1 -0
- data/app/views/madmin/fields/password/_show.html.erb +8 -0
- data/app/views/madmin/fields/polymorphic/_form.html.erb +32 -0
- data/app/views/madmin/fields/polymorphic/_index.html.erb +1 -0
- data/app/views/madmin/fields/polymorphic/_show.html.erb +14 -0
- data/app/views/madmin/fields/select/_form.html.erb +4 -0
- data/app/views/madmin/fields/select/_index.html.erb +1 -0
- data/app/views/madmin/fields/select/_show.html.erb +8 -0
- data/app/views/madmin/fields/text/_form.html.erb +4 -0
- data/app/views/madmin/fields/text/_index.html.erb +1 -0
- data/app/views/madmin/fields/text/_show.html.erb +8 -0
- data/app/views/madmin/fields/text_area/_form.html.erb +4 -0
- data/app/views/madmin/fields/text_area/_index.html.erb +1 -0
- data/app/views/madmin/fields/text_area/_show.html.erb +8 -0
- data/app/views/madmin/resources/_form.html.erb +15 -0
- data/app/views/madmin/resources/_scopes.html.erb +10 -0
- data/app/views/madmin/resources/edit.html.erb +2 -0
- data/app/views/madmin/resources/index.html.erb +13 -0
- data/app/views/madmin/resources/index/_content.html.erb +33 -0
- data/app/views/madmin/resources/new.html.erb +2 -0
- data/app/views/madmin/resources/show.html.erb +10 -0
- data/config/routes.rb +11 -0
- data/lib/generators/madmin/controller/USAGE +8 -0
- data/lib/generators/madmin/controller/controller_generator.rb +10 -0
- data/lib/generators/madmin/install/install_generator.rb +31 -0
- data/lib/generators/madmin/page/USAGE +8 -0
- data/lib/generators/madmin/page/page_generator.rb +20 -0
- data/lib/generators/madmin/page/templates/template.html.erb +2 -0
- data/lib/generators/madmin/page/templates/template.rb.erb +10 -0
- data/lib/generators/madmin/resource/resource_generator.rb +76 -0
- data/lib/generators/madmin/resource/templates/resource.rb.erb +11 -0
- data/lib/generators/madmin/views/views_generator.rb +15 -0
- data/lib/madmin.rb +30 -0
- data/lib/madmin/engine.rb +9 -0
- data/lib/madmin/field.rb +64 -0
- data/lib/madmin/field/associatable.rb +58 -0
- data/lib/madmin/field/belongs_to.rb +9 -0
- data/lib/madmin/field/check_box.rb +8 -0
- data/lib/madmin/field/date_time.rb +8 -0
- data/lib/madmin/field/email.rb +8 -0
- data/lib/madmin/field/has_many.rb +9 -0
- data/lib/madmin/field/has_one.rb +9 -0
- data/lib/madmin/field/number.rb +8 -0
- data/lib/madmin/field/password.rb +8 -0
- data/lib/madmin/field/polymorphic.rb +57 -0
- data/lib/madmin/field/select.rb +13 -0
- data/lib/madmin/field/text.rb +8 -0
- data/lib/madmin/field/text_area.rb +8 -0
- data/lib/madmin/generator_helpers.rb +13 -0
- data/lib/madmin/resourceable.rb +72 -0
- data/lib/madmin/resourceable/class_methods.rb +152 -0
- data/lib/madmin/resources.rb +13 -0
- data/lib/madmin/version.rb +3 -0
- data/lib/tasks/madmin_tasks.rake +4 -0
- metadata +197 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
class Madmin::ControllerGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path("../../../../../", __FILE__)
|
3
|
+
|
4
|
+
def copy_controller
|
5
|
+
copy_file(
|
6
|
+
"app/controllers/madmin/#{file_name}_controller.rb",
|
7
|
+
"app/controllers/madmin/#{file_name}_controller.rb"
|
8
|
+
)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "madmin/generator_helpers"
|
3
|
+
|
4
|
+
module Madmin
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Madmin::GeneratorHelpers
|
8
|
+
|
9
|
+
def generate_resources
|
10
|
+
resources.each do |model|
|
11
|
+
call_generator "madmin:resource", model.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def install_route
|
16
|
+
inject_into_file(
|
17
|
+
Rails.root.join("config/routes.rb"),
|
18
|
+
after: "Rails.application.routes.draw do\n"
|
19
|
+
) { " namespace :madmin do\n end\n mount Madmin::Engine => \"/madmin\"\n" }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def resources
|
25
|
+
Rails.application.eager_load! unless Rails.application.config.cache_classes
|
26
|
+
|
27
|
+
ActiveRecord::Base.descendants.reject(&:abstract_class?)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Madmin::PageGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path("templates", __dir__)
|
3
|
+
|
4
|
+
def copy_template
|
5
|
+
template(
|
6
|
+
"template.rb.erb",
|
7
|
+
Rails.root.join("app/controllers/madmin/#{file_name}_controller.rb"),
|
8
|
+
)
|
9
|
+
|
10
|
+
template(
|
11
|
+
"template.html.erb",
|
12
|
+
Rails.root.join("app/views/madmin/#{file_name}/index.html.erb"),
|
13
|
+
)
|
14
|
+
|
15
|
+
inject_into_file(
|
16
|
+
Rails.root.join("config/routes.rb"),
|
17
|
+
after: "namespace :madmin do\n"
|
18
|
+
) { " get \"#{file_name}\", to: \"#{file_name}#index\"\n" }
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "rails/generators/named_base"
|
2
|
+
require "madmin/generator_helpers"
|
3
|
+
|
4
|
+
module Madmin
|
5
|
+
module Generators
|
6
|
+
class ResourceGenerator < Rails::Generators::NamedBase
|
7
|
+
ATTRIBUTE_TYPE_MAPPING = {
|
8
|
+
boolean: "Field::CheckBox",
|
9
|
+
date: "Field::DateTime",
|
10
|
+
datetime: "Field::DateTime",
|
11
|
+
enum: "Field::Text",
|
12
|
+
float: "Field::Number",
|
13
|
+
integer: "Field::Number",
|
14
|
+
time: "Field::DateTime",
|
15
|
+
text: "Field::TextArea",
|
16
|
+
string: "Field::Text",
|
17
|
+
}
|
18
|
+
|
19
|
+
source_root File.expand_path("../templates", __FILE__)
|
20
|
+
|
21
|
+
def create_resource_file
|
22
|
+
template(
|
23
|
+
"resource.rb.erb",
|
24
|
+
Rails.root.join("app/madmin/resources/#{file_name}.rb"),
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def attributes
|
31
|
+
klass.attribute_types.map { |name, attr|
|
32
|
+
# Skip attributes related to associations
|
33
|
+
next if ignored_attributes.include?(name)
|
34
|
+
|
35
|
+
[name, madmin_type_for_column(attr.type)]
|
36
|
+
}.compact
|
37
|
+
end
|
38
|
+
|
39
|
+
def associations
|
40
|
+
klass.reflections.map do |name, association|
|
41
|
+
if association.polymorphic?
|
42
|
+
[name, "Field::Polymorphic"]
|
43
|
+
elsif association.belongs_to?
|
44
|
+
[name, "Field::BelongsTo"]
|
45
|
+
elsif association.has_one?
|
46
|
+
[name, "Field::HasOne"]
|
47
|
+
else
|
48
|
+
[name, "Field::HasMany"]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def ignored_attributes
|
54
|
+
attrs = []
|
55
|
+
|
56
|
+
klass.reflections.map do |name, association|
|
57
|
+
if association.polymorphic?
|
58
|
+
attrs += [association.foreign_key, association.foreign_type]
|
59
|
+
elsif association.belongs_to?
|
60
|
+
attrs += [association.foreign_key]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
attrs
|
65
|
+
end
|
66
|
+
|
67
|
+
def klass
|
68
|
+
@klass ||= Object.const_get(class_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
def madmin_type_for_column(column_type)
|
72
|
+
ATTRIBUTE_TYPE_MAPPING[column_type]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
|
3
|
+
module Madmin
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Rails::Generators::Base
|
6
|
+
desc("Copies views for customizing Madmin's views")
|
7
|
+
|
8
|
+
source_root File.expand_path("../../../../..", __FILE__)
|
9
|
+
|
10
|
+
def copy_views
|
11
|
+
directory "app/views/madmin", "app/views/madmin"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/madmin.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "madmin/engine"
|
2
|
+
require "madmin/resourceable"
|
3
|
+
require "madmin/resources"
|
4
|
+
|
5
|
+
module Madmin
|
6
|
+
class NoResourcesError < StandardError; end
|
7
|
+
class ResourceNotFoundError < StandardError; end
|
8
|
+
class WrongArgumentError < StandardError; end
|
9
|
+
class UndefinedScopeError < StandardError; end
|
10
|
+
class ScopeWithArgumentsError < StandardError; end
|
11
|
+
|
12
|
+
autoload :Field, "madmin/field"
|
13
|
+
autoload :Resourceable, "madmin/resourceable"
|
14
|
+
|
15
|
+
class Field
|
16
|
+
autoload :Associatable, "madmin/field/associatable"
|
17
|
+
autoload :BelongsTo, "madmin/field/belongs_to"
|
18
|
+
autoload :CheckBox, "madmin/field/check_box"
|
19
|
+
autoload :DateTime, "madmin/field/date_time"
|
20
|
+
autoload :Email, "madmin/field/email"
|
21
|
+
autoload :HasMany, "madmin/field/has_many"
|
22
|
+
autoload :HasOne, "madmin/field/has_one"
|
23
|
+
autoload :Number, "madmin/field/number"
|
24
|
+
autoload :Password, "madmin/field/password"
|
25
|
+
autoload :Polymorphic, "madmin/field/polymorphic"
|
26
|
+
autoload :Select, "madmin/field/select"
|
27
|
+
autoload :TextArea, "madmin/field/text_area"
|
28
|
+
autoload :Text, "madmin/field/text"
|
29
|
+
end
|
30
|
+
end
|
data/lib/madmin/field.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Madmin
|
2
|
+
class Field
|
3
|
+
attr_reader :form
|
4
|
+
attr_reader :index
|
5
|
+
attr_reader :key
|
6
|
+
attr_reader :label
|
7
|
+
attr_reader :model
|
8
|
+
attr_reader :options
|
9
|
+
attr_reader :show
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@key = args[:key]
|
14
|
+
@options = args
|
15
|
+
@model = args[:model]
|
16
|
+
@label = option_or_default(:label, label_from_attribute(key))
|
17
|
+
@form = option_or_default(:form, false)
|
18
|
+
@index = option_or_default(:index, false)
|
19
|
+
@show = option_or_default(:show, true)
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Returns an array of key(s) to use in strong
|
24
|
+
# params for the resources controller.
|
25
|
+
def strong_params_keys
|
26
|
+
[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns the partial path for the field type
|
31
|
+
def to_partial_path
|
32
|
+
"madmin/fields/#{self.class.to_s.split("Madmin::Field::").last.underscore}"
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Returns the value for a given resource
|
37
|
+
def value_for(resource)
|
38
|
+
resource.send(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
##
|
44
|
+
# This method takes an attribute and converts it
|
45
|
+
# into a human readable format for form labels.
|
46
|
+
def label_from_attribute(attribute)
|
47
|
+
attribute.to_s.humanize
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# This method verifies options are present
|
52
|
+
# (as a hash).
|
53
|
+
def options?
|
54
|
+
options.is_a?(Hash)
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# This method extracts the many option checks
|
59
|
+
# performed when assigning field options.
|
60
|
+
def option_or_default(key, default)
|
61
|
+
options? ? options.fetch(key, default) : default
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Madmin
|
2
|
+
class Field
|
3
|
+
module Associatable
|
4
|
+
class << self
|
5
|
+
def included(_base)
|
6
|
+
attr_reader :association_class
|
7
|
+
attr_reader :association_display_value
|
8
|
+
attr_reader :association_foreign_key
|
9
|
+
attr_reader :association_scope
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(args)
|
14
|
+
super(args)
|
15
|
+
implement_association!
|
16
|
+
end
|
17
|
+
|
18
|
+
def association_collection
|
19
|
+
association_class.send(association_scope)
|
20
|
+
end
|
21
|
+
|
22
|
+
def association_id_for(resource)
|
23
|
+
value_for(resource).id
|
24
|
+
end
|
25
|
+
|
26
|
+
def association_id_or_blank_for(resource)
|
27
|
+
value_for(resource).try(:id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def association_param
|
31
|
+
ActiveModel::Naming.param_key(association_class)
|
32
|
+
end
|
33
|
+
|
34
|
+
def association_slug
|
35
|
+
Object.const_get("::Madmin::Resources::#{association_class}").new.slug
|
36
|
+
end
|
37
|
+
|
38
|
+
def association_value_for(resource)
|
39
|
+
value_for(resource).send(association_display_value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def strong_params_keys
|
43
|
+
[association_foreign_key]
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def implement_association!
|
49
|
+
association = model.reflect_on_all_associations.find { |assc| assc.name == key }
|
50
|
+
|
51
|
+
@association_class = association.klass
|
52
|
+
@association_display_value = option_or_default(:display_value, :name)
|
53
|
+
@association_foreign_key = association.foreign_key
|
54
|
+
@association_scope = :all
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|