foreman_templates 7.0.6 → 9.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/template_controller.rb +8 -2
  3. data/app/controllers/concerns/foreman/controller/parameters/template_params.rb +22 -2
  4. data/app/controllers/ui_template_syncs_controller.rb +2 -2
  5. data/app/models/setting/template_sync.rb +12 -2
  6. data/app/services/foreman_templates/export_result.rb +20 -29
  7. data/app/services/foreman_templates/template_exporter.rb +40 -32
  8. data/app/services/foreman_templates/template_importer.rb +20 -4
  9. data/app/views/template_syncs/index.html.erb +20 -19
  10. data/app/views/ui_template_syncs/template_export_result.rabl +4 -4
  11. data/db/migrate/20180627134929_change_lock_setting.rb +5 -0
  12. data/lib/foreman_templates/engine.rb +6 -0
  13. data/lib/foreman_templates/version.rb +1 -1
  14. data/package.json +15 -21
  15. data/webpack/ForemanTemplates.js +17 -13
  16. data/webpack/__mocks__/foremanReact/components/Layout/LayoutSelectors.js +4 -0
  17. data/webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js +2 -0
  18. data/webpack/components/NewTemplateSync/__fixtures__/templateSyncSettings.fixtures.js +4 -4
  19. data/webpack/components/NewTemplateSync/__tests__/__snapshots__/NewTemplateSync.test.js.snap +2 -2
  20. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncForm.js +89 -53
  21. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormSelectors.js +10 -13
  22. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncFormSelectors.test.js +1 -19
  23. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/__snapshots__/NewTemplateSyncFormSelectors.test.js.snap +7 -36
  24. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/index.js +7 -16
  25. data/webpack/components/NewTemplateSync/components/SyncSettingField.js +5 -11
  26. data/webpack/components/NewTemplateSync/components/SyncSettingFields.js +8 -25
  27. data/webpack/components/NewTemplateSync/components/TextButtonField/index.js +27 -20
  28. data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingField.test.js +2 -1
  29. data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingFields.test.js +1 -0
  30. data/webpack/components/NewTemplateSync/components/__tests__/TextButtonField.test.js +4 -4
  31. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingField.test.js.snap +18 -27
  32. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingFields.test.js.snap +5 -3
  33. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/TextButtonField.test.js.snap +8 -91
  34. data/webpack/components/TemplateSyncResult/__fixtures__/templateSyncResult.fixtures.js +2 -2
  35. data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResult.test.js.snap +3 -1
  36. data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResultReducer.test.js.snap +3 -1
  37. data/webpack/components/TemplateSyncResult/components/SyncResultList.js +2 -2
  38. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/__snapshots__/helpers.test.js.snap +37 -0
  39. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/helpers.js +21 -11
  40. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/helpers.test.js +21 -0
  41. data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncResultList.test.js.snap +8 -6
  42. data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncedTemplate.test.js.snap +39 -15
  43. data/webpack/testSetup.js +2 -1
  44. metadata +8 -8
  45. data/webpack/__mocks__/foremanReact/components/common/forms/Form.js +0 -2
  46. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormConstants.js +0 -1
  47. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncForm.test.js +0 -42
  48. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/__snapshots__/NewTemplateSyncForm.test.js.snap +0 -186
@@ -1,19 +1,17 @@
1
1
  import { connect } from 'react-redux';
2
- import { reduxForm } from 'redux-form';
3
2
 
4
3
  import * as FormActions from 'foremanReact/redux/actions/common/forms';
5
4
 
6
- import { NEW_TEMPLATE_SYNC_FORM_NAME } from './NewTemplateSyncFormConstants';
5
+ import { selectLayout } from 'foremanReact/components/Layout/LayoutSelectors';
6
+
7
7
  import NewTemplateSyncForm from './NewTemplateSyncForm';
8
8
 
9
9
  import {
10
10
  selectImportSettings,
11
11
  selectExportSettings,
12
12
  } from '../../NewTemplateSyncSelectors';
