adminable 0.0.1

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 (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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8c8c3f78e6cda87d730a35355df1313ab3fd7674
4
+ data.tar.gz: 95a90979dce955f6408263afeb5b163a8e0104e5
5
+ SHA512:
6
+ metadata.gz: 7fd364eb2250b70f05ff858899bbb8fe836d338d2c568808211d3f1c4390ace87d04b7f7a3eaea610f96d1d9a8b0b8ba5ebdd1112fcef180cb205f0f181ac2f9
7
+ data.tar.gz: e6b5dd483ccd126c981c3e0656fb8a02fff620937d1279f395400a6bd17267f7ea0c84d2f89a4e64d59c64561a16c33844bc331a1fa39a9795695f329ea9f5d8
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Sergey Novikov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,91 @@
1
+ # Adminable
2
+
3
+ Simple admin interface for Ruby on Rails applications.
4
+
5
+ ## Features
6
+
7
+ * Built with common Rails controllers without DSL.
8
+ * Supports namespaced models.
9
+ * Has simple search with Ransack.
10
+ * Uses Bootstrap 4.0.
11
+ * Mobile friendly.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'adminable'
19
+ ```
20
+
21
+ And then execute:
22
+ ```bash
23
+ $ bundle
24
+ ```
25
+
26
+ Or install it yourself as:
27
+ ```bash
28
+ $ gem install adminable
29
+ ```
30
+
31
+ ## Built-in Attributes
32
+
33
+ List of attributes with default modifiable parameters.
34
+
35
+ ##### String
36
+
37
+ * show: `true`
38
+ * center: `false`
39
+
40
+ ##### Text
41
+
42
+ * show: `true`
43
+ * center: `false`
44
+ * wysiwyg: `true`
45
+
46
+ ##### Integer
47
+
48
+ * show: `true`
49
+ * center: `true`
50
+
51
+ ##### Float
52
+
53
+ * show: `true`
54
+ * center: `true`
55
+
56
+ ##### Decimal
57
+
58
+ * show: `true`
59
+ * center: `true`
60
+
61
+ ##### DateTime
62
+
63
+ * show: `true`
64
+ * center: `false`
65
+
66
+ ##### Boolean
67
+
68
+ * show: `true`
69
+ * center: `true`
70
+
71
+ ##### Belongs To
72
+
73
+ * show: `true`
74
+ * center: `false`
75
+
76
+ ##### Has Many
77
+
78
+ * show: `true`
79
+ * center: `false`
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it (https://github.com/droptheplot/adminable/fork)
84
+ 2. Create your feature branch (git checkout -b my-new-feature)
85
+ 3. Commit your changes (git commit -am 'Add some feature')
86
+ 4. Push to the branch (git push origin my-new-feature)
87
+ 5. Create new Pull Request
88
+
89
+ ## License
90
+
91
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,22 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Adminable'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
18
+
19
+ load 'rails/tasks/engine.rake'
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,18 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require tether
16
+ //= require bootstrap
17
+ //= require bootstrap-sprockets
18
+ //= require_tree .
@@ -0,0 +1,20 @@
1
+ $(document).ready(function() {
2
+ if($('#clusterizeScrollArea').length && $('#clusterizeContentArea').length) {
3
+ var clusterize = new Clusterize({
4
+ scrollId: 'clusterizeScrollArea',
5
+ contentId: 'clusterizeContentArea'
6
+ });
7
+ };
8
+
9
+ $('.toggleCheckbox').click(function() {
10
+ var checkbox = $(this).children('input[type=checkbox]');
11
+ checkbox.prop('checked', !checkbox.prop('checked'));
12
+ $(this).toggleClass('active');
13
+ });
14
+
15
+ tinymce.init({
16
+ selector: '.wysiwyg',
17
+ menubar: false,
18
+ statusbar: false
19
+ });
20
+ });
@@ -0,0 +1,3 @@
1
+ $font-size-root: 14px !default;
2
+
3
+ @import 'bootstrap';
@@ -0,0 +1,7 @@
1
+ module Adminable
2
+ class ApplicationController < ActionController::Base
3
+ def welcome
4
+ redirect_to polymorphic_path(Adminable::Configuration.resources.first.route)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,93 @@
1
+ module Adminable
2
+ class ResourcesController < ApplicationController
3
+ before_action :set_resource
4
+ before_action :set_entry, only: [:edit, :update, :destroy]
5
+
6
+ before_action do
7
+ append_view_path Adminable::Engine.root.join('app/views/adminable', controller_name)
8
+ append_view_path Adminable::Engine.root.join('app/views/adminable/resources')
9
+ end
10
+
11
+ def index
12
+ @q = @resource.model.ransack(params[:q])
13
+ @entries = @q.result.includes(*@resource.includes).all
14
+ .page(params[:page]).per(25)
15
+ end
16
+
17
+ def new
18
+ @entry = @resource.model.new
19
+ end
20
+
21
+ def edit
22
+ end
23
+
24
+ def create
25
+ @entry = @resource.model.new(resource_params)
26
+
27
+ if @entry.save
28
+ redirect_to polymorphic_path(@resource.model),
29
+ notice: t(
30
+ 'adminable.resources.created',
31
+ resource: @resource.model.model_name.human
32
+ )
33
+ else
34
+ flash.now[:alert] = @entry.errors.full_messages
35
+ render :new
36
+ end
37
+ end
38
+
39
+ def update
40
+ if @entry.update(resource_params)
41
+ redirect_to polymorphic_path(@resource.model),
42
+ notice: t(
43
+ 'adminable.resources.updated',
44
+ resource: @resource.model.model_name.human
45
+ )
46
+ else
47
+ flash.now[:alert] = @entry.errors.full_messages
48
+ render :edit
49
+ end
50
+ end
51
+
52
+ def destroy
53
+ @entry.destroy
54
+
55
+ redirect_to polymorphic_path(@resource.model),
56
+ notice: t(
57
+ 'adminable.resources.deleted',
58
+ resource: @resource.model.model_name.human
59
+ )
60
+ end
61
+
62
+ private
63
+
64
+ def set_resource
65
+ @resource = Adminable::Configuration.find_resource(resource_model).clone
66
+
67
+ @resource.attributes.index = index_attributes
68
+ @resource.attributes.form = form_attributes
69
+ end
70
+
71
+ def set_entry
72
+ @entry = @resource.model.find(params[:id])
73
+ end
74
+
75
+ def index_attributes
76
+ @resource.attributes.index
77
+ end
78
+
79
+ def form_attributes
80
+ @resource.attributes.form
81
+ end
82
+
83
+ def resource_model
84
+ controller_path.sub(%r{^adminable/}, '')
85
+ end
86
+
87
+ def resource_params
88
+ params.require(@resource.model.model_name.param_key).permit(
89
+ *@resource.attributes.form.values.map(&:strong_parameter)
90
+ )
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,4 @@
1
+ module Adminable
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ %li.page-item
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link'
@@ -0,0 +1,2 @@
1
+ %li.page-item
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, { remote: remote, class: 'page-link' }
@@ -0,0 +1,2 @@
1
+ %li.page-item
2
+ = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link'
@@ -0,0 +1,6 @@
1
+ - if page.current?
2
+ %li.page-item.active
3
+ = content_tag :a, page, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil)), class: 'page-link'
4
+ - else
5
+ %li.page-item
6
+ = link_to page, url, remote: remote, rel: (page.next? ? 'next' : (page.prev? ? 'prev' : nil)), class: 'page-link'
@@ -0,0 +1,10 @@
1
+ = paginator.render do
2
+ %nav
3
+ %ul.pagination
4
+ = first_page_tag unless current_page.first?
5
+ = prev_page_tag unless current_page.first?
6
+ - each_page do |page|
7
+ - if page.left_outer? || page.right_outer? || page.inside_window?
8
+ = page_tag page
9
+ = next_page_tag unless current_page.last?
10
+ = last_page_tag unless current_page.last?
@@ -0,0 +1,2 @@
1
+ %li.page-item
2
+ = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link'
@@ -0,0 +1,14 @@
1
+ = form_for @entry do |f|
2
+ - @resource.attributes.form.each_value do |attribute|
3
+ - if attribute.show?
4
+ %fieldset.form-group
5
+ = render attribute.form_partial_path, f: f, entry: @entry,
6
+ attribute: attribute
7
+ %fieldset.form-group
8
+ = f.submit t('adminable.buttons.submit'), class: 'btn btn-primary'
9
+ = link_to t('adminable.buttons.back'), polymorphic_path(@resource.model),
10
+ class: 'btn btn-secondary-outline'
11
+ - if @entry.persisted?
12
+ = link_to t('adminable.buttons.delete'), polymorphic_path(@entry),
13
+ class: 'btn btn-danger-outline pull-xs-right', method: :delete,
14
+ data: { confirm: t('adminable.ui.confirm') }
@@ -0,0 +1,9 @@
1
+ .card.bg-faded
2
+ .card-block
3
+ = search_form_for @q do |f|
4
+ - @resource.attributes.ransack.each_value do |attribute|
5
+ %fieldset.form-group
6
+ = f.label attribute.ransack_name, @resource.model.human_attribute_name(attribute.name),
7
+ class: 'text-muted'
8
+ = f.search_field attribute.ransack_name, class: 'form-control'
9
+ = f.submit class: 'btn btn-primary-outline'
@@ -0,0 +1,5 @@
1
+ .row
2
+ .col-md-8.col-md-offset-2
3
+ %h1.m-b-3
4
+ = t('adminable.titles.edit', resource: @resource.model.model_name.human)
5
+ = render 'form'
@@ -0,0 +1,3 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.select attribute.key, attribute.options_for_select(entry),
3
+ { include_blank: I18n.t('adminable.ui.not_selected') }, { class: 'form-control c-select' }
@@ -0,0 +1,3 @@
1
+ = f.label attribute.name do
2
+ = f.check_box attribute.name
3
+ = @resource.model.human_attribute_name(attribute.name)
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.datetime_field attribute.name, class: 'form-control'
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.number_field attribute.name, class: 'form-control'
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.number_field attribute.name, class: 'form-control'
@@ -0,0 +1,9 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.key}][]", nil
3
+ #clusterizeScrollArea.clusterize-scroll
4
+ #clusterizeContentArea.clusterize-content.list-group
5
+ - attribute.options_for_select(entry).each do |value, key|
6
+ .list-group-item.bg-faded.toggleCheckbox{ :class => ('active' if f.object.send(attribute.key).include?(key)) }
7
+ = check_box_tag "#{@resource.model.model_name.param_key}[#{attribute.key}][]",
8
+ key, f.object.send(attribute.key).include?(key), hidden: true
9
+ = value
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.number_field attribute.name, class: 'form-control'
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.text_field attribute.name, class: 'form-control'
@@ -0,0 +1,2 @@
1
+ = render 'adminable/shared/label', f: f, attribute: attribute
2
+ = f.text_area attribute.name, class: "form-control #{ 'wysiwyg' if attribute.wysiwyg? }", rows: 5
@@ -0,0 +1,35 @@
1
+ .m-b-1.clearfix
2
+ %h1.pull-md-left.m-b-2
3
+ = @resource.model.model_name.human.pluralize
4
+ = link_to t('adminable.buttons.new', resource: @resource.model.model_name.human),
5
+ new_polymorphic_path(@resource.model), class: 'btn btn-primary pull-md-right m-b-2'
6
+ .row
7
+ .col-md-9
8
+ .table-responsive.m-b-3
9
+ %table.table.table-striped
10
+ %thead
11
+ %tr
12
+ - @resource.attributes.index.each_value do |attribute|
13
+ %th.text-nowrap{ :class => ('text-md-center' if attribute.center?) }
14
+ = @resource.model.human_attribute_name(attribute.name)
15
+ %th
16
+ %tbody
17
+ - @entries.each do |entry|
18
+ %tr
19
+ - @resource.attributes.index.each_value do |attribute|
20
+ %td{ :class => ('text-md-center' if attribute.center?) }
21
+ = render attribute.index_partial_path, entry: entry,
22
+ attribute: attribute, value: entry[attribute.key]
23
+ %td.text-nowrap.text-md-right
24
+ = link_to t('adminable.buttons.edit'), edit_polymorphic_path(entry),
25
+ class: 'label label-primary'
26
+ = link_to t('adminable.buttons.delete'), polymorphic_path(entry),
27
+ class: 'label label-danger', method: :delete,
28
+ data: { confirm: t('adminable.ui.confirm') }
29
+ - if @entries.empty?
30
+ %tr
31
+ %td.text-md-center.text-muted{ :colspan => @resource.attributes.index.size + 1 }
32
+ No data available
33
+ .col-md-3.hidden-sm-down
34
+ = render 'search'
35
+ = paginate @entries, views_prefix: 'adminable'