super 0.0.1 → 0.0.6

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/README.md +64 -78
  4. data/Rakefile +3 -1
  5. data/app/assets/config/super_manifest.js +2 -1
  6. data/app/assets/javascripts/super/application.js +1252 -316
  7. data/app/assets/stylesheets/super/application.css +102704 -17321
  8. data/app/controllers/super/application_controller.rb +50 -42
  9. data/app/helpers/super/application_helper.rb +39 -0
  10. data/app/views/layouts/super/application.html.erb +11 -7
  11. data/app/views/super/application/_collection_header.html.erb +15 -0
  12. data/app/views/super/application/_flash.html.erb +17 -0
  13. data/app/views/super/application/_form_field__destroy.html.erb +9 -0
  14. data/app/views/super/application/_form_field_select.html.erb +23 -0
  15. data/app/views/super/application/_form_field_text.html.erb +13 -0
  16. data/app/views/super/application/_form_fieldset.html.erb +8 -0
  17. data/app/views/super/application/_form_has_many.html.erb +21 -0
  18. data/app/views/super/application/_form_has_one.html.erb +11 -0
  19. data/app/views/super/application/_form_inline_errors.html.erb +10 -0
  20. data/app/views/super/application/_member_header.html.erb +16 -0
  21. data/app/views/super/application/_super_layout.html.erb +29 -0
  22. data/app/views/super/application/_super_panel.html.erb +7 -0
  23. data/app/views/super/application/_super_schema_display_actions.html.erb +5 -0
  24. data/app/views/super/application/_super_schema_display_index.html.erb +39 -0
  25. data/app/views/super/application/_super_schema_display_show.html.erb +8 -0
  26. data/app/views/super/application/_super_schema_form.html.erb +15 -0
  27. data/app/views/super/application/edit.html.erb +4 -5
  28. data/app/views/super/application/index.html.erb +6 -1
  29. data/app/views/super/application/new.html.erb +4 -5
  30. data/app/views/super/application/nothing.html.erb +0 -0
  31. data/app/views/super/application/show.html.erb +6 -10
  32. data/app/views/super/feather/{_chevron_down.svg → _chevron_down.html} +0 -0
  33. data/config/locales/en.yml +5 -0
  34. data/docs/README.md +6 -0
  35. data/docs/cheat.md +41 -0
  36. data/docs/faq.md +44 -0
  37. data/docs/quick_start.md +45 -0
  38. data/docs/webpacker.md +17 -0
  39. data/docs/yard_customizations.rb +41 -0
  40. data/frontend/super-frontend/build.js +14 -12
  41. data/frontend/super-frontend/dist/application.css +102704 -17321
  42. data/frontend/super-frontend/dist/application.js +1252 -316
  43. data/frontend/super-frontend/package.json +11 -4
  44. data/frontend/super-frontend/postcss.config.js +4 -4
  45. data/frontend/super-frontend/src/javascripts/super/application.ts +18 -0
  46. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +19 -0
  47. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +1 -0
  48. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +15 -0
  49. data/frontend/super-frontend/src/stylesheets/super/application.css +63 -0
  50. data/frontend/super-frontend/tailwind.config.js +12 -4
  51. data/frontend/super-frontend/tsconfig.json +13 -0
  52. data/frontend/super-frontend/yarn.lock +1891 -1798
  53. data/lib/generators/super/install/USAGE +4 -2
  54. data/lib/generators/super/install/install_generator.rb +18 -3
  55. data/lib/generators/super/resource/USAGE +1 -2
  56. data/lib/generators/super/resource/resource_generator.rb +0 -2
  57. data/lib/generators/super/resource/templates/resources_controller.rb.tt +38 -2
  58. data/lib/generators/super/webpacker/webpacker_generator.rb +8 -0
  59. data/lib/super.rb +10 -5
  60. data/lib/super/action_inquirer.rb +101 -0
  61. data/lib/super/assets.rb +1 -0
  62. data/lib/super/client_error.rb +43 -0
  63. data/lib/super/compatibility.rb +13 -0
  64. data/lib/super/configuration.rb +60 -45
  65. data/lib/super/controls.rb +26 -15
  66. data/lib/super/controls/optional.rb +65 -0
  67. data/lib/super/controls/required.rb +41 -0
  68. data/lib/super/controls/steps.rb +115 -0
  69. data/lib/super/display/schema_types.rb +60 -18
  70. data/lib/super/engine.rb +1 -0
  71. data/lib/super/error.rb +10 -1
  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 +19 -8
  78. data/lib/super/panel.rb +30 -0
  79. data/lib/super/partial.rb +11 -0
  80. data/lib/super/partial/resolving.rb +24 -0
  81. data/lib/super/schema.rb +64 -1
  82. data/lib/super/version.rb +1 -1
  83. data/lib/super/view_helper.rb +43 -0
  84. metadata +145 -38
  85. data/app/views/super/application/_form.html.erb +0 -13
  86. data/app/views/super/application/_form_field.html.erb +0 -7
  87. data/app/views/super/application/_form_generic_select.html.erb +0 -19
  88. data/app/views/super/application/_form_generic_text.html.erb +0 -7
  89. data/app/views/super/application/_index.html.erb +0 -58
  90. data/frontend/super-frontend/src/javascripts/super/application.js +0 -11
  91. data/lib/generators/super/resource/templates/resource_dashboard.rb.tt +0 -65
  92. data/lib/super/display.rb +0 -9
  93. data/lib/super/inline_callback.rb +0 -82
  94. data/lib/super/test_support/fixtures/members.yml +0 -336
  95. data/lib/super/test_support/fixtures/ships.yml +0 -10
  96. data/lib/super/test_support/setup.rb +0 -79
  97. data/lib/super/test_support/starfleet_seeder.rb +0 -49
  98. data/lib/super/test_support/templates/20190216224956_create_members.rb +0 -11
  99. data/lib/super/test_support/templates/20190803143320_create_ships.rb +0 -11
  100. data/lib/super/test_support/templates/20190806014121_add_ship_to_members.rb +0 -5
  101. data/lib/super/test_support/templates/admin/members_controller.rb +0 -9
  102. data/lib/super/test_support/templates/admin/ships_controller.rb +0 -9
  103. data/lib/super/test_support/templates/admin_controller.rb +0 -2
  104. data/lib/super/test_support/templates/member.rb +0 -16
  105. data/lib/super/test_support/templates/member_dashboard.rb +0 -90
  106. data/lib/super/test_support/templates/routes.rb +0 -10
  107. data/lib/super/test_support/templates/seeds.rb +0 -2
  108. data/lib/super/test_support/templates/ship.rb +0 -3
  109. data/lib/super/test_support/templates/ship_dashboard.rb +0 -79
  110. data/lib/super/view.rb +0 -25
  111. data/lib/tasks/super_tasks.rake +0 -4
