adminable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +91 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/javascripts/adminable/application.js +18 -0
  6. data/app/assets/javascripts/adminable/scripts.js +20 -0
  7. data/app/assets/stylesheets/adminable/application.scss +3 -0
  8. data/app/controllers/adminable/application_controller.rb +7 -0
  9. data/app/controllers/adminable/resources_controller.rb +93 -0
  10. data/app/helpers/adminable/application_helper.rb +4 -0
  11. data/app/views/adminable/kaminari/_first_page.html.haml +2 -0
  12. data/app/views/adminable/kaminari/_last_page.html.haml +2 -0
  13. data/app/views/adminable/kaminari/_next_page.html.haml +2 -0
  14. data/app/views/adminable/kaminari/_page.html.haml +6 -0
  15. data/app/views/adminable/kaminari/_paginator.html.haml +10 -0
  16. data/app/views/adminable/kaminari/_prev_page.html.haml +2 -0
  17. data/app/views/adminable/resources/_form.html.haml +14 -0
  18. data/app/views/adminable/resources/_search.html.haml +9 -0
  19. data/app/views/adminable/resources/edit.html.haml +5 -0
  20. data/app/views/adminable/resources/form/_belongs_to.html.haml +3 -0
  21. data/app/views/adminable/resources/form/_boolean.html.haml +3 -0
  22. data/app/views/adminable/resources/form/_datetime.html.haml +2 -0
  23. data/app/views/adminable/resources/form/_decimal.html.haml +2 -0
  24. data/app/views/adminable/resources/form/_float.html.haml +2 -0
  25. data/app/views/adminable/resources/form/_has_many.html.haml +9 -0
  26. data/app/views/adminable/resources/form/_integer.html.haml +2 -0
  27. data/app/views/adminable/resources/form/_string.html.haml +2 -0
  28. data/app/views/adminable/resources/form/_text.html.haml +2 -0
  29. data/app/views/adminable/resources/index.html.haml +35 -0
  30. data/app/views/adminable/resources/index/_belongs_to.html.haml +5 -0
  31. data/app/views/adminable/resources/index/_boolean.html.haml +2 -0
  32. data/app/views/adminable/resources/index/_datetime.html.haml +2 -0
  33. data/app/views/adminable/resources/index/_decimal.html.haml +1 -0
  34. data/app/views/adminable/resources/index/_float.html.haml +1 -0
  35. data/app/views/adminable/resources/index/_has_many.html.haml +3 -0
  36. data/app/views/adminable/resources/index/_integer.html.haml +1 -0
  37. data/app/views/adminable/resources/index/_string.html.haml +1 -0
  38. data/app/views/adminable/resources/index/_text.html.haml +1 -0
  39. data/app/views/adminable/resources/new.html.haml +5 -0
  40. data/app/views/adminable/shared/_alert.html.haml +4 -0
  41. data/app/views/adminable/shared/_label.html.haml +5 -0
  42. data/app/views/layouts/adminable/application.html.haml +40 -0
  43. data/config/initializers/haml.rb +3 -0
  44. data/config/locales/adminable.en.yml +18 -0
  45. data/config/routes.rb +7 -0
  46. data/lib/adminable.rb +33 -0
  47. data/lib/adminable/attributes/association.rb +21 -0
  48. data/lib/adminable/attributes/base.rb +42 -0
  49. data/lib/adminable/attributes/collection.rb +77 -0
  50. data/lib/adminable/attributes/types/belongs_to.rb +13 -0
  51. data/lib/adminable/attributes/types/boolean.rb +8 -0
  52. data/lib/adminable/attributes/types/datetime.rb +8 -0
  53. data/lib/adminable/attributes/types/decimal.rb +8 -0
  54. data/lib/adminable/attributes/types/float.rb +8 -0
  55. data/lib/adminable/attributes/types/has_many.rb +21 -0
  56. data/lib/adminable/attributes/types/integer.rb +8 -0
  57. data/lib/adminable/attributes/types/string.rb +8 -0
  58. data/lib/adminable/attributes/types/text.rb +8 -0
  59. data/lib/adminable/configuration.rb +19 -0
  60. data/lib/adminable/engine.rb +9 -0
  61. data/lib/adminable/extensions/devise.rb +24 -0
  62. data/lib/adminable/resource.rb +37 -0
  63. data/lib/adminable/version.rb +3 -0
  64. data/lib/generators/cms/resource/templates/resource_controller.rb.erb +2 -0
  65. data/lib/generators/cms/resource_generator.rb +28 -0
  66. metadata +381 -0
