foreman_acd 0.7.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -3
  3. data/app/controllers/foreman_acd/ansible_playbooks_controller.rb +17 -2
  4. data/app/controllers/foreman_acd/app_definitions_controller.rb +104 -7
  5. data/app/controllers/foreman_acd/app_instances_controller.rb +15 -30
  6. data/app/controllers/foreman_acd/concerns/app_instance_mixins.rb +36 -0
  7. data/app/controllers/ui_acd_controller.rb +38 -1
  8. data/app/lib/actions/foreman_acd/run_configurator.rb +1 -0
  9. data/app/models/concerns/foreman_acd/host_managed_extensions.rb +15 -27
  10. data/app/models/foreman_acd/app_instance.rb +47 -2
  11. data/app/models/foreman_acd/foreman_host.rb +8 -0
  12. data/app/services/foreman_acd/app_deployer.rb +19 -2
  13. data/app/services/foreman_acd/inventory_creator.rb +11 -1
  14. data/app/views/foreman_acd/app_definitions/import.html.erb +20 -1
  15. data/app/views/foreman_acd/app_definitions/index.html.erb +3 -6
  16. data/app/views/foreman_acd/app_instances/index.html.erb +15 -11
  17. data/app/views/foreman_acd/app_instances/report.html.erb +7 -2
  18. data/app/views/ui_acd/host_report.json.rabl +4 -0
  19. data/app/views/ui_acd/report_data.json.rabl +10 -0
  20. data/app/views/ui_acd/validate_hostname.json.rabl +6 -0
  21. data/config/routes.rb +3 -0
  22. data/db/migrate/20210818125913_add_is_existing_host_to_foreman_host.rb +8 -0
  23. data/db/migrate/20210902110645_add_initial_configure_task.rb +8 -0
  24. data/lib/foreman_acd/plugin.rb +6 -6
  25. data/lib/foreman_acd/version.rb +1 -1
  26. data/lib/foreman_acd.rb +27 -9
  27. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
  28. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +28 -9
  29. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +6 -0
  30. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +1 -0
  31. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +30 -9
  32. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +3 -0
  33. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +1 -0
  34. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +30 -5
  35. data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +1 -1
  36. data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +3 -3
  37. data/webpack/components/ApplicationDefinition/index.js +6 -0
  38. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.js +214 -0
  39. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.scss +1 -0
  40. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportActions.js +161 -0
  41. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportConstants.js +6 -0
  42. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportReducer.js +79 -0
  43. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportSelectors.js +8 -0
  44. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportConfData_1.fixtures.js +129 -0
  45. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportReducer.fixtures.js +29 -0
  46. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImport.test.js +20 -0
  47. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportReducer.test.js +43 -0
  48. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportSelectors.test.js +29 -0
  49. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImport.test.js.snap +62 -0
  50. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportReducer.test.js.snap +362 -0
  51. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportSelectors.test.js.snap +130 -0
  52. data/webpack/components/ApplicationDefinitionImport/index.js +32 -0
  53. data/webpack/components/ApplicationInstance/ApplicationInstance.js +96 -25
  54. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +112 -6
  55. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +4 -0
  56. data/webpack/components/ApplicationInstance/ApplicationInstanceHelper.js +15 -0
  57. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +71 -30
  58. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +3 -0
  59. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +2 -0
  60. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +1 -0
  61. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +12 -0
  62. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +97 -7
  63. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +271 -0
  64. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +1 -0
  65. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +1 -1
  66. data/webpack/components/ApplicationInstance/helper.js +0 -0
  67. data/webpack/components/ApplicationInstance/index.js +6 -0
  68. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +81 -6
  69. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +35 -1
  70. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +3 -0
  71. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +19 -0
  72. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +4 -0
  73. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +1 -124
  74. data/webpack/components/ApplicationInstanceReport/index.js +8 -1
  75. data/webpack/components/ExistingHostSelection/ExistingHostSelection.js +104 -0
  76. data/webpack/components/ExistingHostSelection/ExistingHostSelection.scss +15 -0
  77. data/webpack/components/ExistingHostSelection/ExistingHostSelectionActions.js +71 -0
  78. data/webpack/components/ExistingHostSelection/ExistingHostSelectionConstants.js +4 -0
  79. data/webpack/components/ExistingHostSelection/ExistingHostSelectionHelper.js +0 -0
  80. data/webpack/components/ExistingHostSelection/ExistingHostSelectionReducer.js +90 -0
  81. data/webpack/components/ExistingHostSelection/ExistingHostSelectionSelectors.js +8 -0
  82. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionConfData_1.fixtures.js +191 -0
  83. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionReducer.fixtures.js +203 -0
  84. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelection.test.js +19 -0
  85. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionReducer.test.js +59 -0
  86. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionSelectors.test.js +36 -0
  87. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelection.test.js.snap +35 -0
  88. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionReducer.test.js.snap +614 -0
  89. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionSelectors.test.js.snap +27 -0
  90. data/webpack/components/ExistingHostSelection/components/ServiceSelector.js +48 -0
  91. data/webpack/components/ExistingHostSelection/components/__tests__/ServiceSelector.test.js +35 -0
  92. data/webpack/components/ExistingHostSelection/components/__tests__/__snapshots__/ServiceSelector.test.js.snap +77 -0
  93. data/webpack/components/ExistingHostSelection/index.js +26 -0
  94. data/webpack/components/ParameterSelection/ParameterSelection.js +98 -1
  95. data/webpack/components/ParameterSelection/ParameterSelection.scss +7 -0
  96. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +36 -2
  97. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +2 -0
  98. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +49 -8
  99. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +1 -0
  100. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +2 -0
  101. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +96 -0
  102. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +5 -0
  103. data/webpack/components/ParameterSelection/index.js +2 -1
  104. data/webpack/components/SyncGitRepo/SyncGitRepo.js +2 -10
  105. data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +1 -2
  106. data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +0 -1
  107. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +1 -0
  108. data/webpack/components/SyncGitRepo/components/FormTextInput.js +1 -1
  109. data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +3 -2
  110. data/webpack/components/common/DeleteTableEntry.js +16 -2
  111. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +38 -0
  112. data/webpack/helper.js +5 -0
  113. data/webpack/index.js +5 -0
  114. data/webpack/js-yaml.js +3874 -0
  115. data/webpack/reducer.js +13 -2
  116. metadata +46 -2
