upmin-admin 0.0.39 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -14
  3. data/Rakefile +24 -15
  4. data/app/assets/javascripts/upmin/application.js +0 -1
  5. data/app/assets/stylesheets/upmin/base.css.scss +4 -0
  6. data/app/assets/stylesheets/upmin/instances.css.scss +11 -1
  7. data/app/controllers/upmin/models_controller.rb +52 -42
  8. data/app/views/layouts/upmin/_navbar.html.haml +3 -3
  9. data/app/views/layouts/upmin/application.html.haml +2 -1
  10. data/app/views/upmin/models/new.html.haml +3 -3
  11. data/app/views/upmin/models/search.html.haml +5 -4
  12. data/app/views/upmin/models/show.html.haml +3 -3
  13. data/app/views/upmin/partials/actions/_action.html.haml +6 -21
  14. data/app/views/upmin/partials/associations/_associations.html.haml +8 -10
  15. data/app/views/upmin/partials/attributes/_boolean.html.haml +8 -6
  16. data/app/views/upmin/partials/attributes/_datetime.html.haml +38 -36
  17. data/app/views/upmin/partials/attributes/_decimal.html.haml +10 -0
  18. data/app/views/upmin/partials/attributes/_float.html.haml +10 -6
  19. data/app/views/upmin/partials/attributes/_integer.html.haml +10 -6
  20. data/app/views/upmin/partials/attributes/_progress_bar.html.haml +1 -0
  21. data/app/views/upmin/partials/attributes/_string.html.haml +17 -6
  22. data/app/views/upmin/partials/attributes/_text.html.haml +8 -6
  23. data/app/views/upmin/partials/attributes/_unknown.html.haml +5 -3
  24. data/app/views/upmin/partials/models/_model.html.haml +18 -46
  25. data/app/views/upmin/partials/models/_new_model.html.haml +9 -31
  26. data/app/views/upmin/partials/parameters/_block_parameter.haml +0 -0
  27. data/app/views/upmin/partials/parameters/_opt_parameter.html.haml +14 -0
  28. data/app/views/upmin/partials/parameters/_req_parameter.html.haml +4 -0
  29. data/app/views/upmin/partials/search_boxes/_ransack_search_box.html.haml +2 -3
  30. data/app/views/upmin/partials/search_results/_results.html.haml +9 -2
  31. data/lib/upmin/action.rb +50 -0
  32. data/lib/upmin/active_record/association.rb +47 -0
  33. data/lib/upmin/active_record/model.rb +54 -0
  34. data/lib/upmin/active_record/query.rb +12 -0
  35. data/lib/upmin/admin.rb +24 -2
  36. data/lib/upmin/association.rb +73 -0
  37. data/lib/upmin/attribute.rb +87 -0
  38. data/lib/upmin/automatic_delegation.rb +76 -0
  39. data/lib/upmin/configuration.rb +103 -0
  40. data/lib/upmin/data_mapper/association.rb +57 -0
  41. data/lib/upmin/data_mapper/model.rb +62 -0
  42. data/lib/upmin/data_mapper/query.rb +57 -0
  43. data/lib/upmin/engine.rb +2 -0
  44. data/lib/upmin/errors.rb +43 -0
  45. data/lib/upmin/model.rb +267 -98
  46. data/lib/upmin/parameter.rb +43 -0
  47. data/lib/upmin/query.rb +51 -0
  48. data/lib/upmin/railtie.rb +11 -1
  49. data/lib/upmin/railties/active_record.rb +5 -50
  50. data/lib/upmin/railties/data_mapper.rb +18 -0
  51. data/lib/upmin/railties/render.rb +34 -98
  52. data/lib/upmin/railties/render_helpers.rb +119 -53
  53. data/lib/upmin/version.rb +1 -1
  54. data/spec/factories/factories.rb +6 -0
  55. data/spec/features/action_spec.rb +39 -46
  56. data/spec/features/edit_model_spec.rb +4 -2
  57. data/spec/features/navbar_spec.rb +48 -0
  58. data/spec/features/new_model_spec.rb +1 -0
  59. data/spec/features/search_spec.rb +7 -4
  60. data/spec/lib/configuration_spec.rb +60 -0
  61. data/spec/spec_helper.rb +14 -8
  62. metadata +25 -7
  63. data/app/assets/javascripts/upmin/moment.js +0 -2856
  64. data/app/helpers/upmin/instances_helper.rb +0 -13
  65. data/app/views/upmin/partials/attributes/_nilable.html.haml +0 -14
  66. data/app/views/upmin/partials/search_results/_result.html.haml +0 -8
  67. data/lib/upmin/klass.rb +0 -170
