katello 3.18.5 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/katello/katello.scss +72 -0
- data/app/controllers/katello/api/registry/registry_proxies_controller.rb +6 -4
- data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +0 -19
- data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -3
- data/app/controllers/katello/api/v2/content_credentials_controller.rb +24 -24
- data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +1 -1
- data/app/controllers/katello/api/v2/content_exports_controller.rb +4 -0
- data/app/controllers/katello/api/v2/content_views_controller.rb +2 -2
- data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +2 -3
- data/app/controllers/katello/api/v2/repositories_controller.rb +3 -19
- data/app/controllers/katello/api/v2/simple_content_access_controller.rb +34 -0
- data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
- data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +8 -4
- data/app/controllers/katello/concerns/api/v2/authorization.rb +1 -14
- data/app/controllers/katello/concerns/authorization/api/v2/content_views_controller.rb +1 -1
- data/app/helpers/katello/sync_management_helper.rb +0 -2
- data/app/lib/actions/candlepin/environment/create.rb +1 -1
- data/app/lib/actions/candlepin/environment/set_content.rb +1 -1
- data/app/lib/actions/katello/activation_key/create.rb +9 -11
- data/app/lib/actions/katello/capsule_content/sync.rb +8 -8
- data/app/lib/actions/katello/capsule_content/sync_capsule.rb +9 -0
- data/app/lib/actions/katello/check_matching_content.rb +17 -0
- data/app/lib/actions/katello/content_view/environment_create.rb +6 -8
- data/app/lib/actions/katello/content_view/publish.rb +1 -1
- data/app/lib/actions/katello/content_view_version/incremental_update.rb +11 -7
- data/app/lib/actions/katello/host/hypervisors_update.rb +4 -4
- data/app/lib/actions/katello/organization/create.rb +3 -5
- data/app/lib/actions/katello/organization/destroy.rb +1 -1
- data/app/lib/actions/katello/organization/manifest_delete.rb +3 -5
- data/app/lib/actions/katello/organization/manifest_import.rb +1 -1
- data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
- data/app/lib/actions/katello/orphan_cleanup/remove_orphans.rb +1 -1
- data/app/lib/actions/katello/repository/check_matching_content.rb +3 -1
- data/app/lib/actions/katello/repository/clone_contents.rb +8 -11
- data/app/lib/actions/katello/repository/create.rb +0 -8
- data/app/lib/actions/katello/repository/filtered_index_content.rb +3 -0
- data/app/lib/actions/katello/repository/index_content.rb +1 -0
- data/app/lib/actions/katello/repository/multi_clone_contents.rb +9 -12
- data/app/lib/actions/katello/repository/sync.rb +1 -5
- data/app/lib/actions/katello/repository/update.rb +0 -8
- data/app/lib/actions/middleware/execute_if_contents_changed.rb +4 -1
- data/app/lib/actions/pulp/orchestration/repository/refresh_repos.rb +0 -6
- data/app/lib/actions/pulp3/capsule_content/refresh_distribution.rb +3 -3
- data/app/lib/actions/pulp3/content_guard/refresh_all_distributions.rb +1 -2
- data/app/lib/actions/pulp3/content_migration_presenter.rb +2 -5
- data/app/lib/actions/pulp3/orchestration/repository/refresh_repos.rb +1 -6
- data/app/lib/katello/concerns/base_template_scope_extensions.rb +8 -0
- data/app/lib/katello/errors.rb +1 -1
- data/app/lib/katello/event_daemon/monitor.rb +53 -0
- data/app/lib/katello/event_daemon/runner.rb +99 -0
- data/app/lib/katello/logging.rb +32 -0
- data/app/lib/katello/messaging/connection.rb +1 -7
- data/app/lib/katello/util/pulpcore_content_filters.rb +1 -1
- data/app/lib/katello/validators/content_view_puppet_module_validator.rb +1 -1
- data/app/models/katello/activation_key.rb +2 -2
- data/app/models/katello/candlepin/repository_mapper.rb +1 -1
- data/app/models/katello/concerns/hostgroup_extensions.rb +2 -4
- data/app/models/katello/concerns/organization_extensions.rb +2 -2
- data/app/models/katello/concerns/pulp_database_unit.rb +0 -12
- data/app/models/katello/concerns/redhat_extensions.rb +8 -9
- data/app/models/katello/concerns/smart_proxy_extensions.rb +24 -0
- data/app/models/katello/content_view.rb +5 -1
- data/app/models/katello/content_view_environment.rb +2 -2
- data/app/models/katello/content_view_puppet_environment.rb +2 -2
- data/app/models/katello/content_view_version.rb +2 -1
- data/app/models/katello/content_view_version_export_history.rb +20 -0
- data/app/models/katello/erratum.rb +3 -1
- data/app/models/katello/file_unit.rb +0 -4
- data/app/models/katello/glue/candlepin/pool.rb +2 -0
- data/app/models/katello/glue/pulp/repo.rb +0 -6
- data/app/models/katello/glue/pulp/repos.rb +1 -22
- data/app/models/katello/host/content_facet.rb +31 -9
- data/app/models/katello/ping.rb +19 -39
- data/app/models/katello/pool.rb +5 -0
- data/app/models/katello/product.rb +3 -3
- data/app/models/katello/repository.rb +3 -3
- data/app/presenters/katello/host_subscription_presenter.rb +3 -4
- data/app/presenters/katello/host_subscriptions_presenter.rb +24 -0
- data/app/services/katello/applicability/applicable_content_helper.rb +6 -8
- data/app/services/katello/candlepin_event_listener.rb +11 -19
- data/app/services/katello/event_monitor/poller_thread.rb +2 -11
- data/app/services/katello/pulp/repository.rb +2 -4
- data/app/services/katello/pulp/smart_proxy_repository.rb +0 -15
- data/app/services/katello/pulp3/api/core.rb +0 -14
- data/app/services/katello/pulp3/erratum.rb +1 -2
- data/app/services/katello/pulp3/migration.rb +9 -83
- data/app/services/katello/pulp3/migration_plan.rb +5 -54
- data/app/services/katello/pulp3/migration_switchover.rb +5 -36
- data/app/services/katello/pulp3/repository/apt.rb +2 -1
- data/app/services/katello/pulp3/repository/yum.rb +2 -11
- data/app/services/katello/pulp3/repository.rb +13 -34
- data/app/services/katello/pulp3/rpm.rb +1 -5
- data/app/services/katello/pulp3/task.rb +5 -8
- data/app/services/katello/pulp3/task_group.rb +5 -13
- data/app/services/katello/repository_type.rb +1 -1
- data/app/views/foreman/smart_proxies/_content_tab.html.erb +4 -47
- data/app/views/foreman/smart_proxies/show.html.erb +1 -1
- data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +22 -25
- data/app/views/katello/api/v2/content_view_version_export_histories/show.json.rabl +1 -0
- data/app/views/katello/api/v2/organizations/show.json.rabl +7 -9
- data/app/views/katello/sync_management/_products.html.erb +1 -1
- data/app/views/overrides/organizations/_edit_override.html.erb +1 -4
- data/app/views/overrides/smart_proxies/_environment_tab.html.erb +1 -1
- data/app/views/overrides/smart_proxies/_environment_tab_pane.html.erb +1 -1
- data/config/katello.yaml.example +0 -3
- data/config/routes/api/v2.rb +8 -10
- data/db/migrate/20191204214919_add_content_view_version_counts.rb +0 -1
- data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +1 -1
- data/db/migrate/20210119162528_delete_puppet_and_ostree_repos.rb +56 -0
- data/db/migrate/20210128231228_add_type_and_from_cvv_to_cvv_export_history.rb +14 -0
- data/db/migrate/20210201163238_migrate_background_download_policy_to_migrate.rb +7 -0
- data/db/seeds.d/104-proxy.rb +1 -1
- data/db/seeds.d/111-upgrade_tasks.rb +2 -1
- data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-host-register-os-client.directive.js +17 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +11 -4
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-deb-client.html +38 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-oracle-client.html +5 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-sles-client.html +28 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register.html +14 -11
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/views/package-filter-details.html +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/download-policy.service.js +0 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +2 -2
- data/lib/katello/engine.rb +4 -5
- data/lib/katello/middleware/event_daemon.rb +1 -1
- data/lib/katello/permission_creator.rb +3 -2
- data/lib/katello/plugin.rb +2 -2
- data/lib/katello/tasks/jenkins.rake +1 -1
- data/lib/katello/tasks/pulp3_content_switchover.rake +20 -31
- data/lib/katello/tasks/pulp3_migration.rake +25 -45
- data/lib/katello/tasks/pulp3_migration_abort.rake +0 -8
- data/lib/katello/tasks/pulp3_migration_stats.rake +3 -46
- data/lib/katello/tasks/upgrades/4.0/remove_ostree_puppet_content.rake +16 -0
- data/lib/katello/version.rb +1 -1
- data/lib/proxy_api/container_gateway.rb +21 -0
- data/locale/bn/katello.edit.po +0 -0
- data/locale/cs/katello.edit.po +0 -0
- data/locale/de/katello.edit.po +0 -0
- data/locale/en/katello.edit.po +0 -0
- data/locale/es/katello.edit.po +0 -0
- data/locale/fr/katello.edit.po +0 -0
- data/locale/gu/katello.edit.po +0 -0
- data/locale/hi/katello.edit.po +0 -0
- data/locale/it/katello.edit.po +0 -0
- data/locale/ja/katello.edit.po +0 -0
- data/locale/kn/katello.edit.po +0 -0
- data/locale/ko/katello.edit.po +0 -0
- data/locale/mr/katello.edit.po +0 -0
- data/locale/or/katello.edit.po +0 -0
- data/locale/pa/katello.edit.po +0 -0
- data/locale/pt/katello.edit.po +0 -0
- data/locale/pt_BR/katello.edit.po +0 -0
- data/locale/ru/katello.edit.po +0 -0
- data/locale/ta/katello.edit.po +0 -0
- data/locale/te/katello.edit.po +0 -0
- data/locale/zh_CN/katello.edit.po +0 -0
- data/locale/zh_TW/katello.edit.po +0 -0
- data/package.json +1 -1
- data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +0 -1
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationHooks.js +2 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/LongDateTime.js +5 -0
- data/webpack/{scenes/ContentViews/Details/Repositories → components/SelectableDropdown}/SelectableDropdown.js +20 -3
- data/webpack/components/SelectableDropdown/__tests__/SelectableDropdown.test.js +45 -0
- data/webpack/components/SelectableDropdown/index.js +3 -0
- data/webpack/components/Table/TableWrapper.js +2 -1
- data/webpack/components/Table/helpers.js +14 -0
- data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +0 -1
- data/webpack/containers/Application/overrides.scss +6 -0
- data/webpack/index.js +6 -0
- data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
- data/webpack/scenes/ContentViews/ContentViewsActions.js +31 -2
- data/webpack/scenes/ContentViews/ContentViewsConstants.js +5 -1
- data/webpack/scenes/ContentViews/Copy/ContentViewCopySelectors.js +16 -0
- data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +77 -0
- data/webpack/scenes/ContentViews/Copy/CopyContentViewModal.js +44 -0
- data/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json +42 -0
- data/webpack/scenes/ContentViews/Copy/__tests__/copyContentView.test.js +39 -0
- data/webpack/scenes/ContentViews/Copy/index.js +4 -0
- data/webpack/scenes/ContentViews/Create/ContentViewCreateSelectors.js +16 -0
- data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +58 -0
- data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +175 -0
- data/webpack/scenes/ContentViews/Create/CreateContentViewModal.js +27 -0
- data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +42 -0
- data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +92 -0
- data/webpack/scenes/ContentViews/Create/index.js +4 -0
- data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +16 -0
- data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +20 -1
- data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +17 -7
- data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +19 -13
- data/webpack/scenes/ContentViews/Details/Filters/ContentType.js +40 -0
- data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +124 -0
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.fixtures.json +134 -0
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.test.js +92 -0
- data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +44 -25
- data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewDetailRepos.test.js +17 -7
- data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetail.test.js +24 -0
- data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +53 -3
- data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +4 -3
- data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +41 -0
- data/webpack/scenes/ContentViews/helpers.js +13 -0
- data/webpack/scenes/SmartProxy/Content.js +17 -0
- data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +11 -0
- data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +3 -0
- data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +16 -0
- data/webpack/scenes/SmartProxy/SmartProxyContentTable.js +152 -0
- data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json +140 -0
- data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +38 -0
- data/webpack/scenes/SmartProxy/index.js +4 -0
- data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +2 -7
- data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +3 -3
- data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +2 -2
- data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +2 -2
- data/webpack/scenes/Subscriptions/Manifest/index.js +0 -1
- data/webpack/test-utils/react-testing-lib-wrapper.js +5 -2
- data/webpack/utils/helpers.js +3 -0
- metadata +103 -63
- data/app/controllers/katello/api/v2/gpg_keys_controller.rb +0 -114
- data/app/lib/actions/pulp3/content_migration_reset.rb +0 -22
- data/app/lib/katello/util/hostgroup_facets_helper.rb +0 -126
- data/app/overrides/disable_turbolinks_on_proxies_index.rb +0 -5
- data/app/services/katello/event_daemon.rb +0 -135
- data/app/services/katello/pulp/content_counts_calculator.rb +0 -60
- data/db/migrate/20210201165835_add_migration_missing_content.rb +0 -12
- data/db/migrate/20210420140050_add_pulp3_hrefs_to_content_types_deb.rb +0 -5
- data/lib/katello/tasks/check_config.rake +0 -11
- data/lib/katello/tasks/fix_hostgroup_facets.rake +0 -8
- data/lib/katello/tasks/pulp3_migration_approve_corrupted.rake +0 -21
- data/lib/katello/tasks/pulp3_migration_reset.rake +0 -26
- data/lib/katello/tasks/reports.rake +0 -7
- data/lib/katello/tasks/upgrades/3.10/update_gpg_key_urls.rake +0 -32
- data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.scss +0 -5
- data/webpack/scenes/ContentViews/Table/actionResolver.js +0 -28
@@ -41,7 +41,6 @@ const buildRow = (contentView, openColumn) => {
|
|
41
41
|
},
|
42
42
|
];
|
43
43
|
if (openColumn) row[openColumn].props.isOpen = true;
|
44
|
-
|
45
44
|
return row;
|
46
45
|
};
|
47
46
|
|
@@ -100,7 +99,7 @@ const buildRowsAndMapping = (contentViews, newRowMapping) => {
|
|
100
99
|
const rows = [];
|
101
100
|
|
102
101
|
contentViews.forEach((contentView) => {
|
103
|
-
const { id } = contentView;
|
102
|
+
const { id, name } = contentView;
|
104
103
|
const rowIndex = rows.length;
|
105
104
|
const needsUpdate = !Object.keys(updatedRowMap).find(i => updatedRowMap[i].id === id) ||
|
106
105
|
!Object.keys(updatedRowMap[rowIndex] || {}).includes('expandedColumn');
|
@@ -109,7 +108,9 @@ const buildRowsAndMapping = (contentViews, newRowMapping) => {
|
|
109
108
|
const cells = buildRow(contentView, openColumn);
|
110
109
|
const isOpen = !!openColumn;
|
111
110
|
|
112
|
-
rows.push({
|
111
|
+
rows.push({
|
112
|
+
cvId: id, cvName: name, isOpen, cells,
|
113
|
+
});
|
113
114
|
rows.push(...buildDetailDropdowns(id, rowIndex, openColumn));
|
114
115
|
});
|
115
116
|
|
@@ -246,4 +246,45 @@ test('No results message is shown for empty search', async (done) => {
|
|
246
246
|
assertNockRequest(withSearchScope);
|
247
247
|
assertNockRequest(searchResultScope, done);
|
248
248
|
});
|
249
|
+
|
250
|
+
test('Displays Create Content View and opens modal with Form', async () => {
|
251
|
+
mockAutocomplete(nockInstance, autocompleteUrl);
|
252
|
+
|
253
|
+
const noResults = {
|
254
|
+
total: 0,
|
255
|
+
subtotal: 0,
|
256
|
+
page: 1,
|
257
|
+
per_page: 20,
|
258
|
+
results: [],
|
259
|
+
};
|
260
|
+
nockInstance
|
261
|
+
.get(cvIndexPath)
|
262
|
+
.query(true)
|
263
|
+
.reply(200, noResults);
|
264
|
+
const {
|
265
|
+
getByText, queryByText, getByLabelText,
|
266
|
+
} = renderWithRedux(<ContentViewsPage />, renderOptions);
|
267
|
+
await patientlyWaitFor(() => expect(queryByText('Create content view')).toBeTruthy());
|
268
|
+
|
269
|
+
expect(queryByText('Description')).not.toBeInTheDocument();
|
270
|
+
expect(queryByText('Name')).not.toBeInTheDocument();
|
271
|
+
expect(queryByText('Label')).not.toBeInTheDocument();
|
272
|
+
expect(queryByText('Composite content view')).not.toBeInTheDocument();
|
273
|
+
expect(queryByText('Component content view')).not.toBeInTheDocument();
|
274
|
+
expect(queryByText('Solve Dependencies')).not.toBeInTheDocument();
|
275
|
+
expect(queryByText('Auto Publish')).not.toBeInTheDocument();
|
276
|
+
expect(queryByText('Import Only')).not.toBeInTheDocument();
|
277
|
+
|
278
|
+
getByLabelText('create_content_view').click();
|
279
|
+
|
280
|
+
expect(getByText('Description')).toBeInTheDocument();
|
281
|
+
expect(getByText('Name')).toBeInTheDocument();
|
282
|
+
expect(getByText('Label')).toBeInTheDocument();
|
283
|
+
expect(getByText('Composite content view')).toBeInTheDocument();
|
284
|
+
expect(getByText('Component content view')).toBeInTheDocument();
|
285
|
+
expect(getByText('Solve Dependencies')).toBeInTheDocument();
|
286
|
+
expect(queryByText('Auto Publish')).not.toBeInTheDocument();
|
287
|
+
expect(getByText('Import Only')).toBeInTheDocument();
|
288
|
+
});
|
289
|
+
|
249
290
|
/* eslint-enable no-useless-escape */
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
2
|
+
|
3
|
+
export const dependenciesHelpText = __('This will solve RPM and module stream dependencies on every publish of this content view. ' +
|
4
|
+
'Dependency solving significantly increases publish time (publishes can take over three times as long) ' +
|
5
|
+
'and filters will be ignored when adding packages to solve dependencies. ' +
|
6
|
+
'Also, certain scenarios involving errata may still cause dependency errors.');
|
7
|
+
|
8
|
+
export const autoPublishHelpText = __('Automatically publish a new version of the composite content view whenever one of its content views is published. ' +
|
9
|
+
'Autopublish will only happen for component views that use the \'Always use latest version\' option.');
|
10
|
+
|
11
|
+
export const importOnlyHelpText = __('Designate whether this content view is for importing from an upstream server. ' +
|
12
|
+
'Import-only content views cannot be published directly.');
|
13
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import SmartProxyContentTable from './SmartProxyContentTable';
|
4
|
+
|
5
|
+
const Content = ({ smartProxyId }) => (
|
6
|
+
<SmartProxyContentTable smartProxyId={smartProxyId} />
|
7
|
+
);
|
8
|
+
|
9
|
+
Content.propTypes = {
|
10
|
+
smartProxyId: PropTypes.number,
|
11
|
+
};
|
12
|
+
|
13
|
+
Content.defaultProps = {
|
14
|
+
smartProxyId: null,
|
15
|
+
};
|
16
|
+
|
17
|
+
export default Content;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { API_OPERATIONS, get } from 'foremanReact/redux/API';
|
2
|
+
import api, { orgId } from '../../services/api';
|
3
|
+
import SMART_PROXY_CONTENT_KEY from './SmartProxyContentConstants';
|
4
|
+
|
5
|
+
const getSmartProxyContent = ({ smartProxyId }) => get({
|
6
|
+
type: API_OPERATIONS.GET,
|
7
|
+
key: SMART_PROXY_CONTENT_KEY,
|
8
|
+
url: api.getApiUrl(`/capsules/${smartProxyId}/content/sync?${orgId()}`),
|
9
|
+
});
|
10
|
+
|
11
|
+
export default getSmartProxyContent;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import {
|
2
|
+
selectAPIStatus,
|
3
|
+
selectAPIError,
|
4
|
+
selectAPIResponse,
|
5
|
+
} from 'foremanReact/redux/API/APISelectors';
|
6
|
+
import { STATUS } from 'foremanReact/constants';
|
7
|
+
import SMART_PROXY_CONTENT_KEY from './SmartProxyContentConstants';
|
8
|
+
|
9
|
+
export const selectSmartProxyContent = state =>
|
10
|
+
selectAPIResponse(state, SMART_PROXY_CONTENT_KEY) || {};
|
11
|
+
|
12
|
+
export const selectSmartProxyContentStatus = state =>
|
13
|
+
selectAPIStatus(state, SMART_PROXY_CONTENT_KEY) || STATUS.PENDING;
|
14
|
+
|
15
|
+
export const selectSmartProxyContentError = state =>
|
16
|
+
selectAPIError(state, SMART_PROXY_CONTENT_KEY);
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { useSelector, useDispatch } from 'react-redux';
|
4
|
+
import { wrappable } from '@patternfly/react-table';
|
5
|
+
import { CheckCircleIcon, TimesCircleIcon } from '@patternfly/react-icons';
|
6
|
+
import { STATUS } from 'foremanReact/constants';
|
7
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
8
|
+
import { urlBuilder } from 'foremanReact/common/urlHelpers';
|
9
|
+
import LongDateTime from 'foremanReact/components/common/dates/LongDateTime';
|
10
|
+
import MainTable from '../../components/Table/MainTable';
|
11
|
+
import getSmartProxyContent from './SmartProxyContentActions';
|
12
|
+
import ContentViewIcon from '../../scenes/ContentViews/components/ContentViewIcon';
|
13
|
+
import {
|
14
|
+
selectSmartProxyContent,
|
15
|
+
selectSmartProxyContentStatus,
|
16
|
+
selectSmartProxyContentError,
|
17
|
+
} from './SmartProxyContentSelectors';
|
18
|
+
|
19
|
+
const SmartProxyContentTable = ({ smartProxyId }) => {
|
20
|
+
const dispatch = useDispatch();
|
21
|
+
const [rows, setRows] = useState([]);
|
22
|
+
const response = useSelector(state => selectSmartProxyContent(state));
|
23
|
+
const status = useSelector(state => selectSmartProxyContentStatus(state));
|
24
|
+
const error = useSelector(state => selectSmartProxyContentError(state));
|
25
|
+
const columnHeaders = [
|
26
|
+
{
|
27
|
+
title: __('Environment'),
|
28
|
+
transforms: [wrappable],
|
29
|
+
},
|
30
|
+
{
|
31
|
+
title: __('Content view'),
|
32
|
+
transforms: [wrappable],
|
33
|
+
},
|
34
|
+
{
|
35
|
+
title: __('Type'),
|
36
|
+
transforms: [wrappable],
|
37
|
+
},
|
38
|
+
{
|
39
|
+
title: __('Last published'),
|
40
|
+
transforms: [wrappable],
|
41
|
+
},
|
42
|
+
{
|
43
|
+
title: __('Repositories'),
|
44
|
+
transforms: [wrappable],
|
45
|
+
},
|
46
|
+
{
|
47
|
+
title: __('Synced to smart proxy'),
|
48
|
+
transforms: [wrappable],
|
49
|
+
},
|
50
|
+
];
|
51
|
+
|
52
|
+
const fetchWithParams = () => {
|
53
|
+
dispatch(getSmartProxyContent({ smartProxyId }));
|
54
|
+
};
|
55
|
+
|
56
|
+
const buildrows = (results) => {
|
57
|
+
const newRows = [];
|
58
|
+
let envCount = 0;
|
59
|
+
results.forEach((env) => {
|
60
|
+
const { name, content_views: contentViews } = env;
|
61
|
+
const cellEnv = {
|
62
|
+
isOpen: false,
|
63
|
+
cells: [name, null, null, null, null, null],
|
64
|
+
};
|
65
|
+
newRows.push(cellEnv);
|
66
|
+
contentViews.forEach((cv) => {
|
67
|
+
const {
|
68
|
+
id, name: cvName, composite, last_published: lastPublished, up_to_date: upToDate, counts,
|
69
|
+
} = cv;
|
70
|
+
const { repositories } = counts;
|
71
|
+
const cvType = <ContentViewIcon composite={composite} />;
|
72
|
+
const upToDateVal = upToDate ? <CheckCircleIcon /> : <TimesCircleIcon />;
|
73
|
+
const cellCv =
|
74
|
+
{
|
75
|
+
parent: envCount,
|
76
|
+
cells: [
|
77
|
+
{
|
78
|
+
title: null,
|
79
|
+
props: {
|
80
|
+
colSpan: 1,
|
81
|
+
},
|
82
|
+
},
|
83
|
+
{
|
84
|
+
title: <a href={urlBuilder('content_views', '', id)}>{cvName}</a>,
|
85
|
+
props: {
|
86
|
+
colSpan: 1,
|
87
|
+
},
|
88
|
+
},
|
89
|
+
{
|
90
|
+
title: cvType,
|
91
|
+
props: {
|
92
|
+
colSpan: 1,
|
93
|
+
},
|
94
|
+
},
|
95
|
+
{
|
96
|
+
title: <LongDateTime date={lastPublished} showRelativeTimeTooltip />,
|
97
|
+
props: {
|
98
|
+
colSpan: 1,
|
99
|
+
},
|
100
|
+
},
|
101
|
+
{
|
102
|
+
title: repositories,
|
103
|
+
props: {
|
104
|
+
colSpan: 1,
|
105
|
+
},
|
106
|
+
},
|
107
|
+
{
|
108
|
+
title: upToDateVal,
|
109
|
+
props: {
|
110
|
+
colSpan: 1,
|
111
|
+
},
|
112
|
+
},
|
113
|
+
],
|
114
|
+
};
|
115
|
+
newRows.push(cellCv);
|
116
|
+
});
|
117
|
+
envCount = newRows.length;
|
118
|
+
});
|
119
|
+
return newRows;
|
120
|
+
};
|
121
|
+
|
122
|
+
const onCollapse = (row, setRow) => (event, rowKey, isOpen) => {
|
123
|
+
const newRows = [...row];
|
124
|
+
newRows[rowKey].isOpen = isOpen;
|
125
|
+
setRow(newRows);
|
126
|
+
};
|
127
|
+
|
128
|
+
|
129
|
+
useEffect(() => fetchWithParams(), []);
|
130
|
+
|
131
|
+
useEffect(() => {
|
132
|
+
if (status !== STATUS.PENDING && response) {
|
133
|
+
const { lifecycle_environments: env } = response;
|
134
|
+
setRows(buildrows(env));
|
135
|
+
}
|
136
|
+
}, [JSON.stringify(response), status, error]);
|
137
|
+
|
138
|
+
|
139
|
+
return (
|
140
|
+
<MainTable onCollapse={onCollapse(rows, setRows)} status={status} cells={columnHeaders} rows={rows} error={error} emptyContentTitle="No content synced" emptyContentBody="No content synced to smart proxy" emptySearchTitle="Empty" emptySearchBody="Empty" />
|
141
|
+
);
|
142
|
+
};
|
143
|
+
|
144
|
+
SmartProxyContentTable.propTypes = {
|
145
|
+
smartProxyId: PropTypes.number,
|
146
|
+
};
|
147
|
+
|
148
|
+
SmartProxyContentTable.defaultProps = {
|
149
|
+
smartProxyId: null,
|
150
|
+
};
|
151
|
+
|
152
|
+
export default SmartProxyContentTable;
|
@@ -0,0 +1,140 @@
|
|
1
|
+
{
|
2
|
+
"last_sync_time": "2021-01-12 14:39:01 -0500",
|
3
|
+
"active_sync_tasks": [],
|
4
|
+
"last_failed_sync_tasks": [],
|
5
|
+
"lifecycle_environments": [
|
6
|
+
{
|
7
|
+
"library": true,
|
8
|
+
"id": 1,
|
9
|
+
"name": "Library",
|
10
|
+
"label": "Library",
|
11
|
+
"description": null,
|
12
|
+
"organization_id": 1,
|
13
|
+
"organization": {
|
14
|
+
"name": "Default Organization",
|
15
|
+
"label": "Default_Organization",
|
16
|
+
"id": 1
|
17
|
+
},
|
18
|
+
"syncable": false,
|
19
|
+
"counts": {
|
20
|
+
"content_hosts": 0,
|
21
|
+
"content_views": 2,
|
22
|
+
"products": 1
|
23
|
+
},
|
24
|
+
"content_views": [
|
25
|
+
{
|
26
|
+
"id": 1,
|
27
|
+
"label": "Default_Organization_View",
|
28
|
+
"name": "Default Organization View",
|
29
|
+
"composite": false,
|
30
|
+
"last_published": "2021-01-05 09:55:20 -0500",
|
31
|
+
"default": true,
|
32
|
+
"up_to_date": true,
|
33
|
+
"counts": {
|
34
|
+
"content_hosts": 0,
|
35
|
+
"products": 1,
|
36
|
+
"repositories": 2
|
37
|
+
}
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"id": 2,
|
41
|
+
"label": "cv1",
|
42
|
+
"name": "cv1",
|
43
|
+
"composite": false,
|
44
|
+
"last_published": "2021-01-12 14:36:31 -0500",
|
45
|
+
"default": false,
|
46
|
+
"up_to_date": true,
|
47
|
+
"counts": {
|
48
|
+
"content_hosts": 0,
|
49
|
+
"products": 1,
|
50
|
+
"repositories": 1
|
51
|
+
}
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"id": 3,
|
55
|
+
"label": "cv2",
|
56
|
+
"name": "cv2",
|
57
|
+
"composite": false,
|
58
|
+
"last_published": "2021-01-12 14:37:05 -0500",
|
59
|
+
"default": false,
|
60
|
+
"up_to_date": true,
|
61
|
+
"counts": {
|
62
|
+
"content_hosts": 0,
|
63
|
+
"products": 1,
|
64
|
+
"repositories": 1
|
65
|
+
}
|
66
|
+
}
|
67
|
+
]
|
68
|
+
},
|
69
|
+
{
|
70
|
+
"library": false,
|
71
|
+
"id": 2,
|
72
|
+
"name": "dev",
|
73
|
+
"label": "dev",
|
74
|
+
"description": null,
|
75
|
+
"organization_id": 1,
|
76
|
+
"organization": {
|
77
|
+
"name": "Default Organization",
|
78
|
+
"label": "Default_Organization",
|
79
|
+
"id": 1
|
80
|
+
},
|
81
|
+
"syncable": false,
|
82
|
+
"counts": {
|
83
|
+
"content_hosts": 0,
|
84
|
+
"content_views": 1,
|
85
|
+
"products": 1
|
86
|
+
},
|
87
|
+
"content_views": [
|
88
|
+
{
|
89
|
+
"id": 2,
|
90
|
+
"label": "cv1",
|
91
|
+
"name": "cv1",
|
92
|
+
"composite": false,
|
93
|
+
"last_published": "2021-01-12 14:36:31 -0500",
|
94
|
+
"default": false,
|
95
|
+
"up_to_date": true,
|
96
|
+
"counts": {
|
97
|
+
"content_hosts": 0,
|
98
|
+
"products": 1,
|
99
|
+
"repositories": 1
|
100
|
+
}
|
101
|
+
}
|
102
|
+
]
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"library": false,
|
106
|
+
"id": 3,
|
107
|
+
"name": "test",
|
108
|
+
"label": "test",
|
109
|
+
"description": null,
|
110
|
+
"organization_id": 1,
|
111
|
+
"organization": {
|
112
|
+
"name": "Default Organization",
|
113
|
+
"label": "Default_Organization",
|
114
|
+
"id": 1
|
115
|
+
},
|
116
|
+
"syncable": true,
|
117
|
+
"counts": {
|
118
|
+
"content_hosts": 0,
|
119
|
+
"content_views": 1,
|
120
|
+
"products": 1
|
121
|
+
},
|
122
|
+
"content_views": [
|
123
|
+
{
|
124
|
+
"id": 2,
|
125
|
+
"label": "cv1",
|
126
|
+
"name": "cv1",
|
127
|
+
"composite": false,
|
128
|
+
"last_published": "2021-01-12 14:36:31 -0500",
|
129
|
+
"default": false,
|
130
|
+
"up_to_date": false,
|
131
|
+
"counts": {
|
132
|
+
"content_hosts": 0,
|
133
|
+
"products": 1,
|
134
|
+
"repositories": 0
|
135
|
+
}
|
136
|
+
}
|
137
|
+
]
|
138
|
+
}
|
139
|
+
]
|
140
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
|
3
|
+
|
4
|
+
import { nockInstance, assertNockRequest } from '../../../test-utils/nockWrapper';
|
5
|
+
import api from '../../../services/api';
|
6
|
+
import SmartProxyContentTable from '../SmartProxyContentTable';
|
7
|
+
|
8
|
+
const smartProxyContentData = require('./SmartProxyContentResult.fixtures.json');
|
9
|
+
|
10
|
+
const smartProxyContentPath = api.getApiUrl('/capsules/1/content/sync');
|
11
|
+
|
12
|
+
const smartProxyContent = { ...smartProxyContentData };
|
13
|
+
|
14
|
+
const contentTable = <SmartProxyContentTable smartProxyId={1} />;
|
15
|
+
|
16
|
+
test('Can display Smart proxy content table', async (done) => {
|
17
|
+
const detailsScope = nockInstance
|
18
|
+
.get(smartProxyContentPath)
|
19
|
+
.query(true)
|
20
|
+
.reply(200, smartProxyContent);
|
21
|
+
|
22
|
+
const { getByText, getAllByLabelText } = renderWithRedux(contentTable);
|
23
|
+
await patientlyWaitFor(() => expect(getByText('Environment')).toBeInTheDocument());
|
24
|
+
expect(getByText('Content view')).toBeInTheDocument();
|
25
|
+
expect(getByText('Type')).toBeInTheDocument();
|
26
|
+
expect(getByText('Last published')).toBeInTheDocument();
|
27
|
+
expect(getByText('Repositories')).toBeInTheDocument();
|
28
|
+
expect(getByText('Synced to smart proxy')).toBeInTheDocument();
|
29
|
+
expect(getAllByLabelText('Details')[0]).toHaveAttribute('aria-expanded', 'false');
|
30
|
+
getAllByLabelText('Details')[0].click();
|
31
|
+
expect(getAllByLabelText('Details')[0]).toHaveAttribute('aria-expanded', 'true');
|
32
|
+
expect(getByText('Library')).toBeInTheDocument();
|
33
|
+
expect(getByText('Default Organization View')).toBeInTheDocument();
|
34
|
+
expect(getByText('dev')).toBeInTheDocument();
|
35
|
+
|
36
|
+
|
37
|
+
assertNockRequest(detailsScope, done);
|
38
|
+
});
|
@@ -51,11 +51,8 @@ class ManageManifestModal extends Component {
|
|
51
51
|
showDeleteManifestModal = () =>
|
52
52
|
this.props.setModalOpen({ id: DELETE_MANIFEST_MODAL_ID });
|
53
53
|
|
54
|
-
hideDeleteManifestModal = () =>
|
55
|
-
|
56
|
-
this.props.setModalClosed({ id: DELETE_MANIFEST_MODAL_ID });
|
57
|
-
}
|
58
|
-
};
|
54
|
+
hideDeleteManifestModal = () =>
|
55
|
+
this.props.setModalClosed({ id: DELETE_MANIFEST_MODAL_ID });
|
59
56
|
|
60
57
|
updateRepositoryUrl = (event) => {
|
61
58
|
this.setState({ redhat_repository_url: event.target.value });
|
@@ -329,7 +326,6 @@ ManageManifestModal.propTypes = {
|
|
329
326
|
canImportManifest: PropTypes.bool,
|
330
327
|
canDeleteManifest: PropTypes.bool,
|
331
328
|
isManifestImported: PropTypes.bool,
|
332
|
-
deleteManifestModalExists: PropTypes.bool,
|
333
329
|
canEditOrganizations: PropTypes.bool,
|
334
330
|
disableManifestActions: PropTypes.bool,
|
335
331
|
disabledReason: PropTypes.string,
|
@@ -355,7 +351,6 @@ ManageManifestModal.defaultProps = {
|
|
355
351
|
canImportManifest: false,
|
356
352
|
canDeleteManifest: false,
|
357
353
|
isManifestImported: false,
|
358
|
-
deleteManifestModalExists: false,
|
359
354
|
canEditOrganizations: false,
|
360
355
|
simpleContentAccess: false,
|
361
356
|
simpleContentAccessEligible: undefined,
|
@@ -88,7 +88,7 @@ export const checkSimpleContentAccessEligible = () => async (dispatch) => {
|
|
88
88
|
dispatch({ type: SIMPLE_CONTENT_ACCESS_ELIGIBLE_REQUEST });
|
89
89
|
|
90
90
|
try {
|
91
|
-
const { data } = await api.get(`/organizations/${orgId()}/
|
91
|
+
const { data } = await api.get(`/organizations/${orgId()}/simple_content_access/eligible`, {});
|
92
92
|
return dispatch({
|
93
93
|
type: SIMPLE_CONTENT_ACCESS_ELIGIBLE_SUCCESS,
|
94
94
|
response: data,
|
@@ -106,7 +106,7 @@ export const enableSimpleContentAccess = (extendedParams = {}) => async (dispatc
|
|
106
106
|
};
|
107
107
|
|
108
108
|
try {
|
109
|
-
const { data } = await api.put(`/organizations/${orgId()}/
|
109
|
+
const { data } = await api.put(`/organizations/${orgId()}/simple_content_access/enable`, {}, params);
|
110
110
|
return dispatch({
|
111
111
|
type: ENABLE_SIMPLE_CONTENT_ACCESS_SUCCESS,
|
112
112
|
response: data,
|
@@ -124,7 +124,7 @@ export const disableSimpleContentAccess = (extendedParams = {}) => async (dispat
|
|
124
124
|
};
|
125
125
|
|
126
126
|
try {
|
127
|
-
const { data } = await api.put(`/organizations/${orgId()}/
|
127
|
+
const { data } = await api.put(`/organizations/${orgId()}/simple_content_access/disable`, {}, params);
|
128
128
|
return dispatch({
|
129
129
|
type: DISABLE_SIMPLE_CONTENT_ACCESS_SUCCESS,
|
130
130
|
response: data,
|
@@ -136,7 +136,7 @@ describe('manifest actions', () => {
|
|
136
136
|
});
|
137
137
|
|
138
138
|
describe('creates ENABLE_SIMPLE_CONTENT_ACCESS_REQUEST', () => {
|
139
|
-
const url = '/katello/api/v2/organizations/1/
|
139
|
+
const url = '/katello/api/v2/organizations/1/simple_content_access/enable';
|
140
140
|
|
141
141
|
it('and then fails with 422', async () => {
|
142
142
|
mockErrorRequest({
|
@@ -158,7 +158,7 @@ describe('creates ENABLE_SIMPLE_CONTENT_ACCESS_REQUEST', () => {
|
|
158
158
|
});
|
159
159
|
|
160
160
|
describe('creates DISABLE_SIMPLE_CONTENT_ACCESS_REQUEST', () => {
|
161
|
-
const url = '/katello/api/v2/organizations/1/
|
161
|
+
const url = '/katello/api/v2/organizations/1/simple_content_access/disable';
|
162
162
|
|
163
163
|
it('and then fails with 422', async () => {
|
164
164
|
mockErrorRequest({
|
@@ -55,8 +55,8 @@ const initialState = {
|
|
55
55
|
},
|
56
56
|
};
|
57
57
|
|
58
|
-
const enableSimpleContetAccessPath = api.getApiUrl('/organizations/1/
|
59
|
-
const disableSimpleContetAccessPath = api.getApiUrl('/organizations/1/
|
58
|
+
const enableSimpleContetAccessPath = api.getApiUrl('/organizations/1/simple_content_access/enable');
|
59
|
+
const disableSimpleContetAccessPath = api.getApiUrl('/organizations/1/simple_content_access/disable');
|
60
60
|
const manifestHistoryPath = api.getApiUrl('/organizations/1/subscriptions/manifest_history');
|
61
61
|
|
62
62
|
test('Enable Simple Content Access after toggle switch value to true', async (done) => {
|
@@ -20,7 +20,6 @@ const mapStateToProps = state => ({
|
|
20
20
|
simpleContentAccess: selectSimpleContentAccessEnabled(state),
|
21
21
|
isManifestImported: selectIsManifestImported(state),
|
22
22
|
modalOpenState: state.foremanModals.ManageManifestModal,
|
23
|
-
deleteManifestModalExists: !!state.foremanModals.deleteManifestModal,
|
24
23
|
manifestActionStarted: selectManifestActionStarted(state),
|
25
24
|
simpleContentAccessEligible: selectSimpleContentAccessEligible(state),
|
26
25
|
});
|
@@ -8,7 +8,7 @@ import { APIMiddleware, reducers as apiReducer } from 'foremanReact/redux/API';
|
|
8
8
|
import { reducers as fillReducers } from 'foremanReact/components/common/Fill';
|
9
9
|
import { reducers as foremanModalReducer } from 'foremanReact/components/ForemanModal';
|
10
10
|
import { STATUS } from 'foremanReact/constants';
|
11
|
-
import { render, waitFor } from '@testing-library/react';
|
11
|
+
import { render, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
12
12
|
import { createStore, applyMiddleware, combineReducers } from 'redux';
|
13
13
|
import { Provider } from 'react-redux';
|
14
14
|
import { MemoryRouter } from 'react-router-dom';
|
@@ -63,7 +63,10 @@ function renderWithRedux(
|
|
63
63
|
|
64
64
|
// When the tests run slower, they can hit the default waitFor timeout, which is 1000ms
|
65
65
|
// There doesn't seem to be a way to set it globally for r-t-lib, so using this wrapper function
|
66
|
-
|
66
|
+
const rtlTimeout = 5000;
|
67
|
+
export const patientlyWaitFor = waitForFunc => waitFor(waitForFunc, { timeout: rtlTimeout });
|
68
|
+
export const patientlyWaitForRemoval = waitForFunc =>
|
69
|
+
waitForElementToBeRemoved(waitForFunc, { timeout: rtlTimeout });
|
67
70
|
|
68
71
|
// re-export everything, so the library can be used from this wrapper.
|
69
72
|
export * from '@testing-library/react';
|
data/webpack/utils/helpers.js
CHANGED
@@ -96,6 +96,9 @@ export const apiError = (actionType, result, additionalData = {}) => (dispatch)
|
|
96
96
|
return resultWithSuccessFlag(result);
|
97
97
|
};
|
98
98
|
|
99
|
+
export const capitalize = s => s && s[0].toUpperCase() + s.slice(1);
|
100
|
+
|
101
|
+
export const truncate = (str, truncateLimit = 50) => (str.length > truncateLimit ? `${str.substring(0, truncateLimit - 3)}...` : str);
|
99
102
|
|
100
103
|
export default {
|
101
104
|
getResponseErrorMsgs,
|