super 0.0.6 → 0.0.11

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CONTRIBUTING.md +56 -0
  4. data/README.md +55 -57
  5. data/Rakefile +16 -14
  6. data/STABILITY.md +50 -0
  7. data/app/assets/javascripts/super/application.js +297 -97
  8. data/app/assets/stylesheets/super/application.css +5600 -0
  9. data/app/controllers/super/application_controller.rb +15 -6
  10. data/app/helpers/super/form_builder_helper.rb +25 -0
  11. data/app/views/layouts/super/application.html.erb +22 -6
  12. data/app/views/super/application/_display_rich_text.html.erb +1 -0
  13. data/app/views/super/application/_filter.html.erb +6 -0
  14. data/app/views/super/application/_filter_type_select.html.erb +21 -0
  15. data/app/views/super/application/_filter_type_text.html.erb +18 -0
  16. data/app/views/super/application/_filter_type_timestamp.html.erb +24 -0
  17. data/app/views/super/application/_form_field__destroy.html.erb +1 -9
  18. data/app/views/super/application/_form_field_checkbox.html.erb +1 -0
  19. data/app/views/super/application/_form_field_rich_text_area.html.erb +1 -0
  20. data/app/views/super/application/_form_field_select.html.erb +1 -23
  21. data/app/views/super/application/_form_field_text.html.erb +1 -13
  22. data/app/views/super/application/_query.html.erb +18 -0
  23. data/app/views/super/application/_sort.html.erb +18 -0
  24. data/app/views/super/application/_sort_expression.html.erb +25 -0
  25. data/app/views/super/application/_super_layout.html.erb +5 -5
  26. data/app/views/super/application/_super_pagination.html.erb +16 -0
  27. data/app/views/super/application/_super_panel.html.erb +2 -2
  28. data/app/views/super/application/_super_schema_display_index.html.erb +9 -24
  29. data/app/views/super/application/_super_schema_display_show.html.erb +4 -4
  30. data/app/views/super/application/_super_schema_form.html.erb +3 -3
  31. data/app/views/super/application/edit.html.erb +2 -6
  32. data/app/views/super/application/index.html.erb +2 -6
  33. data/app/views/super/application/new.html.erb +2 -6
  34. data/app/views/super/application/show.html.erb +2 -6
  35. data/app/views/super/feather/README.md +1 -0
  36. data/app/views/super/feather/_x.html +15 -0
  37. data/config/routes.rb +2 -0
  38. data/docs/README.md +4 -2
  39. data/docs/action_text.md +48 -0
  40. data/docs/cheat.md +8 -8
  41. data/docs/faq.md +3 -3
  42. data/docs/installation.md +21 -0
  43. data/docs/quick_start.md +1 -16
  44. data/docs/webpacker.md +13 -5
  45. data/docs/yard_customizations.rb +2 -0
  46. data/frontend/super-frontend/dist/application.css +5600 -0
  47. data/frontend/super-frontend/dist/application.js +297 -97
  48. data/lib/generators/super/action_text/USAGE +23 -0
  49. data/lib/generators/super/action_text/action_text_generator.rb +32 -0
  50. data/lib/generators/super/action_text/templates/pack_super_action_text.css +23 -0
  51. data/lib/generators/super/action_text/templates/pack_super_action_text.js +4 -0
  52. data/lib/generators/super/install/install_generator.rb +2 -0
  53. data/lib/generators/super/resource/resource_generator.rb +2 -0
  54. data/lib/generators/super/resource/templates/resources_controller.rb.tt +1 -31
  55. data/lib/generators/super/webpacker/USAGE +5 -4
  56. data/lib/generators/super/webpacker/webpacker_generator.rb +5 -2
  57. data/lib/super.rb +23 -2
  58. data/lib/super/action_inquirer.rb +2 -0
  59. data/lib/super/assets.rb +114 -38
  60. data/lib/super/client_error.rb +2 -0
  61. data/lib/super/compatibility.rb +15 -1
  62. data/lib/super/configuration.rb +22 -69
  63. data/lib/super/controls.rb +6 -25
  64. data/lib/super/controls/optional.rb +71 -24
  65. data/lib/super/controls/required.rb +3 -29
  66. data/lib/super/controls/steps.rb +44 -53
  67. data/lib/super/controls/view.rb +55 -0
  68. data/lib/super/display.rb +80 -0
  69. data/lib/super/display/guesser.rb +36 -0
  70. data/lib/super/display/schema_types.rb +28 -33
  71. data/lib/super/engine.rb +11 -1
  72. data/lib/super/error.rb +14 -0
  73. data/lib/super/filter.rb +14 -0
  74. data/lib/super/filter/form_object.rb +94 -0
  75. data/lib/super/filter/guesser.rb +32 -0
  76. data/lib/super/filter/operator.rb +105 -0
  77. data/lib/super/filter/schema_types.rb +114 -0
  78. data/lib/super/form.rb +29 -40
  79. data/lib/super/form/builder.rb +206 -0
  80. data/lib/super/form/guesser.rb +29 -0
  81. data/lib/super/form/inline_errors.rb +28 -0
  82. data/lib/super/form/schema_types.rb +31 -29
  83. data/lib/super/form/strong_params.rb +31 -0
  84. data/lib/super/layout.rb +2 -0
  85. data/lib/super/link.rb +2 -0
  86. data/lib/super/navigation/automatic.rb +2 -0
  87. data/lib/super/pagination.rb +57 -0
  88. data/lib/super/panel.rb +2 -0
  89. data/lib/super/partial.rb +14 -0
  90. data/lib/super/partial/resolving.rb +2 -0
  91. data/lib/super/plugin.rb +36 -63
  92. data/lib/super/query/form_object.rb +48 -0
  93. data/lib/super/schema.rb +2 -24
  94. data/lib/super/schema/common.rb +27 -0
  95. data/lib/super/schema/guesser.rb +79 -0
  96. data/lib/super/sort.rb +110 -0
  97. data/lib/super/version.rb +3 -1
  98. data/lib/super/view_helper.rb +2 -19
  99. metadata +74 -22
  100. data/app/helpers/super/application_helper.rb +0 -39
  101. data/app/views/super/application/_form_inline_errors.html.erb +0 -10
  102. data/frontend/super-frontend/build.js +0 -36
  103. data/frontend/super-frontend/package.json +0 -21
  104. data/frontend/super-frontend/postcss.config.js +0 -6
  105. data/frontend/super-frontend/src/javascripts/super/application.ts +0 -18
  106. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +0 -19
  107. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +0 -1
  108. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +0 -15
  109. data/frontend/super-frontend/src/stylesheets/super/application.css +0 -77
  110. data/frontend/super-frontend/tailwind.config.js +0 -15
  111. data/frontend/super-frontend/tsconfig.json +0 -13
  112. data/frontend/super-frontend/yarn.lock +0 -5448
