super 0.0.9 → 0.0.14

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