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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +56 -0
  3. data/README.md +6 -0
  4. data/STABILITY.md +50 -0
  5. data/app/assets/javascripts/super/application.js +12 -7
  6. data/app/controllers/super/application_controller.rb +1 -1
  7. data/app/views/layouts/super/application.html.erb +14 -6
  8. data/app/views/super/application/_super_panel.html.erb +1 -1
  9. data/app/views/super/application/_super_schema_display_index.html.erb +4 -4
  10. data/app/views/super/application/_super_schema_display_show.html.erb +3 -3
  11. data/app/views/super/application/_super_schema_form.html.erb +1 -1
  12. data/frontend/super-frontend/dist/application.js +12 -7
  13. data/frontend/super-frontend/src/javascripts/super/application.ts +5 -8
  14. data/lib/generators/super/resource/templates/resources_controller.rb.tt +1 -31
  15. data/lib/generators/super/webpacker/webpacker_generator.rb +3 -2
  16. data/lib/super.rb +11 -0
  17. data/lib/super/assets.rb +108 -38
  18. data/lib/super/configuration.rb +18 -73
  19. data/lib/super/controls.rb +2 -25
  20. data/lib/super/controls/optional.rb +41 -16
  21. data/lib/super/controls/required.rb +1 -29
  22. data/lib/super/controls/steps.rb +9 -23
  23. data/lib/super/display.rb +72 -0
  24. data/lib/super/display/guesser.rb +34 -0
  25. data/lib/super/display/schema_types.rb +19 -62
  26. data/lib/super/engine.rb +1 -1
  27. data/lib/super/filter.rb +5 -130
  28. data/lib/super/filter/form_object.rb +97 -0
  29. data/lib/super/filter/guesser.rb +30 -0
  30. data/lib/super/filter/plugin.rb +47 -0
  31. data/lib/super/filter/schema_types.rb +1 -7
  32. data/lib/super/form.rb +27 -40
  33. data/lib/super/form/builder.rb +48 -0
  34. data/lib/super/form/guesser.rb +27 -0
  35. data/lib/super/form/schema_types.rb +19 -29
  36. data/lib/super/form/strong_params.rb +29 -0
  37. data/lib/super/pagination.rb +10 -16
  38. data/lib/super/schema.rb +0 -25
  39. data/lib/super/schema/common.rb +25 -0
  40. data/lib/super/schema/guesser.rb +77 -0
  41. data/lib/super/version.rb +1 -1
  42. metadata +14 -2
@@ -19,84 +19,29 @@ module Super
19
19
  # end
20
20
  # ```
21
21
  class Configuration
22
- module ConfigurationLogic # @api private
23
- def self.included(base)
24
- base.extend(ClassMethods)
25
- end
22
+ def initialize
23
+ self.title = "Super Admin"
24
+ self.index_records_per_page = 20
25
+ self.controller_namespace = "admin"
26
+ self.route_namespace = :admin
26
27
 
27
- def initialize
28
- self.class.defaults.each do |key, value|
29
- if value.respond_to?(:call)
30
- value = value.call
31
- end
28
+ controller_plugins.use(prepend: Super::Filter::ControllerMethods)
29
+ controller_plugins.use(prepend: Super::Pagination::ControllerMethods)
32
30
 
33
- public_send("#{key}=", value)
34
- end
35
-
36
- Plugin::Registry.controller.use(prepend: Super::Filter::ControllerMethods)
37
- Plugin::Registry.controller.use(prepend: Super::Pagination::ControllerMethods)
38
- end
39
-
40
- def configured?(attr)
41
- instance_variable_defined?("@#{attr}")
42
- end
43
-
44
- module ClassMethods
45
- def defaults
46
- @defaults ||= {}
47
- end
48
-
49
- def wraps
50
- @wraps ||= {}
51
- end
52
-
53
- def configure(attr, wrap: nil, enum: nil, **kwargs)
54
- if kwargs.key?(:default)
55
- defaults[attr] = kwargs[:default]
56
- end
57
-
58
- define_method(attr) do
59
- if !configured?(attr)
60
- raise Error::UnconfiguredConfiguration, "unconfigured: #{attr}"
61
- end
62
-
63
- result = instance_variable_get("@#{attr}")
64
-
65
- if wrap.nil?
66
- result
67
- else
68
- wrap.call(result)
69
- end
70
- end
71
-
72
- define_method("#{attr}=") do |value|
73
- if enum.is_a?(Array)
74
- if !enum.include?(value)
75
- raise Error::InvalidConfiguration,
76
- "tried to set `#{attr}` to `#{value.inspect}`, " \
77
- "expected: #{enum.join(", ")}"
78
- end
79
- end
80
-
81
- instance_variable_set("@#{attr}", value)
82
- value
83
- end
84
- end
85
- end
31
+ self.javascripts = [Super::Assets.auto("super/application")]
32
+ self.stylesheets = [Super::Assets.auto("super/application")]
86
33
  end