@@ -1,36 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "super/controls/optional"
2
4
  require "super/controls/required"
3
5
  require "super/controls/steps"
6
+ require "super/controls/view"
4
7
 
5
8
  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.
9
+ # The base Controls class. Most parts of Super can be configured by
10
+ # customizing its methods.
9
11
  class Controls
10
12
  include Required
11
13
  include Optional
12
14
  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
15
+ include View
35
16
  end
36
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Controls
3
5
  # Methods for `Controls` that have a sane default implementation
@@ -6,9 +8,7 @@ module Super
6
8
  #
7
9
  # @return [String]
8
10
  def title
9
- default_for(:title) do
10
- model.name.pluralize
11
- end
11
+ model.name.pluralize
12
12
  end
13
13
 
14
14
  # Configures what database records are visible on load. This is an optional
@@ -17,20 +17,49 @@ module Super
17
17
  # @param action [ActionInquirer]
18
18
  # @return [ActiveRecord::Relation]
19
19
  def scope(action:)
20
- default_for(:scope, action: action) do
21
- model.all
20
+ model.all
21
+ end
22
+
23
+ # Configures the fields that are displayed on the index and show actions.
24
+ # This is a required method
25
+ #
26
+ # @param action [ActionInquirer]
27
+ # @return [Display]
28
+ def display_schema(action:)
29
+ Display.new do |fields, type|
30
+ Display::Guesser.new(model: model, action: action, fields: fields, type: type).call
22
31
  end
