super 0.0.8 → 0.0.13

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +0 -7
  3. data/README.md +53 -79
  4. data/app/assets/javascripts/super/application.js +2728 -96
  5. data/app/assets/stylesheets/super/application.css +6405 -0
  6. data/app/controllers/super/application_controller.rb +19 -13
  7. data/app/helpers/super/form_builder_helper.rb +25 -0
  8. data/app/views/layouts/super/application.html.erb +11 -5
  9. data/app/views/super/application/{_super_schema_display_actions.html.erb → _display_actions.html.erb} +0 -0
  10. data/app/views/super/application/{_super_schema_display_index.html.erb → _display_index.html.erb} +5 -5
  11. data/app/views/super/application/_display_rich_text.html.erb +1 -0
  12. data/app/views/super/application/_display_show.html.erb +8 -0
  13. data/app/views/super/application/_filter.html.erb +5 -13
  14. data/app/views/super/application/_filter_type_select.html.erb +9 -19
  15. data/app/views/super/application/_filter_type_text.html.erb +7 -11
  16. data/app/views/super/application/_filter_type_timestamp.html.erb +6 -17
  17. data/app/views/super/application/_form.html.erb +15 -0
  18. data/app/views/super/application/_form_field__destroy.html.erb +1 -9
  19. data/app/views/super/application/_form_field_checkbox.html.erb +1 -0
  20. data/app/views/super/application/_form_field_flatpickr_date.html.erb +8 -0
  21. data/app/views/super/application/_form_field_flatpickr_datetime.html.erb +8 -0
  22. data/app/views/super/application/_form_field_flatpickr_time.html.erb +8 -0
  23. data/app/views/super/application/_form_field_rich_text_area.html.erb +1 -0
  24. data/app/views/super/application/_form_field_select.html.erb +1 -23
  25. data/app/views/super/application/_form_field_text.html.erb +1 -13
  26. data/app/views/super/application/{_super_layout.html.erb → _layout.html.erb} +7 -7
  27. data/app/views/super/application/{_super_pagination.html.erb → _pagination.html.erb} +1 -1
  28. data/app/views/super/application/{_super_panel.html.erb → _panel.html.erb} +2 -2
  29. data/app/views/super/application/_query.html.erb +18 -0
  30. data/app/views/super/application/_sort.html.erb +18 -0
  31. data/app/views/super/application/_sort_expression.html.erb +25 -0
  32. data/app/views/super/application/edit.html.erb +1 -0
  33. data/app/views/super/application/index.html.erb +1 -0
  34. data/app/views/super/application/new.html.erb +1 -0
  35. data/app/views/super/application/show.html.erb +1 -0
  36. data/app/views/super/feather/README.md +1 -0
  37. data/app/views/super/feather/_x.html +15 -0
  38. data/config/routes.rb +2 -0
  39. data/docs/cheat.md +8 -8
  40. data/frontend/super-frontend/dist/application.css +6405 -0
  41. data/frontend/super-frontend/dist/application.js +2728 -96
  42. data/lib/generators/super/action_text/USAGE +23 -0
  43. data/lib/generators/super/action_text/action_text_generator.rb +32 -0
  44. data/lib/generators/super/action_text/templates/pack_super_action_text.css +23 -0
  45. data/lib/generators/super/action_text/templates/pack_super_action_text.js +4 -0
  46. data/lib/generators/super/install/install_generator.rb +18 -7
  47. data/lib/generators/super/install/templates/base_controller.rb.tt +9 -1
  48. data/lib/generators/super/install/templates/initializer.rb.tt +9 -2
  49. data/lib/generators/super/resource/resource_generator.rb +107 -30
  50. data/lib/generators/super/resource/templates/resources_controller.rb.tt +3 -9
  51. data/lib/generators/super/webpacker/USAGE +5 -4
  52. data/lib/generators/super/webpacker/webpacker_generator.rb +2 -0
  53. data/lib/super.rb +7 -1
  54. data/lib/super/action_inquirer.rb +2 -0
  55. data/lib/super/assets.rb +6 -0
  56. data/lib/super/client_error.rb +2 -0
  57. data/lib/super/compatibility.rb +2 -0
  58. data/lib/super/configuration.rb +16 -24
  59. data/lib/super/controls.rb +11 -2
  60. data/lib/super/controls/optional.rb +35 -1
  61. data/lib/super/controls/steps.rb +27 -35
  62. data/lib/super/controls/view.rb +55 -0
  63. data/lib/super/display.rb +29 -13
  64. data/lib/super/display/guesser.rb +4 -0
  65. data/lib/super/display/schema_types.rb +74 -28
  66. data/lib/super/engine.rb +4 -0
  67. data/lib/super/error.rb +21 -0
  68. data/lib/super/filter.rb +2 -0
  69. data/lib/super/filter/form_object.rb +5 -8
  70. data/lib/super/filter/guesser.rb +2 -0
  71. data/lib/super/filter/operator.rb +2 -0
  72. data/lib/super/filter/schema_types.rb +2 -0
  73. data/lib/super/form.rb +3 -1
  74. data/lib/super/form/builder.rb +289 -39
  75. data/lib/super/form/guesser.rb +12 -1
  76. data/lib/super/form/inline_errors.rb +28 -0
  77. data/lib/super/form/schema_types.rb +25 -0
  78. data/lib/super/form/strong_params.rb +2 -0
  79. data/lib/super/layout.rb +3 -1
  80. data/lib/super/link.rb +7 -0
  81. data/lib/super/navigation/automatic.rb +4 -2
  82. data/lib/super/pagination.rb +3 -1
  83. data/lib/super/panel.rb +3 -1
  84. data/lib/super/partial.rb +2 -0
  85. data/lib/super/partial/resolving.rb +2 -0
  86. data/lib/super/plugin.rb +2 -0
  87. data/lib/super/query/form_object.rb +48 -0
  88. data/lib/super/schema.rb +2 -0
  89. data/lib/super/schema/common.rb +2 -0
  90. data/lib/super/schema/guesser.rb +2 -0
  91. data/lib/super/sort.rb +110 -0
  92. data/lib/super/useful/builder.rb +25 -0
  93. data/lib/super/useful/enum.rb +63 -0
  94. data/lib/super/version.rb +3 -1
  95. data/lib/super/view_helper.rb +2 -19
  96. metadata +56 -38
  97. data/CONTRIBUTING.md +0 -56
  98. data/Rakefile +0 -34
  99. data/STABILITY.md +0 -50
  100. data/app/views/super/application/_form_inline_errors.html.erb +0 -10
  101. data/app/views/super/application/_super_schema_display_show.html.erb +0 -8
  102. data/app/views/super/application/_super_schema_form.html.erb +0 -15
  103. data/docs/README.md +0 -6
  104. data/docs/faq.md +0 -44
  105. data/docs/quick_start.md +0 -45
  106. data/docs/webpacker.md +0 -17
  107. data/docs/yard_customizations.rb +0 -41
  108. data/frontend/super-frontend/build.js +0 -36
  109. data/frontend/super-frontend/package.json +0 -21
  110. data/frontend/super-frontend/postcss.config.js +0 -6
  111. data/frontend/super-frontend/src/javascripts/super/application.ts +0 -15
  112. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +0 -19
  113. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +0 -1
  114. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +0 -15
  115. data/frontend/super-frontend/src/stylesheets/super/application.css +0 -77
  116. data/frontend/super-frontend/tailwind.config.js +0 -15
  117. data/frontend/super-frontend/tsconfig.json +0 -13
  118. data/frontend/super-frontend/yarn.lock +0 -5448
  119. data/lib/super/controls/required.rb +0 -13
  120. data/lib/super/filter/plugin.rb +0 -47
