foreman_acd 0.0.6 → 0.2.1

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_acd/api/v2/app_definitions_controller.rb +1 -2
  3. data/app/controllers/foreman_acd/app_definitions_controller.rb +29 -1
  4. data/app/controllers/foreman_acd/app_instances_controller.rb +70 -21
  5. data/app/controllers/foreman_acd/concerns/app_definition_parameters.rb +1 -1
  6. data/app/controllers/foreman_acd/concerns/app_instance_parameters.rb +1 -1
  7. data/app/controllers/ui_acd_controller.rb +0 -1
  8. data/app/models/foreman_acd/app_definition.rb +0 -1
  9. data/app/views/foreman_acd/app_definitions/_form.html.erb +6 -14
  10. data/app/views/foreman_acd/app_definitions/import.html.erb +18 -0
  11. data/app/views/foreman_acd/app_definitions/index.html.erb +9 -5
  12. data/app/views/foreman_acd/app_instances/_form.html.erb +5 -5
  13. data/app/views/foreman_acd/app_instances/deploy.html.erb +19 -0
  14. data/app/views/foreman_acd/app_instances/index.html.erb +6 -5
  15. data/app/views/foreman_acd/app_instances/report.html.erb +19 -0
  16. data/app/views/ui_acd/app_definition.json.rabl +1 -1
  17. data/config/routes.rb +7 -0
  18. data/db/migrate/20190610202252_create_app_definitions.rb +1 -3
  19. data/db/migrate/20190625140305_create_app_instances.rb +1 -1
  20. data/lib/foreman_acd/plugin.rb +19 -2
  21. data/lib/foreman_acd/version.rb +1 -1
  22. data/webpack/components/ApplicationDefinition/ApplicationDefinition.js +261 -0
  23. data/webpack/components/ApplicationDefinition/ApplicationDefinition.scss +1 -0
  24. data/webpack/components/ApplicationDefinition/ApplicationDefinitionActions.js +211 -0
  25. data/webpack/components/ApplicationDefinition/ApplicationDefinitionConstants.js +9 -0
  26. data/webpack/components/ApplicationDefinition/ApplicationDefinitionReducer.js +147 -0
  27. data/webpack/components/ApplicationDefinition/ApplicationDefinitionSelectors.js +6 -0
  28. data/webpack/components/ApplicationDefinition/index.js +29 -0
  29. data/webpack/components/ApplicationInstance/ApplicationInstance.js +342 -0
  30. data/webpack/components/ApplicationInstance/ApplicationInstance.scss +11 -0
  31. data/webpack/components/ApplicationInstance/ApplicationInstanceActions.js +210 -0
  32. data/webpack/components/ApplicationInstance/ApplicationInstanceConstants.js +12 -0
  33. data/webpack/components/ApplicationInstance/ApplicationInstanceReducer.js +223 -0
  34. data/webpack/components/ApplicationInstance/ApplicationInstanceSelectors.js +8 -0
  35. data/webpack/components/ApplicationInstance/components/AppDefinitionSelector.js +49 -0
  36. data/webpack/components/ApplicationInstance/components/Service.js +30 -0
  37. data/webpack/components/ApplicationInstance/components/ServiceCounter.js +37 -0
  38. data/webpack/components/ApplicationInstance/index.js +33 -0
  39. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.js +155 -0
  40. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReport.scss +27 -0
  41. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportActions.js +86 -0
  42. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportConstants.js +4 -0
  43. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportReducer.js +52 -0
  44. data/webpack/components/ApplicationInstanceReport/ApplicationInstanceReportSelectors.js +5 -0
  45. data/webpack/components/ApplicationInstanceReport/components/ReportViewer.js +26 -0
  46. data/webpack/components/ApplicationInstanceReport/index.js +27 -0
  47. data/webpack/components/ParameterSelection/ParameterSelection.js +65 -161
  48. data/webpack/components/ParameterSelection/ParameterSelection.scss +9 -0
  49. data/webpack/components/ParameterSelection/ParameterSelectionActions.js +42 -71
  50. data/webpack/components/ParameterSelection/ParameterSelectionConstants.js +12 -19
  51. data/webpack/components/ParameterSelection/ParameterSelectionHelper.js +3 -3
  52. data/webpack/components/ParameterSelection/ParameterSelectionReducer.js +76 -75
  53. data/webpack/components/ParameterSelection/ParameterSelectionSelectors.js +2 -6
  54. data/webpack/components/ParameterSelection/__fixtures__/parameterSelection.fixtures.js +12 -21
  55. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionData_1.fixtures.js +1 -1
  56. data/webpack/components/ParameterSelection/__fixtures__/parameterSelectionReducer.fixtures.js +3 -45
  57. data/webpack/components/ParameterSelection/__tests__/ParameterSelection.test.js +20 -0
  58. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionReducer.test.js +22 -46
  59. data/webpack/components/ParameterSelection/__tests__/ParameterSelectionSelectors.test.js +6 -6
  60. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelection.test.js.snap +40 -265
  61. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionReducer.test.js.snap +11 -96
  62. data/webpack/components/ParameterSelection/__tests__/__snapshots__/ParameterSelectionSelectors.test.js.snap +3 -9
  63. data/webpack/components/ParameterSelection/index.js +4 -6
  64. data/webpack/components/common/AddTableEntry.js +30 -0
  65. data/webpack/components/common/DeleteTableEntry.js +39 -0
  66. data/webpack/components/common/ExtSelect.js +43 -0
  67. data/webpack/components/common/RailsData.js +27 -0
  68. data/webpack/components/common/__tests__/AddTableEntry.test.js +26 -0
  69. data/webpack/components/common/__tests__/DeleteTableEntry.test.js +29 -0
  70. data/webpack/components/common/__tests__/ExtSelect.test.js +38 -0
  71. data/webpack/components/common/__tests__/RailsData.test.js +16 -0
  72. data/webpack/components/common/__tests__/__snapshots__/AddParameter.test.js.snap +35 -0
  73. data/webpack/components/common/__tests__/__snapshots__/AddTableEntry.test.js.snap +35 -0
  74. data/webpack/components/common/__tests__/__snapshots__/DeleteParameter.test.js.snap +41 -0
  75. data/webpack/components/common/__tests__/__snapshots__/DeleteTableEntry.test.js.snap +41 -0
  76. data/webpack/components/common/__tests__/__snapshots__/ExtSelect.test.js.snap +18 -0
  77. data/webpack/components/common/__tests__/__snapshots__/RailsData.test.js.snap +10 -0
  78. data/webpack/helper.js +20 -0
  79. data/webpack/index.js +6 -0
  80. data/webpack/reducer.js +40 -3
  81. metadata +47 -46
