super 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/README.md +68 -76
  4. data/app/assets/javascripts/super/application.js +1252 -316
  5. data/app/assets/stylesheets/super/application.css +102704 -17321
  6. data/app/controllers/super/application_controller.rb +49 -71
  7. data/app/views/layouts/super/application.html.erb +10 -8
  8. data/app/views/super/application/_collection_header.html.erb +15 -0
  9. data/app/views/super/application/_filter.html.erb +14 -0
  10. data/app/views/super/application/_filter_type_select.html.erb +31 -0
  11. data/app/views/super/application/_filter_type_text.html.erb +22 -0
  12. data/app/views/super/application/_filter_type_timestamp.html.erb +35 -0
  13. data/app/views/super/application/_flash.html.erb +13 -13
  14. data/app/views/super/application/_form_field__destroy.html.erb +9 -0
  15. data/app/views/super/application/_form_field_select.html.erb +23 -0
  16. data/app/views/super/application/_form_field_text.html.erb +13 -0
  17. data/app/views/super/application/_form_fieldset.html.erb +8 -0
  18. data/app/views/super/application/_form_has_many.html.erb +21 -0
  19. data/app/views/super/application/_form_has_one.html.erb +11 -0
  20. data/app/views/super/application/_form_inline_errors.html.erb +10 -0
  21. data/app/views/super/application/_member_header.html.erb +16 -0
  22. data/app/views/super/application/_super_layout.html.erb +29 -0
  23. data/app/views/super/application/_super_pagination.html.erb +16 -0
  24. data/app/views/super/application/_super_panel.html.erb +7 -0
  25. data/app/views/super/application/_super_schema_display_actions.html.erb +5 -0
  26. data/app/views/super/application/_super_schema_display_index.html.erb +24 -0
  27. data/app/views/super/application/_super_schema_display_show.html.erb +8 -0
  28. data/app/views/super/application/_super_schema_form.html.erb +15 -0
  29. data/app/views/super/application/edit.html.erb +1 -6
  30. data/app/views/super/application/index.html.erb +1 -1
  31. data/app/views/super/application/new.html.erb +1 -6
  32. data/app/views/super/application/show.html.erb +1 -1
  33. data/app/views/super/feather/{_chevron_down.svg → _chevron_down.html} +0 -0
  34. data/config/locales/en.yml +5 -0
  35. data/docs/README.md +6 -0
  36. data/docs/cheat.md +41 -0
  37. data/docs/faq.md +44 -0
  38. data/docs/quick_start.md +45 -0
  39. data/docs/webpacker.md +17 -0
  40. data/docs/yard_customizations.rb +41 -0
  41. data/frontend/super-frontend/build.js +14 -12
  42. data/frontend/super-frontend/dist/application.css +102704 -17321
  43. data/frontend/super-frontend/dist/application.js +1252 -316
  44. data/frontend/super-frontend/package.json +11 -4
  45. data/frontend/super-frontend/postcss.config.js +4 -4
  46. data/frontend/super-frontend/src/javascripts/super/application.ts +18 -0
  47. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +19 -0
  48. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +1 -0
  49. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +15 -0
  50. data/frontend/super-frontend/src/stylesheets/super/application.css +63 -0
  51. data/frontend/super-frontend/tailwind.config.js +12 -4
  52. data/frontend/super-frontend/tsconfig.json +13 -0
  53. data/frontend/super-frontend/yarn.lock +1891 -1798
  54. data/lib/generators/super/install/install_generator.rb +16 -0
  55. data/lib/generators/super/webpacker/webpacker_generator.rb +8 -0
  56. data/lib/super.rb +16 -6
  57. data/lib/super/action_inquirer.rb +14 -1
  58. data/lib/super/assets.rb +1 -0
  59. data/lib/super/client_error.rb +43 -0
  60. data/lib/super/compatibility.rb +25 -0
  61. data/lib/super/configuration.rb +66 -44
  62. data/lib/super/controls.rb +26 -15
  63. data/lib/super/controls/optional.rb +54 -0
  64. data/lib/super/controls/required.rb +41 -0
  65. data/lib/super/controls/steps.rb +128 -0
  66. data/lib/super/display/schema_types.rb +90 -18
  67. data/lib/super/engine.rb +7 -0
  68. data/lib/super/error.rb +9 -8
  69. data/lib/super/filter.rb +137 -0
  70. data/lib/super/filter/operator.rb +103 -0
  71. data/lib/super/filter/schema_types.rb +118 -0
  72. data/lib/super/form.rb +48 -0
  73. data/lib/super/form/schema_types.rb +96 -21
  74. data/lib/super/layout.rb +47 -0
  75. data/lib/super/link.rb +110 -0
  76. data/lib/super/navigation/automatic.rb +2 -0
  77. data/lib/super/pagination.rb +80 -8
  78. data/lib/super/panel.rb +30 -0
  79. data/lib/super/partial.rb +23 -0
  80. data/lib/super/partial/resolving.rb +24 -0
  81. data/lib/super/plugin.rb +34 -63
  82. data/lib/super/schema.rb +65 -1
  83. data/lib/super/version.rb +1 -1
  84. data/lib/super/view_helper.rb +43 -0
  85. metadata +132 -33
  86. data/app/views/super/application/_form.html.erb +0 -15
  87. data/app/views/super/application/_form_field.html.erb +0 -7
  88. data/app/views/super/application/_form_generic_select.html.erb +0 -19
  89. data/app/views/super/application/_form_generic_text.html.erb +0 -7
  90. data/app/views/super/application/_index.html.erb +0 -60
  91. data/app/views/super/application/_show.html.erb +0 -12
  92. data/frontend/super-frontend/src/javascripts/super/application.js +0 -11
  93. data/lib/super/display.rb +0 -9
  94. data/lib/super/inline_callback.rb +0 -82
  95. data/lib/super/test_support/copy_app_templates/20190216224956_create_members.rb +0 -11
  96. data/lib/super/test_support/copy_app_templates/20190803143320_create_ships.rb +0 -11
  97. data/lib/super/test_support/copy_app_templates/20190806014121_add_ship_to_members.rb +0 -5
  98. data/lib/super/test_support/copy_app_templates/member.rb +0 -16
  99. data/lib/super/test_support/copy_app_templates/members_controller.rb +0 -52
  100. data/lib/super/test_support/copy_app_templates/routes.rb +0 -10
  101. data/lib/super/test_support/copy_app_templates/seeds.rb +0 -2
  102. data/lib/super/test_support/copy_app_templates/ship.rb +0 -3
  103. data/lib/super/test_support/copy_app_templates/ships_controller.rb +0 -47
  104. data/lib/super/test_support/fixtures/members.yml +0 -336
  105. data/lib/super/test_support/fixtures/ships.yml +0 -10
  106. data/lib/super/test_support/generate_copy_app.rb +0 -52
  107. data/lib/super/test_support/generate_dummy.rb +0 -94
  108. data/lib/super/test_support/starfleet_seeder.rb +0 -49
  109. data/lib/super/view.rb +0 -25
  110. data/lib/tasks/super_tasks.rake +0 -4