23
32
  end
24
33
 
34
+ # Configures the editable fields on the new and edit actions. This is a
35
+ # required method
36
+ #
37
+ # @param action [ActionInquirer]
38
+ # @return [Form]
39
+ def form_schema(action:)
40
+ Form.new do |fields, type|
41
+ Form::Guesser.new(model: model, fields: fields, type: type).call
42
+ end
43
+ end
44
+
45
+ # Configures which parameters could be written to the database. This is a
46
+ # required method
47
+ #
48
+ # @param params [ActionController::Parameters]
49
+ # @param action [ActionInquirer]
50
+ # @return [ActionController::Parameters]
51
+ def permitted_params(params, action:)
52
+ strong_params = Super::Form::StrongParams.new(form_schema(action: action))
53
+ params.require(strong_params.require(model)).permit(strong_params.permit)
54
+ end
55
+
25
56
  # Configures the actions linked to on the index page. This is an optional
26
57
  # method
27
58
  #
28
59
  # @param action [ActionInquirer]
29
60
  # @return [Array<Link>]
30
61
  def collection_actions(action:)
31
- default_for(:collection_actions, action: action) do
32
- Super::Link.find_all(:new)
33
- end
62
+ Super::Link.find_all(:new)
34
63
  end
35
64
 
36
65
  # Configures the actions linked to on the show page as well as each row of
@@ -39,27 +68,45 @@ module Super
39
68
  # @param action [ActionInquirer]
40
69
  # @return [Array<Link>]
41
70
  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
71
+ if action.show?
72
+ Super::Link.find_all(:edit, :destroy)
73
+ elsif action.edit?
74
+ Super::Link.find_all(:show, :destroy)
75
+ else
76
+ Super::Link.find_all(:show, :edit, :destroy)
50
77
  end
51
78
  end
52
79
 
53
- # Specifies how many records to show per page
54
- #
55
- # @param action [ActionInquirer]
56
- # @param query_params [Hash]
57
- # @return [ActiveRecord::Relation]
58
- def records_per_page(action:, query_params:)
59
- default_for(:records_per_page, action: action, query_params: query_params) do
60
- Super.configuration.index_records_per_page
80
+ def filters_enabled?
81
+ true
82
+ end
83
+
84
+ def filter_schema
85
+ Super::Filter.new do |fields, type|
86
+ Super::Filter::Guesser.new(model: model, fields: fields, type: type).call
61
87
  end
62
88
  end
89
+
90
+ def sort_enabled?
91
+ true
92
+ end
93
+
94
+ def sortable_columns
95
+ action = ActionInquirer.new(
96
+ ActionInquirer.default_for_resources,
97
+ "index"
98
+ )
99
+ attribute_names =
100
+ display_schema(action: action).each_attribute.map do |key, val|
101
+ key if val.real?
102
+ end
103
+
104
+ attribute_names.compact
105
+ end
106
+
107
+ def default_sort
108
+ { id: :desc }
109
+ end
63
110
  end
64
111
  end
65
112
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Controls
3
5
  # Methods for `Controls` that must be defined for Super to work properly
@@ -6,35 +8,7 @@ module Super
6
8
  #
7
9
  # @return [ActiveRecord::Base]
8
10
  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)
11
+ raise NotImplementedError
38
12
  end
39
13
  end
40
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Controls
3
5
  # Methods that are called by controller actions. All of these methods have
@@ -10,40 +12,7 @@ module Super
10
12
  # @param params [ActionController::Parameters]
11
13
  # @return [ActiveRecord::Relation]
12
14
  def load_records(action:, params:)
