foreman_ansible 7.0.4 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/ansible_playbooks_controller.rb +66 -0
  3. data/app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb +5 -1
  4. data/app/controllers/foreman_ansible/api/v2/hosts_controller_extensions.rb +3 -1
  5. data/app/graphql/presenters/ansible_role_presenter.rb +4 -0
  6. data/app/graphql/types/ansible_role.rb +1 -0
  7. data/app/graphql/types/inherited_ansible_role.rb +4 -0
  8. data/app/helpers/foreman_ansible/hosts_helper.rb +19 -0
  9. data/app/jobs/sync_playbooks.rb +25 -0
  10. data/app/lib/proxy_api/ansible.rb +13 -0
  11. data/app/services/foreman_ansible/import_playbooks_error_notification.rb +38 -0
  12. data/app/services/foreman_ansible/import_playbooks_success_notification.rb +33 -0
  13. data/app/services/foreman_ansible/playbooks_importer.rb +73 -0
  14. data/app/services/foreman_ansible/proxy_api.rb +3 -4
  15. data/app/services/foreman_ansible/variables_importer.rb +9 -9
  16. data/app/views/ansible_roles/index.html.erb +2 -0
  17. data/app/views/api/v2/ansible_playbooks/sync.json.rabl +5 -0
  18. data/app/views/api/v2/hostgroups/ansible_roles.json.rabl +9 -1
  19. data/app/views/api/v2/hosts/ansible_roles.json.rabl +9 -1
  20. data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb +4 -1
  21. data/app/views/foreman_ansible/job_templates/ansible_windows_updates.erb +160 -0
  22. data/config/routes.rb +10 -3
  23. data/db/migrate/20200421201839_update_ansible_inv_template_name.rb +1 -5
  24. data/db/seeds.d/90_notification_blueprints.rb +14 -0
  25. data/lib/foreman_ansible/engine.rb +0 -1
  26. data/lib/foreman_ansible/register.rb +9 -3
  27. data/lib/foreman_ansible/version.rb +1 -1
  28. data/locale/action_names.rb +4 -3
  29. data/locale/ca/foreman_ansible.edit.po +1162 -0
  30. data/locale/ca/foreman_ansible.po +360 -45
  31. data/{webpack/components/withPagination.js → locale/ca/foreman_ansible.po.time_stamp} +0 -0
  32. data/locale/cs_CZ/foreman_ansible.edit.po +1207 -0
  33. data/locale/cs_CZ/foreman_ansible.po +372 -57
  34. data/locale/cs_CZ/foreman_ansible.po.time_stamp +0 -0
  35. data/locale/de/foreman_ansible.edit.po +1148 -0
  36. data/locale/de/foreman_ansible.po +355 -40
  37. data/locale/de/foreman_ansible.po.time_stamp +0 -0
  38. data/locale/en/foreman_ansible.edit.po +1146 -0
  39. data/locale/en/foreman_ansible.po +355 -40
  40. data/locale/en/foreman_ansible.po.time_stamp +0 -0
  41. data/locale/en_GB/foreman_ansible.edit.po +1155 -0
  42. data/locale/en_GB/foreman_ansible.po +357 -42
  43. data/locale/en_GB/foreman_ansible.po.time_stamp +0 -0
  44. data/locale/es/foreman_ansible.edit.po +1148 -0
  45. data/locale/es/foreman_ansible.po +355 -40
  46. data/locale/es/foreman_ansible.po.time_stamp +0 -0
  47. data/locale/foreman_ansible.pot +767 -263
  48. data/locale/fr/foreman_ansible.edit.po +1148 -0
  49. data/locale/fr/foreman_ansible.po +355 -40
  50. data/locale/fr/foreman_ansible.po.time_stamp +0 -0
  51. data/locale/gl/foreman_ansible.edit.po +1156 -0
  52. data/locale/gl/foreman_ansible.po +358 -43
  53. data/locale/gl/foreman_ansible.po.time_stamp +0 -0
  54. data/locale/it/foreman_ansible.edit.po +1148 -0
  55. data/locale/it/foreman_ansible.po +355 -40
  56. data/locale/it/foreman_ansible.po.time_stamp +0 -0
  57. data/locale/ja/foreman_ansible.edit.po +1148 -0
  58. data/locale/ja/foreman_ansible.po +355 -40
  59. data/locale/ja/foreman_ansible.po.time_stamp +0 -0
  60. data/locale/ko/foreman_ansible.edit.po +1148 -0
  61. data/locale/ko/foreman_ansible.po +355 -40
  62. data/locale/ko/foreman_ansible.po.time_stamp +0 -0
  63. data/locale/nl_NL/foreman_ansible.edit.po +1168 -0
  64. data/locale/nl_NL/foreman_ansible.po +359 -44
  65. data/locale/nl_NL/foreman_ansible.po.time_stamp +0 -0
  66. data/locale/pl/foreman_ansible.edit.po +1180 -0
  67. data/locale/pl/foreman_ansible.po +363 -48
  68. data/locale/pl/foreman_ansible.po.time_stamp +0 -0
  69. data/locale/pt_BR/foreman_ansible.edit.po +1148 -0
  70. data/locale/pt_BR/foreman_ansible.po +355 -40
  71. data/locale/pt_BR/foreman_ansible.po.time_stamp +0 -0
  72. data/locale/ru/foreman_ansible.edit.po +1149 -0
  73. data/locale/ru/foreman_ansible.po +355 -40
  74. data/locale/ru/foreman_ansible.po.time_stamp +0 -0
  75. data/locale/sv_SE/foreman_ansible.edit.po +1180 -0
  76. data/locale/sv_SE/foreman_ansible.po +363 -48
  77. data/locale/sv_SE/foreman_ansible.po.time_stamp +0 -0
  78. data/locale/zh_CN/foreman_ansible.edit.po +1148 -0
  79. data/locale/zh_CN/foreman_ansible.po +355 -40
  80. data/locale/zh_CN/foreman_ansible.po.time_stamp +0 -0
  81. data/locale/zh_TW/foreman_ansible.edit.po +1148 -0
  82. data/locale/zh_TW/foreman_ansible.po +355 -40
  83. data/locale/zh_TW/foreman_ansible.po.time_stamp +0 -0
  84. data/test/fixtures/playbooks_example_output.json +1 -0
  85. data/test/fixtures/sample_playbooks.json +10 -0
  86. data/test/functional/api/v2/ansible_playbooks_controller_test.rb +65 -0
  87. data/test/functional/hosts_controller_test.rb +2 -2
  88. data/test/graphql/queries/host_ansible_roles_query_test.rb +61 -0
  89. data/test/unit/import_playbooks_test.rb +51 -0
  90. data/test/unit/lib/proxy_api/ansible_test.rb +6 -0
  91. data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTable.js +58 -75
  92. data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js +44 -58
  93. data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js.orig +151 -0
  94. data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/AllRolesTable.js +43 -56
  95. data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/index.js +1 -1
  96. data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/EditRolesForm.js +26 -24
  97. data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/index.js +3 -2
  98. data/webpack/components/AnsibleHostDetail/components/RolesTab/RolesTable.js +39 -43
  99. data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.fixtures.js +30 -0
  100. data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariables.js +27 -38
  101. data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesActions.js +2 -1
  102. data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesConstants.js +1 -0
  103. data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesSelectors.js +6 -0
  104. data/webpack/components/AnsibleRolesAndVariables/index.js +7 -1
  105. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcher.test.js +0 -2
  106. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +3 -12
  107. data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.js +2 -2
  108. data/webpack/components/AnsibleRolesSwitcher/components/OrderedRolesTooltip.js +11 -12
  109. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsibleRole.test.js.snap +6 -20
  110. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +9 -6
  111. data/webpack/components/withLoading.js +7 -12
  112. data/webpack/graphql/queries/allAnsibleRoles.gql +3 -0
  113. data/webpack/graphql/queries/hostAnsibleRoles.gql +3 -0
  114. data/webpack/helpers/pageParamsHelper.js +3 -3
  115. metadata +87 -34
  116. data/app/helpers/foreman_ansible/hosts_helper_extensions.rb +0 -30
  117. data/webpack/helpers/paginationHelper.js +0 -9
