super 0.0.2 → 0.0.3
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 +22 -13
- data/app/assets/javascripts/super/application.js +10970 -64
- data/app/assets/stylesheets/super/application.css +33270 -14020
- data/app/controllers/super/application_controller.rb +1 -0
- data/app/views/super/application/_form.html.erb +1 -2
- data/app/views/super/application/_form_field__destroy.html.erb +5 -0
- data/app/views/super/application/{_form_generic_select.html.erb → _form_field_select.html.erb} +3 -5
- data/app/views/super/application/{_form_generic_text.html.erb → _form_field_text.html.erb} +1 -3
- data/app/views/super/application/_form_fieldset.html.erb +8 -0
- data/app/views/super/application/_form_has_many.html.erb +21 -0
- data/app/views/super/application/_form_has_one.html.erb +11 -0
- data/app/views/super/application/_form_inline_errors.html.erb +10 -0
- data/frontend/super-frontend/build.js +3 -1
- data/frontend/super-frontend/dist/application.css +33270 -14020
- data/frontend/super-frontend/dist/application.js +10970 -64
- data/frontend/super-frontend/package.json +5 -2
- data/frontend/super-frontend/src/javascripts/super/{application.js → application.ts} +3 -1
- data/frontend/super-frontend/src/javascripts/super/nested_attributes_controller.ts +33 -0
- data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +1 -0
- data/frontend/super-frontend/tsconfig.json +13 -0
- data/frontend/super-frontend/yarn.lock +1559 -1523
- data/lib/super/action_inquirer.rb +13 -0
- data/lib/super/assets.rb +1 -0
- data/lib/super/configuration.rb +59 -44
- data/lib/super/controls.rb +31 -15
- data/lib/super/display/schema_types.rb +15 -16
- data/lib/super/engine.rb +1 -0
- data/lib/super/error.rb +1 -0
- data/lib/super/form/schema_types.rb +89 -21
- data/lib/super/navigation/automatic.rb +2 -0
- data/lib/super/schema.rb +50 -1
- data/lib/super/test_support/copy_app_templates/controllers/favorite_things_controller.rb +50 -0
- data/lib/super/test_support/copy_app_templates/{members_controller.rb → controllers/members_controller.rb} +10 -5
- data/lib/super/test_support/copy_app_templates/{ships_controller.rb → controllers/ships_controller.rb} +3 -3
- data/lib/super/test_support/copy_app_templates/{20190216224956_create_members.rb → migrations/20190216224956_create_members.rb} +0 -0
- data/lib/super/test_support/copy_app_templates/{20190803143320_create_ships.rb → migrations/20190803143320_create_ships.rb} +0 -0
- data/lib/super/test_support/copy_app_templates/{20190806014121_add_ship_to_members.rb → migrations/20190806014121_add_ship_to_members.rb} +0 -0
- data/lib/super/test_support/copy_app_templates/migrations/20191126050453_create_favorite_things.rb +10 -0
- data/lib/super/test_support/copy_app_templates/models/favorite_thing.rb +7 -0
- data/lib/super/test_support/copy_app_templates/{member.rb → models/member.rb} +7 -0
- data/lib/super/test_support/copy_app_templates/{ship.rb → models/ship.rb} +0 -0
- data/lib/super/test_support/copy_app_templates/routes.rb +1 -0
- data/lib/super/test_support/fixtures/favorite_things.yml +9 -0
- data/lib/super/test_support/generate_copy_app.rb +5 -16
- data/lib/super/test_support/generate_dummy.rb +0 -1
- data/lib/super/test_support/starfleet_seeder.rb +1 -0
- data/lib/super/version.rb +1 -1
- metadata +25 -14
- data/app/views/super/application/_form_field.html.erb +0 -7
@@ -1,7 +1,20 @@
|
|
1
1
|
module Super
|
2
|
+
# ```ruby
|
3
|
+
# action = Super::ActionInquirer.new(
|
4
|
+
# Super::ActionInquirer.default_resources,
|
5
|
+
# :index
|
6
|
+
# )
|
7
|
+
#
|
8
|
+
# action.read? # => true
|
9
|
+
# action.index? # => true
|
10
|
+
# action.show? # => false
|
11
|
+
# action.write? # => false
|
12
|
+
# ```
|
2
13
|
class ActionInquirer
|
3
14
|
attr_reader :action
|
4
15
|
|
16
|
+
# @return [Hash<Symbol, Array<Symbol>>] default settings for initialization
|
17
|
+
#
|
5
18
|
def self.default_resources
|
6
19
|
{
|
7
20
|
read: %i[index show new edit],
|
data/lib/super/assets.rb
CHANGED
data/lib/super/configuration.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Super
|
2
|
+
# @yield [Configuration]
|
3
|
+
# @return [Configuration]
|
2
4
|
def self.configuration
|
3
5
|
@configuration ||= Configuration.new
|
4
6
|
|
@@ -9,78 +11,91 @@ module Super
|
|
9
11
|
@configuration
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
public_send("#{key}=", value)
|
14
|
+
# Allows setting global configuration
|
15
|
+
#
|
16
|
+
# ```ruby
|
17
|
+
# Super.configuration do |c|
|
18
|
+
# c.title = "My Admin Site"
|
19
|
+
# end
|
20
|
+
# ```
|
21
|
+
class Configuration
|
22
|
+
module ConfigurationLogic # @api private
|
23
|
+
def self.included(base)
|
24
|
+
base.extend(ClassMethods)
|
24
25
|
end
|
25
|
-
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def initialize
|
28
|
+
self.class.defaults.each do |key, value|
|
29
|
+
if value.respond_to?(:call)
|
30
|
+
value = value.call
|
31
|
+
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
@defaults ||= {}
|
33
|
+
public_send("#{key}=", value)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
|
-
def
|
37
|
-
|
37
|
+
def configured?(attr)
|
38
|
+
instance_variable_defined?("@#{attr}")
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
defaults
|
41
|
+
module ClassMethods
|
42
|
+
def defaults
|
43
|
+
@defaults ||= {}
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
def wraps
|
47
|
+
@wraps ||= {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def configure(attr, wrap: nil, enum: nil, **kwargs)
|
51
|
+
if kwargs.key?(:default)
|
52
|
+
defaults[attr] = kwargs[:default]
|
48
53
|
end
|
49
54
|
|
50
|
-
|
55
|
+
define_method(attr) do
|
56
|
+
if !configured?(attr)
|
57
|
+
raise Error::UnconfiguredConfiguration, "unconfigured: #{attr}"
|
58
|
+
end
|
51
59
|
|
52
|
-
|
53
|
-
result
|
54
|
-
else
|
55
|
-
wrap.call(result)
|
56
|
-
end
|
57
|
-
end
|
60
|
+
result = instance_variable_get("@#{attr}")
|
58
61
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
"tried to set `#{attr}` to `#{value.inspect}`, " \
|
64
|
-
"expected: #{enum.join(", ")}"
|
62
|
+
if wrap.nil?
|
63
|
+
result
|
64
|
+
else
|
65
|
+
wrap.call(result)
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
68
|
-
|
69
|
-
|
69
|
+
define_method("#{attr}=") do |value|
|
70
|
+
if enum.is_a?(Array)
|
71
|
+
if !enum.include?(value)
|
72
|
+
raise Error::InvalidConfiguration,
|
73
|
+
"tried to set `#{attr}` to `#{value.inspect}`, " \
|
74
|
+
"expected: #{enum.join(", ")}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
instance_variable_set("@#{attr}", value)
|
79
|
+
value
|
80
|
+
end
|
70
81
|
end
|
71
82
|
end
|
72
83
|
end
|
73
|
-
end
|
74
84
|
|
75
|
-
class Configuration
|
76
85
|
include ConfigurationLogic
|
77
86
|
|
87
|
+
# @!attribute [rw]
|
78
88
|
configure :title
|
89
|
+
# @!attribute [rw]
|
79
90
|
configure :index_resources_per_page, default: 20
|
91
|
+
# @!attribute [rw]
|
80
92
|
configure :controller_namespace, default: "admin"
|
93
|
+
# @!attribute [rw]
|
81
94
|
configure :route_namespace, default: :admin, wrap: -> (val) { [val].flatten }
|
95
|
+
# @!attribute [rw]
|
82
96
|
configure :asset_handler, default: -> { Super::Assets.auto }
|
83
97
|
|
98
|
+
# @api private
|
84
99
|
def path_parts(*parts)
|
85
100
|
route_namespace + parts
|
86
101
|
end
|
data/lib/super/controls.rb
CHANGED
@@ -1,25 +1,41 @@
|
|
1
1
|
module Super
|
2
|
+
# A wrapper around the per-controller Controls classes. This class often
|
3
|
+
# directly delegates to the per-controller classes, but it can also provide
|
4
|
+
# some default implementation.
|
2
5
|
class Controls
|
3
|
-
def initialize(
|
4
|
-
@
|
6
|
+
def initialize(actual)
|
7
|
+
@actual = actual
|
5
8
|
end
|
6
9
|
|
7
|
-
attr_reader :
|
10
|
+
attr_reader :actual
|
8
11
|
|
9
|
-
def
|
10
|
-
|
11
|
-
@dashboard.public_send(method_name, *args)
|
12
|
-
else
|
13
|
-
super
|
14
|
-
end
|
12
|
+
def title
|
13
|
+
@actual.title
|
15
14
|
end
|
16
15
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
def model
|
17
|
+
@actual.model
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param action [ActionInquirer]
|
21
|
+
def scope(action:)
|
22
|
+
@actual.scope(action: action)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param params [ActionController::Parameters]
|
26
|
+
# @param action [ActionInquirer]
|
27
|
+
def permitted_params(params, action:)
|
28
|
+
@actual.permitted_params(params, action: action)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param action [ActionInquirer]
|
32
|
+
def display_schema(action:)
|
33
|
+
@actual.display_schema(action: action)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param action [ActionInquirer]
|
37
|
+
def form_schema(action:)
|
38
|
+
@actual.form_schema(action: action)
|
23
39
|
end
|
24
40
|
end
|
25
41
|
end
|
@@ -3,25 +3,24 @@ module Super
|
|
3
3
|
# This schema type is meant to be used for +#index+ or +#show+ actions to
|
4
4
|
# transform database fields into something that is human friendly.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# ```
|
7
|
+
# class MembersController::Controls
|
8
|
+
# # ...
|
8
9
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# fields[:ship] = type.dynamic { |ship| "#{ship.name} (Ship ##{ship.id})" }
|
18
|
-
# fields[:created_at] = type.dynamic { |created_at| created_at.iso8601 }
|
19
|
-
# fields[:updated_at] = type.dynamic { |updated_at| updated_at.iso8601 }
|
20
|
-
# end
|
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 }
|
21
18
|
# end
|
22
|
-
#
|
23
|
-
# # ...
|
24
19
|
# end
|
20
|
+
#
|
21
|
+
# # ...
|
22
|
+
# end
|
23
|
+
# ```
|
25
24
|
class SchemaTypes
|
26
25
|
class Dynamic
|
27
26
|
def initialize(transform_block)
|
data/lib/super/engine.rb
CHANGED
data/lib/super/error.rb
CHANGED
@@ -2,33 +2,41 @@ module Super
|
|
2
2
|
class Form
|
3
3
|
# This schema type is used on your +#edit+ and +#new+ forms
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# ```ruby
|
6
|
+
# class MembersController::Controls
|
7
|
+
# # ...
|
7
8
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# "write_type_select",
|
18
|
-
# collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
|
19
|
-
# )
|
20
|
-
# end
|
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
|
+
# )
|
21
18
|
# end
|
22
|
-
#
|
23
|
-
# # ...
|
24
19
|
# end
|
20
|
+
#
|
21
|
+
# # ...
|
22
|
+
# end
|
23
|
+
# ```
|
25
24
|
class SchemaTypes
|
26
25
|
class Generic
|
27
|
-
def initialize(partial_path:, extras:)
|
26
|
+
def initialize(partial_path:, extras:, nested:)
|
28
27
|
@partial_path = partial_path
|
29
28
|
@extras = extras
|
29
|
+
@nested_fields = nested
|
30
30
|
end
|
31
31
|
|
32
|
+
attr_reader :nested_fields
|
33
|
+
|
34
|
+
# This takes advantage of a feature of Rails. If the value of
|
35
|
+
# `#to_partial_path` is `my_form_field`, Rails renders
|
36
|
+
# `app/views/super/application/_my_form_field.html.erb`, and this
|
37
|
+
# instance of Generic is accessible via `my_form_field`
|
38
|
+
#
|
39
|
+
# @return [String] the filename of the partial that will be rendered.
|
32
40
|
def to_partial_path
|
33
41
|
@partial_path
|
34
42
|
end
|
@@ -36,11 +44,71 @@ module Super
|
|
36
44
|
def [](key)
|
37
45
|
@extras[key]
|
38
46
|
end
|
47
|
+
|
48
|
+
def reader
|
49
|
+
@extras[:reader]
|
50
|
+
end
|
51
|
+
|
52
|
+
def label
|
53
|
+
if @extras.key?(:label)
|
54
|
+
return @extras[:label]
|
55
|
+
end
|
56
|
+
|
57
|
+
if @extras.key?(:reader)
|
58
|
+
return @extras[:reader].to_s.singularize.humanize
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
return false if other.class != self.class
|
64
|
+
return false if other.instance_variable_get(:@partial_path) != @partial_path
|
65
|
+
return false if other.instance_variable_get(:@extras) != @extras
|
66
|
+
return false if other.instance_variable_get(:@nested) != @nested
|
67
|
+
|
68
|
+
true
|
69
|
+
end
|
39
70
|
end
|
40
71
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
72
|
+
def setup(fields:)
|
73
|
+
@fields = fields
|
74
|
+
end
|
75
|
+
|
76
|
+
def generic(partial_path, **extras)
|
77
|
+
Generic.new(partial_path: partial_path, extras: extras, nested: {})
|
78
|
+
end
|
79
|
+
|
80
|
+
def has_many(reader, **extras)
|
81
|
+
nested = @fields.nested do
|
82
|
+
yield
|
83
|
+
end
|
84
|
+
|
85
|
+
Generic.new(
|
86
|
+
partial_path: "form_has_many",
|
87
|
+
extras: extras.merge(reader: reader),
|
88
|
+
nested: nested
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def has_one(reader, **extras)
|
93
|
+
nested = @fields.nested do
|
94
|
+
yield
|
95
|
+
end
|
96
|
+
|
97
|
+
Generic.new(
|
98
|
+
partial_path: "form_has_one",
|
99
|
+
extras: extras.merge(reader: reader),
|
100
|
+
nested: nested
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
alias_method :belongs_to, :has_one
|
105
|
+
|
106
|
+
def _destroy(**extras)
|
107
|
+
Generic.new(
|
108
|
+
partial_path: "form_field__destroy",
|
109
|
+
extras: extras,
|
110
|
+
nested: {}
|
111
|
+
)
|
44
112
|
end
|
45
113
|
end
|
46
114
|
end
|
data/lib/super/schema.rb
CHANGED
@@ -8,7 +8,11 @@ module Super
|
|
8
8
|
# @param schema_type [Display::SchemaTypes, Form::SchemaTypes]
|
9
9
|
def initialize(schema_type)
|
10
10
|
@schema_type = schema_type
|
11
|
-
@fields =
|
11
|
+
@fields = Fields.new
|
12
|
+
|
13
|
+
if @schema_type.respond_to?(:setup)
|
14
|
+
@schema_type.setup(fields: @fields)
|
15
|
+
end
|
12
16
|
|
13
17
|
if block_given?
|
14
18
|
yield(@fields, @schema_type)
|
@@ -20,5 +24,50 @@ module Super
|
|
20
24
|
def field_keys
|
21
25
|
fields.keys
|
22
26
|
end
|
27
|
+
|
28
|
+
class Fields
|
29
|
+
include Enumerable
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@backing = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](key)
|
36
|
+
@backing[key]
|
37
|
+
end
|
38
|
+
|
39
|
+
def []=(key, value)
|
40
|
+
@backing[key] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
def keys
|
44
|
+
@backing.keys
|
45
|
+
end
|
46
|
+
|
47
|
+
def each
|
48
|
+
if block_given?
|
49
|
+
return @backing.each(&Proc.new)
|
50
|
+
end
|
51
|
+
|
52
|
+
enum_for(:each)
|
53
|
+
end
|
54
|
+
|
55
|
+
def replace(other)
|
56
|
+
@backing = other
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_h
|
60
|
+
@backing
|
61
|
+
end
|
62
|
+
|
63
|
+
def nested
|
64
|
+
outside = @backing
|
65
|
+
inside = {}
|
66
|
+
@backing = inside
|
67
|
+
yield
|
68
|
+
@backing = outside
|
69
|
+
inside
|
70
|
+
end
|
71
|
+
end
|
23
72
|
end
|
24
73
|
end
|