upmin-admin 0.0.39 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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