super 0.0.10 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +0 -9
  3. data/README.md +40 -52
  4. data/app/assets/javascripts/super/application.js +5672 -3671
  5. data/app/assets/stylesheets/super/application.css +114681 -71486
  6. data/app/controllers/super/application_controller.rb +31 -21
  7. data/app/helpers/super/form_builder_helper.rb +2 -0
  8. data/app/views/layouts/super/application.html.erb +15 -14
  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} +4 -4
  11. data/app/views/super/application/_display_show.html.erb +8 -0
  12. data/app/views/super/application/_filter.html.erb +5 -13
  13. data/app/views/super/application/_filter_type_select.html.erb +5 -2
  14. data/app/views/super/application/_filter_type_text.html.erb +6 -4
  15. data/app/views/super/application/_filter_type_timestamp.html.erb +6 -5
  16. data/app/views/super/application/{_super_schema_form.html.erb → _form.html.erb} +2 -2
  17. data/app/views/super/application/_form_field.html.erb +5 -0
  18. data/app/views/super/application/{_super_layout.html.erb → _layout.html.erb} +8 -8
  19. data/app/views/super/application/{_super_pagination.html.erb → _pagination.html.erb} +1 -1
  20. data/app/views/super/application/{_super_panel.html.erb → _panel.html.erb} +2 -2
  21. data/app/views/super/application/_query.html.erb +18 -0
  22. data/app/views/super/application/_sort.html.erb +18 -0
  23. data/app/views/super/application/_sort_expression.html.erb +25 -0
  24. data/app/views/super/feather/README.md +1 -1
  25. data/app/views/super/feather/_x.html +15 -0
  26. data/config/routes.rb +2 -0
  27. data/frontend/super-frontend/dist/application.css +114681 -71486
  28. data/frontend/super-frontend/dist/application.js +5672 -3671
  29. data/lib/generators/super/action_text/action_text_generator.rb +2 -0
  30. data/lib/generators/super/install/install_generator.rb +18 -23
  31. data/lib/generators/super/install/templates/base_controller.rb.tt +9 -1
  32. data/lib/generators/super/install/templates/initializer.rb.tt +9 -2
  33. data/lib/generators/super/resource/resource_generator.rb +107 -30
  34. data/lib/generators/super/resource/templates/resources_controller.rb.tt +3 -9
  35. data/lib/generators/super/webpacker/webpacker_generator.rb +11 -5
  36. data/lib/super.rb +10 -2
  37. data/lib/super/action_inquirer.rb +13 -3
  38. data/lib/super/assets.rb +46 -23
  39. data/lib/super/badge.rb +61 -0
  40. data/lib/super/cheat.rb +17 -0
  41. data/lib/super/client_error.rb +2 -0
  42. data/lib/super/compatibility.rb +21 -0
  43. data/lib/super/configuration.rb +16 -24
  44. data/lib/super/controls.rb +11 -2
  45. data/lib/super/controls/optional.rb +44 -1
  46. data/lib/super/controls/steps.rb +53 -34
  47. data/lib/super/controls/view.rb +55 -0
  48. data/lib/super/display.rb +29 -13
  49. data/lib/super/display/guesser.rb +4 -0
  50. data/lib/super/display/schema_types.rb +118 -29
  51. data/lib/super/engine.rb +2 -0
  52. data/lib/super/error.rb +12 -0
  53. data/lib/super/filter.rb +2 -0
  54. data/lib/super/filter/form_object.rb +5 -8
  55. data/lib/super/filter/guesser.rb +2 -0
  56. data/lib/super/filter/operator.rb +2 -0
  57. data/lib/super/filter/schema_types.rb +2 -0
  58. data/lib/super/form.rb +3 -1
  59. data/lib/super/form/builder.rb +109 -27
  60. data/lib/super/form/guesser.rb +12 -1
  61. data/lib/super/form/inline_errors.rb +2 -0
  62. data/lib/super/form/schema_types.rb +75 -7
  63. data/lib/super/form/strong_params.rb +2 -0
  64. data/lib/super/layout.rb +3 -1
  65. data/lib/super/link.rb +44 -31
  66. data/lib/super/link_builder.rb +58 -0
  67. data/lib/super/navigation.rb +164 -0
  68. data/lib/super/pagination.rb +3 -43
  69. data/lib/super/panel.rb +3 -1
  70. data/lib/super/partial.rb +2 -0
  71. data/lib/super/partial/resolving.rb +2 -0
  72. data/lib/super/plugin.rb +2 -0
  73. data/lib/super/query/form_object.rb +48 -0
  74. data/lib/super/reset.rb +17 -0
  75. data/lib/super/schema.rb +2 -0
  76. data/lib/super/schema/common.rb +2 -0
  77. data/lib/super/schema/guesser.rb +2 -0
  78. data/lib/super/sort.rb +110 -0
  79. data/lib/super/useful/builder.rb +25 -0
  80. data/lib/super/useful/enum.rb +63 -0
  81. data/lib/super/version.rb +3 -1
  82. data/lib/super/view_helper.rb +2 -0
  83. data/lib/tasks/super/cheat.rake +9 -0
  84. metadata +45 -28
  85. data/CONTRIBUTING.md +0 -56
  86. data/Rakefile +0 -34
  87. data/STABILITY.md +0 -50
  88. data/app/views/super/application/_form_field_checkbox.html.erb +0 -1
  89. data/app/views/super/application/_form_field_rich_text_area.html.erb +0 -1
  90. data/app/views/super/application/_form_field_text.html.erb +0 -1
  91. data/app/views/super/application/_super_schema_display_show.html.erb +0 -8
  92. data/app/views/super/feather/_chevron_down.html +0 -1
  93. data/docs/README.md +0 -8
  94. data/docs/action_text.md +0 -48
  95. data/docs/cheat.md +0 -41
  96. data/docs/faq.md +0 -44
  97. data/docs/installation.md +0 -21
  98. data/docs/quick_start.md +0 -30
  99. data/docs/webpacker.md +0 -25
  100. data/docs/yard_customizations.rb +0 -41
  101. data/lib/super/controls/required.rb +0 -13
  102. data/lib/super/filter/plugin.rb +0 -47
  103. data/lib/super/navigation/automatic.rb +0 -71
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Form
3
5
  class Guesser
