foreman_acd 0.7.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  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 +42 -3
  8. data/app/lib/actions/foreman_acd/run_configurator.rb +1 -0
  9. data/app/models/concerns/foreman_acd/host_managed_extensions.rb +40 -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/_form.html.erb +4 -0
  15. data/app/views/foreman_acd/app_definitions/import.html.erb +20 -1
  16. data/app/views/foreman_acd/app_definitions/index.html.erb +3 -6
  17. data/app/views/foreman_acd/app_instances/_form.html.erb +4 -0
  18. data/app/views/foreman_acd/app_instances/index.html.erb +15 -11
  19. data/app/views/foreman_acd/app_instances/report.html.erb +7 -2
  20. data/app/views/ui_acd/host_report.json.rabl +4 -0
  21. data/app/views/ui_acd/report_data.json.rabl +10 -0
  22. data/app/views/ui_acd/validate_hostname.json.rabl +6 -0
  23. data/config/routes.rb +3 -0
  24. data/db/migrate/20210818125913_add_is_existing_host_to_foreman_host.rb +8 -0
  25. data/db/migrate/20210902110645_add_initial_configure_task.rb +8 -0
  26. data/lib/foreman_acd/plugin.rb +9 -9
  27. data/lib/foreman_acd/version.rb +1 -1
  28. data/lib/foreman_acd.rb +27 -9
  29. data/package.json +8 -25
  30. data/test/controllers/ui_acd_controller_test.rb +4 -1
  31. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
  32. data/webpack/__snapshots__/helper.test.js.snap +1 -1
  33. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +34 -10
  34. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +12 -0
  35. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +1 -0
  36. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +30 -9
  37. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +4 -0
  38. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinition.test.js +1 -0
  39. data/webpack/components/ApplicationDefinition/__tests__/ApplicationDefinitionSelectors.test.js +12 -0
  40. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinition.test.js.snap +31 -5
  41. data/webpack/components/ApplicationDefinition/__tests__/__snapshots__/ApplicationDefinitionSelectors.test.js.snap +8 -0
  42. data/webpack/components/ApplicationDefinition/components/AnsiblePlaybookSelector.js +1 -1
  43. data/webpack/components/ApplicationDefinition/components/__tests__/__snapshots__/AnsiblePlaybookSelector.test.js.snap +3 -3
  44. data/webpack/components/ApplicationDefinition/index.js +8 -0
  45. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.js +214 -0
  46. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImport.scss +1 -0
  47. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportActions.js +161 -0
  48. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportConstants.js +6 -0
  49. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportReducer.js +79 -0
  50. data/webpack/components/ApplicationDefinitionImport/ApplicationDefinitionImportSelectors.js +8 -0
  51. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportConfData_1.fixtures.js +129 -0
  52. data/webpack/components/ApplicationDefinitionImport/__fixtures__/applicationDefinitionImportReducer.fixtures.js +29 -0
  53. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImport.test.js +20 -0
  54. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportReducer.test.js +43 -0
  55. data/webpack/components/ApplicationDefinitionImport/__tests__/ApplicationDefinitionImportSelectors.test.js +29 -0
  56. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImport.test.js.snap +62 -0
  57. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportReducer.test.js.snap +362 -0
  58. data/webpack/components/ApplicationDefinitionImport/__tests__/__snapshots__/ApplicationDefinitionImportSelectors.test.js.snap +130 -0
  59. data/webpack/components/ApplicationDefinitionImport/index.js +32 -0
  60. data/webpack/components/ApplicationInstance/ApplicationInstance.js +102 -26
  61. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +118 -6
  62. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +4 -0
  63. data/webpack/components/ApplicationInstance/ApplicationInstanceHelper.js +15 -0
  64. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +71 -30
  65. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +4 -0
  66. data/webpack/components/ApplicationInstance/__fixtures__/applicationInstanceReducer.fixtures.js +2 -0
  67. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstance.test.js +1 -0
  68. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceReducer.test.js +12 -0
  69. data/webpack/components/ApplicationInstance/__tests__/ApplicationInstanceSelectors.test.js +12 -0
  70. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstance.test.js.snap +98 -7
  71. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceReducer.test.js.snap +271 -0
  72. data/webpack/components/ApplicationInstance/__tests__/__snapshots__/ApplicationInstanceSelectors.test.js.snap +8 -0
  73. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +1 -0
  74. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +1 -1
  75. data/webpack/components/ApplicationInstance/helper.js +0 -0
  76. data/webpack/components/ApplicationInstance/index.js +8 -0
  77. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +81 -6
  78. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +35 -1
  79. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +3 -0
  80. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +19 -0
  81. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +4 -0
  82. data/webpack/components/ApplicationInstanceReport/__tests__/__snapshots__/ApplicationInstanceReport.test.js.snap +1 -124
  83. data/webpack/components/ApplicationInstanceReport/index.js +8 -1
  84. data/webpack/components/ExistingHostSelection/ExistingHostSelection.js +104 -0
  85. data/webpack/components/ExistingHostSelection/ExistingHostSelection.scss +15 -0
  86. data/webpack/components/ExistingHostSelection/ExistingHostSelectionActions.js +71 -0
  87. data/webpack/components/ExistingHostSelection/ExistingHostSelectionConstants.js +4 -0
  88. data/webpack/components/ExistingHostSelection/ExistingHostSelectionHelper.js +0 -0
  89. data/webpack/components/ExistingHostSelection/ExistingHostSelectionReducer.js +90 -0
  90. data/webpack/components/ExistingHostSelection/ExistingHostSelectionSelectors.js +8 -0
  91. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionConfData_1.fixtures.js +191 -0
  92. data/webpack/components/ExistingHostSelection/__fixtures__/existingHostSelectionReducer.fixtures.js +203 -0
  93. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelection.test.js +19 -0
  94. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionReducer.test.js +59 -0
  95. data/webpack/components/ExistingHostSelection/__tests__/ExistingHostSelectionSelectors.test.js +36 -0
  96. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelection.test.js.snap +35 -0
  97. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionReducer.test.js.snap +614 -0
  98. data/webpack/components/ExistingHostSelection/__tests__/__snapshots__/ExistingHostSelectionSelectors.test.js.snap +27 -0
  99. data/webpack/components/ExistingHostSelection/components/ServiceSelector.js +48 -0
  100. data/webpack/components/ExistingHostSelection/components/__tests__/ServiceSelector.test.js +35 -0
  101. data/webpack/components/ExistingHostSelection/components/__tests__/__snapshots__/ServiceSelector.test.js.snap +77 -0
  102. data/webpack/components/ExistingHostSelection/index.js +26 -0
  103. data/webpack/components/ParameterSelection/ParameterSelection.js +103 -1
  104. data/webpack/components/ParameterSelection/ParameterSelection.scss +7 -0
  105. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +46 -4
  106. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +2 -0
  107. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +5 -1
  108. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +52 -11
  109. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -0
  110. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +8 -0
  111. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +2 -0
  112. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -0
  113. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +96 -0
  114. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +117 -17
  115. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +13 -0
  116. data/webpack/components/ParameterSelection/index.js +4 -1
  117. data/webpack/components/SyncGitRepo/SyncGitRepo.js +2 -10
  118. data/webpack/components/SyncGitRepo/SyncGitRepoActions.js +2 -3
  119. data/webpack/components/SyncGitRepo/SyncGitRepoConstants.js +0 -1
  120. data/webpack/components/SyncGitRepo/__tests__/__snapshots__/SyncGitRepo.test.js.snap +1 -0
  121. data/webpack/components/SyncGitRepo/components/FormTextInput.js +1 -1
  122. data/webpack/components/SyncGitRepo/components/ScmTypeSelector.js +3 -2
  123. data/webpack/components/common/DeleteTableEntry.js +16 -2
  124. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +38 -0
  125. data/webpack/helper.js +21 -1
  126. data/webpack/helper.test.js +20 -1
  127. data/webpack/index.js +5 -0
  128. data/webpack/js-yaml.js +3874 -0
  129. data/webpack/reducer.js +13 -2
  130. data/webpack/test_setup.js +0 -2
  131. metadata +46 -2