@@ -0,0 +1,9 @@
1
+ export const APPLICATION_DEFINITION_INIT = 'INIT_APPLICATION_DEFINITION_INIT';
2
+ export const APPLICATION_DEFINITION_SERVICE_DELETE = 'APPLICATION_DEFINITION_SERVICE_DELETE';
3
+ export const APPLICATION_DEFINITION_SERVICE_ADD = 'APPLICATION_DEFINITION_SERVICE_ADD';
4
+ export const APPLICATION_DEFINITION_SERVICE_EDIT_ACTIVATE = 'APPLICATION_DEFINITION_SERVICE_EDIT_ACTIVATE';
5
+ export const APPLICATION_DEFINITION_SERVICE_EDIT_CONFIRM = 'APPLICATION_DEFINITION_SERVICE_EDIT_CONFIRM';
6
+ export const APPLICATION_DEFINITION_SERVICE_EDIT_CHANGE = 'APPLICATION_DEFINITION_SERVICE_EDIT_CHANGE';
7
+ export const APPLICATION_DEFINITION_SERVICE_EDIT_CANCEL = 'APPLICATION_DEFINITION_SERVICE_EDIT_CANCEL';
8
+ export const APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_OPEN = 'APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_OPEN';
9
+ export const APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_CLOSE = 'APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_CLOSE';
@@ -0,0 +1,147 @@
1
+ import Immutable from 'seamless-immutable';
2
+
3
+ import {
4
+ cloneDeep,
5
+ findIndex,
6
+ findLastIndex,
7
+ } from 'lodash';
8
+
9
+ import {
10
+ APPLICATION_DEFINITION_INIT,
11
+ APPLICATION_DEFINITION_SERVICE_DELETE,
12
+ APPLICATION_DEFINITION_SERVICE_ADD,
13
+ APPLICATION_DEFINITION_SERVICE_EDIT_ACTIVATE,
14
+ APPLICATION_DEFINITION_SERVICE_EDIT_CONFIRM,
15
+ APPLICATION_DEFINITION_SERVICE_EDIT_CHANGE,
16
+ APPLICATION_DEFINITION_SERVICE_EDIT_CANCEL,
17
+ APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_OPEN,
18
+ APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_CLOSE,
19
+ } from './ApplicationDefinitionConstants';
20
+
21
+ export const initialState = Immutable({
22
+ name: false,
23
+ error: { errorMsg: '', status: '', statusText: '' },
24
+ });
25
+
26
+ const applicationDefinitionConf = (state = initialState, action) => {
27
+ const { payload } = action;
28
+
29
+ switch (action.type) {
30
+ case APPLICATION_DEFINITION_INIT: {
31
+ return state.merge(payload);
32
+ }
33
+ case APPLICATION_DEFINITION_SERVICE_ADD: {
34
+ let services = [];
35
+ let index = 1;
36
+
37
+ if ('services' in state && state.services !== undefined && state.services.length > 0) {
38
+ services = cloneDeep(state.services);
39
+ index = Math.max(...services.map(e => e.id)) + 1;
40
+ }
41
+
42
+ const newRow = {id: index, name: "", description: '', hostgroup: '', minCount: '', maxCount: '', parameters: [], newEntry: true };
43
+ newRow.backup = cloneDeep(newRow)
44
+ services.push(newRow);
45
+
46
+ return state.merge({
47
+ editMode: true,
48
+ services: services
49
+ });
50
+ }
51
+ case APPLICATION_DEFINITION_SERVICE_DELETE: {
52
+ const services = state.services.filter(v => v.id !== payload.rowData.id);
53
+ return state.merge({
54
+ services: services,
55
+ })
56
+ }
57
+ case APPLICATION_DEFINITION_SERVICE_EDIT_ACTIVATE: {
58
+ const services = cloneDeep(state.services);
59
+ const index = findIndex(services, { id: payload.rowData.id });
60
+
61
+ services[index].backup = cloneDeep(services[index]);
62
+
63
+ return state.merge({
64
+ editMode: true,
65
+ services: services
66
+ });
67
+ }
68
+ case APPLICATION_DEFINITION_SERVICE_EDIT_CONFIRM: {
69
+ const services = cloneDeep(state.services);
70
+ const index = findIndex(services, { id: payload.rowData.id });
71
+
72
+ delete services[index].backup;
73
+ delete services[index].newEntry;
74
+
75
+ return state.merge({
76
+ editMode: false,
77
+ services: services
78
+ });
79
+ }
80
+ case APPLICATION_DEFINITION_SERVICE_EDIT_CHANGE: {
81
+ const services = cloneDeep(state.services);
82
+ const index = findIndex(services, { id: payload.rowData.id });
83
+
84
+ services[index][payload.property] = payload.value;
85
+
86
+ return state.set('services', services);
87
+ }
88
+ case APPLICATION_DEFINITION_SERVICE_EDIT_CANCEL: {
89
+ const services = cloneDeep(state.services);
90
+ const index = findIndex(services, { id: payload.rowData.id });
91
+
92
+ services[index] = cloneDeep(services[index].backup);
93
+ delete services[index].backup;
94
+
95
+ if (services[index].newEntry === true) {
96
+ services.splice(index, 1);
97
+ }
98
+
99
+ return state.merge({
100
+ editMode: false,
101
+ services: services
102
+ });
103
+ }
104
+ case APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_OPEN: {
105
+ let parametersData = {};
106
+
107
+ if (payload && payload.rowData) {
108
+ parametersData.serviceDefinition = {
109
+ id: payload.rowData.id,
110
+ name: payload.rowData.name,
111
+ hostgroup_id: payload.rowData.hostgroup
112
+ }
113
+ parametersData.parameters = payload.rowData.parameters;
114
+
115
+ if (parametersData.parameters.length > 0) {
116
+ parametersData.mode = 'editDefinition';
117
+ } else {
118
+ parametersData.mode = 'newDefinition';
119
+ }
120
+ }
121
+
122
+ return state.merge({
123
+ parametersData: parametersData,
124
+ });
125
+ }
126
+ case APPLICATION_DEFINITION_PARAMETER_SELECTION_MODAL_CLOSE: {
127
+ if (payload.mode == 'save') {
128
+ const services = cloneDeep(state.services);
129
+ const index = findIndex(services, { id: state.parametersData.serviceDefinition.id });
130
+ services[index].parameters = cloneDeep(payload.serviceParameterSelection);
131
+
132
+ return state.merge({
133
+ parametersData: null,
134
+ services: services,
135
+ });
136
+ } else {
137
+ return state.merge({
138
+ parametersData: null,
139
+ });
140
+ }
141
+ }
142
+ default:
143
+ return state;
144
+ }
145
+ };
146
+
147
+ export default applicationDefinitionConf;
@@ -0,0 +1,6 @@
1
+ const applicationDefinitionConf = state => state.foremanAcd.applicationDefinitionConf;
2
+
3
+ export const selectEditMode = state => applicationDefinitionConf(state).editMode;
4
+ export const selectServices = state => applicationDefinitionConf(state).services;
5
+ export const selectColumns = state => applicationDefinitionConf(state).columns;
6
+ export const selectParametersData = state => applicationDefinitionConf(state).parametersData;
@@ -0,0 +1,29 @@
1
+ import { bindActionCreators } from 'redux';
2
+ import { connect } from 'react-redux';
3
+
4
+ import './ApplicationDefinition.scss';
5
+ import ApplicationDefinition from './ApplicationDefinition';
6
+ import * as ApplicationDefinitionActions from './ApplicationDefinitionActions';
7
+
8
+ import {
9
+ selectEditMode,
10
+ selectServices,
11
+ selectColumns,
12
+ selectParametersData,
13
+ } from './ApplicationDefinitionSelectors';
14
+
15
+ const mapStateToProps = state => ({
16
+ editMode: selectEditMode(state),
17
+ services: selectServices(state),
18
+ columns: selectColumns(state),
19
+ parametersData: selectParametersData(state),
20
+ });
21
+
22
+ const mapDispatchToProps = dispatch =>
23
+ bindActionCreators(ApplicationDefinitionActions, dispatch);
24
+
25
+ export default connect(
26
+ mapStateToProps,
27
+ mapDispatchToProps
28
+ )(ApplicationDefinition);
29
+
@@ -0,0 +1,342 @@
1
+ import React, { useState } from 'react'
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ Icon,
5
+ Button,
6
+ } from 'patternfly-react';
7
+ import * as resolve from 'table-resolver';
8
+ import ForemanModal from 'foremanReact/components/ForemanModal';
9
+ import Select from 'foremanReact/components/common/forms/Select';
10
+ import ParameterSelection from '../ParameterSelection';
11
+ import AddTableEntry from '../common/AddTableEntry';
12
+ import DeleteTableEntry from '../common/DeleteTableEntry';
13
+ import RailsData from '../common/RailsData'
14
+ import AppDefinitionSelector from './components/AppDefinitionSelector';
15
+ import ServiceCounter from './components/ServiceCounter';
16
+ import { arrayToObject } from '../../helper';
17
+
18
+ import {
19
+ Table,
20
+ FormControl,
21
+ inlineEditFormatterFactory,
22
+ } from 'patternfly-react';
23
+
24
+ class ApplicationInstance extends React.Component {
25
+
26
+ constructor(props) {
27
+ super(props);
28
+ }
29
+
30
+ isEditing({rowData}) {
31
+ return (rowData.backup !== undefined);
32
+ }
33
+
34
+ validateParameters() {
35
+ let result = true;
36
+ let msg = "";
37
+
38
+ this.props.hosts.forEach(h => {
39
+ if (h.parameters.map(e => e.value).filter(i => i == "").length > 0) {
40
+ result = false;
41
+
42
+ if (msg == "") {
43
+ msg += "For some hosts the values for some parameters are missing. Check the values for these hosts:\n";
44
+ }
45
+ msg += "- "+ h.hostname +"\n";
46
+ }
47
+ });
48
+
49
+ const invalidMinServices = this.props.services.filter(s => (Number(s.minCount) != 0) && (s.currentCount < s.minCount));
50
+ const invalidMaxServices = this.props.services.filter(s => (Number(s.maxCount) != 0) && (s.currentCount > s.maxCount));
51
+
52
+ if (invalidMinServices.length > 0 || invalidMaxServices.length > 0) {
53
+ result = false;
54
+
55
+ if (msg != "") {
56
+ msg += "\n";
57
+ }
58
+ msg += "Unachieved service counts: \n";
59
+
60
+ invalidMinServices.map(s => { msg += "- service "+ s.name +" expects at least "+ s.minCount +" configured hosts" });
61
+ invalidMaxServices.map(s => { msg += "- service "+ s.name +" expects no more than "+ s.maxCount +" configured hosts" });
62
+ }
63
+
64
+ if (result === false) {
65
+ window.alert(msg);
66
+ }
67
+ return result;
68
+ }
69
+
70
+ componentDidMount() {
71
+ const {
72
+ data: { mode, appDefinition, hosts, loadAppDefinitionUrl },
73
+ initApplicationInstance,
74
+ addApplicationInstanceHost,
75
+ deleteApplicationInstanceHost,
76
+ activateEditApplicationInstanceHost,
77
+ changeEditApplicationInstanceHost,
78
+ openParameterSelectionModal,
79
+ closeParameterSelectionModal,
80
+ loadApplicationDefinition,
81
+ } = this.props;
82
+
83
+ if (mode === 'editInstance') {
84
+ loadApplicationDefinition(appDefinition.id, { url: loadAppDefinitionUrl });
85
+ }
86
+
87
+ const inlineEditButtonsFormatter = inlineEditFormatterFactory({
88
+ isEditing: additionalData => this.props.editMode,
89
+ renderValue: (value, additionalData) => (
90
+ <td style={{ padding: '2px' }}>
91
+ <Button
92
+ bsStyle="default"
93
+ onClick={() => activateEditApplicationInstanceHost(additionalData)}
94
+ >
95
+ <Icon type="pf" name="edit" />
96
+ </Button>
97
+ <Button
98
+ bsStyle="default"
99
+ onClick={() => openParameterSelectionModal(additionalData)}
100
+ >
101
+ <Icon type="pf" name="settings" />
102
+ </Button>
103
+ <DeleteTableEntry
104
+ hidden={false}
105
+ disabled={false}
106
+ onDeleteTableEntry={deleteApplicationInstanceHost}
107
+ additionalData={additionalData}
108
+ />
109
+ </td>
110
+ ),
111
+ renderEdit: (value, additionalData) => (
112
+ <td style={{ padding: '2px' }}>
113
+ <Button bsStyle="default" disabled>
114
+ <Icon type="pf" name="edit" />
115
+ </Button>
116
+ <Button bsStyle="default" disabled>
117
+ <Icon type="pf" name="settings" />
118
+ </Button>
119
+ <DeleteTableEntry
120
+ hidden={false}
121
+ disabled={true}
122
+ onDeleteTableEntry={deleteApplicationInstanceHost}
123
+ additionalData={additionalData}
124
+ />
125
+ </td>
126
+ )
127
+ });
128
+ this.inlineEditButtonsFormatter = inlineEditButtonsFormatter;
129
+
130
+ const headerFormatter = value => <Table.Heading>{value}</Table.Heading>;
131
+ this.headerFormatter = headerFormatter;
132
+
133
+ const inlineEditFormatterImpl = {
134
+ renderValue: (value, additionalData) => (
135
+ <td>
136
+ <span className="static">{value}</span>
137
+ </td>
138
+ ),
139
+ renderEditText: (value, additionalData, subtype='text') => (
140
+ <td className="editing">
141
+ <FormControl
142
+ type={subtype}
143
+ defaultValue={value}
144
+ onBlur={e => changeEditApplicationInstanceHost(e.target.value, additionalData) }
145
+ />
146
+ </td>
147
+ ),
148
+ renderEditSelect: (value, additionalData, options) => (
149
+ <td className="editing">
150
+ <Select
151
+ value={value.toString()}
152
+ onChange={e => changeEditApplicationInstanceHost(e.target.value, additionalData) }
153
+ options={options}
154
+ allowClear
155
+ key="key"
156
+ />
157
+ </td>
158
+ )
159
+ };
160
+
161
+ const inlineEditFormatter = inlineEditFormatterFactory({
162
+ isEditing: additionalData => this.isEditing(additionalData),
163
+ renderValue: (value, additionalData) => {
164
+ let prettyValue = value;
165
+ if (additionalData.property == 'service') {
166
+ const serviceList = arrayToObject(this.props.services, "id", "name");
167
+ prettyValue = serviceList[value];
168
+ }
169
+ return inlineEditFormatterImpl.renderValue(prettyValue, additionalData)
170
+ },
171
+ renderEdit: (value, additionalData) => {
172
+ let prettyValue = value;
173
+ if (additionalData.property == 'service') {
174
+ const availableServices = this.props.services.filter(service => ((Number(service['maxCount']) == 0) || (service['currentCount'] < service['maxCount'])));
175
+ const serviceList = arrayToObject(availableServices, "id", "name");
176
+
177
+ if (additionalData.rowData.newEntry === true) {
178
+ return inlineEditFormatterImpl.renderEditSelect(value, additionalData, serviceList);
179
+ }
180
+ prettyValue = serviceList[value];
181
+ return inlineEditFormatterImpl.renderValue(prettyValue, additionalData)
182
+ }
183
+ return inlineEditFormatterImpl.renderEditText(prettyValue, additionalData);
184
+ }
185
+ });
186
+ this.inlineEditFormatter = inlineEditFormatter;
187
+
188
+ initApplicationInstance(
189
+ appDefinition,
190
+ hosts,
191
+ this.headerFormatter,
192
+ this.inlineEditFormatter,
193
+ this.inlineEditButtonsFormatter,
194
+ );
195
+ };
196
+
197
+ render() {
198
+ const {
199
+ data: { mode, applications, organization, location, loadForemanDataUrl, loadAppDefinitionUrl },
200
+ appDefinition,
201
+ services,
202
+ hosts,
203
+ columns,
204
+ addApplicationInstanceHost,
205
+ confirmEditApplicationInstanceHost,
206
+ cancelEditApplicationInstanceHost,
207
+ openParameterSelectionModal,
208
+ closeParameterSelectionModal,
209
+ ParameterSelectionModal,
210
+ loadApplicationDefinition,
211
+ } = this.props;
212
+
213
+ // Start from validation when pressing submit. This should be in componentDidMount() but
214
+ // unfortunatley then the event wasn't fired. To make sure, that the on-click is only added
215
+ // once, there is a workaround to check if a css class "bound" exists.
216
+ $('input[type="submit"][name="commit"]:not(.bound)').addClass('bound').on('click', () => this.validateParameters());
217
+
218
+ return (
219
+ <span>
220
+ <div class="service-counter">
221
+ <ServiceCounter
222
+ title="Service counts"
223
+ serviceList={ services }
224
+ hostList={ hosts }
225
+ />
226
+ </div>
227
+ <div>
228
+ <AppDefinitionSelector
229
+ label="Application Definition"
230
+ editable={ mode == 'newInstance' }
231
+ viewText={ appDefinition.name }
232
+ options={ applications }
233
+ onChange={ loadApplicationDefinition }
234
+ selectValue={ appDefinition.id.toString() }
235
+ additionalData={{url: loadAppDefinitionUrl}}
236
+ />
237
+ </div>
238
+ <div className="form-group">
239
+ <AddTableEntry
240
+ hidden={ false }
241
+ disabled={ this.props.editMode }
242
+ onAddTableEntry={ addApplicationInstanceHost }
243
+ />
244
+ <Table.PfProvider
245
+ striped
246
+ bordered
247
+ hover
248
+ dataTable
249
+ inlineEdit
250
+ columns={columns}
251
+ components={{
252
+ body: {
253
+ row: Table.InlineEditRow,
254
+ cell: cellProps => cellProps.children
255
+ }
256
+ }}
257
+ >
258
+ <Table.Header headerRows={resolve.headerRows({ columns })} />
259
+ <Table.Body
260
+ rows={hosts}
261
+ rowKey="id"
262
+ onRow={(rowData, { rowIndex }) => ({
263
+ role: 'row',
264
+ isEditing: () => this.isEditing({ rowData }),
265
+ onCancel: () => cancelEditApplicationInstanceHost({ rowData, rowIndex }),
266
+ onConfirm: () => confirmEditApplicationInstanceHost({ rowData, rowIndex }),
267
+ last: rowIndex === services.length - 1
268
+ })}
269
+ />
270
+ </Table.PfProvider>
271
+ <AddTableEntry
272
+ hidden={ false }
273
+ disabled={ this.props.editMode }
274
+ onAddTableEntry={ addApplicationInstanceHost }
275
+ />
276
+ </div>
277
+ <div>
278
+ <ForemanModal
279
+ id="AppInstanceParamSelection"
280
+ dialogClassName="param_selection_modal"
281
+ title="Parameter specification for Application Instance"
282
+ >
283
+ <ForemanModal.Header closeButton={false}>
284
+ Parameter specification
285
+ </ForemanModal.Header>
286
+ {this.props.parametersData ? (
287
+ <ParameterSelection
288
+ location={ location }
289
+ organization={ organization }
290
+ loadForemanDataUrl= { loadForemanDataUrl }
291
+ data={ this.props.parametersData }
292
+ />
293
+ ) : (<span>Empty</span>)
294
+ }
295
+ <ForemanModal.Footer>
296
+ <div>
297
+ <Button bsStyle="primary" onClick={() => closeParameterSelectionModal({ mode: 'save' })}>Save</Button>
298
+ <Button bsStyle="default" onClick={() => closeParameterSelectionModal({ mode: 'cancel' })}>Cancel</Button>
299
+ </div>
300
+ </ForemanModal.Footer>
301
+ </ForemanModal>
302
+ </div>
303
+ <RailsData
304
+ key='applications_instance'
305
+ view='app_instance'
306
+ parameter='hosts'
307
+ value={JSON.stringify(this.props.hosts)}
308
+ />
309
+ </span>
310
+ )};
311
+ }
312
+
313
+ ApplicationInstance.defaultProps = {
314
+ error: {},
315
+ appDefinition: { "id": '', "name": '' },
316
+ editMode: false,
317
+ services: [],
318
+ hosts: [],
319
+ parametersData: {},
320
+ columns: [],
321
+ editParamsOfRowId: null,
322
+ }
323
+
324
+ ApplicationInstance.propTypes = {
325
+ initApplicationInstance: PropTypes.func,
326
+ editMode: PropTypes.bool.isRequired,
327
+ services: PropTypes.array,
328
+ appDefinition: PropTypes.object,
329
+ columns: PropTypes.array,
330
+ loadApplicationDefinition: PropTypes.func,
331
+ addApplicationInstanceHost: PropTypes.func,
332
+ deleteApplicationInstanceHost: PropTypes.func,
333
+ activateEditApplicationInstanceHost: PropTypes.func,
334
+ confirmEditApplicationInstanceHost: PropTypes.func,
335
+ cancelEditApplicationInstanceHost: PropTypes.func,
336
+ changeEditApplicationInstanceHost: PropTypes.func,
337
+ openParameterSelectionModal: PropTypes.func,
338
+ closeParameterSelectionModal: PropTypes.func,
339
+ parametersData: PropTypes.object,
340
+ };
341
+
342
+ export default ApplicationInstance;