@@ -0,0 +1,5 @@
1
+ - if value.present?
2
+ - if attribute.association.klass.exists?(value)
3
+ = link_to "##{ value }", edit_polymorphic_path(attribute.association.klass.find_by(id: value))
4
+ - else
5
+ = "##{ value }"
@@ -0,0 +1,2 @@
1
+ - if !!(value)
2
+ %i.fa.fa-check
@@ -0,0 +1,2 @@
1
+ - if value
2
+ = l value, format: '%H:%M:%S, %-d %b %Y'
@@ -0,0 +1,3 @@
1
+ - if entry
2
+ - entry.send(attribute.name).each do |resource|
3
+ = link_to "##{ resource.id }", edit_polymorphic_path(resource)
@@ -0,0 +1 @@
1
+ = strip_tags(value.truncate(100)).squish
@@ -0,0 +1,5 @@
1
+ .row
2
+ .col-md-8.col-md-offset-2
3
+ %h1.m-b-3
4
+ = t('adminable.titles.new', resource: @resource.model.model_name.human)
5
+ = render 'form'
@@ -0,0 +1,4 @@
1
+ .alert.alert-dismissible.fade.in.m-b-1{ :class => "alert-#{ type }" }
2
+ %button.close{ 'aria-label' => 'Close', 'data-dismiss' => :alert, :type => :button }
3
+ %span{ 'aria-hidden' => true } ×
4
+ = message
@@ -0,0 +1,5 @@
1
+ = label_tag attribute.name do
2
+ = @resource.model.human_attribute_name(attribute.name)
3
+ - if attribute.required?
4
+ %i.text-muted
5
+ (required)
@@ -0,0 +1,40 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Adminable
5
+ %link{ :href => 'https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css', :rel => 'stylesheet' }/
6
+ %link{ :href => '//oss.maxcdn.com/clusterize.js/0.16.0/clusterize.css', :rel => 'stylesheet' }/
7
+ %script{ :src => '//oss.maxcdn.com/clusterize.js/0.16.0/clusterize.min.js' }
8
+ %script{ :src => '//cdn.tinymce.com/4/tinymce.min.js' }
9
+ %meta{ :content => 'width=device-width, initial-scale=1, shrink-to-fit=no', :name => 'viewport' }/
10
+ %meta{ :content => 'ie=edge', 'http-equiv' => 'x-ua-compatible' }/
11
+ = stylesheet_link_tag 'adminable/application', media: 'all'
12
+ = javascript_include_tag 'adminable/application'
13
+ = csrf_meta_tags
14
+ %body
15
+ #collapsing-nav.collapse.p-y-1
16
+ - Adminable::Configuration.resources.each do |resource|
17
+ = link_to resource.model.model_name.human.pluralize,
18
+ polymorphic_path(resource.route), class: 'btn btn-link btn-block'
19
+ .navbar.navbar-full.navbar-dark.bg-primary.m-b-3
20
+ .hidden-md-up
21
+ %button.navbar-toggler{ 'data-target' => '#collapsing-nav', 'data-toggle' => :collapse, :type => :button }
22
+ \☰
23
+ .container.hidden-sm-down
24
+ %ul.nav.navbar-nav
25
+ %li.nav-item
26
+ = link_to main_app.root_path, class: 'nav-link' do
27
+ %i.fa.fa-home
28
+ - Adminable::Configuration.resources.each do |resource|
29
+ %li.nav-item{ :class => ('active' if current_page?(File.join('/adminable/', resource.name))) }
30
+ = link_to resource.model.model_name.human.pluralize,
31
+ polymorphic_path(resource.route), class: 'nav-link'
32
+ .container.p-b-3
33
+ - if flash[:alert] || notice.present?
34
+ .p-b-2
35
+ - if flash[:alert]
36
+ - flash[:alert].each do |alert|
37
+ = render 'adminable/shared/alert', message: alert, type: 'danger'
38
+ - if notice.present?
39
+ = render 'adminable/shared/alert', message: notice, type: 'success'
40
+ = yield
@@ -0,0 +1,3 @@
1
+ require 'haml/template'
2
+
3
+ Haml::Template.options[:ugly] = true
@@ -0,0 +1,18 @@
1
+ ---
2
+ en:
3
+ adminable:
4
+ ui:
5
+ confirm: Are you sure?
6
+ not_selected: Not selected
7
+ buttons:
8
+ submit: Submit
9
+ back: Back
10
+ edit: Edit
11
+ new: New %{resource}
12
+ titles:
13
+ edit: Edit %{resource}
14
+ new: New %{resource}
15
+ resources:
16
+ created: "%{resource} has been successfully created."
17
+ updated: "%{resource} has been successfully updated."
18
+ deleted: "%{resource} has been successfully deleted."
@@ -0,0 +1,7 @@
1
+ Adminable::Engine.routes.draw do
2
+ Adminable::Configuration.resources.each do |r|
3
+ resources r.route, except: :show, path: r.name, controller: r.name
4
+ end
5
+
6
+ root 'application#welcome'
7
+ end
@@ -0,0 +1,33 @@
1
+ require 'adminable/engine'
2
+ require 'adminable/configuration'
3
+
4
+ require 'adminable/extensions/devise'
5
+
6
+ require 'adminable/resource'
7
+
8
+ require 'adminable/attributes/collection'
9
+ require 'adminable/attributes/association'
10
+
11
+ require 'adminable/attributes/base'
12
+
13
+ require 'adminable/attributes/types/belongs_to'
14
+ require 'adminable/attributes/types/boolean'
15
+ require 'adminable/attributes/types/datetime'
16
+ require 'adminable/attributes/types/decimal'
17
+ require 'adminable/attributes/types/float'
18
+ require 'adminable/attributes/types/has_many'
19
+ require 'adminable/attributes/types/integer'
20
+ require 'adminable/attributes/types/string'
21
+ require 'adminable/attributes/types/text'
22
+
23
+ require 'haml-rails'
24
+ require 'sass-rails'
25
+ require 'coffee-rails'
26
+ require 'jquery-rails'
27
+ require 'bootstrap'
28
+ require 'rails-assets-tether'
29
+ require 'babosa'
30
+ require 'kaminari'
31
+
32
+ module Adminable
33
+ end
@@ -0,0 +1,21 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Association
4
+ attr_reader :options_for_select, :association
5
+
6
+ def options_for_select(entry)
7
+ @association.klass.all.reject { |e| e == entry }.collect do |e|
8
+ [association_option_name(e), e.id]
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def association_option_name(entry)
15
+ %i(email login name title id).each do |a|
16
+ return entry.try(a) unless entry.try(a).nil?
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ module Adminable
2
+ module Attributes
3
+ class Base
4
+ attr_accessor :name, :required, :show, :center, :wysiwyg
5
+ attr_reader :key, :ransack_name
6
+
7
+ def initialize(name, options = {})
8
+ raise 'Base class cannot be initialized' if self.class == Base
9
+
10
+ @name = name
11
+ @key = options[:key] || @name
12
+ @ransack_name = "#{@name}_cont"
13
+ @association = options[:association]
14
+ @required = options[:required] || false
15
+ @show = true
16
+ @center = %w(integer boolean float decimal).include?(type)
17
+ @wysiwyg = %w(text).include?(type)
18
+ end
19
+
20
+ alias required? required
21
+ alias show? show
22
+ alias center? center
23
+ alias wysiwyg? wysiwyg
24
+
25
+ def type
26
+ self.class.name.demodulize.underscore
27
+ end
28
+
29
+ def strong_parameter
30
+ key
31
+ end
32
+
33
+ def index_partial_path
34
+ "index/#{type}"
35
+ end
36
+
37
+ def form_partial_path
38
+ "adminable/resources/form/#{type}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ module Adminable
2
+ module Attributes
3
+ class Collection
4
+ attr_reader :model
5
+ attr_writer :index, :form
6
+
7
+ def initialize(model)
8
+ @model = model
9
+ end
10
+
11
+ def index
12
+ @index ||= all.except(:created_at, :updated_at)
13
+ end
14
+
15
+ def form
16
+ @form ||= all.except(:id, :created_at, :updated_at)
17
+ end
18
+
19
+ def ransack
20
+ @ransack ||= columns.except(:id, :created_at, :updated_at)
21
+ .select { |k, v| %w(string text).include?(v.type) }
22
+ end
23
+
24
+ def all
25
+ [columns, belongs_to, has_many].inject(&:merge)
26
+ end
27
+
28
+ def association
29
+ [belongs_to, has_many].inject(&:merge)
30
+ end
31
+
32
+ def columns
33
+ @columns ||= {}.tap do |attribute|
34
+ @model.columns.reject { |a| a.name.match(/_id$/) }.each do |column|
35
+ attribute[column.name] = "adminable/attributes/types/#{column.type}"
36
+ .classify.constantize.new(
37
+ column.name,
38
+ required: attribute_required?(column.name)
39
+ )
40
+ end
41
+ end.symbolize_keys
42
+ end
43
+
44
+ def belongs_to
45
+ @belongs_to ||= {}.tap do |attribute|
46
+ @model.reflect_on_all_associations(:belongs_to).each do |association|
47
+ attribute[association.name] = Adminable::Attributes::Types::BelongsTo.new(
48
+ association.name,
49
+ required: attribute_required?(association.name),
50
+ association: association
51
+ )
52
+ end
53
+ end.symbolize_keys
54
+ end
55
+
56
+ def has_many
57
+ @has_many ||= {}.tap do |attribute|
58
+ @model.reflect_on_all_associations(:has_many).each do |association|
59
+ attribute[association.name] = Adminable::Attributes::Types::HasMany.new(
60
+ association.name,
61
+ required: attribute_required?(association.name),
62
+ association: association
63
+ )
64
+ end
65
+ end.symbolize_keys
66
+ end
67
+
68
+ private
69
+
70
+ def attribute_required?(name)
71
+ @model.validators_on(name).any? do |validator|
72
+ validator.class == ActiveRecord::Validations::PresenceValidator
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,13 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class BelongsTo < Base
5
+ include Adminable::Attributes::Association
6
+
7
+ def key
8
+ @association.foreign_key
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Boolean < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Datetime < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Decimal < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Float < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class HasMany < Base
5
+ include Adminable::Attributes::Association
6
+
7
+ def key
8
+ @key = "#{@name.to_s.singularize}_ids"
9
+ end
10
+
11
+ def strong_parameter
12
+ { key => [] }
13
+ end
14
+
15
+ def show?
16
+ @association.klass.any?
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Integer < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class String < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Adminable
2
+ module Attributes
3
+ module Types
4
+ class Text < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ module Adminable
2
+ module Configuration
3
+ def self.resources
4
+ @resources ||= resources_paths.map do |resource_path|
5
+ Adminable::Resource.new(
6
+ resource_path.to_s.split('adminable/').last.sub(/_controller\.rb$/, '')
7
+ )
8
+ end
9
+ end
10
+
11
+ def self.find_resource(name)
12
+ resources.find { |resource| resource.name == name }
13
+ end
14
+
15
+ def self.resources_paths
16
+ Dir[Rails.root.join('app/controllers/adminable/**/*_controller.rb')]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Adminable
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Adminable
4
+
5
+ ActionDispatch::Reloader.to_prepare do
6
+ require_dependency Adminable::Engine.root.join('app/controllers/adminable/resources_controller.rb')
7
+ end
8
+ end
9
+ end