foreman_scc_manager 1.8.19 → 2.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/README.md +14 -10
- data/app/controllers/api/v2/scc_accounts_controller.rb +48 -5
- data/app/controllers/api/v2/scc_products_controller.rb +1 -1
- data/app/controllers/scc_accounts_controller.rb +47 -0
- data/app/lib/actions/scc_manager/subscribe_product.rb +61 -19
- data/app/models/scc_account.rb +4 -3
- data/app/models/scc_katello_repository.rb +4 -0
- data/app/models/scc_product.rb +7 -1
- data/app/models/scc_repository.rb +12 -4
- data/app/views/scc_accounts/show.html.erb +7 -51
- data/config/routes.rb +1 -0
- data/db/migrate/20220425132605_add_scc_katello_repository_relation.rb +10 -0
- data/db/migrate/20220429100843_remove_root_repository_id_from_scc_repository.rb +6 -0
- data/db/migrate/20220429102717_populate_scc_katello_repositories.rb +21 -0
- data/db/migrate/20220513132652_populate_upstream_authentication_token.rb +23 -0
- data/db/migrate/20220531120722_add_product_category_to_scc_products.rb +5 -0
- data/lib/foreman_scc_manager/engine.rb +1 -1
- data/lib/foreman_scc_manager/version.rb +1 -1
- data/lib/tasks/republish_repositories.rake +13 -0
- data/lib/tasks/setup_authentication_token.rake +27 -0
- data/package.json +54 -0
- data/test/controllers/scc_accounts_controller_test.rb +6 -0
- data/test/fixtures/models/katello_root_repositories.yml +44 -0
- data/test/fixtures/models/scc_repositories.yml +34 -0
- data/test/support/fixtures_support.rb +3 -1
- data/webpack/components/SCCProductPage/EmptySccProducts.js +46 -0
- data/webpack/components/SCCProductPage/SCCProductPage.js +96 -0
- data/webpack/components/SCCProductPage/SCCProductPageActions.js +27 -0
- data/webpack/components/SCCProductPage/SCCProductPageConstants.js +5 -0
- data/webpack/components/SCCProductPage/SCCProductPageReducer.js +34 -0
- data/webpack/components/SCCProductPage/SCCProductPageSelectors.js +7 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCGenericPicker/index.js +80 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/index.js +174 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/styles.scss +3 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/index.js +303 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/index.js +235 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/styles.scss +10 -0
- data/webpack/components/SCCProductPage/components/SCCProductPickerModal/index.js +81 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/index.js +113 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/styles.scss +14 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/index.js +236 -0
- data/webpack/components/SCCProductPage/components/common/SCCGenericExpander/index.js +58 -0
- data/webpack/components/SCCProductPage/components/common/SCCProductTreeExpander/index.js +21 -0
- data/webpack/components/SCCProductPage/components/common/SCCSubscribedProductsExpander/index.js +21 -0
- data/webpack/components/SCCProductPage/index.js +18 -0
- data/webpack/components/SCCProductPage/sccProductPage.scss +8 -0
- data/webpack/index.js +11 -0
- data/webpack/reducer.js +7 -0
- metadata +48 -14
data/package.json
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
{
|
2
|
+
"name": "foreman_scc_manager",
|
3
|
+
"version": "1.8.16",
|
4
|
+
"description": "Foreman plugin to sync SUSE Customer Center products and repositories into Katello ",
|
5
|
+
"main": "index.js",
|
6
|
+
"directories": {
|
7
|
+
"lib": "lib",
|
8
|
+
"test": "test"
|
9
|
+
},
|
10
|
+
"scripts": {
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
12
|
+
"create-react-component": "yo react-domain"
|
13
|
+
},
|
14
|
+
"repository": {
|
15
|
+
"type": "git",
|
16
|
+
"url": "git+ssh://git@github.com/ATIX-AG/foreman_scc_manager.git"
|
17
|
+
},
|
18
|
+
"peerDependencies": {
|
19
|
+
"@theforeman/vendor": "^4.14.0"
|
20
|
+
},
|
21
|
+
"devDependencies": {
|
22
|
+
"@babel/core": "^7.7.0",
|
23
|
+
"babel-eslint": "^10.0.0",
|
24
|
+
"babel-loader": "^8.0.0",
|
25
|
+
"@theforeman/builder": "^4.14.0",
|
26
|
+
"@theforeman/eslint-plugin-foreman": "^8.16.0",
|
27
|
+
"@theforeman/find-foreman": "^4.14.0",
|
28
|
+
"@theforeman/stories": "^4.14.0",
|
29
|
+
"@theforeman/test": "^4.14.0",
|
30
|
+
"@theforeman/vendor-dev": "^4.14.0",
|
31
|
+
"eslint": "^6.7.2",
|
32
|
+
"eslint-plugin-spellcheck": "0.0.17",
|
33
|
+
"eslint-plugin-react": "^7.27.1",
|
34
|
+
"eslint-plugin-react-hooks": "^4.3.0",
|
35
|
+
"prettier": "^2.5.1",
|
36
|
+
"react-redux-test-utils": "^0.2.0"
|
37
|
+
},
|
38
|
+
"keywords": [
|
39
|
+
"SUSE",
|
40
|
+
"Katello",
|
41
|
+
"products",
|
42
|
+
"repositories"
|
43
|
+
],
|
44
|
+
"author": "ATIX AG",
|
45
|
+
"license": "GPL-3.0",
|
46
|
+
"bugs": {
|
47
|
+
"url": "https://github.com/ATIX-AG/foreman_scc_manager/issues"
|
48
|
+
},
|
49
|
+
"homepage": "https://github.com/ATIX-AG/foreman_scc_manager#readme",
|
50
|
+
"dependencies": {
|
51
|
+
"react-native-elements": "^3.4.2",
|
52
|
+
"react-native-vector-icons": "^9.0.0"
|
53
|
+
}
|
54
|
+
}
|
@@ -2,6 +2,12 @@ require 'test_plugin_helper'
|
|
2
2
|
|
3
3
|
class SccAccountsControllerTest < ActionController::TestCase
|
4
4
|
def setup
|
5
|
+
# rubocop: disable Lint/SuppressedException
|
6
|
+
begin
|
7
|
+
::Katello::ContentCredential
|
8
|
+
rescue NameError
|
9
|
+
end
|
10
|
+
# rubocop: enable Lint/SuppressedException
|
5
11
|
@scc_account = scc_accounts(:one)
|
6
12
|
end
|
7
13
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
sles12_sp4_updates:
|
2
|
+
name: SLES12-SP4-Updates for sle-12-x86_64
|
3
|
+
content_type: yum
|
4
|
+
label: 1759_SLES12-SP4-Updates_for_sle-12-x86_64_description
|
5
|
+
product_id: <%= ActiveRecord::FixtureSet.identify(:suse) %>
|
6
|
+
url: www.not-valid.com
|
7
|
+
download_policy: immediate
|
8
|
+
<% if ActiveRecord::Base.connection.column_exists? :katello_root_repositories, :mirroring_policy %>
|
9
|
+
mirroring_policy: "mirror_content_only"
|
10
|
+
<% else %>
|
11
|
+
mirror_on_sync: "true"
|
12
|
+
<% end %>
|
13
|
+
created_at: <%= Time.now %>
|
14
|
+
updated_at: <%= Time.now %>
|
15
|
+
|
16
|
+
sles12_sp4_installer_updates:
|
17
|
+
name: SLES12-SP4-Installer-Updates for sle-12-x86_64
|
18
|
+
content_type: yum
|
19
|
+
label: 1759_product_name_SLES12-SP4-Installer-Updates_for_sle-12-x86_64_description
|
20
|
+
product_id: <%= ActiveRecord::FixtureSet.identify(:suse) %>
|
21
|
+
url: www.not-valid.com
|
22
|
+
download_policy: on_demand
|
23
|
+
<% if ActiveRecord::Base.connection.column_exists? :katello_root_repositories, :mirroring_policy %>
|
24
|
+
mirroring_policy: "mirror_content_only"
|
25
|
+
<% else %>
|
26
|
+
mirror_on_sync: "true"
|
27
|
+
<% end %>
|
28
|
+
created_at: <%= Time.now %>
|
29
|
+
updated_at: <%= Time.now %>
|
30
|
+
|
31
|
+
sles12_sp4_installer_updates_2:
|
32
|
+
name: SLES12-SP4-Installer-Updates for sle-12-x86_64
|
33
|
+
content_type: yum
|
34
|
+
label: 1760_product_name_SLES12-SP4-Installer-Updates_for_sle-12-x86_64_description
|
35
|
+
product_id: <%= ActiveRecord::FixtureSet.identify(:suse) %>
|
36
|
+
url: www.not-valid.com
|
37
|
+
download_policy: on_demand
|
38
|
+
<% if ActiveRecord::Base.connection.column_exists? :katello_root_repositories, :mirroring_policy %>
|
39
|
+
mirroring_policy: "mirror_content_only"
|
40
|
+
<% else %>
|
41
|
+
mirror_on_sync: "true"
|
42
|
+
<% end %>
|
43
|
+
created_at: <%= Time.now %>
|
44
|
+
updated_at: <%= Time.now %>
|
@@ -25,5 +25,39 @@ repo_9:
|
|
25
25
|
autorefresh: true
|
26
26
|
installer_updates: false
|
27
27
|
|
28
|
+
sles12_updates:
|
29
|
+
id: 10
|
30
|
+
scc_account_id: 1
|
31
|
+
scc_id: 1
|
32
|
+
name: SLES12-SP4-Updates for sle-12-x86_64
|
33
|
+
distro_target: sles_12
|
34
|
+
description: SLES12-SP4-Updates for sle-12-x86_64
|
35
|
+
url: www.not-valid.com
|
36
|
+
token: token_10
|
37
|
+
autorefresh: true
|
38
|
+
installer_updates: false
|
28
39
|
|
29
40
|
|
41
|
+
sles12_installer_updates:
|
42
|
+
id: 11
|
43
|
+
scc_account_id: 1
|
44
|
+
scc_id: 2
|
45
|
+
name: SLES12-SP4-Installer-Updates for sle-12-x86_64
|
46
|
+
distro_target: sles_12
|
47
|
+
description: SLES12-SP4-Installer-Updates for sle-12-x86_64
|
48
|
+
url: www.not-valid.com
|
49
|
+
token: token_11
|
50
|
+
autorefresh: true
|
51
|
+
installer_updates: false
|
52
|
+
|
53
|
+
sles12_installer_updates_2:
|
54
|
+
id: 12
|
55
|
+
scc_account_id: 1
|
56
|
+
scc_id: 3
|
57
|
+
name: SLES12-SP4-Installer-Updates for sle-12-x86_64_2
|
58
|
+
distro_target: sles_9
|
59
|
+
description: SLES12-SP4-Installer-Updates for sle-12-x86_64_2
|
60
|
+
url: www.not-valid.com
|
61
|
+
token: token_12
|
62
|
+
autorefresh: true
|
63
|
+
installer_updates: false
|
@@ -3,7 +3,9 @@ module ForemanSccManager
|
|
3
3
|
FIXTURE_CLASSES = {
|
4
4
|
scc_accounts: ::SccAccount,
|
5
5
|
scc_products: ::SccProduct,
|
6
|
-
scc_repositories: ::SccRepository
|
6
|
+
scc_repositories: ::SccRepository,
|
7
|
+
katello_root_repositories: ::Katello::RootRepository,
|
8
|
+
scc_katello_repositories: SccKatelloRepository
|
7
9
|
}.freeze
|
8
10
|
|
9
11
|
def self.set_fixture_classes(test_class)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useDispatch } from 'react-redux';
|
3
|
+
import PropTypes from 'prop-types';
|
4
|
+
import { Button } from '@patternfly/react-core';
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
import EmptyState from 'foremanReact/components/common/EmptyState';
|
7
|
+
import { syncSccAccountAction } from './SCCProductPageActions';
|
8
|
+
|
9
|
+
export const EmptySccProducts = ({ canCreate, sccAccountId }) => {
|
10
|
+
const dispatch = useDispatch();
|
11
|
+
const onSyncStart = (evt) => {
|
12
|
+
dispatch(syncSccAccountAction(sccAccountId));
|
13
|
+
};
|
14
|
+
|
15
|
+
const content = __(
|
16
|
+
`Please synchronize your SUSE account before you can subscribe to SUSE products.`
|
17
|
+
);
|
18
|
+
return (
|
19
|
+
<>
|
20
|
+
<EmptyState
|
21
|
+
icon="th"
|
22
|
+
iconType="fa"
|
23
|
+
header={__('SUSE Customer Center')}
|
24
|
+
description={<div dangerouslySetInnerHTML={{ __html: content }} />}
|
25
|
+
documentation={{
|
26
|
+
url: 'https://docs.orcharhino.com/or/docs/sources/usage_guides/managing_sles_systems_guide.html#mssg_adding_scc_accounts',
|
27
|
+
}}
|
28
|
+
/>
|
29
|
+
<Button onClick={onSyncStart} className="btn btn-primary">
|
30
|
+
{__('Synchronize SUSE Account')}
|
31
|
+
</Button>
|
32
|
+
</>
|
33
|
+
);
|
34
|
+
};
|
35
|
+
|
36
|
+
EmptySccProducts.propTypes = {
|
37
|
+
canCreate: PropTypes.bool,
|
38
|
+
sccAccountId: PropTypes.number,
|
39
|
+
};
|
40
|
+
|
41
|
+
EmptySccProducts.defaultProps = {
|
42
|
+
canCreate: false,
|
43
|
+
sccAccountId: undefined,
|
44
|
+
};
|
45
|
+
|
46
|
+
export default EmptySccProducts;
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import PropTypes from 'prop-types';
|
2
|
+
import React, { useState } from 'react';
|
3
|
+
import { Stack, StackItem } from '@patternfly/react-core';
|
4
|
+
import { useDispatch } from 'react-redux';
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
|
7
|
+
import SCCProductView from './components/SCCProductView';
|
8
|
+
import EmptySccProducts from './EmptySccProducts';
|
9
|
+
import SCCProductPicker from './components/SCCProductPicker';
|
10
|
+
import SCCProductPickerModal from './components/SCCProductPickerModal';
|
11
|
+
import { SCCPRODUCTPAGE_SUMMARY_MODAL_ID } from './SCCProductPageConstants';
|
12
|
+
import './sccProductPage.scss';
|
13
|
+
|
14
|
+
const SCCProductPage = ({
|
15
|
+
canCreate,
|
16
|
+
sccAccountId,
|
17
|
+
sccProductsInit,
|
18
|
+
...props
|
19
|
+
}) => {
|
20
|
+
const dispatch = useDispatch();
|
21
|
+
const [productToEdit, setProductToEdit] = useState(0);
|
22
|
+
const [reposToSubscribe, setReposToSubscribe] = useState([]);
|
23
|
+
const [subscriptionTaskId, setSubscriptionTaskId] = useState();
|
24
|
+
|
25
|
+
const editProductTree = (productId) => {
|
26
|
+
setProductToEdit(productId);
|
27
|
+
};
|
28
|
+
|
29
|
+
const { setModalOpen, setModalClosed } = useForemanModal({
|
30
|
+
id: SCCPRODUCTPAGE_SUMMARY_MODAL_ID,
|
31
|
+
});
|
32
|
+
|
33
|
+
const handleSubscribeCallback = (
|
34
|
+
subscriptionTaskIdFromAction,
|
35
|
+
reposToSubscribeFromAction
|
36
|
+
) => {
|
37
|
+
setSubscriptionTaskId(subscriptionTaskIdFromAction);
|
38
|
+
const newReposToSubscribe = [];
|
39
|
+
Object.keys(reposToSubscribeFromAction).forEach((k) => {
|
40
|
+
const repo = {
|
41
|
+
productName: reposToSubscribeFromAction[k].productName,
|
42
|
+
repoNames: reposToSubscribeFromAction[k].repoNames,
|
43
|
+
};
|
44
|
+
newReposToSubscribe.push(repo);
|
45
|
+
});
|
46
|
+
setReposToSubscribe(newReposToSubscribe);
|
47
|
+
dispatch(setModalOpen({ id: SCCPRODUCTPAGE_SUMMARY_MODAL_ID }));
|
48
|
+
};
|
49
|
+
|
50
|
+
return sccProductsInit.length > 0 ? (
|
51
|
+
<Stack>
|
52
|
+
<StackItem>
|
53
|
+
<SCCProductPickerModal
|
54
|
+
id={SCCPRODUCTPAGE_SUMMARY_MODAL_ID}
|
55
|
+
title={__('The subscription task has been started successfully')}
|
56
|
+
taskId={subscriptionTaskId}
|
57
|
+
reposToSubscribe={reposToSubscribe}
|
58
|
+
/>
|
59
|
+
</StackItem>
|
60
|
+
<StackItem>
|
61
|
+
<SCCProductView
|
62
|
+
sccProducts={sccProductsInit.filter(
|
63
|
+
(prod) => prod.product_id !== null
|
64
|
+
)}
|
65
|
+
subscriptionTaskId={subscriptionTaskId}
|
66
|
+
editProductTreeGlobal={editProductTree}
|
67
|
+
/>
|
68
|
+
</StackItem>
|
69
|
+
<br />
|
70
|
+
<StackItem />
|
71
|
+
<StackItem>
|
72
|
+
<SCCProductPicker
|
73
|
+
sccProducts={sccProductsInit}
|
74
|
+
sccAccountId={sccAccountId}
|
75
|
+
editProductId={productToEdit}
|
76
|
+
handleSubscribeCallback={handleSubscribeCallback}
|
77
|
+
/>
|
78
|
+
</StackItem>
|
79
|
+
</Stack>
|
80
|
+
) : (
|
81
|
+
<EmptySccProducts sccAccountId={sccAccountId} canCreate={canCreate} />
|
82
|
+
);
|
83
|
+
};
|
84
|
+
|
85
|
+
SCCProductPage.propTypes = {
|
86
|
+
canCreate: PropTypes.bool,
|
87
|
+
sccAccountId: PropTypes.number.isRequired,
|
88
|
+
sccProductsInit: PropTypes.array,
|
89
|
+
};
|
90
|
+
|
91
|
+
SCCProductPage.defaultProps = {
|
92
|
+
canCreate: false,
|
93
|
+
sccProductsInit: [],
|
94
|
+
};
|
95
|
+
|
96
|
+
export default SCCProductPage;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { API_OPERATIONS, put } from 'foremanReact/redux/API';
|
2
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
3
|
+
|
4
|
+
export const subscribeProductsWithReposAction = (
|
5
|
+
sccAccountId,
|
6
|
+
sccProductData,
|
7
|
+
handleSubscription,
|
8
|
+
sccSubscriptionData
|
9
|
+
) =>
|
10
|
+
put({
|
11
|
+
type: API_OPERATIONS.PUT,
|
12
|
+
key: `subscribe_key_${sccAccountId}_${sccProductData[0].scc_product_id}_${sccProductData[0].repository_list}`,
|
13
|
+
url: `/api/scc_accounts/${sccAccountId}/bulk_subscribe_with_repos`,
|
14
|
+
params: { scc_product_data: sccProductData },
|
15
|
+
errorToast: (error) => __('Starting the subscription task failed.'),
|
16
|
+
handleSuccess: (response) =>
|
17
|
+
handleSubscription(response.data.id, sccSubscriptionData),
|
18
|
+
});
|
19
|
+
|
20
|
+
export const syncSccAccountAction = (sccAccountId) =>
|
21
|
+
put({
|
22
|
+
type: API_OPERATIONS.PUT,
|
23
|
+
key: `syncSccAccountKey_${sccAccountId}`,
|
24
|
+
url: `/api/scc_accounts/${sccAccountId}/sync`,
|
25
|
+
successToast: () => __('Sync task started.'),
|
26
|
+
errorToast: (error) => __('Failed to add task to queue.'),
|
27
|
+
});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
import { actionTypeGenerator } from 'foremanReact/redux/API';
|
3
|
+
|
4
|
+
export const initialState = Immutable({
|
5
|
+
sccProducts: [],
|
6
|
+
sccAccountId: undefined,
|
7
|
+
});
|
8
|
+
|
9
|
+
export default (state = initialState, action) => {
|
10
|
+
const { payload } = action;
|
11
|
+
|
12
|
+
const listTypes = actionTypeGenerator('SCC_PRODUCT_LIST');
|
13
|
+
|
14
|
+
switch (action.type) {
|
15
|
+
case 'FETCH_PRODUCT_SUCCESS':
|
16
|
+
return state.merge({
|
17
|
+
sccProducts: payload,
|
18
|
+
});
|
19
|
+
case listTypes.REQUEST:
|
20
|
+
return state.merge({
|
21
|
+
sccProducts: [],
|
22
|
+
});
|
23
|
+
case listTypes.SUCCESS:
|
24
|
+
return state.merge({
|
25
|
+
sccProducts: payload.data,
|
26
|
+
});
|
27
|
+
case listTypes.FAILURE:
|
28
|
+
return state.merge({
|
29
|
+
sccProducts: [payload.error],
|
30
|
+
});
|
31
|
+
default:
|
32
|
+
return state;
|
33
|
+
}
|
34
|
+
};
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { ContextSelector, ContextSelectorItem } from '@patternfly/react-core';
|
4
|
+
|
5
|
+
const GenericSelector = ({
|
6
|
+
selectionItems,
|
7
|
+
setGlobalSelected,
|
8
|
+
screenReaderLabel,
|
9
|
+
initialLabel,
|
10
|
+
}) => {
|
11
|
+
const [isOpen, setIsOpen] = useState(false);
|
12
|
+
const [selected, setSelected] = useState(initialLabel);
|
13
|
+
const [searchValue, setSearchValue] = useState('');
|
14
|
+
const [filteredItems, setFilteredItems] = useState(selectionItems);
|
15
|
+
|
16
|
+
useEffect(() => {
|
17
|
+
setFilteredItems(selectionItems);
|
18
|
+
setSelected(initialLabel);
|
19
|
+
}, [selectionItems, initialLabel]);
|
20
|
+
|
21
|
+
const onToggle = (selectorOpen) => {
|
22
|
+
setIsOpen(selectorOpen);
|
23
|
+
};
|
24
|
+
|
25
|
+
const onSelect = (event, value) => {
|
26
|
+
setSelected(value);
|
27
|
+
setIsOpen(!isOpen);
|
28
|
+
setGlobalSelected(value);
|
29
|
+
};
|
30
|
+
|
31
|
+
const onSearchInputChange = (value) => {
|
32
|
+
setSearchValue(value);
|
33
|
+
};
|
34
|
+
|
35
|
+
const onSearchButtonClick = (event) => {
|
36
|
+
const filtered =
|
37
|
+
searchValue === ''
|
38
|
+
? selectionItems
|
39
|
+
: selectionItems.filter((item) => {
|
40
|
+
const str = item.text ? item.text : item;
|
41
|
+
return str.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1;
|
42
|
+
});
|
43
|
+
|
44
|
+
setFilteredItems(filtered || []);
|
45
|
+
};
|
46
|
+
|
47
|
+
return (
|
48
|
+
<ContextSelector
|
49
|
+
toggleText={selected}
|
50
|
+
onSearchInputChange={onSearchInputChange}
|
51
|
+
isOpen={isOpen}
|
52
|
+
searchInputValue={searchValue}
|
53
|
+
onToggle={onToggle}
|
54
|
+
onSelect={onSelect}
|
55
|
+
onSearchButtonClick={onSearchButtonClick}
|
56
|
+
screenReaderLabel={screenReaderLabel}
|
57
|
+
>
|
58
|
+
{filteredItems.map((item, index) => (
|
59
|
+
<ContextSelectorItem key={index}>
|
60
|
+
{item || 'no arch'}
|
61
|
+
</ContextSelectorItem>
|
62
|
+
))}
|
63
|
+
</ContextSelector>
|
64
|
+
);
|
65
|
+
};
|
66
|
+
|
67
|
+
GenericSelector.propTypes = {
|
68
|
+
selectionItems: PropTypes.array,
|
69
|
+
setGlobalSelected: PropTypes.func.isRequired,
|
70
|
+
screenReaderLabel: PropTypes.string,
|
71
|
+
initialLabel: PropTypes.string,
|
72
|
+
};
|
73
|
+
|
74
|
+
GenericSelector.defaultProps = {
|
75
|
+
selectionItems: [],
|
76
|
+
screenReaderLabel: '',
|
77
|
+
initialLabel: '',
|
78
|
+
};
|
79
|
+
|
80
|
+
export default GenericSelector;
|
@@ -0,0 +1,174 @@
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { sprintf, translate as __ } from 'foremanReact/common/I18n';
|
4
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
5
|
+
|
6
|
+
import './styles.scss';
|
7
|
+
|
8
|
+
const createRepoSelectOption = (repo, disableRepos) => (
|
9
|
+
<SelectOption
|
10
|
+
key={repo.id}
|
11
|
+
isDisabled={repo.katello_root_repository_id !== null || disableRepos}
|
12
|
+
value={repo.name}
|
13
|
+
/>
|
14
|
+
);
|
15
|
+
|
16
|
+
const setRepoSelection = (
|
17
|
+
sccRepos,
|
18
|
+
disableRepos,
|
19
|
+
activateDebugFilter,
|
20
|
+
productAlreadySynced
|
21
|
+
) => {
|
22
|
+
let res = [];
|
23
|
+
// this is necessary because the logic of this option was inverted
|
24
|
+
// Instead of filtering the debug repositories with the corresponding option,
|
25
|
+
// this option now includes the repositories, instead - means, it does exactly the opposite.
|
26
|
+
activateDebugFilter = !activateDebugFilter;
|
27
|
+
if (!disableRepos && !productAlreadySynced) {
|
28
|
+
if (activateDebugFilter) {
|
29
|
+
res = sccRepos.filter(
|
30
|
+
(repo) =>
|
31
|
+
(!repo.name.includes('Debug') &&
|
32
|
+
!repo.name.includes('Source-Pool') &&
|
33
|
+
repo.katello_root_repository_id === null) ||
|
34
|
+
repo.katello_root_repository_id !== null
|
35
|
+
);
|
36
|
+
} else {
|
37
|
+
res = sccRepos;
|
38
|
+
}
|
39
|
+
} else {
|
40
|
+
res = sccRepos.filter((repo) => repo.katello_root_repository_id !== null);
|
41
|
+
}
|
42
|
+
return res.map((repo) => repo.name);
|
43
|
+
};
|
44
|
+
|
45
|
+
// disableRepos makes sure that repos can only be selected if the corresponding product
|
46
|
+
// is also selected
|
47
|
+
const SCCRepoPicker = ({
|
48
|
+
sccRepos,
|
49
|
+
disableRepos,
|
50
|
+
activateDebugFilter,
|
51
|
+
productAlreadySynced,
|
52
|
+
sccProductId,
|
53
|
+
sccProductName,
|
54
|
+
setSelectedReposFromChild,
|
55
|
+
}) => {
|
56
|
+
const [isOpen, setIsOpen] = useState(false);
|
57
|
+
// set initial selected values to the already checked repos
|
58
|
+
const [selected, setSelected] = useState(
|
59
|
+
setRepoSelection(
|
60
|
+
sccRepos,
|
61
|
+
disableRepos,
|
62
|
+
activateDebugFilter,
|
63
|
+
productAlreadySynced
|
64
|
+
)
|
65
|
+
);
|
66
|
+
const onToggle = (toggle) => {
|
67
|
+
setIsOpen(toggle);
|
68
|
+
};
|
69
|
+
|
70
|
+
useEffect(() => {
|
71
|
+
const selectedRepos = setRepoSelection(
|
72
|
+
sccRepos,
|
73
|
+
disableRepos,
|
74
|
+
activateDebugFilter,
|
75
|
+
productAlreadySynced
|
76
|
+
);
|
77
|
+
setSelected(selectedRepos);
|
78
|
+
setSelectedReposFromChild(
|
79
|
+
sccProductId,
|
80
|
+
sccProductName,
|
81
|
+
sccRepos
|
82
|
+
// make sure that we do not request already subscribed repositories
|
83
|
+
.filter(
|
84
|
+
(repo) =>
|
85
|
+
selectedRepos.includes(repo.name) &&
|
86
|
+
repo.katello_root_repository_id === null
|
87
|
+
)
|
88
|
+
.map((repo) => repo.id),
|
89
|
+
sccRepos
|
90
|
+
// make sure that we do not request already subscribed repositories
|
91
|
+
.filter(
|
92
|
+
(repo) =>
|
93
|
+
selectedRepos.includes(repo.name) &&
|
94
|
+
repo.katello_root_repository_id === null
|
95
|
+
)
|
96
|
+
.map((repo) => repo.name)
|
97
|
+
);
|
98
|
+
}, [
|
99
|
+
sccRepos,
|
100
|
+
disableRepos,
|
101
|
+
activateDebugFilter,
|
102
|
+
productAlreadySynced,
|
103
|
+
sccProductId,
|
104
|
+
setSelectedReposFromChild,
|
105
|
+
]);
|
106
|
+
|
107
|
+
const onSelect = (event, selection) => {
|
108
|
+
let selectedRepos = [];
|
109
|
+
if (event.target.checked) {
|
110
|
+
selectedRepos = [...new Set(selected.concat([selection]))];
|
111
|
+
} else {
|
112
|
+
selectedRepos = selected.filter((item) => item !== selection);
|
113
|
+
}
|
114
|
+
setSelected(selectedRepos);
|
115
|
+
setSelectedReposFromChild(
|
116
|
+
sccProductId,
|
117
|
+
sccProductName,
|
118
|
+
sccRepos
|
119
|
+
// make sure that we do not request already subscribed repositories
|
120
|
+
.filter(
|
121
|
+
(repo) =>
|
122
|
+
selectedRepos.includes(repo.name) &&
|
123
|
+
repo.katello_root_repository_id === null
|
124
|
+
)
|
125
|
+
.map((repo) => repo.id),
|
126
|
+
sccRepos
|
127
|
+
// make sure that we do not request already subscribed repositories
|
128
|
+
.filter(
|
129
|
+
(repo) =>
|
130
|
+
selectedRepos.includes(repo.name) &&
|
131
|
+
repo.katello_root_repository_id === null
|
132
|
+
)
|
133
|
+
.map((repo) => repo.name)
|
134
|
+
);
|
135
|
+
};
|
136
|
+
|
137
|
+
const selectOptions = sccRepos.map((repo) =>
|
138
|
+
createRepoSelectOption(repo, disableRepos)
|
139
|
+
);
|
140
|
+
|
141
|
+
return (
|
142
|
+
<Select
|
143
|
+
variant={SelectVariant.checkbox}
|
144
|
+
isCheckboxSelectionBadgeHidden
|
145
|
+
onToggle={onToggle}
|
146
|
+
onSelect={onSelect}
|
147
|
+
selections={selected}
|
148
|
+
isOpen={isOpen}
|
149
|
+
isDisabled={disableRepos}
|
150
|
+
placeholderText={sprintf(__('%s/%s'), selected.length, sccRepos.length)}
|
151
|
+
>
|
152
|
+
{selectOptions}
|
153
|
+
</Select>
|
154
|
+
);
|
155
|
+
};
|
156
|
+
|
157
|
+
SCCRepoPicker.propTypes = {
|
158
|
+
sccRepos: PropTypes.array,
|
159
|
+
disableRepos: PropTypes.bool,
|
160
|
+
activateDebugFilter: PropTypes.bool,
|
161
|
+
productAlreadySynced: PropTypes.bool,
|
162
|
+
sccProductId: PropTypes.number.isRequired,
|
163
|
+
sccProductName: PropTypes.string.isRequired,
|
164
|
+
setSelectedReposFromChild: PropTypes.func.isRequired,
|
165
|
+
};
|
166
|
+
|
167
|
+
SCCRepoPicker.defaultProps = {
|
168
|
+
sccRepos: [],
|
169
|
+
disableRepos: false,
|
170
|
+
activateDebugFilter: false,
|
171
|
+
productAlreadySynced: false,
|
172
|
+
};
|
173
|
+
|
174
|
+
export default SCCRepoPicker;
|