13
- default_for(:load_records, action: action, params: params) do
14
- scope(action: action)
15
- end
16
- end
17
-
18
- # Sets up pagination
19
- #
20
- # @param action [ActionInquirer]
21
- # @param records [ActiveRecord::Relation]
22
- # @param query_params [Hash]
23
- # @return [Pagination]
24
- def initialize_pagination(action:, records:, query_params:)
25
- default_for(:initialize_pagination, action: action, records: records, query_params: query_params) do
26
- Pagination.new(
27
- total_count: records.size,
28
- limit: records_per_page(action: action, query_params: query_params),
29
- query_params: query_params,
30
- page_query_param: :page
31
- )
32
- end
33
- end
34
-
35
- # Paginates
36
- #
37
- # @param action [ActionInquirer]
38
- # @param records [ActiveRecord::Relation]
39
- # @param pagination [Pagination]
40
- # @return [ActiveRecord::Relation]
41
- def paginate_records(action:, records:, pagination:)
42
- default_for(:paginate_records, action: action, records: records, pagination: pagination) do
43
- records
44
- .limit(pagination.limit)
45
- .offset(pagination.offset)
46
- end
15
+ scope(action: action)
47
16
  end
48
17
 
49
18
  # Loads a record using `#scope`
@@ -52,9 +21,7 @@ module Super
52
21
  # @param params [ActionController::Parameters]
53
22
  # @return [ActiveRecord::Base]
54
23
  def load_record(action:, params:)
55
- default_for(:load_record, action: action, params: params) do
56
- scope(action: action).find(params[:id])
57
- end
24
+ scope(action: action).find(params[:id])
58
25
  end
59
26
 
60
27
  # Builds a record using `#scope`
@@ -62,9 +29,7 @@ module Super
62
29
  # @param action [ActionInquirer]
63
30
  # @return [ActiveRecord::Base]
64
31
  def build_record(action:)
65
- default_for(:build_record) do
66
- scope(action: action).build
67
- end
32
+ scope(action: action).build
68
33
  end
69
34
 
70
35
  # Builds and populates a record using `#scope`
@@ -73,31 +38,25 @@ module Super
73
38
  # @param params [ActionController::Parameters]
74
39
  # @return [ActiveRecord::Base]
75
40
  def build_record_with_params(action:, params:)
76
- default_for(:build_record_with_params, action: action, params: params) do
77
- scope(action: action).build(permitted_params(params, action: action))
78
- end
41
+ scope(action: action).build(permitted_params(params, action: action))
79
42
  end
80
43
 
81
44
  # Saves a record
82
45
  #
83
46
  # @param action [ActionInquirer]
84
47
  # @param params [ActionController::Parameters]
85
- # @return [ActiveRecord::Base]
48
+ # @return [true, false]
86
49
  def save_record(action:, record:, params:)
87
- default_for(:save_record, action: action, record: record, params: params) do
88
- record.save
89
- end
50
+ record.save
90
51
  end
91
52
 
92
53
  # Saves a record
93
54
  #
94
55
  # @param action [ActionInquirer]
95
56
  # @param params [ActionController::Parameters]
96
- # @return [ActiveRecord::Base]
57
+ # @return [true, false]
97
58
  def update_record(action:, record:, params:)
98
- default_for(:update_record, action: action, record: record, params: params) do
99
- record.update(permitted_params(params, action: action))
100
- end
59
+ record.update(permitted_params(params, action: action))
101
60
  end
102
61
 
103
62
  # Destroys a record
@@ -106,8 +65,40 @@ module Super
106
65
  # @param params [ActionController::Parameters]
107
66
  # @return [ActiveRecord::Base, false]
108
67
  def destroy_record(action:, record:, params:)
109
- default_for(:update_record, action: action, record: record, params: params) do
110
- record.destroy
68
+ record.destroy
69
+ end
70
+
71
+ def initialize_query_form(params:, current_path:)
72
+ Super::Query::FormObject.new(
73
+ model: model,
74
+ params: params,
75
+ namespace: :q,
76
+ current_path: current_path,
77
+ )
78
+ end
79
+
80
+ def apply_queries(query_form:, records:)
81
+ query_form.apply_changes(records)
82
+ end
83
+
84
+ def initialize_filter_form(query_form:)
85
+ if filters_enabled?
86
+ query_form.add(
87
+ Super::Filter::FormObject,
88
+ namespace: :f,
89
+ schema: filter_schema
90
+ )
91
+ end
92
+ end
93
+
94
+ def initialize_sort_form(query_form:)
95
+ if sort_enabled?
96
+ query_form.add(
97
+ Super::Sort::FormObject,
98
+ namespace: :s,
99
+ default: default_sort,
100
+ sortable_columns: sortable_columns
101
+ )
111
102
  end
