diff --git a/app/lib/actions/katello/capsule_content/update_content_counts.rb b/app/lib/actions/katello/capsule_content/update_content_counts.rb
index 7833208479e..4bf846bac3f 100644
--- a/app/lib/actions/katello/capsule_content/update_content_counts.rb
+++ b/app/lib/actions/katello/capsule_content/update_content_counts.rb
@@ -14,6 +14,10 @@ def run
smart_proxy = ::SmartProxy.unscoped.find(input[:smart_proxy_id])
smart_proxy.update_content_counts!
end
+
+ def rescue_strategy
+ Dynflow::Action::Rescue::Skip
+ end
end
end
end
diff --git a/app/models/katello/concerns/smart_proxy_extensions.rb b/app/models/katello/concerns/smart_proxy_extensions.rb
index 8ba281c460e..c6c2e218f8e 100644
--- a/app/models/katello/concerns/smart_proxy_extensions.rb
+++ b/app/models/katello/concerns/smart_proxy_extensions.rb
@@ -122,7 +122,7 @@ def alternate_content_sources
end
def update_content_counts!
- # {:content_view_versions=>{87=>{:repositories=>{1=>{:rpms=>98, :module_streams=>9898}}}}}
+ # {:content_view_versions=>{87=>{:repositories=>{1=>{:metadata=>{},:counts=>{:rpms=>98, :module_streams=>9898}}}}}
new_content_counts = { content_view_versions: {} }
smart_proxy_helper = ::Katello::SmartProxyHelper.new(self)
repos = smart_proxy_helper.repositories_available_to_capsule
@@ -131,24 +131,30 @@ def update_content_counts!
repos.each do |repo|
repo_mirror_service = repo.backend_service(self).with_mirror_adapter
repo_content_counts = repo_mirror_service.latest_content_counts
- translated_counts = {}
- repo_content_counts.each do |name, count|
+ translated_counts = {metadata: {}, counts: {}}
+ translated_counts[:metadata] = {
+ env_id: repo.environment_id,
+ library_instance_id: repo.library_instance_or_self.id,
+ product_id: repo.product_id,
+ content_type: repo.content_type
+ }
+ repo_content_counts&.each do |name, count|
count = count[:count]
# Some content units in Pulp have the same model
if name == 'rpm.package' && repo.content_counts['srpm'] > 0
- translated_counts['srpm'] = repo_mirror_service.count_by_pulpcore_type(::Katello::Pulp3::Srpm)
- translated_counts['rpm'] = count - translated_counts['srpm']
+ translated_counts[:counts]['srpm'] = repo_mirror_service.count_by_pulpcore_type(::Katello::Pulp3::Srpm)
+ translated_counts[:counts]['rpm'] = count - translated_counts[:counts]['srpm']
elsif name == 'container.manifest' && repo.content_counts['docker_manifest_list'] > 0
- translated_counts['docker_manifest_list'] = repo_mirror_service.count_by_pulpcore_type(::Katello::Pulp3::DockerManifestList)
- translated_counts['docker_manifest'] = count - translated_counts['docker_manifest_list']
+ translated_counts[:counts]['docker_manifest_list'] = repo_mirror_service.count_by_pulpcore_type(::Katello::Pulp3::DockerManifestList)
+ translated_counts[:counts]['docker_manifest'] = count - translated_counts[:counts]['docker_manifest_list']
else
- translated_counts[::Katello::Pulp3::PulpContentUnit.katello_name_from_pulpcore_name(name, repo)] = count
+ translated_counts[:counts][::Katello::Pulp3::PulpContentUnit.katello_name_from_pulpcore_name(name, repo)] = count
end
end
new_content_counts[:content_view_versions][repo.content_view_version_id] ||= { repositories: {}}
# Store counts on capsule of archived repos which are reused across environment copies
# of the archived repo corresponding to each environment CV version is promoted to.
- new_content_counts[:content_view_versions][repo.content_view_version_id][:repositories][repo.content_view_version.archived_repos.find_by(library_instance_id: repo.library_instance_id)&.id] = translated_counts
+ new_content_counts[:content_view_versions][repo.content_view_version_id][:repositories][repo.id] = translated_counts
end
update(content_counts: new_content_counts)
end
@@ -424,10 +430,12 @@ def last_sync_audit
Audited::Audit.where(:auditable_id => self, :auditable_type => SmartProxy.name, action: "sync capsule").order(:created_at).last
end
- def last_sync_time
- task = sync_tasks.where.not(:ended_at => nil).where(:result => 'success').order(:ended_at).last
+ def last_sync_task
+ sync_tasks.where.not(:ended_at => nil).where(:result => 'success').order(:ended_at).last
+ end
- task&.ended_at || last_sync_audit&.created_at&.to_s
+ def last_sync_time
+ last_sync_task&.ended_at || last_sync_audit&.created_at&.to_s
end
def environment_syncable?(env)
diff --git a/app/services/katello/pulp3/repository_mirror.rb b/app/services/katello/pulp3/repository_mirror.rb
index 6164486d89e..5f01be34994 100644
--- a/app/services/katello/pulp3/repository_mirror.rb
+++ b/app/services/katello/pulp3/repository_mirror.rb
@@ -75,7 +75,7 @@ def fetch_repository
end
def version_href
- fetch_repository.latest_version_href
+ fetch_repository&.latest_version_href
end
def publication_href
@@ -225,7 +225,9 @@ def count_by_pulpcore_type(service_class)
end
def latest_content_counts
- api.repository_versions_api.read(version_href)&.content_summary&.present
+ version_pulp_href = version_href
+ return unless version_pulp_href
+ api.repository_versions_api.read(version_pulp_href)&.content_summary&.present
end
def pulp3_enabled_repo_types
diff --git a/app/views/foreman/smart_proxies/_content_tab.html.erb b/app/views/foreman/smart_proxies/_content_tab.html.erb
index 233c548d18f..c54de330c98 100644
--- a/app/views/foreman/smart_proxies/_content_tab.html.erb
+++ b/app/views/foreman/smart_proxies/_content_tab.html.erb
@@ -1,3 +1,3 @@
<%= javascript_include_tag *webpack_asset_paths('katello', extension: 'js') %>
<% @smartProxyId= @smart_proxy.id %>
-<%= react_component('Content', smartProxyId: @smartProxyId,) %>
+<%= react_component('Content', smartProxyId: @smartProxyId, organizationId: Organization.current&.id,) %>
diff --git a/app/views/katello/api/v2/capsule_content/sync_status.json.rabl b/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
index d93d10048b1..d4791c8cd27 100644
--- a/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
+++ b/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
@@ -1,6 +1,9 @@
object @capsule
attribute :last_sync_time
+node :last_sync_words do |_object|
+ @capsule&.last_sync_time ? time_ago_in_words(Time.parse(@capsule&.last_sync_time&.to_s)) : nil
+end
attribute :download_policy
@@ -15,6 +18,14 @@ child :last_failed_sync_tasks => :last_failed_sync_tasks do
extends 'foreman_tasks/api/tasks/show'
end
+child :last_sync_task => :last_sync_task do
+ extends 'foreman_tasks/api/tasks/show'
+end
+
+node :content_counts do
+ @capsule.content_counts
+end
+
child @lifecycle_environments => :lifecycle_environments do
extends 'katello/api/v2/common/identifier'
extends 'katello/api/v2/common/org_reference'
@@ -27,16 +38,17 @@ child @lifecycle_environments => :lifecycle_environments do
if @capsule.has_feature?(SmartProxy::PULP_NODE_FEATURE) || @capsule.has_feature?(SmartProxy::PULP3_FEATURE)
node :counts do |env|
{
- :content_views => env.content_views.non_default.count,
- :content_counts => @capsule.content_counts
+ :content_views => env.content_views.non_default.count
}
end
node :content_views do |env|
env.content_views.ignore_generated.map do |content_view|
+ cvv = ::Katello::ContentViewVersion.in_environment(env).find_by(:content_view => content_view)
attributes = {
:id => content_view.id,
- :cvv_id => ::Katello::ContentViewVersion.in_environment(env).find_by(:content_view => content_view)&.id,
+ :cvv_id => cvv&.id,
+ :cvv_version => cvv&.version,
:label => content_view.label,
:name => content_view.name,
:composite => content_view.composite,
@@ -50,7 +62,9 @@ child @lifecycle_environments => :lifecycle_environments do
{
:id => repo.id,
:name => repo.name,
- :library_id => repo.library_instance_id
+ :library_id => repo.library_instance_id,
+ :product_id => repo.product_id,
+ :content_type => repo.content_type
}
end
}
diff --git a/test/models/concerns/smart_proxy_extensions_test.rb b/test/models/concerns/smart_proxy_extensions_test.rb
index b8ff5cb3697..2000f82371f 100644
--- a/test/models/concerns/smart_proxy_extensions_test.rb
+++ b/test/models/concerns/smart_proxy_extensions_test.rb
@@ -95,21 +95,80 @@ def test_update_content_counts
python_service.expects(:latest_content_counts).once.returns(python_counts)
repos = [yum_repo, file_repo, ansible_repo, container_repo,
ostree_repo, deb_repo, python_repo]
- yum_repo.content_view_version.expects(:archived_repos).returns(::Katello::Repository.where(id: [yum_repo, file_repo, ansible_repo, container_repo,
- ostree_repo, deb_repo, python_repo]))
::Katello::SmartProxyHelper.any_instance.expects(:repositories_available_to_capsule).once.returns(repos)
@proxy.update_content_counts!
counts = @proxy.content_counts
expected_counts = { "content_view_versions" =>
{ yum_repo.content_view_version.id.to_s =>
{ "repositories" =>
- { yum_repo.id.to_s => { "erratum" => 4, "srpm" => 1, "rpm" => 31, "module_stream" => 7, "rpm.modulemd_defaults" => 3, "package_group" => 7, "rpm.packagecategory" => 1 },
- file_repo.id.to_s => { "file" => 100 },
- ansible_repo.id.to_s => { "ansible.collection" => 802 },
- container_repo.id.to_s => { "container.blob" => 30, "docker_manifest_list" => 1, "docker_manifest" => 9, "docker_tag" => 5 },
- ostree_repo.id.to_s => {"ostree_ref" => 30 },
- deb_repo.id.to_s => { "deb" => 987 },
- python_repo.id.to_s => { "python_package" => 42 }
+ { yum_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => yum_repo.environment.id,
+ "library_instance_id" => yum_repo.library_instance_or_self.id,
+ "product_id" => yum_repo.product_id,
+ "content_type" => yum_repo.content_type
+ },
+ "counts" => { "erratum" => 4, "srpm" => 1, "rpm" => 31, "module_stream" => 7, "rpm.modulemd_defaults" => 3, "package_group" => 7, "rpm.packagecategory" => 1 }
+ },
+ file_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => file_repo.environment.id,
+ "library_instance_id" => file_repo.library_instance_or_self.id,
+ "product_id" => file_repo.product_id,
+ "content_type" => file_repo.content_type
+ },
+ "counts" =>
+ { "file" => 100 }
+ },
+ ansible_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => ansible_repo.environment.id,
+ "library_instance_id" => ansible_repo.library_instance_or_self.id,
+ "product_id" => ansible_repo.product_id,
+ "content_type" => ansible_repo.content_type},
+ "counts" =>
+ { "ansible.collection" => 802 }
+ },
+ container_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => container_repo.environment.id,
+ "library_instance_id" => container_repo.library_instance_or_self.id,
+ "product_id" => container_repo.product_id,
+ "content_type" => container_repo.content_type
+ },
+ "counts" =>
+ { "container.blob" => 30, "docker_manifest_list" => 1, "docker_manifest" => 9, "docker_tag" => 5 }
+ },
+ ostree_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => ostree_repo.environment.id,
+ "library_instance_id" => ostree_repo.library_instance_or_self.id,
+ "product_id" => ostree_repo.product_id,
+ "content_type" => ostree_repo.content_type
+ },
+ "counts" =>
+ {"ostree_ref" => 30 }
+ },
+ deb_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => deb_repo.environment.id,
+ "library_instance_id" => deb_repo.library_instance_or_self.id,
+ "product_id" => deb_repo.product_id,
+ "content_type" => deb_repo.content_type
+ },
+ "counts" =>
+ { "deb" => 987 }
+ },
+ python_repo.id.to_s => {
+ "metadata" => {
+ "env_id" => python_repo.environment.id,
+ "library_instance_id" => python_repo.library_instance_or_self.id,
+ "product_id" => python_repo.product_id,
+ "content_type" => python_repo.content_type
+ },
+ "counts" =>
+ { "python_package" => 42 }
+ }
}
}
}
diff --git a/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js b/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js
index 8da108f3f6d..30a47cb6692 100644
--- a/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js
+++ b/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js
@@ -1,6 +1,6 @@
import React from 'react';
import { Tooltip } from '@patternfly/react-core';
-import { BundleIcon, MiddlewareIcon, BoxIcon, CodeBranchIcon, FanIcon, TenantIcon } from '@patternfly/react-icons';
+import { BundleIcon, MiddlewareIcon, BoxIcon, CodeBranchIcon, FanIcon, TenantIcon, AnsibleTowerIcon } from '@patternfly/react-icons';
import PropTypes from 'prop-types';
const RepoIcon = ({ type }) => {
@@ -10,6 +10,7 @@ const RepoIcon = ({ type }) => {
ostree: CodeBranchIcon,
file: TenantIcon,
deb: FanIcon,
+ ansible_collection: AnsibleTowerIcon,
};
const Icon = iconMap[type] || BoxIcon;
diff --git a/webpack/scenes/SmartProxy/Content.js b/webpack/scenes/SmartProxy/Content.js
index 57c096d0cd1..0d838c4c0d9 100644
--- a/webpack/scenes/SmartProxy/Content.js
+++ b/webpack/scenes/SmartProxy/Content.js
@@ -2,16 +2,24 @@ import React from 'react';
import PropTypes from 'prop-types';
import SmartProxyExpandableTable from './SmartProxyExpandableTable';
-const Content = ({ smartProxyId }) => (
-
+const Content = ({ smartProxyId, organizationId }) => (
+
);
Content.propTypes = {
- smartProxyId: PropTypes.number,
+ smartProxyId: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string, // The API can sometimes return strings
+ ]),
+ organizationId: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string, // The API can sometimes return strings
+ ]),
};
Content.defaultProps = {
smartProxyId: null,
+ organizationId: null,
};
export default Content;
diff --git a/webpack/scenes/SmartProxy/ExpandableCvDetails.js b/webpack/scenes/SmartProxy/ExpandableCvDetails.js
index 31a63adc64e..fcfe8425310 100644
--- a/webpack/scenes/SmartProxy/ExpandableCvDetails.js
+++ b/webpack/scenes/SmartProxy/ExpandableCvDetails.js
@@ -9,13 +9,14 @@ import ContentViewIcon from '../ContentViews/components/ContentViewIcon';
import { useSet } from '../../components/Table/TableHooks';
import ExpandedSmartProxyRepositories from './ExpandedSmartProxyRepositories';
-const ExpandableCvDetails = ({ contentViews, counts }) => {
+const ExpandableCvDetails = ({ contentViews, contentCounts, envId }) => {
const columnHeaders = [
__('Content view'),
+ __('Version'),
__('Last published'),
- __('Synced to smart proxy'),
+ __('Synced'),
];
- const { content_counts: contentCounts } = counts;
+ // const { content_counts: contentCounts } = counts;
const expandedTableRows = useSet([]);
const tableRowIsExpanded = id => expandedTableRows.has(id);
@@ -38,18 +39,22 @@ const ExpandableCvDetails = ({ contentViews, counts }) => {
{contentViews.map((cv, rowIndex) => {
const {
- id, name: cvName, composite, up_to_date: upToDate, cvv_id: version, repositories,
+ id, name: cvName, composite, up_to_date: upToDate,
+ cvv_id: versionId, cvv_version: version, repositories,
} = cv;
- const upToDateVal = upToDate ? : ;
- const isExpanded = tableRowIsExpanded(version);
+ const upToDateVal = upToDate ? : ;
+ const isExpanded = tableRowIsExpanded(versionId);
return (
-
-
+
+
expandedTableRows.onToggle(isOpen, version),
+ onToggle: (_event, _rInx, isOpen) =>
+ expandedTableRows.onToggle(isOpen, versionId),
}}
/>
|
@@ -58,14 +63,19 @@ const ExpandableCvDetails = ({ contentViews, counts }) => {
description={{cvName}}
/>
|
+
+ {__('Version ')}{version}
+ |
|
{upToDateVal} |
|
@@ -80,16 +90,18 @@ const ExpandableCvDetails = ({ contentViews, counts }) => {
ExpandableCvDetails.propTypes = {
contentViews: PropTypes.arrayOf(PropTypes.shape({})),
- counts: PropTypes.shape({
- content_counts: PropTypes.shape({
- content_view_versions: PropTypes.shape({}),
- }),
+ contentCounts: PropTypes.shape({
+ content_view_versions: PropTypes.shape({}),
}),
+ envId: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string, // The API can sometimes return strings
+ ]).isRequired,
};
ExpandableCvDetails.defaultProps = {
contentViews: [],
- counts: {},
+ contentCounts: {},
};
export default ExpandableCvDetails;
diff --git a/webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js b/webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js
index c7ef1520f6a..745825c975e 100644
--- a/webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js
+++ b/webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js
@@ -4,53 +4,136 @@ import PropTypes from 'prop-types';
import { translate as __ } from 'foremanReact/common/I18n';
import { DataList, DataListItem, DataListItemRow, DataListItemCells, DataListCell } from '@patternfly/react-core';
import AdditionalCapsuleContent from './AdditionalCapsuleContent';
+import InactiveText from '../ContentViews/components/InactiveText';
+import RepoIcon from '../ContentViews/Details/Repositories/RepoIcon';
+
+const ExpandedSmartProxyRepositories = ({
+ contentCounts, repositories, syncedToCapsule, envId,
+}) => {
+ const filterDataByEnvId = () => {
+ const filteredData = {};
+
+ Object.keys(contentCounts).forEach((key) => {
+ const entry = contentCounts[key];
+ if (entry.metadata.env_id === envId) {
+ filteredData[key] = entry;
+ }
+ });
+
+ return filteredData;
+ };
+ const envContentCounts = filterDataByEnvId();
-const ExpandedSmartProxyRepositories = ({ contentCounts, repositories }) => {
const getRepositoryNameById = id => (repositories.find(repo =>
- Number(repo.id) === Number(id)) || {}).name;
+ Number(repo.id) === Number(id) || Number(repo.library_id) === Number(id)) || {}).name;
+
+ const dataListCellLists = (repoCounts, repo) => {
+ const cellList = [];
+ /* eslint-disable max-len */
+ cellList.push({getRepositoryNameById(envContentCounts[repo].metadata.library_instance_id)});
+ cellList.push();
+ cellList.push({envContentCounts[repo].counts.rpm ? `${envContentCounts[repo].counts.rpm} Packages` : 'N/A'});
+ cellList.push();
+ /* eslint-enable max-len */
+ return cellList;
+ };
- const dataListCellLists = (repo) => {
+ const dataListCellListsNotSynced = (repo) => {
const cellList = [];
/* eslint-disable max-len */
- cellList.push({getRepositoryNameById(repo)});
- cellList.push({contentCounts[repo].rpm ? `${contentCounts[repo].rpm} Packages` : 'N/A'});
- cellList.push();
+ cellList.push({repo.name});
+ cellList.push();
+ cellList.push();
+ cellList.push();
/* eslint-enable max-len */
return cellList;
};
+ if (syncedToCapsule) {
+ return (
+
+ );
+ }
+
return (
- );
+ }
+ );
};
ExpandedSmartProxyRepositories.propTypes = {
contentCounts: PropTypes.shape({}),
repositories: PropTypes.arrayOf(PropTypes.shape({})),
+ syncedToCapsule: PropTypes.bool,
+ envId: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string, // The API can sometimes return strings
+ ]).isRequired,
};
ExpandedSmartProxyRepositories.defaultProps = {
contentCounts: {},
repositories: [{}],
+ syncedToCapsule: false,
};
export default ExpandedSmartProxyRepositories;
diff --git a/webpack/scenes/SmartProxy/SmartProxyContentActions.js b/webpack/scenes/SmartProxy/SmartProxyContentActions.js
index 00e21e3b357..a9a4b103ab9 100644
--- a/webpack/scenes/SmartProxy/SmartProxyContentActions.js
+++ b/webpack/scenes/SmartProxy/SmartProxyContentActions.js
@@ -1,11 +1,14 @@
-import { API_OPERATIONS, get } from 'foremanReact/redux/API';
+import { API_OPERATIONS, get, post } from 'foremanReact/redux/API';
+import { translate as __ } from 'foremanReact/common/I18n';
import api, { foremanApi, orgId } from '../../services/api';
-import SMART_PROXY_CONTENT_KEY, { SMART_PROXY_KEY } from './SmartProxyContentConstants';
+import SMART_PROXY_CONTENT_KEY, { SMART_PROXY_COUNTS_UPDATE_KEY, SMART_PROXY_KEY } from './SmartProxyContentConstants';
+import { renderTaskStartedToast } from '../Tasks/helpers';
+import { getResponseErrorMsgs } from '../../utils/helpers';
-const getSmartProxyContent = ({ smartProxyId }) => get({
+const getSmartProxyContent = ({ smartProxyId, organizationId }) => get({
type: API_OPERATIONS.GET,
key: SMART_PROXY_CONTENT_KEY,
- url: api.getApiUrl(`/capsules/${smartProxyId}/content/sync?${orgId()}`),
+ url: api.getApiUrl(organizationId ? `/capsules/${smartProxyId}/content/sync?organization_id=${organizationId}` : `/capsules/${smartProxyId}/content/sync`),
});
export const getSmartProxies = () => get({
@@ -15,4 +18,14 @@ export const getSmartProxies = () => get({
params: { organization_id: orgId(), per_page: 'all' },
});
+export const updateSmartProxyContentCounts = smartProxyId => post({
+ type: API_OPERATIONS.POST,
+ key: SMART_PROXY_COUNTS_UPDATE_KEY,
+ url: api.getApiUrl(`/capsules/${smartProxyId}/content/update_counts`),
+ handleSuccess: (response) => {
+ renderTaskStartedToast(response?.data, __('Smart proxy content count refresh has started in the background'));
+ },
+ errorToast: error => __(`Something went wrong while refreshing content counts: ${getResponseErrorMsgs(error.response)}`),
+});
+
export default getSmartProxyContent;
diff --git a/webpack/scenes/SmartProxy/SmartProxyContentConstants.js b/webpack/scenes/SmartProxy/SmartProxyContentConstants.js
index 5db4da1414e..14bc5c92630 100644
--- a/webpack/scenes/SmartProxy/SmartProxyContentConstants.js
+++ b/webpack/scenes/SmartProxy/SmartProxyContentConstants.js
@@ -1,3 +1,4 @@
const SMART_PROXY_CONTENT_KEY = 'SMART_PROXY_CONTENT';
export const SMART_PROXY_KEY = 'SMART_PROXY';
+export const SMART_PROXY_COUNTS_UPDATE_KEY = 'SMART_PROXY_COUNTS_UPDATE_KEY';
export default SMART_PROXY_CONTENT_KEY;
diff --git a/webpack/scenes/SmartProxy/SmartProxyContentTable.js b/webpack/scenes/SmartProxy/SmartProxyContentTable.js
deleted file mode 100644
index 0fec8661b63..00000000000
--- a/webpack/scenes/SmartProxy/SmartProxyContentTable.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import useDeepCompareEffect from 'use-deep-compare-effect';
-import PropTypes from 'prop-types';
-import { useSelector, useDispatch } from 'react-redux';
-import { wrappable } from '@patternfly/react-table';
-import { CheckCircleIcon, TimesCircleIcon } from '@patternfly/react-icons';
-import { STATUS } from 'foremanReact/constants';
-import { translate as __ } from 'foremanReact/common/I18n';
-import { urlBuilder } from 'foremanReact/common/urlHelpers';
-import LongDateTime from 'foremanReact/components/common/dates/LongDateTime';
-import MainTable from '../../components/Table/MainTable';
-import getSmartProxyContent from './SmartProxyContentActions';
-import ContentViewIcon from '../../scenes/ContentViews/components/ContentViewIcon';
-import {
- selectSmartProxyContent,
- selectSmartProxyContentStatus,
- selectSmartProxyContentError,
-} from './SmartProxyContentSelectors';
-
-const SmartProxyContentTable = ({ smartProxyId }) => {
- const dispatch = useDispatch();
- const [rows, setRows] = useState([]);
- const response = useSelector(state => selectSmartProxyContent(state));
- const status = useSelector(state => selectSmartProxyContentStatus(state));
- const error = useSelector(state => selectSmartProxyContentError(state));
- const columnHeaders = [
- {
- title: __('Environment'),
- transforms: [wrappable],
- },
- {
- title: __('Content view'),
- transforms: [wrappable],
- },
- {
- title: __('Type'),
- transforms: [wrappable],
- },
- {
- title: __('Last published'),
- transforms: [wrappable],
- },
- {
- title: __('Repositories'),
- transforms: [wrappable],
- },
- {
- title: __('Synced to smart proxy'),
- transforms: [wrappable],
- },
- ];
-
- const buildrows = (results) => {
- const newRows = [];
- let envCount = 0;
- results.forEach((env) => {
- const { name, content_views: contentViews } = env;
- const cellEnv = {
- isOpen: false,
- cells: [name, null, null, null, null, null],
- };
- newRows.push(cellEnv);
- contentViews.forEach((cv) => {
- const {
- id, name: cvName, composite, last_published: lastPublished, up_to_date: upToDate, counts,
- } = cv;
- const { repositories } = counts;
- const cvType = ;
- const upToDateVal = upToDate ? : ;
- const cellCv =
- {
- parent: envCount,
- cells: [
- {
- title: null,
- props: {
- colSpan: 1,
- },
- },
- {
- title: {cvName},
- props: {
- colSpan: 1,
- },
- },
- {
- title: cvType,
- props: {
- colSpan: 1,
- },
- },
- {
- title: ,
- props: {
- colSpan: 1,
- },
- },
- {
- title: repositories,
- props: {
- colSpan: 1,
- },
- },
- {
- title: upToDateVal,
- props: {
- colSpan: 1,
- },
- },
- ],
- };
- newRows.push(cellCv);
- });
- envCount = newRows.length;
- });
- return newRows;
- };
-
- const onCollapse = (row, setRow) => (event, rowKey, isOpen) => {
- const newRows = [...row];
- newRows[rowKey].isOpen = isOpen;
- setRow(newRows);
- };
-
- useEffect(
- () => {
- dispatch(getSmartProxyContent({ smartProxyId }));
- }
- , [dispatch, smartProxyId],
- );
-
- useDeepCompareEffect(() => {
- if (status !== STATUS.PENDING && response) {
- const { lifecycle_environments: env } = response;
- setRows(buildrows(env));
- }
- }, [response, status, error]);
-
-
- return (
-
- );
-};
-
-SmartProxyContentTable.propTypes = {
- smartProxyId: PropTypes.number,
-};
-
-SmartProxyContentTable.defaultProps = {
- smartProxyId: null,
-};
-
-export default SmartProxyContentTable;
diff --git a/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js b/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js
index e90663acf60..6da2412b3a2 100644
--- a/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js
+++ b/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js
@@ -1,9 +1,9 @@
import React, { useState, useCallback } from 'react';
-import { useSelector } from 'react-redux';
+import { useSelector, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import { translate as __ } from 'foremanReact/common/I18n';
import { Thead, Tbody, Th, Tr, Td } from '@patternfly/react-table';
-import getSmartProxyContent from './SmartProxyContentActions';
+import getSmartProxyContent, { updateSmartProxyContentCounts } from './SmartProxyContentActions';
import {
selectSmartProxyContent,
selectSmartProxyContentStatus,
@@ -12,25 +12,40 @@ import {
import { useSet } from '../../components/Table/TableHooks';
import TableWrapper from '../../components/Table/TableWrapper';
import ExpandableCvDetails from './ExpandableCvDetails';
+import ComponentEnvironments from '../ContentViews/Details/ComponentContentViews/ComponentEnvironments';
+import LastSync from '../ContentViews/Details/Repositories/LastSync';
-const SmartProxyExpandableTable = ({ smartProxyId }) => {
+const SmartProxyExpandableTable = ({ smartProxyId, organizationId }) => {
const response = useSelector(selectSmartProxyContent);
const status = useSelector(selectSmartProxyContentStatus);
const error = useSelector(selectSmartProxyContentError);
const [searchQuery, updateSearchQuery] = useState('');
const expandedTableRows = useSet([]);
const tableRowIsExpanded = id => expandedTableRows.has(id);
+ const dispatch = useDispatch();
let metadata = {};
const {
- lifecycle_environments: results,
+ lifecycle_environments: results, last_sync_task: lastTask, last_sync_words: lastSyncWords,
+ content_counts: contentCounts,
} = response;
if (results) {
metadata = { total: results.length, subtotal: results.length };
}
const columnHeaders = [
__('Environment'),
+ __('Last sync'),
];
- const fetchItems = useCallback(() => getSmartProxyContent({ smartProxyId }), [smartProxyId]);
+
+ const refreshCountAction = {
+ title: __('Refresh counts'),
+ onClick: () => {
+ dispatch(updateSmartProxyContentCounts(smartProxyId));
+ },
+ };
+ const fetchItems = useCallback(
+ () => getSmartProxyContent({ smartProxyId, organizationId }),
+ [smartProxyId, organizationId],
+ );
const emptyContentTitle = __('No content views yet');
const emptyContentBody = __('You currently have no content views to display');
@@ -38,6 +53,7 @@ const SmartProxyExpandableTable = ({ smartProxyId }) => {
const emptySearchBody = __('Try changing your search settings.');
const alwaysHideToolbar = true;
const hidePagination = true;
+
return (
{
{col}
))}
+ |
{
- results?.map((env, rowIndex) => {
- const {
- name, id, content_views: contentViews, counts,
- } = env;
- const isExpanded = tableRowIsExpanded(id);
- return (
-
-
-
- expandedTableRows.onToggle(isOpen, id),
- }}
- />
- | {name} |
-
-
-
-
- |
-
-
- );
- })
- }
-
+ results?.map((env, rowIndex) => {
+ const {
+ id, content_views: contentViews,
+ } = env;
+ const isExpanded = tableRowIsExpanded(id);
+ return (
+
+
+
+ expandedTableRows.onToggle(isOpen, id),
+ }}
+ />
+ | |
+ |
+ |
+
+
+
+ {isExpanded ?
+ :
+ <>>}
+ |
+
+
+ );
+ })
+ }
+
);
};
@@ -106,6 +138,14 @@ SmartProxyExpandableTable.propTypes = {
PropTypes.number,
PropTypes.string, // The API can sometimes return strings
]).isRequired,
+ organizationId: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string, // The API can sometimes return strings
+ ]),
+};
+
+SmartProxyExpandableTable.defaultProps = {
+ organizationId: null,
};
export default SmartProxyExpandableTable;
diff --git a/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json b/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json
deleted file mode 100644
index 2260744198d..00000000000
--- a/webpack/scenes/SmartProxy/__tests__/SmartProxyContentResult.fixtures.json
+++ /dev/null
@@ -1,140 +0,0 @@
-{
- "last_sync_time": "2021-01-12 14:39:01 -0500",
- "active_sync_tasks": [],
- "last_failed_sync_tasks": [],
- "lifecycle_environments": [
- {
- "library": true,
- "id": 1,
- "name": "Library",
- "label": "Library",
- "description": null,
- "organization_id": 1,
- "organization": {
- "name": "Default Organization",
- "label": "Default_Organization",
- "id": 1
- },
- "syncable": false,
- "counts": {
- "content_hosts": 0,
- "content_views": 2,
- "products": 1
- },
- "content_views": [
- {
- "id": 1,
- "label": "Default_Organization_View",
- "name": "Default Organization View",
- "composite": false,
- "last_published": "2021-01-05 09:55:20 -0500",
- "default": true,
- "up_to_date": true,
- "counts": {
- "content_hosts": 0,
- "products": 1,
- "repositories": 2
- }
- },
- {
- "id": 2,
- "label": "cv1",
- "name": "cv1",
- "composite": false,
- "last_published": "2021-01-12 14:36:31 -0500",
- "default": false,
- "up_to_date": true,
- "counts": {
- "content_hosts": 0,
- "products": 1,
- "repositories": 1
- }
- },
- {
- "id": 3,
- "label": "cv2",
- "name": "cv2",
- "composite": false,
- "last_published": "2021-01-12 14:37:05 -0500",
- "default": false,
- "up_to_date": true,
- "counts": {
- "content_hosts": 0,
- "products": 1,
- "repositories": 1
- }
- }
- ]
- },
- {
- "library": false,
- "id": 2,
- "name": "dev",
- "label": "dev",
- "description": null,
- "organization_id": 1,
- "organization": {
- "name": "Default Organization",
- "label": "Default_Organization",
- "id": 1
- },
- "syncable": false,
- "counts": {
- "content_hosts": 0,
- "content_views": 1,
- "products": 1
- },
- "content_views": [
- {
- "id": 2,
- "label": "cv1",
- "name": "cv1",
- "composite": false,
- "last_published": "2021-01-12 14:36:31 -0500",
- "default": false,
- "up_to_date": true,
- "counts": {
- "content_hosts": 0,
- "products": 1,
- "repositories": 1
- }
- }
- ]
- },
- {
- "library": false,
- "id": 3,
- "name": "test",
- "label": "test",
- "description": null,
- "organization_id": 1,
- "organization": {
- "name": "Default Organization",
- "label": "Default_Organization",
- "id": 1
- },
- "syncable": true,
- "counts": {
- "content_hosts": 0,
- "content_views": 1,
- "products": 1
- },
- "content_views": [
- {
- "id": 2,
- "label": "cv1",
- "name": "cv1",
- "composite": false,
- "last_published": "2021-01-12 14:36:31 -0500",
- "default": false,
- "up_to_date": false,
- "counts": {
- "content_hosts": 0,
- "products": 1,
- "repositories": 0
- }
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.fixtures.json b/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.fixtures.json
new file mode 100644
index 00000000000..6d24c7ed0f4
--- /dev/null
+++ b/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.fixtures.json
@@ -0,0 +1,799 @@
+{
+ "last_sync_time": "2023-10-23 09:52:53 -0400",
+ "download_policy": "on_demand",
+ "active_sync_tasks": [],
+ "last_failed_sync_tasks": [],
+ "last_sync_task": {
+ "id": "d32ad89d-f37b-44d3-9bb0-e64f6758df3e",
+ "label": "Actions::Katello::CapsuleContent::Sync",
+ "pending": false,
+ "action": "Synchronize smart proxy 'centos8-proxy-devel2.sajha.example.com'",
+ "username": "admin",
+ "started_at": "2023-10-23 09:52:25 -0400",
+ "ended_at": "2023-10-23 09:52:53 -0400",
+ "state": "stopped",
+ "result": "success",
+ "progress": 1,
+ "input": {
+ "options": {
+ "content_view_id": 12,
+ "environment_id": 4
+ },
+ "smart_proxy": {
+ "id": 2,
+ "name": "centos8-proxy-devel2.sajha.example.com"
+ },
+ "services_checked": [
+ "pulp3"
+ ],
+ "smart_proxy_id": 2,
+ "locale": "en",
+ "current_request_id": "a5e3fd5b-daa9-4381-8273-077793a006ec",
+ "current_timezone": "America/New_York",
+ "current_organization_id": 1,
+ "current_location_id": 2,
+ "current_user_id": 4
+ },
+ "output": {},
+ "humanized": {
+ "action": "Synchronize smart proxy",
+ "input": [
+ "'centos8-proxy-devel2.sajha.example.com'"
+ ],
+ "output": "",
+ "errors": []
+ },
+ "cli_example": null,
+ "start_at": "2023-10-23 09:52:25 -0400",
+ "available_actions": {
+ "cancellable": false,
+ "resumable": false
+ }
+ },
+ "lifecycle_environments": [
+ {
+ "library": true,
+ "id": 1,
+ "name": "Library",
+ "label": "Library",
+ "description": null,
+ "organization_id": 1,
+ "organization": {
+ "name": "Default Organization",
+ "label": "Default_Organization",
+ "id": 1
+ },
+ "syncable": false,
+ "counts": {
+ "content_views": 3
+ },
+ "content_views": [
+ {
+ "id": 1,
+ "cvv_id": 1,
+ "cvv_version": "1.0",
+ "label": "Default_Organization_View",
+ "name": "Default Organization View",
+ "composite": false,
+ "last_published": "2023-08-22 14:50:34 -0400",
+ "default": true,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 7
+ },
+ "repositories": [
+ {
+ "id": 3,
+ "name": "test_ansible",
+ "library_id": null
+ },
+ {
+ "id": 20,
+ "name": "Advanced Virtualization CodeReady Builder for RHEL 8 Power little endian RPMs",
+ "library_id": null
+ },
+ {
+ "id": 1,
+ "name": "repo1",
+ "library_id": null
+ },
+ {
+ "id": 16,
+ "name": "file_repo",
+ "library_id": null
+ },
+ {
+ "id": 40,
+ "name": "python-pulp",
+ "library_id": null
+ },
+ {
+ "id": 71,
+ "name": "Advanced Virtualization CodeReady Builder for RHEL 8 IBM z Systems RPMs",
+ "library_id": null
+ },
+ {
+ "id": 72,
+ "name": "deb_test",
+ "library_id": null
+ }
+ ]
+ },
+ {
+ "id": 12,
+ "cvv_id": 30,
+ "cvv_version": "2.0",
+ "label": "cv1",
+ "name": "cv1",
+ "composite": false,
+ "last_published": "2023-10-23 09:52:08 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 2
+ },
+ "repositories": [
+ {
+ "id": 171,
+ "name": "python-pulp",
+ "library_id": 40
+ },
+ {
+ "id": 170,
+ "name": "repo1",
+ "library_id": 1
+ }
+ ]
+ },
+ {
+ "id": 13,
+ "cvv_id": 29,
+ "cvv_version": "2.0",
+ "label": "cv2",
+ "name": "cv2",
+ "composite": false,
+ "last_published": "2023-10-23 09:48:16 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 5
+ },
+ "repositories": [
+ {
+ "id": 163,
+ "name": "python-pulp",
+ "library_id": 40
+ },
+ {
+ "id": 161,
+ "name": "repo1",
+ "library_id": 1
+ },
+ {
+ "id": 164,
+ "name": "deb_test",
+ "library_id": 72
+ },
+ {
+ "id": 160,
+ "name": "test_ansible",
+ "library_id": 3
+ },
+ {
+ "id": 162,
+ "name": "file_repo",
+ "library_id": 16
+ }
+ ]
+ },
+ {
+ "id": 14,
+ "cvv_id": 28,
+ "cvv_version": "1.0",
+ "label": "ccv1",
+ "name": "ccv1",
+ "composite": true,
+ "last_published": "2023-10-23 09:45:23 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 5
+ },
+ "repositories": [
+ {
+ "id": 146,
+ "name": "repo1",
+ "library_id": 1
+ },
+ {
+ "id": 147,
+ "name": "test_ansible",
+ "library_id": 3
+ },
+ {
+ "id": 149,
+ "name": "file_repo",
+ "library_id": 16
+ },
+ {
+ "id": 148,
+ "name": "deb_test",
+ "library_id": 72
+ },
+ {
+ "id": 145,
+ "name": "python-pulp",
+ "library_id": 40
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "library": false,
+ "id": 2,
+ "name": "dev",
+ "label": "dev",
+ "description": null,
+ "organization_id": 1,
+ "organization": {
+ "name": "Default Organization",
+ "label": "Default_Organization",
+ "id": 1
+ },
+ "syncable": false,
+ "counts": {
+ "content_views": 1
+ },
+ "content_views": [
+ {
+ "id": 12,
+ "cvv_id": 26,
+ "cvv_version": "1.0",
+ "label": "cv1",
+ "name": "cv1",
+ "composite": false,
+ "last_published": "2023-10-20 14:44:49 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 2
+ },
+ "repositories": [
+ {
+ "id": 130,
+ "name": "python-pulp",
+ "library_id": 40
+ },
+ {
+ "id": 129,
+ "name": "repo1",
+ "library_id": 1
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "library": false,
+ "id": 4,
+ "name": "qa",
+ "label": "qa",
+ "description": null,
+ "organization_id": 1,
+ "organization": {
+ "name": "Default Organization",
+ "label": "Default_Organization",
+ "id": 1
+ },
+ "syncable": false,
+ "counts": {
+ "content_views": 3
+ },
+ "content_views": [
+ {
+ "id": 12,
+ "cvv_id": 30,
+ "cvv_version": "2.0",
+ "label": "cv1",
+ "name": "cv1",
+ "composite": false,
+ "last_published": "2023-10-23 09:52:08 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 2
+ },
+ "repositories": [
+ {
+ "id": 171,
+ "name": "python-pulp",
+ "library_id": 40
+ },
+ {
+ "id": 170,
+ "name": "repo1",
+ "library_id": 1
+ }
+ ]
+ },
+ {
+ "id": 13,
+ "cvv_id": 29,
+ "cvv_version": "2.0",
+ "label": "cv2",
+ "name": "cv2",
+ "composite": false,
+ "last_published": "2023-10-23 09:48:16 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 5
+ },
+ "repositories": [
+ {
+ "id": 163,
+ "name": "python-pulp",
+ "library_id": 40
+ },
+ {
+ "id": 161,
+ "name": "repo1",
+ "library_id": 1
+ },
+ {
+ "id": 164,
+ "name": "deb_test",
+ "library_id": 72
+ },
+ {
+ "id": 160,
+ "name": "test_ansible",
+ "library_id": 3
+ },
+ {
+ "id": 162,
+ "name": "file_repo",
+ "library_id": 16
+ }
+ ]
+ },
+ {
+ "id": 14,
+ "cvv_id": 28,
+ "cvv_version": "1.0",
+ "label": "ccv1",
+ "name": "ccv1",
+ "composite": true,
+ "last_published": "2023-10-23 09:45:23 -0400",
+ "default": false,
+ "up_to_date": true,
+ "counts": {
+ "repositories": 5
+ },
+ "repositories": [
+ {
+ "id": 146,
+ "name": "repo1",
+ "library_id": 1
+ },
+ {
+ "id": 147,
+ "name": "test_ansible",
+ "library_id": 3
+ },
+ {
+ "id": 149,
+ "name": "file_repo",
+ "library_id": 16
+ },
+ {
+ "id": 148,
+ "name": "deb_test",
+ "library_id": 72
+ },
+ {
+ "id": 145,
+ "name": "python-pulp",
+ "library_id": 40
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "last_sync_words": "3 minutes",
+ "unsyncable_content_types": [],
+ "content_counts": {
+ "content_view_versions": {
+ "1": {
+ "repositories": {
+ "1": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 1
+ }
+ },
+ "3": {
+ "counts": {
+ "ansible_collection": 10
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 3
+ }
+ },
+ "16": {
+ "counts": {
+ "file": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 16
+ }
+ },
+ "20": {
+ "counts": {
+ "rpm": 71,
+ "erratum": 31,
+ "rpm.modulemd": 31,
+ "rpm.repo_metadata_file": 1
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 20
+ }
+ },
+ "40": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 40
+ }
+ },
+ "71": {
+ "counts": {},
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 71
+ }
+ },
+ "72": {
+ "counts": {
+ "deb": 6,
+ "deb.release": 2,
+ "deb.release_file": 2,
+ "deb.package_index": 5,
+ "deb.release_component": 2,
+ "deb.release_architecture": 5,
+ "deb.package_release_component": 6
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 72
+ }
+ }
+ }
+ },
+ "26": {
+ "repositories": {
+ "133": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 2,
+ "library_instance_id": 1
+ }
+ },
+ "134": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 2,
+ "library_instance_id": 40
+ }
+ }
+ }
+ },
+ "28": {
+ "repositories": {
+ "150": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 40
+ }
+ },
+ "151": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 1
+ }
+ },
+ "152": {
+ "counts": {
+ "ansible_collection": 10
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 3
+ }
+ },
+ "153": {
+ "counts": {
+ "deb": 6,
+ "deb.release": 2,
+ "deb.release_file": 2,
+ "deb.package_index": 5,
+ "deb.release_component": 2,
+ "deb.release_architecture": 5,
+ "deb.package_release_component": 6
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 72
+ }
+ },
+ "154": {
+ "counts": {
+ "file": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 16
+ }
+ },
+ "155": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 40
+ }
+ },
+ "156": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 1
+ }
+ },
+ "157": {
+ "counts": {
+ "ansible_collection": 10
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 3
+ }
+ },
+ "158": {
+ "counts": {
+ "deb": 6,
+ "deb.release": 2,
+ "deb.release_file": 2,
+ "deb.package_index": 5,
+ "deb.release_component": 2,
+ "deb.release_architecture": 5,
+ "deb.package_release_component": 6
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 72
+ }
+ },
+ "159": {
+ "counts": {
+ "file": 3
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 16
+ }
+ }
+ }
+ },
+ "29": {
+ "repositories": {
+ "140": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 1
+ }
+ },
+ "141": {
+ "counts": {
+ "ansible_collection": 10
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 3
+ }
+ },
+ "142": {
+ "counts": {
+ "file": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 16
+ }
+ },
+ "143": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 40
+ }
+ },
+ "144": {
+ "counts": {
+ "deb": 6,
+ "deb.release": 2,
+ "deb.release_file": 2,
+ "deb.package_index": 5,
+ "deb.release_component": 2,
+ "deb.release_architecture": 5,
+ "deb.package_release_component": 6
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 72
+ }
+ },
+ "165": {
+ "counts": {
+ "ansible_collection": 10
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 3
+ }
+ },
+ "166": {
+ "counts": {
+ "rpm": 22,
+ "erratum": 7,
+ "rpm.modulemd": 14,
+ "package_group": 2,
+ "rpm.packagecategory": 1,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 1
+ }
+ },
+ "167": {
+ "counts": {
+ "file": 3
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 16
+ }
+ },
+ "168": {
+ "counts": {
+ "python_package": 275
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 40
+ }
+ },
+ "169": {
+ "counts": {
+ "deb": 6,
+ "deb.release": 2,
+ "deb.release_file": 2,
+ "deb.package_index": 5,
+ "deb.release_component": 2,
+ "deb.release_architecture": 5,
+ "deb.package_release_component": 6
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 72
+ }
+ }
+ }
+ },
+ "30": {
+ "repositories": {
+ "131": {
+ "counts": {
+ "rpm": 14,
+ "erratum": 6,
+ "rpm.modulemd": 14,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 1
+ }
+ },
+ "132": {
+ "counts": {},
+ "metadata": {
+ "env_id": 1,
+ "library_instance_id": 40
+ }
+ },
+ "172": {
+ "counts": {
+ "rpm": 14,
+ "erratum": 6,
+ "rpm.modulemd": 14,
+ "rpm.distribution_tree": 1,
+ "rpm.modulemd_defaults": 3
+ },
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 1
+ }
+ },
+ "173": {
+ "counts": {},
+ "metadata": {
+ "env_id": 4,
+ "library_instance_id": 40
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js b/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js
index 58a7c4e97bb..61b3d9ed82c 100644
--- a/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js
+++ b/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js
@@ -1,11 +1,11 @@
import React from 'react';
-import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
+import { renderWithRedux, patientlyWaitFor, within } from 'react-testing-lib-wrapper';
import { nockInstance, assertNockRequest } from '../../../test-utils/nockWrapper';
import api from '../../../services/api';
import SmartProxyExpandableTable from '../SmartProxyExpandableTable';
-const smartProxyContentData = require('./SmartProxyContentResult.fixtures.json');
+const smartProxyContentData = require('./SmartProxyContentTest.fixtures.json');
const smartProxyContentPath = api.getApiUrl('/capsules/1/content/sync');
@@ -13,25 +13,38 @@ const smartProxyContent = { ...smartProxyContentData };
const contentTable = ;
-test('Can display Smart proxy content table', async (done) => {
+test('Can display Smart proxy content table and expand env and cv details', async (done) => {
const detailsScope = nockInstance
.get(smartProxyContentPath)
.query(true)
.reply(200, smartProxyContent);
- const { getByText, getAllByText, getAllByLabelText } = renderWithRedux(contentTable);
+ const {
+ getByText, getAllByText, getByLabelText,
+ } = renderWithRedux(contentTable);
await patientlyWaitFor(() => expect(getByText('Environment')).toBeInTheDocument());
- expect(getAllByText('Content view')[0]).toBeInTheDocument();
+ const tdEnvExpand = getByLabelText('expand-env-1');
+ const envExpansion = within(tdEnvExpand).getByLabelText('Details');
+ envExpansion.click();
+ await patientlyWaitFor(() => expect(getAllByText('Content view')[0]).toBeInTheDocument());
expect(getAllByText('Last published')[0]).toBeInTheDocument();
- expect(getAllByText('Repositories')[0]).toBeInTheDocument();
- expect(getAllByText('Synced to smart proxy')[0]).toBeInTheDocument();
- expect(getAllByLabelText('Details')[0]).toHaveAttribute('aria-expanded', 'false');
- getAllByLabelText('Details')[0].click();
- expect(getAllByLabelText('Details')[0]).toHaveAttribute('aria-expanded', 'true');
+ expect(getAllByText('Repository')[0]).toBeInTheDocument();
+ expect(getAllByText('Synced')[0]).toBeInTheDocument();
+ const tdCvExpand = getByLabelText('expand-cv-1');
+ const cvExpansion = within(tdCvExpand).getByLabelText('Details');
+ expect(cvExpansion).toHaveAttribute('aria-expanded', 'false');
+ cvExpansion.click();
+ await patientlyWaitFor(() => expect(cvExpansion).toHaveAttribute('aria-expanded', 'true'));
expect(getByText('Library')).toBeInTheDocument();
expect(getByText('Default Organization View')).toBeInTheDocument();
- expect(getByText('dev')).toBeInTheDocument();
-
-
+ expect(getAllByText('dev')[0]).toBeInTheDocument();
+ expect(getAllByText('Repository')[0]).toBeInTheDocument();
+ expect(getAllByText('Packages')[0]).toBeInTheDocument();
+ expect(getAllByText('Additional content')[0]).toBeInTheDocument();
+ expect(getAllByText('repo1')[0]).toBeInTheDocument();
+ expect(getAllByText('22 Packages')[0]).toBeInTheDocument();
+ expect(getAllByText(/7 errata/i)[0]).toBeInTheDocument();
+ expect(getAllByText(/14 Module streams/i)[0]).toBeInTheDocument();
+ expect(getAllByText(/2 Package groups/i)[0]).toBeInTheDocument();
assertNockRequest(detailsScope, done);
});