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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -18
  3. data/Rakefile +18 -18
  4. data/app/assets/javascripts/upmin/attributes/datetime.js +37 -11
  5. data/app/assets/stylesheets/upmin/application.css +0 -1
  6. data/app/assets/stylesheets/upmin/base.css.scss +8 -1
  7. data/app/assets/stylesheets/upmin/dashboard.css +16 -0
  8. data/app/assets/stylesheets/upmin/instances.css.scss +7 -0
  9. data/app/controllers/upmin/dashboard_controller.rb +11 -0
  10. data/app/controllers/upmin/models_controller.rb +28 -9
  11. data/app/views/layouts/upmin/application.html.haml +6 -2
  12. data/app/views/upmin/dashboard/_chart.html.haml +9 -0
  13. data/app/views/upmin/dashboard/index.html.haml +14 -0
  14. data/app/views/upmin/models/search.html.haml +20 -4
  15. data/app/views/upmin/partials/attributes/_boolean.html.haml +1 -6
  16. data/app/views/upmin/partials/attributes/_date.html.haml +26 -0
  17. data/app/views/upmin/partials/attributes/_enum.html.haml +9 -0
  18. data/app/views/upmin/partials/attributes/_money_cents.html.haml +10 -0
  19. data/app/views/upmin/partials/models/_model.html.haml +5 -6
  20. data/app/views/upmin/partials/models/_new_model.html.haml +1 -1
  21. data/app/views/upmin/partials/search_boxes/_ransack_search_box.html.haml +6 -1
  22. data/config/routes.rb +3 -5
  23. data/lib/generators/upmin/install_generator.rb +24 -0
  24. data/lib/generators/upmin/templates/initializer.rb +13 -0
  25. data/lib/upmin/active_record/model.rb +15 -1
  26. data/lib/upmin/admin.rb +2 -1
  27. data/lib/upmin/attribute.rb +4 -1
  28. data/lib/upmin/configuration.rb +1 -0
  29. data/lib/upmin/data_mapper/model.rb +10 -0
  30. data/lib/upmin/engine.rb +4 -3
  31. data/lib/upmin/model.rb +37 -5
  32. data/lib/upmin/railtie.rb +1 -0
  33. data/lib/upmin/railties/dashboard.rb +88 -0
  34. data/lib/upmin/railties/render_helpers.rb +2 -0
  35. data/lib/upmin/version.rb +1 -1
  36. data/spec/features/delete_model_spec.rb +38 -0
  37. data/spec/features/edit_model_spec.rb +1 -1
  38. data/spec/features/enum_attributes_spec.rb +24 -0
  39. data/spec/features/navbar_spec.rb +4 -4
  40. data/spec/features/new_model_spec.rb +1 -1
  41. data/spec/features/search_spec.rb +17 -27
  42. data/spec/lib/attribute_spec.rb +15 -0
  43. data/spec/lib/upmin/active_record/model_spec.rb +15 -0
  44. data/spec/spec_helper.rb +8 -0
  45. metadata +49 -4
  46. 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: 910d8396eb70b53feb5a498af6acc41edb1e3d1e
4
- data.tar.gz: 6e2d7366490c0dfb137a503a02fd6784111714c4
3
+ metadata.gz: 04a4f4f1edcfc6d6b2717175fcba3473962400d6
4
+ data.tar.gz: 40a38a4a7233b3a9ddb09e826731911b346c0286
5
5
  SHA512:
6
- metadata.gz: 4aea3404252228d686ed20f0a480e7d32898c70ef6edc895b387272bc14cfdb82bf6e06f8044fa15360fcf3ddc3dea147b6429c3cd6997460dff5d785e153e01
7
- data.tar.gz: bdb283f1c155465a8f94be4b5d290d21ff0c2883c9536323850b809a5e3a0223df65c2d3212f44bb073c89bd587c3b192e1d49f9ded56fe327a6dbdafc815df8
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 also a demo application you can test out here: [store_demo](https://github.com/upmin/store_demo). The repository is maintained and updated by [Upmin](https://www.upmin.com), but you are welcome to contribute to it.
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
- And then mount the engine in your `routes.rb` file:
26
+ Then run the generator:
33
27
 
34
28
  ```ruby
35
- mount Upmin::Engine => '/admin'
29
+ rails g upmin:install
36
30
  ```
37
31
 
38
- If you already have routes pointing to `/admin` you can use any path you want, for example you could use the following instead:
32
+ This mounts the engine in your `routes.rb` file:
39
33
 
40
34
  ```ruby
41
- mount Upmin::Engine => '/ice-ice-baby'
35
+ mount Upmin::Engine => '/admin'
42
36
  ```
43
37
 
44
- And you would access your admin page at `localhost:3000/ice-ice-baby` or `yoursite.com/ice-ice-baby`.
45
-
46
-
47
- ### Rails 4.2
38
+ And adds a configuration file at `config/initializers/upmin.rb`
48
39
 
49
- Add the following to your gemfile:
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
- gem 'ransack', github: 'activerecord-hackery/ransack', branch: 'rails-4.2'
43
+ mount Upmin::Engine => '/ice-ice-baby'
53
44
  ```
54
45
 
55
- `upmin-admin` currently depends on ransack, and you need to use the 4.2 branch of ransack due to changes in ActiveRecord.
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
- puts "Testing in #{`pwd`}"
40
- sh "bundle install --quiet"
41
- sh "bundle update --quiet"
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
- # Drop migrations and recreate
44
- sh "rm -rf db/migrate/*"
42
+ # Drop migrations and recreate
43
+ sh "rm -rf db/migrate/*"
45
44
 
46
- if gemfile != "data_mapper"
47
- sh "bundle exec rake railties:install:migrations > /dev/null"
48
- end
45
+ if gemfile != "data_mapper"
46
+ sh "bundle exec rake railties:install:migrations > /dev/null"
47
+ end
49
48
 
50
- if gemfile == "active_record_32"
51
- sh "bundle exec rake db:drop db:create db:migrate --quiet > /dev/null"
52
- end
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
- sh "RAILS_ENV=test bundle exec rake db:drop db:create db:migrate --quiet > /dev/null"
53
+ sh "RAILS_ENV=test bundle exec rake db:drop db:create db:migrate --quiet > /dev/null"
55
54
 
56
- update_files
55
+ update_files
57
56
 
58
- # Run tests
59
- sh "bundle exec rake"
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
- window.Upmin.Attributes.DateTime = init;
157
+
158
+ window.Upmin.Attributes.DateTime = initDateTime;
159
+ window.Upmin.Attributes.Date = initDate;
134
160
  })();
@@ -13,4 +13,3 @@
13
13
  *= require_tree .
14
14
  *= require_self
15
15
  */
16
-
@@ -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-bottom: 0px;
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;
@@ -0,0 +1,11 @@
1
+ require_dependency "upmin/application_controller"
2
+
3
+ module Upmin
4
+ class DashboardController < ApplicationController
5
+
6
+ def index
7
+ @models = Upmin::Model.all
8
+ end
9
+
10
+ end
11
+ end
@@ -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].to_sym
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", type: "text/css"}
11
- %link{href: "//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css", rel: "stylesheet"}
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"} &times;
6
+ = notice
7
+ - if alert
8
+ .alert.alert-dismissable.alert-danger
9
+ %button.close{"data-dismiss" => "alert", type: "button"}
10
+ %span{"aria-hidden" => "true"} &times;
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
- %br
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
- - if attribute.editable? && f = form_builder
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?)