super 0.0.11 → 0.0.16

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +0 -9
  3. data/README.md +42 -54
  4. data/app/assets/javascripts/super/application.js +5617 -3806
  5. data/app/assets/stylesheets/super/application.css +114687 -71486
  6. data/app/controllers/super/application_controller.rb +41 -47
  7. data/app/controllers/super/substructure_controller.rb +265 -0
  8. data/app/helpers/super/form_builder_helper.rb +7 -0
  9. data/app/views/layouts/super/application.html.erb +4 -21
  10. data/app/views/super/application/_collection_header.html.erb +2 -2
  11. data/app/views/super/application/{_super_schema_display_actions.html.erb → _display_actions.html.erb} +1 -1
  12. data/app/views/super/application/{_super_schema_display_index.html.erb → _display_index.html.erb} +5 -5
  13. data/app/views/super/application/_display_show.html.erb +8 -0
  14. data/app/views/super/application/_filter_type_select.html.erb +1 -1
  15. data/app/views/super/application/_filter_type_text.html.erb +1 -1
  16. data/app/views/super/application/_filter_type_timestamp.html.erb +3 -3
  17. data/app/views/super/application/{_super_schema_form.html.erb → _form.html.erb} +2 -2
  18. data/app/views/super/application/_form_field.html.erb +5 -0
  19. data/app/views/super/application/{_super_layout.html.erb → _layout.html.erb} +8 -8
  20. data/app/views/super/application/_member_header.html.erb +2 -2
  21. data/app/views/super/application/{_super_pagination.html.erb → _pagination.html.erb} +1 -1
  22. data/app/views/super/application/{_super_panel.html.erb → _panel.html.erb} +2 -2
  23. data/app/views/super/application/_site_footer.html.erb +3 -0
  24. data/app/views/super/application/_site_header.html.erb +17 -0
  25. data/app/views/super/feather/README.md +0 -1
  26. data/frontend/super-frontend/dist/application.css +114687 -71486
  27. data/frontend/super-frontend/dist/application.js +5617 -3806
  28. data/lib/generators/super/install/install_generator.rb +16 -23
  29. data/lib/generators/super/install/templates/base_controller.rb.tt +1 -1
  30. data/lib/generators/super/install/templates/initializer.rb.tt +9 -2
  31. data/lib/generators/super/resource/resource_generator.rb +105 -30
  32. data/lib/generators/super/resource/templates/resources_controller.rb.tt +4 -10
  33. data/lib/generators/super/webpacker/webpacker_generator.rb +9 -5
  34. data/lib/super.rb +6 -2
  35. data/lib/super/action_inquirer.rb +18 -3
  36. data/lib/super/assets.rb +44 -23
  37. data/lib/super/badge.rb +60 -0
  38. data/lib/super/cheat.rb +17 -0
  39. data/lib/super/compatibility.rb +19 -0
  40. data/lib/super/configuration.rb +14 -23
  41. data/lib/super/display.rb +16 -8
  42. data/lib/super/display/guesser.rb +2 -0
  43. data/lib/super/display/schema_types.rb +116 -29
  44. data/lib/super/error.rb +7 -0
  45. data/lib/super/form.rb +1 -1
  46. data/lib/super/form/builder.rb +107 -27
  47. data/lib/super/form/guesser.rb +10 -1
  48. data/lib/super/form/schema_types.rb +73 -7
  49. data/lib/super/layout.rb +1 -1
  50. data/lib/super/link.rb +42 -31
  51. data/lib/super/link_builder.rb +58 -0
  52. data/lib/super/navigation.rb +164 -0
  53. data/lib/super/pagination.rb +3 -45
  54. data/lib/super/panel.rb +1 -1
  55. data/lib/super/reset.rb +22 -0
  56. data/lib/super/useful/builder.rb +25 -0
  57. data/lib/super/useful/enum.rb +63 -0
  58. data/lib/super/version.rb +1 -1
  59. data/lib/tasks/super/cheat.rake +9 -0
  60. metadata +27 -31
  61. data/CONTRIBUTING.md +0 -56
  62. data/Rakefile +0 -36
  63. data/STABILITY.md +0 -50
  64. data/app/views/super/application/_form_field_checkbox.html.erb +0 -1
  65. data/app/views/super/application/_form_field_rich_text_area.html.erb +0 -1
  66. data/app/views/super/application/_form_field_text.html.erb +0 -1
  67. data/app/views/super/application/_super_schema_display_show.html.erb +0 -8
  68. data/app/views/super/feather/_chevron_down.html +0 -1
  69. data/docs/README.md +0 -8
  70. data/docs/action_text.md +0 -48
  71. data/docs/cheat.md +0 -41
  72. data/docs/faq.md +0 -44
  73. data/docs/installation.md +0 -21
  74. data/docs/quick_start.md +0 -30
  75. data/docs/webpacker.md +0 -25
  76. data/docs/yard_customizations.rb +0 -43
  77. data/lib/super/controls.rb +0 -17
  78. data/lib/super/controls/optional.rb +0 -112
  79. data/lib/super/controls/required.rb +0 -15
  80. data/lib/super/controls/steps.rb +0 -106
  81. data/lib/super/controls/view.rb +0 -55
  82. data/lib/super/navigation/automatic.rb +0 -73
@@ -22,7 +22,16 @@ module Super
22
22
  private
23
23
 
24
24
  def attribute_type_for(attribute_name)
25
- @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
26
35
  end
27
36
  end
28
37
  end