@@ -1,2 +1,9 @@
1
- - results.each do |result|
2
- = up_search_result(result)
1
+ - query.upmin_results.each do |result|
2
+ %a.search-result-link{href: result.path}
3
+ .upmin-model{class: result.color}
4
+ %dl.dl-horizontal
5
+ - result.attributes.each do |attribute|
6
+ %dt
7
+ = attribute.label_name
8
+ %dd
9
+ = attribute.value
@@ -0,0 +1,50 @@
1
+ module Upmin
2
+ class Action
3
+ include Upmin::AutomaticDelegation
4
+
5
+ attr_reader :model
6
+ attr_reader :name
7
+
8
+ def initialize(model, action_name, options = {})
9
+ @model = model
10
+ @name = action_name.to_sym
11
+ end
12
+
13
+ def title
14
+ return name.to_s.humanize
15
+ end
16
+
17
+ def path
18
+ return upmin_action_path(klass: model.model_class_name, id: model.id, method: name)
19
+ end
20
+
21
+ def parameters
22
+ return @parameters if defined?(@parameters)
23
+ @parameters = []
24
+ model.method(name).parameters.each do |param_type, param_name|
25
+ @parameters << Upmin::Parameter.new(self, param_name, type: param_type)
26
+ end
27
+ return @parameters
28
+ end
29
+ alias_method :arguments, :parameters
30
+
31
+ def perform(arguments)
32
+ array = []
33
+ parameters.each do |parameter|
34
+ if parameter.type == :req
35
+ unless arguments[parameter.name]
36
+ raise Upmin::MissingArgument.new(parameter.name)
37
+ end
38
+ array << arguments[parameter.name]
39
+ elsif parameter.type == :opt
40
+ array << arguments[parameter.name] if arguments[parameter.name]
41
+ else # :block - skip it
42
+ end
43
+ end
44
+ return model.send(name, *array)
45
+ end
46
+
47
+ private
48
+
49
+ end
50
+ end
@@ -0,0 +1,47 @@
1
+ module Upmin::ActiveRecord
2
+ module Association
3
+
4
+ def type
5
+ return @type if defined?(@type)
6
+
7
+ if reflection
8
+ @type = reflection.foreign_type.to_s.gsub(/_type$/, "")
9
+ if collection?
10
+ @type = @type.pluralize.to_sym
11
+ else
12
+ @type = @type.to_sym
13
+ end
14
+ else
15
+ @type = :unknown
16
+ end
17
+
18
+ if @type == :unknown
19
+ @type = infer_type_from_value
20
+ end
21
+
22
+ return @type
23
+ end
24
+
25
+ def collection?
26
+ if reflection
27
+ return reflection.collection?
28
+ elsif value
29
+ return value.responds_to?(:each)
30
+ else
31
+ return false
32
+ end
33
+ end
34
+
35
+
36
+ private
37
+
38
+ def reflection
39
+ return @reflection if defined?(@reflection)
40
+ @reflection = model.model_class.reflect_on_all_associations.select do |r|
41
+ r.name == name
42
+ end.first
43
+ return @reflection
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,54 @@
1
+ module Upmin::ActiveRecord
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+
5
+ def new_record?
6
+ return model.new_record?
7
+ end
8
+
9
+ def to_key
10
+ return model.to_key
11
+ end
12
+
13
+
14
+ module ClassMethods
15
+ # NOTE - ANY method added here must be added to the bottom of
16
+ # Upmin::Model. This ensures that an instance of the class was
17
+ # created, which in turn ensures that the correct module was
18
+ # included in the class.
19
+
20
+ def find(*args)
21
+ return model_class.find(*args)
22
+ end
23
+
24
+ def default_attributes
25
+ return model_class.attribute_names.map(&:to_sym)
26
+ end
27
+
28
+ def attribute_type(attribute)
29
+ adapter = model_class.columns_hash[attribute.to_s]
30
+ return adapter.type if adapter
31
+ return :unknown
32
+ end
33
+
34
+ def associations
35
+ return @associations if defined?(@associations)
36
+
37
+ all = []
38
+ ignored = []
39
+ model_class.reflect_on_all_associations.each do |reflection|
40
+ all << reflection.name.to_sym
41
+
42
+ # We need to remove the ignored later because we don't know the order they come in.
43
+ if reflection.is_a?(::ActiveRecord::Reflection::ThroughReflection)
44
+ ignored << reflection.options[:through]
45
+ end
46
+ end
47
+
48
+ return @associations = (all - ignored).uniq
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ module Upmin::ActiveRecord
2
+ module Query
3
+
4
+ def results
5
+ return klass.model_class.ransack(search_options).result(distinct: true)
6
+ end
7
+
8
+ private
9
+
10
+
11
+ end
12
+ end
@@ -1,12 +1,30 @@
1
1
  require "upmin"
