foreman_ansible 7.1.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/foreman_ansible/api/v2/hostgroups_controller_extensions.rb +5 -1
  3. data/app/controllers/foreman_ansible/api/v2/hosts_controller_extensions.rb +3 -1
  4. data/app/graphql/presenters/ansible_role_presenter.rb +4 -0
  5. data/app/graphql/types/ansible_role.rb +1 -0
  6. data/app/graphql/types/inherited_ansible_role.rb +4 -0
  7. data/app/helpers/foreman_ansible/hosts_helper.rb +19 -0
  8. data/app/services/foreman_ansible/variables_importer.rb +9 -9
  9. data/app/views/api/v2/hostgroups/ansible_roles.json.rabl +9 -1
  10. data/app/views/api/v2/hosts/ansible_roles.json.rabl +9 -1
  11. data/app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb +4 -1
  12. data/config/routes.rb +3 -3
  13. data/lib/foreman_ansible/engine.rb +0 -1
  14. data/lib/foreman_ansible/register.rb +6 -2
  15. data/lib/foreman_ansible/remote_execution.rb +0 -6
  16. data/lib/foreman_ansible/version.rb +1 -1
  17. data/locale/action_names.rb +4 -3
  18. data/locale/ca/foreman_ansible.edit.po +1162 -0
  19. data/locale/ca/foreman_ansible.po +360 -45
  20. data/locale/ca/foreman_ansible.po.time_stamp +0 -0
  21. data/locale/cs_CZ/foreman_ansible.edit.po +1207 -0
  22. data/locale/cs_CZ/foreman_ansible.po +372 -57
  23. data/locale/cs_CZ/foreman_ansible.po.time_stamp +0 -0
  24. data/locale/de/foreman_ansible.edit.po +1148 -0
  25. data/locale/de/foreman_ansible.po +355 -40
  26. data/locale/de/foreman_ansible.po.time_stamp +0 -0
  27. data/locale/en/foreman_ansible.edit.po +1146 -0
  28. data/locale/en/foreman_ansible.po +355 -40
  29. data/locale/en/foreman_ansible.po.time_stamp +0 -0
  30. data/locale/en_GB/foreman_ansible.edit.po +1155 -0
  31. data/locale/en_GB/foreman_ansible.po +357 -42
  32. data/locale/en_GB/foreman_ansible.po.time_stamp +0 -0
  33. data/locale/es/foreman_ansible.edit.po +1148 -0
  34. data/locale/es/foreman_ansible.po +355 -40
  35. data/locale/es/foreman_ansible.po.time_stamp +0 -0
  36. data/locale/foreman_ansible.pot +767 -263
  37. data/locale/fr/foreman_ansible.edit.po +1148 -0
  38. data/locale/fr/foreman_ansible.po +355 -40
  39. data/locale/fr/foreman_ansible.po.time_stamp +0 -0
  40. data/locale/gl/foreman_ansible.edit.po +1156 -0
  41. data/locale/gl/foreman_ansible.po +358 -43
  42. data/locale/gl/foreman_ansible.po.time_stamp +0 -0
  43. data/locale/it/foreman_ansible.edit.po +1148 -0
  44. data/locale/it/foreman_ansible.po +355 -40
  45. data/locale/it/foreman_ansible.po.time_stamp +0 -0
  46. data/locale/ja/foreman_ansible.edit.po +1148 -0
  47. data/locale/ja/foreman_ansible.po +355 -40
  48. data/locale/ja/foreman_ansible.po.time_stamp +0 -0
  49. data/locale/ko/foreman_ansible.edit.po +1148 -0
  50. data/locale/ko/foreman_ansible.po +355 -40
  51. data/locale/ko/foreman_ansible.po.time_stamp +0 -0
  52. data/locale/nl_NL/foreman_ansible.edit.po +1168 -0
  53. data/locale/nl_NL/foreman_ansible.po +359 -44
  54. data/locale/nl_NL/foreman_ansible.po.time_stamp +0 -0
  55. data/locale/pl/foreman_ansible.edit.po +1180 -0
  56. data/locale/pl/foreman_ansible.po +363 -48
  57. data/locale/pl/foreman_ansible.po.time_stamp +0 -0
  58. data/locale/pt_BR/foreman_ansible.edit.po +1148 -0
  59. data/locale/pt_BR/foreman_ansible.po +355 -40
  60. data/locale/pt_BR/foreman_ansible.po.time_stamp +0 -0
  61. data/locale/ru/foreman_ansible.edit.po +1149 -0
  62. data/locale/ru/foreman_ansible.po +355 -40
  63. data/locale/ru/foreman_ansible.po.time_stamp +0 -0
  64. data/locale/sv_SE/foreman_ansible.edit.po +1180 -0
  65. data/locale/sv_SE/foreman_ansible.po +363 -48
  66. data/locale/sv_SE/foreman_ansible.po.time_stamp +0 -0
  67. data/locale/zh_CN/foreman_ansible.edit.po +1148 -0
  68. data/locale/zh_CN/foreman_ansible.po +355 -40
  69. data/locale/zh_CN/foreman_ansible.po.time_stamp +0 -0
  70. data/locale/zh_TW/foreman_ansible.edit.po +1148 -0
  71. data/locale/zh_TW/foreman_ansible.po +355 -40
  72. data/locale/zh_TW/foreman_ansible.po.time_stamp +0 -0
  73. data/test/graphql/queries/host_ansible_roles_query_test.rb +61 -0
  74. data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js.orig +151 -0
  75. data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/AllRolesTable.js +11 -1
  76. data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/EditRolesForm.js +22 -22
  77. data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/index.js +2 -1
  78. data/webpack/components/AnsibleHostDetail/components/RolesTab/RolesTable.js +10 -1
  79. data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.fixtures.js +30 -0
  80. data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcher.test.js +0 -2
  81. data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +3 -12
  82. data/webpack/components/AnsibleRolesSwitcher/components/OrderedRolesTooltip.js +11 -12
  83. data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsibleRole.test.js.snap +6 -20
  84. data/webpack/components/withLoading.js +7 -12
  85. data/webpack/graphql/queries/allAnsibleRoles.gql +3 -0
  86. data/webpack/graphql/queries/hostAnsibleRoles.gql +3 -0
  87. metadata +69 -31
  88. data/app/helpers/foreman_ansible/hosts_helper_extensions.rb +0 -30
  89. data/app/views/foreman_ansible/job_templates/configure_cloud_connector_-_ansible_default.erb +0 -37
