super 0.0.5 → 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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/README.md +55 -23
  4. data/app/assets/javascripts/super/application.js +1062 -261
  5. data/app/assets/stylesheets/super/application.css +72775 -50711
  6. data/app/controllers/super/application_controller.rb +39 -50
  7. data/app/helpers/super/application_helper.rb +24 -17
  8. data/app/views/layouts/super/application.html.erb +4 -0
  9. data/app/views/super/application/{_resources_header.html.erb → _collection_header.html.erb} +5 -6
  10. data/app/views/super/application/_flash.html.erb +13 -13
  11. data/app/views/super/application/_form_field_select.html.erb +1 -1
  12. data/app/views/super/application/_form_has_many.html.erb +1 -1
  13. data/app/views/super/application/{_resource_header.html.erb → _member_header.html.erb} +6 -6
  14. data/app/views/super/application/_super_layout.html.erb +7 -12
  15. data/app/views/super/application/_super_panel.html.erb +2 -6
  16. data/app/views/super/application/_super_schema_display_actions.html.erb +5 -0
  17. data/app/views/super/application/_super_schema_display_index.html.erb +39 -0
  18. data/app/views/super/application/_super_schema_display_show.html.erb +8 -0
  19. data/app/views/super/application/{_form.html.erb → _super_schema_form.html.erb} +2 -4
  20. data/app/views/super/application/edit.html.erb +2 -2
  21. data/app/views/super/application/index.html.erb +2 -2
  22. data/app/views/super/application/new.html.erb +2 -2
  23. data/app/views/super/application/show.html.erb +2 -2
  24. data/app/views/super/feather/{_chevron_down.svg → _chevron_down.html} +0 -0
  25. data/config/locales/en.yml +5 -0
  26. data/docs/cheat.md +41 -0
  27. data/docs/webpacker.md +1 -1
  28. data/frontend/super-frontend/dist/application.css +72775 -50711
  29. data/frontend/super-frontend/dist/application.js +1062 -261
  30. data/frontend/super-frontend/package.json +1 -1
  31. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +6 -8
  32. data/frontend/super-frontend/tailwind.config.js +7 -1
  33. data/frontend/super-frontend/yarn.lock +1103 -1195
  34. data/lib/generators/super/install/install_generator.rb +16 -0
  35. data/lib/super.rb +2 -2
  36. data/lib/super/action_inquirer.rb +2 -2
  37. data/lib/super/client_error.rb +43 -0
  38. data/lib/super/configuration.rb +1 -1
  39. data/lib/super/controls.rb +17 -101
  40. data/lib/super/controls/optional.rb +65 -0
  41. data/lib/super/controls/required.rb +41 -0
  42. data/lib/super/controls/steps.rb +115 -0
  43. data/lib/super/display/schema_types.rb +45 -2
  44. data/lib/super/error.rb +8 -9
  45. data/lib/super/form.rb +48 -0
  46. data/lib/super/form/schema_types.rb +8 -1
  47. data/lib/super/layout.rb +28 -0
  48. data/lib/super/link.rb +55 -32
  49. data/lib/super/panel.rb +13 -0
  50. data/lib/super/partial/resolving.rb +24 -0
  51. data/lib/super/schema.rb +19 -5
  52. data/lib/super/version.rb +1 -1
  53. data/lib/super/view_helper.rb +1 -1
  54. metadata +40 -15
  55. data/app/views/super/application/_index.html.erb +0 -45
  56. data/app/views/super/application/_show.html.erb +0 -10
  57. data/docs/controls.md +0 -39
  58. data/lib/super/display.rb +0 -9
  59. data/lib/super/step.rb +0 -36
  60. data/lib/tasks/super_tasks.rake +0 -4
@@ -29,6 +29,22 @@ module Super
29
29
  create_file("app/controllers/#{controller_namespace}/.keep", "")
30
30
  end
31
31
 
32
+ def copy_cheatsheet
33
+ super_path = Pathname.new(Gem.loaded_specs["super"].full_gem_path).expand_path
34
+ super_cheat_path = super_path.join("docs", "cheat.md")
35
+
36
+ path =
37
+ if options["controller_namespace"].present?
38
+ "app/controllers/#{controller_namespace}/README.md"
39
+ else
40
+ "app/controllers/README.md"
41
+ end
42
+
43
+ create_file(path) do
44
+ super_cheat_path.read.sub(%r{<!--.*?-->}m, "").strip + "\n"
45
+ end
46
+ end
47
+
32
48
  def setup_sprockets4_manifest
33
49
  append_to_file "app/assets/config/manifest.js", "//= link super_manifest.js\n"
34
50
  end
@@ -2,13 +2,14 @@ require "active_support/concern"
2
2
 
3
3
  require "super/action_inquirer"
4
4
  require "super/assets"
