aerogel-admin 1.4.4

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.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +13 -0
  6. data/Rakefile +1 -0
  7. data/aerogel-admin.gemspec +31 -0
  8. data/app/helpers/admin.rb +54 -0
  9. data/app/helpers/decorators.rb +29 -0
  10. data/app/helpers/icons.rb +11 -0
  11. data/app/helpers/table_builder.rb +8 -0
  12. data/app/helpers/tabs_builder.rb +7 -0
  13. data/app/routes/admin.rb +37 -0
  14. data/app/routes/users.rb +71 -0
  15. data/app/routes/users_access.rb +54 -0
  16. data/app/routes/users_roles.rb +53 -0
  17. data/assets/fonts/aerogel-icons.css +28 -0
  18. data/assets/fonts/aerogel-icons.eot +0 -0
  19. data/assets/fonts/aerogel-icons.svg +11 -0
  20. data/assets/fonts/aerogel-icons.ttf +0 -0
  21. data/assets/fonts/aerogel-icons.woff +0 -0
  22. data/assets/javascripts/.gitkeep +0 -0
  23. data/assets/javascripts/controllers/admin-modal.js.coffee +7 -0
  24. data/assets/javascripts/controllers/admin-modal/admin-modal-form-buttons.js.coffee +56 -0
  25. data/assets/javascripts/controllers/admin.js.coffee +13 -0
  26. data/assets/javascripts/controllers/admin/selectize-inputs.js.coffee +7 -0
  27. data/assets/javascripts/controllers/admin/top-menu-shadow.js.coffee +9 -0
  28. data/assets/javascripts/utils/ajax-spinner.js.coffee +26 -0
  29. data/assets/javascripts/utils/ajax-watcher.js.coffee +18 -0
  30. data/assets/javascripts/utils/bootstrap-modal-reload.js.coffee +8 -0
  31. data/assets/javascripts/utils/form-data-async.js.coffee +27 -0
  32. data/assets/javascripts/utils/i18n.js.coffee +27 -0
  33. data/assets/javascripts/utils/on-future-elements.js.coffee +15 -0
  34. data/assets/stylesheets/admin/bootstrap-settings.css.scss +33 -0
  35. data/assets/stylesheets/admin/global.css.scss +61 -0
  36. data/assets/stylesheets/admin/styles/ajax-indicator.css.scss +26 -0
  37. data/assets/stylesheets/admin/styles/bootstrap-modal.css.scss +24 -0
  38. data/assets/stylesheets/admin/styles/language-selector.css.scss +5 -0
  39. data/assets/stylesheets/admin/styles/page-header.css.scss +7 -0
  40. data/assets/stylesheets/admin/styles/sticky-footer-navbar.css.scss +34 -0
  41. data/assets/stylesheets/admin/styles/table.css.scss +3 -0
  42. data/assets/stylesheets/admin/styles/top-menu.css.scss +3 -0
  43. data/assets/stylesheets/admin/utils/center-absolutely.css.scss +5 -0
  44. data/assets/stylesheets/controllers/admin.css.scss +14 -0
  45. data/assets/vendor/bootstrap-datetimepicker.css.scss +1 -0
  46. data/assets/vendor/bootstrap-datetimepicker.js.coffee +1 -0
  47. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css +5 -0
  48. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.js +1 -0
  49. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.ru.js +163 -0
  50. data/assets/vendor/moment.js.coffee +1 -0
  51. data/assets/vendor/momentjs/moment-with-langs.min.js +9 -0
  52. data/assets/vendor/selectize.css.scss +2 -0
  53. data/assets/vendor/selectize.js.coffee +1 -0
  54. data/assets/vendor/selectize/selectize.bootstrap3.css +385 -0
  55. data/assets/vendor/selectize/selectize.css +311 -0
  56. data/assets/vendor/selectize/selectize.default.css +381 -0
  57. data/assets/vendor/selectize/selectize.js +3345 -0
  58. data/assets/vendor/smart-list-table.css.scss +42 -0
  59. data/assets/vendor/smart-list-table.js.coffee +1 -0
  60. data/assets/vendor/smart-list-table/smart-list-table-row.js.coffee +63 -0
  61. data/assets/vendor/smart-list-table/smart-list-table.css.scss +54 -0
  62. data/assets/vendor/smart-list-table/smart-list-table.js.coffee +133 -0
  63. data/assets/vendor/smart-tree-table.css.scss +42 -0
  64. data/assets/vendor/smart-tree-table.js.coffee +1 -0
  65. data/assets/vendor/smart-tree-table/smart-tree-table-drag-n-drop.js.coffee +190 -0
  66. data/assets/vendor/smart-tree-table/smart-tree-table-row.js.coffee +78 -0
  67. data/assets/vendor/smart-tree-table/smart-tree-table.css.scss +54 -0
  68. data/assets/vendor/smart-tree-table/smart-tree-table.js.coffee +267 -0
  69. data/assets/vendor/spin.js +353 -0
  70. data/config/README.md +3 -0
  71. data/config/development/.keep +0 -0
  72. data/config/production/.keep +0 -0
  73. data/db/model/README.md +1 -0
  74. data/db/model/admin/user_new_form.rb +40 -0
  75. data/db/model/user.rb +26 -0
  76. data/db/seed/01_admin_roles.seed +8 -0
  77. data/db/seed/02_admin_access.seed +24 -0
  78. data/db/seed/development/.keep +0 -0
  79. data/db/seed/development/20_users.seed +45 -0
  80. data/db/seed/development/admin_users.seed +38 -0
  81. data/db/seed/production/.keep +0 -0
  82. data/lib/aerogel/admin.rb +25 -0
  83. data/lib/aerogel/admin/core.rb +14 -0
  84. data/lib/aerogel/admin/menu.rb +38 -0
  85. data/lib/aerogel/admin/table_builder.rb +100 -0
  86. data/lib/aerogel/admin/tabs_builder.rb +69 -0
  87. data/lib/aerogel/admin/version.rb +5 -0
  88. data/locales/actions.en.yml +27 -0
  89. data/locales/actions.ru.yml +28 -0
  90. data/locales/admin.en.yml +14 -0
  91. data/locales/admin.ru.yml +14 -0
  92. data/locales/models.en.yml +8 -0
  93. data/locales/models.ru.yml +8 -0
  94. data/locales/views.en.yml +46 -0
  95. data/locales/views.ru.yml +46 -0
  96. data/public/README.md +1 -0
  97. data/rake/README.md +3 -0
  98. data/views/admin/index.html.erb +3 -0
  99. data/views/admin/table_builder/standard/_table_column.html.erb +3 -0
  100. data/views/admin/table_builder/standard/_table_row.html.erb +7 -0
  101. data/views/admin/table_builder/standard/table.html.erb +10 -0
  102. data/views/admin/tabs_builder/standard/_tab.html.erb +3 -0
  103. data/views/admin/tabs_builder/standard/tabs.html.erb +3 -0
  104. data/views/admin/users/_tabs.html.erb +8 -0
  105. data/views/admin/users/access/delete.html.erb +12 -0
  106. data/views/admin/users/access/edit.html.erb +9 -0
  107. data/views/admin/users/access/index.html.erb +23 -0
  108. data/views/admin/users/access/new.html.erb +9 -0
  109. data/views/admin/users/delete.html.erb +12 -0
  110. data/views/admin/users/edit.html.erb +46 -0
  111. data/views/admin/users/index.html.erb +31 -0
  112. data/views/admin/users/new.html.erb +11 -0
  113. data/views/admin/users/roles/delete.html.erb +12 -0
  114. data/views/admin/users/roles/edit.html.erb +9 -0
  115. data/views/admin/users/roles/index.html.erb +21 -0
  116. data/views/admin/users/roles/new.html.erb +7 -0
  117. data/views/form_builder/standard/field_multiselect.erb +14 -0
  118. data/views/form_builder/standard/field_select.erb +17 -0
  119. data/views/layouts/admin.html.erb +63 -0
  120. data/views/layouts/admin/_ajax_indicator.html.erb +4 -0
  121. data/views/layouts/admin/_alerts.html.erb +22 -0
  122. data/views/layouts/admin/_menu.html.erb +50 -0
  123. data/views/layouts/admin/_menu_item.html.erb +5 -0
  124. data/views/layouts/admin/_modals.html.erb +8 -0
  125. data/views/layouts/admin/modal.html.erb +38 -0
  126. metadata +280 -0