data/lib/super/engine.rb CHANGED
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # Configures the host Rails app to work with Super
3
5
  class Engine < ::Rails::Engine
6
+ isolate_namespace Super
7
+
4
8
  initializer "super.assets.precompile" do |app|
5
9
  if Super::Assets::Handler.sprockets_available?
6
10
  app.config.assets.precompile << "config/super_manifest.js"
data/lib/super/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # A container class for all internal errors thrown by this library
3
5
  #
@@ -13,5 +15,24 @@ module Super
13
15
  class ActionInquirerError < Error; end
14
16
  # Error raised when a `Super::Link` couldn't be found
15
17
  class LinkNotRegistered < Error; end
18
+ # Error raised when rendering if `@view` wasn't set by the controller
19
+ class NothingToRender < Error
20
+ def initialize(basename)
21
+ super(
22
+ "Super's built-in `#{basename}.html.erb` requires `@view` to be set " \
23
+ "by the controller, but it wasn't set"
24
+ )
25
+ end
26
+ end
27
+ # Error raised when something wasn't initalized correctly, and if there isn't
28
+ # a more specific error
29
+ class Initalization < Error; end
30
+ class ArgumentError < Error; end
31
+
32
+ class Enum < Error
33
+ class ImpossibleValue < Enum; end
34
+ class ArgumentError < Enum; end
35
+ class UndefinedCase < Enum; end
36
+ end
16
37
  end
