upmin-admin 0.0.38 → 0.0.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -0
  3. data/Rakefile +66 -23
  4. data/app/assets/stylesheets/upmin/actions.css.scss +6 -0
  5. data/app/assets/stylesheets/upmin/attributes.css.scss +0 -1
  6. data/app/assets/stylesheets/upmin/base.css.scss +18 -0
  7. data/app/controllers/upmin/models_controller.rb +62 -3
  8. data/app/views/upmin/models/new.html.haml +21 -0
  9. data/app/views/upmin/models/search.html.haml +6 -1
  10. data/app/views/upmin/models/show.html.haml +2 -2
  11. data/app/views/upmin/partials/actions/_action.html.haml +13 -2
  12. data/app/views/upmin/partials/attributes/_nilable.html.haml +14 -0
  13. data/app/views/upmin/partials/models/_model.html.haml +7 -2
  14. data/app/views/upmin/partials/models/_new_model.html.haml +44 -0
  15. data/config/routes.rb +5 -2
  16. data/lib/upmin/admin.rb +2 -0
  17. data/lib/upmin/klass.rb +5 -0
  18. data/lib/upmin/model.rb +4 -0
  19. data/lib/upmin/paginator.rb +1 -1
  20. data/lib/upmin/railties/active_record.rb +8 -7
  21. data/lib/upmin/railties/render_helpers.rb +6 -4
  22. data/lib/upmin/version.rb +1 -1
  23. data/spec/factories/factories.rb +16 -0
  24. data/spec/features/action_spec.rb +68 -0
  25. data/spec/features/edit_model_spec.rb +74 -0
  26. data/spec/features/new_model_spec.rb +68 -0
  27. data/spec/features/search_spec.rb +77 -0
  28. data/spec/spec_helper.rb +51 -0
  29. metadata +91 -78
  30. data/test/controllers/upmin/model_controller_test.rb +0 -11
  31. data/test/dummy/README.rdoc +0 -28
  32. data/test/dummy/Rakefile +0 -6
  33. data/test/dummy/app/assets/javascripts/application.js +0 -13
  34. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  35. data/test/dummy/app/controllers/application_controller.rb +0 -5
  36. data/test/dummy/app/helpers/application_helper.rb +0 -2
  37. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  38. data/test/dummy/bin/bundle +0 -3
  39. data/test/dummy/bin/rails +0 -4
  40. data/test/dummy/bin/rake +0 -4
  41. data/test/dummy/config.ru +0 -4
  42. data/test/dummy/config/application.rb +0 -23
  43. data/test/dummy/config/boot.rb +0 -5
  44. data/test/dummy/config/database.yml +0 -25
  45. data/test/dummy/config/environment.rb +0 -5
  46. data/test/dummy/config/environments/development.rb +0 -37
  47. data/test/dummy/config/environments/production.rb +0 -83
  48. data/test/dummy/config/environments/test.rb +0 -39
  49. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  50. data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  51. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  52. data/test/dummy/config/initializers/inflections.rb +0 -16
  53. data/test/dummy/config/initializers/mime_types.rb +0 -4
  54. data/test/dummy/config/initializers/session_store.rb +0 -3
  55. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  56. data/test/dummy/config/locales/en.yml +0 -23
  57. data/test/dummy/config/routes.rb +0 -4
  58. data/test/dummy/config/secrets.yml +0 -22
  59. data/test/dummy/public/404.html +0 -67
  60. data/test/dummy/public/422.html +0 -67
  61. data/test/dummy/public/500.html +0 -66
  62. data/test/dummy/public/favicon.ico +0 -0
  63. data/test/helpers/upmin/model_helper_test.rb +0 -6
  64. data/test/integration/navigation_test.rb +0 -10
  65. data/test/test_helper.rb +0 -15
  66. data/test/upmin_test.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6bd7cc2583a8e2019373b7628b6fee2ff186c526
4
- data.tar.gz: f7f129e4e4f4e2691c9822d9cff24cffdccddd56
3
+ metadata.gz: 43ba30f61892c0d1f5983de9ad8ddc6f09f3b804
4
+ data.tar.gz: a3af7bbf0251feec69f0b8c68327bf314a976bfe
5
5
  SHA512:
