upmin-admin 0.1.01 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -18
- data/Rakefile +18 -18
- data/app/assets/javascripts/upmin/attributes/datetime.js +37 -11
- data/app/assets/stylesheets/upmin/application.css +0 -1
- data/app/assets/stylesheets/upmin/base.css.scss +8 -1
- data/app/assets/stylesheets/upmin/dashboard.css +16 -0
- data/app/assets/stylesheets/upmin/instances.css.scss +7 -0
- data/app/controllers/upmin/dashboard_controller.rb +11 -0
- data/app/controllers/upmin/models_controller.rb +28 -9
- data/app/views/layouts/upmin/application.html.haml +6 -2
- data/app/views/upmin/dashboard/_chart.html.haml +9 -0
- data/app/views/upmin/dashboard/index.html.haml +14 -0
- data/app/views/upmin/models/search.html.haml +20 -4
- data/app/views/upmin/partials/attributes/_boolean.html.haml +1 -6
- data/app/views/upmin/partials/attributes/_date.html.haml +26 -0
- data/app/views/upmin/partials/attributes/_enum.html.haml +9 -0
- data/app/views/upmin/partials/attributes/_money_cents.html.haml +10 -0
- data/app/views/upmin/partials/models/_model.html.haml +5 -6
- data/app/views/upmin/partials/models/_new_model.html.haml +1 -1
- data/app/views/upmin/partials/search_boxes/_ransack_search_box.html.haml +6 -1
- data/config/routes.rb +3 -5
- data/lib/generators/upmin/install_generator.rb +24 -0
- data/lib/generators/upmin/templates/initializer.rb +13 -0
- data/lib/upmin/active_record/model.rb +15 -1
- data/lib/upmin/admin.rb +2 -1
- data/lib/upmin/attribute.rb +4 -1
- data/lib/upmin/configuration.rb +1 -0
- data/lib/upmin/data_mapper/model.rb +10 -0
- data/lib/upmin/engine.rb +4 -3
- data/lib/upmin/model.rb +37 -5
- data/lib/upmin/railtie.rb +1 -0
- data/lib/upmin/railties/dashboard.rb +88 -0
- data/lib/upmin/railties/render_helpers.rb +2 -0
- data/lib/upmin/version.rb +1 -1
- data/spec/features/delete_model_spec.rb +38 -0
- data/spec/features/edit_model_spec.rb +1 -1
- data/spec/features/enum_attributes_spec.rb +24 -0
- data/spec/features/navbar_spec.rb +4 -4
- data/spec/features/new_model_spec.rb +1 -1
- data/spec/features/search_spec.rb +17 -27
- data/spec/lib/attribute_spec.rb +15 -0
- data/spec/lib/upmin/active_record/model_spec.rb +15 -0
- data/spec/spec_helper.rb +8 -0
- metadata +49 -4
- data/app/views/upmin/models/dashboard.html.haml +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04a4f4f1edcfc6d6b2717175fcba3473962400d6
|
4
|
+
data.tar.gz: 40a38a4a7233b3a9ddb09e826731911b346c0286
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6a111fa50f037447043dc456538dbd033ebae0f77b17fd5ce42228ce529576c60c0c9a8844fa84769dcf1e522a9e240121a8a46e509deb946713f6a3465b5d0
|
7
|
+
data.tar.gz: 3acbf22f1bf9df75aab7b3481e30712b935d5c26cb7b6613bd61c9962ea59e80a17357ab396c1c3c7317291611b0b1fef958595ead294d0ecf5c79c366187912
|
data/README.md
CHANGED
@@ -6,15 +6,9 @@ Upmin Admin is a framework for creating powerful Ruby on Rails admin backends wi
|
|
6
6
|
Upmin currently supports Rails 3.2, 4.0, 4.1 & 4.2.
|
7
7
|
|
8
8
|
|
9
|
-
## Demo Videos
|
10
|
-
|
11
|
-
**NOTE** - The videos are currently outdated, and are only relevant for versions below `0.1.0`. Please refer to the docs for recent releases until we get them updated.
|
12
|
-
|
13
|
-
To see videos showing how to install and giving a pretty good overview of the main features of upmin-admin go to [https://www.upmin.com/admin-rails](https://www.upmin.com/admin-rails).
|
14
|
-
|
15
9
|
## Demo Applications
|
16
10
|
|
17
|
-
There is
|
11
|
+
There is a demo application you can test out here: [store_demo](https://github.com/upmin/store_demo).
|
18
12
|
|
19
13
|
If you do choose to use the [store_demo](https://github.com/upmin/store_demo), please follow the directions in the [README](https://github.com/upmin/store_demo/blob/master/README.md) to ensure you have seed data to work with.
|
20
14
|
|
@@ -29,31 +23,29 @@ Installing `upmin-admin` is incredibly easy. Simple add the gem to your `Gemfile
|
|
29
23
|
gem 'upmin-admin'
|
30
24
|
```
|
31
25
|
|
32
|
-
|
26
|
+
Then run the generator:
|
33
27
|
|
34
28
|
```ruby
|
35
|
-
|
29
|
+
rails g upmin:install
|
36
30
|
```
|
37
31
|
|
38
|
-
|
32
|
+
This mounts the engine in your `routes.rb` file:
|
39
33
|
|
40
34
|
```ruby
|
41
|
-
mount Upmin::Engine => '/
|
35
|
+
mount Upmin::Engine => '/admin'
|
42
36
|
```
|
43
37
|
|
44
|
-
And
|
45
|
-
|
46
|
-
|
47
|
-
### Rails 4.2
|
38
|
+
And adds a configuration file at `config/initializers/upmin.rb`
|
48
39
|
|
49
|
-
|
40
|
+
If you already have routes pointing to `/admin` you can use any path you want, for example you could use the following instead:
|
50
41
|
|
51
42
|
```ruby
|
52
|
-
|
43
|
+
mount Upmin::Engine => '/ice-ice-baby'
|
53
44
|
```
|
54
45
|
|
55
|
-
|
46
|
+
And you would access your admin page at `localhost:3000/ice-ice-baby` or `example.com/ice-ice-baby`.
|
56
47
|
|
48
|
+
If you prefer not to use the generator, simply add the route, and optionally the config file as documented in the wiki.
|
57
49
|
|
58
50
|
## Documentation
|
59
51
|
|
data/Rakefile
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
|
-
require 'bundler'
|
5
|
-
Bundler::GemHelper.install_tasks
|
4
|
+
require 'bundler/gem_tasks'
|
6
5
|
|
7
6
|
require 'rspec/core'
|
8
7
|
require 'rspec/core/rake_task'
|
@@ -35,28 +34,29 @@ namespace :spec do
|
|
35
34
|
%w(active_record_32 active_record_40 active_record_41 active_record_42 will_paginate data_mapper).each do |gemfile|
|
36
35
|
desc "Run Tests against #{gemfile}"
|
37
36
|
task "#{gemfile}" do
|
38
|
-
Dir.chdir("test_apps/#{gemfile}")
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
Dir.chdir("test_apps/#{gemfile}") do
|
38
|
+
puts "Testing in #{`pwd`}"
|
39
|
+
sh "bundle install --quiet"
|
40
|
+
sh "bundle update --quiet"
|
42
41
|
|
43
|
-
|
44
|
-
|
42
|
+
# Drop migrations and recreate
|
43
|
+
sh "rm -rf db/migrate/*"
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
if gemfile != "data_mapper"
|
46
|
+
sh "bundle exec rake railties:install:migrations > /dev/null"
|
47
|
+
end
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
if gemfile == "active_record_32"
|
50
|
+
sh "bundle exec rake db:drop db:create db:migrate --quiet > /dev/null"
|
51
|
+
end
|
53
52
|
|
54
|
-
|
53
|
+
sh "RAILS_ENV=test bundle exec rake db:drop db:create db:migrate --quiet > /dev/null"
|
55
54
|
|
56
|
-
|
55
|
+
update_files
|
57
56
|
|
58
|
-
|
59
|
-
|
57
|
+
# Run tests
|
58
|
+
sh "bundle exec rake"
|
59
|
+
end
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -7,9 +7,9 @@
|
|
7
7
|
return null;
|
8
8
|
} else {
|
9
9
|
var m = moment();
|
10
|
-
m.utc().year(matches[1]);
|
11
|
-
m.utc().month(matches[2]);
|
12
|
-
m.utc().date(matches[3]);
|
10
|
+
m.utc().year(parseInt(matches[1]));
|
11
|
+
m.utc().month(parseInt(matches[2])-1);
|
12
|
+
m.utc().date(parseInt(matches[3]));
|
13
13
|
return m;
|
14
14
|
}
|
15
15
|
}
|
@@ -68,13 +68,8 @@
|
|
68
68
|
return curMoment;
|
69
69
|
}
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
// Initializing the attribute view.
|
77
|
-
var init = function(formId) {
|
71
|
+
// Initializing the DateTime attribute view.
|
72
|
+
var initDateTime = function(formId) {
|
78
73
|
var dtSection = $("." + formId + ".datetime-attribute");
|
79
74
|
var hiddenInput = dtSection.find("input#" + formId + "[type=hidden]");
|
80
75
|
var dateInput = dtSection.find("#" + formId + "-date");
|
@@ -123,6 +118,35 @@
|
|
123
118
|
});
|
124
119
|
}
|
125
120
|
|
121
|
+
// Initializing the Date attribute view.
|
122
|
+
// TODO: Dry this up against DateTime
|
123
|
+
var initDate = function(formId) {
|
124
|
+
var dtSection = $("." + formId + ".date-attribute");
|
125
|
+
var hiddenInput = dtSection.find("input#" + formId + "[type=hidden]");
|
126
|
+
var dateInput = dtSection.find("#" + formId + "-date");
|
127
|
+
|
128
|
+
var dtMoment = moment(hiddenInput.val());
|
129
|
+
if (hiddenInput.val() == "") {
|
130
|
+
dtMoment = null;
|
131
|
+
}
|
132
|
+
|
133
|
+
var handleDateSelect = function() {
|
134
|
+
var newDateMoment = parseDate(dateInput.val());
|
135
|
+
setInputDate(newDateMoment, hiddenInput);
|
136
|
+
return newDateMoment;
|
137
|
+
}
|
138
|
+
|
139
|
+
// Create Date Picker
|
140
|
+
var datePicker = new Pikaday({ field: $("#" + formId + "-date")[0], onSelect: handleDateSelect });
|
141
|
+
|
142
|
+
dtSection.closest("form").submit(function(event) {
|
143
|
+
event.preventDefault();
|
144
|
+
|
145
|
+
handleDateSelect();
|
146
|
+
|
147
|
+
event.target.submit();
|
148
|
+
});
|
149
|
+
}
|
126
150
|
|
127
151
|
if (window.Upmin == null) {
|
128
152
|
window.Upmin = {};
|
@@ -130,5 +154,7 @@
|
|
130
154
|
if (window.Upmin.Attributes == null) {
|
131
155
|
window.Upmin.Attributes = {};
|
132
156
|
}
|
133
|
-
|
157
|
+
|
158
|
+
window.Upmin.Attributes.DateTime = initDateTime;
|
159
|
+
window.Upmin.Attributes.Date = initDate;
|
134
160
|
})();
|
@@ -52,10 +52,17 @@ body {
|
|
52
52
|
padding-top: 8px;
|
53
53
|
}
|
54
54
|
|
55
|
+
.page-entries-info {
|
56
|
+
margin: 5px 0px 15px;
|
57
|
+
}
|
58
|
+
|
55
59
|
.pagination:first-of-type {
|
56
|
-
margin
|
60
|
+
margin: 5px 0px 0px;
|
57
61
|
}
|
58
62
|
|
63
|
+
.pagination:last-of-type {
|
64
|
+
margin: 10px 0px 20px;
|
65
|
+
}
|
59
66
|
|
60
67
|
.wizard span {padding: 12px 12px 10px 12px; margin-right:5px; background:#efefef; position:relative; display:inline-block; }
|
61
68
|
.wizard span:before {width:0px; height:0px; border-top: 20px inset transparent; border-bottom: 20px inset transparent; border-left: 20px solid #fff; position: absolute; content: ""; top: 0; left: 0;}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
.panel .panel-heading {
|
3
|
+
border-bottom: 1px solid #d7d7d7;
|
4
|
+
color: #666;
|
5
|
+
font-size: 14px;
|
6
|
+
font-weight: 200;
|
7
|
+
padding: 7px 10px 4px;
|
8
|
+
}
|
9
|
+
|
10
|
+
.panel .panel-footer {
|
11
|
+
background: #fbfbfb;
|
12
|
+
border-top: 1px solid #e2e2e2;
|
13
|
+
color: #808080;
|
14
|
+
font-size: 12px;
|
15
|
+
padding: 8px 10px 5px;
|
16
|
+
}
|
@@ -24,6 +24,9 @@
|
|
24
24
|
> a {
|
25
25
|
color: $hex;
|
26
26
|
}
|
27
|
+
> a.delete {
|
28
|
+
color: #fff;
|
29
|
+
}
|
27
30
|
}
|
28
31
|
}
|
29
32
|
}
|
@@ -67,6 +70,10 @@
|
|
67
70
|
font-size: 1.1em;
|
68
71
|
}
|
69
72
|
|
73
|
+
.radio, .radio-inline input {
|
74
|
+
height: auto;
|
75
|
+
}
|
76
|
+
|
70
77
|
.well {
|
71
78
|
padding: 9px;
|
72
79
|
margin-bottom: 0;
|
@@ -2,8 +2,8 @@ require_dependency "upmin/application_controller"
|
|
2
2
|
|
3
3
|
module Upmin
|
4
4
|
class ModelsController < ApplicationController
|
5
|
-
before_filter :set_klass, only: [:new, :create, :show, :update, :search, :action]
|
6
|
-
before_filter :set_model, only: [:show, :update, :action]
|
5
|
+
before_filter :set_klass, only: [:new, :create, :show, :update, :destroy, :search, :action]
|
6
|
+
before_filter :set_model, only: [:show, :update, :destroy, :action]
|
7
7
|
|
8
8
|
before_filter :set_page, only: [:search]
|
9
9
|
before_filter :set_query, only: [:search]
|
@@ -12,9 +12,6 @@ module Upmin
|
|
12
12
|
before_filter :set_action, only: [:action]
|
13
13
|
before_filter :set_arguments, only: [:action]
|
14
14
|
|
15
|
-
def dashboard
|
16
|
-
end
|
17
|
-
|
18
15
|
# GET /:model_name/:id
|
19
16
|
def show
|
20
17
|
end
|
@@ -29,7 +26,7 @@ module Upmin
|
|
29
26
|
@model = @klass.new
|
30
27
|
raw_model = @model.model
|
31
28
|
|
32
|
-
args = params[@klass.underscore_name]
|
29
|
+
args = params[@klass.underscore_name] || []
|
33
30
|
|
34
31
|
args.each do |key, value|
|
35
32
|
# TODO(jon): Figure out a way to do transforms.
|
@@ -55,7 +52,6 @@ module Upmin
|
|
55
52
|
end
|
56
53
|
end
|
57
54
|
|
58
|
-
|
59
55
|
# PUT /:model_name/:id
|
60
56
|
def update
|
61
57
|
|
@@ -89,6 +85,25 @@ module Upmin
|
|
89
85
|
# @results = Upmin::Paginator.paginate(@q.result(distinct: true), @page, 30)
|
90
86
|
end
|
91
87
|
|
88
|
+
# DELETE /:model_name/:id
|
89
|
+
def destroy
|
90
|
+
raw_model = @model.model
|
91
|
+
#destroy does not work when using datamapper and have associations but destroy! works fine
|
92
|
+
#destroy! does not exist in ActiveRecord
|
93
|
+
if defined?(raw_model.destroy!)
|
94
|
+
@result = raw_model.destroy! #data mapper
|
95
|
+
else
|
96
|
+
@result = raw_model.destroy #active record
|
97
|
+
end
|
98
|
+
if @result
|
99
|
+
flash.now[:notice] = "#{@klass.humanized_name(:singular)} deleted successfully."
|
100
|
+
redirect_to @klass.search_path
|
101
|
+
else
|
102
|
+
flash.now[:alert] = "#{@klass.humanized_name(:singular)} was NOT deleted."
|
103
|
+
render(:show)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
92
107
|
def action
|
93
108
|
@response = @action.perform(@arguments)
|
94
109
|
|
@@ -128,9 +143,13 @@ module Upmin
|
|
128
143
|
@klass = Upmin::Model.find_class(params[:klass])
|
129
144
|
end
|
130
145
|
|
146
|
+
def set_klasses
|
147
|
+
@klasses = Upmin::Model.find_class(params[:klass])
|
148
|
+
end
|
149
|
+
|
131
150
|
def set_action
|
132
|
-
action_name = params[:method]
|
133
|
-
@action = @model.actions.select{ |action| action.name == action_name }.first
|
151
|
+
action_name = params[:method]
|
152
|
+
@action = @model.actions.select{ |action| action.name.to_s == action_name }.first
|
134
153
|
|
135
154
|
raise Upmin::InvalidAction.new(params[:method]) unless @action
|
136
155
|
end
|
@@ -1,16 +1,20 @@
|
|
1
1
|
!!!
|
2
2
|
%html
|
3
3
|
%head
|
4
|
+
%meta{ name: "viewport", content: "width=device-width, initial-scale=1.0" }
|
4
5
|
%title
|
5
6
|
Upmin Dashboard
|
6
7
|
= stylesheet_link_tag("upmin/application", media: "all")
|
8
|
+
%script{src: "//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"}
|
7
9
|
= javascript_include_tag("upmin/application")
|
8
10
|
= csrf_meta_tags
|
9
11
|
|
10
|
-
%link{href: "//cdn.jsdelivr.net/bootstrap/3.2.0/css/bootstrap.min.css", rel: "stylesheet"
|
11
|
-
|
12
|
+
%link{href: "//cdn.jsdelivr.net/bootstrap/3.2.0/css/bootstrap.min.css", rel: "stylesheet"}
|
13
|
+
-#%link{href: "//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css", rel: "stylesheet"}
|
12
14
|
%script{src: "//cdn.jsdelivr.net/bootstrap/3.2.0/js/bootstrap.min.js"}
|
13
15
|
%script{src: "//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"}
|
16
|
+
-# TODO (matt): Only include this on the dashboard page:
|
17
|
+
= javascript_include_tag "//www.google.com/jsapi", "chartkick"
|
14
18
|
|
15
19
|
- if content_for?(:head)
|
16
20
|
= yield(:head)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-limit ||= 30
|
2
|
+
.col-sm-6.col-md-4
|
3
|
+
.panel.panel-default
|
4
|
+
.panel-heading
|
5
|
+
#{model.humanized_name} created per #{model.model_class.grouping limit}
|
6
|
+
.panel-body
|
7
|
+
= column_chart model.model_class.group_by_best_fit limit
|
8
|
+
.panel-footer
|
9
|
+
Number of #{model.model_name.plural} created per #{model.model_class.grouping limit}, for all #{model.count} records.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-if defined?(DataMapper)
|
2
|
+
.container
|
3
|
+
.row
|
4
|
+
.jumbotron
|
5
|
+
%h2
|
6
|
+
Sorry, the default dashboard doesn't support DataMapper
|
7
|
+
%p
|
8
|
+
Please create a custom dashboard view in:
|
9
|
+
%code
|
10
|
+
app/views/upmin/dashboard/index.html.[haml|erb|etc]
|
11
|
+
-else
|
12
|
+
.container-fluid
|
13
|
+
.row
|
14
|
+
= render partial: 'chart', collection: @models, as: 'model', locals: { limit: 30 }
|
@@ -1,13 +1,29 @@
|
|
1
1
|
.container
|
2
|
+
- if notice
|
3
|
+
.alert.alert-dismissable.alert-info
|
4
|
+
%button.close{"data-dismiss" => "alert", type: "button"}
|
5
|
+
%span{"aria-hidden" => "true"} ×
|
6
|
+
= notice
|
7
|
+
- if alert
|
8
|
+
.alert.alert-dismissable.alert-danger
|
9
|
+
%button.close{"data-dismiss" => "alert", type: "button"}
|
10
|
+
%span{"aria-hidden" => "true"} ×
|
11
|
+
= alert
|
12
|
+
- if @model.errors.any?
|
13
|
+
%ul
|
14
|
+
- @model.errors.each do |field, error|
|
15
|
+
%li
|
16
|
+
%b
|
17
|
+
= field
|
18
|
+
= error
|
2
19
|
.row
|
3
20
|
.col-md-8
|
21
|
+
.page-entries-info
|
22
|
+
= page_entries_info(@query.paginated_results)
|
4
23
|
= up_paginate(@query.paginated_results)
|
5
|
-
-# TODO(jon): Add pagination w/ search results
|
6
24
|
= up_render(@query)
|
7
|
-
%br
|
8
25
|
= up_paginate(@query.paginated_results)
|
9
|
-
|
10
|
-
%br
|
26
|
+
|
11
27
|
.col-md-4
|
12
28
|
-# TODO(jon): Implement up_search_box
|
13
29
|
= up_render(@klass)
|
@@ -2,9 +2,4 @@
|
|
2
2
|
%label{for: attribute.form_id}
|
3
3
|
= attribute.label_name
|
4
4
|
|
5
|
-
|
6
|
-
= f.check_box(attribute.name, value: boolean, class: "boolean")
|
7
|
-
|
8
|
-
- else
|
9
|
-
%p.well
|
10
|
-
= attribute.value
|
5
|
+
= form_builder.check_box(attribute.name, value: boolean, class: "boolean", disabled: !attribute.editable?)
|