@@ -20,7 +22,16 @@ module Super
20
22
  private
21
23
 
22
24
  def attribute_type_for(attribute_name)
23
- @type.string
25
+ case @model.type_for_attribute(attribute_name).type
26
+ when :datetime
27
+ @type.datetime_flatpickr
28
+ when :time
29
+ @type.time_flatpickr
30
+ when :date
31
+ @type.date_flatpickr
32
+ else
33
+ @type.string
34
+ end
24
35
  end
25
36
  end
26
37
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Form
3
5
  module InlineErrors
@@ -1,6 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Form
3
5
  class SchemaTypes
6
+ class Direct
7
+ def initialize(super_builder:, method_name:, args:, kwargs:)
8
+ @super_builder = super_builder
9
+ @method_name = method_name
10
+ @args = args
11
+ @kwargs = kwargs
12
+ end
13
+
14
+ attr_reader :super_builder
15
+ attr_reader :method_name
16
+ attr_reader :args
17
+ attr_reader :kwargs
18
+
19
+ def nested_fields
20
+ {}
21
+ end
22
+
23
+ def to_partial_path
24
+ "form_field"
25
+ end
26
+
27
+ def ==(other)
28
+ return false if other.class != self.class
29
+ return false if other.super_builder != super_builder
30
+ return false if other.method_name != method_name
31
+ return false if other.args != args
32
+ return false if other.kwargs != kwargs
33
+
34
+ true
35
+ end
36
+ end
37
+
4
38
  class Generic
5
39
  def initialize(partial_path:, extras:, nested:)
6
40
  @partial_path = partial_path
@@ -9,6 +43,7 @@ module Super
9
43
  end
10
44
 
11
45
  attr_reader :nested_fields
46
+ attr_reader :extras
12
47
 
13
48
  def each_attribute
14
49
  if block_given?
@@ -66,24 +101,57 @@ module Super
66
101
  Generic.new(partial_path: partial_path, extras: extras, nested: {})
67
102
  end
68
103
 
104
+ def direct(method_name, *args, super_builder: true, **kwargs)
105
+ Direct.new(super_builder: super_builder, method_name: method_name, args: args, kwargs: kwargs)
106
+ end
107
+
69
108
  def select(**extras)
70
109
  Generic.new(partial_path: "form_field_select", extras: extras, nested: {})
71
110
  end
72
111
 