@@ -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
@@ -1,5 +1,7 @@
1
1
  module Super
2
2
  class Navigation
3
+ # Traverses the defined Rails Routes and attempts to build a list of links.
4
+ # This is used for building the nav bar on each admin page.
3
5
  class Automatic
4
6
  def initialize(route_namespace:)
5
7
  route_namespace = route_namespace.to_s
@@ -29,19 +29,15 @@ module Super
29
29
  end
30
30
  end
31
31
 
32
+ def necessary?
33
+ pages > 1
34
+ end
35
+
32
36
  def each
33
37
  if !block_given?
34
38
  return enum_for(:each)
35
39
  end
36
40
 
37
- quotient, remainder = @total_count.divmod(@limit)
38
- pages =
39
- if remainder.zero?
40
- quotient
41
- else
42
- quotient + 1
43
- end
44
-
45
41
  (1..pages).each do |pageno|
46
42
  is_current_page = pageno == current_pageno
47
43
  display = pageno.to_s
@@ -55,5 +51,20 @@ module Super
55
51
  yield(page_query_params, is_current_page, display)
56
52
  end
57
53
  end
54
+
55
+ private
56
+
57
+ def pages
58
+ @pages ||=
59
+ begin
60
+ quotient, remainder = @total_count.divmod(@limit)
61
+
62
+ if remainder.zero?
63
+ quotient
64
+ else
65
+ quotient + 1
66
+ end
67
+ end
68
+ end
58
69
  end