87
34
 
88
- include ConfigurationLogic
35
+ attr_accessor :title
36
+ attr_accessor :index_records_per_page
37
+ attr_accessor :controller_namespace
38
+ attr_writer :route_namespace
39
+ def route_namespace
40
+ [@route_namespace].flatten
41
+ end
89
42
 
90
- # @!attribute [rw]
91
- configure :title
92
- # @!attribute [rw]
93
- configure :index_records_per_page, default: 20
94
- # @!attribute [rw]
95
- configure :controller_namespace, default: "admin"
96
- # @!attribute [rw]
97
- configure :route_namespace, default: :admin, wrap: -> (val) { [val].flatten }
98
- # @!attribute [rw]
99
- configure :asset_handler, default: -> { Super::Assets.auto }
43
+ attr_accessor :javascripts
44
+ attr_accessor :stylesheets
100
45
 
101
46
  def controller_plugins
102
47
  Plugin::Registry.controller
@@ -3,34 +3,11 @@ require "super/controls/required"
3
3
  require "super/controls/steps"
4
4
 
5
5
  module Super
6
- # A wrapper around the per-controller Controls classes. This class often
7
- # directly delegates to the per-controller classes, but it can also provide
8
- # some default implementation.
6
+ # The base Controls class. Most parts of Super can be configured by
7
+ # customizing its methods.
9
8
  class Controls
10
9
  include Required
11
10
  include Optional
12
11
  include Steps
13
-
14
- def initialize(actual)
15
- @actual = actual
16
- end
17
-
18
- attr_reader :actual
19
-
20
- private
21
-
22
- def default_for(method_name, *args, **kwargs)
23
- if @actual.respond_to?(method_name)
24
- if args.empty? && kwargs.empty?
25
- return @actual.public_send(method_name)
26
- elsif args.empty?
27
- return @actual.public_send(method_name, **kwargs)
28
- else
29
- return @actual.public_send(method_name, *args)
30
- end
31
- end
32
-
33
- yield
34
- end
35
12
  end
36
13
  end
@@ -6,9 +6,7 @@ module Super
6
6
  #
7
7
  # @return [String]
8
8
  def title
9
- default_for(:title) do
10
- model.name.pluralize
11
- end
9
+ model.name.pluralize
12
10
  end
13
11
 
14
12
  # Configures what database records are visible on load. This is an optional
@@ -17,20 +15,49 @@ module Super
17
15
  # @param action [ActionInquirer]
18
16
  # @return [ActiveRecord::Relation]
19
17
  def scope(action:)
20
- default_for(:scope, action: action) do
21
- model.all
18
+ model.all
19
+ end
20
+
21
+ # Configures the fields that are displayed on the index and show actions.
22
+ # This is a required method
23
+ #
24
+ # @param action [ActionInquirer]
25
+ # @return [Display]
26
+ def display_schema(action:)
27
+ Display.new(action: action) do |fields, type|
28
+ Display::Guesser.new(model: model, action: action, fields: fields, type: type).call
22
29
  end
23
30
  end
24
31
 
32
+ # Configures the editable fields on the new and edit actions. This is a
33
+ # required method
34
+ #
35
+ # @param action [ActionInquirer]
36
+ # @return [Form]
37
+ def form_schema(action:)
38
+ Form.new do |fields, type|
39
+ Form::Guesser.new(model: model, fields: fields, type: type).call
40
+ end
41
+ end
42
+
43
+ # Configures which parameters could be written to the database. This is a
44
+ # required method
45
+ #
46
+ # @param params [ActionController::Parameters]
47
+ # @param action [ActionInquirer]
48
+ # @return [ActionController::Parameters]
49
+ def permitted_params(params, action:)
50
+ strong_params = Super::Form::StrongParams.new(form_schema(action: action))
51
+ params.require(strong_params.require(model)).permit(strong_params.permit)
52
+ end
53
+
25
54
  # Configures the actions linked to on the index page. This is an optional
