super 0.0.9 → 0.0.14

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 (119) 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 +5671 -3669
  5. data/app/assets/stylesheets/super/application.css +114693 -71486
  6. data/app/controllers/super/application_controller.rb +24 -13
  7. data/app/helpers/super/form_builder_helper.rb +25 -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} +5 -5
  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 +9 -19
  14. data/app/views/super/application/_filter_type_text.html.erb +7 -11
  15. data/app/views/super/application/_filter_type_timestamp.html.erb +6 -17
  16. data/app/views/super/application/_form.html.erb +15 -0
  17. data/app/views/super/application/_form_field__destroy.html.erb +1 -9
  18. data/app/views/super/application/_form_field_checkbox.html.erb +1 -15
  19. data/app/views/super/application/_form_field_flatpickr_date.html.erb +8 -0
  20. data/app/views/super/application/_form_field_flatpickr_datetime.html.erb +8 -0
  21. data/app/views/super/application/_form_field_flatpickr_time.html.erb +8 -0
  22. data/app/views/super/application/_form_field_rich_text_area.html.erb +1 -13
  23. data/app/views/super/application/_form_field_select.html.erb +1 -23
  24. data/app/views/super/application/_form_field_text.html.erb +1 -13
  25. data/app/views/super/application/{_super_layout.html.erb → _layout.html.erb} +8 -8
  26. data/app/views/super/application/{_super_pagination.html.erb → _pagination.html.erb} +1 -1
  27. data/app/views/super/application/{_super_panel.html.erb → _panel.html.erb} +2 -2
  28. data/app/views/super/application/_query.html.erb +18 -0
  29. data/app/views/super/application/_sort.html.erb +18 -0
  30. data/app/views/super/application/_sort_expression.html.erb +25 -0
  31. data/app/views/super/application/edit.html.erb +1 -0
  32. data/app/views/super/application/index.html.erb +1 -0
  33. data/app/views/super/application/new.html.erb +1 -0
  34. data/app/views/super/application/show.html.erb +1 -0
  35. data/app/views/super/feather/README.md +1 -0
  36. data/app/views/super/feather/_x.html +15 -0
  37. data/config/routes.rb +2 -0
  38. data/frontend/super-frontend/dist/application.css +114693 -71486
  39. data/frontend/super-frontend/dist/application.js +5671 -3669
  40. data/lib/generators/super/action_text/action_text_generator.rb +2 -0
  41. data/lib/generators/super/install/install_generator.rb +18 -7
  42. data/lib/generators/super/install/templates/base_controller.rb.tt +9 -1
  43. data/lib/generators/super/install/templates/initializer.rb.tt +9 -2
  44. data/lib/generators/super/resource/resource_generator.rb +107 -30
  45. data/lib/generators/super/resource/templates/resources_controller.rb.tt +3 -9
  46. data/lib/generators/super/webpacker/webpacker_generator.rb +11 -5
  47. data/lib/super.rb +9 -2
  48. data/lib/super/action_inquirer.rb +2 -0
  49. data/lib/super/assets.rb +46 -23
  50. data/lib/super/cheat.rb +17 -0
  51. data/lib/super/client_error.rb +2 -0
  52. data/lib/super/compatibility.rb +21 -0
  53. data/lib/super/configuration.rb +16 -24
  54. data/lib/super/controls.rb +11 -2
  55. data/lib/super/controls/optional.rb +35 -1
  56. data/lib/super/controls/steps.rb +27 -35
  57. data/lib/super/controls/view.rb +55 -0
  58. data/lib/super/display.rb +29 -13
  59. data/lib/super/display/guesser.rb +4 -0
  60. data/lib/super/display/schema_types.rb +73 -33
  61. data/lib/super/engine.rb +4 -0
  62. data/lib/super/error.rb +21 -0
  63. data/lib/super/filter.rb +2 -0
  64. data/lib/super/filter/form_object.rb +5 -8
  65. data/lib/super/filter/guesser.rb +2 -0
  66. data/lib/super/filter/operator.rb +2 -0
  67. data/lib/super/filter/schema_types.rb +2 -0
  68. data/lib/super/form.rb +3 -1
  69. data/lib/super/form/builder.rb +289 -39
  70. data/lib/super/form/guesser.rb +12 -1
  71. data/lib/super/form/inline_errors.rb +28 -0
  72. data/lib/super/form/schema_types.rb +15 -0
  73. data/lib/super/form/strong_params.rb +2 -0
  74. data/lib/super/layout.rb +3 -1
  75. data/lib/super/link.rb +44 -31
  76. data/lib/super/link_builder.rb +58 -0
  77. data/lib/super/navigation.rb +164 -0
  78. data/lib/super/pagination.rb +3 -1
  79. data/lib/super/panel.rb +3 -1
  80. data/lib/super/partial.rb +2 -0
  81. data/lib/super/partial/resolving.rb +2 -0
  82. data/lib/super/plugin.rb +2 -0
  83. data/lib/super/query/form_object.rb +48 -0
  84. data/lib/super/schema.rb +2 -0
  85. data/lib/super/schema/common.rb +2 -0
  86. data/lib/super/schema/guesser.rb +2 -0
  87. data/lib/super/sort.rb +110 -0
  88. data/lib/super/useful/builder.rb +25 -0
  89. data/lib/super/useful/enum.rb +63 -0
  90. data/lib/super/version.rb +3 -1
  91. data/lib/super/view_helper.rb +2 -19
  92. data/lib/tasks/super/cheat.rake +9 -0
  93. metadata +53 -40
  94. data/CONTRIBUTING.md +0 -56
  95. data/Rakefile +0 -34
  96. data/STABILITY.md +0 -50
  97. data/app/views/super/application/_form_field_generic.html.erb +0 -19
  98. data/app/views/super/application/_form_inline_errors.html.erb +0 -10
  99. data/app/views/super/application/_super_schema_display_show.html.erb +0 -8
  100. data/app/views/super/application/_super_schema_form.html.erb +0 -15
  101. data/docs/README.md +0 -8
  102. data/docs/action_text.md +0 -48
  103. data/docs/faq.md +0 -44
  104. data/docs/installation.md +0 -21
  105. data/docs/quick_start.md +0 -30
  106. data/docs/webpacker.md +0 -25
  107. data/docs/yard_customizations.rb +0 -41
  108. data/frontend/super-frontend/build.js +0 -36
  109. data/frontend/super-frontend/package.json +0 -20
  110. data/frontend/super-frontend/postcss.config.js +0 -6
  111. data/frontend/super-frontend/src/javascripts/super/application.js +0 -15
  112. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.js +0 -17
  113. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.js +0 -15
  114. data/frontend/super-frontend/src/stylesheets/super/application.css +0 -77
  115. data/frontend/super-frontend/tailwind.config.js +0 -15
  116. data/frontend/super-frontend/yarn.lock +0 -5443
  117. data/lib/super/controls/required.rb +0 -13
  118. data/lib/super/filter/plugin.rb +0 -47
  119. data/lib/super/navigation/automatic.rb +0 -71
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Cheat
5
+ def controls
6
+ paths = %w[controls.rb controls/optional.rb controls/steps.rb controls/view.rb]
7
+ methods =
8
+ paths
9
+ .map { |f| File.read(File.join(__dir__, f)) }
10
+ .flat_map { |content| content.scan(/^\s+def .*$/) }
11
+ .map { |method| method.strip.sub(/^def /, "#") }
12
+
13
+ puts "== Super::Controls"
14
+ puts methods.join("\n")
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # A container class for all user-facing (4xx) errors thrown by this library.
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  module Compatability
3
5
  module_function
