Skip to content

Commit

Permalink
Fixes #36807 - Update UI for metadata in content counts
Browse files Browse the repository at this point in the history
  • Loading branch information
sjha4 committed Oct 23, 2023
1 parent 82fc4db commit a5982ec
Show file tree
Hide file tree
Showing 12 changed files with 987 additions and 1,542 deletions.
7 changes: 6 additions & 1 deletion app/models/katello/concerns/smart_proxy_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,12 @@ def update_content_counts!
repo_mirror_service = repo.backend_service(self).with_mirror_adapter
repo_content_counts = repo_mirror_service.latest_content_counts
translated_counts = {metadata: {}, counts: {}}
translated_counts[:metadata] = {env_id: repo.environment_id, library_instance_id: repo.library_instance_or_self.id }
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
Expand Down
2 changes: 1 addition & 1 deletion app/views/foreman/smart_proxies/_content_tab.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<%= javascript_include_tag *webpack_asset_paths('katello', extension: 'js') %>
<% @smartProxyId= @smart_proxy.id %>
<%= react_component('Content', smartProxyId: @smartProxyId, organizationId: Organization.current.id,) %>
<%= react_component('Content', smartProxyId: @smartProxyId, organizationId: Organization.current&.id,) %>
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ child :last_sync_task => :last_sync_task do
end

node :content_counts do
@capsule.content_counts
@capsule.content_counts
end

child @lifecycle_environments => :lifecycle_environments do
Expand All @@ -38,7 +38,7 @@ 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_views => env.content_views.non_default.count
}
end

Expand All @@ -62,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
}
Expand Down
76 changes: 68 additions & 8 deletions test/models/concerns/smart_proxy_extensions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +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(:default?).returns(true)
::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, "rpm.modulemd" => 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 }
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js
Original file line number Diff line number Diff line change
@@ -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 }) => {
Expand All @@ -10,6 +10,7 @@ const RepoIcon = ({ type }) => {
ostree: CodeBranchIcon,
file: TenantIcon,
deb: FanIcon,
ansible_collection: AnsibleTowerIcon,
};
const Icon = iconMap[type] || BoxIcon;

Expand Down
17 changes: 10 additions & 7 deletions webpack/scenes/SmartProxy/ExpandableCvDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +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'),
];
const { content_counts: contentCounts } = counts;
// const { content_counts: contentCounts } = counts;
const expandedTableRows = useSet([]);
const tableRowIsExpanded = id => expandedTableRows.has(id);

Expand Down Expand Up @@ -75,6 +75,7 @@ const ExpandableCvDetails = ({ contentViews, counts }) => {
contentCounts={contentCounts?.content_view_versions[versionId]?.repositories}
repositories={repositories}
syncedToCapsule={upToDate}
envId={envId}
/>
</Td>
</Tr>
Expand All @@ -89,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;
104 changes: 87 additions & 17 deletions webpack/scenes/SmartProxy/ExpandedSmartProxyRepositories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,87 @@ 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, syncedToCapsule }) => {
const getRepositoryNameById = id => (repositories.find(repo =>
Number(repo.id) === Number(id)) || {}).name;
const dataListCellLists = (repo) => {
Number(repo.id) === Number(id) || Number(repo.library_id) === Number(id)) || {}).name;