73
- def string(**extras)
74
- Generic.new(partial_path: "form_field_text", extras: extras, nested: {})
112
+ def text_field(*args, **kwargs)
113
+ Direct.new(super_builder: true, method_name: :text_field!, args: args, kwargs: kwargs)
114
+ end
115
+
116
+ alias string text_field
117
+ alias text text_field
118
+
119
+ def rich_text_area(*args, **kwargs)
120
+ Direct.new(super_builder: true, method_name: :rich_text_area!, args: args, kwargs: kwargs)
121
+ end
122
+
123
+ def check_box(*args, **kwargs)
124
+ Direct.new(super_builder: true, method_name: :check_box!, args: args, kwargs: kwargs)
125
+ end
126
+
127
+ alias checkbox check_box
128
+
129
+ def date_flatpickr(*args, **kwargs)
130
+ Direct.new(super_builder: true, method_name: :date_flatpickr!, args: args, kwargs: kwargs)
131
+ end
132
+
133
+ alias flatpickr_date date_flatpickr
134
+
135
+ def datetime_flatpickr(*args, **kwargs)
136
+ Direct.new(super_builder: true, method_name: :datetime_flatpickr!, args: args, kwargs: kwargs)
75
137
  end
76
138
 
77
- alias text string
139
+ alias flatpickr_datetime datetime_flatpickr
140
+
141
+ def hidden_field(*args, **kwargs)
142
+ Direct.new(super_builder: false, method_name: :hidden_field, args: args, kwargs: kwargs)
143
+ end
78
144
 
79
- def rich_text_area(**extras)
80
- Generic.new(partial_path: "form_field_rich_text_area", extras: extras, nested: {})
145
+ def password_field(*args, **kwargs)
146
+ Direct.new(super_builder: true, method_name: :password_field!, args: args, kwargs: kwargs)
81
147
  end
82
148
 
83
- def checkbox(**extras)
84
- Generic.new(partial_path: "form_field_checkbox", extras: extras, nested: {})
149
+ def time_flatpickr(*args, **kwargs)
150
+ Direct.new(super_builder: true, method_name: :time_flatpickr!, args: args, kwargs: kwargs)
85
151
  end
86
152
 
153
+ alias flatpickr_time time_flatpickr
154
+
87
155
  def has_many(reader, **extras)
88
156
  nested = @fields.nested do
89
157
  yield
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Form
3
5
  class StrongParams
data/lib/super/layout.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "super/partial/resolving"
2
4
 
3
5
  module Super
@@ -17,7 +19,7 @@ module Super
17
19
  attr_reader :footers
18
20
 
19
21
  def to_partial_path
20
- "super_layout"
22
+ "layout"
21
23
  end
22
24
 
23
25
  def resolve(template)
data/lib/super/link.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # Links have three required attributes that are passed directly into Rails'
3
5
  # `link_to` helper
@@ -20,57 +22,57 @@ module Super
20
22
 
21
23
  def self.registry
