super 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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