super 0.0.5 → 0.0.6

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