17
38
  end
data/lib/super/filter.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Filter
3
5
  def initialize
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Filter
3
5
  class FormObject
@@ -42,11 +44,10 @@ module Super
42
44
  end
43
45
  end
44
46
 
45
- def initialize(model:, url:, schema:, params:)
47
+ def initialize(model:, params:, schema:)
46
48
  @model = model
47
- @url = url
48
- @schema = schema
49
49
  @params = params
50
+ @schema = schema
50
51
 
51
52
  @form_fields = {}
52
53
  end
@@ -57,15 +58,11 @@ module Super
57
58
  end
58
59
  end
59
60
 
60
- def url
61
- @url
62
- end
63
-
64
61
  def to_partial_path
65
62
  "filter"
66
63
  end
67
64
 
68
- def to_search_query(relation)
65
+ def apply_changes(relation)
69
66
  each_field do |form_field|
70
67
  next if form_field.specified_values.values.map(&:to_s).map(&:strip).all? { |specified_value| specified_value == "" }
71
68
  next if !Super::Filter::Operator.registry.key?(form_field.op)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Filter
3
5
  class Guesser
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Filter
3
5
  module Operator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Filter
3
5
  # This schema type is used to configure the filtering form on your +#index+
data/lib/super/form.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # This schema type is used on your +#edit+ and +#new+ forms
3
5
  #
@@ -29,7 +31,7 @@ module Super
29
31
  end
30
32
 
31
33
  def to_partial_path
32
- "super_schema_form"
34
+ "form"
33
35
  end
34
36
  end
35
37
  end
@@ -1,48 +1,298 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Form
3
- module FieldErrorProc
4
- def error_wrapping(html_tag)
5
- if Thread.current[:super_form_builder]
6
- return html_tag
7
- end
5
+ # Example
6
+ #
7
+ # ```ruby
8
+ # super_form_for([:admin, @member]) do |f|
9
+ # # the long way
10
+ # f.super.label :name
11
+ # f.super.text_field :name
12
+ # f.super.inline_errors :name
13
+ #
14
+ # # the short way (slightly different from the long way, for alignment)
15
+ # f.super.text_field! :position
16
+ # end
17
+ # ```
18
+ #
19
+ # Refer to the Rails docs:
20
+ # https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
21
+ class Builder < ActionView::Helpers::FormBuilder
22
+ FIELD_ERROR_PROC = proc { |html_tag, instance| html_tag }
23
+ FORM_BUILDER_DEFAULTS = { builder: self }.freeze
8
24
 
9
- super
25
+ def super(**options)
26
+ @super_wrappers ||= Wrappers.new(self, @template)
10
27
  end