@@ -1,15 +1,12 @@
1
1
  <% title _('Application Definitions') %>
2
2
 
3
- <% title_actions button_group(
4
- new_link(_('New Application Definition')),
5
- display_link_if_authorized(_("Import"), hash_for_import_app_definitions_path, :class => 'btn btn-default', :style => "display: none;")
6
- ) %>
3
+ <% title_actions new_link(_('New Application Definition')), display_link_if_authorized(_("Import"), hash_for_import_app_definitions_path, :class => 'btn btn-default') %>
7
4
 
8
5
  <table class="table table-bordered table-striped">
9
6
  <tr>
10
7
  <th><%= sort :name, :as => s_('AppDefinition|Name') %></th>
11
8
  <th><%= _('Description') %></th>
12
- <th></th>
9
+ <th><%= _('Actions') %></th>
13
10
  </tr>
14
11
  <% for app_definition in @app_definitions %>
15
12
  <tr>
@@ -19,7 +16,7 @@
19
16
  <%= action_buttons(
20
17
  display_delete_if_authorized(hash_for_app_definition_path(:id => app_definition),
21
18
  :data => { 'confirm': _('Delete %s?') % app_definition.name }),
22
- # TODO: add export feature again if app-def + ansible playbook can be exported together display_link_if_authorized(_("Export"), hash_for_export_app_definition_path(:id => app_definition))
19
+ display_link_if_authorized(_("Export"), hash_for_export_app_definition_path(:id => app_definition))
23
20
  ) %>
24
21
  </td>
25
22
  </tr>
@@ -53,21 +53,25 @@
53
53
  <div class="modal-content">
54
54
  <div class="modal-header">
55
55
  <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
56
- <h4 class="modal-title"><%= _('Confirmation Box')%></h4>
56
+ <h4 class="modal-title"><%= _('Confirmation')%></h4>
57
57
  </div>
58
58
  <div class="modal-body">
59
- <p> <%= _("Confirm to delete ") %> <%= app_instance %></p>
59
+ <p> <%= _("Confirm to delete application instance: ") %> <%= app_instance %></p>
60
60
  <%= form_tag destroy_with_hosts_app_instance_path(:id => app_instance.id), :method => :delete do %>