59
70
  end
@@ -0,0 +1,30 @@
1
+ require "super/partial/resolving"
2
+
3
+ module Super
4
+ class Panel
5
+ include Super::Partial::Resolving
6
+
7
+ def initialize(*parts)
8
+ if block_given?
9
+ @parts = Array.new(yield)
10
+ end
11
+
12
+ @parts = parts
13
+ end
14
+
15
+ attr_reader :parts
16
+
17
+ def resolve(template, block)
18
+ @resolved_parts ||= resolve_for_rendering(template, parts, block)
19
+ self
20
+ end
21
+
22
+ def resolved_parts
23
+ @resolved_parts || []
24
+ end
25
+
26
+ def to_partial_path
27
+ "super_panel"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module Super
2
+ class Partial
3
+ def initialize(path, locals: {})
4
+ @to_partial_path = path
5
+ @locals = locals
6
+ end
7
+
8
+ attr_reader :to_partial_path
9
+ attr_reader :locals
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Super
2
+ class Partial
3
+ module Resolving
4
+ module_function
5
+
6
+ def resolve_for_rendering(template, partials, block)
7
+ if block
8
+ partials = [block.call, *parts]
9
+ end
10
+
11
+ partials =
12
+ partials.map do |partial|
13
+ if partial.is_a?(Symbol)
14
+ template.instance_variable_get(partial)
15
+ else
16
+ partial
17
+ end
18
+ end
19
+
20
+ partials.compact
21
+ end
22
+ end
23
+ end
24
+ end
@@ -8,11 +8,15 @@ module Super
8
8
  # @param schema_type [Display::SchemaTypes, Form::SchemaTypes]
9
9
  def initialize(schema_type)
10
10
  @schema_type = schema_type
11
- @fields = {}
11
+ @fields = Fields.new
12
+
13
+ @schema_type.before_yield(fields: @fields)
12
14
 
13
15
  if block_given?
14
16
  yield(@fields, @schema_type)
15
17
  end
18
+
19
+ @schema_type.after_yield
16
20
  end
17
21
 
18
22
  attr_reader :fields
@@ -20,5 +24,64 @@ module Super
20
24
  def field_keys
21
25
  fields.keys
22
26
  end
27
+
28
+ def to_partial_path
29
+ @schema_type.to_partial_path
30
+ end
31
+
32
+ # This class can be thought of as a Hash, where the keys usually refer to
33
+ # the model's column name and the value refers to the column type. Note
34
+ # though that this isn't always the case—different `SchemaTypes` can do
35
+ # whatever makes sense in their context
36
+ class Fields
37
+ include Enumerable
38
+
39
+ def initialize
40
+ @backing = {}
41
+ end
42
+
43
+ def [](key)
44
+ @backing[key]
45
+ end
46
+
47
+ def []=(key, value)
48
+ @backing[key] = value
49
+ end
50
+
51
+ def keys
52
+ @backing.keys
53
+ end
54
+
55
+ def values
56
+ @backing.values
57
+ end
58
+
59
+ def each(&block)
60
+ if block_given?
61
+ return @backing.each(&block)
62
+ end
63
+
64
+ enum_for(:each)
65
+ end
66
+
67
+ def replace(other)
68
+ @backing = other
69
+ end
70
+
71
+ def to_h
72
+ @backing
73
+ end
74
+
75
+ def nested
76
+ outside = @backing
77
+ inside = {}
78
+ @backing = inside
79
+ yield
80
+ return inside
81
+ ensure
82
+ @backing = outside
83
+ inside
84
+ end
85
+ end
23
86
  end
24
87
  end