@@ -0,0 +1,118 @@
1
+ module Super
2
+ class Filter
3
+ # This schema type is used to configure the filtering form on your +#index+
4
+ # action.
5
+ #
6
+ # The +operators:+ keyword argument can be left out in each case. There is
7
+ # a default set of operators that are provided.
8
+ #
9
+ # Note: The constants under "Defined Under Namespace" are considered
10
+ # private.
11
+ #
12
+ # class MemberDashboard
13
+ # # ...
14
+ #
15
+ # def filter_schema
16
+ # Super::Schema.new(Super::Filter::SchemaTypes.new) do |fields, type|
17
+ # fields[:name] = type.text(operators: [
18
+ # Super::Filter::Operator.eq,
19
+ # Super::Filter::Operator.contain,
20
+ # Super::Filter::Operator.ncontain,
21
+ # Super::Filter::Operator.start,
22
+ # Super::Filter::Operator.end,
23
+ # ])
24
+ # fields[:rank] = type.select(collection: Member.ranks.values)
25
+ # fields[:position] = type.text(operators: [
26
+ # Super::Filter::Operator.eq,
27
+ # Super::Filter::Operator.neq,
28
+ # Super::Filter::Operator.contain,
29
+ # Super::Filter::Operator.ncontain,
30
+ # ])
31
+ # fields[:ship_id] = type.select(
32
+ # collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
33
+ # )
34
+ # fields[:created_at] = type.timestamp
35
+ # fields[:updated_at] = type.timestamp
36
+ # end
37
+ # end
38
+ #
39
+ # # ...
40
+ # end
41
+ class SchemaTypes
42
+ class Text
43
+ def initialize(partial_path:, operators:)
44
+ @partial_path = partial_path
45
+ @operators = operators
46
+ end
47
+
48
+ attr_reader :operators
49
+
50
+ def to_partial_path
51
+ @partial_path
52
+ end
53
+
54
+ def q
55
+ [:q]
56
+ end
57
+ end
58
+
59
+ class Select
60
+ def initialize(collection:, operators:)
61
+ @collection = collection
62
+ @operators = operators
63
+ end
64
+
65
+ attr_reader :collection
66
+ attr_reader :operators
67
+
68
+ def to_partial_path
69
+ "filter_type_select"
70
+ end
71
+
72
+ def q
73
+ [:q]
74
+ end
75
+ end
76
+
77
+ class Timestamp
78
+ def initialize(operators:)
79
+ @operators = operators
80
+ end
81
+
82
+ attr_reader :operators
83
+
84
+ def to_partial_path
85
+ "filter_type_timestamp"
86
+ end
87
+
88
+ def q
89
+ [:q0, :q1]
90
+ end
91
+ end
92
+
93
+ def before_yield(fields:)
94
+ end
95
+
96
+ def after_yield
97
+ end
98
+
99
+ def select(collection:, operators: Filter::Operator.select_defaults)
100
+ Select.new(
101
+ collection: collection,
102
+ operators: operators
103
+ )
104
+ end
105
+
106
+ def text(operators: Filter::Operator.text_defaults)
107
+ Text.new(
108
+ partial_path: "filter_type_text",
109
+ operators: operators
110
+ )
111
+ end
112
+
113
+ def timestamp(operators: Filter::Operator.range_defaults)
114
+ Timestamp.new(operators: operators)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,48 @@
1
+ module Super
2
+ class Form
3
+ module FieldErrorProc
4
+ def error_wrapping(html_tag)
5
+ if Thread.current[:super_form_builder]
6
+ return html_tag
7
+ end
8
+
9
+ super
10
+ end
11
+ end
12
+
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
39
+
40
+ alias datetime_local_field datetime_field
41
+ alias phone_field telephone_field
42
+ end
43
+ end
44
+ end
45
+
46
+ ActionView::Helpers::Tags::Base.class_eval do
47
+ prepend Super::Form::FieldErrorProc
48
+ end
@@ -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
- # Note: The constants under "Defined Under Namespace" are considered
6
- # private.
5
+ # ```ruby
6
+ # class MembersController::Controls
7
+ # # ...
7
8
  #
