wallaby-core 0.1.0
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/app/controllers/wallaby/application_controller.rb +84 -0
- data/app/controllers/wallaby/resources_controller.rb +381 -0
- data/app/controllers/wallaby/secure_controller.rb +81 -0
- data/app/security/ability.rb +13 -0
- data/config/locales/wallaby.en.yml +140 -0
- data/config/locales/wallaby_class.en.yml +30 -0
- data/config/routes.rb +39 -0
- data/lib/adaptors/wallaby/custom.rb +7 -0
- data/lib/adaptors/wallaby/custom/default_provider.rb +9 -0
- data/lib/adaptors/wallaby/custom/model_decorator.rb +71 -0
- data/lib/adaptors/wallaby/custom/model_finder.rb +13 -0
- data/lib/adaptors/wallaby/custom/model_pagination_provider.rb +14 -0
- data/lib/adaptors/wallaby/custom/model_service_provider.rb +48 -0
- data/lib/authorizers/wallaby/cancancan_authorization_provider.rb +72 -0
- data/lib/authorizers/wallaby/default_authorization_provider.rb +58 -0
- data/lib/authorizers/wallaby/model_authorizer.rb +100 -0
- data/lib/authorizers/wallaby/pundit_authorization_provider.rb +89 -0
- data/lib/concerns/wallaby/authorizable.rb +103 -0
- data/lib/concerns/wallaby/baseable.rb +36 -0
- data/lib/concerns/wallaby/decoratable.rb +101 -0
- data/lib/concerns/wallaby/defaultable.rb +38 -0
- data/lib/concerns/wallaby/engineable.rb +61 -0
- data/lib/concerns/wallaby/fieldable.rb +78 -0
- data/lib/concerns/wallaby/paginatable.rb +72 -0
- data/lib/concerns/wallaby/rails_overridden_methods.rb +42 -0
- data/lib/concerns/wallaby/resourcable.rb +149 -0
- data/lib/concerns/wallaby/servicable.rb +68 -0
- data/lib/concerns/wallaby/shared_helpers.rb +22 -0
- data/lib/concerns/wallaby/themeable.rb +40 -0
- data/lib/decorators/wallaby/resource_decorator.rb +189 -0
- data/lib/errors/wallaby/cell_handling.rb +6 -0
- data/lib/errors/wallaby/forbidden.rb +6 -0
- data/lib/errors/wallaby/general_error.rb +6 -0
- data/lib/errors/wallaby/invalid_error.rb +6 -0
- data/lib/errors/wallaby/model_not_found.rb +11 -0
- data/lib/errors/wallaby/not_authenticated.rb +6 -0
- data/lib/errors/wallaby/not_found.rb +6 -0
- data/lib/errors/wallaby/not_implemented.rb +6 -0
- data/lib/errors/wallaby/resource_not_found.rb +11 -0
- data/lib/errors/wallaby/unprocessable_entity.rb +6 -0
- data/lib/forms/wallaby/form_builder.rb +60 -0
- data/lib/helpers/wallaby/application_helper.rb +79 -0
- data/lib/helpers/wallaby/base_helper.rb +65 -0
- data/lib/helpers/wallaby/configuration_helper.rb +18 -0
- data/lib/helpers/wallaby/form_helper.rb +62 -0
- data/lib/helpers/wallaby/index_helper.rb +84 -0
- data/lib/helpers/wallaby/links_helper.rb +213 -0
- data/lib/helpers/wallaby/resources_helper.rb +52 -0
- data/lib/helpers/wallaby/secure_helper.rb +54 -0
- data/lib/helpers/wallaby/styling_helper.rb +82 -0
- data/lib/interfaces/wallaby/mode.rb +72 -0
- data/lib/interfaces/wallaby/model_authorization_provider.rb +99 -0
- data/lib/interfaces/wallaby/model_decorator.rb +168 -0
- data/lib/interfaces/wallaby/model_finder.rb +12 -0
- data/lib/interfaces/wallaby/model_pagination_provider.rb +107 -0
- data/lib/interfaces/wallaby/model_service_provider.rb +84 -0
- data/lib/paginators/wallaby/model_paginator.rb +115 -0
- data/lib/paginators/wallaby/resource_paginator.rb +12 -0
- data/lib/parsers/wallaby/parser.rb +34 -0
- data/lib/renderers/wallaby/cell.rb +137 -0
- data/lib/renderers/wallaby/cell_resolver.rb +89 -0
- data/lib/renderers/wallaby/custom_lookup_context.rb +64 -0
- data/lib/renderers/wallaby/custom_partial_renderer.rb +33 -0
- data/lib/renderers/wallaby/custom_renderer.rb +16 -0
- data/lib/responders/wallaby/json_api_responder.rb +101 -0
- data/lib/responders/wallaby/resources_responder.rb +28 -0
- data/lib/routes/wallaby/resources_router.rb +72 -0
- data/lib/servicers/wallaby/model_servicer.rb +154 -0
- data/lib/services/wallaby/engine_name_finder.rb +22 -0
- data/lib/services/wallaby/engine_url_for.rb +46 -0
- data/lib/services/wallaby/link_options_normalizer.rb +19 -0
- data/lib/services/wallaby/map/mode_mapper.rb +27 -0
- data/lib/services/wallaby/map/model_class_collector.rb +49 -0
- data/lib/services/wallaby/map/model_class_mapper.rb +38 -0
- data/lib/services/wallaby/prefixes_builder.rb +66 -0
- data/lib/services/wallaby/sorting/hash_builder.rb +19 -0
- data/lib/services/wallaby/sorting/link_builder.rb +69 -0
- data/lib/services/wallaby/sorting/next_builder.rb +63 -0
- data/lib/services/wallaby/sorting/single_builder.rb +20 -0
- data/lib/services/wallaby/type_renderer.rb +50 -0
- data/lib/support/action_dispatch/routing/mapper.rb +75 -0
- data/lib/tree/wallaby/node.rb +25 -0
- data/lib/utils/wallaby/cell_utils.rb +34 -0
- data/lib/utils/wallaby/field_utils.rb +43 -0
- data/lib/utils/wallaby/filter_utils.rb +20 -0
- data/lib/utils/wallaby/model_utils.rb +51 -0
- data/lib/utils/wallaby/module_utils.rb +46 -0
- data/lib/utils/wallaby/params_utils.rb +14 -0
- data/lib/utils/wallaby/preload_utils.rb +44 -0
- data/lib/utils/wallaby/test_utils.rb +34 -0
- data/lib/utils/wallaby/utils.rb +27 -0
- data/lib/wallaby/configuration.rb +103 -0
- data/lib/wallaby/configuration/features.rb +24 -0
- data/lib/wallaby/configuration/mapping.rb +140 -0
- data/lib/wallaby/configuration/metadata.rb +23 -0
- data/lib/wallaby/configuration/models.rb +46 -0
- data/lib/wallaby/configuration/pagination.rb +30 -0
- data/lib/wallaby/configuration/security.rb +98 -0
- data/lib/wallaby/configuration/sorting.rb +28 -0
- data/lib/wallaby/constants.rb +45 -0
- data/lib/wallaby/core.rb +117 -0
- data/lib/wallaby/core/version.rb +7 -0
- data/lib/wallaby/engine.rb +43 -0
- data/lib/wallaby/map.rb +170 -0
- metadata +222 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Wallaby application helper
|
|
5
|
+
module ApplicationHelper
|
|
6
|
+
include ConfigurationHelper
|
|
7
|
+
include Engineable
|
|
8
|
+
include SharedHelpers
|
|
9
|
+
|
|
10
|
+
# @!method try_to(subject, method_id, *args, &block)
|
|
11
|
+
# (see Wallaby::ModuleUtils.try_to)
|
|
12
|
+
# @see Wallaby::ModuleUtils.try_to
|
|
13
|
+
delegate :try_to, to: ModuleUtils
|
|
14
|
+
|
|
15
|
+
# Override the origin view_renderer to support {Wallaby::Cell} rendering
|
|
16
|
+
# @!attribute [r] view_renderer
|
|
17
|
+
# @see Wallaby::CustomRenderer
|
|
18
|
+
def view_renderer
|
|
19
|
+
return @view_renderer if @view_renderer.is_a? CustomRenderer
|
|
20
|
+
|
|
21
|
+
@view_renderer = CustomRenderer.new @view_renderer.lookup_context
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Override origin method to handle URL for Wallaby engine.
|
|
25
|
+
#
|
|
26
|
+
# As Wallaby's routes are declared in a
|
|
27
|
+
# {https://guides.rubyonrails.org/routing.html#routing-to-rack-applications Rack application} fashion, this will
|
|
28
|
+
# lead to **ActionController::RoutingError** exception when using ordinary **url_for**
|
|
29
|
+
# (e.g. `url_for action: :index`).
|
|
30
|
+
#
|
|
31
|
+
# Gotcha: Wallaby can't cope well with the following situation.
|
|
32
|
+
# It's due to the limit of route declaration and matching:
|
|
33
|
+
#
|
|
34
|
+
# ```
|
|
35
|
+
# scope path: '/prefix' do
|
|
36
|
+
# wresources :products, controller: 'wallaby/resources'
|
|
37
|
+
# end
|
|
38
|
+
# ```
|
|
39
|
+
# @param options [String, Hash, ActionController::Parameters]
|
|
40
|
+
# @option options [Boolean]
|
|
41
|
+
# :with_query to include `request.query_parameters` values for url generation.
|
|
42
|
+
# @option options [String]
|
|
43
|
+
# :engine_name to specify the engine_name to use, default to {Wallaby::Engineable#current_engine_name}
|
|
44
|
+
# @return [String] URL string
|
|
45
|
+
# @see Wallaby::EngineUrlFor.handle
|
|
46
|
+
# @see https://api.rubyonrails.org/classes/ActionView/RoutingUrlFor.html#method-i-url_for
|
|
47
|
+
# ActionView::RoutingUrlFor#url_for
|
|
48
|
+
def url_for(options = nil)
|
|
49
|
+
if options.is_a?(Hash) || try_to(options, :permitted?)
|
|
50
|
+
# merge with all current query parameters
|
|
51
|
+
options = request.query_parameters.merge(options) if options.delete(:with_query)
|
|
52
|
+
options = ParamsUtils.presence url_options, options # remove blank values
|
|
53
|
+
EngineUrlFor.handle(
|
|
54
|
+
engine_name: options.fetch(:engine_name, current_engine_name), parameters: options
|
|
55
|
+
)
|
|
56
|
+
end || super(options)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Override origin method to add turbolinks tracking when it's enabled
|
|
60
|
+
# @param sources [Array<String>]
|
|
61
|
+
# @return [String] stylesheet link tags HTML
|
|
62
|
+
def stylesheet_link_tag(*sources)
|
|
63
|
+
default_options =
|
|
64
|
+
features.turbolinks_enabled ? { 'data-turbolinks-track' => true } : {}
|
|
65
|
+
options = default_options.merge!(sources.extract_options!.stringify_keys)
|
|
66
|
+
super(*sources, options)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Override origin method to add turbolinks tracking when it's enabled
|
|
70
|
+
# @param sources [Array<String>]
|
|
71
|
+
# @return [String] javascript script tags HTML
|
|
72
|
+
def javascript_include_tag(*sources)
|
|
73
|
+
default_options =
|
|
74
|
+
features.turbolinks_enabled ? { 'data-turbolinks-track' => true, 'data-turbolinks-eval' => false } : {}
|
|
75
|
+
options = default_options.merge!(sources.extract_options!.stringify_keys)
|
|
76
|
+
super(*sources, options)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# NOTE: Global helper methods should go in here
|
|
5
|
+
module BaseHelper
|
|
6
|
+
include StylingHelper
|
|
7
|
+
include LinksHelper
|
|
8
|
+
|
|
9
|
+
# @see ModelUtils.to_model_label
|
|
10
|
+
# @return [String] label for given model class
|
|
11
|
+
def to_model_label(model_class)
|
|
12
|
+
ModelUtils.to_model_label model_class
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @see Map.resources_name_map
|
|
16
|
+
# @return [String] resources name for given model class
|
|
17
|
+
def to_resources_name(model_class)
|
|
18
|
+
Map.resources_name_map model_class
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Generate body class from the following sources:
|
|
22
|
+
# - `:action` parameter
|
|
23
|
+
# - converted current resources name (e.g. `order__item` from `Order::Item`)
|
|
24
|
+
# - `:custom_body_class` content
|
|
25
|
+
# @return [String] css classes for body tag
|
|
26
|
+
def body_class
|
|
27
|
+
[
|
|
28
|
+
params[:action],
|
|
29
|
+
controller_path.gsub(SLASH, '__'),
|
|
30
|
+
current_resources_name.try(:gsub, COLONS, '__'),
|
|
31
|
+
content_for(:custom_body_class)
|
|
32
|
+
].compact.join SPACE
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Turn a list of classes into tree structure by inheritance.
|
|
36
|
+
# @param classes [Array<Class>]
|
|
37
|
+
# a list of all the classes that wallaby supports
|
|
38
|
+
# @return [Array<Wallaby::Node>] a tree structure of given classes
|
|
39
|
+
def model_classes(classes = Map.model_classes)
|
|
40
|
+
nested_hash = classes.each_with_object({}) do |klass, hash|
|
|
41
|
+
hash[klass] = Node.new(klass)
|
|
42
|
+
end
|
|
43
|
+
nested_hash.each do |klass, node|
|
|
44
|
+
node.parent = parent = nested_hash[klass.superclass]
|
|
45
|
+
parent.children << node if parent
|
|
46
|
+
end
|
|
47
|
+
nested_hash.values.select { |v| v.parent.nil? }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Turn the tree of classes into a nested `ul` list.
|
|
51
|
+
# @param array [Array<Wallaby::Node>] root classes
|
|
52
|
+
# @return [String] HTML for the whole tree
|
|
53
|
+
def model_tree(array, base_class = nil)
|
|
54
|
+
return EMPTY_STRING if array.blank?
|
|
55
|
+
|
|
56
|
+
options = { html_options: { class: 'dropdown-item' } }
|
|
57
|
+
content_tag :ul, class: 'dropdown-menu', 'aria-labelledby': base_class do
|
|
58
|
+
array.sort_by(&:name).each do |node|
|
|
59
|
+
content = index_link(node.klass, options).try :<<, model_tree(node.children)
|
|
60
|
+
concat content_tag(:li, content)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Configuration helper module. Provide shortcut methods to configurations.
|
|
5
|
+
module ConfigurationHelper
|
|
6
|
+
delegate :models, :security, :mapping, :pagination, :features, :sorting, to: :configuration
|
|
7
|
+
|
|
8
|
+
# @return [Wallaby::Configuration] shortcut method of configuration
|
|
9
|
+
def configuration
|
|
10
|
+
Wallaby.configuration
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [Wallaby::Configuration::Metadata] shortcut method of metadata
|
|
14
|
+
def default_metadata
|
|
15
|
+
configuration.metadata
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Form helper
|
|
5
|
+
module FormHelper
|
|
6
|
+
# @deprecated Use {Wallaby::ResourcesHelper#type_render} instead. It will be removed from 5.3.*
|
|
7
|
+
def form_type_partial_render(options = {}, locals = {}, &block)
|
|
8
|
+
Utils.deprecate 'deprecation.form_type_partial_render', caller: caller
|
|
9
|
+
type_render options, locals, &block
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# To generate remote URL for auto select plugin.
|
|
13
|
+
# @see https://github.com/reinteractive/wallaby/blob/master/app/assets/javascripts/wallaby/auto_select.js
|
|
14
|
+
# auto_select.js
|
|
15
|
+
# @param url [String, nil]
|
|
16
|
+
# if URL is nil, it will fall back to default remote URL
|
|
17
|
+
# @param model_class [Class]
|
|
18
|
+
# @param wildcard [String] wildcard that auto_select uses to replace with
|
|
19
|
+
# the typed keyword
|
|
20
|
+
# @return [String] URL for autocomplete
|
|
21
|
+
def remote_url(url, model_class, wildcard = 'QUERY')
|
|
22
|
+
url || index_path(model_class, url_params: { q: wildcard, per: pagination.page_size })
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# To generate dropdown options (class => url) for polymorphic class.
|
|
26
|
+
# @see https://github.com/reinteractive/wallaby/blob/master/app/assets/javascripts/wallaby/auto_select.js
|
|
27
|
+
# auto_select.js
|
|
28
|
+
# This function will pull out remote URLs from `metadata[:remote_urls]`
|
|
29
|
+
# (Class => url).
|
|
30
|
+
# @see ActionView::Helpers::FormOptionsHelper#options_for_select
|
|
31
|
+
# @param metadata [Hash]
|
|
32
|
+
# @param wildcard [String] wildcard to be used in the URL
|
|
33
|
+
# @param select_options [Hash]
|
|
34
|
+
# @return [String] options HTML
|
|
35
|
+
def polymorphic_options(metadata, wildcard = 'QUERY', select_options = {})
|
|
36
|
+
urls = metadata[:remote_urls] || {}
|
|
37
|
+
options = (metadata[:polymorphic_list] || []).map do |klass|
|
|
38
|
+
[
|
|
39
|
+
klass, klass,
|
|
40
|
+
{ data: { url: remote_url(urls[klass], klass, wildcard) } }
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
options_for_select options, select_options
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# To fetch the hints from the following keys:
|
|
47
|
+
# - hints.#\{ type \}_html
|
|
48
|
+
# - hints.#\{ type \}
|
|
49
|
+
# @param metadata [Hash]
|
|
50
|
+
# @return [String, nil] HTML
|
|
51
|
+
def hint_of(metadata)
|
|
52
|
+
type = metadata[:type]
|
|
53
|
+
hint = metadata[:hint]
|
|
54
|
+
# @see http://guides.rubyonrails.org/i18n.html#using-safe-html-translations
|
|
55
|
+
hint ||= type && t("hints.#{type}_html", default: '').presence
|
|
56
|
+
hint ||= type && t("hints.#{type}", default: '').presence
|
|
57
|
+
return unless hint
|
|
58
|
+
|
|
59
|
+
content_tag :p, hint, class: 'help-block'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Helper methods for index action
|
|
5
|
+
module IndexHelper
|
|
6
|
+
# @deprecated This method is no longer in use. It will be removed from 5.3.*
|
|
7
|
+
def index_params(parameters = params)
|
|
8
|
+
Utils.deprecate 'deprecation.index_params', caller: caller
|
|
9
|
+
parameters
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @deprecated Use {Wallaby::Paginatable#current_paginator} instead. It will be removed from 5.3.*
|
|
13
|
+
def paginator_of(_model_class, _collection, _params)
|
|
14
|
+
Utils.deprecate 'deprecation.paginator_of', caller: caller
|
|
15
|
+
current_paginator
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Just a label
|
|
19
|
+
# @return [String]
|
|
20
|
+
def all_label
|
|
21
|
+
t 'filters.all'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# If `:fields` parameter is given, only display fields that is in `index_field_names`
|
|
25
|
+
# Otherwise, `index_field_names`
|
|
26
|
+
# @param decorated_collection [Array<Wallaby::ResourceDecorator>]
|
|
27
|
+
# @param fields_from_params [Array<String>]
|
|
28
|
+
# @return [Array<String>] a list of field names for json builder
|
|
29
|
+
def json_fields_of(decorated_collection, fields_from_params = params[:fields])
|
|
30
|
+
return [] if decorated_collection.blank?
|
|
31
|
+
|
|
32
|
+
decorated = decorated_collection.first
|
|
33
|
+
index_field_names = decorated.index_field_names.map(&:to_s)
|
|
34
|
+
fields = (fields_from_params.presence || index_field_names).split(/\s*,\s*/).flatten
|
|
35
|
+
fields & index_field_names
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param filter_name [String, Symbol]
|
|
39
|
+
# @param filters [Hash]
|
|
40
|
+
# @return [String] filter label for the given field name
|
|
41
|
+
def filter_label(filter_name, filters)
|
|
42
|
+
# TODO: use locale for filter_name label
|
|
43
|
+
filters[filter_name].try(:[], :label) || filter_name.to_s.humanize
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @param filter_name [String, Symbol]
|
|
47
|
+
# @param filters [Hash]
|
|
48
|
+
# @return [String] filter name
|
|
49
|
+
# @see Wallaby::FilterUtils.filter_name_by
|
|
50
|
+
def filter_name_by(filter_name, filters)
|
|
51
|
+
FilterUtils.filter_name_by filter_name, filters
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Link for a given model class and filter name
|
|
55
|
+
# @param model_class [Class]
|
|
56
|
+
# @param filter_name [String, Symbol]
|
|
57
|
+
# @param filters [Hash]
|
|
58
|
+
# @param url_params [Hash, ActionController::Parameters]
|
|
59
|
+
# @return [String] HTML anchor link
|
|
60
|
+
def filter_link(model_class, filter_name, filters: {}, url_params: {})
|
|
61
|
+
is_all = filter_name == :all
|
|
62
|
+
config = filters[filter_name] || {}
|
|
63
|
+
label = is_all ? all_label : filter_label(filter_name, filters)
|
|
64
|
+
url_params[:filter] = config[:default] ? nil : filter_name
|
|
65
|
+
index_link(model_class, options: { url: url_for(url_params.merge(with_query: true)) }) { label }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param model_class [Class]
|
|
69
|
+
# @param url_params [Hash, ActionController::Parameters] extra URL params
|
|
70
|
+
# @return [String] Export link for the given model_class.
|
|
71
|
+
def export_link(model_class, url_params: {})
|
|
72
|
+
index_link(model_class, url_params: { format: 'csv', page: nil, per: nil, with_query: true }.merge(url_params)) do
|
|
73
|
+
t 'links.export', ext: 'CSV'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @return [Wallaby::Sorting::LinkBuilder]
|
|
78
|
+
# @see Wallaby::Sorting::LinkBuilder
|
|
79
|
+
def sort_link_builder
|
|
80
|
+
@sort_link_builder ||=
|
|
81
|
+
Sorting::LinkBuilder.new current_model_decorator, params.slice(:sort).permit!, self, sorting.strategy
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wallaby
|
|
4
|
+
# Links helper
|
|
5
|
+
module LinksHelper
|
|
6
|
+
# Return link to index page for a given model class
|
|
7
|
+
# @param model_class [Class]
|
|
8
|
+
# @param options [Hash]
|
|
9
|
+
# @option options [String] :url url/path for the link
|
|
10
|
+
# @param url_params [ActionController::Parameters, Hash]
|
|
11
|
+
# @param html_options [Hash] (see
|
|
12
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
13
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
14
|
+
# @yield block to return the link label
|
|
15
|
+
# @return [String] anchor link to index page for a given model class
|
|
16
|
+
# @return [nil] if user's not authorized
|
|
17
|
+
def index_link(model_class, options: {}, url_params: {}, html_options: {}, &block)
|
|
18
|
+
return if unauthorized? :index, model_class
|
|
19
|
+
|
|
20
|
+
html_options, block = LinkOptionsNormalizer.normalize(
|
|
21
|
+
html_options, block,
|
|
22
|
+
block: -> { to_model_label model_class }
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
url_params = request.query_parameters.merge(url_params) if url_params.delete(:with_query)
|
|
26
|
+
url = options[:url] || index_path(model_class, url_params: url_params)
|
|
27
|
+
link_to url, html_options, &block
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Return link to create page for a given model class
|
|
31
|
+
# @param model_class [Class]
|
|
32
|
+
# @param options [Hash]
|
|
33
|
+
# @option options [String] :url url/path for the link
|
|
34
|
+
# @param url_params [ActionController::Parameters, Hash]
|
|
35
|
+
# @param html_options [Hash] (see
|
|
36
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
37
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
38
|
+
# @yield block to return the link label
|
|
39
|
+
# @return [String, nil] anchor element
|
|
40
|
+
# @return [nil] if user's not authorized
|
|
41
|
+
def new_link(model_class, options: {}, url_params: {}, html_options: {}, &block)
|
|
42
|
+
return if unauthorized? :new, model_class
|
|
43
|
+
|
|
44
|
+
html_options, block = LinkOptionsNormalizer.normalize(
|
|
45
|
+
html_options, block,
|
|
46
|
+
class: 'resource__create',
|
|
47
|
+
block: -> { t 'links.new', model: to_model_label(model_class) }
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
url = options[:url] || new_path(model_class, url_params: url_params)
|
|
51
|
+
link_to url, html_options, &block
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return link to show page for a given model class.
|
|
55
|
+
# @param resource [Object, Wallaby::ResourceDecorator] model class
|
|
56
|
+
# @param options [Hash]
|
|
57
|
+
# @option options [String] :url url/path for the link
|
|
58
|
+
# @option options [Boolean] :readonly readonly and therefore output the label
|
|
59
|
+
# @option options [Boolean] :is_resource to tell {#show_path} if it is a resource
|
|
60
|
+
# @param url_params [ActionController::Parameters, Hash]
|
|
61
|
+
# @param html_options [Hash] (see
|
|
62
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
63
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
64
|
+
# @yield block to return the link label
|
|
65
|
+
# @return [String] anchor element / text
|
|
66
|
+
# @return [nil] if user's not authorized
|
|
67
|
+
def show_link(resource, options: {}, url_params: {}, html_options: {}, &block)
|
|
68
|
+
# NOTE: to_s is a must
|
|
69
|
+
# if a block is returning integer (e.g. `{ 1 }`)
|
|
70
|
+
# `link_to` will render blank text note inside hyper link
|
|
71
|
+
html_options, block = LinkOptionsNormalizer.normalize(
|
|
72
|
+
html_options, block,
|
|
73
|
+
block: -> { decorate(resource).to_label.to_s }
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
default = options[:readonly] && block.call || nil
|
|
77
|
+
return default if unauthorized? :show, extract(resource)
|
|
78
|
+
|
|
79
|
+
url = options[:url] || show_path(resource, is_resource: options[:is_resource], url_params: url_params)
|
|
80
|
+
link_to url, html_options, &block
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Return link to edit page for a given model class.
|
|
84
|
+
# @param resource [Object, Wallaby::ResourceDecorator] model class
|
|
85
|
+
# @param options [Hash]
|
|
86
|
+
# @option options [String] :url url/path for the link
|
|
87
|
+
# @option options [Boolean] :readonly readonly and therefore output the label
|
|
88
|
+
# @option options [Boolean] :is_resource to tell {#edit_path} if it is a resource
|
|
89
|
+
# @param url_params [ActionController::Parameters, Hash]
|
|
90
|
+
# @param html_options [Hash] (see
|
|
91
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
92
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
93
|
+
# @yield block to return the link label
|
|
94
|
+
# @return [String] anchor element / text
|
|
95
|
+
# @return [nil] if user's not authorized
|
|
96
|
+
def edit_link(resource, options: {}, url_params: {}, html_options: {}, &block)
|
|
97
|
+
html_options, block = LinkOptionsNormalizer.normalize(
|
|
98
|
+
html_options, block,
|
|
99
|
+
class: 'resource__update',
|
|
100
|
+
block: -> { "#{t 'links.edit'} #{decorate(resource).to_label}" }
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
default = options[:readonly] && block.call || nil
|
|
104
|
+
return default if unauthorized? :edit, extract(resource)
|
|
105
|
+
|
|
106
|
+
url = options[:url] || edit_path(resource, is_resource: options[:is_resource], url_params: url_params)
|
|
107
|
+
link_to url, html_options, &block
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Return link to delete action for a given model class.
|
|
111
|
+
# @param resource [Object, Wallaby::ResourceDecorator] model class
|
|
112
|
+
# @param options [Hash]
|
|
113
|
+
# @option options [String] :url url/path for the link
|
|
114
|
+
# @option options [Boolean] :is_resource to tell {#edit_path} if it is a resource
|
|
115
|
+
# @param url_params [ActionController::Parameters, Hash]
|
|
116
|
+
# @param html_options [Hash] (see
|
|
117
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
118
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
119
|
+
# @yield block to return the link label
|
|
120
|
+
# @return [String, nil] anchor element
|
|
121
|
+
# @return [nil] if user's not authorized
|
|
122
|
+
def delete_link(resource, options: {}, url_params: {}, html_options: {}, &block)
|
|
123
|
+
return if unauthorized? :destroy, extract(resource)
|
|
124
|
+
|
|
125
|
+
html_options, block = LinkOptionsNormalizer.normalize(
|
|
126
|
+
html_options, block, class: 'resource__destroy', block: -> { t 'links.delete' }
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
html_options[:method] ||= :delete
|
|
130
|
+
(html_options[:data] ||= {})[:confirm] ||= t 'links.confirm.delete'
|
|
131
|
+
|
|
132
|
+
url = options[:url] || show_path(resource, is_resource: options[:is_resource], url_params: url_params)
|
|
133
|
+
link_to url, html_options, &block
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Return link to cancel action
|
|
137
|
+
# @param html_options [Hash] (see
|
|
138
|
+
# {https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
|
|
139
|
+
# ActionView::Helpers::UrlHelper#link_to})
|
|
140
|
+
# @yield block to return the link label
|
|
141
|
+
# @return [String] anchor link of cancel action
|
|
142
|
+
def cancel_link(html_options: {}, &block)
|
|
143
|
+
block ||= -> { t 'links.cancel' }
|
|
144
|
+
link_to 'javascript:history.back()', html_options, &block
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @param model_class [Class]
|
|
148
|
+
# @param url_params [Hash]
|
|
149
|
+
# @return [String] index page path
|
|
150
|
+
def index_path(model_class, url_params: {})
|
|
151
|
+
hash = ParamsUtils.presence(
|
|
152
|
+
{ action: :index },
|
|
153
|
+
default_path_params(resources: to_resources_name(model_class)),
|
|
154
|
+
url_params.to_h
|
|
155
|
+
)
|
|
156
|
+
current_engine.try(:resources_path, hash) || url_for(hash)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @param model_class [Class]
|
|
160
|
+
# @param url_params [Hash]
|
|
161
|
+
# @return [String] new page path
|
|
162
|
+
def new_path(model_class, url_params: {})
|
|
163
|
+
hash = ParamsUtils.presence(
|
|
164
|
+
{ action: :new },
|
|
165
|
+
default_path_params(resources: to_resources_name(model_class)),
|
|
166
|
+
url_params.to_h
|
|
167
|
+
)
|
|
168
|
+
current_engine.try(:new_resource_path, hash) || url_for(hash)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @param resource [Object]
|
|
172
|
+
# @param is_resource [Boolean]
|
|
173
|
+
# @param url_params [Hash]
|
|
174
|
+
# @return [String] show page path
|
|
175
|
+
def show_path(resource, is_resource: false, url_params: {})
|
|
176
|
+
decorated = decorate resource
|
|
177
|
+
return unless is_resource || decorated.primary_key_value
|
|
178
|
+
|
|
179
|
+
hash = ParamsUtils.presence(
|
|
180
|
+
{ action: :show, id: decorated.primary_key_value },
|
|
181
|
+
default_path_params(resources: decorated.resources_name),
|
|
182
|
+
url_params.to_h
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
current_engine.try(:resource_path, hash) || url_for(hash)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @param resource [Object]
|
|
189
|
+
# @param is_resource [Boolean]
|
|
190
|
+
# @param url_params [Hash]
|
|
191
|
+
# @return [String] edit page path
|
|
192
|
+
def edit_path(resource, is_resource: false, url_params: {})
|
|
193
|
+
decorated = decorate resource
|
|
194
|
+
return unless is_resource || decorated.primary_key_value
|
|
195
|
+
|
|
196
|
+
hash = ParamsUtils.presence(
|
|
197
|
+
{ action: :edit, id: decorated.primary_key_value },
|
|
198
|
+
default_path_params(resources: decorated.resources_name),
|
|
199
|
+
url_params.to_h
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
current_engine.try(:edit_resource_path, hash) || url_for(hash)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @return [Hash] default path params
|
|
206
|
+
def default_path_params(resources: nil)
|
|
207
|
+
{ script_name: request.env[SCRIPT_NAME] }.tap do |default|
|
|
208
|
+
default[:resources] = resources if current_engine || resources
|
|
209
|
+
default[:only_path] = true unless default.key?(:only_path)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|