@@ -0,0 +1,151 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import { usePaginationOptions } from 'foremanReact/components/Pagination/PaginationHooks';
5
+
6
+ import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
7
+
8
+ import {
9
+ TableComposable,
10
+ Thead,
11
+ Tbody,
12
+ Tr,
13
+ Th,
14
+ Td,
15
+ } from '@patternfly/react-table';
16
+ import { Flex, FlexItem, Pagination } from '@patternfly/react-core';
17
+
18
+ import { decodeId } from '../../../../globalIdHelper';
19
+ import withLoading from '../../../withLoading';
20
+ <<<<<<< HEAD
21
+ import { readableCron } from './JobsTabHelper';
22
+ import {
23
+ preparePerPageOptions,
24
+ refreshPage,
25
+ } from '../../../../helpers/paginationHelper';
26
+ =======
27
+ import { readableCron, readablePurpose } from './JobsTabHelper';
28
+ >>>>>>> 5b01704 (Fixes #34458 - Show Hostgroup jobs on the Host Detail page)
29
+
30
+ const PreviousJobsTable = ({ history, totalCount, jobs, pagination }) => {
31
+ const columns = [
32
+ __('Description'),
33
+ __('Result'),
34
+ __('State'),
35
+ __('Executed at'),
36
+ __('Schedule'),
37
+ ];
38
+
39
+ const handlePerPageSelected = (event, perPage) => {
40
+ refreshPage(history, { page: 1, perPage });
41
+ };
42
+
43
+ const handlePageSelected = (event, page) => {
44
+ refreshPage(history, { ...pagination, page });
45
+ };
46
+
47
+ const perPageOptions = preparePerPageOptions(usePaginationOptions());
48
+
49
+ return (
50
+ <React.Fragment>
51
+ <h3>{__('Previously executed jobs')}</h3>
52
+ <<<<<<< HEAD
53
+ <Flex className="pf-u-pt-md">
54
+ =======
55
+ <Flex direction={{ default: 'column' }} className="pf-u-pt-md">
56
+ <FlexItem align={{ default: 'alignRight' }}>
57
+ <Pagination updateParamsByUrl itemCount={totalCount} variant="top" />
58
+ </FlexItem>
59
+ <FlexItem>
60
+ <TableComposable variant="compact">
61
+ <Thead>
62
+ <Tr>
63
+ {columns.map(col => (
64
+ <Th key={col}>{col}</Th>
65
+ ))}
66
+ </Tr>
67
+ </Thead>
68
+ <Tbody>
69
+ {jobs.map(job => (
70
+ <Tr key={job.id}>
71
+ <Td>
72
+ <a
73
+ onClick={() =>
74
+ window.tfm.nav.pushUrl(
75
+ `/job_invocations/${decodeId(job.id)}`
76
+ )
77
+ }
78
+ >
79
+ {job.description}
80
+ </a>
81
+ &nbsp;
82
+ {readablePurpose(job.recurringLogic.purpose)}
83
+ </Td>
84
+ <Td>{job.task.result}</Td>
85
+ <Td>{job.task.state}</Td>
86
+ <Td>
87
+ <RelativeDateTime date={job.startAt} />
88
+ </Td>
89
+ <Td>{readableCron(job.recurringLogic.cronLine)}</Td>
90
+ </Tr>
91
+ ))}
92
+ </Tbody>
93
+ </TableComposable>
94
+ </FlexItem>
95
+ >>>>>>> 5b01704 (Fixes #34458 - Show Hostgroup jobs on the Host Detail page)
96
+ <FlexItem align={{ default: 'alignRight' }}>
97
+ <Pagination
98
+ itemCount={totalCount}
99
+ page={pagination.page}
100
+ perPage={pagination.perPage}
101
+ onSetPage={handlePageSelected}
102
+ onPerPageSelect={handlePerPageSelected}
103
+ perPageOptions={perPageOptions}
104
+ variant="top"
105
+ />
106
+ </FlexItem>
107
+ </Flex>
108
+ <TableComposable variant="compact">
109
+ <Thead>
110
+ <Tr>
111
+ {columns.map(col => (
112
+ <Th key={col}>{col}</Th>
113
+ ))}
114
+ </Tr>
115
+ </Thead>
116
+ <Tbody>
117
+ {jobs.map(job => (
118
+ <Tr key={job.id}>
119
+ <Td>
120
+ <a
121
+ onClick={() =>
122
+ window.tfm.nav.pushUrl(
123
+ `/job_invocations/${decodeId(job.id)}`
124
+ )
125
+ }
126
+ >
127
+ {job.description}
128
+ </a>
129
+ </Td>
130
+ <Td>{job.task.result}</Td>
131
+ <Td>{job.task.state}</Td>
132
+ <Td>
133
+ <RelativeDateTime date={job.startAt} />
134
+ </Td>
135
+ <Td>{readableCron(job.recurringLogic.cronLine)}</Td>
136
+ </Tr>
137
+ ))}
138
+ </Tbody>
139
+ </TableComposable>
140
+ </React.Fragment>
141
+ );
142
+ };
143
+
144
+ PreviousJobsTable.propTypes = {
145
+ jobs: PropTypes.array.isRequired,
146
+ history: PropTypes.object.isRequired,
147
+ totalCount: PropTypes.number.isRequired,
148
+ pagination: PropTypes.object.isRequired,
149
+ };
150
+
151
+ export default withLoading(PreviousJobsTable);
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { translate as __ } from 'foremanReact/common/I18n';
4
- import { usePaginationOptions } from 'foremanReact/components/Pagination/PaginationHooks';
5
4
 
6
5
  import {
7
6
  TableComposable,
@@ -11,70 +10,60 @@ import {
11
10
  Th,
12
11
  Td,
13
12
  } from '@patternfly/react-table';
14
-
15
- import { Flex, FlexItem, Pagination } from '@patternfly/react-core';
13
+ import { Flex, FlexItem } from '@patternfly/react-core';
14
+ import Pagination from 'foremanReact/components/Pagination';
16
15
  import withLoading from '../../../../withLoading';
17
- import {
18
- preparePerPageOptions,
19
- refreshPage,
20
- } from '../../../../../helpers/paginationHelper';
21
-
22
- const AllRolesTable = ({
23
- allAnsibleRoles,
24
- totalCount,
25
- pagination,
26
- history,
27
- }) => {
28
- const columns = [__('Name'), __('Source')];
29
16
 
30
- const handlePerPageSelected = (event, allPerPage) => {
31
- refreshPage(history, { allPage: 1, allPerPage });
32
- };
33
-
34
- const handlePageSelected = (event, allPage) => {
35
- refreshPage(history, { ...pagination, allPage });
36
- };
37
-
38
- const perPageOptions = preparePerPageOptions(usePaginationOptions());
17
+ const AllRolesTable = ({ allAnsibleRoles, totalCount }) => {
18
+ const columns = [__('Name'), __('Variables'), __('Source')];
39
19
 
40
20
  return (
41
21
  <React.Fragment>
42
- <Flex className="pf-u-pt-md">
22
+ <Flex direction={{ default: 'column' }} className="pf-u-pt-md">
23
+ <FlexItem align={{ default: 'alignRight' }}>
24
+ <Pagination updateParamsByUrl itemCount={totalCount} variant="top" />
25
+ </FlexItem>
26
+ <TableComposable variant="compact">
27
+ <Thead>
28
+ <Tr>
29
+ <Th />
30
+ {columns.map(col => (
31
+ <Th key={`${col}-all`}>{col}</Th>
32
+ ))}
33
+ </Tr>
34
+ </Thead>
35
+ <Tbody>
36
+ {allAnsibleRoles.map(role => (
37
+ <Tr key={`${role.id}-all`} id={role.id}>
38
+ <Td />
39
+ <Td>{role.name}</Td>
40
+ <Td>
41
+ <a
42
+ href={`/ansible/ansible_variables?search=ansible_role=${role.name}`}
43
+ target="_blank"
44
+ rel="noreferrer"
45
+ >
46
+ {role.ansibleVariables.totalCount}
47
+ </a>
48
+ </Td>
49
+
50
+ <Td>
51
+ {role.inherited
52
+ ? __('Inherited from Hostgroup')
53
+ : __('Directly assigned to Host')}
54
+ </Td>
55
+ </Tr>
56
+ ))}
57
+ </Tbody>
58
+ </TableComposable>
43
59
  <FlexItem align={{ default: 'alignRight' }}>
44
60
  <Pagination
61
+ updateParamsByUrl
45
62
  itemCount={totalCount}
46
- page={pagination.allPage}
47
- perPage={pagination.allPerPage}
48
- onSetPage={handlePageSelected}
49
- onPerPageSelect={handlePerPageSelected}
50
- perPageOptions={perPageOptions}
51
- variant="top"
63
+ variant="bottom"
52
64
  />
53
65
  </FlexItem>
54
66
  </Flex>
55
- <TableComposable variant="compact">
56
- <Thead>
57
- <Tr>
58
- <Th />
59
- {columns.map(col => (
60
- <Th key={`${col}-all`}>{col}</Th>
61
- ))}
62
- </Tr>
63
- </Thead>
64
- <Tbody>
65
- {allAnsibleRoles.map(role => (
66
- <Tr key={`${role.id}-all`} id={role.id}>
67
- <Td />
68
- <Td>{role.name}</Td>
69
- <Td>
70
- {role.inherited
71
- ? __('Inherited from Hostgroup')
72
- : __('Directly assigned to Host')}
73
- </Td>
74
- </Tr>
75
- ))}
76
- </Tbody>
77
- </TableComposable>
78
67
  </React.Fragment>
79
68
  );
80
69
  };
@@ -82,8 +71,6 @@ const AllRolesTable = ({
82
71
  AllRolesTable.propTypes = {
83
72
  allAnsibleRoles: PropTypes.array.isRequired,
84
73
  totalCount: PropTypes.number.isRequired,
85
- pagination: PropTypes.object.isRequired,
86
- history: PropTypes.object.isRequired,
87
74
  };
88
75
 
89
76
  export default withLoading(AllRolesTable);
@@ -27,7 +27,7 @@ const AllRolesModal = ({ hostGlobalId, onClose, history }) => {
27
27
  ),
28
28
  };
29
29
 
30
- const paginationKeys = { page: 'allPage', perPage: 'allPerPage' };
30
+ const paginationKeys = { page: 'page', perPage: 'per_page' };
31
31
 
32
32
  const wrapper = child => <Modal {...baseModalProps}>{child}</Modal>;
33
33
 
@@ -1,7 +1,7 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { translate as __ } from 'foremanReact/common/I18n';
3
3
  import PropTypes from 'prop-types';
4
-
4
+ import { isEqual } from 'lodash';
5
5
  import { useMutation } from '@apollo/client';
6
6
 
7
7
  import { Button, Modal, Spinner } from '@patternfly/react-core';
@@ -21,17 +21,15 @@ const EditRolesForm = props => {
21
21
  actions,
22
22
  } = props;
23
23
 
24
- const [formState, setFormState] = useState({
25
- availableOptions: [],
26
- chosenOptions: [],
27
- });
24
+ const initAvailableOpt = availableRoles.map(item => item.name);
25
+ const initChosenOpt = assignedRoles.map(item => item.name);
26
+ const [availableOptions, setAvailableOptions] = useState(initAvailableOpt);
27
+ const [chosenOptions, setChosenOptions] = useState(initChosenOpt);
28
28
 
29
- useEffect(() => {
30
- setFormState({
31
- availableOptions: availableRoles.map(item => item.name),
32
- chosenOptions: assignedRoles.map(item => item.name) || [],
33
- });
34
- }, [availableRoles, assignedRoles]);
29
+ const onListChange = (nextAvailable, nextChosen) => {
30
+ setAvailableOptions(nextAvailable);
31
+ setChosenOptions(nextChosen);
32
+ };
35
33
 
36
34
  const [callMutation, { loading }] = useMutation(assignAnsibleRoles, {
37
35
  onCompleted: onCompleted(closeModal),
@@ -42,15 +40,19 @@ const EditRolesForm = props => {
42
40
 
43
41
  const variables = {
44
42
  id: encodeId('Host', hostId),
45
- ansibleRoleIds: roleNamesToIds(allRoles, formState.chosenOptions),
43
+ ansibleRoleIds: roleNamesToIds(allRoles, chosenOptions),
46
44
  };
47
45
 
46
+ const didNotModifyOptions = () =>
47
+ isEqual(initAvailableOpt.sort(), availableOptions.sort()) &&
48
+ isEqual(initChosenOpt, chosenOptions); // The order of the chosen options is important.
49
+
48
50
  const formActions = [
49
51
  <Button
50
52
  key="confirm"
51
53
  variant="primary"
52
54
  onClick={() => callMutation({ variables })}
53
- isDisabled={loading}
55
+ isDisabled={loading || didNotModifyOptions()}
54
56
  aria-label="submit ansible roles"
55
57
  >
56
58
  {__('Confirm')}
@@ -65,14 +67,9 @@ const EditRolesForm = props => {
65
67
  return (
66
68
  <Modal {...baseModalProps} actions={formActions}>
67
69
  <DualList
68
- availableOptions={formState.availableOptions}
69
- chosenOptions={formState.chosenOptions}
70
- onListChange={(newAvailable, newChosen) =>
71
- setFormState({
72
- availableOptions: newAvailable,
73
- chosenOptions: newChosen,
74
- })
75
- }
70
+ availableOptions={availableOptions}
71
+ chosenOptions={chosenOptions}
72
+ onListChange={onListChange}
76
73
  />
77
74
  </Modal>
78
75
  );
@@ -80,11 +77,16 @@ const EditRolesForm = props => {
80
77
 
81
78
  EditRolesForm.propTypes = {
82
79
  closeModal: PropTypes.func.isRequired,
83
- assignedRoles: PropTypes.array.isRequired,
84
- availableRoles: PropTypes.array.isRequired,
80
+ assignedRoles: PropTypes.array,
81
+ availableRoles: PropTypes.array,
85
82
  actions: PropTypes.array.isRequired,
86
83
  hostId: PropTypes.number.isRequired,
87
84
  baseModalProps: PropTypes.object.isRequired,
88
85
  };
89
86
 
87
+ EditRolesForm.defaultProps = {
88
+ assignedRoles: [],
89
+ availableRoles: [],
90
+ };
91
+
90
92
  export default withLoading(EditRolesForm);
@@ -20,7 +20,7 @@ const EditRolesModal = ({
20
20
  canEditHost,
21
21
  }) => {
22
22
  const baseModalProps = {
23
- width: '70%',
23
+ width: '50%',
24
24
  isOpen,
25
25
  className: 'foreman-modal',
26
26
  showClose: false,
@@ -54,6 +54,7 @@ const EditRolesModal = ({
54
54
 
55
55
  const renameData = data => ({
56
56
  availableRoles: data.host.availableAnsibleRoles.nodes,
57
+ assignedRoles,
57
58
  });
58
59
 
59
60
  return (
@@ -64,7 +65,7 @@ const EditRolesModal = ({
64
65
  baseModalProps={baseModalProps}
65
66
  fetchFn={useFetchFn}
66
67
  renameData={renameData}
67
- renamedDataPath="availableRoles"
68
+ renamedDataPath="availableRoles.assignedRoles"
68
69
  assignedRoles={assignedRoles}
69
70
  closeModal={closeModal}
70
71
  hostId={hostId}
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { translate as __ } from 'foremanReact/common/I18n';
4
4
  import { Route, Link } from 'react-router-dom';
5
- import { usePaginationOptions } from 'foremanReact/components/Pagination/PaginationHooks';
5
+ import Pagination from 'foremanReact/components/Pagination';
6
6
 
7
7
  import {
8
8
  TableComposable,
@@ -12,37 +12,22 @@ import {
12
12
  Th,
13
13
  Td,
14
14
  } from '@patternfly/react-table';
15
- import { Flex, FlexItem, Button, Pagination } from '@patternfly/react-core';
15
+ import { Flex, FlexItem, Button } from '@patternfly/react-core';
16
16
 
17
17
  import EditRolesModal from './EditRolesModal';
18
18
 
19
19
  import withLoading from '../../../withLoading';
20
20
  import AllRolesModal from './AllRolesModal';
21
- import {
22
- preparePerPageOptions,
23
- refreshPage,
24
- } from '../../../../helpers/paginationHelper';
25
21
 
26
22
  const RolesTable = ({
27
23
  totalCount,
28
- pagination,
29
24
  history,
30
25
  ansibleRoles,
31
26
  hostId,
32
27
  hostGlobalId,
33
28
  canEditHost,
34
29
  }) => {
35
- const columns = [__('Name')];
36
-
37
- const handlePerPageSelected = (event, perPage) => {
38
- refreshPage(history, { page: 1, perPage });
39
- };
40
-
41
- const handlePageSelected = (event, page) => {
42
- refreshPage(history, { ...pagination, page });
43
- };
44
-
45
- const perPageOptions = preparePerPageOptions(usePaginationOptions());
30
+ const columns = [__('Name'), __('Variables')];
46
31
 
47
32
  const editBtn = canEditHost ? (
48
33
  <FlexItem>
@@ -67,36 +52,48 @@ const RolesTable = ({
67
52
  </Flex>
68
53
  <Flex>
69
54
  <FlexItem>{editBtn}</FlexItem>
55
+ <FlexItem align={{ default: 'alignRight' }}>
56
+ <Pagination updateParamsByUrl itemCount={totalCount} variant="top" />
57
+ </FlexItem>
58
+ </Flex>
59
+ <Flex direction={{ default: 'column' }}>
60
+ <FlexItem>
61
+ <TableComposable variant="compact">
62
+ <Thead>
63
+ <Tr>
64
+ {columns.map(col => (
65
+ <Th key={col}>{col}</Th>
66
+ ))}
67
+ </Tr>
68
+ </Thead>
69
+ <Tbody>
70
+ {ansibleRoles.map(role => (
71
+ <Tr key={role.id}>
72
+ <Td>
73
+ <a href={role.path}>{role.name}</a>
74
+ </Td>
75
+ <Td>
76
+ <a
77
+ href={`/ansible/ansible_variables?search=ansible_role=${role.name}`}
78
+ target="_blank"
79
+ rel="noreferrer"
80
+ >
81
+ {role.ansibleVariables.totalCount}
82
+ </a>
83
+ </Td>
84
+ </Tr>
85
+ ))}
86
+ </Tbody>
87
+ </TableComposable>
88
+ </FlexItem>
70
89
  <FlexItem align={{ default: 'alignRight' }}>
71
90
  <Pagination
91
+ updateParamsByUrl
72
92
  itemCount={totalCount}
73
- page={pagination.page}
74
- perPage={pagination.perPage}
75
- onSetPage={handlePageSelected}
76
- onPerPageSelect={handlePerPageSelected}
77
- perPageOptions={perPageOptions}
78
- variant="top"
93
+ variant="bottom"
79
94
  />
80
95
  </FlexItem>
81
96
  </Flex>
82
- <TableComposable variant="compact">
83
- <Thead>
84
- <Tr>
85
- {columns.map(col => (
86
- <Th key={col}>{col}</Th>
87
- ))}
88
- </Tr>
89
- </Thead>
90
- <Tbody>
91
- {ansibleRoles.map(role => (
92
- <Tr key={role.id}>
93
- <Td>
94
- <a href={role.path}>{role.name}</a>
95
- </Td>
96
- </Tr>
97
- ))}
98
- </Tbody>
99
- </TableComposable>
100
97
  <Route path="/Ansible/roles/edit">
101
98
  <EditRolesModal
102
99
  closeModal={() => history.goBack()}
@@ -123,7 +120,6 @@ RolesTable.propTypes = {
123
120
  hostId: PropTypes.number.isRequired,
124
121
  hostGlobalId: PropTypes.string.isRequired,
125
122
  history: PropTypes.object.isRequired,
126
- pagination: PropTypes.object.isRequired,
127
123
  totalCount: PropTypes.number.isRequired,
128
124
  canEditHost: PropTypes.bool.isRequired,
129
125
  };
@@ -35,6 +35,9 @@ const role1 = {
35
35
  id: 'MDE6QW5zaWJsZVJvbGUtMw==',
36
36
  name: 'aardvaark.cube',
37
37
  path: '/ansible/ansible_roles/search="name = aardvaark.cube"',
38
+ ansibleVariables: {
39
+ totalCount: 1,
40
+ },
38
41
  };
39
42
 
40
43
  const role2 = {
@@ -42,6 +45,9 @@ const role2 = {
42
45
  id: 'MDE6QW5zaWJsZVJvbGUtNQ==',
43
46
  name: 'aardvaark.sphere',
44
47
  path: '/ansible/ansible_roles/search="name = aardvaark.sphere"',
48
+ ansibleVariables: {
49
+ totalCount: 2,
50
+ },
45
51
  };
46
52
 
47
53
  const role3 = {
@@ -49,6 +55,9 @@ const role3 = {
49
55
  id: 'MDE6QW5zaWJsZVJvbGUtMzA=',
50
56
  name: 'another.role',
51
57
  path: '/ansible/ansible_roles/search="name = another.role"',
58
+ ansibleVariables: {
59
+ totalCount: 3,
60
+ },
52
61
  };
53
62
 
54
63
  const role4 = {
@@ -56,6 +65,9 @@ const role4 = {
56
65
  id: 'MDE6QW5zaWJsZVJvbGUtMzk=',
57
66
  name: 'geerlingguy.ceylon',
58
67
  path: '/ansible/ansible_roles/search="name = geerlingguy.ceylon"',
68
+ ansibleVariables: {
69
+ totalCount: 4,
70
+ },
59
71
  };
60
72
 
61
73
  const ansibleRolesMock = {
@@ -77,30 +89,45 @@ const availableRoles = {
77
89
  name: 'theforeman.foreman_scap_client',
78
90
  path:
79
91
  '/ansible/ansible_roles/search="name = theforeman.foreman_scap_client"',
92
+ ansibleVariables: {
93
+ totalCount: 23,
94
+ },
80
95
  },
81
96
  {
82
97
  __typename: 'AnsibleRole',
83
98
  id: 'MDE6QW5zaWJsZVJvbGUtMg==',
84
99
  name: 'adriagalin.motd',
85
100
  path: '/ansible/ansible_roles/search="name = adriagalin.motd"',
101
+ ansibleVariables: {
102
+ totalCount: 23,
103
+ },
86
104
  },
87
105
  {
88
106
  __typename: 'AnsibleRole',
89
107
  id: 'MDE6QW5zaWJsZVJvbGUtMjI=',
90
108
  name: 'geerlingguy.php',
91
109
  path: '/ansible/ansible_roles/search="name = geerlingguy.php"',
110
+ ansibleVariables: {
111
+ totalCount: 23,
112
+ },
92
113
  },
93
114
  {
94
115
  __typename: 'AnsibleRole',
95
116
  id: 'MDE6QW5zaWJsZVJvbGUtNTc=',
96
117
  name: 'robertdebock.epel',
97
118
  path: '/ansible/ansible_roles/search="name = robertdebock.epel"',
119
+ ansibleVariables: {
120
+ totalCount: 23,
121
+ },
98
122
  },
99
123
  {
100
124
  __typename: 'AnsibleRole',
101
125
  id: 'MDE6QW5zaWJsZVJvbGUtNTg=',
102
126
  name: 'geerlingguy.nfs',
103
127
  path: '/ansible/ansible_roles/search="name = geerlingguy.nfs"',
128
+ ansibleVariables: {
129
+ totalCount: 23,
130
+ },
104
131
  },
105
132
  ],
106
133
  };
@@ -118,6 +145,9 @@ export const allRolesMocks = allAnsibleRolesMockFactory(
118
145
  name: 'adriagalin.motd',
119
146
  path: '/ansible/ansible_roles/search="name = adriagalin.motd"',
120
147
  inherited: true,
148
+ ansibleVariables: {
149
+ totalCount: 23,
150
+ },
121
151
  },
122
152
  { ...role1, inherited: false },
123
153
  { ...role2, inherited: false },