@@ -21,5 +23,24 @@ module Super
21
23
  ActiveRecord::Base.sanitize_sql_like(query)
22
24
  end
23
25
  end
26
+
27
+ def polymorphic_path_container
28
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 0
29
+ @polymorphic_path_container ||=
30
+ begin
31
+ klass = Class.new do
32
+ include ActionDispatch::Routing::PolymorphicRoutes
33
+
34
+ def method_missing(method_name)
35
+ Rails.application.routes.url_helpers.public_send(method_name)
36
+ end
37
+ end
38
+
39
+ klass.new
40
+ end
41
+ else
42
+ Rails.application.routes.url_helpers
43
+ end
44
+ end
24
45
  end
25
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # @yield [Configuration]
3
5
  # @return [Configuration]
@@ -19,37 +21,27 @@ module Super
19
21
  # end
20
22
  # ```
21
23
  class Configuration
22
- def initialize
23
- self.title = "Super Admin"
24
- self.index_records_per_page = 20
25
- self.controller_namespace = "admin"
26
- self.route_namespace = :admin
27
-
28
- controller_plugins.use(prepend: Super::Filter::ControllerMethods)
29
- controller_plugins.use(prepend: Super::Pagination::ControllerMethods)
24
+ include ActiveSupport::Configurable
30
25
 
31
- self.javascripts = [Super::Assets.auto("super/application")]
32
- self.stylesheets = [Super::Assets.auto("super/application")]
26
+ config_accessor(:title) { "Super Admin" }
27
+ config_accessor(:index_records_per_page) { 100 }
28
+ config_accessor(:javascripts) do
29
+ [Super::Assets.auto("super/application")]
33
30
  end