5
+ require "super/client_error"
5
6
  require "super/compatibility"
6
7
  require "super/configuration"
7
8
  require "super/controls"
8
- require "super/display"
9
9
  require "super/display/schema_types"
10
10
  require "super/engine"
11
11
  require "super/error"
12
+ require "super/form"
12
13
  require "super/form/schema_types"
13
14
  require "super/layout"
14
15
  require "super/link"
@@ -18,6 +19,5 @@ require "super/panel"
18
19
  require "super/partial"
19
20
  require "super/plugin"
20
21
  require "super/schema"
21
- require "super/step"
22
22
  require "super/version"
23
23
  require "super/view_helper"
@@ -1,7 +1,7 @@
1
1
  module Super
2
2
  # ```ruby
3
3
  # action = Super::ActionInquirer.new(
4
- # Super::ActionInquirer.default_resources,
4
+ # Super::ActionInquirer.default_for_resources,
5
5
  # :index
6
6
  # )
7
7
  #
@@ -15,7 +15,7 @@ module Super
15
15
 
16
16
  # @return [Hash<Symbol, Array<Symbol>>] default settings for initialization
17
17
  #
18
- def self.default_resources
18
+ def self.default_for_resources
19
19
  {
20
20
  read: %i[index show new edit],
21
21
  write: %i[create update destroy],
@@ -0,0 +1,43 @@
1
+ module Super
2
+ # A container class for all user-facing (4xx) errors thrown by this library.
3
+ #
4
+ # See also `Super::Error`
5
+ class ClientError < StandardError
6
+ class BadRequest < ClientError; end
7
+ class Unauthorized < ClientError; end
8
+ class Forbidden < ClientError; end
9
+ class NotFound < ClientError; end
10
+ class UnprocessableEntity < ClientError; end
11
+
12
+ module Handling
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ rescue_from ::Super::ClientError do |exception|
17
+ code, default_message =
18
+ case exception
19
+ when ClientError::UnprocessableEntity
20
+ [422, "Unprocessable entity"]
21
+ when ClientError::NotFound
22
+ [404, "Not found"]
23
+ when ClientError::Forbidden
24
+ [403, "Forbidden"]
25
+ when ClientError::Unauthorized
26
+ [401, "Unauthorized"]
27
+ when ClientError::BadRequest, ClientError
28
+ [400, "Bad request"]
29
+ end
30
+
31
+ flash.now.alert =
32
+ if exception.message == exception.class.name.to_s
33
+ default_message
34
+ else
35
+ exception.message
36
+ end
37
+
38
+ render "nothing", status: code
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -87,7 +87,7 @@ module Super
87
87
  # @!attribute [rw]
88
88
  configure :title
89
89
  # @!attribute [rw]
90
- configure :index_resources_per_page, default: 20
90
+ configure :index_records_per_page, default: 20
91
91
  # @!attribute [rw]
92
92
  configure :controller_namespace, default: "admin"
93
93
  # @!attribute [rw]
@@ -1,120 +1,36 @@
1
+ require "super/controls/optional"
2
+ require "super/controls/required"
3
+ require "super/controls/steps"
4
+
1
5
  module Super
2
6
  # A wrapper around the per-controller Controls classes. This class often
3
7
  # directly delegates to the per-controller classes, but it can also provide
4
8
  # some default implementation.
5
9
  class Controls
10
+ include Required
11
+ include Optional
12
+ include Steps
13
+
6
14
  def initialize(actual)
7
15
  @actual = actual
8
16
  end
9
17
 
10
18
  attr_reader :actual
11
19
 
12
- # This is an optional method
13
- #
14
- # @return [String]
15
- def title
16
- if @actual.respond_to?(:title)
17
- return @actual.title
18
- end
19
-
20
- model.name.pluralize
21
- end
22
-
23
- # Specifies the model. This is a required method
24
- #
25
- # @return [ActiveRecord::Base]
26
- def model
27
- @actual.model
28
- end
20
+ private
29
21
 
30
- # Configures the actions linked to on the index page. This is an optional
31
- # method
32
- #
33
- # @param params [ActionController::Parameters]
34
- # @param action [ActionInquirer]
35
- # @return [Array<Link>]
36
- def resources_actions(params:, action:)
37
- actions =
38
- if @actual.respond_to?(:resources_actions)
39
- @actual.resources_actions(params: params, action: action)
22
+ def default_for(method_name, *args, **kwargs)
23
+ if @actual.respond_to?(method_name)
24
+ if args.empty? && kwargs.empty?
25
+ return @actual.public_send(method_name)
26
+ elsif args.empty?
27
+ return @actual.public_send(method_name, **kwargs)
40
28
  else
41
- [:new]
29
+ return @actual.public_send(method_name, *args)
42
30
  end
43
-
44
- actions.map do |link|
45
- link = Link.resolve(link)
46
-
47
- link.call(params: params)
48
31
  end
49
- end
50
-
51
- # Configures the actions linked to on the show page as well as each row of
52
- # the table on the index page. This is an optional method
53
- #
54
- # @param resource [ActiveRecord::Base]
55
- # @param params [ActionController::Parameters]
56
- # @param action [ActionInquirer]
57
- # @return [Array<Link>]
58
- def resource_actions(resource, params:, action:)
59
- actions =
60
- if @actual.respond_to?(:resource_actions)
61
- @actual.resource_actions(resource, params: params, action: action)
62
- else
63
- if action.show?
64
- [:edit, :destroy]
65
- elsif action.edit?
66
- [:show, :destroy]
67
- else
68
- [:show, :edit, :destroy]
69
- end
70
- end
71
-
72
- actions.map do |link|
73
- link = Link.resolve(link)
74
-
75
- link.call(resource, params: params)
76
- end
77
- end
78
-
79
- # Configures what database records are visible on load. This is an optional
80
- # method, it defaults to "`all`" methods
81
- #
82
- # @param action [ActionInquirer]
83
- # @return [ActiveRecord::Relation]
84
- def scope(action:)
85
- if @actual.respond_to?(:scope)
86
- return @actual.scope(action: action)
87
- end
88
-
89
- model.all
90
- end
91
-
92
- # Configures which parameters could be written to the database. This is a
93
- # required method
94
- #
95
- # @param params [ActionController::Parameters]
96
- # @param action [ActionInquirer]
97
- # @return [ActionController::Parameters]
98
- def permitted_params(params, action:)
99
- @actual.permitted_params(params, action: action)
100
- end
101
-
102
- # Configures the fields that are displayed on the index and show actions.
103
- # This is a required method
104
- #
105
- # @param action [ActionInquirer]
106
- # @return [Schema]
107
- def display_schema(action:)
108
- @actual.display_schema(action: action)
109
- end
110
32
 
111
- # Configures the editable fields on the new and edit actions. This is a
112
- # required method
113
- #
114
- # @param action [ActionInquirer]
115
- # @return [Schema]
116
- def form_schema(action:)
117
- @actual.form_schema(action: action)
33
+ yield
118
34
  end
119
35
  end
120
36
  end
@@ -0,0 +1,65 @@
1
+ module Super
2
+ class Controls
3
+ # Methods for `Controls` that have a sane default implementation
4
+ module Optional
5
+ # This is an optional method
6
+ #
7
+ # @return [String]
8
+ def title
9
+ default_for(:title) do
10
+ model.name.pluralize
11
+ end
12
+ end
13
+
14
+ # Configures what database records are visible on load. This is an optional
15
+ # method, it defaults to "`all`" methods
16
+ #
17
+ # @param action [ActionInquirer]
18
+ # @return [ActiveRecord::Relation]
19
+ def scope(action:)
20
+ default_for(:scope, action: action) do
21
+ model.all
22
+ end
23
+ end
24
+
25
+ # Configures the actions linked to on the index page. This is an optional
26
+ # method
27
+ #
28
+ # @param action [ActionInquirer]
29
+ # @return [Array<Link>]
30
+ def collection_actions(action:)
31
+ default_for(:collection_actions, action: action) do
32
+ Super::Link.find_all(:new)
33
+ end
34
+ end
35
+
36
+ # Configures the actions linked to on the show page as well as each row of
37
+ # the table on the index page. This is an optional method
38
+ #
39
+ # @param action [ActionInquirer]
40
+ # @return [Array<Link>]
41
+ def member_actions(action:)
42
+ default_for(:member_actions, action: action) do
43
+ if action.show?
44
+ Super::Link.find_all(:edit, :destroy)
45
+ elsif action.edit?
46
+ Super::Link.find_all(:show, :destroy)
47
+ else
48
+ Super::Link.find_all(:show, :edit, :destroy)
49
+ end
50
+ end
51
+ end
52
+
53
+ # Specifies how many records to show per page
54
+ #
55
+ # @param action [ActionInquirer]
56
+ # @param query_params [Hash]
57
+ # @return [ActiveRecord::Relation]
58
+ def records_per_page(action:, query_params:)
59
+ default_for(:records_per_page, action: action, query_params: query_params) do
60
+ Super.configuration.index_records_per_page
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,41 @@
1
+ module Super
2
+ class Controls
3
+ # Methods for `Controls` that must be defined for Super to work properly
4
+ module Required
5
+ # Specifies the model. This is a required method
6
+ #
7
+ # @return [ActiveRecord::Base]
8
+ def model
9
+ @actual.model
10
+ end
11
+
12
+ # Configures which parameters could be written to the database. This is a
13
+ # required method
14
+ #
15
+ # @param params [ActionController::Parameters]
16
+ # @param action [ActionInquirer]
17
+ # @return [ActionController::Parameters]
18
+ def permitted_params(params, action:)
19
+ @actual.permitted_params(params, action: action)
20
+ end
21
+
22
+ # Configures the fields that are displayed on the index and show actions.
23
+ # This is a required method
24
+ #
25
+ # @param action [ActionInquirer]
26
+ # @return [Schema]
27
+ def display_schema(action:)
28
+ @actual.display_schema(action: action)
29
+ end
30
+
31
+ # Configures the editable fields on the new and edit actions. This is a
32
+ # required method
33
+ #
34
+ # @param action [ActionInquirer]
35
+ # @return [Schema]
36
+ def form_schema(action:)
37
+ @actual.form_schema(action: action)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,115 @@
1
+ module Super
2
+ class Controls
3
+ # Methods that are called by controller actions. All of these methods have
4
+ # a default implementation, but feel free to override as needed.
5
+ module Steps
6
+ # Tells the controller how to load records in the index action using
7
+ # `#scope`
8
+ #
9
+ # @param action [ActionInquirer]
10
+ # @param params [ActionController::Parameters]
11
+ # @return [ActiveRecord::Relation]
12
+ def load_records(action:, params:)
13
+ default_for(:load_records, action: action, params: params) do
14
+ scope(action: action)
15
+ end
16
+ end
17
+
18
+ # Sets up pagination
19
+ #
20
+ # @param action [ActionInquirer]
21
+ # @param records [ActiveRecord::Relation]
22
+ # @param query_params [Hash]
23
+ # @return [Pagination]
24
+ def initialize_pagination(action:, records:, query_params:)
25
+ default_for(:initialize_pagination, action: action, records: records, query_params: query_params) do
26
+ Pagination.new(
27
+ total_count: records.size,
28
+ limit: records_per_page(action: action, query_params: query_params),
29
+ query_params: query_params,
30
+ page_query_param: :page
31
+ )
32
+ end
33
+ end
34
+
35
+ # Paginates
36
+ #
37
+ # @param action [ActionInquirer]
38
+ # @param records [ActiveRecord::Relation]
39
+ # @param pagination [Pagination]
40
+ # @return [ActiveRecord::Relation]
41
+ def paginate_records(action:, records:, pagination:)
42
+ default_for(:paginate_records, action: action, records: records, pagination: pagination) do
43
+ records
44
+ .limit(pagination.limit)
45
+ .offset(pagination.offset)
46
+ end
47
+ end
48
+
49
+ # Loads a record using `#scope`
50
+ #
51
+ # @param action [ActionInquirer]
52
+ # @param params [ActionController::Parameters]
53
+ # @return [ActiveRecord::Base]
54
+ def load_record(action:, params:)
55
+ default_for(:load_record, action: action, params: params) do
56
+ scope(action: action).find(params[:id])
57
+ end
58
+ end
59
+
60
+ # Builds a record using `#scope`
61
+ #
62
+ # @param action [ActionInquirer]
63
+ # @return [ActiveRecord::Base]
64
+ def build_record(action:)
65
+ default_for(:build_record) do
66
+ scope(action: action).build
67
+ end
68
+ end
69
+
70
+ # Builds and populates a record using `#scope`
71
+ #
72
+ # @param action [ActionInquirer]
73
+ # @param params [ActionController::Parameters]
74
+ # @return [ActiveRecord::Base]
75
+ def build_record_with_params(action:, params:)
76
+ default_for(:build_record_with_params, action: action, params: params) do
77
+ scope(action: action).build(permitted_params(params, action: action))
78
+ end
79
+ end
80
+
81
+ # Saves a record
82
+ #
83
+ # @param action [ActionInquirer]
84
+ # @param params [ActionController::Parameters]
85
+ # @return [ActiveRecord::Base]
86
+ def save_record(action:, record:, params:)
87
+ default_for(:save_record, action: action, record: record, params: params) do
88
+ record.save
89
+ end
90
+ end
91
+
92
+ # Saves a record
93
+ #
94
+ # @param action [ActionInquirer]
95
+ # @param params [ActionController::Parameters]
96
+ # @return [ActiveRecord::Base]
97
+ def update_record(action:, record:, params:)
98
+ default_for(:update_record, action: action, record: record, params: params) do
99
+ record.update(permitted_params(params, action: action))
100
+ end
101
+ end
102
+
103
+ # Destroys a record
104
+ #
105
+ # @param action [ActionInquirer]
106
+ # @param params [ActionController::Parameters]
107
+ # @return [ActiveRecord::Base, false]
108
+ def destroy_record(action:, record:, params:)
109
+ default_for(:update_record, action: action, record: record, params: params) do
110
+ record.destroy
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end