26
55
  # method
27
56
  #
28
57
  # @param action [ActionInquirer]
29
58
  # @return [Array<Link>]
30
59
  def collection_actions(action:)
31
- default_for(:collection_actions, action: action) do
32
- Super::Link.find_all(:new)
33
- end
60
+ Super::Link.find_all(:new)
34
61
  end
35
62
 
36
63
  # Configures the actions linked to on the show page as well as each row of
@@ -39,14 +66,12 @@ module Super
39
66
  # @param action [ActionInquirer]
40
67
  # @return [Array<Link>]
41
68
  def member_actions(action:)
42
- default_for(:member_actions, action: action) do
43
- if action.show?
44
- Super::Link.find_all(:edit, :destroy)
45
- elsif action.edit?
46
- Super::Link.find_all(:show, :destroy)
47
- else
48
- Super::Link.find_all(:show, :edit, :destroy)
49
- end
69
+ if action.show?
70
+ Super::Link.find_all(:edit, :destroy)
71
+ elsif action.edit?
72
+ Super::Link.find_all(:show, :destroy)
73
+ else
74
+ Super::Link.find_all(:show, :edit, :destroy)
50
75
  end
51
76
  end
52
77
  end
@@ -6,35 +6,7 @@ module Super
6
6
  #
7
7
  # @return [ActiveRecord::Base]
8
8
  def model
9
- @actual.model
10
- end
11
-
12
- # Configures which parameters could be written to the database. This is a
13
- # required method
14
- #
15
- # @param params [ActionController::Parameters]
16
- # @param action [ActionInquirer]
17
- # @return [ActionController::Parameters]
18
- def permitted_params(params, action:)
19
- @actual.permitted_params(params, action: action)
20
- end
21
-
22
- # Configures the fields that are displayed on the index and show actions.
23
- # This is a required method
24
- #
25
- # @param action [ActionInquirer]
26
- # @return [Schema]
27
- def display_schema(action:)
28
- @actual.display_schema(action: action)
29
- end
30
-
31
- # Configures the editable fields on the new and edit actions. This is a
32
- # required method
33
- #
34
- # @param action [ActionInquirer]
35
- # @return [Schema]
36
- def form_schema(action:)
37
- @actual.form_schema(action: action)
9
+ raise NotImplementedError
38
10
  end
39
11
  end
40
12
  end
@@ -10,9 +10,7 @@ module Super
10
10
  # @param params [ActionController::Parameters]
11
11
  # @return [ActiveRecord::Relation]
12
12
  def load_records(action:, params:)
13
- default_for(:load_records, action: action, params: params) do
14
- scope(action: action)
15
- end
13
+ scope(action: action)
16
14
  end
17
15
 
18
16
  # Loads a record using `#scope`
@@ -21,9 +19,7 @@ module Super
21
19
  # @param params [ActionController::Parameters]
22
20
  # @return [ActiveRecord::Base]
23
21
  def load_record(action:, params:)
24
- default_for(:load_record, action: action, params: params) do
25
- scope(action: action).find(params[:id])
26
- end
22
+ scope(action: action).find(params[:id])
27
23
  end
28
24
 
29
25
  # Builds a record using `#scope`
@@ -31,9 +27,7 @@ module Super
31
27
  # @param action [ActionInquirer]
32
28
  # @return [ActiveRecord::Base]
33
29
  def build_record(action:)
34
- default_for(:build_record) do
35
- scope(action: action).build
36
- end
30
+ scope(action: action).build
37
31
  end
38
32
 
39
33
  # Builds and populates a record using `#scope`
@@ -42,31 +36,25 @@ module Super
42
36
  # @param params [ActionController::Parameters]
43
37
  # @return [ActiveRecord::Base]
44
38
  def build_record_with_params(action:, params:)
45
- default_for(:build_record_with_params, action: action, params: params) do
46
- scope(action: action).build(permitted_params(params, action: action))
47
- end
39
+ scope(action: action).build(permitted_params(params, action: action))
48
40
  end
49
41
 
50
42
  # Saves a record
51
43
  #
52
44
  # @param action [ActionInquirer]
53
45
  # @param params [ActionController::Parameters]
54
- # @return [ActiveRecord::Base]
46
+ # @return [true, false]
55
47
  def save_record(action:, record:, params:)