@@ -3,6 +3,38 @@
3
3
  module Super
4
4
  class Form
5
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
+
6
38
  class Generic
7
39
  def initialize(partial_path:, extras:, nested:)
8
40
  @partial_path = partial_path
@@ -11,6 +43,7 @@ module Super
11
43
  end
12
44
 
13
45
  attr_reader :nested_fields
46
+ attr_reader :extras
14
47
 
15
48
  def each_attribute
16
49
  if block_given?
@@ -68,24 +101,57 @@ module Super
68
101
  Generic.new(partial_path: partial_path, extras: extras, nested: {})
69
102
  end
70
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
+
71
108
  def select(**extras)
72
109
  Generic.new(partial_path: "form_field_select", extras: extras, nested: {})
73
110
  end
74
111
 
75
- def string(**extras)
76
- 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)
77
125
  end
78
126
 
79
- alias text string
127
+ alias checkbox check_box
80
128
 
81
- def rich_text_area(**extras)
82
- Generic.new(partial_path: "form_field_rich_text_area", extras: extras, nested: {})
129
+ def date_flatpickr(*args, **kwargs)
130
+ Direct.new(super_builder: true, method_name: :date_flatpickr!, args: args, kwargs: kwargs)
83
131
  end
84
132
 
85
- def checkbox(**extras)
86
- Generic.new(partial_path: "form_field_checkbox", extras: extras, nested: {})
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)
87
137
  end
88
138
 
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
144
+
145
+ def password_field(*args, **kwargs)
146
+ Direct.new(super_builder: true, method_name: :password_field!, args: args, kwargs: kwargs)
147
+ end
148
+
149
+ def time_flatpickr(*args, **kwargs)
150
+ Direct.new(super_builder: true, method_name: :time_flatpickr!, args: args, kwargs: kwargs)
151
+ end
152
+
153
+ alias flatpickr_time time_flatpickr
154
+
89
155
  def has_many(reader, **extras)
90
156
  nested = @fields.nested do
91
157
  yield
data/lib/super/layout.rb CHANGED
@@ -19,7 +19,7 @@ module Super
19
19
  attr_reader :footers
20
20
 
21
21
  def to_partial_path
22
- "super_layout"
22
+ "layout"
23
23
  end
24
24
 
25
25
  def resolve(template)
data/lib/super/link.rb CHANGED
@@ -22,57 +22,57 @@ module Super
22
22
 
23
23
  def self.registry
24
24
  @registry ||= {
25
- new: new(
25
+ new: LinkBuilder.new(
26
26
  "New",
27
27
  -> (params:) {
28
- Rails.application.routes.url_for(
28
+ {
29
29
  controller: params[:controller],
30
30
  action: :new,
31
31
  only_path: true
32
- )
32
+ }
33
33
  }
34
34
  ),
35
- index: new(
35
+ index: LinkBuilder.new(
36
36
  "Index",
37
37
  -> (params:) {
38
- Rails.application.routes.url_for(
38
+ {
39
39
  controller: params[:controller],
40
40
  action: :index,
41
41
  only_path: true
42
- )
42
+ }
43
43
  }
44
44
  ),
45
- show: new(
45
+ show: LinkBuilder.new(
46
46
  "View",
47
47
  -> (record:, params:) {
48
- Rails.application.routes.url_for(
48
+ {
49
49
  controller: params[:controller],
50
50
  action: :show,
51
51
  id: record,
52
52
  only_path: true
53
- )
53
+ }
54
54
  }
55
55
  ),
56
- edit: new(
56
+ edit: LinkBuilder.new(
57
57
  "Edit",
58
58
  -> (record:, params:) {
59
- Rails.application.routes.url_for(
59
+ {
60
60
  controller: params[:controller],
61
61
  action: :edit,
62
62
  id: record,
63
63
  only_path: true
64
- )
64
+ }
65
65
  }
66
66
  ),
67
- destroy: new(
67
+ destroy: LinkBuilder.new(
68
68
  "Delete",
69
69
  -> (record:, params:) {
70
- Rails.application.routes.url_for(
70
+ {
71
71
  controller: params[:controller],
72
72
  action: :destroy,
73
73
  id: record,
74
74
  only_path: true
75
- )
75
+ }
76
76
  },
77
77
  method: :delete,
78
78
  data: { confirm: "Really delete?" }
@@ -80,33 +80,44 @@ module Super
80
80
  }
81
81
  end
82
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.map { |part| part.is_a?(String) ? part.to_sym : part } + parts_tail
86
+ end
87
+
83
88
  def initialize(text, href, **options)
84
89
  @text = text
85
90
  @href = href
86
91
  @options = options
87
92
  end
88
93
 
89
- 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)
90
111
  default_options ||= {}
91
112
  ActionController::Base.helpers.link_to(
92
- value(text, proc_arguments),
93
- value(href, proc_arguments),
94
- default_options.deep_merge(value(options, proc_arguments))
113
+ text,
114
+ href,
115
+ default_options.deep_merge(options)
95
116
  )
96
117
  end
97
118
 
98
- private
99
-
100
- attr_reader :text
101
- attr_reader :href
102
- attr_reader :options
103
-
104
- def value(proc_or_value, proc_arguments)
105
- if proc_or_value.kind_of?(Proc)
106
- proc_or_value.call(**proc_arguments)
107
- else
108
- proc_or_value
109
- end
119
+ def ==(other)
120
+ self.class == other.class && text == other.text && href == other.href && options == other.options
110
121
  end
111
122
  end
112
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