8
- # class MemberDashboard
9
- # # ...
10
- #
11
- # def new_schema
12
- # Super::Schema.new(Super::Form::SchemaTypes.new) do |fields, type|
13
- # fields[:name] = type.generic("write_type_text")
14
- # fields[:rank] = type.generic("write_type_select", collection: Member.ranks.keys)
15
- # fields[:position] = type.generic("write_type_text")
16
- # fields[:ship_id] = type.generic(
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,78 @@ 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_fields) != @nested_fields
67
+
68
+ true
69
+ end
70
+ end
71
+
72
+ def before_yield(fields:)
73
+ @fields = fields
74
+ end
75
+
76
+ def after_yield
77
+ end
78
+
79
+ def generic(partial_path, **extras)
80
+ Generic.new(partial_path: partial_path, extras: extras, nested: {})
81
+ end
82
+
83
+ def has_many(reader, **extras)
84
+ nested = @fields.nested do
85
+ yield
86
+ end
87
+
88
+ Generic.new(
89
+ partial_path: "form_has_many",
90
+ extras: extras.merge(reader: reader),
91
+ nested: nested
92
+ )
93
+ end
94
+
95
+ def has_one(reader, **extras)
96
+ nested = @fields.nested do
97
+ yield
98
+ end
99
+
100
+ Generic.new(
101
+ partial_path: "form_has_one",
102
+ extras: extras.merge(reader: reader),
103
+ nested: nested
104
+ )
105
+ end
106
+
107
+ alias_method :belongs_to, :has_one
108
+
109
+ def _destroy(**extras)
110
+ Generic.new(
111
+ partial_path: "form_field__destroy",
112
+ extras: extras,
113
+ nested: {}
114
+ )
39
115
  end
40
116
 
41
- def generic(partial_path, extras = nil)
42
- extras ||= {}
43
- Generic.new(partial_path: partial_path, extras: extras)
117
+ def to_partial_path
118
+ "super_schema_form"
44
119
  end
