From 2472424a246ce23388d6b13485f9feb24a0ff883 Mon Sep 17 00:00:00 2001 From: Gasper Vrhovsek Date: Wed, 4 Apr 2018 16:10:44 +0200 Subject: [PATCH] Introduce support for multi-tab orchestration dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now it was hard-coded that orchestration service dialog uses a single tab only, named "Basic Information". For some providers, however, this is not too convinient because there are many fields in dialog that can be grouped into multiple tabs. With this commit we allow provider to decide how many tabs to use and what content to put in each tab. New feature is optional and fully backwards compatible. Usage: should provider decide to define custom tabs, it can now override function `tabs` that returns a list of tab specifications. Signed-off-by: Gašper Vrhovšek Signed-off-by: Miha Pleško --- .../orchestration_template_service_dialog.rb | 10 +- app/models/orchestration_template.rb | 10 + ...hestration_template_service_dialog_spec.rb | 181 +++++++++++++++++- spec/models/orchestration_template_spec.rb | 16 ++ 4 files changed, 203 insertions(+), 14 deletions(-) diff --git a/app/models/dialog/orchestration_template_service_dialog.rb b/app/models/dialog/orchestration_template_service_dialog.rb index 281340b40c0..c9c5be3e2c9 100644 --- a/app/models/dialog/orchestration_template_service_dialog.rb +++ b/app/models/dialog/orchestration_template_service_dialog.rb @@ -6,11 +6,11 @@ def self.create_dialog(name, template) def create_dialog(name, template) Dialog.new(:name => name, :buttons => "submit,cancel").tap do |dialog| - tab = dialog.dialog_tabs.build(:display => "edit", :label => "Basic Information", :position => 0) - add_stack_group(template.deployment_options, tab, 0) - - template.parameter_groups.each_with_index do |parameter_group, index| - add_parameter_group(parameter_group, tab, index + 1) + template.tabs.each_with_index do |data, idx| + tab = dialog.dialog_tabs.build(:display => "edit", :label => data[:title], :position => idx) + offset = data[:stack_group] ? 1 : 0 + add_stack_group(data[:stack_group], tab, 0) if data[:stack_group] + Array(data[:param_groups]).each_with_index { |group, i| add_parameter_group(group, tab, i + offset) } end dialog.save! end diff --git a/app/models/orchestration_template.rb b/app/models/orchestration_template.rb index a376536d2d2..48c58874574 100644 --- a/app/models/orchestration_template.rb +++ b/app/models/orchestration_template.rb @@ -86,6 +86,16 @@ def self.not_in_use includes(:stacks).where(:orchestration_stacks => {:orchestration_template_id => nil}) end + def tabs + [ + { + :title => "Basic Information", + :stack_group => deployment_options, + :param_groups => parameter_groups + } + ] + end + def parameter_groups raise NotImplementedError, _("parameter_groups must be implemented in subclass") end diff --git a/spec/models/dialog/orchestration_template_service_dialog_spec.rb b/spec/models/dialog/orchestration_template_service_dialog_spec.rb index dd81637c4cc..4ab5aeef958 100644 --- a/spec/models/dialog/orchestration_template_service_dialog_spec.rb +++ b/spec/models/dialog/orchestration_template_service_dialog_spec.rb @@ -2,10 +2,12 @@ let(:orchestration_template) do FactoryGirl.create(:orchestration_template).tap do |template| allow(template).to receive(:parameter_groups).and_return(param_groups) + allow(template).to receive(:tabs).and_return(tabs) if tabs.count > 0 end end let(:param_groups) { create_parameters(param_options) } - let(:dialog) { described_class.create_dialog("test", orchestration_template) } + let(:dialog) { described_class.create_dialog("test", orchestration_template) } + let(:tabs) { [] } describe ".create_dialog" do let(:param_groups) { [] } @@ -17,7 +19,160 @@ ) tabs = dialog.dialog_tabs - assert_tab_attributes(tabs[0]) + assert_tab_attributes(tabs[0], :label => "Basic Information", :display => "edit") + end + + context "with custom tabs" do + let(:dialog_tabs) { dialog.dialog_tabs } + let(:first_tab) { dialog_tabs.first } + let(:first_group) { first_tab.dialog_groups.first } + let(:second_tab) { dialog_tabs.second } + + describe 'tab with stack group' do + let(:tabs) do + [ + { + :title => 'Tab 1', + :stack_group => [ + template_param(:label => 'Param 1'), + template_param(:label => 'Param 2') + ] + } + ] + end + + it do + expect(dialog_tabs.size).to eq(1) + assert_tab_attributes(first_tab, :label => 'Tab 1', :display => 'edit') + assert_group(first_group, 'Options', ['Param 1', 'Param 2']) + end + end + + describe 'tab with param group' do + let(:tabs) do + [ + { + :title => 'Tab 1', + :param_groups => [ + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 1', + :parameters => [ + template_param(:label => 'Param 1'), + template_param(:label => 'Param 2') + ], + ) + ] + }, + ] + end + + it do + expect(dialog_tabs.size).to eq(1) + assert_tab_attributes(first_tab, :label => 'Tab 1', :display => 'edit') + assert_group(first_group, 'Parameter Group 1', ['Param 1', 'Param 2']) + end + end + + describe 'tab with two param groups' do + let(:tabs) do + [ + { + :title => 'Tab 1', + :param_groups => [ + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 1', + :parameters => [ + template_param(:label => 'Param 1'), + template_param(:label => 'Param 2') + ], + ), + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 2', + :parameters => [ + template_param(:label => 'Param 3'), + template_param(:label => 'Param 4') + ], + ) + ] + }, + ] + end + + it do + expect(dialog_tabs.size).to eq(1) + assert_group(first_group, 'Parameter Group 1', ['Param 1', 'Param 2']) + assert_group(first_tab.dialog_groups[1], 'Parameter Group 2', ['Param 3', 'Param 4']) + end + end + + describe 'tab with stack group and param group' do + let(:tabs) do + [ + { + :title => 'Tab 1', + :stack_group => [ + template_param(:label => 'Param 1'), + template_param(:label => 'Param 2') + ], + :param_groups => [ + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 1', + :parameters => [ + template_param(:label => 'Param 3'), + template_param(:label => 'Param 4') + ], + ) + ] + }, + ] + end + + it do + expect(dialog_tabs.size).to eq(1) + assert_tab_attributes(first_tab, :label => 'Tab 1', :display => 'edit') + assert_group(first_group, 'Options', ['Param 1', 'Param 2']) + assert_group(first_tab.dialog_groups[1], 'Parameter Group 1', ['Param 3', 'Param 4']) + end + end + + describe 'two tabs' do + let(:tabs) do + [ + { + :title => 'Tab 1', + :param_groups => [ + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 1', + :parameters => [ + template_param(:label => 'Param 1'), + template_param(:label => 'Param 2') + ], + ) + ] + }, + { + :title => 'Tab 2', + :param_groups => [ + OrchestrationTemplate::OrchestrationParameterGroup.new( + :label => 'Parameter Group 2', + :parameters => [ + template_param(:label => 'Param 3'), + template_param(:label => 'Param 4') + ], + ) + ] + }, + ] + end + + it do + expect(dialog_tabs.size).to eq(2) + assert_tab_attributes(first_tab, :label => 'Tab 1', :display => 'edit') + assert_group(first_group, 'Parameter Group 1', ['Param 1', 'Param 2']) + assert_tab_attributes(second_tab, :label => 'Tab 2', :display => 'edit') + assert_group(second_tab.dialog_groups.first, 'Parameter Group 2', ['Param 3', 'Param 4']) + end + end end end @@ -99,7 +254,7 @@ end def assert_stack_tab(tab) - assert_tab_attributes(tab) + assert_tab_attributes(tab, :label => "Basic Information", :display => "edit") groups = tab.dialog_groups expect(groups.size).to eq(3) @@ -107,11 +262,8 @@ def assert_stack_tab(tab) assert_stack_group(groups[0]) end - def assert_tab_attributes(tab) - expect(tab).to have_attributes( - :label => "Basic Information", - :display => "edit" - ) + def assert_tab_attributes(tab, attributes) + expect(tab).to have_attributes(attributes) end def assert_stack_group(group) @@ -124,7 +276,7 @@ def assert_stack_group(group) expect(fields.size).to eq(4) expect(fields[0].resource_action.fqname).to eq("/Cloud/Orchestration/Operations/Methods/Available_Tenants") - assert_field(fields[0], DialogFieldDropDownList, :name => "tenant_name", :dynamic => true, :reconfigurable => false) + assert_field(fields[0], DialogFieldDropDownList, :name => "tenant_name", :dynamic => true, :reconfigurable => nil) assert_field(fields[1], DialogFieldTextBox, :name => "stack_name", :validator_rule => '^[A-Za-z][A-Za-z0-9\-]*$', :reconfigurable => false) end @@ -133,6 +285,11 @@ def assert_field(field, clss, attributes) expect(field).to have_attributes(attributes) end + def assert_group(group, group_label, names) + expect(group.label).to eq(group_label) + expect(group.dialog_fields.map(&:label)).to eq(names) + end + def test_field(dialog) # First ensure that the dialog is properly constructed. tabs = dialog.dialog_tabs @@ -148,4 +305,10 @@ def create_parameters(options) options.reverse_merge!(:name => 'user', :label => 'User Parameter', :data_type => 'string', :required => true) [OrchestrationTemplate::OrchestrationParameterGroup.new(:label => 'group', :parameters => [OrchestrationTemplate::OrchestrationParameter.new(options)])] end + + def template_param(options) + options[:name] ||= SecureRandom.hex + options[:data_type] ||= 'string' + OrchestrationTemplate::OrchestrationParameter.new(options) + end end diff --git a/spec/models/orchestration_template_spec.rb b/spec/models/orchestration_template_spec.rb index 78121f58bab..592e83b7d03 100644 --- a/spec/models/orchestration_template_spec.rb +++ b/spec/models/orchestration_template_spec.rb @@ -309,6 +309,22 @@ end end + describe ".tabs" do + it do + expect(subject).to receive(:deployment_options).and_return('deployment-options') + expect(subject).to receive(:parameter_groups).and_return('parameter-groups') + expect(subject.tabs).to eq( + [ + { + :title => 'Basic Information', + :stack_group => 'deployment-options', + :param_groups => 'parameter-groups' + } + ] + ) + end + end + def assert_deployment_option(option, name, constraint_type, required) expect(option.name).to eq(name) expect(option.required?).to eq(required)