11
- end
12
28
 
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
29
+ class Wrappers
30
+ def initialize(builder, template)
31
+ @builder = builder
32
+ @template = template
33
+ end
34
+
35
+ def inline_errors(attribute)
36
+ if @builder.object
37
+ messages = InlineErrors.error_messages(@builder.object, attribute).map do |msg|
38
+ error_content_tag(msg)
39
+ end
40
+
41
+ @template.safe_join(messages)
42
+ else
43
+ error_content_tag(<<~MSG.html_safe)
44
+ This form doesn't have an object, so something is probably wrong.
45
+ Maybe <code>accepts_nested_attributes_for</code> isn't set up?
46
+ MSG
47
+ end
48
+ end
49
+
50
+ def label(attribute, text = nil, options = {}, &block)
51
+ options, defaults = split_defaults(options, class: "block")
52
+ options[:class] = join_classes(defaults[:class], options[:class])
53
+
54
+ @builder.label(attribute, text, options, &block)
55
+ end
56
+
57
+ def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0")
58
+ @builder.check_box(attribute, options, checked_value, unchecked_value)
59
+ end
60
+
61
+ def flatpickr_date(attribute, options = {})
62
+ options, defaults = split_defaults(
63
+ options,
64
+ class: "super-input w-full",
65
+ data: {
66
+ controller: "flatpickr",
67
+ flatpickr_options_value: {
68
+ dateFormat: "Y-m-d",
69
+ }
70
+ }
71
+ )
72
+ options[:class] = join_classes(defaults[:class], options[:class])
73
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
74
+
75
+ @builder.text_field(attribute, options)
76
+ end
77
+
78
+ def flatpickr_datetime(attribute, options = {})
79
+ options, defaults = split_defaults(
80
+ options,
81
+ class: "super-input w-full",
82
+ data: {
83
+ controller: "flatpickr",
84
+ flatpickr_options_value: {
85
+ enableSeconds: true,
86
+ enableTime: true,
87
+ dateFormat: "Z",
88
+ }
89
+ }
90
+ )
91
+ options[:class] = join_classes(defaults[:class], options[:class])
92
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
39
93
 
