foreman_ansible 17.0.9 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/foreman_ansible/register.rb +1 -1
- data/lib/foreman_ansible/version.rb +1 -1
- data/webpack/components/AnsibleRolesAndVariables/AnsibleRolesAndVariablesActions.js +6 -1
- data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcher.scss +6 -13
- data/webpack/components/AnsibleRolesSwitcher/AnsibleRolesSwitcherReducer.js +11 -6
- data/webpack/components/AnsibleRolesSwitcher/__tests__/AnsibleRolesSwitcherReducer.test.js +41 -0
- data/webpack/components/AnsibleRolesSwitcher/components/InheritedRolesList.js +9 -4
- data/webpack/components/DualList/DualList.test.js +101 -0
- data/webpack/components/DualList/index.js +36 -92
- data/webpack/global_index.js +3 -1
- metadata +3 -8
- data/webpack/components/DualList/DualList.scss +0 -3
- data/webpack/components/DualList/ListControls.js +0 -65
- data/webpack/components/DualList/ListHeader.js +0 -18
- data/webpack/components/DualList/ListItem.js +0 -69
- data/webpack/components/DualList/ListPane.js +0 -95
- data/webpack/components/DualList/SelectedStatus.js +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '087d3ebdcf70f8891bf6de236413f46c971950589ecc7a9b32aa781b747f0d64'
|
|
4
|
+
data.tar.gz: 11d10eeff06402af8baaeda250d021c44db0fc21bd86450a1123f47d19083353
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 550e5075d68631d646f73b56b370d7816dc2f59a784cc1d828c04b453fde61871d14293aba62fbdca70aa063eec4d74cbe77d5b8d2b1eedd9bafd12c0f24d610
|
|
7
|
+
data.tar.gz: 4b459dcf5991a72248fe82f8bc348a28f10593834fb5c3b352fbebc55a22020efee2af4fe593cd2a67d161f7b197ef4fd0e96682b0e0f5a5de93184a9f0149da
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
ANSIBLE_ROLES_INDEX,
|
|
10
10
|
} from './AnsibleRolesAndVariablesConstants';
|
|
11
11
|
|
|
12
|
+
const REDIRECT_DELAY_MS = 500;
|
|
13
|
+
|
|
12
14
|
export const foremanUrl = path => `${window.URL_PREFIX}${path}`;
|
|
13
15
|
|
|
14
16
|
export const onSubmit = (rows, proxy) => dispatch => {
|
|
@@ -19,7 +21,10 @@ export const onSubmit = (rows, proxy) => dispatch => {
|
|
|
19
21
|
url: ANSIBLE_ROLE_CONFIRM_IMPORT_PATH,
|
|
20
22
|
params: { changed: params, proxy },
|
|
21
23
|
handleSuccess: () => {
|
|
22
|
-
setTimeout(
|
|
24
|
+
setTimeout(
|
|
25
|
+
() => dispatch(push(ANSIBLE_ROLES_INDEX)),
|
|
26
|
+
REDIRECT_DELAY_MS
|
|
27
|
+
);
|
|
23
28
|
},
|
|
24
29
|
successToast: response => (
|
|
25
30
|
<span>
|
|
@@ -6,19 +6,12 @@
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
.ansible-inherited-roles {
|
|
9
|
-
|
|
10
|
-
--pf-v5-global--
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
--pf-v5-global--
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.pf-v5-c-dual-list-selector__header {
|
|
17
|
-
margin-block-end: var(--pf-v5-c-dual-list-selector__header--MarginBottom);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.pf-v5-c-dual-list-selector__title-text {
|
|
21
|
-
font-weight: var(--pf-v5-c-dual-list-selector__title-text--FontWeight);
|
|
9
|
+
.ansible-inherited-roles-title {
|
|
10
|
+
margin: 0 0 var(--pf-v5-global--spacer--sm);
|
|
11
|
+
font-family: var(--pf-v5-global--FontFamily--text);
|
|
12
|
+
font-size: var(--pf-v5-global--FontSize--sm);
|
|
13
|
+
font-weight: var(--pf-v5-global--FontWeight--bold);
|
|
14
|
+
line-height: var(--pf-v5-global--LineHeight--md);
|
|
22
15
|
}
|
|
23
16
|
|
|
24
17
|
ul {
|
|
@@ -34,6 +34,7 @@ const ansibleRoles = (state = initialState, action) => {
|
|
|
34
34
|
return state.merge({ error: payload.error, loading: false });
|
|
35
35
|
case ANSIBLE_ROLES_DUAL_LIST_CHANGE: {
|
|
36
36
|
const { chosenNames } = payload;
|
|
37
|
+
const chosenNamesUnique = [...new Set(chosenNames)];
|
|
37
38
|
const inherited = state.assignedRoles.filter(role =>
|
|
38
39
|
state.inheritedRoleIds.includes(role.id)
|
|
39
40
|
);
|
|
@@ -42,20 +43,24 @@ const ansibleRoles = (state = initialState, action) => {
|
|
|
42
43
|
);
|
|
43
44
|
const roleByName = name =>
|
|
44
45
|
currentOwn.find(role => role.name === name) ||
|
|
45
|
-
state.
|
|
46
|
-
state.
|
|
46
|
+
state.toDestroyRoles.find(role => role.name === name) ||
|
|
47
|
+
state.results.find(role => role.name === name);
|
|
47
48
|
|
|
48
49
|
const removed = currentOwn.filter(
|
|
49
|
-
role => !
|
|
50
|
+
role => !chosenNamesUnique.includes(role.name)
|
|
50
51
|
);
|
|
51
|
-
const newOwn =
|
|
52
|
+
const newOwn = chosenNamesUnique
|
|
52
53
|
.map(name => roleByName(name))
|
|
53
|
-
.filter(role => role && !state.inheritedRoleIds.includes(role.id))
|
|
54
|
+
.filter(role => role && !state.inheritedRoleIds.includes(role.id))
|
|
55
|
+
.map(role => ({ ...role, destroy: false }));
|
|
56
|
+
|
|
57
|
+
const isSameRole = (left, right) =>
|
|
58
|
+
left.name === right.name || String(left.id) === String(right.id);
|
|
54
59
|
|
|
55
60
|
return state.merge({
|
|
56
61
|
assignedRoles: inherited.concat(newOwn),
|
|
57
62
|
toDestroyRoles: state.toDestroyRoles
|
|
58
|
-
.filter(item => !newOwn.some(role => role
|
|
63
|
+
.filter(item => !newOwn.some(role => isSameRole(role, item)))
|
|
59
64
|
.concat(removed.map(role => ({ ...role, destroy: true }))),
|
|
60
65
|
});
|
|
61
66
|
}
|
|
@@ -72,4 +72,45 @@ describe('AnsibleRolesSwitcherReducer', () => {
|
|
|
72
72
|
expect(state.inheritedRoleIds).toEqual([4]);
|
|
73
73
|
expect(state.results).toEqual(ansibleRolesLong);
|
|
74
74
|
});
|
|
75
|
+
|
|
76
|
+
it('restores removed roles without duplicating destroy entries', () => {
|
|
77
|
+
const ownRole = {
|
|
78
|
+
...ansibleRolesLong[4],
|
|
79
|
+
host_ansible_role_id: 42,
|
|
80
|
+
};
|
|
81
|
+
const stateAfterRemoveAll = reducer(
|
|
82
|
+
successState.set('assignedRoles', [
|
|
83
|
+
ansibleRolesLong[3],
|
|
84
|
+
ownRole,
|
|
85
|
+
ansibleRolesLong[5],
|
|
86
|
+
]),
|
|
87
|
+
{
|
|
88
|
+
type: ANSIBLE_ROLES_DUAL_LIST_CHANGE,
|
|
89
|
+
payload: { chosenNames: [] },
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(stateAfterRemoveAll.toDestroyRoles).toEqual([
|
|
94
|
+
{ ...ownRole, destroy: true },
|
|
95
|
+
{ ...ansibleRolesLong[5], destroy: true },
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const stateAfterReAdd = reducer(stateAfterRemoveAll, {
|
|
99
|
+
type: ANSIBLE_ROLES_DUAL_LIST_CHANGE,
|
|
100
|
+
payload: {
|
|
101
|
+
chosenNames: [ownRole.name, ansibleRolesLong[5].name],
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(stateAfterReAdd.assignedRoles.map(role => role.name)).toEqual([
|
|
106
|
+
ansibleRolesLong[3].name,
|
|
107
|
+
ownRole.name,
|
|
108
|
+
ansibleRolesLong[5].name,
|
|
109
|
+
]);
|
|
110
|
+
expect(stateAfterReAdd.assignedRoles[1]).toEqual({
|
|
111
|
+
...ownRole,
|
|
112
|
+
destroy: false,
|
|
113
|
+
});
|
|
114
|
+
expect(stateAfterReAdd.toDestroyRoles).toEqual([]);
|
|
115
|
+
});
|
|
75
116
|
});
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Tooltip } from '@patternfly/react-core';
|
|
3
|
+
import { Title, Tooltip } from '@patternfly/react-core';
|
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
|
|
6
|
-
import ListHeader from '../../DualList/ListHeader';
|
|
7
|
-
|
|
8
6
|
const InheritedRolesList = ({ roles, resourceName }) => {
|
|
9
7
|
if (roles.length === 0) {
|
|
10
8
|
return null;
|
|
@@ -17,7 +15,14 @@ const InheritedRolesList = ({ roles, resourceName }) => {
|
|
|
17
15
|
|
|
18
16
|
return (
|
|
19
17
|
<div className="ansible-inherited-roles">
|
|
20
|
-
<
|
|
18
|
+
<Title
|
|
19
|
+
headingLevel="h2"
|
|
20
|
+
size="md"
|
|
21
|
+
className="ansible-inherited-roles-title"
|
|
22
|
+
ouiaId="inherited-ansible-roles-title"
|
|
23
|
+
>
|
|
24
|
+
{__('Inherited Ansible Roles')}
|
|
25
|
+
</Title>
|
|
21
26
|
<ul>
|
|
22
27
|
{roles.map(role => (
|
|
23
28
|
<li key={role.id}>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
|
+
|
|
6
|
+
import DualList from './index';
|
|
7
|
+
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
availableOptions: ['role.a', 'role.b'],
|
|
10
|
+
chosenOptions: ['role.c'],
|
|
11
|
+
onListChange: jest.fn(),
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('DualList', () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('renders available and chosen options', () => {
|
|
20
|
+
render(<DualList {...defaultProps} />);
|
|
21
|
+
|
|
22
|
+
expect(screen.getByText('Available Ansible roles')).toBeInTheDocument();
|
|
23
|
+
expect(screen.getByText('Assigned Ansible roles')).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByText('role.a')).toBeInTheDocument();
|
|
25
|
+
expect(screen.getByText('role.b')).toBeInTheDocument();
|
|
26
|
+
expect(screen.getByText('role.c')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('moves selected available options to chosen', () => {
|
|
30
|
+
render(<DualList {...defaultProps} />);
|
|
31
|
+
|
|
32
|
+
fireEvent.click(screen.getByRole('option', { name: 'role.a' }));
|
|
33
|
+
userEvent.click(screen.getByRole('button', { name: 'Add selected' }));
|
|
34
|
+
|
|
35
|
+
expect(defaultProps.onListChange).toHaveBeenCalledWith(
|
|
36
|
+
['role.b'],
|
|
37
|
+
['role.c', 'role.a']
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('moves selected chosen options to available', () => {
|
|
42
|
+
render(<DualList {...defaultProps} />);
|
|
43
|
+
|
|
44
|
+
fireEvent.click(screen.getByRole('option', { name: 'role.c' }));
|
|
45
|
+
userEvent.click(screen.getByRole('button', { name: 'Remove selected' }));
|
|
46
|
+
|
|
47
|
+
expect(defaultProps.onListChange).toHaveBeenCalledWith(
|
|
48
|
+
['role.a', 'role.b', 'role.c'],
|
|
49
|
+
[]
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('moves all available options to chosen', () => {
|
|
54
|
+
render(<DualList {...defaultProps} />);
|
|
55
|
+
|
|
56
|
+
userEvent.click(screen.getByRole('button', { name: 'Add all' }));
|
|
57
|
+
|
|
58
|
+
expect(defaultProps.onListChange).toHaveBeenCalledWith(
|
|
59
|
+
[],
|
|
60
|
+
['role.c', 'role.a', 'role.b']
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('moves all chosen options to available', () => {
|
|
65
|
+
render(<DualList {...defaultProps} />);
|
|
66
|
+
|
|
67
|
+
userEvent.click(screen.getByRole('button', { name: 'Remove all' }));
|
|
68
|
+
|
|
69
|
+
expect(defaultProps.onListChange).toHaveBeenCalledWith(
|
|
70
|
+
['role.a', 'role.b', 'role.c'],
|
|
71
|
+
[]
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('disables move controls when nothing is selected or lists are empty', () => {
|
|
76
|
+
render(
|
|
77
|
+
<DualList
|
|
78
|
+
availableOptions={[]}
|
|
79
|
+
chosenOptions={[]}
|
|
80
|
+
onListChange={jest.fn()}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(screen.getByRole('button', { name: 'Add selected' })).toBeDisabled();
|
|
85
|
+
expect(screen.getByRole('button', { name: 'Add all' })).toBeDisabled();
|
|
86
|
+
expect(screen.getByRole('button', { name: 'Remove all' })).toBeDisabled();
|
|
87
|
+
expect(
|
|
88
|
+
screen.getByRole('button', { name: 'Remove selected' })
|
|
89
|
+
).toBeDisabled();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('shows selection status for each pane', () => {
|
|
93
|
+
render(<DualList {...defaultProps} />);
|
|
94
|
+
|
|
95
|
+
fireEvent.click(screen.getByRole('option', { name: 'role.a' }));
|
|
96
|
+
fireEvent.click(screen.getByRole('option', { name: 'role.c' }));
|
|
97
|
+
|
|
98
|
+
expect(screen.getByText('1 of 2 items selected')).toBeInTheDocument();
|
|
99
|
+
expect(screen.getByText('1 of 1 items selected')).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -1,103 +1,47 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import OrderableDualListSelector from 'foremanReact/components/common/OrderableDualListSelector/OrderableDualListSelector';
|
|
3
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const isItemSelected = stateName => item =>
|
|
28
|
-
selectState[stateName].includes(item);
|
|
29
|
-
|
|
30
|
-
const onAddAll = () =>
|
|
31
|
-
props.onListChange([], [...props.chosenOptions, ...props.availableOptions]);
|
|
32
|
-
const onRemoveAll = () =>
|
|
33
|
-
props.onListChange([...props.availableOptions, ...props.chosenOptions], []);
|
|
34
|
-
|
|
35
|
-
const onAddSelected = () => {
|
|
36
|
-
const [newAvailable, newChosen] = moveItems(
|
|
37
|
-
props.availableOptions,
|
|
38
|
-
props.chosenOptions,
|
|
39
|
-
selectState.availableSelected
|
|
40
|
-
);
|
|
41
|
-
setSelectState(defaultSelectState);
|
|
42
|
-
props.onListChange(newAvailable, newChosen);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const onRemoveSelected = () => {
|
|
46
|
-
const [newChosen, newAvailable] = moveItems(
|
|
47
|
-
props.chosenOptions,
|
|
48
|
-
props.availableOptions,
|
|
49
|
-
selectState.chosenSelected
|
|
50
|
-
);
|
|
51
|
-
setSelectState(defaultSelectState);
|
|
52
|
-
props.onListChange(newAvailable, newChosen);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const moveItems = (removeFrom, addTo, selected) => {
|
|
56
|
-
const newRemoveFrom = removeFrom.filter(item => !selected.includes(item));
|
|
57
|
-
return [newRemoveFrom, [...addTo, ...selected]];
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const onChosenSetOrder = items =>
|
|
61
|
-
props.onListChange(props.availableOptions, items);
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div className="pf-v5-c-dual-list-selector">
|
|
65
|
-
<ListPane
|
|
66
|
-
title={__('Available Ansible roles')}
|
|
67
|
-
items={props.availableOptions}
|
|
68
|
-
paneClass="pf-m-available"
|
|
69
|
-
onItemClick={onItemClick('availableSelected')}
|
|
70
|
-
selected={selectState.availableSelected}
|
|
71
|
-
isItemSelected={isItemSelected('availableSelected')}
|
|
72
|
-
/>
|
|
73
|
-
<ListControls
|
|
74
|
-
onAddSelected={onAddSelected}
|
|
75
|
-
onRemoveSelected={onRemoveSelected}
|
|
76
|
-
onRemoveAll={onRemoveAll}
|
|
77
|
-
onAddAll={onAddAll}
|
|
78
|
-
addAllDisabled={props.availableOptions.length === 0}
|
|
79
|
-
removeAllDisabled={props.chosenOptions.length === 0}
|
|
80
|
-
addSelectedDisabled={selectState.availableSelected.length === 0}
|
|
81
|
-
removeSelectedDisabled={selectState.chosenSelected.length === 0}
|
|
82
|
-
/>
|
|
83
|
-
<ListPane
|
|
84
|
-
title={__('Assigned Ansible roles')}
|
|
85
|
-
items={props.chosenOptions}
|
|
86
|
-
paneClass="pf-m-chosen"
|
|
87
|
-
draggable
|
|
88
|
-
onItemClick={onItemClick('chosenSelected')}
|
|
89
|
-
selected={selectState.chosenSelected}
|
|
90
|
-
isItemSelected={isItemSelected('chosenSelected')}
|
|
91
|
-
onSetOrderedItems={onChosenSetOrder}
|
|
92
|
-
/>
|
|
93
|
-
</div>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
6
|
+
const DualList = ({
|
|
7
|
+
availableOptions,
|
|
8
|
+
chosenOptions,
|
|
9
|
+
onListChange,
|
|
10
|
+
id,
|
|
11
|
+
availableOptionsTitle,
|
|
12
|
+
chosenOptionsTitle,
|
|
13
|
+
isDisabled,
|
|
14
|
+
showTooltips,
|
|
15
|
+
}) => (
|
|
16
|
+
<OrderableDualListSelector
|
|
17
|
+
id={id}
|
|
18
|
+
availableOptions={availableOptions}
|
|
19
|
+
chosenOptions={chosenOptions}
|
|
20
|
+
onListChange={onListChange}
|
|
21
|
+
availableOptionsTitle={availableOptionsTitle}
|
|
22
|
+
chosenOptionsTitle={chosenOptionsTitle}
|
|
23
|
+
isDisabled={isDisabled}
|
|
24
|
+
showTooltips={showTooltips}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
96
27
|
|
|
97
28
|
DualList.propTypes = {
|
|
98
29
|
onListChange: PropTypes.func.isRequired,
|
|
99
30
|
chosenOptions: PropTypes.array.isRequired,
|
|
100
31
|
availableOptions: PropTypes.array.isRequired,
|
|
32
|
+
id: PropTypes.string,
|
|
33
|
+
availableOptionsTitle: PropTypes.string,
|
|
34
|
+
chosenOptionsTitle: PropTypes.string,
|
|
35
|
+
isDisabled: PropTypes.bool,
|
|
36
|
+
showTooltips: PropTypes.bool,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
DualList.defaultProps = {
|
|
40
|
+
id: 'ansible-roles-dual-list',
|
|
41
|
+
availableOptionsTitle: __('Available Ansible roles'),
|
|
42
|
+
chosenOptionsTitle: __('Assigned Ansible roles'),
|
|
43
|
+
isDisabled: false,
|
|
44
|
+
showTooltips: true,
|
|
101
45
|
};
|
|
102
46
|
|
|
103
47
|
export default DualList;
|
data/webpack/global_index.js
CHANGED
|
@@ -8,11 +8,13 @@ import AnsibleHostDetail from './components/AnsibleHostDetail';
|
|
|
8
8
|
|
|
9
9
|
import { ANSIBLE_KEY } from './components/AnsibleHostDetail/constants';
|
|
10
10
|
|
|
11
|
+
const ANSIBLE_TAB_WEIGHT = 500;
|
|
12
|
+
|
|
11
13
|
addGlobalFill(
|
|
12
14
|
'host-details-page-tabs',
|
|
13
15
|
ANSIBLE_KEY,
|
|
14
16
|
<AnsibleHostDetail key="ansible-host-detail" />,
|
|
15
|
-
|
|
17
|
+
ANSIBLE_TAB_WEIGHT
|
|
16
18
|
);
|
|
17
19
|
|
|
18
20
|
registerRoutes('foreman_ansible', routes);
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_ansible
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 18.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Lobato Garcia
|
|
@@ -416,12 +416,7 @@ files:
|
|
|
416
416
|
- webpack/components/AnsibleRolesSwitcher/components/InheritedRolesList.test.js
|
|
417
417
|
- webpack/components/AnsibleRolesSwitcher/components/withProtectedView.js
|
|
418
418
|
- webpack/components/AnsibleRolesSwitcher/index.js
|
|
419
|
-
- webpack/components/DualList/DualList.
|
|
420
|
-
- webpack/components/DualList/ListControls.js
|
|
421
|
-
- webpack/components/DualList/ListHeader.js
|
|
422
|
-
- webpack/components/DualList/ListItem.js
|
|
423
|
-
- webpack/components/DualList/ListPane.js
|
|
424
|
-
- webpack/components/DualList/SelectedStatus.js
|
|
419
|
+
- webpack/components/DualList/DualList.test.js
|
|
425
420
|
- webpack/components/DualList/index.js
|
|
426
421
|
- webpack/components/ErrorState.js
|
|
427
422
|
- webpack/components/ReportJsonViewer.js
|
|
@@ -470,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
470
465
|
- !ruby/object:Gem::Version
|
|
471
466
|
version: '0'
|
|
472
467
|
requirements: []
|
|
473
|
-
rubygems_version: 4.0.
|
|
468
|
+
rubygems_version: 4.0.16
|
|
474
469
|
specification_version: 4
|
|
475
470
|
summary: Ansible integration with Foreman (theforeman.org)
|
|
476
471
|
test_files:
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
|
-
|
|
5
|
-
const ListControls = props => (
|
|
6
|
-
<div className="pf-v5-c-dual-list-selector__controls">
|
|
7
|
-
<div className="pf-v5-c-dual-list-selector__controls-item">
|
|
8
|
-
<button
|
|
9
|
-
className="pf-v5-c-button pf-m-plain"
|
|
10
|
-
type="button"
|
|
11
|
-
disabled={props.addSelectedDisabled}
|
|
12
|
-
onClick={props.onAddSelected}
|
|
13
|
-
aria-label={__('Add selected')}
|
|
14
|
-
>
|
|
15
|
-
<i className="fas fa-fw fa-angle-right" />
|
|
16
|
-
</button>
|
|
17
|
-
</div>
|
|
18
|
-
<div className="pf-v5-c-dual-list-selector__controls-item">
|
|
19
|
-
<button
|
|
20
|
-
className="pf-v5-c-button pf-m-plain"
|
|
21
|
-
type="button"
|
|
22
|
-
disabled={props.addAllDisabled}
|
|
23
|
-
onClick={props.onAddAll}
|
|
24
|
-
aria-label={__('Add all')}
|
|
25
|
-
>
|
|
26
|
-
<i className="fas fa-fw fa-angle-double-right" />
|
|
27
|
-
</button>
|
|
28
|
-
</div>
|
|
29
|
-
<div className="pf-v5-c-dual-list-selector__controls-item">
|
|
30
|
-
<button
|
|
31
|
-
className="pf-v5-c-button pf-m-plain"
|
|
32
|
-
type="button"
|
|
33
|
-
disabled={props.removeAllDisabled}
|
|
34
|
-
onClick={props.onRemoveAll}
|
|
35
|
-
aria-label={__('Remove all')}
|
|
36
|
-
>
|
|
37
|
-
<i className="fas fa-fw fa-angle-double-left" />
|
|
38
|
-
</button>
|
|
39
|
-
</div>
|
|
40
|
-
<div className="pf-v5-c-dual-list-selector__controls-item">
|
|
41
|
-
<button
|
|
42
|
-
className="pf-v5-c-button pf-m-plain"
|
|
43
|
-
type="button"
|
|
44
|
-
disabled={props.removeSelectedDisabled}
|
|
45
|
-
onClick={props.onRemoveSelected}
|
|
46
|
-
aria-label={__('Remove selected')}
|
|
47
|
-
>
|
|
48
|
-
<i className="fas fa-fw fa-angle-left" />
|
|
49
|
-
</button>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
ListControls.propTypes = {
|
|
55
|
-
addSelectedDisabled: PropTypes.bool.isRequired,
|
|
56
|
-
onAddSelected: PropTypes.func.isRequired,
|
|
57
|
-
addAllDisabled: PropTypes.bool.isRequired,
|
|
58
|
-
onAddAll: PropTypes.func.isRequired,
|
|
59
|
-
removeAllDisabled: PropTypes.bool.isRequired,
|
|
60
|
-
onRemoveAll: PropTypes.func.isRequired,
|
|
61
|
-
removeSelectedDisabled: PropTypes.bool.isRequired,
|
|
62
|
-
onRemoveSelected: PropTypes.func.isRequired,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default ListControls;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
|
|
4
|
-
const ListHeader = props => (
|
|
5
|
-
<div className="pf-v5-c-dual-list-selector__header">
|
|
6
|
-
<div className="pf-v5-c-dual-list-selector__title">
|
|
7
|
-
<div className="pf-v5-c-dual-list-selector__title-text">
|
|
8
|
-
{props.title}
|
|
9
|
-
</div>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
ListHeader.propTypes = {
|
|
15
|
-
title: PropTypes.string.isRequired,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default ListHeader;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import classNames from 'classnames';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
|
|
5
|
-
const ListItem = props => {
|
|
6
|
-
const draggableBtn = (
|
|
7
|
-
<div className="pf-v5-c-dual-list-selector__draggable">
|
|
8
|
-
<button
|
|
9
|
-
className="pf-v5-c-button pf-m-plain"
|
|
10
|
-
type="button"
|
|
11
|
-
aria-pressed="false"
|
|
12
|
-
aria-label="Reorder"
|
|
13
|
-
id="draggable-list-item-2-draggable-button"
|
|
14
|
-
aria-labelledby="draggable-list-item-2-draggable-button draggable-list-item-2-item-text"
|
|
15
|
-
aria-describedby="draggable-help"
|
|
16
|
-
>
|
|
17
|
-
<i className="fas fa-grip-vertical" aria-hidden="true" />
|
|
18
|
-
</button>
|
|
19
|
-
</div>
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const orderBtn = (
|
|
23
|
-
<span className="foreman-dual-list-order">{`${props.index + 1}. `}</span>
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<li className="pf-v5-c-dual-list-selector__list-item">
|
|
28
|
-
<div
|
|
29
|
-
className={classNames('pf-v5-c-dual-list-selector__list-item-row ', {
|
|
30
|
-
'pf-m-selected': props.selected,
|
|
31
|
-
'pf-m-ghost-row': props.dragging,
|
|
32
|
-
})}
|
|
33
|
-
>
|
|
34
|
-
{props.draggable && draggableBtn}
|
|
35
|
-
<button
|
|
36
|
-
className="pf-v5-c-dual-list-selector__item"
|
|
37
|
-
type="button"
|
|
38
|
-
onClick={props.onClick}
|
|
39
|
-
>
|
|
40
|
-
<span className="pf-v5-c-dual-list-selector__item-main">
|
|
41
|
-
<span className="pf-v5-c-dual-list-selector__item-text">
|
|
42
|
-
{props.draggable && orderBtn}
|
|
43
|
-
<span>{props.name}</span>
|
|
44
|
-
</span>
|
|
45
|
-
</span>
|
|
46
|
-
<span className="pf-v5-c-dual-list-selector__item-count">
|
|
47
|
-
<span className="pf-v5-c-badge pf-m-read" />
|
|
48
|
-
</span>
|
|
49
|
-
</button>
|
|
50
|
-
</div>
|
|
51
|
-
</li>
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
ListItem.propTypes = {
|
|
56
|
-
selected: PropTypes.bool.isRequired,
|
|
57
|
-
dragging: PropTypes.bool,
|
|
58
|
-
draggable: PropTypes.bool,
|
|
59
|
-
onClick: PropTypes.func.isRequired,
|
|
60
|
-
name: PropTypes.string.isRequired,
|
|
61
|
-
index: PropTypes.number.isRequired,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
ListItem.defaultProps = {
|
|
65
|
-
draggable: false,
|
|
66
|
-
dragging: false,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export default ListItem;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { DndProvider } from 'react-dnd';
|
|
3
|
-
import { HTML5Backend } from 'react-dnd-html5-backend';
|
|
4
|
-
import PropTypes from 'prop-types';
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
orderable,
|
|
8
|
-
orderDragged,
|
|
9
|
-
} from 'foremanReact/components/common/forms/OrderableSelect/helpers';
|
|
10
|
-
|
|
11
|
-
import ListItem from './ListItem';
|
|
12
|
-
import ListHeader from './ListHeader';
|
|
13
|
-
import SelectedStatus from './SelectedStatus';
|
|
14
|
-
|
|
15
|
-
const OrderableListItem = orderable(ListItem, {
|
|
16
|
-
type: 'orderableItem',
|
|
17
|
-
getItem: props => ({ id: props.name }),
|
|
18
|
-
direction: 'vertical',
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const ListPane = ({
|
|
22
|
-
items,
|
|
23
|
-
isItemSelected,
|
|
24
|
-
draggable,
|
|
25
|
-
onItemClick,
|
|
26
|
-
paneClass,
|
|
27
|
-
title,
|
|
28
|
-
selected,
|
|
29
|
-
onSetOrderedItems,
|
|
30
|
-
}) => {
|
|
31
|
-
const moveValue = (dragIndex, hoverIndex) => {
|
|
32
|
-
onSetOrderedItems(orderDragged(items, dragIndex, hoverIndex));
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const renderOrderableItem = (item, idx) => (
|
|
36
|
-
<OrderableListItem
|
|
37
|
-
key={item}
|
|
38
|
-
name={item}
|
|
39
|
-
index={idx}
|
|
40
|
-
moveValue={moveValue}
|
|
41
|
-
onClick={onItemClick(item)}
|
|
42
|
-
selected={isItemSelected(item)}
|
|
43
|
-
draggable={draggable}
|
|
44
|
-
/>
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
const renderListItem = (item, idx) => (
|
|
48
|
-
<ListItem
|
|
49
|
-
key={item}
|
|
50
|
-
name={item}
|
|
51
|
-
index={idx}
|
|
52
|
-
onClick={onItemClick(item)}
|
|
53
|
-
selected={isItemSelected(item)}
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
const renderItem = draggable ? renderOrderableItem : renderListItem;
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<div
|
|
61
|
-
className={`pf-v5-c-dual-list-selector__pane pf-m-available ${paneClass}`}
|
|
62
|
-
>
|
|
63
|
-
<ListHeader title={title} />
|
|
64
|
-
<SelectedStatus
|
|
65
|
-
selectedCount={selected.length}
|
|
66
|
-
totalCount={items.length}
|
|
67
|
-
/>
|
|
68
|
-
<div className="pf-v5-c-dual-list-selector__menu">
|
|
69
|
-
<DndProvider backend={HTML5Backend}>
|
|
70
|
-
<ul className="pf-v5-c-dual-list-selector__list">
|
|
71
|
-
{items.map(renderItem)}
|
|
72
|
-
</ul>
|
|
73
|
-
</DndProvider>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
ListPane.propTypes = {
|
|
80
|
-
items: PropTypes.array.isRequired,
|
|
81
|
-
isItemSelected: PropTypes.func.isRequired,
|
|
82
|
-
draggable: PropTypes.bool,
|
|
83
|
-
onItemClick: PropTypes.func.isRequired,
|
|
84
|
-
paneClass: PropTypes.string.isRequired,
|
|
85
|
-
title: PropTypes.string.isRequired,
|
|
86
|
-
selected: PropTypes.array.isRequired,
|
|
87
|
-
onSetOrderedItems: PropTypes.func,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
ListPane.defaultProps = {
|
|
91
|
-
draggable: false,
|
|
92
|
-
onSetOrderedItems: () => {},
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export default ListPane;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { translate as __, sprintf } from 'foremanReact/common/I18n';
|
|
4
|
-
|
|
5
|
-
const SelectedStatus = ({ selectedCount, totalCount }) => (
|
|
6
|
-
<div className="pf-v5-c-dual-list-selector__status">
|
|
7
|
-
<span className="pf-v5-c-dual-list-selector__status-text">
|
|
8
|
-
{sprintf(__('%(selectedCount)s of %(totalCount)s items selected'), {
|
|
9
|
-
selectedCount,
|
|
10
|
-
totalCount,
|
|
11
|
-
})}
|
|
12
|
-
</span>
|
|
13
|
-
</div>
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
SelectedStatus.propTypes = {
|
|
17
|
-
selectedCount: PropTypes.number.isRequired,
|
|
18
|
-
totalCount: PropTypes.number.isRequired,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default SelectedStatus;
|