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.
- checksums.yaml +4 -4
- data/README.md +25 -14
- data/Rakefile +24 -15
- data/app/assets/javascripts/upmin/application.js +0 -1
- data/app/assets/stylesheets/upmin/base.css.scss +4 -0
- data/app/assets/stylesheets/upmin/instances.css.scss +11 -1
- data/app/controllers/upmin/models_controller.rb +52 -42
- data/app/views/layouts/upmin/_navbar.html.haml +3 -3
- data/app/views/layouts/upmin/application.html.haml +2 -1
- data/app/views/upmin/models/new.html.haml +3 -3
- data/app/views/upmin/models/search.html.haml +5 -4
- data/app/views/upmin/models/show.html.haml +3 -3
- data/app/views/upmin/partials/actions/_action.html.haml +6 -21
- data/app/views/upmin/partials/associations/_associations.html.haml +8 -10
- data/app/views/upmin/partials/attributes/_boolean.html.haml +8 -6
- data/app/views/upmin/partials/attributes/_datetime.html.haml +38 -36
- data/app/views/upmin/partials/attributes/_decimal.html.haml +10 -0
- data/app/views/upmin/partials/attributes/_float.html.haml +10 -6
- data/app/views/upmin/partials/attributes/_integer.html.haml +10 -6
- data/app/views/upmin/partials/attributes/_progress_bar.html.haml +1 -0
- data/app/views/upmin/partials/attributes/_string.html.haml +17 -6
- data/app/views/upmin/partials/attributes/_text.html.haml +8 -6
- data/app/views/upmin/partials/attributes/_unknown.html.haml +5 -3
- data/app/views/upmin/partials/models/_model.html.haml +18 -46
- data/app/views/upmin/partials/models/_new_model.html.haml +9 -31
- data/app/views/upmin/partials/parameters/_block_parameter.haml +0 -0
- data/app/views/upmin/partials/parameters/_opt_parameter.html.haml +14 -0
- data/app/views/upmin/partials/parameters/_req_parameter.html.haml +4 -0
- data/app/views/upmin/partials/search_boxes/_ransack_search_box.html.haml +2 -3
- data/app/views/upmin/partials/search_results/_results.html.haml +9 -2
- data/lib/upmin/action.rb +50 -0
- data/lib/upmin/active_record/association.rb +47 -0
- data/lib/upmin/active_record/model.rb +54 -0
- data/lib/upmin/active_record/query.rb +12 -0
- data/lib/upmin/admin.rb +24 -2
- data/lib/upmin/association.rb +73 -0
- data/lib/upmin/attribute.rb +87 -0
- data/lib/upmin/automatic_delegation.rb +76 -0
- data/lib/upmin/configuration.rb +103 -0
- data/lib/upmin/data_mapper/association.rb +57 -0
- data/lib/upmin/data_mapper/model.rb +62 -0
- data/lib/upmin/data_mapper/query.rb +57 -0
- data/lib/upmin/engine.rb +2 -0
- data/lib/upmin/errors.rb +43 -0
- data/lib/upmin/model.rb +267 -98
- data/lib/upmin/parameter.rb +43 -0
- data/lib/upmin/query.rb +51 -0
- data/lib/upmin/railtie.rb +11 -1
- data/lib/upmin/railties/active_record.rb +5 -50
- data/lib/upmin/railties/data_mapper.rb +18 -0
- data/lib/upmin/railties/render.rb +34 -98
- data/lib/upmin/railties/render_helpers.rb +119 -53
- data/lib/upmin/version.rb +1 -1
- data/spec/factories/factories.rb +6 -0
- data/spec/features/action_spec.rb +39 -46
- data/spec/features/edit_model_spec.rb +4 -2
- data/spec/features/navbar_spec.rb +48 -0
- data/spec/features/new_model_spec.rb +1 -0
- data/spec/features/search_spec.rb +7 -4
- data/spec/lib/configuration_spec.rb +60 -0
- data/spec/spec_helper.rb +14 -8
- metadata +25 -7
- data/app/assets/javascripts/upmin/moment.js +0 -2856
- data/app/helpers/upmin/instances_helper.rb +0 -13
- data/app/views/upmin/partials/attributes/_nilable.html.haml +0 -14
- data/app/views/upmin/partials/search_results/_result.html.haml +0 -8
- data/lib/upmin/klass.rb +0 -170
@@ -1,2 +1,9 @@
|
|
1
|
-
-
|
2
|
-
|
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
|
data/lib/upmin/action.rb
ADDED
@@ -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
|
data/lib/upmin/admin.rb
CHANGED
@@ -1,12 +1,30 @@
|
|
1
1
|
require "upmin"
|
2
2
|
require "upmin/engine"
|
3
3
|
|
4
|
-
require "upmin/
|
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
|
-
|
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
|