6
- metadata.gz: 03e51d88c3c4552e02605da44b6cae42a70c0f86f8bcbeab1950c199d063ca6c5cf2757550525ee16ee3624bc1914f1bd52f6cec69ff7cb0e458f1def3c0cd76
7
- data.tar.gz: 40284c1fe7e51a3acd9d1b13397548db8d695648dbc0aa74fa97089f8f27992b372eec98adb87e06116173f5985c0541d09c2569a833df60843dc4e93fb7a9f7
6
+ metadata.gz: 329aa9e96c2172c45fc7b130e473d614ccb70452b3f57fb507b5ec231cb3a22528b410dbd6040edb1bff61e62c46f3c9a506a0948966cee5f4abeb0c94f65391
7
+ data.tar.gz: d706420835d063d0bac98ca9a3bc7af161a694f23ef6f8b1068d1e416e2cfa4597ad15b9fc9124eb1b8c547901b50738880bc37720165005f46df4d5b217c735
@@ -0,0 +1,71 @@
1
+ # Upmin Admin
2
+
3
+ Upmin Admin is a framework for creating powerful admin backends with minimal effort.
4
+
5
+ ## Demo Videos
6
+
7
+ 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).
8
+
9
+ ### Demo Application
10
+
11
+ 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.
12
+
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.
14
+
15
+
16
+ ## Installation
17
+
18
+ Installing `upmin-admin` is incredibly easy. Simple add the gem to your `Gemfile`:
19
+
20
+ ```ruby
21
+ gem 'upmin-admin'
22
+ ```
23
+
24
+ And then mount the engine in your `routes.rb` file:
25
+
26
+ ```ruby
27
+ mount Upmin::Engine => '/admin'
28
+ ```
29
+
30
+ Authentication is currently supported with an existing Devise install. Simply use something like this:
31
+
32
+ ```ruby
33
+ authenticate :user, lambda { |u| u.admin? } do
34
+ mount Upmin::Engine => '/admin'
35
+ end
36
+ ```
37
+
38
+ ### Rails 4.2
39
+
40
+ Add the following to your gemfile:
41
+
42
+ ```ruby
43
+ gem 'ransack', github: 'activerecord-hackery/ransack', branch: 'rails-4.2'
44
+ ```
45
+
46
+ `upmin-admin` currently depends on ransack, and you need to use the 4.2 branch of ransack due to changes in ActiveRecord.
47
+
48
+ ## Documentation
49
+
50
+ We are currently working on the docs on our [Wiki](https://github.com/upmin/upmin-admin-ruby/wiki), but they are far from complete so if you have any trouble or can't find the documentation to do something please let us know via email - [support@upmin.com](support@upmin.com) or chat with us on [HipChat](http://www.hipchat.com/gvREostp6).
51
+
52
+
53
+ ## Going Forward
54
+
55
+ There are a lot of things that need built going forward and we are looking for anyone who wants to get involved. Just hop in our hipchat (link below) or email us (link also below).
56
+
57
+ The major features that are being worked on now are:
58
+
59
+ 1. DataMapper support
60
+ 2. Fixing bugs - specifically ones like ActsAsTaggable causing the menu to have far too many models.
61
+ 3. Implementing the Dashboard
62
+ 4. Adding useful widgets, such as an EasyPost Tracking label widget, a Stripe Card widget, and other commonly used APIs, as well as Map widgets for plotting routes or just showing a location.
63
+
64
+
65
+ ## Support & Feedback
66
+
67
+ The goal of Upmin is to make it easier to build admin pages with minimal effort. With that in mind, we are always looking for feedback and suggestions. You can get in touch several ways.
68
+
69
+ Email - [support@upmin.com](support@upmin.com)
70
+
71
+ Chat - [http://www.hipchat.com/gvREostp6](http://www.hipchat.com/gvREostp6)
data/Rakefile CHANGED
@@ -1,34 +1,77 @@
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
1
+ #!/usr/bin/env rake
2
+ # encoding: utf-8
3
+
4
+ require 'bundler'
5
+ Bundler::GemHelper.install_tasks
6
6
 
7
- require 'rdoc/task'
7
+ require 'rspec/core'
8
+ require 'rspec/core/rake_task'
8
9
 
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Upmin'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
10
+ RSpec::Core::RakeTask.new(:spec) do |spec|
11
+ spec.pattern = FileList['spec/**/*_spec.rb']
15
12
  end
16
13
 
17
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
- load 'rails/tasks/engine.rake'
14
+ task :default => "spec:all"
19
15
 
16
+ namespace :spec do
17
+ # Full bundle install & test.
18
+ %w(active_record_32 active_record_40 active_record_41 active_record_42 will_paginate).each do |gemfile|
19
+ desc "Run Tests against #{gemfile}"
20
+ task "#{gemfile}" do
21
+ Dir.chdir("test_apps/#{gemfile}")
22
+ puts "Testing in #{`pwd`}"
23
+ sh "bundle install --quiet"
24
+ sh "bundle update --quiet"
20
25
 
26
+ # Drop migrations and recreate
27
+ sh "rm -rf db/migrate/*"
28
+ sh "bundle exec rake railties:install:migrations --quiet"
21
29
 
22
- Bundler::GemHelper.install_tasks
30
+ if gemfile == "active_record_32"
31
+ sh "bundle exec rake db:drop db:create db:migrate --quiet"
32
+ end
23
33
 
24
- require 'rake/testtask'
34
+ sh "RAILS_ENV=test bundle exec rake db:drop db:create db:migrate --quiet"
25
35
 
26
- Rake::TestTask.new(:test) do |t|
27
- t.libs << 'lib'
28
- t.libs << 'test'
29
- t.pattern = 'test/**/*_test.rb'
30
- t.verbose = false
31
- end
36
+ # Drop and reload spec files
37
+ sh "rm -rf spec/"
38
+ sh "cp -R ../../spec spec"
39
+ sh "cp ../../.rspec .rspec"
40
+
41
+ # Run tests
42
+ sh "bundle exec rake"
43
+ end
44
+ end
32
45
 
46
+ # Use existing models & install and just rake.
47
+ %w(active_record_32 active_record_40 active_record_41 active_record_42 will_paginate).each do |gemfile|
48
+ desc "Run Tests against #{gemfile}"
49
+ task "#{gemfile}_quick" do
50
+ Dir.chdir("test_apps/#{gemfile}")
51
+ puts "Re-testing in #{`pwd`}. Bundle install and migration updates will NOT happen!"
33
52
 
34
- task default: :test
53
+ # Drop and reload spec files
54
+ sh "rm -rf spec/"
55
+ sh "cp -R ../../spec spec"
56
+ sh "cp ../../.rspec .rspec"
57
+
58
+ # Run tests
59
+ sh "bundle exec rake"
60
+ end
61
+ end
62
+
63
+ desc "Run Tests against all ORMs"
64
+ task :all do
65
+ %w(active_record_32 active_record_40 active_record_41 active_record_42 will_paginate).each do |gemfile|
66
+ sh "rake spec:#{gemfile}"
67
+ end
68
+ end
69
+
70
+ desc "Run Tests against all ORMs"
71
+ task :all_quick do
72
+ %w(active_record_32 active_record_40 active_record_41 active_record_42 will_paginate).each do |gemfile|
73
+ sh "rake spec:#{gemfile}_quick"
74
+ end
75
+ end
76
+
77
+ end
@@ -0,0 +1,6 @@
1
+ .action-well input.boolean {
2
+ float: left;
3
+ height: auto;
4
+ margin: 4px 8px;
5
+ clear:both;
6
+ }
@@ -5,7 +5,6 @@
5
5
  clear:both;
6
6
  }
7
7
 
8
-
9
8
  ol.progbar {
10
9
  margin: 0 0 50px 0;
11
10
  padding: 0;
@@ -35,6 +35,24 @@ body {
35
35
  }
36
36
  }
37
37
 
38
+ .nilable-addon {
39
+ .form-group {
40
+ margin-bottom: 0;
41
+ }
42
+ label {
43
+ padding-top: 6px;
44
+ padding-left: 28px;
45
+ }
46
+ input[type=checkbox] {
47
+ margin-top: -17px !important;
48
+ }
49
+ }
50
+
51
+ .new-button-wrapper {
52
+ padding-top: 8px;
53
+ }
54
+
55
+
38
56
  .wizard span {padding: 12px 12px 10px 12px; margin-right:5px; background:#efefef; position:relative; display:inline-block; }
39
57
  .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;}
40
58
  .wizard span:after {width:0px; height:0px; border-top: 20px inset transparent; border-bottom: 20px inset transparent; border-left: 20px solid #efefef; position: absolute; content: ""; top: 0; right: -20px; z-index:2;}
@@ -2,7 +2,7 @@ require_dependency "upmin/application_controller"
2
2
 
3
3
  module Upmin
4
4
  class ModelsController < ApplicationController
5
- before_filter :set_klass, only: [:show, :update, :search, :action]
5
+ before_filter :set_klass, only: [:new, :create, :show, :update, :search, :action]
6
6
  before_filter :set_model, only: [:show, :update, :action]
7
7
 
8
8
  before_filter :set_page, only: [:search]
@@ -17,6 +17,49 @@ module Upmin
17
17
  def show
18
18
  end
19
19
 
20
+ # GET /:model_name/new
21
+ def new
22
+ @model = @klass.new
23
+ end
24
+
25
+ # POST /:model_name
26
+ def create
27
+ @model = @klass.new
28
+ instance = @model.instance
29
+
30
+ args = params[@klass.name.underscore]
31
+ transforms = args.delete(:transforms) || {}
32
+
33
+ args.each do |key, value|
34
+ # TODO(jon): Figure out a better way to do transforms.
35
+ # This could cause issues and is exploitable, but it
36
+ # should be fine for now since this is only on admin pages
37
+ if transforms[key] and not value.blank?
38
+ value = transform(transforms, key, value)
39
+ end
40
+
41
+ # TODO(jon): Remove duplicate code between update and create
42
+ if args["#{key}_is_nil"] == "1"
43
+ instance.send("#{key}=", nil)
44
+ else
45
+ if key.ends_with?("_is_nil")
46
+ # Skip this, since we use the non _is_nil arg.
47
+ else
48
+ instance.send("#{key}=", value)
49
+ end
50
+ end
51
+ end
52
+
53
+ if instance.save
54
+ flash[:notice] = "#{@klass.humanized_name(:singular)} created successfully with id=#{instance.id}."
55
+ redirect_to(upmin_model_path(@model.path_hash))
56
+ else
57
+ flash.now[:alert] = "#{@klass.humanized_name(:singular)} was NOT created."
58
+ render(:new)
59
+ end
60
+ end
61
+
62
+
20
63
  # PUT /:model_name/:id
21
64
  def update
22
65
  instance = @model.instance
@@ -31,7 +74,16 @@ module Upmin
31
74
  value = transform(transforms, key, value)
32
75
  end
33
76
 
34
- instance.send("#{key}=", value)
77
+ # TODO(jon): Remove duplicate code between update and create
78
+ if updates["#{key}_is_nil"] == "1"
79
+ instance.send("#{key}=", nil)
80
+ else
81
+ if key.ends_with?("_is_nil")
82
+ # Skip this, since we use the non _is_nil arg.
83
+ else
84
+ instance.send("#{key}=", value)
85
+ end
86
+ end
35
87
  end
36
88
 
37
89
  if instance.save
@@ -76,7 +128,14 @@ module Upmin
76
128
 
77
129
  def set_arguments
78
130
  arguments = params[@method] || {}
79
- @arguments = arguments.select{|k, v| !v.empty? }
131
+ @arguments = {}
132
+ arguments.each do |k, v|
133
+ unless k.ends_with?("_is_nil")
134
+ if arguments["#{k}_is_nil"] != "1"
135
+ @arguments[k] = v
136
+ end
137
+ end
138
+ end
80
139
  end
81
140
 
82
141
  def set_page
@@ -0,0 +1,21 @@
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.instance.errors.any?
13
+ %ul
14
+ - @model.instance.errors.each do |field, error|
15
+ %li
16
+ %b
17
+ = field
18
+ = error
19
+ .row
20
+ .col-sm-12
21
+ = up_model(@model.instance)
@@ -4,9 +4,14 @@
4
4
  -# TODO(jon): Add pagination w/ search results
5
5
  = up_search_results(@q, @results)
6
6
  %br
7
- = up_paginate @results
7
+ = up_paginate(@results)
8
8
  %br
9
9
  %br
10
10
  .col-md-4
11
11
  -# TODO(jon): Implement up_search_box
12
12
  = up_search_box(@klass)
13
+ .new-button-wrapper
14
+ %a.btn.btn-block.btn-success{href: upmin_new_model_path(klass: @klass.name)}
15
+ Create a new
16
+ = @klass.humanized_name(:singular)
17
+ %br
@@ -9,9 +9,9 @@
9
9
  %button.close{"data-dismiss" => "alert", type: "button"}
10
10
  %span{"aria-hidden" => "true"} &times;
11
11
  = alert
12
- - if @instance.errors.any?
12
+ - if @model.instance.errors.any?
13
13
  %ul
14
- - @instance.errors.each do |field, error|
14
+ - @model.instance.errors.each do |field, error|
15
15
  %li
16
16
  %b
17
17
  = field
@@ -1,4 +1,4 @@
1
- .well
1
+ .well.action-well
2
2
  = form_tag(upmin_action_path(upmin_model.path_hash.merge(method: action_name))) do
3
3
  - upmin_model.action_parameters(action_name).each do |param_type, param_name|
4
4
 
@@ -6,8 +6,19 @@
6
6
 
7
7
  .form-group
8
8
  = label(action_name, param_name, param_name.to_s.capitalize.gsub("_", " "))
9
- = text_field(action_name, param_name, class: "form-control")
9
+
10
10
  - if param_type == :opt
11
+ .input-group
12
+ = text_field(action_name, param_name, class: "form-control")
13
+ .input-group-addon.nilable-addon
14
+ .form-group
15
+ %label{for: "#{action_name}_#{param_name}_is_nil"}
16
+ Do Not Provide
17
+ = check_box(action_name, "#{param_name}_is_nil", class: "boolean")
11
18
  %small
12
19
  * Optional
20
+ - else
21
+ = text_field(action_name, param_name, class: "form-control")
22
+
23
+
13
24
  = submit_tag("Submit", class: "btn btn-primary")
@@ -0,0 +1,14 @@
1
+ - if editable && f = form_builder
2
+ -# TODO(jon): Find a better place for code like this. Kinda sucks to have it in the view.
3
+ - is_nil = upmin_model.attribute(attr_name).nil? && !upmin_model.instance.new_record?
4
+ .input-group
5
+ = up_attribute(upmin_model.instance, attr_name, locals: { form_builder: form_builder })
6
+ .input-group-addon.nilable-addon
7
+ .form-group
8
+ %label{for: "#{upmin_model.klass.name.underscore}_#{attr_name}_is_nil"}
9
+ Make This Nil
10
+ = check_box(upmin_model.klass.name.underscore, "#{attr_name}_is_nil", class: "boolean", checked: is_nil, value: is_nil)
11
+
12
+ - else
13
+ %p.well
14
+ = nilable
@@ -28,12 +28,17 @@
28
28
 
29
29
  -# Render each attribute
30
30
  - upmin_model.klass.attributes.each do |attribute|
31
- .form-group
31
+ - any_errors = model.errors[attribute].any?
32
+ .form-group{class: any_errors ? "has-error" : ""}
32
33
  -# = f.label(attribute.to_s) # Not using this because it drops _id and this isn't always desirable
33
34
 
34
35
  %label{for: upmin_model.attribute_form_id(attribute)}
35
36
  = upmin_model.attribute_label_name(attribute)
36
- = up_attribute(upmin_model.instance, attribute, locals: { form_builder: f })
37
+ - if upmin_model.attribute_type(attribute) == :string
38
+ = up_attribute(upmin_model.instance, attribute, locals: { form_builder: f }, as: :nilable)
39
+ - else
40
+ = up_attribute(upmin_model.instance, attribute, locals: { form_builder: f })
41
+
37
42
 
38
43
  = f.submit("Save", class: "btn btn-primary")
39
44
 
@@ -0,0 +1,44 @@
1
+ -# The following are all available to you here:
2
+ -# unknown - This is the model passed into the up_model method.
3
+ -# This attribute is always present in any partial rendered
4
+ -# by Upmin, and will always match the name of the partial
5
+ -# *UNLESS* nil, true, or false are passed in.
6
+ -# upmin_model - This is an Upmin::Model instantiated with unknown
7
+ -# and is always present.
8
+ -#
9
+ -# In general, the upmin_model makes it significantly easier to
10
+ -# render a view, so I suggest using it. It is way simpler than
11
+ -# trying to find all associations for a model on your own.
12
+ -#
13
+ -# Just an FYI: upmin_model.instance == unknown
14
+
15
+ .upmin-model{class: upmin_model.color}
16
+ -# Display the model title as "Model # ID"
17
+ %h3
18
+ Create a
19
+ = upmin_model.klass.humanized_name(:singular)
20
+
21
+ %br
22
+ %br
23
+ %h3{style: "color: #333;"}
24
+ Attributes
25
+ %hr
26
+ -# Create a form to wrap the attributes in.
27
+ -# TODO(jon): Update the URL with a decent helper?
28
+ = form_for(upmin_model.instance, url: upmin_create_model_path(klass: @klass.name), html: { method: :post }) do |f|
29
+
30
+ -# Render each attribute
31
+ - upmin_model.klass.attributes.each do |attribute|
32
+ - any_errors = new_model.errors[attribute].any?
33
+ .form-group{class: any_errors ? "has-error" : ""}
34
+ -# = f.label(attribute.to_s) # Not using this because it drops _id and this isn't always desirable
35
+
36
+ %label{for: upmin_model.attribute_form_id(attribute)}
37
+ = upmin_model.attribute_label_name(attribute)
38
+ - if upmin_model.attribute_type(attribute) == :string
39
+ = up_attribute(upmin_model.instance, attribute, locals: { form_builder: f }, as: :nilable)
40
+ - else
41
+ = up_attribute(upmin_model.instance, attribute, locals: { form_builder: f })
42
+
43
+ = f.submit("Create", class: "btn btn-primary")
44
+