foreman_ansible 2.3.6 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/ui_ansible_roles_controller.rb +14 -0
  3. data/app/helpers/foreman_ansible/ansible_roles_helper.rb +4 -0
  4. data/app/models/ansible_role.rb +1 -0
  5. data/app/models/foreman_ansible/ansible_provider.rb +6 -1
  6. data/app/models/setting/ansible.rb +10 -10
  7. data/app/services/foreman_ansible/inventory_creator.rb +26 -23
  8. data/app/views/foreman_ansible/ansible_roles/_select_tab_content.html.erb +13 -13
  9. data/app/views/ui_ansible_roles/index.json.rabl +3 -0
  10. data/app/views/ui_ansible_roles/main.json.rabl +3 -0
  11. data/app/views/ui_ansible_roles/show.json.rabl +3 -0
  12. data/config/routes.rb +2 -0
  13. data/db/migrate/20190328114657_remove_top_level_ansible_variables_setting.rb +6 -0
  14. data/lib/foreman_ansible/register.rb +3 -2
  15. data/lib/foreman_ansible/version.rb +1 -1
  16. data/locale/de/foreman_ansible.edit.po +90 -191
  17. data/locale/en/foreman_ansible.edit.po +90 -191
  18. data/locale/es/foreman_ansible.edit.po +90 -191
  19. data/locale/fr/foreman_ansible.edit.po +90 -191
  20. data/locale/it/foreman_ansible.edit.po +90 -191
  21. data/locale/ja/foreman_ansible.edit.po +90 -191
  22. data/locale/ko/foreman_ansible.edit.po +90 -191
  23. data/locale/pt_BR/foreman_ansible.edit.po +90 -191
  24. data/locale/ru/foreman_ansible.edit.po +90 -191
  25. data/locale/zh_CN/foreman_ansible.edit.po +90 -191
  26. data/locale/zh_TW/foreman_ansible.edit.po +90 -191
  27. data/package.json +50 -9
  28. data/test/factories/ansible_variables.rb +1 -0
  29. data/test/functional/ui_ansible_roles_controller_test.rb +14 -0
  30. data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +11 -11
  31. data/test/unit/services/inventory_creator_test.rb +75 -24
  32. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  33. data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +5 -0
  34. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.js +140 -0
  35. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.scss +45 -0
  36. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherActions.js +69 -0
  37. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherConstants.js +7 -0
  38. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherHelpers.js +7 -0
  39. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherReducer.js +69 -0
  40. data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherSelectors.js +68 -0
  41. data/webpack/components/AnsibleRolesSwitcher/__fixtures__/ansibleRolesData.fixtures.js +20 -0
  42. data/webpack/components/AnsibleRolesSwitcher/__fixtures__/ansibleRolesSwitcherReducer.fixtures.js +36 -0
  43. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcher.test.js +30 -0
  44. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcherReducer.test.js +73 -0
  45. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcherSelectors.test.js +43 -0
  46. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcher.test.js.snap +79 -0
  47. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcherReducer.test.js.snap +399 -0
  48. data/webpack/components/AnsibleRolesSwitcher/__tests__/__snapshots__/AnsibleRolesSwitcherSelectors.test.js.snap +60 -0
  49. data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.js +33 -0
  50. data/webpack/components/AnsibleRolesSwitcher/components/AnsiblePermissionDenied.test.js +9 -0
  51. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +56 -0
  52. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.test.js +26 -0
  53. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRoleActionButton.js +16 -0
  54. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRolesSwitcherError.js +32 -0
  55. data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.js +67 -0
  56. data/webpack/components/AnsibleRolesSwitcher/components/AssignedRolesList.test.js +19 -0
  57. data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.js +52 -0
  58. data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.test.js +22 -0
  59. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsiblePermissionDenied.test.js.snap +26 -0
  60. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsibleRole.test.js.snap +108 -0
  61. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap +64 -0
  62. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +54 -0
  63. data/webpack/components/AnsibleRolesSwitcher/components/withProtectedView.js +14 -0
  64. data/webpack/components/AnsibleRolesSwitcher/index.js +44 -0
  65. data/webpack/components/ReportJsonViewer.js +11 -7
  66. data/webpack/index.js +14 -1
  67. data/webpack/reducer.js +7 -0
  68. data/webpack/test_setup.js +11 -0
  69. metadata +44 -2
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { EmptyStatePattern as EmptyState } from 'foremanReact/components/common/EmptyState';
3
+
4
+ const AnsiblePermissionDenied = props => {
5
+ const description = (
6
+ <span>
7
+ {__('You are not authorized to perform this action.')}
8
+ <br />
9
+ {__(
10
+ 'Please request one of the required permissions listed below from a Foreman administrator:'
11
+ )}
12
+ <br />
13
+ </span>
14
+ );
15
+
16
+ const doc = (
17
+ <ul className="list-unstyled">
18
+ <li>view_ansible_roles</li>
19
+ </ul>
20
+ );
21
+
22
+ return (
23
+ <EmptyState
24
+ iconType="fa"
25
+ icon="lock"
26
+ header={__('Permission Denied')}
27
+ description={description}
28
+ documentation={doc}
29
+ />
30
+ );
31
+ };
32
+
33
+ export default AnsiblePermissionDenied;
@@ -0,0 +1,9 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+ import AnsiblePermissionDenied from './AnsiblePermissionDenied';
3
+
4
+ jest.mock('foremanReact/components/common/EmptyState');
5
+
6
+ describe('AnsiblePermissionDenied', () =>
7
+ testComponentSnapshotsWithFixtures(AnsiblePermissionDenied, {
8
+ 'should render': {},
9
+ }));
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { ListView, Tooltip, OverlayTrigger } from 'patternfly-react';
3
+ import classNames from 'classnames';
4
+
5
+ import AnsibleRoleActionButton from './AnsibleRoleActionButton';
6
+ import '../AnsibleRolesSwitcher.scss';
7
+
8
+ const AnsibleRole = ({ role, icon, onClick, resourceName }) => {
9
+ const text =
10
+ resourceName === 'hostgroup'
11
+ ? __('This Ansible role is inherited from parent host group')
12
+ : __('This Ansible role is inherited from host group');
13
+
14
+ const tooltip = (
15
+ <Tooltip id={role.id}>
16
+ <span>{text}</span>
17
+ </Tooltip>
18
+ );
19
+
20
+ const clickHandler = (onClickFn, ansibleRole) => event => {
21
+ event.preventDefault();
22
+ onClickFn(ansibleRole);
23
+ };
24
+
25
+ const listItem = (click = undefined) => (
26
+ <ListView.Item
27
+ id={role.id}
28
+ className={classNames('listViewItem--listItemVariants', {
29
+ 'ansible-role-disabled': role.inherited,
30
+ 'ansible-role-movable': !role.inherited,
31
+ })}
32
+ heading={role.name}
33
+ actions={
34
+ role.inherited ? (
35
+ ''
36
+ ) : (
37
+ <AnsibleRoleActionButton icon={icon} role={role} />
38
+ )
39
+ }
40
+ stacked
41
+ onClick={typeof click === 'function' ? click(onClick, role) : click}
42
+ />
43
+ );
44
+
45
+ if (role.inherited) {
46
+ return (
47
+ <OverlayTrigger overlay={tooltip} placement="top">
48
+ {listItem()}
49
+ </OverlayTrigger>
50
+ );
51
+ }
52
+
53
+ return listItem(clickHandler);
54
+ };
55
+
56
+ export default AnsibleRole;
@@ -0,0 +1,26 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import AnsibleRole from './AnsibleRole';
4
+
5
+ const noop = () => {};
6
+
7
+ const fixtures = {
8
+ 'should render a role to add': {
9
+ role: { name: 'test.role', id: 5 },
10
+ icon: 'fa fa-plus-circle',
11
+ onClick: noop,
12
+ },
13
+ 'should render a role to remove': {
14
+ role: { name: 'test.role', id: 5 },
15
+ icon: 'fa fa-minus-circle',
16
+ onClick: noop,
17
+ },
18
+ 'should render inherited role to remove': {
19
+ role: { name: 'test.role', id: 5, inherited: true },
20
+ icon: 'fa fa-minus-circle',
21
+ onClick: noop,
22
+ },
23
+ };
24
+
25
+ describe('AnsibleRole', () =>
26
+ testComponentSnapshotsWithFixtures(AnsibleRole, fixtures));
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import { Icon } from 'patternfly-react';
5
+
6
+ const AnsibleRoleActionButton = ({ icon }) => (
7
+ <button href="#" className="role-add-remove-btn">
8
+ <Icon className="fa-2x" type="fa" name={icon} />
9
+ </button>
10
+ );
11
+
12
+ AnsibleRoleActionButton.propTypes = {
13
+ icon: PropTypes.string.isRequired,
14
+ };
15
+
16
+ export default AnsibleRoleActionButton;
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { Col, Alert } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ const ErrorMsg = ({ error }) => {
6
+ const status = error.statusText ? `${error.statusText}: ` : '';
7
+ return `${status}${error.errorMsg}`;
8
+ };
9
+
10
+ const AnsibleRolesSwitcherError = ({ error }) =>
11
+ error && error.errorMsg ? (
12
+ <Col sm={12}>
13
+ <Alert type="error">
14
+ <ErrorMsg error={error} />
15
+ </Alert>
16
+ </Col>
17
+ ) : (
18
+ ''
19
+ );
20
+
21
+ AnsibleRolesSwitcherError.propTypes = {
22
+ error: PropTypes.shape({
23
+ errorMsg: PropTypes.string,
24
+ statusText: PropTypes.string,
25
+ }),
26
+ };
27
+
28
+ AnsibleRolesSwitcherError.defaultProps = {
29
+ error: {},
30
+ };
31
+
32
+ export default AnsibleRolesSwitcherError;
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { ListView } from 'patternfly-react';
3
+ import PaginationWrapper from 'foremanReact/components/Pagination/PaginationWrapper';
4
+ import { reject } from 'lodash';
5
+ import PropTypes from 'prop-types';
6
+
7
+ import AnsibleRole from './AnsibleRole';
8
+
9
+ const AssignedRolesList = ({
10
+ assignedRoles,
11
+ pagination,
12
+ itemCount,
13
+ onPaginationChange,
14
+ onRemoveRole,
15
+ resourceName,
16
+ }) => {
17
+ const directlyAssignedRoles = reject(assignedRoles, role => role.inherited);
18
+
19
+ return (
20
+ <div>
21
+ <ListView>
22
+ <div className="sticky-pagination sticky-pagination-grey">
23
+ <PaginationWrapper
24
+ viewType="list"
25
+ itemCount={itemCount}
26
+ pagination={pagination}
27
+ onChange={onPaginationChange}
28
+ dropdownButtonId="assigned-ansible-roles-pagination-row-dropdown"
29
+ />
30
+ </div>
31
+ {assignedRoles.map(role => (
32
+ <AnsibleRole
33
+ key={role.id}
34
+ role={role}
35
+ icon="fa fa-minus-circle"
36
+ onClick={onRemoveRole}
37
+ resourceName={resourceName}
38
+ />
39
+ ))}
40
+ </ListView>
41
+ <div>
42
+ {directlyAssignedRoles.map(role => (
43
+ <input
44
+ key={role.id}
45
+ type="hidden"
46
+ name={`${resourceName}[ansible_role_ids][]`}
47
+ value={role.id}
48
+ />
49
+ ))}
50
+ </div>
51
+ </div>
52
+ );
53
+ };
54
+
55
+ AssignedRolesList.propTypes = {
56
+ assignedRoles: PropTypes.arrayOf(PropTypes.object).isRequired,
57
+ pagination: PropTypes.shape({
58
+ page: PropTypes.number,
59
+ perPage: PropTypes.number,
60
+ }).isRequired,
61
+ itemCount: PropTypes.number.isRequired,
62
+ onPaginationChange: PropTypes.func.isRequired,
63
+ onRemoveRole: PropTypes.func.isRequired,
64
+ resourceName: PropTypes.string.isRequired,
65
+ };
66
+
67
+ export default AssignedRolesList;
@@ -0,0 +1,19 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import AssignedRolesList from './AssignedRolesList';
4
+
5
+ const noop = () => {};
6
+
7
+ const fixtures = {
8
+ 'should render': {
9
+ assignedRoles: [{ id: 1, name: 'fake.role' }, { id: 2, name: 'test.role' }],
10
+ pagination: { page: 1, perPage: 25 },
11
+ itemCount: 2,
12
+ onPaginationChange: noop,
13
+ onRemoveRole: noop,
14
+ resourceName: 'host',
15
+ },
16
+ };
17
+
18
+ describe('AssignedRolesList', () =>
19
+ testComponentSnapshotsWithFixtures(AssignedRolesList, fixtures));
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import { ListView, LoadingState } from 'patternfly-react';
5
+ import PaginationWrapper from 'foremanReact/components/Pagination/PaginationWrapper';
6
+
7
+ import AnsibleRole from './AnsibleRole';
8
+
9
+ const AvailableRolesList = ({
10
+ unassignedRoles,
11
+ pagination,
12
+ itemCount,
13
+ onListingChange,
14
+ onAddRole,
15
+ loading,
16
+ }) => (
17
+ <ListView>
18
+ <div className="sticky-pagination">
19
+ <PaginationWrapper
20
+ viewType="list"
21
+ itemCount={itemCount}
22
+ pagination={pagination}
23
+ onChange={onListingChange}
24
+ dropdownButtonId="available-ansible-roles-pagination-row-dropdown"
25
+ />
26
+ </div>
27
+ <LoadingState loading={loading}>
28
+ {unassignedRoles.map(role => (
29
+ <AnsibleRole
30
+ key={role.id}
31
+ role={role}
32
+ icon="fa fa-plus-circle"
33
+ onClick={onAddRole}
34
+ />
35
+ ))}
36
+ </LoadingState>
37
+ </ListView>
38
+ );
39
+
40
+ AvailableRolesList.propTypes = {
41
+ unassignedRoles: PropTypes.arrayOf(PropTypes.object).isRequired,
42
+ pagination: PropTypes.shape({
43
+ page: PropTypes.number,
44
+ perPage: PropTypes.number,
45
+ }).isRequired,
46
+ itemCount: PropTypes.number.isRequired,
47
+ onListingChange: PropTypes.func.isRequired,
48
+ onAddRole: PropTypes.func.isRequired,
49
+ loading: PropTypes.bool.isRequired,
50
+ };
51
+
52
+ export default AvailableRolesList;
@@ -0,0 +1,22 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import AvailableRolesList from './AvailableRolesList';
4
+
5
+ const noop = () => {};
6
+
7
+ const fixtures = {
8
+ 'should render': {
9
+ unassignedRoles: [
10
+ { id: 1, name: 'fake.role' },
11
+ { id: 2, name: 'test.role' },
12
+ ],
13
+ pagination: { page: 1, perPage: 25 },
14
+ itemCount: 2,
15
+ onListingChange: noop,
16
+ onAddRole: noop,
17
+ loading: false,
18
+ },
19
+ };
20
+
21
+ describe('AvailableRolesList', () =>
22
+ testComponentSnapshotsWithFixtures(AvailableRolesList, fixtures));
@@ -0,0 +1,26 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`AnsiblePermissionDenied should render 1`] = `
4
+ <EmptyStatePattern
5
+ description={
6
+ <span>
7
+ You are not authorized to perform this action.
8
+ <br />
9
+ Please request one of the required permissions listed below from a Foreman administrator:
10
+ <br />
11
+ </span>
12
+ }
13
+ documentation={
14
+ <ul
15
+ className="list-unstyled"
16
+ >
17
+ <li>
18
+ view_ansible_roles
19
+ </li>
20
+ </ul>
21
+ }
22
+ header="Permission Denied"
23
+ icon="lock"
24
+ iconType="fa"
25
+ />
26
+ `;
@@ -0,0 +1,108 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`AnsibleRole should render a role to add 1`] = `
4
+ <ListViewItem
5
+ actions={
6
+ <AnsibleRoleActionButton
7
+ icon="fa fa-plus-circle"
8
+ role={
9
+ Object {
10
+ "id": 5,
11
+ "name": "test.role",
12
+ }
13
+ }
14
+ />
15
+ }
16
+ additionalInfo={null}
17
+ checkboxInput={null}
18
+ className="listViewItem--listItemVariants ansible-role-movable"
19
+ compoundExpand={false}
20
+ compoundExpanded={false}
21
+ description={null}
22
+ heading="test.role"
23
+ hideCloseIcon={false}
24
+ id={5}
25
+ initExpanded={false}
26
+ leftContent={null}
27
+ onClick={[Function]}
28
+ onCloseCompoundExpand={[Function]}
29
+ onExpand={[Function]}
30
+ onExpandClose={[Function]}
31
+ stacked={true}
32
+ />
33
+ `;
34
+
35
+ exports[`AnsibleRole should render a role to remove 1`] = `
36
+ <ListViewItem
37
+ actions={
38
+ <AnsibleRoleActionButton
39
+ icon="fa fa-minus-circle"
40
+ role={
41
+ Object {
42
+ "id": 5,
43
+ "name": "test.role",
44
+ }
45
+ }
46
+ />
47
+ }
48
+ additionalInfo={null}
49
+ checkboxInput={null}
50
+ className="listViewItem--listItemVariants ansible-role-movable"
51
+ compoundExpand={false}
52
+ compoundExpanded={false}
53
+ description={null}
54
+ heading="test.role"
55
+ hideCloseIcon={false}
56
+ id={5}
57
+ initExpanded={false}
58
+ leftContent={null}
59
+ onClick={[Function]}
60
+ onCloseCompoundExpand={[Function]}
61
+ onExpand={[Function]}
62
+ onExpandClose={[Function]}
63
+ stacked={true}
64
+ />
65
+ `;
66
+
67
+ exports[`AnsibleRole should render inherited role to remove 1`] = `
68
+ <OverlayTrigger
69
+ defaultOverlayShown={false}
70
+ overlay={
71
+ <Tooltip
72
+ bsClass="tooltip"
73
+ id={5}
74
+ placement="right"
75
+ >
76
+ <span>
77
+ This Ansible role is inherited from host group
78
+ </span>
79
+ </Tooltip>
80
+ }
81
+ placement="top"
82
+ trigger={
83
+ Array [
84
+ "hover",
85
+ "focus",
86
+ ]
87
+ }
88
+ >
89
+ <ListViewItem
90
+ actions=""
91
+ additionalInfo={null}
92
+ checkboxInput={null}
93
+ className="listViewItem--listItemVariants ansible-role-disabled"
94
+ compoundExpand={false}
95
+ compoundExpanded={false}
96
+ description={null}
97
+ heading="test.role"
98
+ hideCloseIcon={false}
99
+ id={5}
100
+ initExpanded={false}
101
+ leftContent={null}
102
+ onCloseCompoundExpand={[Function]}
103
+ onExpand={[Function]}
104
+ onExpandClose={[Function]}
105
+ stacked={true}
106
+ />
107
+ </OverlayTrigger>
108
+ `;