@@ -0,0 +1,61 @@
1
+ require 'test_plugin_helper'
2
+
3
+ module Queries
4
+ class HostAnsibleRolesQueryTest < GraphQLQueryTestCase
5
+ let(:role1) { FactoryBot.create(:ansible_role) }
6
+ let(:role2) { FactoryBot.create(:ansible_role) }
7
+ let(:hostgroup) { FactoryBot.create(:hostgroup, ansible_roles: [role1]) }
8
+ let(:host) { FactoryBot.create(:host, hostgroup: hostgroup, ansible_roles: [role2]) }
9
+ let(:variables) { { id: Foreman::GlobalId.for(host) } }
10
+ let(:query) do
11
+ <<-GRAPHQL
12
+ query ($id: String!) {
13
+ host(id: $id) {
14
+ id
15
+ allAnsibleRoles {
16
+ totalCount
17
+ nodes {
18
+ id
19
+ name
20
+ inherited
21
+ ansibleVariables {
22
+ totalCount
23
+ nodes {
24
+ key
25
+ override
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ GRAPHQL
33
+ end
34
+
35
+ context 'with admin permissions' do
36
+ let(:context_user) { FactoryBot.create(:user, :admin) }
37
+ let(:data) { result['data']['host']['allAnsibleRoles'] }
38
+
39
+ it 'allows to fetch inherited roles' do
40
+ value(data['totalCount']).must_equal(2)
41
+ r1_data = data['nodes'].first
42
+ r2_data = data['nodes'].second
43
+ value(r1_data['name']).must_equal(role1.name)
44
+ value(r1_data['inherited']).must_equal(true)
45
+ value(r2_data['name']).must_equal(role2.name)
46
+ value(r2_data['inherited']).must_equal(false)
47
+ end
48
+
49
+ it 'allow fetching variables' do
50
+ var1 = FactoryBot.create(:ansible_variable, ansible_role: role1, override: true)
51
+ FactoryBot.create(:ansible_variable, ansible_role: role1)
52
+ FactoryBot.create(:ansible_variable, ansible_role: role2, override: true)
53
+ r1_vars = data['nodes'].first['ansibleVariables']
54
+ r2_vars = data['nodes'].second['ansibleVariables']
55
+ value(r1_vars['totalCount']).must_equal(2)
56
+ value(r2_vars['totalCount']).must_equal(1)
57
+ value(r1_vars['nodes'].first['key']).must_equal(var1.key)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -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);
@@ -15,7 +15,7 @@ import Pagination from 'foremanReact/components/Pagination';
15
15
  import withLoading from '../../../../withLoading';
16
16
 
17
17
  const AllRolesTable = ({ allAnsibleRoles, totalCount }) => {
18
- const columns = [__('Name'), __('Source')];
18
+ const columns = [__('Name'), __('Variables'), __('Source')];
19
19
 
20
20
  return (
21
21
  <React.Fragment>
@@ -37,6 +37,16 @@ const AllRolesTable = ({ allAnsibleRoles, totalCount }) => {
37
37
  <Tr key={`${role.id}-all`} id={role.id}>
38
38
  <Td />
39
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
+
40
50
  <Td>
41
51
  {role.inherited
42
52
  ? __('Inherited from Hostgroup')
@@ -1,4 +1,4 @@
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
 
@@ -21,17 +21,17 @@ const EditRolesForm = props => {
21
21
  actions,
22
22
  } = props;
23
23
 
24
- const [formState, setFormState] = useState({
25
- availableOptions: [],
26
- chosenOptions: [],
27
- });
24
+ const [availableOptions, setAvailableOptions] = useState(
25
+ availableRoles.map(item => item.name)
26
+ );
27
+ const [chosenOptions, setChosenOptions] = useState(
28
+ assignedRoles.map(item => item.name)
29
+ );
28
30
 
29
- useEffect(() => {
30
- setFormState({
31
- availableOptions: availableRoles.map(item => item.name),
32
- chosenOptions: assignedRoles.map(item => item.name) || [],
33
- });
34
- }, [availableRoles, assignedRoles]);
31
+ const onListChange = (nextAvailable, nextChosen) => {
32
+ setAvailableOptions(nextAvailable);
33
+ setChosenOptions(nextChosen);
34
+ };
35
35
 
36
36
  const [callMutation, { loading }] = useMutation(assignAnsibleRoles, {
37
37
  onCompleted: onCompleted(closeModal),
@@ -42,7 +42,7 @@ const EditRolesForm = props => {
42
42
 
43
43
  const variables = {
44
44
  id: encodeId('Host', hostId),
45
- ansibleRoleIds: roleNamesToIds(allRoles, formState.chosenOptions),
45
+ ansibleRoleIds: roleNamesToIds(allRoles, chosenOptions),
46
46
  };
47
47
 
48
48
  const formActions = [
@@ -65,14 +65,9 @@ const EditRolesForm = props => {
65
65
  return (
66
66
  <Modal {...baseModalProps} actions={formActions}>
67
67
  <DualList
68
- availableOptions={formState.availableOptions}
69
- chosenOptions={formState.chosenOptions}
70
- onListChange={(newAvailable, newChosen) =>
71
- setFormState({
72
- availableOptions: newAvailable,
73
- chosenOptions: newChosen,
74
- })
75
- }
68
+ availableOptions={availableOptions}
69
+ chosenOptions={chosenOptions}
70
+ onListChange={onListChange}
76
71
  />
77
72
  </Modal>
78
73
  );
@@ -80,11 +75,16 @@ const EditRolesForm = props => {
80
75
 
81
76
  EditRolesForm.propTypes = {
82
77
  closeModal: PropTypes.func.isRequired,
83
- assignedRoles: PropTypes.array.isRequired,
84
- availableRoles: PropTypes.array.isRequired,
78
+ assignedRoles: PropTypes.array,
79
+ availableRoles: PropTypes.array,
85
80
  actions: PropTypes.array.isRequired,
86
81
  hostId: PropTypes.number.isRequired,
87
82
  baseModalProps: PropTypes.object.isRequired,
88
83
  };
89
84
 
85
+ EditRolesForm.defaultProps = {
86
+ assignedRoles: [],
87
+ availableRoles: [],
88
+ };
89
+
90
90
  export default withLoading(EditRolesForm);
@@ -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}
@@ -27,7 +27,7 @@ const RolesTable = ({
27
27
  hostGlobalId,
28
28
  canEditHost,
29
29
  }) => {
30
- const columns = [__('Name')];
30
+ const columns = [__('Name'), __('Variables')];
31
31
 
32
32
  const editBtn = canEditHost ? (
33
33
  <FlexItem>
@@ -72,6 +72,15 @@ const RolesTable = ({
72
72
  <Td>
73
73
  <a href={role.path}>{role.name}</a>
74
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>
75
84
  </Tr>
76
85
  ))}
77
86
  </Tbody>
@@ -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 },
@@ -2,8 +2,6 @@ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
2
 
3
3
  import AnsibleRolesSwitcher from '../AnsibleRolesSwitcher';
4
4
 
5
- jest.mock('foremanReact/components/Pagination/PaginationWrapper');
6
-
7
5
  const noop = () => {};
8
6
 
9
7
  const fixtures = {
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { ListView, Tooltip, OverlayTrigger } from 'patternfly-react';
3
+ import { ListView } from 'patternfly-react';
4
+ import { Tooltip } from '@patternfly/react-core';
4
5
  import classNames from 'classnames';
5
6
  import { translate as __ } from 'foremanReact/common/I18n';
6
7
 
@@ -13,12 +14,6 @@ const AnsibleRole = ({ role, icon, onClick, resourceName, index }) => {
13
14
  ? __('This Ansible role is inherited from parent host group')
14
15
  : __('This Ansible role is inherited from host group');
15
16
 
16
- const tooltip = (
17
- <Tooltip id={role.id}>
18
- <span>{text}</span>
19
- </Tooltip>
20
- );
21
-
22
17
  const clickHandler = (onClickFn, ansibleRole) => event => {
23
18
  event.preventDefault();
24
19
  onClickFn(ansibleRole);
@@ -48,11 +43,7 @@ const AnsibleRole = ({ role, icon, onClick, resourceName, index }) => {
48
43
  );
49
44
 
50
45
  if (role.inherited) {
51
- return (
52
- <OverlayTrigger overlay={tooltip} placement="top">
53
- {listItem()}
54
- </OverlayTrigger>
55
- );
46
+ return <Tooltip content={<span>{text}</span>}>{listItem()}</Tooltip>;
56
47
  }
57
48
 
58
49
  return listItem(clickHandler);
@@ -1,22 +1,21 @@
1
1
  import React from 'react';
2
2
  import { translate as __ } from 'foremanReact/common/I18n';
3
- import { Tooltip, Icon, OverlayTrigger } from 'patternfly-react';
3
+ import { Tooltip } from '@patternfly/react-core';
4
+ import { InfoCircleIcon } from '@patternfly/react-icons';
4
5
 
5
6
  const OrderedRolesTooltip = props => {
6
- const tooltip = (
7
- <Tooltip id="assigned-ansible-roles-tooltip">
8
- <span>
9
- {__(
10
- 'Use drag and drop to change order of the roles. Ordering of roles is respected for Ansible runs, inherited roles are always before those assigned directly'
11
- )}
12
- </span>
13
- </Tooltip>
7
+ const content = (
8
+ <span>
9
+ {__(
10
+ 'Use drag and drop to change order of the roles. Ordering of roles is respected for Ansible runs, inherited roles are always before those assigned directly'
11
+ )}
12
+ </span>
14
13
  );
15
14
 
16
15
  return (
17
- <OverlayTrigger overlay={tooltip} trigger={['hover', 'focus']}>
18
- <Icon type="pf" name="info" style={{ 'margin-right': '10px' }} />
19
- </OverlayTrigger>
16
+ <Tooltip content={content}>
17
+ <InfoCircleIcon style={{ marginRight: '10px' }} />
18
+ </Tooltip>
20
19
  );
21
20
  };
22
21
 
@@ -65,25 +65,11 @@ exports[`AnsibleRole should render a role to remove 1`] = `
65
65
  `;
66
66
 
67
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
- ]
68
+ <Tooltip
69
+ content={
70
+ <span>
71
+ This Ansible role is inherited from host group
72
+ </span>
87
73
  }
88
74
  >
89
75
  <ListViewItem
@@ -104,5 +90,5 @@ exports[`AnsibleRole should render inherited role to remove 1`] = `
104
90
  onExpandClose={[Function]}
105
91
  stacked={true}
106
92
  />
107
- </OverlayTrigger>
93
+ </Tooltip>
108
94
  `;
@@ -13,14 +13,12 @@ import {
13
13
  } from '../permissionsHelper';
14
14
  import ErrorState from './ErrorState';
15
15
 
16
- const pluckData = (data, path) => {
16
+ const getResultsLength = (data, path) => {
17
17
  const split = path.split('.');
18
- return split.reduce((memo, item) => {
19
- if (item) {
20
- return memo[item];
21
- }
22
- throw new Error('Unexpected empty segment in response data path');
23
- }, data);
18
+ return split.reduce(
19
+ (prevValue, currentValue) => prevValue + data[currentValue]?.length || 0,
20
+ 0
21
+ );
24
22
  };
25
23
 
26
24
  const withLoading = Component => {
@@ -79,12 +77,9 @@ const withLoading = Component => {
79
77
  }
80
78
 
81
79
  const renamedData = renameData(data);
82
- const result = pluckData(renamedData, renamedDataPath);
80
+ const resultLength = getResultsLength(renamedData, renamedDataPath);
83
81
 
84
- if (
85
- showEmptyState &&
86
- ((Array.isArray(result) && result.length === 0) || !result)
87
- ) {
82
+ if (showEmptyState && !resultLength) {
88
83
  return emptyWrapper(
89
84
  <EmptyState
90
85
  {...{
@@ -7,6 +7,9 @@ query($id: String!, $first: Int, $last: Int){
7
7
  id
8
8
  name
9
9
  inherited
10
+ ansibleVariables {
11
+ totalCount
12
+ }
10
13
  }
11
14
  }
12
15
  }
@@ -9,6 +9,9 @@ query($id: String!, $first: Int, $last: Int) {
9
9
  id
10
10
  name
11
11
  path
12
+ ansibleVariables {
13
+ totalCount
14
+ }
12
15
  }
13
16
  }
14
17
  }