@@ -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,9 +1,13 @@
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;
6
9
  export const selectColumns = state => applicationDefinitionConf(state).columns;
10
+ export const selectHiddenForemanParameterTypes = state => applicationDefinitionConf(state).hiddenForemanParameterTypes;
7
11
  export const selectParametersData = state => applicationDefinitionConf(state).parametersData;
8
12
  export const selectAnsibleVarsAll = state => applicationDefinitionConf(state).ansibleVarsAll;
9
13
  export const selectParamEditMode = state => applicationDefinitionConf(state).paramEditMode;
@@ -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,
@@ -1,10 +1,14 @@
1
1
  import { testSelectorsSnapshotWithFixtures } from 'react-redux-test-utils';
2
2
 
3
3
  import {
4
+ selectShowAlertModal,
5
+ selectAlertModalText,
6
+ selectAlertModalTitle,
4
7
  selectEditMode,
5
8
  selectAnsiblePlaybook,
6
9
  selectServices,
7
10
  selectColumns,
11
+ selectHiddenForemanParameterTypes,
8
12
  selectParametersData,
9
13
  selectAnsibleVarsAll,
10
14
  selectParamEditMode,
@@ -21,6 +25,12 @@ const stateFactory = obj => ({
21
25
  });
22
26
 
23
27
  const fixtures = {
28
+ 'should return showAlertModal from applicationDefinitionConfData_1 fixtures': () =>
29
+ selectShowAlertModal(stateFactory(applicationDefinitionConfData_1)),
30
+ 'should return alertModalText from applicationDefinitionConfData_1 fixtures': () =>
31
+ selectAlertModalText(stateFactory(applicationDefinitionConfData_1)),
32
+ 'should return alertModalTitle from applicationDefinitionConfData_1 fixtures': () =>
33
+ selectAlertModalTitle(stateFactory(applicationDefinitionConfData_1)),
24
34
  'should return editMode from applicationDefinitionConfData_1 fixtures': () =>
25
35
  selectEditMode(stateFactory(applicationDefinitionConfData_1)),
26
36
  'should return ansiblePlaybook from applicationDefinitionConfData_1 fixtures': () =>
@@ -31,6 +41,8 @@ const fixtures = {
31
41
  selectParametersData(stateFactory(applicationDefinitionConfData_1)),
32
42
  'should return columns from applicationDefinitionConfData_1 fixtures': () =>
33
43
  selectColumns(stateFactory(applicationDefinitionConfData_1)),
44
+ 'should return hiddenForemanParameterTypes from applicationDefinitionConfData_1 fixtures': () =>
45
+ selectHiddenForemanParameterTypes(stateFactory(applicationDefinitionConfData_1)),
34
46
  'should return ansibleVarsAll from applicationDefinitionConfData_1 fixtures': () =>
35
47
  selectAnsibleVarsAll(stateFactory(applicationDefinitionConfData_1)),
36
48
  'should return ParamEditMode from applicationDefinitionConfData_1 fixtures': () =>
@@ -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>
@@ -109,6 +134,7 @@ exports[`ApplicationDefinition should render application definition 1`] = `
109
134
  <Connect(ParameterSelection)
110
135
  data={Object {}}
111
136
  editModeCallback={[Function]}
137
+ hiddenParameterTypes={Array []}
112
138
  location="Default Location"
113
139
  organization="Default Organization"
114
140
  paramDataUrl="url/does/not/exist"
@@ -185,13 +211,13 @@ exports[`ApplicationDefinition should render application definition 1`] = `
185
211
  </ForemanModal>
186
212
  </div>
187
213
  <RailsData
188
- key="applications_definition"
214
+ key="application_definition_services_data"
189
215
  parameter="services"
190
216
  value="[]"
191
217
  view="app_definition"
192
218
  />
193
219
  <RailsData
194
- key="applications_definition"
220
+ key="application_definition_ansible_data"
195
221
  parameter="ansible_vars_all"
196
222
  value="[]"
197
223
  view="app_definition"
@@ -2,6 +2,10 @@
2
2
 
3
3
  exports[`ApplicationDefinitionSelectors should return ParamEditMode from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
4
4
 
5
+ exports[`ApplicationDefinitionSelectors should return alertModalText from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
6
+
7
+ exports[`ApplicationDefinitionSelectors should return alertModalTitle from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
8
+
5
9
  exports[`ApplicationDefinitionSelectors should return ansiblePlaybook from applicationDefinitionConfData_1 fixtures 1`] = `
6
10
  Object {
7
11
  "groups": Object {
@@ -214,6 +218,8 @@ Array [
214
218
 
215
219
  exports[`ApplicationDefinitionSelectors should return editMode from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
216
220
 
221
+ exports[`ApplicationDefinitionSelectors should return hiddenForemanParameterTypes from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
222
+
217
223
  exports[`ApplicationDefinitionSelectors should return parametersData from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
218
224
 
219
225
  exports[`ApplicationDefinitionSelectors should return services from applicationDefinitionConfData_1 fixtures 1`] = `
@@ -297,3 +303,5 @@ Array [
297
303
  },
298
304
  ]
299
305
  `;
306
+
307
+ exports[`ApplicationDefinitionSelectors should return showAlertModal from applicationDefinitionConfData_1 fixtures 1`] = `undefined`;
@@ -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,20 +6,28 @@ 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,
12
15
  selectColumns,
16
+ selectHiddenForemanParameterTypes,
13
17
  selectParametersData,
14
18
  selectAnsibleVarsAll,
15
19
  selectParamEditMode,
16
20
  } from './ApplicationDefinitionSelectors';
17
21
 
18
22
  const mapStateToProps = state => ({
23
+ showAlertModal: selectShowAlertModal(state),
24
+ alertModalText: selectAlertModalText(state),
25
+ alertModalTitle: selectAlertModalTitle(state),
19
26
  editMode: selectEditMode(state),
20
27
  ansiblePlaybook: selectAnsiblePlaybook(state),
21
28
  services: selectServices(state),
22
29
  columns: selectColumns(state),
30
+ hiddenForemanParameterTypes: selectHiddenForemanParameterTypes(state),
23
31
  parametersData: selectParametersData(state),
24
32
  ansibleVarsAll: selectAnsibleVarsAll(state),
25
33
  paramEditMode: selectParamEditMode(state),
@@ -0,0 +1,214 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ cloneDeep,
4
+ } from 'lodash';
5
+ import PropTypes from 'prop-types';
6
+ import {
7
+ Icon,
8
+ Button,
9
+ MessageDialog,
10
+ } from 'patternfly-react';
11
+ import * as resolve from 'table-resolver';
12
+ import Select from 'foremanReact/components/common/forms/Select';
13
+ import CommonForm from 'foremanReact/components/common/forms/CommonForm';
14
+ import AddTableEntry from '../common/AddTableEntry';
15
+ import DeleteTableEntry from '../common/DeleteTableEntry';
16
+ import RailsData from '../common/RailsData';
17
+ import { EasyHeaderFormatter } from '../../helper';
18
+ import { translate as __ } from 'foremanReact/common/I18n';
19
+
20
+ import {
21
+ Table,
22
+ FormControl,
23
+ inlineEditFormatterFactory,
24
+ } from 'patternfly-react';
25
+
26
+ class ApplicationDefinitionImport extends React.Component {
27
+
28
+ constructor(props) {
29
+ super(props);
30
+ }
31
+
32
+ onFileChange = event => {
33
+ // Update the state
34
+ this.setState({ selectedFile: event.target.files[0] });
35
+
36
+ };
37
+
38
+ isEditing({rowData}) {
39
+ return (rowData.backup !== undefined);
40
+ }
41
+
42
+ setAnsiblePlaybookServices() {
43
+ this.setState({ansiblePlaybookServices: this.props.ansiblePlaybookServices});
44
+ }
45
+
46
+ componentDidMount() {
47
+ const {
48
+ mode,
49
+ ansiblePlaybookServices,
50
+ hostgroups, } = this.props;
51
+
52
+ const {
53
+ initApplicationDefinitionImport,
54
+ changeEditApplicationDefinitionImportService,
55
+ handleImportAnsiblePlaybook,
56
+ } = this.props;
57
+
58
+ this.headerFormatter = EasyHeaderFormatter;
59
+
60
+ const inlineEditFormatterImpl = {
61
+ renderValue: (value, additionalData) => (
62
+ <td>
63
+ <span className="static">{value}</span>
64
+ </td>
65
+ ),
66
+ renderEditSelect: (value, additionalData, options) => (
67
+ <td className="editing">
68
+ <Select
69
+ value={value.toString()}
70
+ onChange={e => changeEditApplicationDefinitionImportService(e.target.value, additionalData) }
71
+ options={options}
72
+ allowClear
73
+ key="key"
74
+ />
75
+ </td>
76
+ )
77
+ };
78
+
79
+ const inlineEditFormatter = inlineEditFormatterFactory({
80
+ isEditing: additionalData => this.isEditing(additionalData),
81
+ renderValue: (value, additionalData) => {
82
+ let prettyValue = value;
83
+ if (additionalData.property == 'hostgroup') {
84
+ prettyValue = hostgroups[value];
85
+ }
86
+ return inlineEditFormatterImpl.renderValue(prettyValue, additionalData)
87
+ },
88
+ renderEdit: (value, additionalData) => {
89
+ if (additionalData.property == 'hostgroup') {
90
+ if (additionalData.rowData) {
91
+ return inlineEditFormatterImpl.renderEditSelect(value, additionalData, hostgroups);
92
+ }
93
+ return inlineEditFormatterImpl.renderValue(hostgroups[value], additionalData)
94
+ }
95
+ return inlineEditFormatterImpl.renderValue(value, additionalData);
96
+ }
97
+ });
98
+ this.inlineEditFormatter = inlineEditFormatter;
99
+
100
+ initApplicationDefinitionImport(
101
+ ansiblePlaybookServices,
102
+ this.headerFormatter,
103
+ this.inlineEditFormatter,
104
+ );
105
+ };
106
+
107
+ render() {
108
+ const {
109
+ organization,
110
+ location,
111
+ foremanDataUrl,
112
+ mode,} = this.props;
113
+
114
+ const {
115
+ showAlertModal,
116
+ alertModalText,
117
+ alertModalTitle,
118
+ closeAlertModal,
119
+ ansiblePlaybookServices,
120
+ columns,
121
+ handleImportAnsiblePlaybook,
122
+ } = this.props;
123
+ let ansibleServices;
124
+
125
+ return (
126
+ <span>
127
+ {ansibleServices = this.setAnsiblePlaybookServices}
128
+ {ansibleServices}
129
+ <MessageDialog
130
+ show={showAlertModal}
131
+ onHide={closeAlertModal}
132
+ primaryAction={closeAlertModal}
133
+ primaryActionButtonContent={__('OK')}
134
+ primaryActionButtonBsStyle={"danger"}
135
+ icon={<Icon type="pf" name="error-circle-o" />}
136
+ title={alertModalTitle}
137
+ primaryContent={alertModalText}
138
+ />
139
+ <div>
140
+ <CommonForm label="Application Definition file" className="custom-file-upload">
141
+ <input
142
+ type="file"
143
+ onChange={this.onFileChange}
144
+ />
145
+ </CommonForm>
146
+ <CommonForm>
147
+ <Button
148
+ bsStyle="default"
149
+ onClick={e => handleImportAnsiblePlaybook(this.state.selectedFile, e)}
150
+ >
151
+ {__('Import')} </Button>
152
+ </CommonForm>
153
+ </div>
154
+
155
+ {(Object.keys(this.props.ansiblePlaybookServices).length > 0) ? (
156
+ <div className="form-group">
157
+ <Table.PfProvider
158
+ striped
159
+ bordered
160
+ hover
161
+ dataTable
162
+ columns={columns}
163
+ components={{
164
+ body: {
165
+ cell: cellProps => cellProps.children
166
+ }
167
+ }}
168
+ >
169
+ <Table.Header headerRows={resolve.headerRows({ columns })} />
170
+ <Table.Body
171
+ rows={this.props.ansiblePlaybookServices}
172
+ rowKey="id"
173
+ onRow={(rowData, { rowIndex }) => ({
174
+ role: 'row',
175
+ isEditing: () => this.isEditing({ rowData }),
176
+ last: rowIndex === this.props.ansiblePlaybookServices.length - 1
177
+ })}
178
+ />
179
+ </Table.PfProvider>
180
+ </div>) : null }
181
+ <RailsData
182
+ key='applications_definition_import'
183
+ view='app_definition_import'
184
+ parameter='services'
185
+ value={JSON.stringify(this.props.ansiblePlaybookServices)}
186
+ />
187
+ </span>
188
+ )};
189
+ }
190
+
191
+ ApplicationDefinitionImport.defaultProps = {
192
+ error: {},
193
+ showAlertModal: false,
194
+ alertModalText: '',
195
+ alertModalTitle: '',
196
+ editMode: false,
197
+ columns: [],
198
+ ansiblePlaybookServices: {},
199
+ editParamsOfRowId: null,
200
+ }
201
+
202
+ ApplicationDefinitionImport.propTypes = {
203
+ initApplicationDefinitionImport: PropTypes.func,
204
+ editMode: PropTypes.bool.isRequired,
205
+ columns: PropTypes.array,
206
+ showAlertModal: PropTypes.bool,
207
+ alertModalText: PropTypes.string,
208
+ alertModalTitle: PropTypes.string,
209
+ closeAlertModal: PropTypes.func,
210
+ handleImportAnsiblePlaybook: PropTypes.func,
211
+ changeEditApplicationDefinitionImportService: PropTypes.func,
212
+ };
213
+
214
+ export default ApplicationDefinitionImport;
@@ -0,0 +1 @@
1
+ @import '~@theforeman/vendor/scss/variables';
@@ -0,0 +1,161 @@
1
+ import React from 'react';
2
+ import { API, actionTypeGenerator } from 'foremanReact/redux/API';
3
+ import { addToast } from 'foremanReact/components/ToastsList';
4
+ import { sprintf, translate as __ } from 'foremanReact/common/I18n';
5
+
6
+
7
+ import {
8
+ setModalOpen,
9
+ setModalClosed,
10
+ } from 'foremanReact/components/ForemanModal/ForemanModalActions';
11
+
12
+ import {
13
+ actionHeaderCellFormatter,
14
+ } from 'patternfly-react';
15
+
16
+ import {
17
+ propsToSnakeCase,
18
+ propsToCamelCase,
19
+ } from 'foremanReact/common/helpers';
20
+
21
+ import {
22
+ APPLICATION_DEFINITION_IMPORT_INIT,
23
+ APPLICATION_DEFINITION_IMPORT_CLOSE_ALERT_MODAL,
24
+ APPLICATION_DEFINITION_IMPORT_SERVICE_EDIT_CHANGE,
25
+ APPLICATION_DEFINITION_IMPORT_FILE_REQUEST,
26
+ APPLICATION_DEFINITION_IMPORT_FILE_SUCCESS,
27
+ APPLICATION_DEFINITION_IMPORT_FILE_FAILURE,
28
+ } from './ApplicationDefinitionImportConstants';
29
+
30
+
31
+ export const initApplicationDefinitionImport = (
32
+ ansiblePlaybookServices,
33
+ headerFormatter,
34
+ inlineEditFormatter,
35
+ ) => dispatch => {
36
+ const initialState = {};
37
+
38
+ initialState.columns = [
39
+ {
40
+ property: 'name',
41
+ header: {
42
+ label: 'Service name',
43
+ formatters: [headerFormatter],
44
+ props: {
45
+ index: 0,
46
+ style: {
47
+ width: '20%'
48
+ }
49
+ },
50
+ },
51
+ cell: {
52
+ props: {
53
+ index: 0,
54
+ },
55
+ formatters: [inlineEditFormatter]
56
+ }
57
+ },
58
+ {
59
+ property: 'hostgroup',
60
+ header: {
61
+ label: 'Hostgroup',
62
+ formatters: [headerFormatter],
63
+ props: {
64
+ index: 1,
65
+ style: {
66
+ width: '20%'
67
+ }
68
+ },
69
+ },
70
+ cell: {
71
+ props: {
72
+ index: 1,
73
+ },
74
+ formatters: [inlineEditFormatter]
75
+ }
76
+ }
77
+ ];
78
+
79
+ initialState.ansiblePlaybookServices = ansiblePlaybookServices;
80
+
81
+ dispatch({
82
+ type: APPLICATION_DEFINITION_IMPORT_INIT,
83
+ payload: initialState,
84
+ });
85
+ };
86
+
87
+
88
+ const errorHandler = (msg, err) => {
89
+ const error = {
90
+ errorMsg: __('Failed to fetch data from server.'),
91
+ statusText: err,
92
+ };
93
+ return { type: msg, payload: { error } };
94
+ };
95
+
96
+ export const closeAlertModal = () => ({
97
+ type: APPLICATION_DEFINITION_IMPORT_CLOSE_ALERT_MODAL,
98
+ payload: {}
99
+ });
100
+
101
+ export const changeEditApplicationDefinitionImportService = (value, additionalData) => ({
102
+ type: APPLICATION_DEFINITION_IMPORT_SERVICE_EDIT_CHANGE,
103
+ payload: {
104
+ value,
105
+ ...additionalData,
106
+ },
107
+ });
108
+
109
+
110
+ export const handleImportAnsiblePlaybook = (
111
+ file, e,) => async dispatch => {
112
+ e.preventDefault();
113
+ dispatch({
114
+ type: APPLICATION_DEFINITION_IMPORT_FILE_REQUEST,
115
+ payload: {
116
+ app_definition_file: file,
117
+ }});
118
+ try {
119
+ const formData = new FormData();
120
+
121
+ // Update the formData object
122
+ formData.append(
123
+ "app_definition_file",
124
+ file,
125
+ file.name
126
+ );
127
+ const { data } = await API.post(
128
+ '/acd/app_definitions/handle_file_upload', formData);
129
+ dispatch(
130
+ addToast({
131
+ type: 'success',
132
+ message: sprintf(
133
+ __('Sucessfully synced imported app template')
134
+ ),
135
+ key: APPLICATION_DEFINITION_IMPORT_FILE_SUCCESS,
136
+ })
137
+ );
138
+ return dispatch({
139
+ type: APPLICATION_DEFINITION_IMPORT_FILE_SUCCESS,
140
+ payload: {
141
+ ansiblePlaybookServices: data,
142
+ },
143
+ response: data,
144
+ });
145
+ } catch (error) {
146
+ dispatch(
147
+ addToast({
148
+ type: 'error',
149
+ message: sprintf(__('Error occurred while importing app template: %s'), error.response.data.message),
150
+ key: APPLICATION_DEFINITION_IMPORT_FILE_FAILURE,
151
+ })
152
+ );
153
+ return dispatch({
154
+ type: APPLICATION_DEFINITION_IMPORT_FILE_FAILURE,
155
+ payload: {
156
+ error: error,
157
+ },
158
+ response: error,
159
+ });
160
+ }
161
+ };