foreman_scc_manager 4.0.1 → 5.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/app/views/scc_accounts/_form.html.erb +2 -2
- data/lib/foreman_scc_manager/version.rb +1 -1
- data/package.json +6 -6
- data/webpack/components/SCCProductPage/EmptySccProducts.js +7 -2
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCGenericPicker/index.js +238 -50
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/index.js +26 -12
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/styles.scss +2 -2
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/index.js +5 -3
- data/webpack/components/SCCProductPage/components/SCCProductPicker/index.js +48 -33
- data/webpack/components/SCCProductPage/components/SCCProductPicker/styles.scss +5 -5
- data/webpack/components/SCCProductPage/components/SCCProductPickerModal/index.js +13 -6
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/index.js +36 -23
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/styles.scss +10 -10
- data/webpack/components/SCCProductPage/components/SCCProductView/index.js +26 -8
- data/webpack/components/SCCProductPage/components/common/SCCGenericExpander/SCCGenericExpander.test.js +2 -2
- data/webpack/components/SCCProductPage/components/common/SCCGenericExpander/index.js +28 -10
- data/webpack/components/SCCProductPage/sccProductPage.scss +5 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6f492d673c20e4247e652cd47b8c00525da25c7d475fb91f53689810b3161af
|
4
|
+
data.tar.gz: b64d59e459bfbe4fd902515aa6155313157d9874e734770f4927901f00546200
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7748ed462a087d4f07e182b4a4197aec9900af6f04f1527eede78c7f839e139c3cdd9a1fcce0388612f7577e4416368b1a05b7a65e31a118c0e51aabd5547f6f
|
7
|
+
data.tar.gz: ba25b57f3809040e460865d74bc3a07c5680d6168fad57d4f442dd512af0cd2a24d850690bc2acd34eadbf3fe338df08d1bf5a8829cd32db3ed694e0b1fae73e
|
@@ -15,8 +15,8 @@
|
|
15
15
|
<%= password_f f, :password %>
|
16
16
|
<%= text_f f, :base_url, label: _('Base URL') %>
|
17
17
|
<%= selectable_f f, :interval, SccAccount::TYPES, {},
|
18
|
-
{ :label => _('
|
19
|
-
<%= field f, :sync_date, label: _('
|
18
|
+
{ :label => _('Token refresh interval'), :help_block => _("The token refresh interval is used to periodically update the SCC authentication tokens of any imported products.") } %>
|
19
|
+
<%= field f, :sync_date, label: _('Token refresh time'), :help_block => _("Specifies the daily time when the SCC authentication token refresh process starts. Set this to a time outside of business hours (e.g., during the night) to minimize disruption.") do
|
20
20
|
f.datetime_field :sync_date, placeholder: Time.now
|
21
21
|
end %>
|
22
22
|
<%= selectable_f f, :katello_gpg_key_id, @selectable_gpg_keys, {},
|
data/package.json
CHANGED
@@ -22,16 +22,16 @@
|
|
22
22
|
"devDependencies": {
|
23
23
|
"@babel/core": "^7.7.0",
|
24
24
|
"babel-eslint": ">= 10.0.3",
|
25
|
-
"@theforeman/builder": "
|
26
|
-
"@theforeman/eslint-plugin-foreman": "
|
27
|
-
"@theforeman/find-foreman": "
|
28
|
-
"@theforeman/test": "
|
29
|
-
"@theforeman/vendor-dev": "
|
25
|
+
"@theforeman/builder": "^15.0.0",
|
26
|
+
"@theforeman/eslint-plugin-foreman": "^15.0.0",
|
27
|
+
"@theforeman/find-foreman": "^15.0.0",
|
28
|
+
"@theforeman/test": "^15.0.0",
|
29
|
+
"@theforeman/vendor-dev": "^15.0.0",
|
30
30
|
"eslint": "^6.7.2",
|
31
31
|
"eslint-plugin-spellcheck": ">= 0.0.17",
|
32
32
|
"eslint-plugin-react": ">= 7.27.1",
|
33
33
|
"eslint-plugin-react-hooks": ">= 4.3.0",
|
34
|
-
"prettier": "^
|
34
|
+
"prettier": "^1.19.1"
|
35
35
|
},
|
36
36
|
"keywords": [
|
37
37
|
"SUSE",
|
@@ -23,10 +23,15 @@ export const EmptySccProducts = ({ canCreate, sccAccountId }) => {
|
|
23
23
|
header={__('SUSE Customer Center')}
|
24
24
|
description={<div dangerouslySetInnerHTML={{ __html: content }} />}
|
25
25
|
documentation={{
|
26
|
-
url:
|
26
|
+
url:
|
27
|
+
'https://docs.orcharhino.com/or/docs/sources/usage_guides/managing_sles_systems_guide.html#mssg_adding_scc_accounts',
|
27
28
|
}}
|
28
29
|
/>
|
29
|
-
<Button
|
30
|
+
<Button
|
31
|
+
onClick={onSyncStart}
|
32
|
+
ouiaId="scc-manager-welcome-sync-products"
|
33
|
+
className="btn btn-primary"
|
34
|
+
>
|
30
35
|
{__('Synchronize SUSE Account')}
|
31
36
|
</Button>
|
32
37
|
</>
|
@@ -1,79 +1,267 @@
|
|
1
|
+
// Reference: https://v5-archive.patternfly.org/components/menus/select#typeahead
|
2
|
+
|
1
3
|
import React, { useState, useEffect } from 'react';
|
2
4
|
import PropTypes from 'prop-types';
|
3
|
-
import {
|
5
|
+
import {
|
6
|
+
Select,
|
7
|
+
SelectOption,
|
8
|
+
SelectList,
|
9
|
+
MenuToggle,
|
10
|
+
TextInputGroup,
|
11
|
+
TextInputGroupMain,
|
12
|
+
TextInputGroupUtilities,
|
13
|
+
Button,
|
14
|
+
} from '@patternfly/react-core';
|
15
|
+
import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';
|
16
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
4
17
|
|
5
18
|
const GenericSelector = ({
|
6
|
-
|
7
|
-
|
8
|
-
screenReaderLabel,
|
19
|
+
initialSelectOptions,
|
20
|
+
setSelected,
|
9
21
|
initialLabel,
|
22
|
+
selected,
|
23
|
+
inputValue,
|
24
|
+
setInputValue,
|
10
25
|
}) => {
|
11
26
|
const [isOpen, setIsOpen] = useState(false);
|
12
|
-
const [
|
13
|
-
const [
|
14
|
-
|
27
|
+
const [filterValue, setFilterValue] = useState('');
|
28
|
+
const [selectOptions, setSelectOptions] = useState(
|
29
|
+
initialSelectOptions.map((option) => ({
|
30
|
+
children: option,
|
31
|
+
value: option,
|
32
|
+
}))
|
33
|
+
);
|
34
|
+
const [focusedItemIndex, setFocusedItemIndex] = useState(null);
|
35
|
+
const [activeItemId, setActiveItemId] = useState(null);
|
36
|
+
const NO_RESULTS = __('no results');
|
15
37
|
|
16
38
|
useEffect(() => {
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
39
|
+
let newSelectOptions = initialSelectOptions.map((option) => ({
|
40
|
+
children: option,
|
41
|
+
value: option,
|
42
|
+
}));
|
43
|
+
if (filterValue) {
|
44
|
+
newSelectOptions = newSelectOptions.filter((menuItem) =>
|
45
|
+
String(menuItem.children)
|
46
|
+
.toLowerCase()
|
47
|
+
.includes(filterValue.toLowerCase())
|
48
|
+
);
|
49
|
+
if (!newSelectOptions.length) {
|
50
|
+
newSelectOptions = [
|
51
|
+
{
|
52
|
+
isAriaDisabled: true,
|
53
|
+
children: `No results found for "${filterValue}"`,
|
54
|
+
value: NO_RESULTS,
|
55
|
+
},
|
56
|
+
];
|
57
|
+
}
|
58
|
+
if (!isOpen) {
|
59
|
+
setIsOpen(true);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
setSelectOptions(newSelectOptions);
|
63
|
+
}, [filterValue, initialSelectOptions]);
|
64
|
+
const createItemId = (value) =>
|
65
|
+
`select-typeahead-${value?.replace(' ', '-')}`;
|
66
|
+
const setActiveAndFocusedItem = (itemIndex) => {
|
67
|
+
setFocusedItemIndex(itemIndex);
|
68
|
+
const focusedItem = selectOptions[itemIndex];
|
69
|
+
setActiveItemId(createItemId(focusedItem.value));
|
23
70
|
};
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
setIsOpen(!isOpen);
|
28
|
-
setGlobalSelected(value);
|
71
|
+
const resetActiveAndFocusedItem = () => {
|
72
|
+
setFocusedItemIndex(null);
|
73
|
+
setActiveItemId(null);
|
29
74
|
};
|
30
|
-
|
31
|
-
|
32
|
-
|
75
|
+
const closeMenu = () => {
|
76
|
+
setIsOpen(false);
|
77
|
+
resetActiveAndFocusedItem();
|
33
78
|
};
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
79
|
+
const onInputClick = () => {
|
80
|
+
if (!isOpen) {
|
81
|
+
setIsOpen(true);
|
82
|
+
} else if (!inputValue) {
|
83
|
+
closeMenu();
|
84
|
+
}
|
85
|
+
};
|
86
|
+
const selectOption = (value, content) => {
|
87
|
+
setInputValue(String(content));
|
88
|
+
setFilterValue('');
|
89
|
+
setSelected(String(value));
|
90
|
+
closeMenu();
|
45
91
|
};
|
92
|
+
const onSelect = (_event, value) => {
|
93
|
+
if (value && value !== NO_RESULTS) {
|
94
|
+
const optionText = selectOptions.find((option) => option.value === value)
|
95
|
+
?.children;
|
96
|
+
selectOption(value, optionText);
|
97
|
+
}
|
98
|
+
};
|
99
|
+
const onTextInputChange = (_event, value) => {
|
100
|
+
setInputValue(value);
|
101
|
+
setFilterValue(value);
|
102
|
+
resetActiveAndFocusedItem();
|
103
|
+
if (value !== selected) {
|
104
|
+
setSelected('');
|
105
|
+
}
|
106
|
+
};
|
107
|
+
const handleMenuArrowKeys = (key) => {
|
108
|
+
let indexToFocus = 0;
|
109
|
+
if (!isOpen) {
|
110
|
+
setIsOpen(true);
|
111
|
+
}
|
112
|
+
if (selectOptions.every((option) => option.isDisabled)) {
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
if (key === 'ArrowUp') {
|
116
|
+
if (focusedItemIndex === null || focusedItemIndex === 0) {
|
117
|
+
indexToFocus = selectOptions.length - 1;
|
118
|
+
} else {
|
119
|
+
indexToFocus = focusedItemIndex - 1;
|
120
|
+
}
|
121
|
+
while (selectOptions[indexToFocus].isDisabled) {
|
122
|
+
indexToFocus--;
|
123
|
+
if (indexToFocus === -1) {
|
124
|
+
indexToFocus = selectOptions.length - 1;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
if (key === 'ArrowDown') {
|
129
|
+
if (
|
130
|
+
focusedItemIndex === null ||
|
131
|
+
focusedItemIndex === selectOptions.length - 1
|
132
|
+
) {
|
133
|
+
indexToFocus = 0;
|
134
|
+
} else {
|
135
|
+
indexToFocus = focusedItemIndex + 1;
|
136
|
+
}
|
137
|
+
while (selectOptions[indexToFocus].isDisabled) {
|
138
|
+
indexToFocus++;
|
139
|
+
if (indexToFocus === selectOptions.length) {
|
140
|
+
indexToFocus = 0;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
setActiveAndFocusedItem(indexToFocus);
|
145
|
+
};
|
146
|
+
const onInputKeyDown = (event) => {
|
147
|
+
const focusedItem =
|
148
|
+
focusedItemIndex !== null ? selectOptions[focusedItemIndex] : null;
|
149
|
+
switch (event.key) {
|
150
|
+
case 'Enter':
|
151
|
+
if (
|
152
|
+
isOpen &&
|
153
|
+
focusedItem &&
|
154
|
+
focusedItem.value !== NO_RESULTS &&
|
155
|
+
!focusedItem.isAriaDisabled
|
156
|
+
) {
|
157
|
+
selectOption(focusedItem.value, focusedItem.children);
|
158
|
+
}
|
159
|
+
if (!isOpen) {
|
160
|
+
setIsOpen(true);
|
161
|
+
}
|
162
|
+
break;
|
163
|
+
case 'ArrowUp':
|
164
|
+
case 'ArrowDown':
|
165
|
+
event.preventDefault();
|
166
|
+
handleMenuArrowKeys(event.key);
|
167
|
+
break;
|
168
|
+
default:
|
169
|
+
break;
|
170
|
+
}
|
171
|
+
};
|
172
|
+
const onToggleClick = () => {
|
173
|
+
setIsOpen(!isOpen);
|
174
|
+
};
|
175
|
+
const onClearButtonClick = () => {
|
176
|
+
setSelected('');
|
177
|
+
setInputValue('');
|
178
|
+
setFilterValue('');
|
179
|
+
resetActiveAndFocusedItem();
|
180
|
+
};
|
181
|
+
const toggle = (toggleRef) => (
|
182
|
+
<MenuToggle
|
183
|
+
ref={toggleRef}
|
184
|
+
variant="typeahead"
|
185
|
+
onClick={onToggleClick}
|
186
|
+
isExpanded={isOpen}
|
187
|
+
isFullWidth
|
188
|
+
>
|
189
|
+
<TextInputGroup isPlain>
|
190
|
+
<TextInputGroupMain
|
191
|
+
value={inputValue}
|
192
|
+
onClick={onInputClick}
|
193
|
+
onChange={onTextInputChange}
|
194
|
+
onKeyDown={onInputKeyDown}
|
195
|
+
id={initialLabel.concat('typeahead-select-input')}
|
196
|
+
autoComplete="off"
|
197
|
+
placeholder={initialLabel}
|
198
|
+
{...(activeItemId && {
|
199
|
+
'aria-activedescendant': activeItemId,
|
200
|
+
})}
|
201
|
+
role="combobox"
|
202
|
+
isExpanded={isOpen}
|
203
|
+
/>
|
46
204
|
|
205
|
+
<TextInputGroupUtilities
|
206
|
+
{...(!inputValue
|
207
|
+
? {
|
208
|
+
style: {
|
209
|
+
display: 'none',
|
210
|
+
},
|
211
|
+
}
|
212
|
+
: {})}
|
213
|
+
>
|
214
|
+
<Button
|
215
|
+
variant="plain"
|
216
|
+
ouiaId={initialLabel.concat('scc-product-picker-button')}
|
217
|
+
onClick={onClearButtonClick}
|
218
|
+
>
|
219
|
+
<TimesIcon aria-hidden />
|
220
|
+
</Button>
|
221
|
+
</TextInputGroupUtilities>
|
222
|
+
</TextInputGroup>
|
223
|
+
</MenuToggle>
|
224
|
+
);
|
47
225
|
return (
|
48
|
-
<
|
49
|
-
|
50
|
-
|
226
|
+
<Select
|
227
|
+
id={initialLabel}
|
228
|
+
ouiaId={initialLabel.concat('scc-product-picker-select')}
|
51
229
|
isOpen={isOpen}
|
52
|
-
|
53
|
-
onToggle={onToggle}
|
230
|
+
selected={selected}
|
54
231
|
onSelect={onSelect}
|
55
|
-
|
56
|
-
|
232
|
+
onOpenChange={(isOpenSelect) => {
|
233
|
+
!isOpenSelect && closeMenu();
|
234
|
+
}}
|
235
|
+
toggle={toggle}
|
236
|
+
shouldFocusFirstItemOnOpen={false}
|
57
237
|
>
|
58
|
-
{
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
238
|
+
<SelectList id={initialLabel.concat('select-typeahead-listbox')}>
|
239
|
+
{selectOptions.map((option, index) => (
|
240
|
+
<SelectOption
|
241
|
+
key={option.value || option.children}
|
242
|
+
isFocused={focusedItemIndex === index}
|
243
|
+
id={createItemId(option.value)}
|
244
|
+
className={option.className}
|
245
|
+
{...option}
|
246
|
+
ref={null}
|
247
|
+
/>
|
248
|
+
))}
|
249
|
+
</SelectList>
|
250
|
+
</Select>
|
64
251
|
);
|
65
252
|
};
|
66
253
|
|
67
254
|
GenericSelector.propTypes = {
|
68
|
-
|
69
|
-
setGlobalSelected: PropTypes.func.isRequired,
|
70
|
-
screenReaderLabel: PropTypes.string,
|
255
|
+
initialSelectOptions: PropTypes.array,
|
71
256
|
initialLabel: PropTypes.string,
|
257
|
+
selected: PropTypes.string.isRequired,
|
258
|
+
setSelected: PropTypes.func.isRequired,
|
259
|
+
inputValue: PropTypes.string.isRequired,
|
260
|
+
setInputValue: PropTypes.func.isRequired,
|
72
261
|
};
|
73
262
|
|
74
263
|
GenericSelector.defaultProps = {
|
75
|
-
|
76
|
-
screenReaderLabel: '',
|
264
|
+
initialSelectOptions: [],
|
77
265
|
initialLabel: '',
|
78
266
|
};
|
79
267
|
|
@@ -1,16 +1,25 @@
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
Select,
|
6
|
+
SelectOption,
|
7
|
+
SelectList,
|
8
|
+
MenuToggle,
|
9
|
+
} from '@patternfly/react-core';
|
5
10
|
|
6
11
|
import './styles.scss';
|
7
12
|
|
8
|
-
const createRepoSelectOption = (repo, disableRepos) => (
|
13
|
+
const createRepoSelectOption = (repo, disableRepos, selectedItems) => (
|
9
14
|
<SelectOption
|
15
|
+
hasCheckbox
|
10
16
|
key={repo.id}
|
11
17
|
isDisabled={repo.katello_repository_id !== null || disableRepos}
|
12
18
|
value={repo.name}
|
13
|
-
|
19
|
+
isSelected={selectedItems.includes(repo.name)}
|
20
|
+
>
|
21
|
+
{repo.name}
|
22
|
+
</SelectOption>
|
14
23
|
);
|
15
24
|
|
16
25
|
const setRepoSelection = (
|
@@ -63,8 +72,9 @@ const SCCRepoPicker = ({
|
|
63
72
|
productAlreadySynced
|
64
73
|
)
|
65
74
|
);
|
66
|
-
|
67
|
-
|
75
|
+
|
76
|
+
const onToggleClick = () => {
|
77
|
+
setIsOpen(!isOpen);
|
68
78
|
};
|
69
79
|
|
70
80
|
useEffect(() => {
|
@@ -135,21 +145,25 @@ const SCCRepoPicker = ({
|
|
135
145
|
};
|
136
146
|
|
137
147
|
const selectOptions = sccRepos.map((repo) =>
|
138
|
-
createRepoSelectOption(repo, disableRepos)
|
148
|
+
createRepoSelectOption(repo, disableRepos, selected)
|
149
|
+
);
|
150
|
+
|
151
|
+
const toggle = (toggleRef) => (
|
152
|
+
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
|
153
|
+
{sprintf(__('%s/%s'), selected.length, sccRepos.length)}
|
154
|
+
</MenuToggle>
|
139
155
|
);
|
140
156
|
|
141
157
|
return (
|
142
158
|
<Select
|
143
|
-
|
144
|
-
|
145
|
-
onToggle={onToggle}
|
159
|
+
ouiaId={sccProductId.toString().concat('scc-manager-repo-picker')}
|
160
|
+
toggle={toggle}
|
146
161
|
onSelect={onSelect}
|
147
162
|
selections={selected}
|
148
163
|
isOpen={isOpen}
|
149
|
-
|
150
|
-
placeholderText={sprintf(__('%s/%s'), selected.length, sccRepos.length)}
|
164
|
+
onOpenChange={(nextOpen) => setIsOpen(nextOpen)}
|
151
165
|
>
|
152
|
-
{selectOptions}
|
166
|
+
<SelectList>{selectOptions}</SelectList>
|
153
167
|
</Select>
|
154
168
|
);
|
155
169
|
};
|
@@ -1,3 +1,3 @@
|
|
1
|
-
.pf-c-tree-view__node .pf-c-tree-view__node-count .pf-c-badge.pf-m-read {
|
2
|
-
--pf-c-badge--m-read--BackgroundColor: transparent;
|
1
|
+
.pf-v5-c-tree-view__node .pf-v5-c-tree-view__node-count .pf-v5-c-badge.pf-m-read {
|
2
|
+
--pf-v5-c-badge--m-read--BackgroundColor: transparent;
|
3
3
|
}
|
data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/index.js
CHANGED
@@ -38,7 +38,7 @@ const addSCCRepoPickerToTree = (
|
|
38
38
|
) => {
|
39
39
|
tree.customBadgeContent = [];
|
40
40
|
tree.customBadgeContent.push(
|
41
|
-
<Tooltip content={__('Filter repositories')}>
|
41
|
+
<Tooltip aria="none" aria-live="polite" content={__('Filter repositories')}>
|
42
42
|
<SCCRepoPicker
|
43
43
|
sccRepos={tree.scc_repositories}
|
44
44
|
disableRepos={tree.product_id === null && !tree.checkProps.checked}
|
@@ -234,7 +234,7 @@ const SCCTreePicker = ({
|
|
234
234
|
};
|
235
235
|
|
236
236
|
return (
|
237
|
-
<Card>
|
237
|
+
<Card ouiaId="scc-manager-product-picker-card">
|
238
238
|
<CardBody>
|
239
239
|
<Flex direction={{ default: 'column' }}>
|
240
240
|
<Flex>
|
@@ -249,6 +249,7 @@ const SCCTreePicker = ({
|
|
249
249
|
>
|
250
250
|
<Switch
|
251
251
|
id="filter-debug-switch"
|
252
|
+
ouiaId="scc-manager-filter-debug-switch"
|
252
253
|
onChange={debugFilterChange}
|
253
254
|
isChecked={activateDebugFilter}
|
254
255
|
label={__('Include Debug and Source Pool repositories')}
|
@@ -261,13 +262,14 @@ const SCCTreePicker = ({
|
|
261
262
|
data={sccProductTree}
|
262
263
|
allExpanded={expandAll}
|
263
264
|
onCheck={onCheck}
|
264
|
-
|
265
|
+
hasCheckboxes
|
265
266
|
hasBadges
|
266
267
|
hasGuides
|
267
268
|
/>
|
268
269
|
</Flex>
|
269
270
|
<Flex>
|
270
271
|
<Button
|
272
|
+
ouiaId="scc-manager-add-products-button"
|
271
273
|
variant="primary"
|
272
274
|
onClick={submitForm}
|
273
275
|
isDisabled={Object.keys(selectedRepos).length === 0}
|
@@ -24,9 +24,6 @@ const resetSelectionStringArch = __(' -- Select Architecture --');
|
|
24
24
|
const genericFilter = (object, comparator) =>
|
25
25
|
// we can have architectures that are not set
|
26
26
|
comparator === '' ||
|
27
|
-
comparator === resetSelectionStringProduct ||
|
28
|
-
comparator === resetSelectionStringVersion ||
|
29
|
-
comparator === resetSelectionStringArch ||
|
30
27
|
object === comparator ||
|
31
28
|
(object === null && comparator === 'no arch');
|
32
29
|
|
@@ -61,6 +58,9 @@ const SCCProductPicker = ({
|
|
61
58
|
const [filteredSccProducts, setFilteredSccProducts] = useState([]);
|
62
59
|
const [showSearchTree, setShowSearchTree] = useState(false);
|
63
60
|
const [isExpanded, setIsExpanded] = useState(false);
|
61
|
+
const [searchInputProduct, setSearchInputProduct] = useState('');
|
62
|
+
const [searchInputVersion, setSearchInputVersion] = useState('');
|
63
|
+
const [searchInputArch, setSearchInputArch] = useState('');
|
64
64
|
|
65
65
|
useEffect(() => {
|
66
66
|
if (editProductId !== 0) {
|
@@ -78,10 +78,12 @@ const SCCProductPicker = ({
|
|
78
78
|
}, [editProductId, sccProducts]);
|
79
79
|
|
80
80
|
const onProductSelectionChange = (value) => {
|
81
|
-
if (value
|
82
|
-
setVersionItems(filterVersionByProduct(sccProducts, value));
|
83
|
-
} else {
|
81
|
+
if (value === '') {
|
84
82
|
setVersionItems([]);
|
83
|
+
setSearchInputVersion('');
|
84
|
+
setSearchInputArch('');
|
85
|
+
} else {
|
86
|
+
setVersionItems(filterVersionByProduct(sccProducts, value));
|
85
87
|
}
|
86
88
|
setSelectedProduct(value);
|
87
89
|
setArchItems([]);
|
@@ -90,8 +92,9 @@ const SCCProductPicker = ({
|
|
90
92
|
};
|
91
93
|
|
92
94
|
const onVersionSelectionChange = (value) => {
|
93
|
-
if (value ===
|
95
|
+
if (value === '') {
|
94
96
|
setArchItems([]);
|
97
|
+
setSearchInputArch('');
|
95
98
|
} else {
|
96
99
|
setArchItems(
|
97
100
|
filterArchByVersionAndProduct(sccProducts, selectedProduct, value)
|
@@ -102,6 +105,9 @@ const SCCProductPicker = ({
|
|
102
105
|
};
|
103
106
|
|
104
107
|
const onArchSelectionChange = (value) => {
|
108
|
+
if (value === '') {
|
109
|
+
setArchItems([]);
|
110
|
+
}
|
105
111
|
setSelectedArch(value);
|
106
112
|
};
|
107
113
|
|
@@ -126,10 +132,20 @@ const SCCProductPicker = ({
|
|
126
132
|
setSelectedProduct('');
|
127
133
|
setSelectedVersion('');
|
128
134
|
setSelectedArch('');
|
135
|
+
setVersionItems([]);
|
136
|
+
setArchItems([]);
|
137
|
+
setSearchInputProduct('');
|
138
|
+
setSearchInputVersion('');
|
139
|
+
setSearchInputArch('');
|
129
140
|
};
|
130
141
|
|
131
142
|
return (
|
132
|
-
<Card
|
143
|
+
<Card
|
144
|
+
border="dark"
|
145
|
+
ouiaId="scc-manager-product-selection-card"
|
146
|
+
id="product-selection-card"
|
147
|
+
isExpanded={isExpanded}
|
148
|
+
>
|
133
149
|
<CardHeader onExpand={onExpand}>
|
134
150
|
<CardTitle>{__('Select SUSE products')}</CardTitle>
|
135
151
|
</CardHeader>
|
@@ -139,62 +155,61 @@ const SCCProductPicker = ({
|
|
139
155
|
<Flex>
|
140
156
|
<FlexItem>
|
141
157
|
<SCCGenericPicker
|
142
|
-
key="prod-select"
|
143
|
-
|
144
|
-
|
145
|
-
? productItems
|
146
|
-
: [resetSelectionStringProduct].concat(productItems)
|
147
|
-
}
|
148
|
-
setGlobalSelected={onProductSelectionChange}
|
149
|
-
screenReaderLabel={resetSelectionStringProduct}
|
158
|
+
key="scc-prod-select"
|
159
|
+
initialSelectOptions={productItems}
|
160
|
+
setSelected={onProductSelectionChange}
|
150
161
|
initialLabel={
|
151
162
|
selectedProduct === ''
|
152
163
|
? resetSelectionStringProduct
|
153
164
|
: selectedProduct
|
154
165
|
}
|
166
|
+
selected={selectedProduct}
|
167
|
+
inputValue={searchInputProduct}
|
168
|
+
setInputValue={setSearchInputProduct}
|
155
169
|
/>
|
156
170
|
</FlexItem>
|
157
171
|
<FlexItem>
|
158
172
|
<SCCGenericPicker
|
159
|
-
key="vers-select"
|
160
|
-
|
161
|
-
|
162
|
-
? versionItems
|
163
|
-
: [resetSelectionStringVersion].concat(versionItems)
|
164
|
-
}
|
165
|
-
setGlobalSelected={onVersionSelectionChange}
|
166
|
-
screenReaderLabel={resetSelectionStringVersion}
|
173
|
+
key="scc-vers-select"
|
174
|
+
initialSelectOptions={versionItems}
|
175
|
+
setSelected={onVersionSelectionChange}
|
167
176
|
initialLabel={
|
168
177
|
selectedVersion === ''
|
169
178
|
? resetSelectionStringVersion
|
170
179
|
: selectedVersion
|
171
180
|
}
|
181
|
+
selected={selectedVersion}
|
182
|
+
inputValue={searchInputVersion}
|
183
|
+
setInputValue={setSearchInputVersion}
|
172
184
|
/>
|
173
185
|
</FlexItem>
|
174
186
|
<FlexItem>
|
175
187
|
<SCCGenericPicker
|
176
|
-
key="arch-select"
|
177
|
-
|
178
|
-
|
179
|
-
? archItems
|
180
|
-
: [resetSelectionStringArch].concat(archItems)
|
181
|
-
}
|
182
|
-
setGlobalSelected={onArchSelectionChange}
|
183
|
-
screenReaderLabel={resetSelectionStringArch}
|
188
|
+
key="scc-arch-select"
|
189
|
+
initialSelectOptions={archItems}
|
190
|
+
setSelected={onArchSelectionChange}
|
184
191
|
initialLabel={
|
185
192
|
selectedArch === ''
|
186
193
|
? resetSelectionStringArch
|
187
194
|
: selectedArch
|
188
195
|
}
|
196
|
+
selected={selectedArch}
|
197
|
+
inputValue={searchInputArch}
|
198
|
+
setInputValue={setSearchInputArch}
|
189
199
|
/>
|
190
200
|
</FlexItem>
|
191
201
|
<FlexItem>
|
192
|
-
<Button
|
202
|
+
<Button
|
203
|
+
ouiaId="scc-manager-product-search-button"
|
204
|
+
variant="primary"
|
205
|
+
onClick={filterProducts}
|
206
|
+
>
|
193
207
|
{__('Search')}
|
194
208
|
</Button>
|
195
209
|
</FlexItem>
|
196
210
|
<FlexItem>
|
197
211
|
<Button
|
212
|
+
ouiaId="scc-manager-product-search-reset-button"
|
198
213
|
variant="link"
|
199
214
|
icon={<TimesIcon />}
|
200
215
|
onClick={resetTreeForm}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
@import '~@theforeman/vendor/scss/variables';
|
2
2
|
|
3
|
-
.pf-c-select__toggle {
|
4
|
-
font-size: var(--pf-global--FontSize--xs);
|
5
|
-
font-weight: var(--pf-global--FontWeight--bold);
|
3
|
+
.pf-v5-c-select__toggle {
|
4
|
+
font-size: var(--pf-v5-global--FontSize--xs);
|
5
|
+
font-weight: var(--pf-v5-global--FontWeight--bold);
|
6
6
|
};
|
7
7
|
|
8
|
-
.pf-c-switch__input ~ .pf-c-switch__label {
|
9
|
-
font-size: var(--pf-global--FontSize--xs);
|
8
|
+
.pf-v5-c-switch__input ~ .pf-v5-c-switch__label {
|
9
|
+
font-size: var(--pf-v5-global--FontSize--xs);
|
10
10
|
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { Fragment } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import ForemanModal from 'foremanReact/components/ForemanModal';
|
4
4
|
|
@@ -15,14 +15,14 @@ import {
|
|
15
15
|
} from '@patternfly/react-core';
|
16
16
|
|
17
17
|
const generateRepoList = (repoNames, productName) => (
|
18
|
-
|
18
|
+
<Fragment key={productName}>
|
19
19
|
<TextListItem key={productName}>{productName}</TextListItem>
|
20
20
|
<TextList key={repoNames}>
|
21
21
|
{repoNames.map((repo) => (
|
22
22
|
<TextListItem key={repo}>{repo}</TextListItem>
|
23
23
|
))}
|
24
24
|
</TextList>
|
25
|
-
|
25
|
+
</Fragment>
|
26
26
|
);
|
27
27
|
|
28
28
|
const generateProductList = (reposToSubscribe) => (
|
@@ -41,12 +41,16 @@ const SCCProductPickerModal = ({ id, taskId, reposToSubscribe }) => (
|
|
41
41
|
title={__('Summary of SCC product subscription')}
|
42
42
|
enforceFocus
|
43
43
|
>
|
44
|
-
<Card>
|
44
|
+
<Card ouiaId="scc-product-picker-modal">
|
45
45
|
<CardBody>
|
46
46
|
<TextContent key={taskId}>
|
47
|
-
<Text
|
47
|
+
<Text
|
48
|
+
ouiaId={'modal1'.concat(taskId)}
|
49
|
+
key={'modal1'.concat(taskId)}
|
50
|
+
>
|
48
51
|
{__('The subscription task with id ')}
|
49
52
|
<Text
|
53
|
+
ouiaId={'modal2'.concat(taskId)}
|
50
54
|
key={'modal2'.concat(taskId)}
|
51
55
|
component={TextVariants.a}
|
52
56
|
target="_blank"
|
@@ -56,7 +60,10 @@ const SCCProductPickerModal = ({ id, taskId, reposToSubscribe }) => (
|
|
56
60
|
</Text>
|
57
61
|
{__(' has started successfully.')}
|
58
62
|
</Text>
|
59
|
-
<Text
|
63
|
+
<Text
|
64
|
+
ouiaId={'modal3'.concat(taskId)}
|
65
|
+
key={'modal3'.concat(taskId)}
|
66
|
+
>
|
60
67
|
{__('The following products will be imported:')}
|
61
68
|
</Text>
|
62
69
|
{generateProductList(reposToSubscribe)}
|
data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/index.js
CHANGED
@@ -5,10 +5,11 @@ import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
import PropTypes from 'prop-types';
|
6
6
|
import React, { useState } from 'react';
|
7
7
|
import {
|
8
|
+
Tooltip,
|
8
9
|
Dropdown,
|
9
10
|
DropdownItem,
|
10
|
-
|
11
|
-
|
11
|
+
DropdownList,
|
12
|
+
MenuToggle,
|
12
13
|
} from '@patternfly/react-core';
|
13
14
|
import { Icon } from 'patternfly-react';
|
14
15
|
import { BrowserRouter, Link } from 'react-router-dom';
|
@@ -20,7 +21,10 @@ const createKatelloRepoLink = (repo, sccProductId) => {
|
|
20
21
|
`/products/${sccProductId}/repositories/${repo.katello_repository_id}`
|
21
22
|
);
|
22
23
|
return (
|
23
|
-
<Tooltip
|
24
|
+
<Tooltip
|
25
|
+
key={'scc-manager-repo-view-tooltip-'.concat(repo.id)}
|
26
|
+
content={__('Go to Repository page')}
|
27
|
+
>
|
24
28
|
<BrowserRouter>
|
25
29
|
<Link to={url} target="_blank">
|
26
30
|
{repo.name}
|
@@ -33,18 +37,25 @@ const createKatelloRepoLink = (repo, sccProductId) => {
|
|
33
37
|
const createRepoDropDownItem = (repo, sccProductId) => (
|
34
38
|
<DropdownItem
|
35
39
|
key={repo.id}
|
40
|
+
ouiaId={repo.id}
|
36
41
|
component="button"
|
37
42
|
icon={
|
38
43
|
repo.subscription_valid ? (
|
39
44
|
repo.katello_repository_id !== null ? (
|
40
45
|
<Icon name="check" type="fa" />
|
41
46
|
) : (
|
42
|
-
<Tooltip
|
47
|
+
<Tooltip
|
48
|
+
key={'scc-manager-repo-link-tooltip-'.concat(repo.id)}
|
49
|
+
content={__('Repository not imported')}
|
50
|
+
>
|
43
51
|
<Icon name="ban" type="fa" />
|
44
52
|
</Tooltip>
|
45
53
|
)
|
46
54
|
) : (
|
47
|
-
<Tooltip
|
55
|
+
<Tooltip
|
56
|
+
key={'scc-manager-repo-link-tooltip-'.concat(repo.id)}
|
57
|
+
content={__('Please check your SUSE subscription')}
|
58
|
+
>
|
48
59
|
<Icon name="warning-triangle-o" type="pf" size="2x" />
|
49
60
|
</Tooltip>
|
50
61
|
)
|
@@ -58,8 +69,8 @@ const createRepoDropDownItem = (repo, sccProductId) => (
|
|
58
69
|
|
59
70
|
const SCCRepoView = ({ sccRepos, sccProductId }) => {
|
60
71
|
const [isOpen, setIsOpen] = useState(false);
|
61
|
-
const
|
62
|
-
setIsOpen(
|
72
|
+
const onToggleClick = () => {
|
73
|
+
setIsOpen(!isOpen);
|
63
74
|
};
|
64
75
|
|
65
76
|
const onFocus = () => {
|
@@ -70,7 +81,7 @@ const SCCRepoView = ({ sccRepos, sccProductId }) => {
|
|
70
81
|
};
|
71
82
|
|
72
83
|
const onSelect = (event) => {
|
73
|
-
setIsOpen(
|
84
|
+
setIsOpen(false);
|
74
85
|
onFocus();
|
75
86
|
};
|
76
87
|
|
@@ -78,25 +89,27 @@ const SCCRepoView = ({ sccRepos, sccProductId }) => {
|
|
78
89
|
createRepoDropDownItem(repo, sccProductId)
|
79
90
|
);
|
80
91
|
|
92
|
+
const toggle = (toggleRef) => (
|
93
|
+
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
|
94
|
+
{sprintf(
|
95
|
+
__('Repositories (%s/%s)'),
|
96
|
+
sccRepos.filter((r) => r.katello_repository_id !== null).length,
|
97
|
+
sccRepos.length
|
98
|
+
)}
|
99
|
+
</MenuToggle>
|
100
|
+
);
|
101
|
+
|
81
102
|
return (
|
82
103
|
<Dropdown
|
104
|
+
ouiaId={sccProductId?.toString().concat('scc-manager-repo-view')}
|
105
|
+
onClick={onToggleClick}
|
83
106
|
onSelect={onSelect}
|
84
|
-
toggle={
|
85
|
-
<BadgeToggle
|
86
|
-
id={sprintf('scc-repo-show-toggle-id-%s', sccProductId)}
|
87
|
-
key={sprintf('scc-repo-show-toggle-id-%s', sccProductId)}
|
88
|
-
onToggle={onToggle}
|
89
|
-
>
|
90
|
-
{sprintf(
|
91
|
-
__('Repositories (%s/%s)'),
|
92
|
-
sccRepos.filter((r) => r.katello_repository_id !== null).length,
|
93
|
-
sccRepos.length
|
94
|
-
)}
|
95
|
-
</BadgeToggle>
|
96
|
-
}
|
107
|
+
toggle={toggle}
|
97
108
|
isOpen={isOpen}
|
98
|
-
|
99
|
-
|
109
|
+
onOpenChange={(isOpenMenu) => setIsOpen(isOpenMenu)}
|
110
|
+
>
|
111
|
+
<DropdownList>{dropdownItems}</DropdownList>
|
112
|
+
</Dropdown>
|
100
113
|
);
|
101
114
|
};
|
102
115
|
|
data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/styles.scss
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
.pf-c-button.pf-m-plain {
|
2
|
-
--pf-c-button--PaddingTop: var(--pf-global--spacer--xs);
|
3
|
-
--pf-c-button--PaddingRight: var(--pf-global--spacer--sm);
|
4
|
-
--pf-c-button--PaddingBottom: var(--pf-global--spacer--xs);
|
5
|
-
--pf-c-button--PaddingLeft: var(--pf-global--spacer--sm);
|
1
|
+
.pf-v5-c-button.pf-m-plain {
|
2
|
+
--pf-v5-c-button--PaddingTop: var(--pf-v5-global--spacer--xs);
|
3
|
+
--pf-v5-c-button--PaddingRight: var(--pf-v5-global--spacer--sm);
|
4
|
+
--pf-v5-c-button--PaddingBottom: var(--pf-v5-global--spacer--xs);
|
5
|
+
--pf-v5-c-button--PaddingLeft: var(--pf-v5-global--spacer--sm);
|
6
6
|
}
|
7
7
|
|
8
|
-
.pf-c-dropdown__toggle::before {
|
9
|
-
--pf-c-button--PaddingTop: var(--pf-global--spacer--xs);
|
10
|
-
--pf-c-button--PaddingRight: var(--pf-global--spacer--xs);
|
11
|
-
--pf-c-button--PaddingBottom: var(--pf-global--spacer--xs);
|
12
|
-
--pf-c-button--PaddingLeft: var(--pf-global--spacer--xs);
|
8
|
+
.pf-v5-c-dropdown__toggle::before {
|
9
|
+
--pf-v5-c-button--PaddingTop: var(--pf-v5-global--spacer--xs);
|
10
|
+
--pf-v5-c-button--PaddingRight: var(--pf-v5-global--spacer--xs);
|
11
|
+
--pf-v5-c-button--PaddingBottom: var(--pf-v5-global--spacer--xs);
|
12
|
+
--pf-v5-c-button--PaddingLeft: var(--pf-v5-global--spacer--xs);
|
13
13
|
}
|
14
14
|
|
@@ -33,7 +33,13 @@ const addKatelloLinkToTree = (tree) => {
|
|
33
33
|
<BrowserRouter>
|
34
34
|
<Link to={url} target="_blank">
|
35
35
|
<Tooltip content={__('Go to Product page')}>
|
36
|
-
<Button
|
36
|
+
<Button
|
37
|
+
ouiaId={tree.product_id
|
38
|
+
.toString()
|
39
|
+
.concat('scc-manager-product-page-link')}
|
40
|
+
variant="plain"
|
41
|
+
id="tt-ref"
|
42
|
+
>
|
37
43
|
<Icon name="external-link" type="fa" />
|
38
44
|
</Button>
|
39
45
|
</Tooltip>
|
@@ -45,8 +51,14 @@ const addKatelloLinkToTree = (tree) => {
|
|
45
51
|
|
46
52
|
const addEditIcon = (tree, editProductTree) => {
|
47
53
|
tree.customBadgeContent.push(
|
48
|
-
<Tooltip
|
54
|
+
<Tooltip
|
55
|
+
key={'scc-manager-add-sub-tooltip'.concat(tree.id.toString())}
|
56
|
+
content={__('Add more sub products to Product tree')}
|
57
|
+
>
|
49
58
|
<Button
|
59
|
+
ouiaId={tree.id
|
60
|
+
.toString()
|
61
|
+
.concat('scc-manager-add-sub-products-button')}
|
50
62
|
variant="plain"
|
51
63
|
id={tree.id.toString()}
|
52
64
|
onClick={(evt) => editProductTree(evt, tree.id)}
|
@@ -61,7 +73,10 @@ const addEditIcon = (tree, editProductTree) => {
|
|
61
73
|
|
62
74
|
const addReposToTree = (tree) => {
|
63
75
|
tree.customBadgeContent.push(
|
64
|
-
<Tooltip
|
76
|
+
<Tooltip
|
77
|
+
key="scc-manager-repoview-show-repos-tooltip"
|
78
|
+
content={__('Show currently added repositories')}
|
79
|
+
>
|
65
80
|
<SCCRepoView
|
66
81
|
sccRepos={tree.scc_repositories}
|
67
82
|
sccProductId={tree.product_id}
|
@@ -74,7 +89,10 @@ const addReposToTree = (tree) => {
|
|
74
89
|
const addValidationStatusToTree = (tree) => {
|
75
90
|
tree.customBadgeContent.push(
|
76
91
|
<Tooltip content={__('Please check your SUSE subscription')}>
|
77
|
-
<Button
|
92
|
+
<Button
|
93
|
+
ouiaId="scc-manager-check-suse-subscription-button"
|
94
|
+
variant="plain"
|
95
|
+
>
|
78
96
|
<Icon name="warning-triangle-o" type="pf" size="2x" />
|
79
97
|
</Button>
|
80
98
|
</Tooltip>
|
@@ -157,7 +175,7 @@ const SCCProductView = ({
|
|
157
175
|
};
|
158
176
|
|
159
177
|
return (
|
160
|
-
<Card>
|
178
|
+
<Card ouiaId="scc-manager-select-suse-products-card">
|
161
179
|
<CardTitle>{__('Selected SUSE Products')}</CardTitle>
|
162
180
|
{sccProducts.length > 0 && (
|
163
181
|
<CardBody>
|
@@ -173,7 +191,7 @@ const SCCProductView = ({
|
|
173
191
|
<TreeView
|
174
192
|
data={showAll ? allProducts : subscribedProducts}
|
175
193
|
allExpanded={expandAll}
|
176
|
-
|
194
|
+
hasCheckboxes
|
177
195
|
hasBadges
|
178
196
|
hasGuides
|
179
197
|
/>
|
@@ -190,7 +208,7 @@ const SCCProductView = ({
|
|
190
208
|
<Flex>
|
191
209
|
{sccProducts.length > 0 && (
|
192
210
|
<FlexItem>
|
193
|
-
<Button variant="link">
|
211
|
+
<Button ouiaId="scc-manager-show-all-tasks-button" variant="link">
|
194
212
|
<BrowserRouter>
|
195
213
|
<Link
|
196
214
|
to="/foreman_tasks/tasks/?search=Subscribe+SCC+Product"
|
@@ -204,7 +222,7 @@ const SCCProductView = ({
|
|
204
222
|
)}
|
205
223
|
{subscriptionTaskId !== '' && (
|
206
224
|
<FlexItem>
|
207
|
-
<Button variant="link">
|
225
|
+
<Button ouiaId="scc-manager-show-last-task-button" variant="link">
|
208
226
|
<BrowserRouter>
|
209
227
|
<Link
|
210
228
|
to={sprintf('/foreman_tasks/tasks/%s', subscriptionTaskId)}
|
@@ -34,8 +34,8 @@ describe('SCCGenericExpander', () => {
|
|
34
34
|
// Select
|
35
35
|
const select = wrapper.find('Select');
|
36
36
|
expect(select.exists()).toBe(true);
|
37
|
-
expect(select.props()).toHaveProperty('
|
38
|
-
expect(select.prop('
|
37
|
+
expect(select.props()).toHaveProperty('selected');
|
38
|
+
expect(select.prop('selected')).toContain('open/close');
|
39
39
|
|
40
40
|
// SelectOptions
|
41
41
|
const selectOptions = wrapper.find('SelectOption');
|
@@ -1,6 +1,13 @@
|
|
1
1
|
import React, { useState } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
Flex,
|
5
|
+
FlexItem,
|
6
|
+
Select,
|
7
|
+
SelectList,
|
8
|
+
MenuToggle,
|
9
|
+
SelectOption,
|
10
|
+
} from '@patternfly/react-core';
|
4
11
|
|
5
12
|
const SCCGenericExpander = ({
|
6
13
|
setInParent,
|
@@ -11,12 +18,14 @@ const SCCGenericExpander = ({
|
|
11
18
|
const [label, setLabel] = useState(initLabel);
|
12
19
|
const [isOpen, setIsOpen] = useState(false);
|
13
20
|
|
14
|
-
const options =
|
15
|
-
<
|
16
|
-
|
17
|
-
|
21
|
+
const options = (
|
22
|
+
<SelectList>
|
23
|
+
<SelectOption value={selectOptionOpen}>{selectOptionOpen}</SelectOption>
|
24
|
+
<SelectOption value={selectOptionClose}>{selectOptionClose}</SelectOption>
|
25
|
+
</SelectList>
|
26
|
+
);
|
18
27
|
|
19
|
-
const onSelect = (
|
28
|
+
const onSelect = (_evt, selection) => {
|
20
29
|
if (selection === selectOptionOpen) {
|
21
30
|
setInParent(true);
|
22
31
|
} else {
|
@@ -26,18 +35,27 @@ const SCCGenericExpander = ({
|
|
26
35
|
setIsOpen(false);
|
27
36
|
};
|
28
37
|
|
29
|
-
const
|
30
|
-
setIsOpen(
|
38
|
+
const onToggleClick = () => {
|
39
|
+
setIsOpen(!isOpen);
|
31
40
|
};
|
32
41
|
|
42
|
+
const toggle = (toggleRef) => (
|
43
|
+
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
|
44
|
+
{label}
|
45
|
+
</MenuToggle>
|
46
|
+
);
|
47
|
+
|
33
48
|
return (
|
34
49
|
<Flex>
|
35
50
|
<FlexItem>
|
36
51
|
<Select
|
37
|
-
|
52
|
+
ouiaId={initLabel.concat('scc-manager-generic-expander-select')}
|
53
|
+
toggle={toggle}
|
38
54
|
onSelect={onSelect}
|
39
|
-
|
55
|
+
selected={label}
|
40
56
|
isOpen={isOpen}
|
57
|
+
onOpenChange={(nextOpen) => setIsOpen(isOpen)}
|
58
|
+
shouldFocusToggleOnSelect
|
41
59
|
>
|
42
60
|
{options}
|
43
61
|
</Select>
|
@@ -1,8 +1,8 @@
|
|
1
1
|
@import '~@theforeman/vendor/scss/variables';
|
2
2
|
|
3
|
-
.pf-c-tile {
|
4
|
-
--pf-c-tile--PaddingTop: var(--pf-global--spacer--xs);
|
5
|
-
--pf-c-tile--PaddingRight: var(--pf-global--spacer--xs);
|
6
|
-
--pf-c-tile--PaddingBottom: var(--pf-global--spacer--xs);
|
7
|
-
--pf-c-tile--PaddingLeft: var(--pf-global--spacer--xs);
|
3
|
+
.pf-v5-c-tile {
|
4
|
+
--pf-v5-c-tile--PaddingTop: var(--pf-v5-global--spacer--xs);
|
5
|
+
--pf-v5-c-tile--PaddingRight: var(--pf-v5-global--spacer--xs);
|
6
|
+
--pf-v5-c-tile--PaddingBottom: var(--pf-v5-global--spacer--xs);
|
7
|
+
--pf-v5-c-tile--PaddingLeft: var(--pf-v5-global--spacer--xs);
|
8
8
|
}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_scc_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ATIX AG
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-08-13 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rdoc
|
@@ -254,7 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
254
254
|
- !ruby/object:Gem::Version
|
255
255
|
version: '0'
|
256
256
|
requirements: []
|
257
|
-
rubygems_version: 3.6.
|
257
|
+
rubygems_version: 3.6.9
|
258
258
|
specification_version: 4
|
259
259
|
summary: Suse Customer Center plugin for Foreman
|
260
260
|
test_files:
|