adminable 0.0.1 → 0.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 +94 -33
- data/app/assets/javascripts/adminable/scripts.js +8 -5
- data/app/assets/stylesheets/adminable/application.scss +15 -0
- data/app/controllers/adminable/application_controller.rb +0 -3
- data/app/controllers/adminable/resources_controller.rb +49 -24
- data/app/models/concerns/adminable/resource_concern.rb +15 -0
- data/app/views/adminable/resources/_form.html.haml +5 -9
- data/app/views/adminable/resources/_search.html.haml +2 -2
- data/app/views/adminable/resources/edit.html.haml +1 -1
- data/app/views/adminable/resources/form/_belongs_to.html.haml +13 -3
- data/app/views/adminable/resources/form/_boolean.html.haml +5 -2
- data/app/views/adminable/resources/form/_date.html.haml +3 -0
- data/app/views/adminable/resources/form/_datetime.html.haml +3 -2
- data/app/views/adminable/resources/form/_decimal.html.haml +3 -2
- data/app/views/adminable/resources/form/_float.html.haml +3 -2
- data/app/views/adminable/resources/form/_has_many.html.haml +12 -8
- data/app/views/adminable/resources/form/_integer.html.haml +3 -2
- data/app/views/adminable/resources/form/_string.html.haml +3 -2
- data/app/views/adminable/resources/form/_text.html.haml +4 -2
- data/app/views/adminable/resources/form/_time.html.haml +3 -0
- data/app/views/adminable/resources/form/_timestamp.html.haml +3 -0
- data/app/views/adminable/resources/index.html.haml +12 -14
- data/app/views/adminable/resources/index/_belongs_to.html.haml +4 -5
- data/app/views/adminable/resources/index/_date.html.haml +2 -0
- data/app/views/adminable/resources/index/_has_many.html.haml +1 -2
- data/app/views/adminable/resources/index/_text.html.haml +1 -1
- data/app/views/adminable/resources/index/_time.html.haml +2 -0
- data/app/views/adminable/resources/index/_timestamp.html.haml +2 -0
- data/app/views/adminable/shared/_label.html.haml +6 -3
- data/app/views/layouts/adminable/application.html.haml +3 -4
- data/config/locales/adminable.en.yml +4 -1
- data/config/locales/adminable.ru.yml +21 -0
- data/config/routes.rb +1 -1
- data/lib/adminable.rb +9 -4
- data/lib/adminable/attributes/association.rb +7 -14
- data/lib/adminable/attributes/base.rb +36 -18
- data/lib/adminable/attributes/collection.rb +75 -36
- data/lib/adminable/attributes/types/belongs_to.rb +1 -3
- data/lib/adminable/attributes/types/date.rb +8 -0
- data/lib/adminable/attributes/types/has_many.rb +0 -6
- data/lib/adminable/attributes/types/time.rb +8 -0
- data/lib/adminable/attributes/types/timestamp.rb +8 -0
- data/lib/adminable/configuration.rb +7 -2
- data/lib/adminable/engine.rb +5 -1
- data/lib/adminable/errors.rb +7 -0
- data/lib/adminable/presenters/base_presenter.rb +11 -0
- data/lib/adminable/presenters/entries_presenter.rb +55 -0
- data/lib/adminable/presenters/entry_presenter.rb +68 -0
- data/lib/adminable/resource.rb +9 -15
- data/lib/adminable/version.rb +1 -1
- data/lib/generators/adminable/install/templates/application_controller.rb +2 -0
- data/lib/generators/adminable/install_generator.rb +27 -0
- data/lib/generators/{cms → adminable}/resource/templates/resource_controller.rb.erb +0 -0
- data/lib/generators/{cms → adminable}/resource_generator.rb +0 -0
- metadata +77 -33
- data/lib/adminable/extensions/devise.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f528b224feece004bb0e267e9d3c7c59fc8cb82c
|
4
|
+
data.tar.gz: 1cef3dc442b2ac04713f0695762429afdf0b4637
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a463389478cd68106b2e48567d1efe341f6aff36f087b5c0067e5d84d42c825ca020bae79b6650c3158b4433f00767582c5c2357435fb717c77f2dd33e7b6276
|
7
|
+
data.tar.gz: de6a89ee40356740af5537167d0411cca5c922323339ff38a2d6be3c55b3264e2f3ab70e35194f1a48e3694db248aa32585e59df74a459bcd74f212616926d1e
|
data/README.md
CHANGED
@@ -1,15 +1,28 @@
|
|
1
1
|
# Adminable
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/adminable)
|
4
|
+
[](https://travis-ci.org/droptheplot/adminable)
|
5
|
+
[](https://codeclimate.com/github/droptheplot/adminable)
|
6
|
+
[](https://codeclimate.com/github/droptheplot/adminable/coverage)
|
7
|
+
[](https://gemnasium.com/github.com/droptheplot/adminable)
|
8
|
+
|
9
|
+
|
3
10
|
Simple admin interface for Ruby on Rails applications.
|
4
11
|
|
5
12
|
## Features
|
6
13
|
|
7
|
-
* Built with common Rails controllers
|
14
|
+
* Built with common Rails controllers with a small DSL.
|
8
15
|
* Supports namespaced models.
|
9
|
-
* Has simple search with Ransack.
|
10
|
-
* Uses Bootstrap 4.0.
|
16
|
+
* Has simple search with [Ransack](https://github.com/activerecord-hackery/ransack).
|
17
|
+
* Uses [Bootstrap](https://github.com/twbs/bootstrap) 4.0.
|
18
|
+
* Handles a lot of associations with [Clusterize.js](https://github.com/NeXTs/Clusterize.js).
|
19
|
+
* Has built-in WYSIWYG editor [TinyMCE](https://github.com/tinymce/tinymce).
|
11
20
|
* Mobile friendly.
|
12
21
|
|
22
|
+

|
23
|
+
|
24
|
+

|
25
|
+
|
13
26
|
## Installation
|
14
27
|
|
15
28
|
Add this line to your application's Gemfile:
|
@@ -28,55 +41,103 @@ Or install it yourself as:
|
|
28
41
|
$ gem install adminable
|
29
42
|
```
|
30
43
|
|
31
|
-
##
|
44
|
+
## Getting Started
|
32
45
|
|
33
|
-
|
46
|
+
First things first. Add routes and create `application_controller.rb` class using generator:
|
34
47
|
|
35
|
-
|
48
|
+
```bash
|
49
|
+
rails g adminable:install
|
50
|
+
# => create app/controllers/adminable/application_controller.rb
|
51
|
+
# => insert config/routes.rb
|
52
|
+
```
|
36
53
|
|
37
|
-
|
38
|
-
* center: `false`
|
54
|
+
#### Generating Resources
|
39
55
|
|
40
|
-
|
56
|
+
For example you have model `User`, then run:
|
41
57
|
|
42
|
-
|
43
|
-
|
44
|
-
|
58
|
+
```bash
|
59
|
+
rails g adminable:resource user
|
60
|
+
# => create app/controllers/adminable/users_controller.rb
|
61
|
+
```
|
45
62
|
|
46
|
-
|
63
|
+
For namespaced models, like `Blog::Post`, use:
|
47
64
|
|
48
|
-
|
49
|
-
|
65
|
+
```bash
|
66
|
+
rails g adminable:resource blog/post
|
67
|
+
# => create app/controllers/adminable/blog/posts_controller.rb
|
68
|
+
```
|
50
69
|
|
51
|
-
|
70
|
+
#### Customizing Attributes
|
52
71
|
|
53
|
-
|
54
|
-
* center: `true`
|
72
|
+
You can update attributes with simple DSL inside `set_attributes` block:
|
55
73
|
|
56
|
-
#####
|
74
|
+
##### For existing attributes
|
57
75
|
|
58
|
-
|
59
|
-
|
76
|
+
```ruby
|
77
|
+
set(name, options = {})
|
78
|
+
```
|
60
79
|
|
61
|
-
#####
|
80
|
+
##### For new attributes
|
62
81
|
|
63
|
-
|
64
|
-
|
82
|
+
```ruby
|
83
|
+
add(name, type, options = {})
|
84
|
+
```
|
85
|
+
|
86
|
+
##### Attributes Parameters
|
87
|
+
|
88
|
+
* `index` - *(true/false)* - Shows attribute on index page.
|
89
|
+
* `form` - *(true/false)* - Shows attribute on new/edit page.
|
90
|
+
* `center` - *(true/false)* - Adds `text-align: center` for attribute value on index page.
|
91
|
+
* `search` - *(true/false)* - Enables search for this attribute.
|
92
|
+
|
93
|
+
##### Examples
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class Adminable::Blog::PostsController < Adminable::ResourcesController
|
97
|
+
set_attributes do |attributes|
|
98
|
+
# Enables search for title column
|
99
|
+
attributes.set :title, search: true
|
100
|
+
|
101
|
+
# Hides title from new and edit pages
|
102
|
+
attributes.set :title, form: true
|
103
|
+
|
104
|
+
# Adds wysiwyg plugin and hides from index table
|
105
|
+
attributes.set :text, wysiwyg: true, index: false
|
65
106
|
|
66
|
-
|
107
|
+
# Adds new attribute `password` with type `string` and some options
|
108
|
+
attributes.add :password, :string, wysiwyg: true, index: false
|
67
109
|
|
68
|
-
|
69
|
-
|
110
|
+
# Adds new attribute `author`
|
111
|
+
attributes << Adminable::Attributes::Types::String.new(:author)
|
70
112
|
|
71
|
-
|
113
|
+
# Allows search for multiple attributes
|
114
|
+
attributes.set :title, :body, search: true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
##### See Also
|
72
120
|
|
73
|
-
*
|
74
|
-
* center: `false`
|
121
|
+
* Configured controller for Devise model: [app/controllers/adminable/users_controller.rb](https://github.com/droptheplot/adminable/blob/master/spec/dummy/app/controllers/adminable/users_controller.rb)
|
75
122
|
|
76
|
-
|
123
|
+
## Built-in Attributes
|
77
124
|
|
78
|
-
|
79
|
-
|
125
|
+
List of attributes with default parameters.
|
126
|
+
|
127
|
+
| | index | form | center | wysiwyg |
|
128
|
+
|------------|-------|------|--------|---------|
|
129
|
+
| String | + | + | | |
|
130
|
+
| Text | + | + | | + |
|
131
|
+
| Integer | + | + | + | |
|
132
|
+
| Float | + | + | + | |
|
133
|
+
| Decimal | + | + | + | |
|
134
|
+
| Date | + | + | | |
|
135
|
+
| DateTime | + | + | | |
|
136
|
+
| Time | + | + | | |
|
137
|
+
| Timestamp | + | + | | |
|
138
|
+
| Boolean | + | + | + | |
|
139
|
+
| Belongs To | | + | | |
|
140
|
+
| Has Many | | + | | |
|
80
141
|
|
81
142
|
## Contributing
|
82
143
|
|
@@ -4,12 +4,13 @@ $(document).ready(function() {
|
|
4
4
|
scrollId: 'clusterizeScrollArea',
|
5
5
|
contentId: 'clusterizeContentArea'
|
6
6
|
});
|
7
|
-
}
|
7
|
+
}
|
8
8
|
|
9
|
-
$('.
|
10
|
-
var
|
11
|
-
|
12
|
-
|
9
|
+
$('.uncheck-associations').click(function() {
|
10
|
+
var inputs = $(this).parent().next().next('.associations').find('input[type=radio], input[type=checkbox]');
|
11
|
+
inputs.each(function(index, value) {
|
12
|
+
value.checked = false;
|
13
|
+
});
|
13
14
|
});
|
14
15
|
|
15
16
|
tinymce.init({
|
@@ -17,4 +18,6 @@ $(document).ready(function() {
|
|
17
18
|
menubar: false,
|
18
19
|
statusbar: false
|
19
20
|
});
|
21
|
+
|
22
|
+
$('[data-toggle="tooltip"]').tooltip();
|
20
23
|
});
|
@@ -1,3 +1,18 @@
|
|
1
1
|
$font-size-root: 14px !default;
|
2
2
|
|
3
3
|
@import 'bootstrap';
|
4
|
+
|
5
|
+
.associations {
|
6
|
+
border: 1px solid $input-border-color;
|
7
|
+
border-radius: $border-radius;
|
8
|
+
.association {
|
9
|
+
padding: .75rem;
|
10
|
+
&:not(:last-child) {
|
11
|
+
border-bottom: 1px solid $gray-lighter;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
.uncheck-associations {
|
17
|
+
cursor: pointer;
|
18
|
+
}
|
@@ -1,17 +1,28 @@
|
|
1
1
|
module Adminable
|
2
2
|
class ResourcesController < ApplicationController
|
3
|
-
|
3
|
+
def initialize(*)
|
4
|
+
@resource = Adminable::Configuration.find_resource(resource_model)
|
5
|
+
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
4
9
|
before_action :set_entry, only: [:edit, :update, :destroy]
|
5
10
|
|
6
11
|
before_action do
|
7
|
-
append_view_path
|
8
|
-
|
12
|
+
append_view_path(
|
13
|
+
[
|
14
|
+
Adminable::Engine.root.join('app/views/adminable', controller_name),
|
15
|
+
Adminable::Engine.root.join('app/views/adminable/resources')
|
16
|
+
]
|
17
|
+
)
|
9
18
|
end
|
10
19
|
|
11
20
|
def index
|
12
21
|
@q = @resource.model.ransack(params[:q])
|
13
|
-
@entries =
|
14
|
-
|
22
|
+
@entries = Adminable::EntriesPresenter.new(
|
23
|
+
@q.result.includes(*@resource.includes).order(id: :desc)
|
24
|
+
.page(params[:page]).per(25)
|
25
|
+
)
|
15
26
|
end
|
16
27
|
|
17
28
|
def new
|
@@ -21,6 +32,7 @@ module Adminable
|
|
21
32
|
def edit
|
22
33
|
end
|
23
34
|
|
35
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
24
36
|
def create
|
25
37
|
@entry = @resource.model.new(resource_params)
|
26
38
|
|
@@ -31,7 +43,7 @@ module Adminable
|
|
31
43
|
resource: @resource.model.model_name.human
|
32
44
|
)
|
33
45
|
else
|
34
|
-
flash.now[:alert] = @entry.errors.full_messages
|
46
|
+
flash.now[:alert] = @entry.errors.full_messages.first
|
35
47
|
render :new
|
36
48
|
end
|
37
49
|
end
|
@@ -44,7 +56,7 @@ module Adminable
|
|
44
56
|
resource: @resource.model.model_name.human
|
45
57
|
)
|
46
58
|
else
|
47
|
-
flash.now[:alert] = @entry.errors.full_messages
|
59
|
+
flash.now[:alert] = @entry.errors.full_messages.first
|
48
60
|
render :edit
|
49
61
|
end
|
50
62
|
end
|
@@ -59,25 +71,38 @@ module Adminable
|
|
59
71
|
)
|
60
72
|
end
|
61
73
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
74
|
+
# Calls from children controller class to manage resource attributes
|
75
|
+
# @example Update attributes for Adminable::Blog::PostsController
|
76
|
+
# # app/controllers/adminable/blog/posts_controller.rb
|
77
|
+
#
|
78
|
+
# set_attributes do |attributes|
|
79
|
+
# # Enables search for title column
|
80
|
+
# attributes.set :title, search: true
|
81
|
+
#
|
82
|
+
# # Hides title from new and edit pages
|
83
|
+
# attributes.set :title, form: true
|
84
|
+
#
|
85
|
+
# # Adds wysiwyg plugin and hides from index table
|
86
|
+
# attributes.set :text, wysiwyg: true, index: false
|
87
|
+
#
|
88
|
+
# # Adds new attribute `password` with type `string` and some options
|
89
|
+
# attributes.add :password, :string, wysiwyg: true, index: false
|
90
|
+
#
|
91
|
+
# # Adds new attribute `author`
|
92
|
+
# attributes << Adminable::Attributes::Types::String.new(:author)
|
93
|
+
# end
|
94
|
+
def self.set_attributes
|
95
|
+
before_action do
|
96
|
+
@resource.attributes.configure { yield(@resource.attributes) }
|
73
97
|
end
|
98
|
+
end
|
74
99
|
|
75
|
-
|
76
|
-
@resource.attributes.index
|
77
|
-
end
|
100
|
+
private
|
78
101
|
|
79
|
-
def
|
80
|
-
@
|
102
|
+
def set_entry
|
103
|
+
@entry = Adminable::EntryPresenter.new(
|
104
|
+
@resource.model.find(params[:id])
|
105
|
+
)
|
81
106
|
end
|
82
107
|
|
83
108
|
def resource_model
|
@@ -86,7 +111,7 @@ module Adminable
|
|
86
111
|
|
87
112
|
def resource_params
|
88
113
|
params.require(@resource.model.model_name.param_key).permit(
|
89
|
-
*@resource.attributes.form.
|
114
|
+
*@resource.attributes.form.map(&:strong_parameter)
|
90
115
|
)
|
91
116
|
end
|
92
117
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Adminable
|
2
|
+
module ResourceConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def adminable
|
6
|
+
%i(title name email login id).each do |name|
|
7
|
+
begin
|
8
|
+
return OpenStruct.new(name: public_send(name))
|
9
|
+
rescue NoMethodError
|
10
|
+
next
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,14 +1,10 @@
|
|
1
|
-
= form_for @entry do |f|
|
2
|
-
- @resource.attributes.form.
|
3
|
-
-
|
4
|
-
|
5
|
-
= render attribute.form_partial_path, f: f, entry: @entry,
|
6
|
-
attribute: attribute
|
1
|
+
= form_for @entry, method: (@entry.persisted? ? :patch : :post) do |f|
|
2
|
+
- @resource.attributes.form.each do |attribute|
|
3
|
+
%fieldset.form-group
|
4
|
+
= render attribute.form_partial_path, entry: @entry, attribute: attribute
|
7
5
|
%fieldset.form-group
|
8
6
|
= f.submit t('adminable.buttons.submit'), class: 'btn btn-primary'
|
9
7
|
= link_to t('adminable.buttons.back'), polymorphic_path(@resource.model),
|
10
8
|
class: 'btn btn-secondary-outline'
|
11
9
|
- if @entry.persisted?
|
12
|
-
=
|
13
|
-
class: 'btn btn-danger-outline pull-xs-right', method: :delete,
|
14
|
-
data: { confirm: t('adminable.ui.confirm') }
|
10
|
+
= @entry.link_to_delete
|
@@ -1,9 +1,9 @@
|
|
1
1
|
.card.bg-faded
|
2
2
|
.card-block
|
3
3
|
= search_form_for @q do |f|
|
4
|
-
- @resource.attributes.
|
4
|
+
- @resource.attributes.search.each do |attribute|
|
5
5
|
%fieldset.form-group
|
6
6
|
= f.label attribute.ransack_name, @resource.model.human_attribute_name(attribute.name),
|
7
7
|
class: 'text-muted'
|
8
8
|
= f.search_field attribute.ransack_name, class: 'form-control'
|
9
|
-
= f.submit class: 'btn btn-primary-outline'
|
9
|
+
= f.submit t('adminable.buttons.search'), class: 'btn btn-primary-outline'
|
@@ -1,3 +1,13 @@
|
|
1
|
-
= render 'adminable/shared/label',
|
2
|
-
=
|
3
|
-
|
1
|
+
= render 'adminable/shared/label', attribute: attribute
|
2
|
+
= hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.key}]", nil
|
3
|
+
#clusterizeScrollArea.clusterize-scroll.associations
|
4
|
+
#clusterizeContentArea.clusterize-content
|
5
|
+
- attribute.association.all.each do |association_entry|
|
6
|
+
.association
|
7
|
+
%label.c-input.c-radio.m-a-0
|
8
|
+
= radio_button_tag "#{@resource.model.model_name.param_key}[#{attribute.key}]",
|
9
|
+
association_entry.id, entry.send(attribute.key) == association_entry.id
|
10
|
+
%span.c-indicator
|
11
|
+
= link_to association_entry.to_name,
|
12
|
+
edit_polymorphic_path(association_entry),
|
13
|
+
target: '_blank'
|
@@ -1,3 +1,6 @@
|
|
1
|
-
|
2
|
-
=
|
1
|
+
%label.c-input.c-checkbox
|
2
|
+
= hidden_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]", 0
|
3
|
+
= check_box_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]", 1,
|
4
|
+
entry.send(attribute.key)
|
5
|
+
%span.c-indicator
|
3
6
|
= @resource.model.human_attribute_name(attribute.name)
|
@@ -1,2 +1,3 @@
|
|
1
|
-
= render 'adminable/shared/label',
|
2
|
-
=
|
1
|
+
= render 'adminable/shared/label', attribute: attribute
|
2
|
+
= datetime_field_tag "#{@resource.model.model_name.param_key}[#{attribute.name}]",
|
3
|
+
entry[attribute.name], class: 'form-control'
|