61
- <% if app_instance.foreman_hosts.where.not(:host_id => [nil, false]).any? %>
62
- <p><%= _("Select the hosts to delete along with ") %> <%= app_instance %>: </p>
63
- <% end %>
64
- <% app_instance.foreman_hosts.each do |foreman_host|%>
61
+ <% showSelectHostsNote = true %>
62
+ <% app_instance.foreman_hosts.select(&:fresh_host?).each do |foreman_host|%>
65
63
  <% if foreman_host.host_id? %>
66
- <%= check_box_tag 'foreman_host_ids[]', foreman_host.host_id -%>
67
- <%= h foreman_host.host.name -%>
68
- </br>
64
+ <% if showSelectHostsNote %>
65
+ <p><%= _("Select the hosts to delete along with ") %> <%= app_instance %>: </p>
66
+ <% showSelectHostsNote = false %>
67
+ <% end %>
68
+ <%= check_box_tag 'foreman_host_ids[]', foreman_host.host_id, false, class: 'acd_host' -%> <%= h foreman_host.host.name -%>
69
+ </br>
69
70
  <% end %>
70
71
  <% end %>
72
+ <hr width="90%">
73
+ <p> <%= check_box_tag "check_all", "", false, { :onchange => "toggleCheckboxesBySelector('.acd_host')" } %> Select / unselect all hosts</p>
74
+ <br /><p><%= _("Note: Hosts which already existed and were added to the application instance are not shown in this dialog!") %></p>
71
75
  </div>
72
76
  <div class="modal-footer">
73
77
  <button type="button" class="btn btn-primary" data-dismiss="modal"><%= _('Cancel') %></button>
@@ -91,8 +95,8 @@
91
95
  <%= form_tag deploy_app_instance_path(:id => app_instance.id), :method => :post do %>
92
96
  <% if app_instance.foreman_hosts.where.not(:host_id => [nil, false]).any? %>
93
97
  <ul>
94
- <li><%= check_box_tag 'delete_hosts'-%><%= _('Delete all hosts before deploying ') %><%= app_instance%></li>
95
- <li><%= check_box_tag 'safe_deploy' -%><%= _('Deploy only new and changed hosts for ') %><%= app_instance%></li>
98
+ <li><%= check_box_tag 'delete_hosts'-%> <%= _('Delete all hosts before deploying ') %><%= app_instance%></li>
99
+ <li><%= check_box_tag 'safe_deploy' -%> <%= _('Deploy only new and changed hosts for ') %><%= app_instance%></li>
96
100
  </ul>
97
101
  <% end %>
98
102
  </div>
@@ -9,12 +9,17 @@
9
9
 
10
10
  <%
11
11
  json = {
12
- "mode": 'lastReport',
12
+ "deploymentState": @app_instance.deployment_state.to_s,
13
+ "initialConfigureState": @app_instance.initial_configure_state.to_s,
13
14
  "appInstanceName": @app_instance.name,
14
15
  "hosts": @report_hosts,
15
16
  "deployTaskUrl": foreman_tasks_task_path(@app_instance.last_deploy_task),
16
- "configureJobUrl": job_invocations_path(search: "description ~ \"ACD application #{@app_instance.name}\"")
17
+ "configureJobUrl": job_invocations_path(search: "description ~ \"ACD application #{@app_instance.name}\""),
18
+ "reportDataUrl": ui_acd_report_data_path("__id__"),
19
+ "appInstanceId": @app_instance.id,
17
20
  }
21
+
22
+ json["initialConfigureJobUrl"] = job_invocation_path(@app_instance.initial_configure_job) unless @app_instance.initial_configure_job.nil?
18
23
  %>
19
24
 
20
25
  <div id='report'></div>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ collection @hosts
4
+ attributes :id, :name, :build, :hostUrl, :isExistingHost, :progress_report, :powerStatusUrl
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ object @report_data
4
+ attribute :deploymentState
5
+ attribute :initialConfigureState
6
+ attribute :initialConfigureJobUrl
7
+
8
+ child :hosts => :hosts do
9
+ extends 'ui_acd/host_report'
10
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ object @host_validation
4
+ attribute :hostname
5
+ attribute :fqdn
6
+ attribute :result
data/config/routes.rb CHANGED
@@ -18,6 +18,7 @@ Rails.application.routes.draw do
18
18
  collection do
19
19
  get 'auto_complete_search'
20
20
  get 'import'
21
+ post 'handle_file_upload'
21
22
  end
22
23
 
23
24
  member do