22
24
  @registry ||= {
23
- new: new(
25
+ new: LinkBuilder.new(
24
26
  "New",
25
27
  -> (params:) {
26
- Rails.application.routes.url_for(
28
+ {
27
29
  controller: params[:controller],
28
30
  action: :new,
29
31
  only_path: true
30
- )
32
+ }
31
33
  }
32
34
  ),
33
- index: new(
35
+ index: LinkBuilder.new(
34
36
  "Index",
35
37
  -> (params:) {
36
- Rails.application.routes.url_for(
38
+ {
37
39
  controller: params[:controller],
38
40
  action: :index,
39
41
  only_path: true
40
- )
42
+ }
41
43
  }
42
44
  ),
43
- show: new(
45
+ show: LinkBuilder.new(
44
46
  "View",
45
47
  -> (record:, params:) {
46
- Rails.application.routes.url_for(
48
+ {
47
49
  controller: params[:controller],
48
50
  action: :show,
49
51
  id: record,
50
52
  only_path: true
51
- )
53
+ }
52
54
  }
53
55
  ),
54
- edit: new(
56
+ edit: LinkBuilder.new(
55
57
  "Edit",
56
58
  -> (record:, params:) {
57
- Rails.application.routes.url_for(
59
+ {
58
60
  controller: params[:controller],
59
61
  action: :edit,
60
62
  id: record,
61
63
  only_path: true
62
- )
64
+ }
63
65
  }
64
66
  ),
65
- destroy: new(
67
+ destroy: LinkBuilder.new(
66
68
  "Delete",
67
69
  -> (record:, params:) {
68
- Rails.application.routes.url_for(
70
+ {
69
71
  controller: params[:controller],
70
72
  action: :destroy,
71
73
  id: record,
72
74
  only_path: true
73
- )
75
+ }
74
76
  },
75
77
  method: :delete,
76
78
  data: { confirm: "Really delete?" }
@@ -78,33 +80,44 @@ module Super
78
80
  }
79
81
  end
80
82
 
83
+ def self.polymorphic_parts(*parts_tail)
84
+ parts_head = Super.configuration.path.strip.gsub(%r{\A/+}, "").gsub(%r{/+\z}, "").strip.split("/")
85
+ parts_head + parts_tail
86
+ end
87
+
81
88
  def initialize(text, href, **options)
82
89
  @text = text
83
90
  @href = href
84
91
  @options = options
85
92
  end
86
93
 
87
- def to_s(default_options: nil, **proc_arguments)
94
+ attr_reader :text
95
+ attr_reader :options
96
+
97
+ def href
98
+ if @href.is_a?(String)
99
+ return @href
100
+ end
101
+
102
+ if @href.is_a?(Hash)
103
+ @href = Rails.application.routes.url_for(**@href)
104
+ return @href
105
+ end
106
+
107
+ @href = Super::Compatability.polymorphic_path_container.polymorphic_path(@href)
108
+ end
109
+
110
+ def to_s(default_options: nil)
88
111
  default_options ||= {}
89
112
  ActionController::Base.helpers.link_to(
90
- value(text, proc_arguments),
91
- value(href, proc_arguments),
92
- default_options.deep_merge(value(options, proc_arguments))
113
+ text,
114
+ href,
115
+ default_options.deep_merge(options)
93
116
  )
94
117
  end
95
118
 
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
119
+ def ==(other)
120
+ self.class == other.class && text == other.text && href == other.href && options == other.options
108
121
  end
109
122
  end
110
123
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class LinkBuilder
5
+ def initialize(text, href, **options)
6
+ @text = text
7
+ @href = href
8
+ @options = options
9
+ @requirements = []
10
+ @requirements += gather_requirements(text)
11
+ @requirements += gather_requirements(href)
12
+ @requirements += gather_requirements(options)
13
+
14
+ unknown_arguments = @requirements - known_requirements
15
+ if unknown_arguments.any?
16
+ raise Error::ArgumentError, "Unknown arguments: #{unknown_arguments.join(", ")}"
17
+ end
18
+ end
19
+
20
+ attr_reader :requirements
21
+
22
+ def to_s(default_options: nil, **kwargs)
23
+ resolve(**kwargs).to_s(default_options: default_options)
24
+ end
25
+
26
+ def resolve(**kwargs)
27
+ Link.new(
28
+ into_value(@text, kwargs),
29
+ into_value(@href, kwargs),
30
+ **into_value(@options, kwargs),
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def known_requirements
37
+ %i[params record].freeze
38
+ end
39
+
40
+ def gather_requirements(value_or_proc)
41
+ return [] if !value_or_proc.is_a?(Proc)
42
+
43
+ requirements =
44
+ value_or_proc
45
+ .parameters
46
+ .select { |(kind, name)| kind = :keyreq }
47
+ .map(&:last)
48
+ end
49
+
50
+ def into_value(value_or_proc, kwargs)
51
+ if value_or_proc.kind_of?(Proc)
52
+ value_or_proc.call(**kwargs)
53
+ else
54
+ value_or_proc
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Navigation
5
+ def initialize
6
+ @builder = Builder.new
7
+ @definition = yield @builder
8
+ if !@definition.is_a?(Array)
9
+ @definition = [@definition]
10
+ end
11
+ end
12
+
13
+ def definition
14
+ return @defs if instance_variable_defined?(:@defs)
15
+
16
+ searcher = RouteFormatterButReallySearcher.new
17
+ inspector = ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes)
18
+ inspector.format(searcher)
19
+ all_matches = searcher.matches
20
+ unused_matches = all_matches.each_with_object({}) { |match, hash| hash[match] = true }
21
+
22
+ defs = expand_proc_syntax_sugar(@definition)
23
+ defs = validate_and_determine_explicit_links(defs, unused_matches)
24
+ @defs = expand_directives(defs, all_matches, unused_matches.keys)
25
+ end
26
+
27
+ private
28
+
29
+ # This expands the syntax sugar that allows `nav.menu("Name")[nav.link(Item)]`
30
+ def expand_proc_syntax_sugar(definition)
31
+ definition.map do |link_or_menu_or_rest_or_menuproc|
32
+ link_or_menu_or_rest =
33
+ if link_or_menu_or_rest_or_menuproc.is_a?(Proc)
34
+ link_or_menu_or_rest_or_menuproc.call
35
+ else
36
+ link_or_menu_or_rest_or_menuproc
37
+ end
38
+
39
+ if link_or_menu_or_rest.is_a?(Menu)
40
+ link_or_menu_or_rest.links = link_or_menu_or_rest.links.map do |menu_item|
41
+ if menu_item.is_a?(Proc)
42
+ menu_item.call
43
+ else
44
+ menu_item
45
+ end
46
+ end
47
+ end
48
+
49
+ link_or_menu_or_rest
50
+ end
51
+ end
52
+
53
+ def validate_and_determine_explicit_links(definition, unused_links)
54
+ definition.each do |link_or_menu_or_rest|
55
+ if link_or_menu_or_rest.is_a?(Super::Link)
56
+ unused_links.delete(link_or_menu_or_rest.href)
57
+ elsif link_or_menu_or_rest.is_a?(Menu)
58
+ link_or_menu_or_rest.links.each do |link_or_rest|
59
+ if link_or_rest.is_a?(Menu)
60
+ raise Super::Error::ArgumentError, "Navigation menus can't be nested"
61
+ end
62
+
63
+ if link_or_rest.is_a?(Link)
64
+ unused_links.delete(link_or_rest.href)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def expand_directives(defs, all_hrefs, rest_hrefs)
72
+ defs.flat_map do |link_or_menu_or_rest|
73
+ if link_or_menu_or_rest.is_a?(Menu)
74
+ link_or_menu_or_rest.links = link_or_menu_or_rest.links.flat_map do |link_or_rest|
75
+ if link_or_rest == ALL
76
+ linkify_hrefs(all_hrefs)
77
+ elsif link_or_rest == REST
78
+ linkify_hrefs(rest_hrefs)
79
+ else
80
+ link_or_rest
81
+ end
82
+ end
83
+
84
+ link_or_menu_or_rest
85
+ elsif link_or_menu_or_rest == ALL
86
+ linkify_hrefs(all_hrefs)
87
+ elsif link_or_menu_or_rest == REST
88
+ linkify_hrefs(rest_hrefs)
89
+ else
90
+ link_or_menu_or_rest
91
+ end
92
+ end
93
+ end
94
+
95
+ def linkify_hrefs(hrefs)
96
+ hrefs.map do |href|
97
+ Super::Link.new(href.split("/").last.humanize, href)
98
+ end
99
+ end
100
+
101
+ ALL = Object.new
102
+ REST = Object.new
103
+ Menu = Struct.new(:title, :links)
104
+
105
+ class Builder
106
+ def link(model, **kwargs)
107
+ text = model.model_name.human.pluralize
108
+ parts = Super::Link.polymorphic_parts(model)
109
+
110
+ Super::Link.new(text, parts, **kwargs)
111
+ end
112
+
113
+ def link_to(*args, **kwargs)
114
+ Super::Link.new(*args, **kwargs)
115
+ end
116
+
117
+ def menu(title, *links)
118
+ menu = Menu.new(title, links)
119
+ proc do |*more_links|
120
+ menu.links += more_links
121
+ menu
122
+ end
123
+ end
124
+
125
+ def rest
126
+ REST
127
+ end
128
+
129
+ def all
130
+ ALL
131
+ end
132
+ end
133
+
134
+ class RouteFormatterButReallySearcher
135
+ def initialize(route_namespace: Super.configuration.path)
136
+ @route_namespace = route_namespace.strip.gsub(%r{\A/+}, "").gsub(%r{/+\z}, "").strip
137
+ @route_namespace = "/#{@route_namespace}/"
138
+ @matches = []
139
+ end
140
+
141
+ def matches
142
+ @matches.map do |route|
143
+ route[:path].sub(/\(.*\)\Z/, "")
144
+ end
145
+ end
146
+
147
+ def section(routes)
148
+ @matches += routes.select do |route|
149
+ next false unless route[:verb] == "GET" || route[:verb] == ""
150
+ next false unless route[:path].start_with?(@route_namespace)
151
+ next false if route[:path].include?("/:")
152
+ next false if route[:reqs].end_with?("#new")
153
+
154
+ true
155
+ end
156
+ end
157
+
158
+ def header(routes); end
159
+ def no_routes(routes, filter); end
160
+ def result; end
161
+ def section_title(title); end
162
+ end
163
+ end
164
+ end