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
data/lib/super/form.rb
CHANGED
@@ -1,48 +1,35 @@
|
|
1
1
|
module Super
|
2
|
+
# This schema type is used on your +#edit+ and +#new+ forms
|
3
|
+
#
|
4
|
+
# ```ruby
|
5
|
+
# class MembersController::Controls
|
6
|
+
# # ...
|
7
|
+
#
|
8
|
+
# def new_schema
|
9
|
+
# Super::Form.new do |fields, type|
|
10
|
+
# fields[:name] = type.string
|
11
|
+
# fields[:rank] = type.select
|
12
|
+
# fields[:position] = type.string
|
13
|
+
# fields[:ship_id] = type.select(
|
14
|
+
# collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
|
15
|
+
# )
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # ...
|
20
|
+
# end
|
21
|
+
# ```
|
2
22
|
class Form
|
3
|
-
|
4
|
-
def error_wrapping(html_tag)
|
5
|
-
if Thread.current[:super_form_builder]
|
6
|
-
return html_tag
|
7
|
-
end
|
23
|
+
include Schema::Common
|
8
24
|
|
9
|
-
|
10
|
-
|
25
|
+
def initialize
|
26
|
+
@fields = Schema::Fields.new
|
27
|
+
@schema_types = SchemaTypes.new(fields: @fields)
|
28
|
+
yield(@fields, @schema_types)
|
11
29
|
end
|
12
30
|
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
# * actionview/lib/action_view/helpers/form_helper.rb
|
17
|
-
# * actionview/lib/action_view/helpers/form_options_helper.rb
|
18
|
-
# * actionview/lib/action_view/helpers/date_helper.rb
|
19
|
-
%w[
|
20
|
-
label text_field password_field hidden_field file_field text_area
|
21
|
-
check_box radio_button color_field search_field telephone_field
|
22
|
-
date_field time_field datetime_field month_field week_field url_field
|
23
|
-
email_field number_field range_field
|
24
|
-
|
25
|
-
select collection_select grouped_collection_select time_zone_select
|
26
|
-
collection_radio_buttons collection_check_boxes
|
27
|
-
|
28
|
-
time_select datetime_select date_select
|
29
|
-
].each do |field_type_method|
|
30
|
-
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
31
|
-
def #{field_type_method}(*)
|
32
|
-
Thread.current[:super_form_builder] = true
|
33
|
-
super
|
34
|
-
ensure
|
35
|
-
Thread.current[:super_form_builder] = nil
|
36
|
-
end
|
37
|
-
RUBY
|
38
|
-
end
|
39
|
-
|
40
|
-
alias datetime_local_field datetime_field
|
41
|
-
alias phone_field telephone_field
|
31
|
+
def to_partial_path
|
32
|
+
"super_schema_form"
|
42
33
|
end
|
43
34
|
end
|
44
35
|
end
|
45
|
-
|
46
|
-
ActionView::Helpers::Tags::Base.class_eval do
|
47
|
-
prepend Super::Form::FieldErrorProc
|
48
|
-
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Super
|
2
|
+
class Form
|
3
|
+
module FieldErrorProc
|
4
|
+
def error_wrapping(html_tag)
|
5
|
+
if Thread.current[:super_form_builder]
|
6
|
+
return html_tag
|
7
|
+
end
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Builder < ActionView::Helpers::FormBuilder
|
14
|
+
# These methods were originally defined in the following files
|
15
|
+
#
|
16
|
+
# * actionview/lib/action_view/helpers/form_helper.rb
|
17
|
+
# * actionview/lib/action_view/helpers/form_options_helper.rb
|
18
|
+
# * actionview/lib/action_view/helpers/date_helper.rb
|
19
|
+
%w[
|
20
|
+
label text_field password_field hidden_field file_field text_area
|
21
|
+
check_box radio_button color_field search_field telephone_field
|
22
|
+
date_field time_field datetime_field month_field week_field url_field
|
23
|
+
email_field number_field range_field
|
24
|
+
|
25
|
+
select collection_select grouped_collection_select time_zone_select
|
26
|
+
collection_radio_buttons collection_check_boxes
|
27
|
+
|
28
|
+
time_select datetime_select date_select
|
29
|
+
].each do |field_type_method|
|
30
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
31
|
+
def #{field_type_method}(*)
|
32
|
+
Thread.current[:super_form_builder] = true
|
33
|
+
super
|
34
|
+
ensure
|
35
|
+
Thread.current[:super_form_builder] = nil
|
36
|
+
end
|
37
|
+
RUBY
|
38
|
+
end
|
39
|
+
|
40
|
+
alias datetime_local_field datetime_field
|
41
|
+
alias phone_field telephone_field
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
ActionView::Helpers::Tags::Base.class_eval do
|
47
|
+
prepend Super::Form::FieldErrorProc
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Super
|
2
|
+
class Form
|
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
|
+
.reject { |attribute_name| attribute_name == "id" }
|
15
|
+
.reject { |attribute_name| attribute_name == "created_at" }
|
16
|
+
.reject { |attribute_name| attribute_name == "updated_at" }
|
17
|
+
.call
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def attribute_type_for(attribute_name)
|
23
|
+
@type.string
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,26 +1,5 @@
|
|
1
1
|
module Super
|
2
2
|
class Form
|
3
|
-
# This schema type is used on your +#edit+ and +#new+ forms
|
4
|
-
#
|
5
|
-
# ```ruby
|
6
|
-
# class MembersController::Controls
|
7
|
-
# # ...
|
8
|
-
#
|
9
|
-
# def new_schema
|
10
|
-
# Super::Schema.new(Super::Form::SchemaTypes.new) do |fields, type|
|
11
|
-
# fields[:name] = type.generic("form_field_text")
|
12
|
-
# fields[:rank] = type.generic("form_field_select", collection: Member.ranks.keys)
|
13
|
-
# fields[:position] = type.generic("form_field_text")
|
14
|
-
# fields[:ship_id] = type.generic(
|
15
|
-
# "form_field_select",
|
16
|
-
# collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
|
17
|
-
# )
|
18
|
-
# end
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# # ...
|
22
|
-
# end
|
23
|
-
# ```
|
24
3
|
class SchemaTypes
|
25
4
|
class Generic
|
26
5
|
def initialize(partial_path:, extras:, nested:)
|
@@ -31,6 +10,16 @@ module Super
|
|
31
10
|
|
32
11
|
attr_reader :nested_fields
|
33
12
|
|
13
|
+
def each_attribute
|
14
|
+
if block_given?
|
15
|
+
@nested_fields.each do |key, value|
|
16
|
+
yield(key, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
enum_for(:each_attribute)
|
21
|
+
end
|
22
|
+
|
34
23
|
# This takes advantage of a feature of Rails. If the value of
|
35
24
|
# `#to_partial_path` is `my_form_field`, Rails renders
|
36
25
|
# `app/views/super/application/_my_form_field.html.erb`, and this
|
@@ -69,17 +58,22 @@ module Super
|
|
69
58
|
end
|
70
59
|
end
|
71
60
|
|
72
|
-
def
|
61
|
+
def initialize(fields:)
|
73
62
|
@fields = fields
|
74
63
|
end
|
75
64
|
|
76
|
-
def after_yield
|
77
|
-
end
|
78
|
-
|
79
65
|
def generic(partial_path, **extras)
|
80
66
|
Generic.new(partial_path: partial_path, extras: extras, nested: {})
|
81
67
|
end
|
82
68
|
|
69
|
+
def select(**extras)
|
70
|
+
Generic.new(partial_path: "form_field_select", extras: extras, nested: {})
|
71
|
+
end
|
72
|
+
|
73
|
+
def string(**extras)
|
74
|
+
Generic.new(partial_path: "form_field_text", extras: extras, nested: {})
|
75
|
+
end
|
76
|
+
|
83
77
|
def has_many(reader, **extras)
|
84
78
|
nested = @fields.nested do
|
85
79
|
yield
|
@@ -113,10 +107,6 @@ module Super
|
|
113
107
|
nested: {}
|
114
108
|
)
|
115
109
|
end
|
116
|
-
|
117
|
-
def to_partial_path
|
118
|
-
"super_schema_form"
|
119
|
-
end
|
120
110
|
end
|
121
111
|
end
|
122
112
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Super
|
2
|
+
class Form
|
3
|
+
class StrongParams
|
4
|
+
def initialize(form_schema)
|
5
|
+
@form_schema = form_schema
|
6
|
+
end
|
7
|
+
|
8
|
+
def require(model)
|
9
|
+
model.model_name.singular
|
10
|
+
end
|
11
|
+
|
12
|
+
def permit
|
13
|
+
unfurl(@form_schema)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def unfurl(responds_to_each_attribute)
|
19
|
+
responds_to_each_attribute.each_attribute.map do |name, type|
|
20
|
+
if type.nested_fields&.any?
|
21
|
+
{ name => [:id, *unfurl(type)] }
|
22
|
+
else
|
23
|
+
name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/super/pagination.rb
CHANGED
@@ -89,9 +89,7 @@ module Super
|
|
89
89
|
# @param query_params [Hash]
|
90
90
|
# @return [ActiveRecord::Relation]
|
91
91
|
def records_per_page(action:, query_params:)
|
92
|
-
|
93
|
-
Super.configuration.index_records_per_page
|
94
|
-
end
|
92
|
+
Super.configuration.index_records_per_page
|
95
93
|
end
|
96
94
|
end
|
97
95
|
|
@@ -103,14 +101,12 @@ module Super
|
|
103
101
|
# @param query_params [Hash]
|
104
102
|
# @return [Pagination]
|
105
103
|
def initialize_pagination(action:, records:, query_params:)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
)
|
113
|
-
end
|
104
|
+
Pagination.new(
|
105
|
+
total_count: records.size,
|
106
|
+
limit: records_per_page(action: action, query_params: query_params),
|
107
|
+
query_params: query_params,
|
108
|
+
page_query_param: :page
|
109
|
+
)
|
114
110
|
end
|
115
111
|
|
116
112
|
# Paginates
|
@@ -120,11 +116,9 @@ module Super
|
|
120
116
|
# @param pagination [Pagination]
|
121
117
|
# @return [ActiveRecord::Relation]
|
122
118
|
def paginate_records(action:, records:, pagination:)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
.offset(pagination.offset)
|
127
|
-
end
|
119
|
+
records
|
120
|
+
.limit(pagination.limit)
|
121
|
+
.offset(pagination.offset)
|
128
122
|
end
|
129
123
|
end
|
130
124
|
end
|
data/lib/super/schema.rb
CHANGED
@@ -5,31 +5,6 @@ module Super
|
|
5
5
|
#
|
6
6
|
# The various "schema types" are likely of more interest
|
7
7
|
class Schema
|
8
|
-
# @param schema_type [Display::SchemaTypes, Form::SchemaTypes]
|
9
|
-
def initialize(schema_type)
|
10
|
-
@schema_type = schema_type
|
11
|
-
@fields = Fields.new
|
12
|
-
|
13
|
-
@schema_type.before_yield(fields: @fields)
|
14
|
-
|
15
|
-
if block_given?
|
16
|
-
yield(@fields, @schema_type)
|
17
|
-
end
|
18
|
-
|
19
|
-
@schema_type.after_yield
|
20
|
-
end
|
21
|
-
|
22
|
-
attr_reader :fields
|
23
|
-
attr_reader :schema_type
|
24
|
-
|
25
|
-
def field_keys
|
26
|
-
fields.keys
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_partial_path
|
30
|
-
@schema_type.to_partial_path
|
31
|
-
end
|
32
|
-
|
33
8
|
# This class can be thought of as a Hash, where the keys usually refer to
|
34
9
|
# the model's column name and the value refers to the column type. Note
|
35
10
|
# though that this isn't always the case—different `SchemaTypes` can do
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Super
|
2
|
+
class Schema
|
3
|
+
module Common
|
4
|
+
def each_attribute_name
|
5
|
+
if block_given?
|
6
|
+
@fields.keys.each do |key|
|
7
|
+
yield(key)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
enum_for(:each_attribute_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def each_attribute
|
15
|
+
if block_given?
|
16
|
+
@fields.each do |key, value|
|
17
|
+
yield(key, value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
enum_for(:each_attribute)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Super
|
2
|
+
class Schema
|
3
|
+
class Guesser
|
4
|
+
def initialize(model:, fields:, type:)
|
5
|
+
@model = model
|
6
|
+
@fields = fields
|
7
|
+
@type = type
|
8
|
+
@rejects = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def limit
|
12
|
+
@limit = yield
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def reject(&block)
|
17
|
+
@rejects.push(block)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def ignore_foreign_keys
|
22
|
+
@rejects.push(-> (attribute_name) { is_foreign_key[attribute_name] })
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def assign_type(&block)
|
27
|
+
@assign_type = block
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def call
|
32
|
+
result = sorted_attribute_names
|
33
|
+
result = @rejects.reduce(result) do |intermediary_result, rejection_proc|
|
34
|
+
intermediary_result.reject(&rejection_proc)
|
35
|
+
end
|
36
|
+
|
37
|
+
result = result.first(@limit) if @limit && @limit != Float::INFINITY
|
38
|
+
|
39
|
+
result.each do |name|
|
40
|
+
@fields[name] = @assign_type.call(name)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def sorted_attribute_names
|
47
|
+
@model
|
48
|
+
.attribute_names
|
49
|
+
.sort_by { |name| sort_weight[name] }
|
50
|
+
end
|
51
|
+
|
52
|
+
def sort_weight
|
53
|
+
@sort_weight ||= Hash.new do |hash, name|
|
54
|
+
hash[name] =
|
55
|
+
case name
|
56
|
+
when "id" then 0
|
57
|
+
when "title" then 1000
|
58
|
+
when "name" then 1300
|
59
|
+
when "created_at" then 9500
|
60
|
+
when "updated_at" then 9750
|
61
|
+
else
|
62
|
+
2000 + hash.size
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def is_foreign_key
|
68
|
+
@is_foreign_key ||=
|
69
|
+
@model
|
70
|
+
.reflect_on_all_associations
|
71
|
+
.select { |a| a.macro == :belongs_to }
|
72
|
+
.map { |a| [a.foreign_key, true] }
|
73
|
+
.to_h
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|