56
- default_for(:save_record, action: action, record: record, params: params) do
57
- record.save
58
- end
48
+ record.save
59
49
  end
60
50
 
61
51
  # Saves a record
62
52
  #
63
53
  # @param action [ActionInquirer]
64
54
  # @param params [ActionController::Parameters]
65
- # @return [ActiveRecord::Base]
55
+ # @return [true, false]
66
56
  def update_record(action:, record:, params:)
67
- default_for(:update_record, action: action, record: record, params: params) do
68
- record.update(permitted_params(params, action: action))
69
- end
57
+ record.update(permitted_params(params, action: action))
70
58
  end
71
59
 
72
60
  # Destroys a record
@@ -75,9 +63,7 @@ module Super
75
63
  # @param params [ActionController::Parameters]
76
64
  # @return [ActiveRecord::Base, false]
77
65
  def destroy_record(action:, record:, params:)
78
- default_for(:update_record, action: action, record: record, params: params) do
79
- record.destroy
80
- end
66
+ record.destroy
81
67
  end
82
68
 
83
69
  def build_index_view
@@ -0,0 +1,72 @@
1
+ module Super
2
+ # This schema type is meant to be used for +#index+ or +#show+ actions to
3
+ # transform database fields into something that is human friendly.
4
+ #
5
+ # ```
6
+ # class MembersController::Controls
7
+ # # ...
8
+ #
9
+ # def show_schema
10
+ # Super::Display.new do |fields, type|
11
+ # fields[:name] = type.manual { |name| name }
12
+ # fields[:rank] = type.manual { |rank| rank }
13
+ # fields[:position] = type.manual { |position| position }
14
+ # fields[:ship] = type.manual { |ship| "#{ship.name} (Ship ##{ship.id})" }
15
+ # fields[:created_at] = type.manual { |created_at| created_at.iso8601 }
16
+ # fields[:updated_at] = type.manual { |updated_at| updated_at.iso8601 }
17
+ # end
18
+ # end
19
+ #
20
+ # # ...
21
+ # end
22
+ # ```
23
+ class Display
24
+ include Schema::Common
25
+
26
+ def initialize(action:)
27
+ @action_inquirer = action
28
+ @fields = Super::Schema::Fields.new
29
+ @schema_types = SchemaTypes.new(fields: @fields)
30
+
31
+ yield(@fields, @schema_types)
32
+
33
+ return if !@action_inquirer.index?
34
+ return if @schema_types.actions_called?
35
+ @fields[:actions] = @schema_types.actions
36
+ end
37
+
38
+ def to_partial_path
39
+ if @action_inquirer.index?
40
+ "super_schema_display_index"
41
+ elsif @action_inquirer.show?
42
+ "super_schema_display_show"
43
+ else
44
+ "super_schema_display_#{@action_inquirer.action}"
45
+ end
46
+ end
47
+
48
+ # @private
49
+ def render_field(template:, record:, column:)
50
+ formatter = @fields[column]
51
+
52
+ formatted =
53
+ if formatter.real?
54
+ value = record.public_send(column)
55
+ formatter.present(value)
56
+ else
57
+ formatter.present
58
+ end
59
+
60
+ if formatted.respond_to?(:to_partial_path)
61
+ if formatted.respond_to?(:locals)
62
+ formatted.locals[:record] ||= record
63
+ template.render(formatted, formatted.locals)
64
+ else
65
+ template.render(formatted)
66
+ end
67
+ else
68
+ formatted
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,34 @@
1
+ module Super
2
+ class Display
3
+ class Guesser
4
+ def initialize(model:, action:, fields:, type:)
5
+ @model = model
6
+ @action_inquirer = action
7
+ @fields = fields
8
+ @type = type
9
+ end
10
+
11
+ def call
12
+ Schema::Guesser
13
+ .new(model: @model, fields: @fields, type: @type)
14
+ .ignore_foreign_keys
15
+ .limit { 5 if @action_inquirer.index? }
16
+ .assign_type { |attribute_name| attribute_type_for(attribute_name) }
17
+ .call
18
+ end
19
+
20
+ private
21
+
22
+ def attribute_type_for(attribute_name)
23
+ type = @model.type_for_attribute(attribute_name).type
24
+
25
+ case type
26
+ when :datetime
27
+ @type.timestamp
28
+ else
29
+ @type.text
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end