13
- import {
14
- selectInitialFormValues,
15
- selectRegisteredFields,
16
- } from './NewTemplateSyncFormSelectors';
13
+
14
+ import { selectInitialFormValues } from './NewTemplateSyncFormSelectors';
17
15
 
18
16
  const mapStateToProps = (state, ownProps) => {
19
17
  const importSettings = selectImportSettings(state);
@@ -22,20 +20,13 @@ const mapStateToProps = (state, ownProps) => {
22
20
 
23
21
  const initialFormValues = selectInitialFormValues(state);
24
22
 
25
- const currentFields = selectRegisteredFields(
26
- NEW_TEMPLATE_SYNC_FORM_NAME,
27
- state
28
- );
29
-
30
23
  return {
31
24
  initialValues: { ...initialFormValues },
32
25
  importSettings,
33
26
  exportSettings,
34
- currentFields,
27
+ currentOrganization: selectLayout(state).currentOrganization,
28
+ currentLocation: selectLayout(state).currentLocation,
35
29
  };
36
30
  };
37
31
 
38
- const form = reduxForm({ form: NEW_TEMPLATE_SYNC_FORM_NAME })(
39
- NewTemplateSyncForm
40
- );
41
- export default connect(mapStateToProps, FormActions)(form);
32
+ export default connect(mapStateToProps, FormActions)(NewTemplateSyncForm);
@@ -5,7 +5,7 @@ import { FieldLevelHelp } from 'patternfly-react';
5
5
  import TextButtonField from './TextButtonField';
6
6
  import ButtonTooltip from './ButtonTooltip';
7
7
 
8
- const SyncSettingField = ({ setting, resetField, disabled }) => {
8
+ const SyncSettingField = ({ setting, resetField, disabled, syncType }) => {
9
9
  const label = settingObj => `${settingObj.fullName} `;
10
10
 
11
11
  const fieldSelector = settingObj => {
@@ -20,10 +20,6 @@ const SyncSettingField = ({ setting, resetField, disabled }) => {
20
20
  return 'text';
21
21
  };
22
22
 
23
- const handleReset = (settingName, settingValue) => {
24
- resetField(settingName, settingValue);
25
- };
26
-
27
23
  const tooltipContent = (
28
24
  <div
29
25
  dangerouslySetInnerHTML={{
@@ -34,18 +30,15 @@ const SyncSettingField = ({ setting, resetField, disabled }) => {
34
30
 
35
31
  return (
36
32
  <TextButtonField
37
- name={setting.name}
33
+ name={`${syncType}.${setting.name}`}
38
34
  label={label(setting)}
39
35
  blank={{}}
40
36
  item={setting}
41
- buttonAttrs={{
42
- buttonText: <ButtonTooltip tooltipId={setting.name} />,
43
- buttonAction: () => handleReset(setting.name, setting.value),
44
- }}
37
+ buttonText={<ButtonTooltip tooltipId={setting.name} />}
38
+ buttonAction={resetField(`${syncType}.${setting.name}`, setting.value)}
45
39
  fieldSelector={fieldSelector}
46
40
  disabled={disabled}
47
41
  fieldRequired={setting.required}
48
- validate={setting.validate}
49
42
  tooltipHelp={<FieldLevelHelp content={tooltipContent} />}
50
43
  >
51
44
  {setting.value}
@@ -57,6 +50,7 @@ SyncSettingField.propTypes = {
57
50
  setting: PropTypes.object.isRequired,
58
51
  resetField: PropTypes.func.isRequired,
59
52
  disabled: PropTypes.bool.isRequired,
53
+ syncType: PropTypes.string.isRequired,
60
54
  };
61
55
 
62
56
  export default SyncSettingField;
@@ -1,36 +1,20 @@
1
1
  import React from 'react';
2
- import { memoize, upperFirst } from 'lodash';
2
+ import { upperFirst } from 'lodash';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
5
  import SyncSettingField from './SyncSettingField';
6
6
 
7
- const repoFormat = memoize(formatAry => value => {
8
- if (value) {
9
- const valid = formatAry
10
- .map(item => value.startsWith(item))
11
- .reduce((memo, item) => item || memo, false);
12
-
13
- if (valid) {
14
- return undefined;
15
- }
16
- }
17
-
18
- return `Invalid repo format, must start with one of: ${formatAry.join(', ')}`;
19
- });
20
-
21
7
  const SyncSettingsFields = ({
22
8
  importSettings,
23
9
  exportSettings,
24
10
  syncType,
25
11
  resetField,
26
- disabled,
27
- validationData,
12
+ formProps: { isSubmitting },
28
13
  }) => {
29
- const addValidationToSetting = (setting, validations) =>
14
+ const addRequiredToSetting = setting =>
30
15
  setting.name === 'repo'
31
16
  ? setting.merge({
32
17
  required: true,
33
- validate: [repoFormat(validations.repo)],
34
18
  })
35
19
  : setting;
36
20
 
@@ -58,14 +42,15 @@ const SyncSettingsFields = ({
58
42
  return (
59
43
  <React.Fragment>
60
44
  {settingsAry
61
- .map(setting => addValidationToSetting(setting, validationData))
45
+ .map(addRequiredToSetting)
62
46
  .map(setting => modifyDescription(setting, syncType))
63
47
  .map(setting => specializeDescription(setting, syncType))
64
48
  .map(setting => (
65
49
  <SyncSettingField
66
50
  setting={setting}
51
+ syncType={syncType}
67
52
  key={setting.name}
68
- disabled={disabled}
53
+ disabled={isSubmitting}
69
54
  resetField={resetField}
70
55
  />
71
56
  ))}
@@ -78,13 +63,11 @@ SyncSettingsFields.propTypes = {
78
63
  exportSettings: PropTypes.array.isRequired,
79
64
  syncType: PropTypes.string.isRequired,
80
65
  resetField: PropTypes.func.isRequired,
81
- disabled: PropTypes.bool,
82
- validationData: PropTypes.object,
66
+ formProps: PropTypes.object,
83
67
  };
84
68
 
85
69
  SyncSettingsFields.defaultProps = {
86
- disabled: false,
87
- validationData: {},
70
+ formProps: {},
88
71
  };
89
72
 
90
73
  export default SyncSettingsFields;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { Field } from 'redux-form';
2
+ import { get } from 'lodash';
3
+ import { Field as FormikField } from 'formik';
3
4
  import PropTypes from 'prop-types';
4
5
 
5
6
  import RenderField from './RenderField';
@@ -11,25 +12,35 @@ const TextButtonField = ({
11
12
  className,
12
13
  inputClassName,
13
14
  blank,
14
- buttonAttrs,
15
+ buttonText,
16
+ buttonAction,
15
17
  fieldSelector,
16
- validate,
17
18
  disabled,
18
19
  fieldRequired,
19
20
  tooltipHelp,
20
21
  }) => (
21
- <Field
22
+ <FormikField
22
23
  name={name}
23
- label={label}
24
- fieldSelector={fieldSelector}
25
- tooltipHelp={tooltipHelp}
26
- component={RenderField}
27
- buttonAttrs={buttonAttrs}
28
- blank={blank}
29
- item={item}
30
- disabled={disabled}
31
- validate={item.validate}
32
- fieldRequired={fieldRequired}
24
+ render={({ field, form }) => (
25
+ <RenderField
26
+ label={label}
27
+ fieldSelector={fieldSelector}
28
+ tooltipHelp={tooltipHelp}
29
+ buttonAttrs={{
30
+ buttonText,
31
+ buttonAction: () => buttonAction(form.setFieldValue),
32
+ }}
33
+ blank={blank}
34
+ item={item}
35
+ disabled={disabled}
36
+ fieldRequired={fieldRequired}
37
+ meta={{
38
+ touched: get(form.touched, name),
39
+ error: get(form.errors, name),
40
+ }}
41
+ input={field}
42
+ />
43
+ )}
33
44
  />
34
45
  );
35
46
 
@@ -43,12 +54,9 @@ TextButtonField.propTypes = {
43
54
  label: PropTypes.string,
44
55
  value: PropTypes.string,
45
56
  }),
46
- buttonAttrs: PropTypes.shape({
47
- buttonText: PropTypes.node,
48
- buttonAction: PropTypes.func,
49
- }).isRequired,
57
+ buttonText: PropTypes.node.isRequired,
58
+ buttonAction: PropTypes.func.isRequired,
50
59
  fieldSelector: PropTypes.func,
51
- validate: PropTypes.array,
52
60
  disabled: PropTypes.bool,
53
61
  fieldRequired: PropTypes.bool,
54
62
  tooltipHelp: PropTypes.node,
@@ -58,7 +66,6 @@ TextButtonField.defaultProps = {
58
66
  blank: { label: 'Choose one...', value: '' },
59
67
  className: '',
60
68
  inputClassName: 'col-md-6',
61
- validate: [],
62
69
  disabled: false,
63
70
  fieldRequired: false,
64
71
  tooltipHelp: null,
@@ -8,11 +8,12 @@ import {
8
8
  filterSetting,
9
9
  } from '../../__fixtures__/templateSyncSettings.fixtures';
10
10
 
11
- const noop = () => {};
11
+ const noop = () => () => {};
12
12
 
13
13
  const commonFixtures = {
14
14
  resetField: noop,
15
15
  disabled: false,
16
+ syncType: 'import',
16
17
  };
17
18
 
18
19
  const fixtures = {
@@ -13,6 +13,7 @@ const commonFixtures = {
13
13
  importSettings,
14
14
  exportSettings,
15
15
  resetField: noop,
16
+ formProps: { isSubmitting: false },
16
17
  disabled: false,
17
18
  };
18
19
 
@@ -29,7 +29,7 @@ const fixtures = {
29
29
  name: 'Text field',
30
30
  item: textItem,
31
31
  fieldSelector,
32
- buttonAttrs,
32
+ ...buttonAttrs,
33
33
  disabled: false,
34
34
  label: 'Text',
35
35
  blank: {},
@@ -38,7 +38,7 @@ const fixtures = {
38
38
  name: 'Checkbox field',
39
39
  item: checkboxItem,
40
40
  fieldSelector,
41
- buttonAttrs,
41
+ ...buttonAttrs,
42
42
  disabled: false,
43
43
  label: 'Checkbox',
44
44
  blank: {},
@@ -47,7 +47,7 @@ const fixtures = {
47
47
  name: 'select field',
48
48
  item: selectItem,
49
49
  fieldSelector,
50
- buttonAttrs,
50
+ ...buttonAttrs,
51
51
  label: 'Select',
52
52
  disabled: false,
53
53
  blank,
@@ -55,7 +55,7 @@ const fixtures = {
55
55
  'should render text field without field selector': {
56
56
  name: 'no selector',
57
57
  label: 'Text field',
58
- buttonAttrs,
58
+ ...buttonAttrs,
59
59
  disabled: false,
60
60
  blank: {},
61
61
  },
@@ -3,13 +3,11 @@
3
3
  exports[`SyncSettingField should render boolean setting as checkbox 1`] = `
4
4
  <TextButtonField
5
5
  blank={Object {}}
6
- buttonAttrs={
7
- Object {
8
- "buttonAction": [Function],
9
- "buttonText": <ButtonTooltip
10
- tooltipId="force"
11
- />,
12
- }
6
+ buttonAction={[Function]}
7
+ buttonText={
8
+ <ButtonTooltip
9
+ tooltipId="force"
10
+ />
13
11
  }
14
12
  className=""
15
13
  disabled={false}
@@ -26,7 +24,7 @@ exports[`SyncSettingField should render boolean setting as checkbox 1`] = `
26
24
  }
27
25
  }
28
26
  label="undefined "
29
- name="force"
27
+ name="import.force"
30
28
  tooltipHelp={
31
29
  <FieldLevelHelp
32
30
  buttonClass=""
@@ -43,20 +41,17 @@ exports[`SyncSettingField should render boolean setting as checkbox 1`] = `
43
41
  rootClose={true}
44
42
  />
45
43
  }
46
- validate={Array []}
47
44
  />
48
45
  `;
49
46
 
50
47
  exports[`SyncSettingField should render setting with input field 1`] = `
51
48
  <TextButtonField
52
49
  blank={Object {}}
53
- buttonAttrs={
54
- Object {
55
- "buttonAction": [Function],
56
- "buttonText": <ButtonTooltip
57
- tooltipId="filter"
58
- />,
59
- }
50
+ buttonAction={[Function]}
51
+ buttonText={
52
+ <ButtonTooltip
53
+ tooltipId="filter"
54
+ />
60
55
  }
61
56
  className=""
62
57
  disabled={false}
@@ -73,7 +68,7 @@ exports[`SyncSettingField should render setting with input field 1`] = `
73
68
  }
74
69
  }
75
70
  label="undefined "
76
- name="filter"
71
+ name="import.filter"
77
72
  tooltipHelp={
78
73
  <FieldLevelHelp
79
74
  buttonClass=""
@@ -90,20 +85,17 @@ exports[`SyncSettingField should render setting with input field 1`] = `
90
85
  rootClose={true}
91
86
  />
92
87
  }
93
- validate={Array []}
94
88
  />
95
89
  `;
96
90
 
97
91
  exports[`SyncSettingField should render setting with select choices 1`] = `
98
92
  <TextButtonField
99
93
  blank={Object {}}
100
- buttonAttrs={
101
- Object {
102
- "buttonAction": [Function],
103
- "buttonText": <ButtonTooltip
104
- tooltipId="associate"
105
- />,
106
- }
94
+ buttonAction={[Function]}
95
+ buttonText={
96
+ <ButtonTooltip
97
+ tooltipId="associate"
98
+ />
107
99
  }
108
100
  className=""
109
101
  disabled={false}
@@ -134,7 +126,7 @@ exports[`SyncSettingField should render setting with select choices 1`] = `
134
126
  }
135
127
  }
136
128
  label="undefined "
137
- name="associate"
129
+ name="import.associate"
138
130
  tooltipHelp={
139
131
  <FieldLevelHelp
140
132
  buttonClass=""
@@ -151,7 +143,6 @@ exports[`SyncSettingField should render setting with select choices 1`] = `
151
143
  rootClose={true}
152
144
  />
153
145
  }
154
- validate={Array []}
155
146
  >
156
147
  new
157
148
  </TextButtonField>
@@ -15,6 +15,7 @@ exports[`SyncSettingFields should show export settings 1`] = `
15
15
  "value": "",
16
16
  }
17
17
  }
18
+ syncType="export"
18
19
  />
19
20
  <SyncSettingField
20
21
  disabled={false}
@@ -29,6 +30,7 @@ exports[`SyncSettingFields should show export settings 1`] = `
29
30
  "value": false,
30
31
  }
31
32
  }
33
+ syncType="export"
32
34
  />
33
35
  <SyncSettingField
34
36
  disabled={false}
@@ -41,12 +43,10 @@ exports[`SyncSettingFields should show export settings 1`] = `
41
43
  "name": "repo",
42
44
  "required": true,
43
45
  "settingsType": "string",
44
- "validate": Array [
45
- [Function],
46
- ],
47
46
  "value": "https://github.com/theforeman/community-templates.git",
48
47
  }
49
48
  }
49
+ syncType="export"
50
50
  />
51
51
  </Fragment>
52
52
  `;
@@ -80,6 +80,7 @@ exports[`SyncSettingFields should show import settings 1`] = `
80
80
  "value": "new",
81
81
  }
82
82
  }
83
+ syncType="import"
83
84
  />
84
85
  <SyncSettingField
85
86
  disabled={false}
@@ -94,6 +95,7 @@ exports[`SyncSettingFields should show import settings 1`] = `
94
95
  "value": false,
95
96
  }
96
97
  }
98
+ syncType="import"
97
99
  />
98
100
  </Fragment>
99
101
  `;