@@ -42,6 +43,8 @@ Rails.application.routes.draw do
42
43
  get 'ui_acd_app/:id', :to => 'ui_acd#app', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_app
43
44
  get 'ui_acd_foreman_data/:id', :to => 'ui_acd#foreman_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_foreman_data
44
45
  get 'ui_acd_ansible_data/:id', :to => 'ui_acd#ansible_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_ansible_data
46
+ get 'ui_acd_report_data/:id', :to => 'ui_acd#report_data', :constraints => { :id => /[\w\.-]+/ }, :as => :ui_acd_report_data
47
+ get 'ui_acd_validate_hostname', :to => 'ui_acd#validate_hostname', :as => :ui_acd_validate_hostname
45
48
 
46
49
  scope :api, :path => '/api', :defaults => { :format => 'json' } do
47
50
  scope '(:apiv)', :defaults => { :apiv => 'v2' },
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add is_existing_host to app instance
4
+ class AddIsExistingHostToForemanHost < ActiveRecord::Migration[6.0]
5
+ def change
6
+ add_column :acd_foreman_hosts, :is_existing_host, :boolean, :default => false, :null => false
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add AddInitialConfigureTask
4
+ class AddInitialConfigureTask < ActiveRecord::Migration[5.2]
5
+ def change
6
+ add_column :acd_app_instances, :initial_configure_task_id, :uuid, :null => true
7
+ end
8
+ end
@@ -111,13 +111,13 @@ Foreman::Plugin.register :foreman_acd do
111
111
  :'foreman_acd/api/v2/app_instances' => [:report] },
112
112
  :resource_type => 'ForemanAcd::AppInstance'
113
113
 
114
- permission :new_remote_execution,
114
+ permission :new_acd_configure_job,
115
115
  { :'foreman_acd/remote_execution' => [:new] },
116
- :resource_type => 'ForemanAcd::RemoteExecution'
116
+ :resource_type => 'ForemanAcd::AppInstance'
117
117
 
118
- permission :create_remote_execution,
118
+ permission :create_acd_configure_job,
119
119
  { :'foreman_acd/remote_execution' => [:create] },
120
- :resource_type => 'ForemanAcd::RemoteExecution'
120
+ :resource_type => 'ForemanAcd::AppInstance'
121
121
 
122
122
  permission :view_ui_acd,
123
123
  { :ui_acd => [:app, :foreman_data, :ansible_data] }
@@ -137,7 +137,7 @@ Foreman::Plugin.register :foreman_acd do
137
137
  :create_app_instances, :view_app_instances, :edit_app_instances,
138
138
  :destroy_app_instances,
139
139
  :deploy_app_instances,
140
- :new_remote_execution, :create_remote_execution,
140
+ :new_acd_configure_job, :create_acd_configure_job,
141
141
  :report_app_instances,
142
142
  :view_ui_acd,
143
143
  :view_hosts, :build_hosts, :power_hosts, :create_hosts, :edit_hosts, :destroy_hosts, :console_hosts,