45
120
  end
46
121
  end
@@ -0,0 +1,47 @@
1
+ require "super/partial/resolving"
2
+
3
+ module Super
4
+ class Layout
5
+ include Super::Partial::Resolving
6
+
7
+ def initialize(headers: nil, asides: nil, mains: nil, footers: nil)
8
+ @headers = Array(headers).compact
9
+ @asides = Array(asides).compact
10
+ @mains = Array(mains).compact
11
+ @footers = Array(footers).compact
12
+ end
13
+
14
+ attr_reader :headers
15
+ attr_reader :asides
16
+ attr_reader :mains
17
+ attr_reader :footers
18
+
19
+ def to_partial_path
20
+ "super_layout"
21
+ end
22
+
23
+ def resolve(template)
24
+ @resolved_headers = resolve_for_rendering(template, headers, nil)
25
+ @resolved_asides = resolve_for_rendering(template, asides, nil)
26
+ @resolved_mains = resolve_for_rendering(template, mains, nil)
27
+ @resolved_footers = resolve_for_rendering(template, footers, nil)
28
+ self
29
+ end
30
+
31
+ def resolved_headers
32
+ @resolved_headers || []
33
+ end
34
+
35
+ def resolved_asides
36
+ @resolved_asides || []
37
+ end
38
+
39
+ def resolved_mains
40
+ @resolved_mains || []
41
+ end
42
+
43
+ def resolved_footers
44
+ @resolved_footers || []
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,110 @@
1
+ module Super
2
+ # Links have three required attributes that are passed directly into Rails'
3
+ # `link_to` helper
4
+ class Link
5
+ def self.find_all(*links)
6
+ links.map { |link| find(link) }
7
+ end
8
+
9
+ def self.find(link)
10
+ if link.kind_of?(self)
11
+ return link
12
+ end
13
+
14
+ if registry.key?(link)
15
+ return registry[link]
16
+ end
17
+
18
+ raise Error::LinkNotRegistered, "Unknown link `#{link}`"
19
+ end
20
+
21
+ def self.registry
22
+ @registry ||= {
23
+ new: new(
24
+ "New",
25
+ -> (params:) {
26
+ Rails.application.routes.url_for(
27
+ controller: params[:controller],
28
+ action: :new,
29
+ only_path: true
30
+ )
31
+ }
32
+ ),
33
+ index: new(
34
+ "Index",
35
+ -> (params:) {
36
+ Rails.application.routes.url_for(
37
+ controller: params[:controller],
38
+ action: :index,
39
+ only_path: true
40
+ )
41
+ }
42
+ ),
43
+ show: new(
44
+ "View",
45
+ -> (record:, params:) {
46
+ Rails.application.routes.url_for(
47
+ controller: params[:controller],
48
+ action: :show,
49
+ id: record,
50
+ only_path: true
51
+ )
52
+ }
53
+ ),
54
+ edit: new(
55
+ "Edit",
56
+ -> (record:, params:) {
57
+ Rails.application.routes.url_for(
58
+ controller: params[:controller],
59
+ action: :edit,
60
+ id: record,
61
+ only_path: true
62
+ )
63
+ }
64
+ ),
65
+ destroy: new(
66
+ "Delete",
67
+ -> (record:, params:) {
68
+ Rails.application.routes.url_for(
69
+ controller: params[:controller],
70
+ action: :destroy,
71
+ id: record,
72
+ only_path: true
73
+ )
74
+ },
75
+ method: :delete,
76
+ data: { confirm: "Really delete?" }
77
+ ),
78
+ }
79
+ end
80
+
81
+ def initialize(text, href, **options)
82
+ @text = text
83
+ @href = href
84
+ @options = options
85
+ end
86
+
87
+ def to_s(default_options: nil, **proc_arguments)
88
+ default_options ||= {}
89
+ ActionController::Base.helpers.link_to(
90
+ value(text, proc_arguments),
91
+ value(href, proc_arguments),
92
+ default_options.deep_merge(value(options, proc_arguments))
93
+ )
94
+ end
95
+
96
+ private
97
+
98
+ attr_reader :text
99
+ attr_reader :href
100
+ attr_reader :options
101
+
102
+ def value(proc_or_value, proc_arguments)
103
+ if proc_or_value.kind_of?(Proc)
104
+ proc_or_value.call(**proc_arguments)
105
+ else
106
+ proc_or_value
107
+ end
108
+ end
109
+ end
110
+ end