super 0.0.7 → 0.0.8
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/CONTRIBUTING.md +56 -0
- data/README.md +6 -0
- data/STABILITY.md +50 -0
- data/app/assets/javascripts/super/application.js +12 -7
- data/app/controllers/super/application_controller.rb +1 -1
- data/app/views/layouts/super/application.html.erb +14 -6
- data/app/views/super/application/_super_panel.html.erb +1 -1
- data/app/views/super/application/_super_schema_display_index.html.erb +4 -4
- data/app/views/super/application/_super_schema_display_show.html.erb +3 -3
- data/app/views/super/application/_super_schema_form.html.erb +1 -1
- data/frontend/super-frontend/dist/application.js +12 -7
- data/frontend/super-frontend/src/javascripts/super/application.ts +5 -8
- data/lib/generators/super/resource/templates/resources_controller.rb.tt +1 -31
- data/lib/generators/super/webpacker/webpacker_generator.rb +3 -2
- data/lib/super.rb +11 -0
- data/lib/super/assets.rb +108 -38
- data/lib/super/configuration.rb +18 -73
- data/lib/super/controls.rb +2 -25
- data/lib/super/controls/optional.rb +41 -16
- data/lib/super/controls/required.rb +1 -29
- data/lib/super/controls/steps.rb +9 -23
- data/lib/super/display.rb +72 -0
- data/lib/super/display/guesser.rb +34 -0
- data/lib/super/display/schema_types.rb +19 -62
- data/lib/super/engine.rb +1 -1
- data/lib/super/filter.rb +5 -130
- data/lib/super/filter/form_object.rb +97 -0
- data/lib/super/filter/guesser.rb +30 -0
- data/lib/super/filter/plugin.rb +47 -0
- data/lib/super/filter/schema_types.rb +1 -7
- data/lib/super/form.rb +27 -40
- data/lib/super/form/builder.rb +48 -0
- data/lib/super/form/guesser.rb +27 -0
- data/lib/super/form/schema_types.rb +19 -29
- data/lib/super/form/strong_params.rb +29 -0
- data/lib/super/pagination.rb +10 -16
- data/lib/super/schema.rb +0 -25
- data/lib/super/schema/common.rb +25 -0
- data/lib/super/schema/guesser.rb +77 -0
- data/lib/super/version.rb +1 -1
- metadata +14 -2
@@ -1,33 +1,15 @@
|
|
1
1
|
module Super
|
2
2
|
class Display
|
3
|
-
# This schema type is meant to be used for +#index+ or +#show+ actions to
|
4
|
-
# transform database fields into something that is human friendly.
|
5
|
-
#
|
6
|
-
# ```
|
7
|
-
# class MembersController::Controls
|
8
|
-
# # ...
|
9
|
-
#
|
10
|
-
# def show_schema
|
11
|
-
# Super::Schema.new(Super::Display::SchemaTypes.new) do |fields, type|
|
12
|
-
# fields[:name] = type.dynamic { |name| name }
|
13
|
-
# fields[:rank] = type.dynamic { |rank| rank }
|
14
|
-
# fields[:position] = type.dynamic { |position| position }
|
15
|
-
# fields[:ship] = type.dynamic { |ship| "#{ship.name} (Ship ##{ship.id})" }
|
16
|
-
# fields[:created_at] = type.dynamic { |created_at| created_at.iso8601 }
|
17
|
-
# fields[:updated_at] = type.dynamic { |updated_at| updated_at.iso8601 }
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# # ...
|
22
|
-
# end
|
23
|
-
# ```
|
24
3
|
class SchemaTypes
|
25
4
|
class Dynamic
|
26
|
-
def initialize(transform_block)
|
5
|
+
def initialize(ignore_nil: true, &transform_block)
|
27
6
|
@transform_block = transform_block
|
7
|
+
@ignore_nil = ignore_nil
|
28
8
|
end
|
29
9
|
|
30
10
|
def present(value)
|
11
|
+
return nil if value.nil? && @ignore_nil
|
12
|
+
|
31
13
|
@transform_block.call(value)
|
32
14
|
end
|
33
15
|
|
@@ -51,23 +33,27 @@ module Super
|
|
51
33
|
end
|
52
34
|
end
|
53
35
|
|
54
|
-
def initialize(
|
55
|
-
@action_inquirer = action_inquirer
|
36
|
+
def initialize(fields:)
|
56
37
|
@actions_called = false
|
38
|
+
@fields = fields
|
57
39
|
end
|
58
40
|
|
59
|
-
def
|
60
|
-
|
41
|
+
def string
|
42
|
+
Dynamic.new(&:to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
alias text string
|
46
|
+
|
47
|
+
def timestamp
|
48
|
+
Dynamic.new(&:iso8601)
|
61
49
|
end
|
62
50
|
|
63
|
-
def
|
64
|
-
|
65
|
-
return if @actions_called
|
66
|
-
@fields[:actions] = actions
|
51
|
+
def manual(&transform_block)
|
52
|
+
Dynamic.new(&transform_block)
|
67
53
|
end
|
68
54
|
|
69
55
|
def dynamic(&transform_block)
|
70
|
-
Dynamic.new(transform_block)
|
56
|
+
Dynamic.new(&transform_block)
|
71
57
|
end
|
72
58
|
|
73
59
|
def actions
|
@@ -75,38 +61,9 @@ module Super
|
|
75
61
|
Bypass.new(partial: "super_schema_display_actions", real: false)
|
76
62
|
end
|
77
63
|
|
78
|
-
def to_partial_path
|
79
|
-
if @action_inquirer.index?
|
80
|
-
"super_schema_display_index"
|
81
|
-
elsif @action_inquirer.show?
|
82
|
-
"super_schema_display_show"
|
83
|
-
else
|
84
|
-
"super_schema_display_#{@action_inquirer.action}"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
64
|
# @private
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
formatted =
|
93
|
-
if formatter.real?
|
94
|
-
value = record.public_send(column)
|
95
|
-
formatter.present(value)
|
96
|
-
else
|
97
|
-
formatter.present
|
98
|
-
end
|
99
|
-
|
100
|
-
if formatted.respond_to?(:to_partial_path)
|
101
|
-
if formatted.respond_to?(:locals)
|
102
|
-
formatted.locals[:record] ||= record
|
103
|
-
template.render(formatted, formatted.locals)
|
104
|
-
else
|
105
|
-
template.render(formatted)
|
106
|
-
end
|
107
|
-
else
|
108
|
-
formatted
|
109
|
-
end
|
65
|
+
def actions_called?
|
66
|
+
@actions_called
|
110
67
|
end
|
111
68
|
end
|
112
69
|
end
|
data/lib/super/engine.rb
CHANGED
@@ -2,7 +2,7 @@ module Super
|
|
2
2
|
# Configures the host Rails app to work with Super
|
3
3
|
class Engine < ::Rails::Engine
|
4
4
|
initializer "super.assets.precompile" do |app|
|
5
|
-
if Super::Assets.sprockets_available?
|
5
|
+
if Super::Assets::Handler.sprockets_available?
|
6
6
|
app.config.assets.precompile << "config/super_manifest.js"
|
7
7
|
end
|
8
8
|
end
|
data/lib/super/filter.rb
CHANGED
@@ -1,137 +1,12 @@
|
|
1
1
|
module Super
|
2
2
|
class Filter
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
@filter_form = controls.initialize_filtering(params: params, query_params: request.GET)
|
7
|
-
@records = controls.filter_records(filter_form: @filter_form, records: @records)
|
8
|
-
@view.asides.push(:@filter_form)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class FilterFormField
|
13
|
-
def initialize(humanized_field_name:, field_name:, type:, params:)
|
14
|
-
@humanized_field_name = humanized_field_name
|
15
|
-
@field_name = field_name
|
16
|
-
@field_type = type
|
17
|
-
@params = params
|
18
|
-
@specified_values =
|
19
|
-
type.q
|
20
|
-
.map do |query_field_name|
|
21
|
-
[
|
22
|
-
query_field_name,
|
23
|
-
(params || {})[query_field_name],
|
24
|
-
]
|
25
|
-
end
|
26
|
-
.to_h
|
27
|
-
|
28
|
-
@specified_values.each do |key, value|
|
29
|
-
define_singleton_method(key) { value }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_reader :humanized_field_name
|
34
|
-
attr_reader :field_name
|
35
|
-
attr_reader :field_type
|
36
|
-
attr_reader :specified_values
|
37
|
-
|
38
|
-
def op
|
39
|
-
(@params || {})[:op]
|
40
|
-
end
|
41
|
-
|
42
|
-
def operators
|
43
|
-
@field_type.operators
|
44
|
-
.map { |o| [o.name, o.identifier] }
|
45
|
-
.to_h
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_partial_path
|
49
|
-
@field_type.to_partial_path
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def initialize(model:, url:, schema:, params:)
|
54
|
-
@model = model
|
55
|
-
@url = url
|
56
|
-
@schema = schema
|
57
|
-
@params = params
|
58
|
-
|
59
|
-
@form_fields = {}
|
60
|
-
end
|
61
|
-
|
62
|
-
def each_field
|
63
|
-
@schema.fields.each do |field_name, _field_type|
|
64
|
-
yield(form_field_for(field_name))
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def url
|
69
|
-
@url
|
70
|
-
end
|
3
|
+
def initialize
|
4
|
+
@schema_type = Filter::SchemaTypes.new
|
5
|
+
@fields = Schema::Fields.new
|
71
6
|
|
72
|
-
|
73
|
-
"filter"
|
7
|
+
yield(@fields, @schema_type)
|
74
8
|
end
|
75
9
|
|
76
|
-
|
77
|
-
each_field do |form_field|
|
78
|
-
next if form_field.specified_values.values.map(&:to_s).map(&:strip).all? { |specified_value| specified_value == "" }
|
79
|
-
next if !Super::Filter::Operator.registry.key?(form_field.op)
|
80
|
-
|
81
|
-
operator = Super::Filter::Operator.registry[form_field.op]
|
82
|
-
updated_relation = operator.filter(relation, form_field.field_name, *form_field.specified_values.values)
|
83
|
-
|
84
|
-
if updated_relation.is_a?(ActiveRecord::Relation)
|
85
|
-
relation = updated_relation
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
relation
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def form_field_for(field_name)
|
95
|
-
@form_fields[field_name] ||=
|
96
|
-
FilterFormField.new(
|
97
|
-
humanized_field_name: @model.human_attribute_name(field_name),
|
98
|
-
field_name: field_name,
|
99
|
-
type: @schema.fields[field_name],
|
100
|
-
params: (@params || {})[field_name]
|
101
|
-
)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class Controls
|
106
|
-
module Optional
|
107
|
-
def filters_enabled?
|
108
|
-
actual.respond_to?(:filter_schema)
|
109
|
-
end
|
110
|
-
|
111
|
-
def filter_schema
|
112
|
-
actual.filter_schema
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
module Steps
|
117
|
-
def initialize_filtering(params:, query_params:)
|
118
|
-
if filters_enabled?
|
119
|
-
Super::Filter.new(
|
120
|
-
model: model,
|
121
|
-
schema: filter_schema,
|
122
|
-
params: params[:q],
|
123
|
-
url: query_params
|
124
|
-
)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def filter_records(filter_form:, records:)
|
129
|
-
if filters_enabled? && records
|
130
|
-
filter_form.to_search_query(records)
|
131
|
-
else
|
132
|
-
records
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
10
|
+
attr_reader :fields
|
136
11
|
end
|
137
12
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Super
|
2
|
+
class Filter
|
3
|
+
class FormObject
|
4
|
+
class FilterFormField
|
5
|
+
def initialize(humanized_field_name:, field_name:, type:, params:)
|
6
|
+
@humanized_field_name = humanized_field_name
|
7
|
+
@field_name = field_name
|
8
|
+
@field_type = type
|
9
|
+
@params = params
|
10
|
+
@specified_values =
|
11
|
+
type.q
|
12
|
+
.map do |query_field_name|
|
13
|
+
[
|
14
|
+
query_field_name,
|
15
|
+
(params || {})[query_field_name],
|
16
|
+
]
|
17
|
+
end
|
18
|
+
.to_h
|
19
|
+
|
20
|
+
@specified_values.each do |key, value|
|
21
|
+
define_singleton_method(key) { value }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :humanized_field_name
|
26
|
+
attr_reader :field_name
|
27
|
+
attr_reader :field_type
|
28
|
+
attr_reader :specified_values
|
29
|
+
|
30
|
+
def op
|
31
|
+
(@params || {})[:op]
|
32
|
+
end
|
33
|
+
|
34
|
+
def operators
|
35
|
+
@field_type.operators
|
36
|
+
.map { |o| [o.name, o.identifier] }
|
37
|
+
.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_partial_path
|
41
|
+
@field_type.to_partial_path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(model:, url:, schema:, params:)
|
46
|
+
@model = model
|
47
|
+
@url = url
|
48
|
+
@schema = schema
|
49
|
+
@params = params
|
50
|
+
|
51
|
+
@form_fields = {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def each_field
|
55
|
+
@schema.fields.each do |field_name, _field_type|
|
56
|
+
yield(form_field_for(field_name))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def url
|
61
|
+
@url
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_partial_path
|
65
|
+
"filter"
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_search_query(relation)
|
69
|
+
each_field do |form_field|
|
70
|
+
next if form_field.specified_values.values.map(&:to_s).map(&:strip).all? { |specified_value| specified_value == "" }
|
71
|
+
next if !Super::Filter::Operator.registry.key?(form_field.op)
|
72
|
+
|
73
|
+
operator = Super::Filter::Operator.registry[form_field.op]
|
74
|
+
updated_relation = operator.filter(relation, form_field.field_name, *form_field.specified_values.values)
|
75
|
+
|
76
|
+
if updated_relation.is_a?(ActiveRecord::Relation)
|
77
|
+
relation = updated_relation
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
relation
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def form_field_for(field_name)
|
87
|
+
@form_fields[field_name] ||=
|
88
|
+
FilterFormField.new(
|
89
|
+
humanized_field_name: @model.human_attribute_name(field_name),
|
90
|
+
field_name: field_name,
|
91
|
+
type: @schema.fields[field_name],
|
92
|
+
params: (@params || {})[field_name]
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Super
|
2
|
+
class Filter
|
3
|
+
class Guesser
|
4
|
+
def initialize(model:, fields:, type:)
|
5
|
+
@model = model
|
6
|
+
@fields = fields
|
7
|
+
@type = type
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
Schema::Guesser
|
12
|
+
.new(model: @model, fields: @fields, type: @type)
|
13
|
+
.assign_type { |attribute_name| attribute_type_for(attribute_name) }
|
14
|
+
.call
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def attribute_type_for(attribute_name)
|
20
|
+
type = @model.type_for_attribute(attribute_name).type
|
21
|
+
case type
|
22
|
+
when :datetime
|
23
|
+
@type.timestamp
|
24
|
+
else
|
25
|
+
@type.text
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Super
|
2
|
+
class Filter
|
3
|
+
module ControllerMethods
|
4
|
+
def index
|
5
|
+
super
|
6
|
+
@filter_form = controls.initialize_filtering(params: params, query_params: request.GET)
|
7
|
+
@records = controls.filter_records(filter_form: @filter_form, records: @records)
|
8
|
+
@view.asides.push(:@filter_form)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Controls
|
14
|
+
module Optional
|
15
|
+
def filters_enabled?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_schema
|
20
|
+
Filter.new do |fields, type|
|
21
|
+
Filter::Guesser.new(model: model, fields: fields, type: type).call
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Steps
|
27
|
+
def initialize_filtering(params:, query_params:)
|
28
|
+
if filters_enabled?
|
29
|
+
Super::Filter::FormObject.new(
|
30
|
+
model: model,
|
31
|
+
schema: filter_schema,
|
32
|
+
params: params[:q],
|
33
|
+
url: query_params
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def filter_records(filter_form:, records:)
|
39
|
+
if filters_enabled? && records
|
40
|
+
filter_form.to_search_query(records)
|
41
|
+
else
|
42
|
+
records
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -13,7 +13,7 @@ module Super
|
|
13
13
|
# # ...
|
14
14
|
#
|
15
15
|
# def filter_schema
|
16
|
-
# Super::
|
16
|
+
# Super::Filter.new do |fields, type|
|
17
17
|
# fields[:name] = type.text(operators: [
|
18
18
|
# Super::Filter::Operator.eq,
|
19
19
|
# Super::Filter::Operator.contain,
|
@@ -90,12 +90,6 @@ module Super
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
def before_yield(fields:)
|
94
|
-
end
|
95
|
-
|
96
|
-
def after_yield
|
97
|
-
end
|
98
|
-
|
99
93
|
def select(collection:, operators: Filter::Operator.select_defaults)
|
100
94
|
Select.new(
|
101
95
|
collection: collection,
|