@@ -150,7 +150,7 @@ Foreman::Plugin.register :foreman_acd do
150
150
  role 'Application Centric Deployment User', [:create_app_instances, :view_app_instances, :edit_app_instances,
151
151
  :destroy_app_instances,
152
152
  :deploy_app_instances,
153
- :new_remote_execution, :create_remote_execution,
153
+ :new_acd_configure_job, :create_acd_configure_job,
154
154
  :report_app_instances,
155
155
  :view_ui_acd,
156
156
  :view_hosts, :build_hosts, :power_hosts, :create_hosts, :edit_hosts, :destroy_hosts, :console_hosts,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ForemanAcd
4
- VERSION = '0.7.0'
4
+ VERSION = '0.9.0'
5
5
  end
data/lib/foreman_acd.rb CHANGED
@@ -4,16 +4,34 @@ require 'foreman_acd/engine'
4
4
 
5
5
  # Module required to start the Foreman Rails engine
6
6
  module ForemanAcd
7
- def self.acd_base_path
8
- '/var/lib/foreman/foreman_acd/'
9
- end
7
+ RUN_CONFIGURATOR_DELAY = 240
10
8
 
11
- def self.ansible_playbook_path
12
- File.join(acd_base_path, 'ansible-playbooks')
13
- end
9
+ class << self
10
+ def acd_base_path
11
+ '/var/lib/foreman/foreman_acd/'
12
+ end
13
+
14
+ def ansible_playbook_path
15
+ File.join(acd_base_path, 'ansible-playbooks')
16
+ end
17
+
18
+ def proxy_setting
19
+ HttpProxy.default_global_content_proxy&.full_url ||
20
+ Setting[:http_proxy]
21
+ end
22
+
23
+ def initiate_acd_app_configurator(app_instance)
24
+ return unless app_instance.hosts_deployment_finished?
25
+
26
+ ::Foreman::Logging.logger('foreman_acd').info("All hosts of app (#{app_instance.name}) were built. Schedule app configurator...")
27
+ start_acd_app_configurator(app_instance)
28
+ end
14
29
 
15
- def self.proxy_setting
16
- HttpProxy.default_global_content_proxy&.full_url ||
17
- Setting[:http_proxy]
30
+ def start_acd_app_configurator(app_instance)
31
+ task = ForemanTasks.delay(::Actions::ForemanAcd::RunConfigurator,
32
+ { :start_at => Time.zone.now + RUN_CONFIGURATOR_DELAY },
33
+ app_instance)
34
+ app_instance.update(:initial_configure_task_id => task.id)
35
+ end
18
36
  end
19
37
  end
@@ -0,0 +1,2 @@
1
+ export const setModalOpen = () => jest.fn();
2
+ export const setModalClosed = () => jest.fn();
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
4
4
  import {
5
5
  Icon,
6
6
  Button,
7
+ MessageDialog,
7
8
  } from 'patternfly-react';
8
9
  import * as resolve from 'table-resolver';
9
10
  import ForemanModal from 'foremanReact/components/ForemanModal';
@@ -75,21 +76,21 @@ class ApplicationDefinition extends React.Component {
75
76
  bsStyle="default"
76
77
  onClick={() => activateEditApplicationDefinitionService(additionalData)}
77
78
  >
78
- <Icon type="pf" name="edit" title={__("edit entry")} />
79
+ <Icon type="pf" name="edit" title={__("Edit entry")} />
79
80
  </Button>
80
81
  &nbsp;
81
82
  <Button
82
83
  bsStyle="default"
83
84
  onClick={() => openForemanParameterSelectionModal(additionalData)}
84
85
  >
85
- <Icon type="pf" name="settings" title={__("change parameters")} />
86
+ <Icon type="pf" name="settings" title={__("Change parameters")} />
86
87
  </Button>
87
88
  &nbsp;
88
89
  <Button
89
90
  bsStyle="default"
90
91
  onClick={() => openAnsibleParameterSelectionModal(additionalData)}
91
92
  >
92
- <span title={__("change ansible variables")}>A</span>
93
+ <span title={__("Change ansible variables")}>A</span>
93
94
  </Button>
94
95
  &nbsp;
95
96
  <DeleteTableEntry
@@ -202,6 +203,7 @@ class ApplicationDefinition extends React.Component {
202
203
  render() {
203
204
  const {
204
205
  data: { organization, location, mode, ansiblePlaybooks, foremanDataUrl, ansibleDataUrl },
206
+ showAlertModal, alertModalText, alertModalTitle, closeAlertModal,
205
207
  ansiblePlaybook,
206
208
  services,
207
209
  columns,
@@ -216,12 +218,22 @@ class ApplicationDefinition extends React.Component {
216
218
  loadAnsibleData,
217
219
  } = this.props;
218
220
 
219
-
220
221
  return (
221
222
  <span>
223
+ <MessageDialog
224
+ show={showAlertModal}
225
+ onHide={closeAlertModal}
226
+ primaryAction={closeAlertModal}
227
+ primaryActionButtonContent={__('OK')}
228
+ primaryActionButtonBsStyle={"danger"}
229
+ icon={<Icon type="pf" name="error-circle-o" />}
230
+ title={alertModalTitle}
231
+ primaryContent={alertModalText}
232
+ />
222
233
  <div>
223
234
  <AnsiblePlaybookSelector
224
235
  label="Ansible Playbook"
236
+ hidden={ false }
225
237
  editable={ mode == 'newDefinition' }
226
238
  viewText={ ansiblePlaybook.name }
227
239
  options={ ansiblePlaybooks }
@@ -230,9 +242,9 @@ class ApplicationDefinition extends React.Component {
230
242
  additionalData={{url: ansibleDataUrl }}
231
243
  />
232
244
  {ansiblePlaybook.id == '' ? (
233
- <p style={{ paddingTop: 25 }}>
245
+ <div style={{ paddingTop: 25 }}>
234
246
  <pre>{ "Ansible Playbook can't be blank" }</pre>
235
- </p>
247
+ </div>
236
248
  ) : (<div></div>)}
237
249
 
238
250
  </div>
@@ -279,7 +291,7 @@ class ApplicationDefinition extends React.Component {
279
291
  isAllGroup: true
280
292
  })}
281
293
  >
282
- <span title={__("change ansible variables for 'all'")}>A</span>
294
+ <span title={__("Change ansible variables for 'all'")}>A</span>
283
295
  </Button>
284
296
  </span>
285
297
  </div>
@@ -339,13 +351,13 @@ class ApplicationDefinition extends React.Component {
339
351
  </ForemanModal>
340
352
  </div>
341
353
  <RailsData
342
- key='applications_definition'
354
+ key='application_definition_services_data'
343
355
  view='app_definition'
344
356
  parameter='services'
345
357
  value={JSON.stringify(this.props.services)}
346
358
  />
347
359
  <RailsData
348
- key='applications_definition'
360
+ key='application_definition_ansible_data'
349
361
  view='app_definition'
350
362
  parameter='ansible_vars_all'
351
363
  value={JSON.stringify(this.props.ansibleVarsAll)}
@@ -356,6 +368,9 @@ class ApplicationDefinition extends React.Component {
356
368
 
357
369
  ApplicationDefinition.defaultProps = {
358
370
  error: {},
371
+ showAlertModal: false,
372
+ alertModalText: '',
373
+ alertModalTitle: '',
359
374
  editMode: false,
360
375
  ansiblePlaybook: { "id": '', "name": '' },
361
376
  services: [],
@@ -368,11 +383,15 @@ ApplicationDefinition.defaultProps = {
368
383
 
369
384
  ApplicationDefinition.propTypes = {
370
385
  initApplicationDefinition: PropTypes.func,
386
+ showAlertModal: PropTypes.bool,
387
+ alertModalText: PropTypes.string,
388
+ alertModalTitle: PropTypes.string,
371
389
  editMode: PropTypes.bool.isRequired,
372
390
  ansiblePlaybook: PropTypes.object,
373
391
  services: PropTypes.array,
374
392
  ansibleVarsAll: PropTypes.array,
375
393
  columns: PropTypes.array,
394
+ closeAlertModal: PropTypes.func,
376
395
  addApplicationDefinitionService: PropTypes.func,
377
396
  deleteApplicationDefinitionService: PropTypes.func,
378
397
  activateEditApplicationDefinitionService: PropTypes.func,
@@ -17,6 +17,7 @@ import {
17
17
 
18
18
  import {
19
19
  APPLICATION_DEFINITION_INIT,
20
+ APPLICATION_DEFINITION_CLOSE_ALERT_MODAL,
20
21
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST,
21
22
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS,
22
23
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE,
@@ -182,6 +183,11 @@ const errorHandler = (msg, err) => {
182
183
  return { type: msg, payload: { error } };
183
184
  };
184
185
 
186
+ export const closeAlertModal = () => ({
187
+ type: APPLICATION_DEFINITION_CLOSE_ALERT_MODAL,
188
+ payload: {}
189
+ });
190
+
185
191
  export const loadAnsibleData = (
186
192
  ansiblePlaybookId,
187
193
  additionalData
@@ -1,4 +1,5 @@
1
1
  export const APPLICATION_DEFINITION_INIT = 'INIT_APPLICATION_DEFINITION_INIT';
2
+ export const APPLICATION_DEFINITION_CLOSE_ALERT_MODAL = 'APPLICATION_DEFINITION_CLOSE_ALERT_MODAL';
2
3
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST';
3
4
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS';
4
5
  export const APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE = 'APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE';
@@ -1,4 +1,5 @@
1
1
  import Immutable from 'seamless-immutable';
2
+ import { translate as __ } from 'foremanReact/common/I18n';
2
3
 
3
4
  import {
4
5
  cloneDeep,
@@ -8,6 +9,7 @@ import {
8
9
 
9
10
  import {
10
11
  APPLICATION_DEFINITION_INIT,
12
+ APPLICATION_DEFINITION_CLOSE_ALERT_MODAL,
11
13
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST,
12
14
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_SUCCESS,
13
15
  APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE,
@@ -45,8 +47,15 @@ const applicationDefinitionConf = (state = initialState, action) => {
45
47
  case APPLICATION_DEFINITION_INIT: {
46
48
  return state.merge(payload);
47
49
  }
48
-
50
+ case APPLICATION_DEFINITION_CLOSE_ALERT_MODAL: {
51
+ return state.merge({
52
+ showAlertModal: false,
53
+ alertModalTitle: '',
54
+ alertModalText: '',
55
+ });
56
+ }
49
57
  case APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_FAILURE: {
58
+ console.log("Error while loading ansible data: "+ payload.error);
50
59
  return state.merge({ error: payload.error, loading: false });
51
60
  }
52
61
  case APPLICATION_DEFINITION_LOAD_ANSIBLE_DATA_REQUEST: {
@@ -113,23 +122,35 @@ const applicationDefinitionConf = (state = initialState, action) => {
113
122
  const thisService = services[index];
114
123
 
115
124
  if (thisService.name == '') {
116
- window.alert("Every service needs to have a valid name.");
117
- return state;
125
+ return state.merge({
126
+ showAlertModal: true,
127
+ alertModalTitle: __("Error"),
128
+ alertModalText: __("Every service needs to have a valid name."),
129
+ });
118
130
  }
119
131
 
120
132
  if (thisService.hostgroup == '') {
121
- window.alert("Every service needs to be assigned to a hostgroup.");
122
- return state;
133
+ return state.merge({
134
+ showAlertModal: true,
135
+ alertModalTitle: __("Error"),
136
+ alertModalText: __("Every service needs to be assigned to a hostgroup."),
137
+ });
123
138
  }
124
139
 
125
140
  if (thisService.ansibleGroup == '') {
126
- window.alert("Every service needs to be assigned to a ansible group.");
127
- return state;
141
+ return state.merge({
142
+ showAlertModal: true,
143
+ alertModalTitle: __("Error"),
144
+ alertModalText: __("Every service needs to be assigned to an ansible group."),
145
+ });
128
146
  }
129
147
 
130
148
  if (state.services.filter(v => v.name === thisService.name && v.id != thisService.id).length > 0) {
131
- window.alert("Service name already used in this Application Definition. Please make sure that every service name is unique.");
132
- return state;
149
+ return state.merge({
150
+ showAlertModal: true,
151
+ alertModalTitle: __("Error"),
152
+ alertModalText: __("Service name already used in this Application Definition. Please make sure that every service name is unique."),
153
+ });
133
154
  }
134
155
 
135
156
  delete services[index].backup;
@@ -1,5 +1,8 @@
1
1
  const applicationDefinitionConf = state => state.foremanAcd.applicationDefinitionConf;
2
2
 
3
+ export const selectShowAlertModal = state => applicationDefinitionConf(state).showAlertModal;
4
+ export const selectAlertModalText = state => applicationDefinitionConf(state).alertModalText;
5
+ export const selectAlertModalTitle = state => applicationDefinitionConf(state).alertModalTitle;
3
6
  export const selectEditMode = state => applicationDefinitionConf(state).editMode;
4
7
  export const selectAnsiblePlaybook = state => applicationDefinitionConf(state).ansiblePlaybook;
5
8
  export const selectServices = state => applicationDefinitionConf(state).services;
@@ -15,6 +15,7 @@ const fixtures = {
15
15
  services: [],
16
16
  ansibleVarsAll: [],
17
17
  },
18
+ closeAlertModal: noop,
18
19
  loadAnsibleData: noop,
19
20
  initApplicationDefinition: noop,
20
21
  addApplicationDefinitionService: noop,
@@ -2,6 +2,30 @@
2
2
 
3
3
  exports[`ApplicationDefinition should render application definition 1`] = `
4
4
  <span>
5
+ <MessageDialog
6
+ accessibleDescription=""
7
+ accessibleName=""
8
+ className=""
9
+ enforceFocus={true}
10
+ footer={null}
11
+ icon={
12
+ <Icon
13
+ name="error-circle-o"
14
+ type="pf"
15
+ />
16
+ }
17
+ onHide={[Function]}
18
+ primaryAction={[Function]}
19
+ primaryActionButtonBsStyle="danger"
20
+ primaryActionButtonContent="OK"
21
+ primaryContent=""
22
+ secondaryAction={[Function]}
23
+ secondaryActionButtonBsStyle="default"
24
+ secondaryActionButtonContent={null}
25
+ secondaryContent={null}
26
+ show={false}
27
+ title=""
28
+ />
5
29
  <div>
6
30
  <AnsiblePlaybookSelector
7
31
  additionalData={
@@ -10,12 +34,13 @@ exports[`ApplicationDefinition should render application definition 1`] = `
10
34
  }
11
35
  }
12
36
  editable={false}
37
+ hidden={false}
13
38
  label="Ansible Playbook"
14
39
  onChange={[Function]}
15
40
  selectValue=""
16
41
  viewText=""
17
42
  />
18
- <p
43
+ <div
19
44
  style={
20
45
  Object {
21
46
  "paddingTop": 25,
@@ -25,7 +50,7 @@ exports[`ApplicationDefinition should render application definition 1`] = `
25
50
  <pre>
26
51
  Ansible Playbook can't be blank
27
52
  </pre>
28
- </p>
53
+ </div>
29
54
  </div>
30
55
  <div
31
56
  className="form-group"
@@ -88,7 +113,7 @@ exports[`ApplicationDefinition should render application definition 1`] = `
88
113
  }
89
114
  >
90
115
  <span
91
- title="change ansible variables for 'all'"
116
+ title="Change ansible variables for 'all'"
92
117
  >
93
118
  A
94
119
  </span>
@@ -185,13 +210,13 @@ exports[`ApplicationDefinition should render application definition 1`] = `
185
210
  </ForemanModal>
186
211
  </div>
187
212
  <RailsData
188
- key="applications_definition"
213
+ key="application_definition_services_data"
189
214
  parameter="services"
190
215
  value="[]"
191
216
  view="app_definition"
192
217
  />
193
218
  <RailsData
194
- key="applications_definition"
219
+ key="application_definition_ansible_data"
195
220
  parameter="ansible_vars_all"
196
221
  value="[]"
197
222
  view="app_definition"
@@ -27,7 +27,7 @@ const AnsiblePlaybookSelector= ({
27
27
  additionalData={additionalData}
28
28
  />
29
29
  <RailsData
30
- key='ansible_playbook_id'
30
+ key='ansible_playbook_data'
31
31
  view='app_definition'
32
32
  parameter='acd_ansible_playbook_id'
33
33
  value={selectValue}
@@ -31,7 +31,7 @@ exports[`AnsiblePlaybookSelector should render ansible playbook selector 1`] = `
31
31
  viewText="myText"
32
32
  />
33
33
  <RailsData
34
- key="ansible_playbook_id"
34
+ key="ansible_playbook_data"
35
35
  parameter="acd_ansible_playbook_id"
36
36
  value="1"
37
37
  view="app_definition"
@@ -71,7 +71,7 @@ exports[`AnsiblePlaybookSelector should render hidden ansible playbook selector
71
71
  viewText="myText"
72
72
  />
73
73
  <RailsData
74
- key="ansible_playbook_id"
74
+ key="ansible_playbook_data"
75
75
  parameter="acd_ansible_playbook_id"
76
76
  value="1"
77
77
  view="app_definition"
@@ -111,7 +111,7 @@ exports[`AnsiblePlaybookSelector should render not editable ansible playbook sel
111
111
  viewText="myText"
112
112
  />
113
113
  <RailsData
114
- key="ansible_playbook_id"
114
+ key="ansible_playbook_data"
115
115
  parameter="acd_ansible_playbook_id"
116
116
  value="1"
117
117
  view="app_definition"
@@ -6,6 +6,9 @@ import ApplicationDefinition from './ApplicationDefinition';
6
6
  import * as ApplicationDefinitionActions from './ApplicationDefinitionActions';
7
7
 
8
8
  import {
9
+ selectShowAlertModal,
10
+ selectAlertModalText,
11
+ selectAlertModalTitle,
9
12
  selectEditMode,
10
13
  selectAnsiblePlaybook,
11
14
  selectServices,
@@ -16,6 +19,9 @@ import {
16
19
  } from './ApplicationDefinitionSelectors';
17
20
 
18
21
  const mapStateToProps = state => ({
22
+ showAlertModal: selectShowAlertModal(state),
23
+ alertModalText: selectAlertModalText(state),
24
+ alertModalTitle: selectAlertModalTitle(state),
19
25
  editMode: selectEditMode(state),
20
26
  ansiblePlaybook: selectAnsiblePlaybook(state),
21
27
  services: selectServices(state),