diff --git a/app/models/mixins/custom_actions_mixin.rb b/app/models/mixins/custom_actions_mixin.rb index 21b66279fd1..c7f7bdf17ba 100644 --- a/app/models/mixins/custom_actions_mixin.rb +++ b/app/models/mixins/custom_actions_mixin.rb @@ -8,19 +8,19 @@ module CustomActionsMixin virtual_has_one :custom_action_buttons, :class_name => "Array" end - def custom_actions + def custom_actions(applies_to = self) { - :buttons => filter_by_visibility(custom_buttons).collect(&method(:serialize_button)), + :buttons => serialize_buttons_if_visible(custom_buttons, applies_to), :button_groups => custom_button_sets_with_generics.collect do |button_set| button_set.serializable_hash.merge( - :buttons => filter_by_visibility(button_set.children).collect(&method(:serialize_button)) + :buttons => serialize_buttons_if_visible(button_set.children, applies_to) ) end } end - def custom_action_buttons - filter_by_visibility(custom_buttons + custom_button_sets_with_generics.collect(&:children).flatten) + def custom_action_buttons(applies_to = self) + filter_by_visibility(custom_buttons + custom_button_sets_with_generics.collect(&:children).flatten, applies_to) end def generic_button_group @@ -39,15 +39,26 @@ def direct_custom_buttons CustomButton.buttons_for(self).select { |b| b.parent.nil? } end - def filter_by_visibility(buttons) - buttons.select { |b| b.evaluate_visibility_expression_for(self) } + def filter_by_visibility(buttons, applies_to = self) + buttons.select { |b| b.evaluate_visibility_expression_for(target_for_expression(b, applies_to)) } end - def serialize_button(button) - button.expanded_serializable_hash.merge("enabled" => button.evaluate_enablement_expression_for(self)) + def serialize_button(button, applies_to = self) + obj = target_for_expression(button, applies_to) + button.expanded_serializable_hash.merge("enabled" => button.evaluate_enablement_expression_for(obj)) end def generic_custom_buttons CustomButton.buttons_for(self.class.base_model.name) end + + private + + def serialize_buttons_if_visible(buttons, applies_to) + filter_by_visibility(buttons, applies_to).collect { |button| serialize_button(button, applies_to) } + end + + def target_for_expression(button, applies_to) + button.applies_to_class == applies_to.class.base_model.name ? applies_to : self + end end diff --git a/app/models/service.rb b/app/models/service.rb index a3559c9f8b7..63de8af284c 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -54,7 +54,6 @@ class Service < ApplicationRecord before_validation :set_tenant_from_group before_create :apply_dialog_settings - delegate :custom_actions, :custom_action_buttons, :to => :service_template, :allow_nil => true delegate :provision_dialog, :to => :miq_request, :allow_nil => true delegate :user, :to => :miq_request, :allow_nil => true @@ -99,6 +98,14 @@ def power_states vms.map(&:power_state) end + def custom_actions + service_template&.custom_actions(self) + end + + def custom_action_buttons + service_template&.custom_action_buttons(self) + end + def power_state if options[:power_status] == "starting" return 'on' if power_states_match?(:start) diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index f92d0b0e8b4..06d2cf6b0e6 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -808,4 +808,23 @@ def create_deep_tree @service_c121 = FactoryGirl.create(:service, :service => @service_c12) @service_c2 = FactoryGirl.create(:service, :service => @service) end + + context "custom actions" do + let(:service_template) { FactoryGirl.create(:service_template) } + let(:service) { FactoryGirl.create(:service, :service_template => service_template) } + + describe "#custom_actions" do + it "get list of custom actions from linked service template" do + expect(service_template).to receive(:custom_actions) + service.custom_actions + end + end + + describe "#custom_action_buttons" do + it "get list of custom action buttons from linked service template" do + expect(service_template).to receive(:custom_action_buttons) + service.custom_action_buttons + end + end + end end diff --git a/spec/models/service_template_spec.rb b/spec/models/service_template_spec.rb index 542d2fadca2..4d410c6c9ba 100644 --- a/spec/models/service_template_spec.rb +++ b/spec/models/service_template_spec.rb @@ -82,6 +82,65 @@ expect(service_template.custom_actions).to match(expected) end + context "expression evaluation" do + let(:service_template) { FactoryGirl.create(:service_template, :prov_type=> "vmware") } + let(:service) { FactoryGirl.create(:service, :name => "foo", :service_template => service_template) } + let(:true_expression_on_template) do + MiqExpression.new("=" => {"field" => "ServiceTemplate-prov_type", "value" => "vmware"}) + end + let(:false_expression_on_template) do + MiqExpression.new("=" => {"field" => "ServiceTemplate-prov_type", "value" => "not_vmware"}) + end + let(:true_expression_on_service) do + MiqExpression.new("=" => {"field" => "Service-name", "value" => "foo"}) + end + let(:false_expression_on_service) do + MiqExpression.new("=" => {"field" => "Service-name", "value" => "not_foo"}) + end + + before do + FactoryGirl.create(:custom_button, + :name => "visible button on service", + :applies_to_class => "Service", + :visibility_expression => true_expression_on_service) + FactoryGirl.create(:custom_button, + :name => "hidden button on service", + :applies_to_class => "Service", + :visibility_expression => false_expression_on_service) + FactoryGirl.create(:custom_button, + :name => "visible button on template", + :applies_to_class => "ServiceTemplate", + :applies_to_id => service_template.id, + :visibility_expression => true_expression_on_template) + FactoryGirl.create(:custom_button, + :name => "hidden visible button on template", + :applies_to_class => "ServiceTemplate", + :applies_to_id => service_template.id, + :visibility_expression => false_expression_on_template) + end + + it "uses ServiceTemplate object to evaluate expression defined on Service Template if no parameter passed" do + expected = { + :buttons => [ + a_hash_including("name" => "visible button on template") + ], + :button_groups => [] + } + expect(service_template.custom_actions).to match(expected) + end + + it "uses passed object for expression defined on that object and ServiceTemplate for expression on template" do + expected = { + :buttons => a_collection_containing_exactly( + a_hash_including("name" => "visible button on service"), + a_hash_including("name" => "visible button on template") + ), + :button_groups => [] + } + expect(service_template.custom_actions(service)).to match(expected) + end + end + it "serializes the enablement" do service_template = FactoryGirl.create(:service_template, :name => "foo") true_expression = MiqExpression.new("=" => {"field" => "ServiceTemplate-name", "value" => "foo"})