compony 0.7.1 → 0.8.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 +4 -4
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +1 -1
- data/README.md +10 -14
- data/VERSION +1 -1
- data/compony.gemspec +4 -4
- data/doc/ComponentGenerator.html +1 -1
- data/doc/Components.html +1 -1
- data/doc/ComponentsGenerator.html +1 -1
- data/doc/Compony/Component.html +193 -457
- data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +3 -3
- data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone.html +187 -1
- data/doc/Compony/ComponentMixins/Default.html +1 -1
- data/doc/Compony/ComponentMixins/Resourceful.html +2 -2
- data/doc/Compony/ComponentMixins.html +1 -1
- data/doc/Compony/Components/Button.html +2 -2
- data/doc/Compony/Components/Buttons/CssButton.html +282 -0
- data/doc/Compony/Components/Buttons/Link.html +252 -0
- data/doc/Compony/Components/Buttons.html +126 -0
- data/doc/Compony/Components/Destroy.html +11 -11
- data/doc/Compony/Components/Edit.html +14 -14
- data/doc/Compony/Components/Form.html +100 -100
- data/doc/Compony/Components/Index.html +2 -2
- data/doc/Compony/Components/List.html +3 -3
- data/doc/Compony/Components/New.html +2 -2
- data/doc/Compony/Components/Show.html +24 -24
- data/doc/Compony/Components/WithForm.html +3 -3
- data/doc/Compony/Components.html +5 -3
- data/doc/Compony/ControllerMixin.html +2 -2
- data/doc/Compony/Engine.html +1 -1
- data/doc/Compony/ExposedIntentsDsl.html +403 -0
- data/doc/Compony/Intent.html +1503 -0
- data/doc/Compony/MethodAccessibleHash.html +1 -1
- data/doc/Compony/ModelFields/Anchormodel.html +1 -1
- data/doc/Compony/ModelFields/Association.html +2 -2
- data/doc/Compony/ModelFields/Attachment.html +1 -1
- data/doc/Compony/ModelFields/Base.html +1 -1
- data/doc/Compony/ModelFields/Boolean.html +1 -1
- data/doc/Compony/ModelFields/Color.html +1 -1
- data/doc/Compony/ModelFields/Currency.html +1 -1
- data/doc/Compony/ModelFields/Date.html +1 -1
- data/doc/Compony/ModelFields/Datetime.html +1 -1
- data/doc/Compony/ModelFields/Decimal.html +1 -1
- data/doc/Compony/ModelFields/Email.html +1 -1
- data/doc/Compony/ModelFields/Float.html +1 -1
- data/doc/Compony/ModelFields/Integer.html +1 -1
- data/doc/Compony/ModelFields/Percentage.html +1 -1
- data/doc/Compony/ModelFields/Phone.html +1 -1
- data/doc/Compony/ModelFields/RichText.html +1 -1
- data/doc/Compony/ModelFields/String.html +1 -1
- data/doc/Compony/ModelFields/Text.html +1 -1
- data/doc/Compony/ModelFields/Time.html +1 -1
- data/doc/Compony/ModelFields/Url.html +1 -1
- data/doc/Compony/ModelFields.html +1 -1
- data/doc/Compony/ModelMixin.html +1 -1
- data/doc/Compony/NaturalOrdering.html +1 -1
- data/doc/Compony/RequestContext.html +177 -14
- data/doc/Compony/Version.html +1 -1
- data/doc/Compony/ViewHelpers.html +15 -272
- data/doc/Compony/VirtualModel.html +1 -1
- data/doc/Compony.html +303 -837
- data/doc/ComponyController.html +1 -1
- data/doc/_index.html +30 -2
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +11 -18
- data/doc/guide/basic_component.md +12 -8
- data/doc/guide/example.md +17 -17
- data/doc/guide/feasibility.md +4 -2
- data/doc/guide/generators.md +4 -2
- data/doc/guide/inheritance.md +4 -2
- data/doc/guide/installation.md +4 -2
- data/doc/guide/intents.md +167 -0
- data/doc/guide/internal_datastructures.md +4 -2
- data/doc/guide/model_fields.md +4 -2
- data/doc/guide/nesting.md +5 -3
- data/doc/guide/ownership.md +5 -3
- data/doc/guide/pre_built_components/destroy.md +3 -3
- data/doc/guide/pre_built_components/edit.md +1 -1
- data/doc/guide/pre_built_components/form.md +1 -1
- data/doc/guide/pre_built_components/index.md +1 -1
- data/doc/guide/pre_built_components/list.md +1 -1
- data/doc/guide/pre_built_components/new.md +2 -2
- data/doc/guide/pre_built_components/show.md +1 -1
- data/doc/guide/pre_built_components/with_form.md +1 -1
- data/doc/guide/pre_built_components.md +4 -3
- data/doc/guide/resourceful.md +5 -3
- data/doc/guide/standalone.md +10 -2
- data/doc/guide/virtual_models.md +4 -2
- data/doc/index.html +11 -18
- data/doc/method_list.html +273 -161
- data/doc/top-level-namespace.html +1 -1
- data/lib/compony/component.rb +19 -48
- data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +2 -2
- data/lib/compony/component_mixins/default/standalone.rb +16 -0
- data/lib/compony/component_mixins/resourceful.rb +1 -1
- data/lib/compony/components/buttons/css_button.rb +32 -0
- data/lib/compony/components/buttons/link.rb +31 -0
- data/lib/compony/components/destroy.rb +9 -8
- data/lib/compony/components/edit.rb +5 -4
- data/lib/compony/components/form.rb +7 -1
- data/lib/compony/components/index.rb +2 -2
- data/lib/compony/components/list.rb +4 -4
- data/lib/compony/components/new.rb +1 -1
- data/lib/compony/components/show.rb +8 -11
- data/lib/compony/components/with_form.rb +1 -1
- data/lib/compony/exposed_intents_dsl.rb +29 -0
- data/lib/compony/intent.rb +145 -0
- data/lib/compony/model_fields/association.rb +1 -1
- data/lib/compony/request_context.rb +21 -0
- data/lib/compony/view_helpers.rb +5 -48
- data/lib/compony.rb +63 -149
- metadata +12 -6
- data/doc/guide/helpers.md +0 -156
- data/doc/guide/pre_built_components/button.md +0 -8
- data/doc/guide/root_actions.md +0 -67
- data/lib/compony/components/button.rb +0 -61
data/lib/compony/view_helpers.rb
CHANGED
|
@@ -4,55 +4,12 @@ module Compony
|
|
|
4
4
|
# Rule of thumb: this holds methods that require a view context and results are rendered immediately.
|
|
5
5
|
# @see Compony Compony for standalone/pure helpers
|
|
6
6
|
module ViewHelpers
|
|
7
|
-
#
|
|
8
|
-
def compony_actions
|
|
9
|
-
return nil unless Compony.root_comp
|
|
10
|
-
Compony.root_comp.render_actions(self, wrapper_class: 'root-actions', action_class: 'root-action')
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Renders a link to a component given a comp and model or family. If authentication is configured
|
|
7
|
+
# Renders a button/link to a component given a comp and model or family. If authentication is configured
|
|
14
8
|
# and the current user has insufficient permissions to access the target object, the link is not displayed.
|
|
15
|
-
#
|
|
16
|
-
# @param
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# @param link_args [Array] Positional arguments that will be passed to the Rails `link_to` helper
|
|
20
|
-
# @param label_opts [Hash] Options hash that will be passed to the label method (see {Compony::ComponentMixins::Default::Labelling#label})
|
|
21
|
-
# @param link_kwargs [Hash] Named arguments that will be passed to the Rails `link_to` helper
|
|
22
|
-
def compony_link(comp_name_or_cst_or_class,
|
|
23
|
-
model_or_family_name_or_cst = nil,
|
|
24
|
-
*link_args,
|
|
25
|
-
label: nil,
|
|
26
|
-
label_opts: {},
|
|
27
|
-
params: {},
|
|
28
|
-
feasibility_action: nil,
|
|
29
|
-
feasibility_target: nil,
|
|
30
|
-
standalone_name: nil,
|
|
31
|
-
**link_kwargs)
|
|
32
|
-
model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil
|
|
33
|
-
if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
|
|
34
|
-
target_comp_instance = comp_name_or_cst_or_class.new(data: model)
|
|
35
|
-
else
|
|
36
|
-
target_comp_instance = Compony.comp_class_for!(comp_name_or_cst_or_class, model_or_family_name_or_cst).new(data: model)
|
|
37
|
-
end
|
|
38
|
-
return unless target_comp_instance.standalone_access_permitted_for?(self, standalone_name:)
|
|
39
|
-
feasibility_action ||= comp_name_or_cst_or_class.to_s.underscore.to_sym
|
|
40
|
-
feasibility_target ||= model
|
|
41
|
-
label ||= target_comp_instance.label(model, **label_opts)
|
|
42
|
-
path ||= Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params)
|
|
43
|
-
if feasibility_target && !feasibility_target.feasible?(feasibility_action)
|
|
44
|
-
path = '#'
|
|
45
|
-
link_kwargs[:class] = link_kwargs[:class].is_a?(String) ? "#{link_kwargs[:class]} disabled" : 'disabled'
|
|
46
|
-
link_kwargs[:title] = feasibility_target.full_feasibility_messages(feasibility_action).presence
|
|
47
|
-
end
|
|
48
|
-
return helpers.link_to(label, path, *link_args, **link_kwargs)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Given a component and a family/model, this instanciates and renders a button component.
|
|
52
|
-
# @see Compony#button Check Compony.button for accepted params
|
|
53
|
-
# @see Compony::Components::Button Compony::Components::Button: the default underlying implementation
|
|
54
|
-
def compony_button(...)
|
|
55
|
-
Compony.button(...).render(helpers.controller)
|
|
9
|
+
# When inside a request context (`content do...`), this is preceded by {RequestContext#render_intent}.
|
|
10
|
+
# @param button [Hash] Parameters that will be given to the button component initializer.
|
|
11
|
+
def render_intent(*, button: {}, **)
|
|
12
|
+
Compony.intent(*, **).render(self, **button)
|
|
56
13
|
end
|
|
57
14
|
end
|
|
58
15
|
end
|
data/lib/compony.rb
CHANGED
|
@@ -3,17 +3,25 @@
|
|
|
3
3
|
# the setters, create an initializer `config/initializers/compony.rb` and call
|
|
4
4
|
# them from there.
|
|
5
5
|
# @see Compony::ViewHelpers Compony::ViewHelpers for helpers that require a view context and render results immediately
|
|
6
|
+
# @see Compony::RequestContext Compony::RequestContext for helpers that require a view context and render results immediately
|
|
6
7
|
module Compony
|
|
7
8
|
##########=====-------
|
|
8
9
|
# Configuration writers
|
|
9
10
|
##########=====-------
|
|
10
11
|
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# button component
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@
|
|
12
|
+
# Adds a button style that can be referred to when rendering an intent.
|
|
13
|
+
# @param name [Symbol] Name of the style. If it exists already, will override the style.
|
|
14
|
+
# @param button_component_class [String] String with the class name of the button component that will be instanciated to render the intent.
|
|
15
|
+
def self.register_button_style(name, button_component_class_name)
|
|
16
|
+
@button_component_class_names ||= {}
|
|
17
|
+
@button_component_class_names[name.to_sym] = button_component_class_name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Setter for the default button style. Defaults to :css_button.
|
|
21
|
+
# @param default_button_style [Symbol] Name of the style that should be used as default.
|
|
22
|
+
# @see {Compony#default_button_style}
|
|
23
|
+
def self.default_button_style=(default_button_style)
|
|
24
|
+
@default_button_style = default_button_style
|
|
17
25
|
end
|
|
18
26
|
|
|
19
27
|
# Setter for the global field namespaces. This allows you to implement custom
|
|
@@ -58,12 +66,31 @@ module Compony
|
|
|
58
66
|
# Configuration readers
|
|
59
67
|
##########=====-------
|
|
60
68
|
|
|
61
|
-
# Getter for the
|
|
62
|
-
# @
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
# Getter for the button component class for a given style.
|
|
70
|
+
# @param style [Symbol] Style for which the matching button component class should be returned. Defaults to {Compony.default_button_style}.
|
|
71
|
+
# @see {Compony#register_button_style}
|
|
72
|
+
# @see {Compony#default_button_style}
|
|
73
|
+
def self.button_component_class(style = default_button_style)
|
|
74
|
+
# Lazy initialize
|
|
75
|
+
if @button_component_classes.nil?
|
|
76
|
+
@button_component_classes = {
|
|
77
|
+
css_button: Compony::Components::Buttons::CssButton,
|
|
78
|
+
link: Compony::Components::Buttons::Link
|
|
79
|
+
}.merge(@button_component_class_names&.transform_values(&:constantize) || {})
|
|
80
|
+
@button_component_classes.each_value do |button_component_class|
|
|
81
|
+
unless button_component_class.is_a?(Class) && button_component_class < Compony::Component
|
|
82
|
+
fail("Expected a button component class, got #{button_component_class.inspect}")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
# Retrieval
|
|
87
|
+
return @button_component_classes[style&.to_sym] || fail("Unknown button style #{style.inspect}. Use one of: #{@button_component_classes.keys.inspect}")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Getter for the default button style, defaults to `:css_button`.
|
|
91
|
+
# @see {Compony#default_button_style=}
|
|
92
|
+
def self.default_button_style
|
|
93
|
+
return @default_button_style || :css_button
|
|
67
94
|
end
|
|
68
95
|
|
|
69
96
|
# Getter for the global field namespaces.
|
|
@@ -94,123 +121,38 @@ module Compony
|
|
|
94
121
|
# Application-wide available pure helpers
|
|
95
122
|
##########=====-------
|
|
96
123
|
|
|
124
|
+
# Pure helper to create a Compony Intent. If given an intent, will return it unchanged. Otherwise, will give all params to the intent initializer.
|
|
125
|
+
def self.intent(intent_or_comp_args, ...)
|
|
126
|
+
if intent_or_comp_args.is_a?(Intent)
|
|
127
|
+
return intent_or_comp_args
|
|
128
|
+
else
|
|
129
|
+
return Intent.new(intent_or_comp_args, ...)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
97
133
|
# Generates a Rails path to a component. Examples: `Compony.path(:index, :users)`, `Compony.path(:show, User.first)`
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# or an instance implementing `model_name` from which the family name is auto-generated. Examples:
|
|
102
|
-
# `Users`, `'Users'`, `:users`, `User.first`
|
|
103
|
-
# @param standalone_name [Symbol,nil] Name of the standalone config to point to (defaults to nil the default standalone config).
|
|
104
|
-
# @param args_for_path_helper [Array] Positional arguments passed to the Rails helper
|
|
105
|
-
# @param kwargs_for_path_helper [Hash] Named arguments passed to the Rails helper. If a model is given to `model_or_family_name_or_cst`,
|
|
106
|
-
# the param `id` defaults to the passed model's ID.
|
|
107
|
-
def self.path(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil, *args_for_path_helper, standalone_name: nil, **kwargs_for_path_helper)
|
|
108
|
-
# Extract model if any, to get the ID
|
|
109
|
-
model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil
|
|
110
|
-
comp_class = if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
|
|
111
|
-
comp_name_or_cst_or_class
|
|
112
|
-
else
|
|
113
|
-
comp_class_for!(comp_name_or_cst_or_class, model_or_family_name_or_cst)
|
|
114
|
-
end
|
|
115
|
-
return comp_class.new.path(model, *args_for_path_helper, standalone_name:, **kwargs_for_path_helper)
|
|
134
|
+
# The first two arguments are given to create an {Intent} and all subsequend args and all kwargs are given to {Intent#path}
|
|
135
|
+
def self.path(comp_name_or_cst_or_class, model_or_family_name_or_cst = nil, ...)
|
|
136
|
+
intent(comp_name_or_cst_or_class, model_or_family_name_or_cst).path(...)
|
|
116
137
|
end
|
|
117
138
|
|
|
118
139
|
# Given a component and a family/model, this returns the matching component class if any, or nil if the component does not exist.
|
|
119
|
-
# @
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
family_cst_str = family_name_for(model_or_family_name_or_cst).camelize
|
|
125
|
-
comp_cst_str = comp_name_or_cst.to_s.camelize
|
|
126
|
-
return nil unless ::Components.const_defined?(family_cst_str)
|
|
127
|
-
family_constant = ::Components.const_get(family_cst_str)
|
|
128
|
-
return nil unless family_constant.const_defined?(comp_cst_str)
|
|
129
|
-
return family_constant.const_get(comp_cst_str)
|
|
140
|
+
# @see Intent for allowed parameters.
|
|
141
|
+
def self.comp_class_for(...)
|
|
142
|
+
return intent(...).comp_class
|
|
143
|
+
rescue NameError
|
|
144
|
+
return nil
|
|
130
145
|
end
|
|
131
146
|
|
|
132
147
|
# Same as Compony#comp_class_for but fails if none found
|
|
148
|
+
# @see Intent for allowed parameters.
|
|
133
149
|
# @see Compony#comp_class_for
|
|
134
|
-
def self.comp_class_for!(
|
|
135
|
-
comp_class_for(
|
|
150
|
+
def self.comp_class_for!(...)
|
|
151
|
+
comp_class_for(...) || fail(
|
|
136
152
|
"No component found for [#{comp_name_or_cst.inspect}, #{model_or_family_name_or_cst.inspect}]"
|
|
137
153
|
)
|
|
138
154
|
end
|
|
139
155
|
|
|
140
|
-
# Given a component and a family, this returns the name of the Rails URL helper returning the path to this component.<br>
|
|
141
|
-
# The parameters are the same as for {Compony#rails_action_name}.<br>
|
|
142
|
-
# Example usage: `send("#{path_helper_name(:index, :users)}_url)`
|
|
143
|
-
# @see Compony#path
|
|
144
|
-
# @see Compony#rails_action_name rails_action_name for the accepted params
|
|
145
|
-
def self.path_helper_name(...)
|
|
146
|
-
"#{rails_action_name(...)}_comp"
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Given a component and a family or a component class, this returns the name of the ComponyController action for this component.<br>
|
|
150
|
-
# Optionally can pass a name for extra standalone configs.
|
|
151
|
-
# @param comp_name_or_cst [String,Symbol] Name of the component the action points to.
|
|
152
|
-
# @param model_or_family_name_or_cst [String,Symbol] Name of the family the action points to.
|
|
153
|
-
# @param name [String,Symbol] If referring to an extra standalone entrypoint, specify its name using this param.
|
|
154
|
-
# @see Compony#path
|
|
155
|
-
def self.rails_action_name(comp_name_or_cst_or_class, model_or_family_name_or_cst, name = nil)
|
|
156
|
-
if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
|
|
157
|
-
comp_class = comp_name_or_cst_or_class
|
|
158
|
-
comp_name_or_cst_or_class = comp_class.comp_name
|
|
159
|
-
model_or_family_name_or_cst = comp_class.family_name
|
|
160
|
-
end
|
|
161
|
-
[name.presence, comp_name_or_cst_or_class.to_s.underscore, family_name_for(model_or_family_name_or_cst)].compact.join('_')
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Given a component and a family/model, this instanciates and returns a button component.
|
|
165
|
-
# @param comp_name_or_cst_or_class [String,Symbol,Class] The component that should be loaded, for instance `ShowForAll`, `'ShowForAll'` or `:show_for_all`
|
|
166
|
-
# @param model_or_family_name_or_cst [String,Symbol,ApplicationRecord] Either the family that contains the requested component,
|
|
167
|
-
# or an instance implementing `model_name` from which the family name is auto-generated. Examples:
|
|
168
|
-
# `Users`, `'Users'`, `:users`, `User.first`
|
|
169
|
-
# @param label_opts [Hash] Options hash that will be passed to the label method (see {Compony::ComponentMixins::Default::Labelling#label})
|
|
170
|
-
# @param params [Hash] GET parameters to be inclued into the path this button points to. Special case: e.g. format: :pdf -> some.url/foo/bar.pdf
|
|
171
|
-
# @param feasibility_action [Symbol] Name of the feasibility action that should be checked for this button, defaults to the component name
|
|
172
|
-
# @param feasibility_target [Symbol] Name of the feasibility target (subject) that the feasibility should be checked on, defaults to the model if given
|
|
173
|
-
# @param standalone_name [Symbol,nil] Name of the standalone config to point to (defaults to nil the default standalone config).
|
|
174
|
-
# @param override_kwargs [Hash] Override button options, see options for {Compony::Components::Button}
|
|
175
|
-
# @see Compony::ViewHelpers#compony_button View helper providing a wrapper for this method that immediately renders a button.
|
|
176
|
-
# @see Compony::Components::Button Compony::Components::Button: the default underlying implementation
|
|
177
|
-
def self.button(comp_name_or_cst_or_class,
|
|
178
|
-
model_or_family_name_or_cst = nil,
|
|
179
|
-
label_opts: nil,
|
|
180
|
-
params: nil,
|
|
181
|
-
feasibility_action: nil,
|
|
182
|
-
feasibility_target: nil,
|
|
183
|
-
method: nil,
|
|
184
|
-
standalone_name: nil,
|
|
185
|
-
**override_kwargs)
|
|
186
|
-
label_opts ||= button_defaults[:label_opts] || {}
|
|
187
|
-
params ||= button_defaults[:params] || {}
|
|
188
|
-
model = model_or_family_name_or_cst.respond_to?(:model_name) ? model_or_family_name_or_cst : nil
|
|
189
|
-
if comp_name_or_cst_or_class.is_a?(Class) && (comp_name_or_cst_or_class <= Compony::Component)
|
|
190
|
-
target_comp_instance = comp_name_or_cst_or_class.new(data: model)
|
|
191
|
-
else
|
|
192
|
-
target_comp_instance = Compony.comp_class_for!(comp_name_or_cst_or_class, model_or_family_name_or_cst).new(data: model)
|
|
193
|
-
end
|
|
194
|
-
feasibility_action ||= button_defaults[:feasibility_action] || comp_name_or_cst_or_class.to_s.underscore.to_sym
|
|
195
|
-
feasibility_target ||= button_defaults[:feasibility_target] || model
|
|
196
|
-
options = {
|
|
197
|
-
label: target_comp_instance.label(model, **label_opts),
|
|
198
|
-
icon: target_comp_instance.icon,
|
|
199
|
-
color: target_comp_instance.color,
|
|
200
|
-
path: Compony.path(target_comp_instance.comp_name, target_comp_instance.family_name, model, standalone_name:, **params),
|
|
201
|
-
method:,
|
|
202
|
-
visible: ->(controller) { target_comp_instance.standalone_access_permitted_for?(controller, standalone_name:, verb: method) }
|
|
203
|
-
}
|
|
204
|
-
if feasibility_target
|
|
205
|
-
options.merge!({
|
|
206
|
-
enabled: feasibility_target.feasible?(feasibility_action),
|
|
207
|
-
title: feasibility_target.full_feasibility_messages(feasibility_action).presence
|
|
208
|
-
})
|
|
209
|
-
end
|
|
210
|
-
options.merge!(override_kwargs.symbolize_keys)
|
|
211
|
-
return Compony.button_component_class.new(**options.symbolize_keys)
|
|
212
|
-
end
|
|
213
|
-
|
|
214
156
|
# Returns the current root component, if any
|
|
215
157
|
def self.root_comp
|
|
216
158
|
RequestStore.store[:compony_root_comp]
|
|
@@ -228,37 +170,6 @@ module Compony
|
|
|
228
170
|
end
|
|
229
171
|
end
|
|
230
172
|
|
|
231
|
-
# Getter for current button defaults
|
|
232
|
-
# @todo document params
|
|
233
|
-
def self.button_defaults
|
|
234
|
-
RequestStore.store[:button_defaults] || {}
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
# Overwrites the keys of the current button defaults by the ones provided during the execution of a given block and restores them afterwords.
|
|
238
|
-
# This method is useful when the same set of options is to be given to a multitude of buttons.
|
|
239
|
-
# @param keys_to_overwrite [Hash] Options that should be given to the buttons within the block, with their values
|
|
240
|
-
# @param block [Block] Within this block, all omitted button options point to `keys_to_overwrite`
|
|
241
|
-
def self.with_button_defaults(**keys_to_overwrite, &block)
|
|
242
|
-
# Lazy initialize butto_defaults store if it hasn't been yet
|
|
243
|
-
RequestStore.store[:button_defaults] ||= {}
|
|
244
|
-
keys_to_overwrite.transform_keys!(&:to_sym)
|
|
245
|
-
old_values = {}
|
|
246
|
-
newly_defined_keys = keys_to_overwrite.keys - RequestStore.store[:button_defaults].keys
|
|
247
|
-
keys_to_overwrite.each do |key, new_value|
|
|
248
|
-
# Assign new value
|
|
249
|
-
old_values[key] = RequestStore.store[:button_defaults][key]
|
|
250
|
-
RequestStore.store[:button_defaults][key] = new_value
|
|
251
|
-
end
|
|
252
|
-
return_value = block.call
|
|
253
|
-
# Restore previous value
|
|
254
|
-
keys_to_overwrite.each_key do |key|
|
|
255
|
-
RequestStore.store[:button_defaults][key] = old_values[key]
|
|
256
|
-
end
|
|
257
|
-
# Undefine keys that were not there previously
|
|
258
|
-
newly_defined_keys.each { |key| RequestStore.store[:button_defaults].delete(key) }
|
|
259
|
-
return return_value
|
|
260
|
-
end
|
|
261
|
-
|
|
262
173
|
# Goes through model_field_namespaces and returns the first hit for the given constant
|
|
263
174
|
# @param constant [Constant] The constant that is searched, e.g. RichText -> would return e.g. Compony::ModelFields::RichText
|
|
264
175
|
def self.model_field_class_for(constant)
|
|
@@ -279,6 +190,7 @@ require 'request_store'
|
|
|
279
190
|
require 'schemacop'
|
|
280
191
|
require 'simple_form'
|
|
281
192
|
|
|
193
|
+
require 'compony/intent'
|
|
282
194
|
require 'compony/engine'
|
|
283
195
|
require 'compony/model_fields/base'
|
|
284
196
|
require 'compony/model_fields/anchormodel'
|
|
@@ -306,8 +218,10 @@ require 'compony/component_mixins/default/standalone/verb_dsl'
|
|
|
306
218
|
require 'compony/component_mixins/default/standalone/resourceful_verb_dsl'
|
|
307
219
|
require 'compony/component_mixins/default/labelling'
|
|
308
220
|
require 'compony/component_mixins/resourceful'
|
|
221
|
+
require 'compony/exposed_intents_dsl'
|
|
309
222
|
require 'compony/component'
|
|
310
|
-
require 'compony/components/
|
|
223
|
+
require 'compony/components/buttons/link'
|
|
224
|
+
require 'compony/components/buttons/css_button'
|
|
311
225
|
require 'compony/components/index'
|
|
312
226
|
require 'compony/components/list'
|
|
313
227
|
require 'compony/components/show'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: compony
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sandro Kalbermatter
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2025-11-
|
|
12
|
+
date: 2025-11-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: yard
|
|
@@ -203,6 +203,9 @@ files:
|
|
|
203
203
|
- doc/Compony/ComponentMixins/Resourceful.html
|
|
204
204
|
- doc/Compony/Components.html
|
|
205
205
|
- doc/Compony/Components/Button.html
|
|
206
|
+
- doc/Compony/Components/Buttons.html
|
|
207
|
+
- doc/Compony/Components/Buttons/CssButton.html
|
|
208
|
+
- doc/Compony/Components/Buttons/Link.html
|
|
206
209
|
- doc/Compony/Components/Destroy.html
|
|
207
210
|
- doc/Compony/Components/Edit.html
|
|
208
211
|
- doc/Compony/Components/Form.html
|
|
@@ -213,6 +216,8 @@ files:
|
|
|
213
216
|
- doc/Compony/Components/WithForm.html
|
|
214
217
|
- doc/Compony/ControllerMixin.html
|
|
215
218
|
- doc/Compony/Engine.html
|
|
219
|
+
- doc/Compony/ExposedIntentsDsl.html
|
|
220
|
+
- doc/Compony/Intent.html
|
|
216
221
|
- doc/Compony/MethodAccessibleHash.html
|
|
217
222
|
- doc/Compony/ModelFields.html
|
|
218
223
|
- doc/Compony/ModelFields/Anchormodel.html
|
|
@@ -254,15 +259,14 @@ files:
|
|
|
254
259
|
- doc/guide/example.md
|
|
255
260
|
- doc/guide/feasibility.md
|
|
256
261
|
- doc/guide/generators.md
|
|
257
|
-
- doc/guide/helpers.md
|
|
258
262
|
- doc/guide/inheritance.md
|
|
259
263
|
- doc/guide/installation.md
|
|
264
|
+
- doc/guide/intents.md
|
|
260
265
|
- doc/guide/internal_datastructures.md
|
|
261
266
|
- doc/guide/model_fields.md
|
|
262
267
|
- doc/guide/nesting.md
|
|
263
268
|
- doc/guide/ownership.md
|
|
264
269
|
- doc/guide/pre_built_components.md
|
|
265
|
-
- doc/guide/pre_built_components/button.md
|
|
266
270
|
- doc/guide/pre_built_components/destroy.md
|
|
267
271
|
- doc/guide/pre_built_components/edit.md
|
|
268
272
|
- doc/guide/pre_built_components/form.md
|
|
@@ -272,7 +276,6 @@ files:
|
|
|
272
276
|
- doc/guide/pre_built_components/show.md
|
|
273
277
|
- doc/guide/pre_built_components/with_form.md
|
|
274
278
|
- doc/guide/resourceful.md
|
|
275
|
-
- doc/guide/root_actions.md
|
|
276
279
|
- doc/guide/standalone.md
|
|
277
280
|
- doc/guide/virtual_models.md
|
|
278
281
|
- doc/imgs/intro-example-destroy.png
|
|
@@ -297,7 +300,8 @@ files:
|
|
|
297
300
|
- lib/compony/component_mixins/default/standalone/standalone_dsl.rb
|
|
298
301
|
- lib/compony/component_mixins/default/standalone/verb_dsl.rb
|
|
299
302
|
- lib/compony/component_mixins/resourceful.rb
|
|
300
|
-
- lib/compony/components/
|
|
303
|
+
- lib/compony/components/buttons/css_button.rb
|
|
304
|
+
- lib/compony/components/buttons/link.rb
|
|
301
305
|
- lib/compony/components/destroy.rb
|
|
302
306
|
- lib/compony/components/edit.rb
|
|
303
307
|
- lib/compony/components/form.rb
|
|
@@ -308,6 +312,8 @@ files:
|
|
|
308
312
|
- lib/compony/components/with_form.rb
|
|
309
313
|
- lib/compony/controller_mixin.rb
|
|
310
314
|
- lib/compony/engine.rb
|
|
315
|
+
- lib/compony/exposed_intents_dsl.rb
|
|
316
|
+
- lib/compony/intent.rb
|
|
311
317
|
- lib/compony/method_accessible_hash.rb
|
|
312
318
|
- lib/compony/model_fields/anchormodel.rb
|
|
313
319
|
- lib/compony/model_fields/association.rb
|
data/doc/guide/helpers.md
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
[Back to the guide](/README.md#guide)
|
|
2
|
-
|
|
3
|
-
# Compony helpers, links and buttons
|
|
4
|
-
|
|
5
|
-
When pointing to or instantiating a component, writing the whole class name would be cumbersome. For this reason, Compony has several helpers that will retrieve the correct class for you. The most important ones are explained in this subsection. The terms are defined as follows:
|
|
6
|
-
|
|
7
|
-
- Component name or constant: For a component `Components::Users::Show`, this would be `'Show'`, `'show'`, or `:show`
|
|
8
|
-
- Family name or constant: For a component `Components::Users::Show`, this would be `'Users'`, `'users'`, or `:users`
|
|
9
|
-
- Model: an instance of a class that implements the `model_name` method in the same way as `ActiveRecord::Base` does. For helpers that support giving models, Compony will use `model_name` to auto-infer the family name. This requires you to name the component according to convention, i.e. the family name must match the model's pluralized camelized `model_name`.
|
|
10
|
-
|
|
11
|
-
## Getting the class of a component
|
|
12
|
-
|
|
13
|
-
- `Compony.comp_class_for(comp_name_or_cst, model_or_family_name_or_cst)` returns the class or nil if not found.
|
|
14
|
-
- `Compony.comp_class_for!(comp_name_or_cst, model_or_family_name_or_cst)` returns the class. If the class is not found, an error will be raised.
|
|
15
|
-
|
|
16
|
-
Example:
|
|
17
|
-
|
|
18
|
-
```ruby
|
|
19
|
-
my_component = Compony.comp_class_for!(:show, User.first).new
|
|
20
|
-
my_component.class # Components::Users::Show
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Getting a path to a component
|
|
24
|
-
|
|
25
|
-
- `Compony.path(comp_name_or_cst, model_or_family_name_or_cst)` returns the route to a component. Additional positional and keyword arguments will be passed to the Rails helper.
|
|
26
|
-
|
|
27
|
-
If a model is given, its ID will automatically be added as the `id` parameter when generating the route. This means:
|
|
28
|
-
|
|
29
|
-
- To generate a path to a non-resourceful component, pass the family name.
|
|
30
|
-
- To generate a path to a resourceful component, prefer passing an instance instead of a family name.
|
|
31
|
-
|
|
32
|
-
Examples:
|
|
33
|
-
|
|
34
|
-
```ruby
|
|
35
|
-
link_to 'User overview', Compony.path(:index, :users) # -> 'users/index'
|
|
36
|
-
link_to 'See user page', Compony.path(:show, User.first) # -> 'users/show/1'
|
|
37
|
-
link_to 'See user page', Compony.path(:show, :users, id: 1) # -> 'users/show/1'
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Note that the generated paths in the example are just for illustration purposes. The paths point to whatever path you configure in the target component's default standalone config. Also, this example is not how you should generate links to components, as is explained in the next subsection.
|
|
41
|
-
|
|
42
|
-
### Customizing path generation
|
|
43
|
-
|
|
44
|
-
By implementing `path do ... end` inside the `setup` method of a component, you can override the way paths to that component are generated. Customizing the path generation will affect all mentioned methods mentioned here involving paths, such as `Compony.path`, `compony_link`, `Compony.button`, `compony_button` etc.
|
|
45
|
-
|
|
46
|
-
This is an advanced usage. Refer to the default implementation of `Component`'s `path_block` to see an exmple.
|
|
47
|
-
|
|
48
|
-
## Generating a link to a component
|
|
49
|
-
|
|
50
|
-
In order to allow a user to visit another component, don't implement your links and buttons manually. Instead, use Compony's links and buttons, as those extract information from the target component, avoiding redundant code and making refactoring much easier.
|
|
51
|
-
|
|
52
|
-
Compony comes with the view helper `compony_link` that is available in any of your views, including a component's `content` blocks. The link's label is inferred from the component the link points to. `compony_link` is used as follows:
|
|
53
|
-
|
|
54
|
-
- To generate a link to a non-resourceful component, pass the family name.
|
|
55
|
-
- To generate a link to a resourceful component, prefer passing an instance instead of a family name. More precisely, you must pass an instance if the component's label requires an argument.
|
|
56
|
-
|
|
57
|
-
Any additional arguments passed to `compony_link` will be given to Rails' `link_to` method, allowing you to set parameters, HTTP method, terget, rel etc.
|
|
58
|
-
|
|
59
|
-
Examples:
|
|
60
|
-
|
|
61
|
-
```ruby
|
|
62
|
-
compony_link(:index, :users) # "View all users" -> 'users/index'
|
|
63
|
-
compony_link(Components::Users::Index) # same as above
|
|
64
|
-
compony_link(:index, :users, label_opts: { format: :short }) # "All" -> 'users/index'
|
|
65
|
-
compony_link(:show, User.first) # "View John Doe" -> 'users/show/1'
|
|
66
|
-
compony_link(:destroy, User.first, method: :delete) # "Delete John Doe" -> 'users/destroy/1'
|
|
67
|
-
|
|
68
|
-
# NOT working:
|
|
69
|
-
compony_link(:show, :users, id: 1) # Error: The label for the Users::Show component takes an argument which was not provided (the user's label)
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Generating a button to a component
|
|
73
|
-
|
|
74
|
-
Compony buttons are components that render a button to another component. While the view helper `compony_button` works similar to `compony_link`, you can also manually instantiate a button and work with it like with any other component.
|
|
75
|
-
|
|
76
|
-
Similar to links, Compony buttons take a component name and either a family or model. The label, path, method and title (i.e. tooltip) can be overwritten by passing the respective arguments as shown below.
|
|
77
|
-
|
|
78
|
-
Compony buttons have a type that is either `:button` or `:submit`. While the first works like a link redirecting the user elsewhere, the second is used for submitting forms. It can be used inside a `form_for` or `simple_form_for`.
|
|
79
|
-
|
|
80
|
-
A compony button figures out on it's own whether it's clickable or not:
|
|
81
|
-
|
|
82
|
-
- Buttons can be disabled explicitly by passing `enabled: false` as a parameter.
|
|
83
|
-
- If a user is not authorized to access the component a button is pointing to, the button is not displayed.
|
|
84
|
-
- If the target component should not be accessible due to a prevention in the [feasibility framework](./feasibility.md), the button is disabled and a tooltip is shown explaining why the button is not clickable.
|
|
85
|
-
|
|
86
|
-
Do not directly instantiate `Compony::Components::Button`. Instead, use `Compony.button`:
|
|
87
|
-
|
|
88
|
-
```ruby
|
|
89
|
-
my_button = Compony.button(:index, :users) # "View all users" -> 'users/index'
|
|
90
|
-
my_button = Compony.button(:index, :users, label_opts: { format: :short }) # "All" -> 'users/index'
|
|
91
|
-
my_button = Compony.button(:index, :users, label: 'Back') # "Back" -> 'users/index'
|
|
92
|
-
my_button = Compony.button(:show, User.first) # "View John Doe" -> 'users/show/1'
|
|
93
|
-
my_button = Compony.button(:new, :users, label: 'New customer', params: { user: { type: 'customer' } }) # "New customer" -> 'users/new?user[type]=customer'
|
|
94
|
-
my_button = Compony.button(:new, :users, label: 'New customer', params: { user: { type: 'customer' } }, method: :post) # Instantly creates user.
|
|
95
|
-
my_button = Compony.button(label: 'I point to a plain Rails route', path: 'some/path') # Specifying a custom path
|
|
96
|
-
my_button = Compony.button(label: 'Nothing happens if you click me') # javascript:void()
|
|
97
|
-
my_button = Compony.button(label: 'Not implemented yet', enabled: false) # Disabled button
|
|
98
|
-
|
|
99
|
-
# `enabled` and `path` can also be provided with a callable (block or lambda) to defer evaluation until when the button is rendered.
|
|
100
|
-
# The lambdas will be called in the button's `before_render` and given the controller, allowing you to query request specific data.
|
|
101
|
-
my_button = Compony.button(label: 'I point to a plain Rails route', path: ->{ |controller| controller.helpers.some_rails_path })
|
|
102
|
-
my_button = Compony.button(:index, :users, enabled: -> { |controller| controller.current_ability.can?(:read, :index_pages) })
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
A Compony button can be rendered like any other component:
|
|
106
|
-
|
|
107
|
-
```erb
|
|
108
|
-
<%= my_button.render(controller) %>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
However, it is much easier to just use the appropriate view helper instead, which takes the same arguments as `Compony.button`:
|
|
112
|
-
|
|
113
|
-
```ruby
|
|
114
|
-
compony_button(:index, :users)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
If you need to render many buttons that share a parameter, the call `Compony.with_button_defaults` allows you to DRY up your code:
|
|
118
|
-
|
|
119
|
-
```ruby
|
|
120
|
-
# Assuming this is inside a Dyny view context and each button should be inside a div.
|
|
121
|
-
# Without with_button_defaults:
|
|
122
|
-
div compony_button(:new, :documents, label_opts: { format: :short }, method: :post)
|
|
123
|
-
div compony_button(:new, :letters, label_opts: { format: :short }, method: :post)
|
|
124
|
-
div compony_button(:new, :articles, label_opts: { format: :short }, method: :post)
|
|
125
|
-
|
|
126
|
-
# Equivalent using with_button_defaults:
|
|
127
|
-
Compony.with_button_defaults(label_opts: { format: :short }, method: :post) do
|
|
128
|
-
div compony_button(:new, :documents)
|
|
129
|
-
div compony_button(:new, :letters)
|
|
130
|
-
div compony_button(:new, :articles)
|
|
131
|
-
end
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Implementing custom buttons
|
|
135
|
-
|
|
136
|
-
Plain HTML buttons are not exactly eye candy, so you will likely want to implement your button kind with black jack and icons. For this reason, the button instantiated by Compony's button helpers can be customized.
|
|
137
|
-
|
|
138
|
-
To build your own button class, inherit as follows:
|
|
139
|
-
|
|
140
|
-
```ruby
|
|
141
|
-
class MyButton < Compony::Components::Button
|
|
142
|
-
def initialize(*args, **kwargs, &block) # Add extra arguments here
|
|
143
|
-
super(*args, **kwargs, &block)
|
|
144
|
-
# Add extra initialization code here
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# Add/replace before_render/content here. Be careful to not overwrite code you depend on. Check Compony's button's code for details.
|
|
148
|
-
end
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
Then, in the Compony initializer, register your custom button class to have Compony instantiate it whenever `Compony.button` or another helper is called:
|
|
152
|
-
|
|
153
|
-
```ruby
|
|
154
|
-
# config/initializers/compony.rb
|
|
155
|
-
Compony.button_component_class = 'MyButton'
|
|
156
|
-
```
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
- [Back to the guide](/README.md#guide)
|
|
2
|
-
- [List of pre-built components](/doc/guide/pre_built_components.md)
|
|
3
|
-
|
|
4
|
-
# Pre-built components: Button
|
|
5
|
-
|
|
6
|
-
As stated earlier, buttons are just regular components that rendered in-place. They don't make use of nesting logic (and presumably never will), and thus they are rendered as-is, without `sub_comp`.
|
|
7
|
-
|
|
8
|
-
You will rarely (or probably never) instantiate a button on your own, but use helpers like `Compony.button` or `compony_button`. For this reason, the documentation for instantiating buttons is located in the [section documenting helpers](/doc/guide/helpers.md).
|
data/doc/guide/root_actions.md
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
[Back to the guide](/README.md#guide)
|
|
2
|
-
|
|
3
|
-
# Compony root actions
|
|
4
|
-
|
|
5
|
-
The word "actions" is heavily overused, so here is a disambiguation:
|
|
6
|
-
|
|
7
|
-
- Rails controller actions: a method that is implemented in a Rails controller
|
|
8
|
-
- CanCanCan actions: the first method to CanCanCan's `can?` method
|
|
9
|
-
- Compony root actions: buttons that point to other components
|
|
10
|
-
|
|
11
|
-
At this point, Compony actions are a loose concept, which will likely be refined in the future. Currently, Compony actions are defined as buttons, rendered by the application layout, that point to other components. They provide context-sensitive buttons to your application.
|
|
12
|
-
|
|
13
|
-
## Defining and manipulating root actions
|
|
14
|
-
|
|
15
|
-
In addition to regular buttons that are rendered as part of the content blocks, components can expose root actions with the `actions` call. Root actions will only be rendered if the component they are defined in is currently the root component.
|
|
16
|
-
|
|
17
|
-
To have a component expose a root action, call the method `action` in a `setup` block and return a Compony button:
|
|
18
|
-
|
|
19
|
-
```ruby
|
|
20
|
-
setup do
|
|
21
|
-
action :edit do
|
|
22
|
-
Compony.button(:edit, @data)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
action :destroy do
|
|
26
|
-
Compony.button(:destroy, @data)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The name of the action ("edit" and "destroy" in the example above) allows you to refer to that action in a component inheriting from this one:
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
# Assuming that this component inherits from the example above
|
|
35
|
-
setup do
|
|
36
|
-
skip_action :destroy
|
|
37
|
-
|
|
38
|
-
action :overview, before: :edit do
|
|
39
|
-
Compony.button(:index, :users, label: 'Overview')
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
In this example, two actions will be shown: overview and edit.
|
|
45
|
-
|
|
46
|
-
An action button can be disabled through the [feasibility framework](./feasibility.md). However, it can also instead be hidden completely by returning nil from within the action block:
|
|
47
|
-
|
|
48
|
-
```ruby
|
|
49
|
-
action :edit do
|
|
50
|
-
next if @data.locked?
|
|
51
|
-
Compony.button(:edit, @data)
|
|
52
|
-
end
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
The action in this example will be skipped entirely if `locked?` returns true.
|
|
56
|
-
|
|
57
|
-
## Displaying root actions
|
|
58
|
-
|
|
59
|
-
Root actions are not shown by default in Compony because layouting is up to you. In order to display the root component's actions, add the following view helper call to your layout:
|
|
60
|
-
|
|
61
|
-
```erb
|
|
62
|
-
<%# layouts/application.html.erb %>
|
|
63
|
-
...
|
|
64
|
-
<%= compony_actions %>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
If there is currently no root component, or if the root component defines no actions, this does nothing. However, if there are root actions available, the Compony buttons returned by the root component will be rendered.
|