34
-
35
- attr_accessor :title
36
- attr_accessor :index_records_per_page
37
- attr_accessor :controller_namespace
38
- attr_writer :route_namespace
39
- def route_namespace
40
- [@route_namespace].flatten
31
+ config_accessor(:stylesheets) do
32
+ [Super::Assets.auto("super/application")]
41
33
  end
42
34
 
43
- attr_accessor :javascripts
44
- attr_accessor :stylesheets
35
+ config_accessor(:path) { "/admin" }
36
+ config_accessor(:generator_module) { "admin" }
37
+ config_accessor(:generator_as) { "admin" }
45
38
 
46
- def controller_plugins
47
- Plugin::Registry.controller
39
+ def initialize
40
+ controller_plugins.use(prepend: Super::Pagination::ControllerMethods)
48
41
  end
49
42
 
50
- # @api private
51
- def path_parts(*parts)
52
- route_namespace + parts
43
+ def controller_plugins
44
+ Plugin::Registry.controller
53
45
  end
54
46
  end
55
47
  end
@@ -1,13 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "super/controls/optional"
2
- require "super/controls/required"
3
4
  require "super/controls/steps"
5
+ require "super/controls/view"
4
6
 
5
7
  module Super
6
8
  # The base Controls class. Most parts of Super can be configured by
7
9
  # customizing its methods.
8
10
  class Controls
9
- include Required
10
11
  include Optional
11
12
  include Steps
13
+ include View
14
+
15
+ # Specifies the model. This is a required method
16
+ #
17
+ # @return [ActiveRecord::Base]
18
+ def model
19
+ raise NotImplementedError
20
+ end
12
21
  end
13
22
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Controls
3
5
  # Methods for `Controls` that have a sane default implementation
@@ -24,7 +26,7 @@ module Super
24
26
  # @param action [ActionInquirer]
25
27
  # @return [Display]
26
28
  def display_schema(action:)
27
- Display.new(action: action) do |fields, type|
29
+ Display.new do |fields, type|
28
30
  Display::Guesser.new(model: model, action: action, fields: fields, type: type).call
29
31
  end
30
32
  end
@@ -74,6 +76,38 @@ module Super
74
76
  Super::Link.find_all(:show, :edit, :destroy)
75
77
  end
76
78
  end
79
+
80
+ def filters_enabled?
81
+ true
82
+ end
83
+
84
+ def filter_schema
85
+ Super::Filter.new do |fields, type|
86
+ Super::Filter::Guesser.new(model: model, fields: fields, type: type).call
87
+ end
88
+ end
89
+
90
+ def sort_enabled?
91
+ true
92
+ end
93
+
94
+ def sortable_columns
95
+ action = ActionInquirer.new(
96
+ ActionInquirer.default_for_resources,
97
+ "index"
98
+ )
99
+ attribute_names =
100
+ display_schema(action: action).each_attribute.map do |key, val|
101
+ val = val.build if val.respond_to?(:build)
102
+ key if val.real?
103
+ end
104
+
105
+ attribute_names.compact
106
+ end
107
+
108
+ def default_sort
109
+ { id: :desc }
110
+ end
77
111
  end
78
112
  end
79
113
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Controls
3
5
  # Methods that are called by controller actions. All of these methods have
@@ -66,48 +68,38 @@ module Super
66
68
  record.destroy
67
69
  end
68
70
 