2
2
  require "upmin/engine"
3
3
 
4
- require "upmin/klass"
4
+ require "upmin/automatic_delegation"
5
+ require "upmin/configuration"
6
+ require "upmin/errors"
7
+ require "upmin/paginator"
8
+
5
9
  require "upmin/model"
10
+ require "upmin/attribute"
11
+ require "upmin/association"
12
+ require "upmin/action"
13
+ require "upmin/parameter"
14
+ require "upmin/query"
6
15
 
7
- require "upmin/paginator"
16
+ # ActiveRecord Specifics.
17
+ if defined?(ActiveRecord)
18
+ Dir["#{File.dirname(__FILE__)}/active_record/**/*.rb"].each { |f| require f }
19
+ end
20
+
21
+ # DataMapper Specifics
22
+ if defined?(DataMapper)
23
+ Dir["#{File.dirname(__FILE__)}/data_mapper/**/*.rb"].each { |f| require f }
24
+ end
8
25
 
9
26
  # Monkey patch code into rails
27
+ require "upmin/railties/data_mapper"
10
28
  require "upmin/railties/active_record"
11
29
  require "upmin/railties/paginator"
12
30
  require "upmin/railties/render"
@@ -19,6 +37,9 @@ require "ransack"
19
37
  require "haml"
20
38
  require "sass-rails"
21
39
 
40
+
41
+ require "ostruct"
42
+
22
43
  # If WillPaginate is present we just use it, but by default upmin-admin uses Kaminari
23
44
  require "kaminari" unless defined?(WillPaginate)
24
45
 
@@ -28,3 +49,4 @@ module Upmin
28
49
  module Admin
29
50
  end
30
51
  end