40
- alias datetime_local_field datetime_field
41
- alias phone_field telephone_field
94
+ @builder.text_field(attribute, options)
95
+ end
96
+
97
+ def flatpickr_time(attribute, options = {})
98
+ options, defaults = split_defaults(
99
+ options,
100
+ class: "super-input w-full",
101
+ data: {
102
+ controller: "flatpickr",
103
+ flatpickr_options_value: {
104
+ enableSeconds: true,
105
+ enableTime: true,
106
+ noCalendar: true,
107
+ dateFormat: "H:i:S",
108
+ }
109
+ }
110
+ )
111
+ options[:class] = join_classes(defaults[:class], options[:class])
112
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
113
+
114
+ @builder.text_field(attribute, options)
115
+ end
116
+
117
+ def password_field(attribute, options = {})
118
+ options, defaults = split_defaults(options, class: "super-input w-full")
119
+ options[:class] = join_classes(defaults[:class], options[:class])
120
+
121
+ @builder.password_field(attribute, options)
122
+ end
123
+
124
+ def rich_text_area(attribute, options = {})
125
+ options, defaults = split_defaults(options, class: "trix-content super-input w-full")
126
+ options[:class] = join_classes(defaults[:class], options[:class])
127
+
128
+ @builder.rich_text_area(attribute, options)
129
+ end
130
+
131
+ def select(attribute, choices, options = {}, html_options = {}, &block)
132
+ options, defaults = split_defaults(options, include_blank: true)
133
+ options = defaults.merge(options)
134
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select-field")
135
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
136
+
137
+ parts = [
138
+ %(<div class="super-input-select">).html_safe,
139
+ @builder.select(attribute, choices, options, html_options, &block),
140
+ <<~HTML.html_safe,
141
+ <div class="super-input-select-icon text-blue-700">
142
+ <span class="h-4 w-4">
143
+ HTML
144
+ @template.render("super/feather/chevron_down"),
145
+ <<~HTML.html_safe,
146
+ </span>
147
+ </div>
148
+ HTML
149
+ %(</div>).html_safe,
150
+ ]
151
+
152
+ @template.safe_join(parts)
153
+ end
154
+
155
+ def submit(value = nil, options = {})
156
+ value, options = nil, value if value.is_a?(Hash)
157
+ options, defaults = split_defaults(options, class: "super-button")
158
+ options[:class] = join_classes(defaults[:class], options[:class])
159
+
160
+ @builder.submit(value, options)
161
+ end
162
+
163
+ def text_field(attribute, options = {})
164
+ options, defaults = split_defaults(options, class: "super-input w-full")
165
+ options[:class] = join_classes(defaults[:class], options[:class])
166
+
167
+ @builder.text_field(attribute, options)
168
+ end
169
+
170
+ def container(&block)
171
+ @template.content_tag(:div, class: "super-field-group", &block)
172
+ end
173
+
174
+ def check_box!(attribute, checked_value = "1", unchecked_value = "0", label: {}, field: {}, show_errors: true)
175
+ label[:super] ||= {}
176
+ label[:super] = { class: "select-none ml-1" }.merge(label[:super])
177
+ container do
178
+ compact_join([
179
+ "<div>".html_safe,
180
+ public_send(:check_box, attribute, field, checked_value, unchecked_value),
181
+ public_send(:label, attribute, nil, label),
182
+ "</div>".html_safe,
183
+ show_errors && inline_errors(attribute),
184
+ ])
185
+ end
186
+ end
187
+
188
+ def flatpickr_date!(attribute, label: {}, field: {}, show_errors: true)
189
+ container do
190
+ compact_join([
191
+ public_send(:label, attribute, label),
192
+ %(<div class="mt-1">).html_safe,
193
+ public_send(:flatpickr_date, attribute, field),
194
+ show_errors && inline_errors(attribute),
195
+ %(</div>).html_safe,
196
+ ])
197
+ end
198
+ end
199
+
200
+ def flatpickr_datetime!(attribute, label: {}, field: {}, show_errors: true)
201
+ container do
202
+ compact_join([
203
+ public_send(:label, attribute, label),
204
+ %(<div class="mt-1">).html_safe,
205
+ public_send(:flatpickr_datetime, attribute, field),
206
+ show_errors && inline_errors(attribute),
207
+ %(</div>).html_safe,
208
+ ])
209
+ end
210
+ end
211
+
212
+ def flatpickr_time!(attribute, label: {}, field: {}, show_errors: true)
213
+ container do
214
+ compact_join([
215
+ public_send(:label, attribute, label),
216
+ %(<div class="mt-1">).html_safe,
217
+ public_send(:flatpickr_time, attribute, field),
218
+ show_errors && inline_errors(attribute),
219
+ %(</div>).html_safe,
220
+ ])
221
+ end
222
+ end
223
+
224
+ def password_field!(attribute, label: {}, field: {}, show_errors: true)
225
+ container do
226
+ compact_join([
227
+ public_send(:label, attribute, label),
228
+ %(<div class="mt-1">).html_safe,
229
+ public_send(:password_field, attribute, field),
230
+ show_errors && inline_errors(attribute),
231
+ %(</div>).html_safe,
232
+ ])
233
+ end
234
+ end
235
+
236
+ def rich_text_area!(attribute, label: {}, field: {}, show_errors: true)
237
+ container do
238
+ compact_join([
239
+ public_send(:label, attribute, label),
240
+ %(<div class="mt-1">).html_safe,
241
+ public_send(:rich_text_area, attribute, field),
242
+ show_errors && inline_errors(attribute),
243
+ %(</div>).html_safe,
244
+ ])
245
+ end
246
+ end
247
+
248
+ def select!(attribute, collection, label: {}, field: {}, show_errors: true)
249
+ container do
250
+ compact_join([
251
+ public_send(:label, attribute, label),
252
+ %(<div class="mt-1">).html_safe,
253
+ public_send(:select, attribute, collection, field),
254
+ show_errors && inline_errors(attribute),
255
+ %(</div>).html_safe,
256
+ ])
257
+ end
258
+ end
259
+
260
+ def text_field!(attribute, label: {}, field: {}, show_errors: true)
261
+ container do
262
+ compact_join([
263
+ public_send(:label, attribute, label),
264
+ %(<div class="mt-1">).html_safe,
265
+ public_send(:text_field, attribute, field),
266
+ show_errors && inline_errors(attribute),
267
+ %(</div>).html_safe,
268
+ ])
269
+ end
270
+ end
271
+
272
+ private
273
+
274
+ def split_defaults(options, **internal_defaults)
275
+ defaults = options.delete(:super) || {}
276
+ # prefer options set in `defaults`, since they are user overrides
277
+ defaults = internal_defaults.merge(defaults)
278
+
279
+ [options, defaults]
280
+ end
281
+
282
+ def join_classes(*class_lists)
283
+ class_lists.flatten.map(&:presence).compact
284
+ end
285
+
286
+ def error_content_tag(content)
287
+ @template.content_tag(:p, content, class: "text-red-400 text-xs italic pt-1")
288
+ end
289
+
290
+ def compact_join(*parts)
291
+ @template.safe_join(
292
+ parts.flatten.map(&:presence).compact
293
+ )
294
+ end
295
+ end
42
296
  end
43
297
  end
44
298
  end
45
-
46
- ActionView::Helpers::Tags::Base.class_eval do
47
- prepend Super::Form::FieldErrorProc
48
- end