adminable 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/adminable.svg)](https://badge.fury.io/rb/adminable)
|
4
|
+
[![Build Status](https://travis-ci.org/droptheplot/adminable.svg?branch=master)](https://travis-ci.org/droptheplot/adminable)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/droptheplot/adminable/badges/gpa.svg)](https://codeclimate.com/github/droptheplot/adminable)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/droptheplot/adminable/badges/coverage.svg)](https://codeclimate.com/github/droptheplot/adminable/coverage)
|
7
|
+
[![Dependency Status](https://gemnasium.com/badges/github.com/droptheplot/adminable.svg)](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
|
+
![Example1](https://raw.githubusercontent.com/droptheplot/adminable/master/screenshots/1.png)
|
23
|
+
|
24
|
+
![Example2](https://raw.githubusercontent.com/droptheplot/adminable/master/screenshots/2.png)
|
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'
|