52
+
@@ -0,0 +1,73 @@
1
+ module Upmin
2
+ class Association
3
+ attr_reader :model
4
+ attr_reader :name
5
+
6
+ def initialize(model, assoc_name, options = {})
7
+ if model.class.active_record?
8
+ extend Upmin::ActiveRecord::Association
9
+ elsif model.class.data_mapper?
10
+ extend Upmin::DataMapper::Association
11
+ else
12
+ raise ArgumentError.new(model)
13
+ end
14
+
15
+ @model = model
16
+ @name = assoc_name.to_sym
17
+ end
18
+
19
+ def value
20
+ # TODO(jon): Add some way to handle exceptions.
21
+ return model.send(name)
22
+ end
23
+
24
+ def title
25
+ return name.to_s.humanize
26
+ end
27
+
28
+ def upmin_values(options = {})
29
+ options[:limit] ||= 5
30
+ if collection?
31
+ vals = [value.limit(options[:limit])].flatten
32
+ else
33
+ vals = [value]
34
+ end
35
+
36
+ return vals.map(&:upmin_model)
37
+ end
38
+
39
+ def type
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def collection?
44
+ raise NotImplementedError
45
+ end
46
+
47
+ def empty?
48
+ if collection?
49
+ return value.count == 0
50
+ else
51
+ return ![value].flatten.any?
52
+ end
53
+ end
54
+
55
+
56
+
57
+ private
58
+
59
+ def infer_type_from_value
60
+ if first = [value].flatten.first
61
+ type = first.class.name.underscore
62
+ if collection?
63
+ return type.pluralize.to_sym
64
+ else
65
+ return type.to_sym
66
+ end
67
+ else
68
+ return :unknown
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,87 @@
1
+ module Upmin
2
+ class Attribute
3
+ attr_reader :model
4
+ attr_reader :name
5
+
6
+ def initialize(model, attr_name, options = {})
7
+ @model = model
8
+ @name = attr_name.to_sym
9
+ end
10
+
11
+ def value
12
+ # TODO(jon): Add some way to handle exceptions.
13
+ return model.send(name)
14
+ end
15
+
16
+ def type
17
+ # TODO(jon): Add a way to override with widgets?
18
+ return @type if defined?(@type)
19
+
20
+ # Try to get it from the model_class
21
+ @type = model.class.attribute_type(name)
22
+
23
+ # If we still don't know the type, try to infer it from the value
24
+ if @type == :unknown
25
+ @type = infer_type_from_value
26
+ end
27
+
28
+ return @type
29
+ end
30
+
31
+ def editable?
32
+ case name.to_sym
33
+ when :id
34
+ return false
35
+ when :created_at
36
+ return false
37
+ when :created_on
38
+ return false
39
+ when :updated_at
40
+ return false
41
+ when :updated_on
42
+ return false
43
+ else
44
+ # TODO(jon): Add a way to declare which attributes are editable and which are not later.
45
+ return model.respond_to?("#{name}=")
46
+ end
47
+ end
48
+
49
+ def errors?
50
+ return model.errors[name].any?
51
+ end
52
+
53
+ def label_name
54
+ return name.to_s.gsub(/_/, " ").capitalize
55
+ end
56
+
57
+ def form_id
58
+ return "#{model.underscore_name}_#{name}"
59
+ end
60
+
61
+ def nilable_id
62
+ return "#{form_id}_is_nil"
63
+ end
64
+
65
+
66
+ private
67
+
68
+ def infer_type_from_value
69
+ class_sym = value.class.to_s.underscore.to_sym
70
+ if class_sym == :false_class || class_sym == :true_class
71
+ return :boolean
72
+ elsif class_sym == :nil_class
73
+ return :unknown
74
+ elsif class_sym == :fixnum
75
+ return :integer
76
+ elsif class_sym == :big_decimal
77
+ return :decimal
78
+ elsif class_sym == :"active_support/time_with_zone"
79
+ return :datetime
80
+ else
81
+ # This should prevent any classes from being skipped, but we may not have an exhaustive list yet.
82
+ return class_sym
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,76 @@
1
+ module Upmin
2
+ module AutomaticDelegation
3
+ extend ActiveSupport::Concern
4
+
5
+ # Delegates missing instance methods to the source model.
6
+ def method_missing(method, *args, &block)
7
+ if delegatable?(method)
8
+ self.class.delegate(method, to: :model)
9
+ send(method, *args, &block)
10
+ else
11
+ return super
12
+ end
13
+ end
14
+
15
+ def delegatable?(method)
16
+ return model.respond_to?(method)
17
+ end
18
+
19
+ def delegated?(method)
20
+ return self.class.delegated?(method)
21
+ end
22
+
23
+ def respond_to?(method)
24
+ super || delegatable?(method)
25
+ end
26
+
27
+ def method(method_name)
28
+ if delegated?(method_name)
29
+ return model.method(method_name)
30
+ else
31
+ return super(method_name)
32
+ end
33
+ rescue NameError => e
34
+ if delegatable?(method_name)
35
+ self.class.delegate(method_name, to: :model)
36
+ return method(method_name)
37
+ else
38
+ super(method_name)
39
+ end
40
+ end
41
+
42
+ module ClassMethods
43
+ # Proxies missing class methods to the source class.
44
+ def method_missing(method, *args, &block)
45
+ return super unless delegatable?(method)
46
+
47
+ model_class.send(method, *args, &block)
48
+ end
49
+
50
+ def delegatable?(method)
51
+ @test ||={}
52
+ @test[method] ||= 0
53
+ @test[method] += 1
54
+ return false if @test[method] > 2
55
+ model_class? && model_class.respond_to?(method)
56
+ end
57
+
58
+ def delegate(method, *args)
59
+ @delegated ||= []
60
+ @delegated << method.to_sym
61
+ super(method, *args)
62
+ end
63
+
64
+ def delegated?(method)
65
+ @delegated ||= []
66
+ return @delegated.include?(method.to_sym)
67
+ end
68
+
69
+ # Avoids reloading the model class when ActiveSupport clears autoloaded
70
+ # dependencies in development mode.
71
+ def before_remove_const
72
+ end
73
+ end
74
+
75
+ end
76
+ end