@@ -0,0 +1,3 @@
1
+ A place for your ```*.conf``` files.
2
+
3
+ Environment specific configs go into folders 'production' or 'development'.
File without changes
File without changes
@@ -0,0 +1 @@
1
+ A place for your models.
@@ -0,0 +1,40 @@
1
+ module Admin
2
+ class UserNewForm
3
+ include Model::NonPersistent
4
+
5
+ field :full_name, type: String
6
+ field :email, type: String
7
+ field :roles, type: Array, default: [:user]
8
+
9
+ validates_presence_of :full_name, :email, :roles
10
+ validates_format_of :email, with: /@/, message: :invalid_format
11
+
12
+ validate do |record|
13
+ # validate email
14
+ if User.elem_match( :authentications => { :provider => :password, :uid => record.email } ).count > 0
15
+ record.errors.add :email, :taken
16
+ elsif User.elem_match( :emails => { :email => record.email } ).count > 0
17
+ record.errors.add :email, :taken
18
+ end
19
+ # validate roles
20
+ if record.roles_changed?
21
+ unless Role.slugs.contains? record.roles
22
+ record.errors.add :roles, :invalid_roles
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ # accessors:
29
+ def roles=( value )
30
+ if value.is_a? Array
31
+ self[:roles] = value.map(&:to_sym)
32
+ elsif value.is_a? String
33
+ self[:roles] = value.split(",").map{|v| v.strip.to_sym}
34
+ else
35
+ raise ArgumentError.new "Invalid value of class #{value.class} passed to roles= setter"
36
+ end
37
+ end
38
+
39
+ end # class UserNewForm
40
+ end # module Admin
@@ -0,0 +1,26 @@
1
+ class User
2
+
3
+ # Creates a User from Admin::UserNewForm.
4
+ #
5
+ def self.create_from_admin_user_new_form( object )
6
+ raise "Cannot create User from #{object.class}" unless object.is_a? Admin::UserNewForm
7
+
8
+ tmp_password = self.generate_confirmation_token # generates random password
9
+ self.new(
10
+ full_name: object.full_name,
11
+ roles: object.roles,
12
+ emails: [{
13
+ email: object.email,
14
+ confirmed: false
15
+ }],
16
+ authentications: [{
17
+ provider: :password,
18
+ uid: object.email,
19
+ email_id: object.email,
20
+ password: tmp_password,
21
+ password_confirmation: tmp_password
22
+ }]
23
+ )
24
+ end
25
+
26
+ end # class User
@@ -0,0 +1,8 @@
1
+ model Role
2
+
3
+ find_by [:slug]
4
+
5
+ seeds [
6
+ { slug: :admin, name: "Administrator" }
7
+ ]
8
+
@@ -0,0 +1,24 @@
1
+ # A .seed file is a .conf file which stores
2
+ # database seed data and rules.
3
+ #
4
+
5
+ # Model class to use
6
+ #
7
+ # ! required
8
+ model Access
9
+
10
+ # Attribute name or a list of attribute names to be used as key(s)
11
+ # when finding objects
12
+ #
13
+ # Usage:
14
+ # find_by :name
15
+ # or
16
+ # find_by [:first_name, :last_name]
17
+ #
18
+ # ! required
19
+ find_by [:path, :role]
20
+
21
+ seeds [
22
+ { path: '/admin/**', access: :RW, role: :admin }
23
+ ]
24
+
File without changes
@@ -0,0 +1,45 @@
1
+ model User
2
+
3
+ find_by :full_name
4
+
5
+ # Values of attributes listed here will be set even
6
+ # if they exist already in the matching database object.
7
+ #
8
+ # Other attributes in the seed data will be treated as a default value,
9
+ # i.e. they will only be set if the matching database object does not exist
10
+ # or its corresponding attribute is not set.
11
+ #
12
+ # Usage:
13
+ # force :value
14
+ # or:
15
+ # force [:value, :description]
16
+ #
17
+ # default is: no fields are forced
18
+
19
+ #force :value
20
+
21
+ def create_test_user( name )
22
+ email = "#{name}@#{name}"
23
+ {
24
+ full_name: name,
25
+ roles: [:user],
26
+ emails:[{
27
+ email: email,
28
+ confirmed: true
29
+ }],
30
+ authentications:[{
31
+ provider: :password,
32
+ uid: email,
33
+ email_id: email,
34
+ password: 'test',
35
+ password_confirmation: 'test'
36
+ }]
37
+ }
38
+ end
39
+
40
+ user_seeds = []
41
+ 20.times do |i|
42
+ user_seeds << create_test_user( "user#{i}" )
43
+ end
44
+
45
+ seeds user_seeds
@@ -0,0 +1,38 @@
1
+ model User
2
+
3
+ find_by :full_name
4
+
5
+ # Values of attributes listed here will be set even
6
+ # if they exist already in the matching database object.
7
+ #
8
+ # Other attributes in the seed data will be treated as a default value,
9
+ # i.e. they will only be set if the matching database object does not exist
10
+ # or its corresponding attribute is not set.
11
+ #
12
+ # Usage:
13
+ # force :value
14
+ # or:
15
+ # force [:value, :description]
16
+ #
17
+ # default is: no fields are forced
18
+
19
+ #force :value
20
+
21
+ seeds [
22
+ {
23
+ full_name: 'admin',
24
+ roles: [:user, :admin],
25
+ emails:[{
26
+ email: 'admin@admin',
27
+ confirmed: true
28
+ }],
29
+ authentications:[{
30
+ provider: :password,
31
+ uid: 'admin@admin',
32
+ email_id: 'admin@admin',
33
+ password: 'admin',
34
+ password_confirmation: 'admin'
35
+ }]
36
+ }
37
+ ]
38
+
File without changes
@@ -0,0 +1,25 @@
1
+ require 'aerogel/core'
2
+ require 'aerogel/forms'
3
+ require 'aerogel/users'
4
+ require 'aerogel/media'
5
+ require 'aerogel/bootstrap'
6
+ require 'aerogel/font_awesome'
7
+
8
+ require "aerogel/admin/version"
9
+ require "aerogel/admin/core"
10
+ require "aerogel/admin/menu"
11
+ require "aerogel/admin/table_builder"
12
+ require "aerogel/admin/tabs_builder"
13
+
14
+ module Aerogel
15
+
16
+ # Finally, register module's root folder
17
+ register_path File.join( File.dirname(__FILE__), '..', '..' )
18
+
19
+ # configure module
20
+ on_load do |app|
21
+ app.register Aerogel::Admin
22
+ end
23
+
24
+ end
25
+
@@ -0,0 +1,14 @@
1
+ module Aerogel::Admin
2
+
3
+ def self.registered(app)
4
+ setup_reloader(app) if Aerogel.config.aerogel.reloader?
5
+
6
+ # module initialization
7
+ end
8
+
9
+ def self.setup_reloader(app)
10
+ app.use Aerogel::Reloader, :routes, before: true do
11
+ Aerogel::Admin::Menu.reset!
12
+ end
13
+ end
14
+ end # module Aerogel::Admin
@@ -0,0 +1,38 @@
1
+ module Aerogel::Admin
2
+ class Menu
3
+ attr_accessor :items
4
+ def initialize()
5
+ @items = []
6
+ end
7
+
8
+ def self.instance
9
+ @instance ||= self.new
10
+ end
11
+
12
+ def self.reset!
13
+ instance.items.clear
14
+ end
15
+
16
+ class Item
17
+ attr_accessor :url, :icon, :label, :priority
18
+ def initialize( url, opts = {} )
19
+ self.url = url
20
+ self.icon = opts[:icon]
21
+ self.label = opts[:label] || url
22
+ self.priority = opts[:priority] || 50
23
+ end
24
+
25
+ def self.create( url, opts = {} )
26
+ Menu.instance.items << self.new( url, opts )
27
+ end
28
+
29
+ def human_label
30
+ if label.is_a? Symbol
31
+ I18n.t label
32
+ else
33
+ label.humanize
34
+ end
35
+ end
36
+ end # class Item
37
+ end # class Menu
38
+ end # module Aerogel::Admin
@@ -0,0 +1,100 @@
1
+ module Aerogel::Admin
2
+
3
+ # TableBuilder constructs and displays a table populated with data obtained
4
+ # from passed object.
5
+ #
6
+ # Example:
7
+ # table User.all do
8
+ # column :full_name
9
+ # column :roles
10
+ # end
11
+ #
12
+ class TableBuilder < Aerogel::Render::BlockHelper
13
+
14
+ attr_accessor :object, :options, :columns, :style
15
+
16
+ DEFAULT_OPTIONS = {
17
+ class: 'table-striped',
18
+ style: 'standard',
19
+ html_params: {}
20
+ }
21
+
22
+ def initialize( object, options = {}, &block )
23
+ super( &block )
24
+ self.object = object
25
+ self.options = DEFAULT_OPTIONS.deep_merge( options )
26
+ self.style = self.options[:style]
27
+ self.columns = []
28
+ end
29
+
30
+ def column( *args, &block )
31
+ self.columns << Column.new( self, *args, &block )
32
+ nil
33
+ end
34
+
35
+ def template( name )
36
+ "admin/table_builder/#{style}/#{name}".to_sym
37
+ end
38
+
39
+ def wrap( content )
40
+ erb template("table.html"), locals: { table: self }, layout: false
41
+ end
42
+
43
+ # Renders html params for <table ...>
44
+ #
45
+ def html_params
46
+ attrs = @options[:html_params].dup
47
+ attrs.merge!({
48
+ # :action => @options[:action]
49
+ })
50
+ attrs.map{|n, v| v.nil? ? "#{n}" : "#{n}=\"#{v}\""}.join(" ")
51
+ end
52
+
53
+
54
+ private
55
+
56
+ class Column
57
+
58
+ attr_accessor :table, :field, :label, :options, :block
59
+
60
+ KNOWN_OPTIONS = [ :label ]
61
+
62
+ def initialize( table, field, options = {}, &block )
63
+ self.table = table
64
+ self.field = field
65
+ self.options = options
66
+ self.block = block
67
+ self.label = self.options[:label] || self.field.to_sym
68
+ end
69
+
70
+ def human_label
71
+ if label.is_a? Symbol
72
+ if table.object.respond_to? :human_attribute_name
73
+ table.object.human_attribute_name label, default: label
74
+ elsif table.object.respond_to?( :first ) && table.object.first.class.respond_to?( :human_attribute_name )
75
+ table.object.first.class.human_attribute_name label, default: label
76
+ else
77
+ I18n.t label
78
+ end
79
+ elsif label.is_a? String
80
+ label
81
+ else
82
+ label.to_s.humanize
83
+ end
84
+ end
85
+
86
+ # Renders html params for column cells
87
+ #
88
+ def html_params
89
+ attrs = @options.except( *KNOWN_OPTIONS )
90
+ attrs = attrs.deep_merge( @options[:html_params] ) if @options.key? :html_params
91
+ attrs.to_html_params
92
+ end
93
+
94
+ end # class Column
95
+
96
+ end # class TableBuilder
97
+
98
+ end # module Aerogel::Admin
99
+
100
+
@@ -0,0 +1,69 @@
1
+ module Aerogel::Admin
2
+
3
+ # TabsBuilder constructs and displays a tab navigation.
4
+ # from passed object.
5
+ #
6
+ # Example:
7
+ # tabs do
8
+ # tab "/url/to/page1", label: "Page 1"
9
+ # tab "/url/to/page2", label: "Page 2"
10
+ # end
11
+ #
12
+ class TabsBuilder < Aerogel::Render::BlockHelper
13
+
14
+ attr_accessor :options, :tabs, :style
15
+
16
+ DEFAULT_OPTIONS = {
17
+ style: 'standard'
18
+ }
19
+
20
+ def initialize( options = {}, &block )
21
+ super( &block )
22
+ self.options = DEFAULT_OPTIONS.deep_merge( options )
23
+ self.style = self.options[:style]
24
+ self.tabs = []
25
+ end
26
+
27
+ def tab( *args, &block )
28
+ self.tabs << Tab.new( *args, &block )
29
+ nil
30
+ end
31
+
32
+ def template( name )
33
+ "admin/tabs_builder/#{style}/#{name}".to_sym
34
+ end
35
+
36
+ def wrap( content )
37
+ erb template("tabs.html"), locals: { tabs: self }, layout: false
38
+ end
39
+
40
+ private
41
+
42
+ class Tab
43
+
44
+ attr_accessor :url, :label, :options, :block
45
+
46
+ def initialize( url, options = {}, &block )
47
+ self.url = url
48
+ self.options = options
49
+ self.label = self.options[:label] || self.url
50
+ self.block = block
51
+ end
52
+
53
+ def human_label
54
+ if label.is_a? String
55
+ label
56
+ elsif label.is_a? Symbol
57
+ I18n.t label
58
+ else
59
+ label.humanize
60
+ end
61
+ end
62
+
63
+ end # class Tab
64
+
65
+ end # class TabsBuilder
66
+
67
+ end # module Aerogel::Admin
68
+
69
+