69
- def build_index_view
70
- Super::Layout.new(
71
- mains: [
72
- Super::Panel.new(
73
- Super::Partial.new("collection_header"),
74
- :@display
75
- ),
76
- ]
71
+ def initialize_query_form(params:, current_path:)
72
+ Super::Query::FormObject.new(
73
+ model: model,
74
+ params: params,
75
+ namespace: :q,
76
+ current_path: current_path,
77
77
  )
78
78
  end
79
79
 
80
- def build_show_view
81
- Super::Layout.new(
82
- mains: [
83
- Super::Panel.new(
84
- Super::Partial.new("member_header"),
85
- :@display
86
- ),
87
- ]
88
- )
80
+ def apply_queries(query_form:, records:)
81
+ query_form.apply_changes(records)
89
82
  end
90
83
 
91
- def build_new_view
92
- Super::Layout.new(
93
- mains: [
94
- Super::Panel.new(
95
- Super::Partial.new("collection_header"),
96
- :@form
97
- ),
98
- ]
99
- )
84
+ def initialize_filter_form(query_form:)
85
+ if filters_enabled?
86
+ query_form.add(
87
+ Super::Filter::FormObject,
88
+ namespace: :f,
89
+ schema: filter_schema
90
+ )
91
+ end
100
92
  end
101
93
 
102
- def build_edit_view
103
- Super::Layout.new(
104
- mains: [
105
- Super::Panel.new(
106
- Super::Partial.new("member_header"),
107
- :@form
108
- ),
109
- ]
110
- )
94
+ def initialize_sort_form(query_form:)
95
+ if sort_enabled?
96
+ query_form.add(
97
+ Super::Sort::FormObject,
98
+ namespace: :s,
99
+ default: default_sort,
100
+ sortable_columns: sortable_columns
101
+ )
102
+ end
111
103
  end
112
104
  end
113
105
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Controls
5
+ # Methods for `Controls` that have a sane default implementation
6
+ module View
7
+ def index_view
8
+ Super::Layout.new(
9
+ mains: [
10
+ Super::Panel.new(
11
+ Super::Partial.new("collection_header"),
12
+ :@display
13
+ ),
14
+ ],
15
+ asides: [
16
+ :@query_form,
17
+ ]
18
+ )
19
+ end
20
+
21
+ def show_view
22
+ Super::Layout.new(
23
+ mains: [
24
+ Super::Panel.new(
25
+ Super::Partial.new("member_header"),
26
+ :@display
27
+ ),
28
+ ]
29
+ )
30
+ end
31
+
32
+ def new_view
33
+ Super::Layout.new(
34
+ mains: [
35
+ Super::Panel.new(
36
+ Super::Partial.new("collection_header"),
37
+ :@form
38
+ ),
39
+ ]
40
+ )
41
+ end
42
+
43
+ def edit_view
44
+ Super::Layout.new(
45
+ mains: [
46
+ Super::Panel.new(
47
+ Super::Partial.new("member_header"),
48
+ :@form
49
+ ),
50
+ ]
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
data/lib/super/display.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  # This schema type is meant to be used for +#index+ or +#show+ actions to
3
5
  # transform database fields into something that is human friendly.
@@ -23,39 +25,53 @@ module Super
23
25
  class Display
24
26
  include Schema::Common
25
27
 
26
- def initialize(action:)
27
- @action_inquirer = action
28
+ def initialize
28
29
  @fields = Super::Schema::Fields.new
29
30
  @schema_types = SchemaTypes.new(fields: @fields)
30
31
 
31
32
  yield(@fields, @schema_types)
33
+ end
32
34
 
33
- return if !@action_inquirer.index?
34
- return if @schema_types.actions_called?
35
+ def apply(action:)
36
+ @action_inquirer = action
37
+ return self if !@action_inquirer.index?
38
+ return self if @schema_types.actions_called?
35
39
  @fields[:actions] = @schema_types.actions
40
+ self
36
41
  end
37
42
 
38
43
  def to_partial_path
39
- if @action_inquirer.index?
40
- "super_schema_display_index"
44
+ if @action_inquirer.nil?
45
+ raise Super::Error::Initalization,
46
+ "You must call the `#apply` method after instantiating Super::Display"
47
+ elsif @action_inquirer.index?
48
+ "display_index"
41
49
  elsif @action_inquirer.show?
42
- "super_schema_display_show"
50
+ "display_show"
43
51
  else
44
- "super_schema_display_#{@action_inquirer.action}"
52
+ "display_#{@action_inquirer.action}"
45
53
  end
46
54
  end
47
55
 
48
56
  # @private
49
- def render_field(template:, record:, column:)
57
+ def render_attribute(template:, record:, column:)
50
58
  formatter = @fields[column]
59
+ formatter = formatter.build if formatter.respond_to?(:build)
51
60
 
52
61
  formatted =
53
- if formatter.real?
62
+ SchemaTypes::TYPES
63
+ .case(formatter.type)
64
+ .when(:record) do
65
+ formatter.present(column, record)
66
+ end
67
+ .when(:column) do
54
68
  value = record.public_send(column)
55
- formatter.present(value)
56
- else
57
- formatter.present
69
+ formatter.present(column, value)
70
+ end
71
+ .when(:none) do
72
+ formatter.present(column)
58
73
  end
74
+ .result
59
75
 
60
76
  if formatted.respond_to?(:to_partial_path)
61
77
  if formatted.respond_to?(:locals)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Display
3
5
  class Guesser
@@ -25,6 +27,8 @@ module Super
25
27
  case type
26
28
  when :datetime
27
29
  @type.timestamp
30
+ when :time
31
+ @type.time
28
32
  else
29
33
  @type.text
30
34
  end
@@ -1,35 +1,63 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Super
2
4
  class Display
3
5
  class SchemaTypes
4
- class Dynamic
5
- def initialize(ignore_nil: true, &transform_block)
6
- @transform_block = transform_block
7
- @ignore_nil = ignore_nil
8
- end
6
+ TYPES = Useful::Enum.new(:column, :record, :none)
9
7
 
10
- def present(value)
11
- return nil if value.nil? && @ignore_nil
8
+ class Builder
9
+ extend Useful::Builder
12
10
 
13
- @transform_block.call(value)
11
+ builder_with_block def transform(&block)
12
+ @transform_block = block
14
13
  end
15
14
 
16
- def real?
17
- true
15
+ builder def real; @real = true; end
16
+ builder def computed; @real = false; end
17
+
18
+ builder def column; @type = :column; end
19
+ builder def record; @type = :record; end
20
+ builder def none; @type = :none; end
21
+
22
+ builder def ignore_nil; @ignore_nil = true; end
23
+
24
+ def build
25
+ Built.new(
26
+ real: @real,
27
+ type: @type,
28
+ ignore_nil: !!@ignore_nil,
29
+ &@transform_block
30
+ )
18
31
  end
19
32
  end
20
33
 
21
- class Bypass
22
- def initialize(partial:, real:)
23
- @partial = partial
34
+ class Built
35
+ def initialize(real:, type:, ignore_nil:, &transform_block)
24
36
  @real = real
37
+ @type = type
38
+ @ignore_nil = ignore_nil
39
+ @transform_block = transform_block
25
40
  end
26
41
 
27
- def present
28
- Partial.new(@partial)
29
- end
42
+ def real?; @real; end
43
+ attr_reader :type
44
+
45
+ def present(attribute_name, value = nil)
46
+ if @transform_block.nil?
47
+ if attribute_name
48
+ raise Error::ArgumentError, "Transformation block is not set for column: #{attribute_name}"
49
+ else
50
+ raise Error::ArgumentError, "Transformation block is not set!"
51
+ end
52
+ end
53
+
54
+ return nil if value.nil? && @ignore_nil
30
55
 
31
- def real?
32
- @real
56
+ if @type == :none
57
+ @transform_block.call
58
+ else
59
+ @transform_block.call(value)
60
+ end
33
61
  end
34
62
  end
35
63
 
@@ -38,33 +66,45 @@ module Super
38
66
  @fields = fields
39
67
  end
40
68
 
41
- def string
42
- Dynamic.new(&:to_s)
69
+ def real(type = :column, &transform_block)
70
+ TYPES
71
+ .case(type)
72
+ .when(:column) { Builder.new.real.ignore_nil.column.transform(&transform_block) }
73
+ .when(:record) { Builder.new.real.ignore_nil.record.transform(&transform_block) }
74
+ .when(:none) { Builder.new.real.ignore_nil.none.transform(&transform_block) }
75
+ .result
43
76
  end
44
77
 
45
- alias text string
78
+ def computed(type = :column, &transform_block)
79
+ TYPES
80
+ .case(type)
81
+ .when(:column) { Builder.new.computed.ignore_nil.column.transform(&transform_block) }
82
+ .when(:record) { Builder.new.computed.ignore_nil.record.transform(&transform_block) }
83
+ .when(:none) { Builder.new.computed.ignore_nil.none.transform(&transform_block) }
84
+ .result
85
+ end
46
86
 
47
- def timestamp
48
- Dynamic.new(&:iso8601)
87
+ def manual(&transform_block)
88
+ real(:column, &transform_block)
49
89
  end
50
90
 
91
+ def string; real(&:to_s); end
92
+ alias text string
93
+
94
+ def timestamp; real(&:to_s); end
95
+ def time; real { |value| value.strftime("%H:%M:%S") }; end
96
+
51
97
  def rich_text
52
- Dynamic.new do |value|
98
+ computed do |value|
53
99
  Partial.new("display_rich_text", locals: { rich_text: value })
54
100
  end
55
101
  end
56
102
 
57
- def manual(&transform_block)
58
- Dynamic.new(&transform_block)
59
- end
60
-
61
- def dynamic(&transform_block)
62
- Dynamic.new(&transform_block)
63
- end
64
-
65
103
  def actions
66
104
  @actions_called = true
67
- Bypass.new(partial: "super_schema_display_actions", real: false)
105
+ Builder.new.computed.none.transform do
106
+ Partial.new("display_actions")
107
+ end
68
108
  end
69
109
 
70
110
  # @private