112
103
  end
113
104
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Controls
5
+ # Methods for `Controls` that have a sane default implementation
6
+ module View
7
+ def index_view
8
+ Super::Layout.new(
9
+ mains: [
10
+ Super::Panel.new(
11
+ Super::Partial.new("collection_header"),
12
+ :@display
13
+ ),
14
+ ],
15
+ asides: [
16
+ :@query_form,
17
+ ]
18
+ )
19
+ end
20
+
21
+ def show_view
22
+ Super::Layout.new(
23
+ mains: [
24
+ Super::Panel.new(
25
+ Super::Partial.new("member_header"),
26
+ :@display
27
+ ),
28
+ ]
29
+ )
30
+ end
31
+
32
+ def new_view
33
+ Super::Layout.new(
34
+ mains: [
35
+ Super::Panel.new(
36
+ Super::Partial.new("collection_header"),
37
+ :@form
38
+ ),
39
+ ]
40
+ )
41
+ end
42
+
43
+ def edit_view
44
+ Super::Layout.new(
45
+ mains: [
46
+ Super::Panel.new(
47
+ Super::Partial.new("member_header"),
48
+ :@form
49
+ ),
50
+ ]
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ # This schema type is meant to be used for +#index+ or +#show+ actions to
5
+ # transform database fields into something that is human friendly.
6
+ #
7
+ # ```
8
+ # class MembersController::Controls
9
+ # # ...
10
+ #
11
+ # def show_schema
12
+ # Super::Display.new do |fields, type|
13
+ # fields[:name] = type.manual { |name| name }
14
+ # fields[:rank] = type.manual { |rank| rank }
15
+ # fields[:position] = type.manual { |position| position }
16
+ # fields[:ship] = type.manual { |ship| "#{ship.name} (Ship ##{ship.id})" }
17
+ # fields[:created_at] = type.manual { |created_at| created_at.iso8601 }
18
+ # fields[:updated_at] = type.manual { |updated_at| updated_at.iso8601 }
19
+ # end
20
+ # end
21
+ #
22
+ # # ...
23
+ # end
24
+ # ```
25
+ class Display
26
+ include Schema::Common
27
+
28
+ def initialize
29
+ @fields = Super::Schema::Fields.new
30
+ @schema_types = SchemaTypes.new(fields: @fields)
31
+
32
+ yield(@fields, @schema_types)
33
+ end
34
+
35
+ def apply(action:)
36
+ @action_inquirer = action
37
+ return self if !@action_inquirer.index?
38
+ return self if @schema_types.actions_called?
39
+ @fields[:actions] = @schema_types.actions
40
+ self
41
+ end
42
+
43
+ def to_partial_path
44
+ if @action_inquirer.nil?
45
+ raise Super::Error::Initalization,
46
+ "You must call the `#apply` method after instantiating Super::Display"
47
+ elsif @action_inquirer.index?
48
+ "super_schema_display_index"
49
+ elsif @action_inquirer.show?
50
+ "super_schema_display_show"
51
+ else
52
+ "super_schema_display_#{@action_inquirer.action}"
53
+ end
54
+ end
55
+
56
+ # @private
57
+ def render_field(template:, record:, column:)
58
+ formatter = @fields[column]
59
+
60
+ formatted =
61
+ if formatter.real?
62
+ value = record.public_send(column)
63
+ formatter.present(value)
64
+ else
65
+ formatter.present
66
+ end
67
+
68
+ if formatted.respond_to?(:to_partial_path)
69
+ if formatted.respond_to?(:locals)
70
+ formatted.locals[:record] ||= record
71
+ template.render(formatted, formatted.locals)
72
+ else
73
+ template.render(formatted)
74
+ end
75
+ else
76
+ formatted
77
+ end
78
+ end
79
+ end
80
+ end