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.
- checksums.yaml +4 -4
- data/app/controllers/api/v2/template_controller.rb +8 -2
- data/app/controllers/concerns/foreman/controller/parameters/template_params.rb +22 -2
- data/app/controllers/ui_template_syncs_controller.rb +2 -2
- data/app/models/setting/template_sync.rb +12 -2
- data/app/services/foreman_templates/export_result.rb +20 -29
- data/app/services/foreman_templates/template_exporter.rb +40 -32
- data/app/services/foreman_templates/template_importer.rb +20 -4
- data/app/views/template_syncs/index.html.erb +20 -19
- data/app/views/ui_template_syncs/template_export_result.rabl +4 -4
- data/db/migrate/20180627134929_change_lock_setting.rb +5 -0
- data/lib/foreman_templates/engine.rb +6 -0
- data/lib/foreman_templates/version.rb +1 -1
- data/package.json +15 -21
- data/webpack/ForemanTemplates.js +17 -13
- data/webpack/__mocks__/foremanReact/components/Layout/LayoutSelectors.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js +2 -0
- data/webpack/components/NewTemplateSync/__fixtures__/templateSyncSettings.fixtures.js +4 -4
- data/webpack/components/NewTemplateSync/__tests__/__snapshots__/NewTemplateSync.test.js.snap +2 -2
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncForm.js +89 -53
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormSelectors.js +10 -13
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncFormSelectors.test.js +1 -19
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/__snapshots__/NewTemplateSyncFormSelectors.test.js.snap +7 -36
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/index.js +7 -16
- data/webpack/components/NewTemplateSync/components/SyncSettingField.js +5 -11
- data/webpack/components/NewTemplateSync/components/SyncSettingFields.js +8 -25
- data/webpack/components/NewTemplateSync/components/TextButtonField/index.js +27 -20
- data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingField.test.js +2 -1
- data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingFields.test.js +1 -0
- data/webpack/components/NewTemplateSync/components/__tests__/TextButtonField.test.js +4 -4
- data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingField.test.js.snap +18 -27
- data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingFields.test.js.snap +5 -3
- data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/TextButtonField.test.js.snap +8 -91
- data/webpack/components/TemplateSyncResult/__fixtures__/templateSyncResult.fixtures.js +2 -2
- data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResult.test.js.snap +3 -1
- data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResultReducer.test.js.snap +3 -1
- data/webpack/components/TemplateSyncResult/components/SyncResultList.js +2 -2
- data/webpack/components/TemplateSyncResult/components/SyncedTemplate/__snapshots__/helpers.test.js.snap +37 -0
- data/webpack/components/TemplateSyncResult/components/SyncedTemplate/helpers.js +21 -11
- data/webpack/components/TemplateSyncResult/components/SyncedTemplate/helpers.test.js +21 -0
- data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncResultList.test.js.snap +8 -6
- data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncedTemplate.test.js.snap +39 -15
- data/webpack/testSetup.js +2 -1
- metadata +8 -8
- data/webpack/__mocks__/foremanReact/components/common/forms/Form.js +0 -2
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormConstants.js +0 -1
- data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncForm.test.js +0 -42
- 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 {
|
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
|
-
|
14
|
-
|
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
|
-
|
27
|
+
currentOrganization: selectLayout(state).currentOrganization,
|
28
|
+
currentLocation: selectLayout(state).currentLocation,
|
35
29
|
};
|
36
30
|
};
|
37
31
|
|
38
|
-
|
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
|
-
|
42
|
-
|
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 {
|
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
|
-
|
27
|
-
validationData,
|
12
|
+
formProps: { isSubmitting },
|
28
13
|
}) => {
|
29
|
-
const
|
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(
|
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={
|
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
|
-
|
82
|
-
validationData: PropTypes.object,
|
66
|
+
formProps: PropTypes.object,
|
83
67
|
};
|
84
68
|
|
85
69
|
SyncSettingsFields.defaultProps = {
|
86
|
-
|
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 {
|
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
|
-
|
15
|
+
buttonText,
|
16
|
+
buttonAction,
|
15
17
|
fieldSelector,
|
16
|
-
validate,
|
17
18
|
disabled,
|
18
19
|
fieldRequired,
|
19
20
|
tooltipHelp,
|
20
21
|
}) => (
|
21
|
-
<
|
22
|
+
<FormikField
|
22
23
|
name={name}
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
47
|
-
|
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 = {
|
@@ -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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
"
|
10
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
"
|
57
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
"
|
104
|
-
|
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
|
`;
|