const dataListCellLists = (repoCounts, repo) => {
const cellList = [];
/* eslint-disable max-len */
if (syncedToCapsule) {
cellList.push(<DataListCell key={`${repo.id}-name`}><span>{getRepositoryNameById(repo)}</span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-rpm`}><span>{contentCounts[repo].rpm ? `${contentCounts[repo].rpm} Packages` : 'N/A'}</span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-count`}><AdditionalCapsuleContent counts={contentCounts[repo]} /></DataListCell>);
} else {
cellList.push(<DataListCell key={`${repo.id}-not-synced`}><InactiveText text={__('Content view is not synced to capsule')} /></DataListCell>);
}
cellList.push(<DataListCell key={`${repo.id}-name`}><span><a href={`/products/${envContentCounts[repo].metadata.product_id}/repositories/${envContentCounts[repo].metadata.library_instance_id}/`}>{getRepositoryNameById(envContentCounts[repo].metadata.library_instance_id)}</a></span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-type`}><RepoIcon type={envContentCounts[repo].metadata.content_type} /></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-rpm`}><span>{envContentCounts[repo].counts.rpm ? `${envContentCounts[repo].counts.rpm} Packages` : 'N/A'}</span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-count`}><AdditionalCapsuleContent counts={envContentCounts[repo].counts} /></DataListCell>);
/* eslint-enable max-len */
return cellList;
};

const dataListCellListsNotSynced = (repo) => {
const cellList = [];
/* eslint-disable max-len */
cellList.push(<DataListCell key={`${repo.id}-name`}><span><a href={`/products/${repo.product_id}/repositories/${repo.library_id}/`}>{repo.name}</a></span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-type`}><RepoIcon type={repo.content_type} /></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-rpm`}><span><InactiveText text="N/A" /></span></DataListCell>);
cellList.push(<DataListCell key={`${repo.id}-count`}><InactiveText text="N/A" /></DataListCell>);
/* eslint-enable max-len */
return cellList;
};
if (syncedToCapsule) {
return (
<DataList aria-label="Expanded repository details" isCompact>
<DataListItem key="headers" >
<DataListItemRow>
<DataListItemCells dataListCells={[
<DataListCell key="primary content">
<b>{__('Repository')}</b>
</DataListCell>,
<DataListCell key="Type"><b>{__('Type')}</b></DataListCell>,
<DataListCell key="Package count"><b>{__('Packages')}</b></DataListCell>,
<DataListCell key="Additional content"><b>{__('Additional content')}</b></DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
{Object.keys(envContentCounts).length ?
Object.keys(envContentCounts).map((repo, index) => (
<DataListItem key={`${repo.id}-${index}`}>
<DataListItemRow>
<DataListItemCells
dataListCells={dataListCellLists(envContentCounts[repo], repo)}
/>
</DataListItemRow>
</DataListItem>
)) :
<DataListItem key="empty">
<DataListItemRow>
<DataListItemCells
dataListCells={[<DataListCell key="cv-empty"><InactiveText text={__('Content view version is empty')} /></DataListCell>]}
/>
</DataListItemRow>
</DataListItem>
}
</DataList>
);
}

return (
<DataList aria-label="Expanded repository details" isCompact>
<DataListItem key="headers" >
Expand All @@ -30,34 +94,40 @@ const ExpandedSmartProxyRepositories = ({ contentCounts, repositories, syncedToC
<DataListCell key="primary content">
<b>{__('Repository')}</b>
</DataListCell>,
<DataListCell key="Type"><b>{__('Type')}</b></DataListCell>,
<DataListCell key="Package count"><b>{__('Packages')}</b></DataListCell>,
<DataListCell key="Additional content"><b>{__('Additional content')}</b></DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
{Object.keys(contentCounts).length ?
Object.keys(contentCounts).map((repo, index) => (
{repositories.length ?
repositories.map((repo, index) => (
<DataListItem key={`${repo.id}-${index}`}>
<DataListItemRow>
<DataListItemCells dataListCells={dataListCellLists(repo)} />
<DataListItemCells dataListCells={dataListCellListsNotSynced(repo)} />
</DataListItemRow>
</DataListItem>
)) :
<DataListItem key="empty">
<DataListItemRow>
<DataListItemCells dataListCells={[<DataListCell key="cv-empty"><InactiveText text={__('Content view version is empty')} /></DataListCell>]} />
<DataListItemCells
dataListCells={[<DataListCell key="cv-empty"><InactiveText text={__('Content view version is empty')} /></DataListCell>]}
/>
</DataListItemRow>
</DataListItem>
}
</DataList>
);
}
</DataList>);
};

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 = {
Expand Down
2 changes: 1 addition & 1 deletion webpack/scenes/SmartProxy/SmartProxyContentActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getResponseErrorMsgs } from '../../utils/helpers';
const getSmartProxyContent = ({ smartProxyId, organizationId }) => get({
type: API_OPERATIONS.GET,
key: SMART_PROXY_CONTENT_KEY,
url: api.getApiUrl(`/capsules/${smartProxyId}/content/sync?organization_id=${organizationId}`),
url: api.getApiUrl(organizationId ? `/capsules/${smartProxyId}/content/sync?organization_id=${organizationId}` : `/capsules/${smartProxyId}/content/sync`),
});

export const getSmartProxies = () => get({
Expand Down
9 changes: 7 additions & 2 deletions webpack/scenes/SmartProxy/SmartProxyExpandableTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const SmartProxyExpandableTable = ({ smartProxyId, organizationId }) => {
let metadata = {};
const {
lifecycle_environments: results, last_sync_task: lastTask, last_sync_words: lastSyncWords,
content_counts: contentCounts,
} = response;
if (results) {
metadata = { total: results.length, subtotal: results.length };
Expand Down Expand Up @@ -88,7 +89,7 @@ const SmartProxyExpandableTable = ({ smartProxyId, organizationId }) => {
{
results?.map((env, rowIndex) => {
const {
id, content_views: contentViews, counts,
id, content_views: contentViews,
} = env;
const isExpanded = tableRowIsExpanded(id);
return (
Expand Down Expand Up @@ -116,7 +117,11 @@ const SmartProxyExpandableTable = ({ smartProxyId, organizationId }) => {
<Tr key="child_row" ouiaId={`ContentViewTableRowChild-${id}`} isExpanded={isExpanded}>
<Td colSpan={4}>
{isExpanded ?
<ExpandableCvDetails contentViews={contentViews} counts={counts} /> :
<ExpandableCvDetails
contentViews={contentViews}
contentCounts={contentCounts}
envId={id}
/> :
<></>}
</Td>
</Tr>
Expand Down
Loading

0 comments on commit a5982ec

Please sign in to comment.