super 0.0.6 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
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