Skip to content

Commit

Permalink
Fixes #37596 - Bulk Errata Wizard
Browse files Browse the repository at this point in the history
Co-authored-by: Jeremy Lenz <[email protected]>

Refs #37596 - PR Suggestions

Refs #37596 - updated select all

Refs #37596 - added some errata status checks

Refs #37596 - Addressed PR Comments to handle errata filtering

Refs #37596 - imporved handling of selectAll
  • Loading branch information
parthaa committed Jul 3, 2024
1 parent 2072d3f commit 231c41f
Show file tree
Hide file tree
Showing 12 changed files with 638 additions and 8 deletions.
6 changes: 5 additions & 1 deletion app/models/katello/concerns/host_managed_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,11 @@ def deb_names_for_job_template(action:, search:)
end

def advisory_ids(search:)
::Katello::Erratum.installable_for_hosts([self]).search_for(search).pluck(:errata_id)
ids = ::Katello::Erratum.installable_for_hosts([self]).search_for(search).pluck(:errata_id)
if ids.empty?
fail _("Cannot install errata: No installable errata found for search term '%s'") % search
end
ids
end

def filtered_entitlement_quantity_consumed(pool)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ const katelloTracerResolveParams = ({ hostname, search }) =>
});

const katelloHostErrataInstallParams = ({
hostname, search,
hostname, hostSearch, search, descriptionFormat,
}) => baseParams({
hostname,
hostSearch,
inputs: { [ERRATA_SEARCH_QUERY]: search },
feature: REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH,
descriptionFormat,
});

const katelloModuleStreamActionsParams = ({ hostname, action, moduleSpec }) =>
Expand Down Expand Up @@ -218,13 +220,13 @@ export const resolveTraces = ({ hostname, search }) => post({
});

export const installErrata = ({
hostname, search,
hostname, hostSearch, search, descriptionFormat,
}) => post({
type: API_OPERATIONS.POST,
key: REX_JOB_INVOCATIONS_KEY,
url: foremanApi.getApiUrl('/job_invocations'),
params: katelloHostErrataInstallParams({
hostname, search,
hostname, search, hostSearch, descriptionFormat,
}),
handleSuccess: showRexToast,
errorToast,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ export const resolveTraceUrl = ({ hostname, search }) => createJob({
inputs: { [TRACES_SEARCH_QUERY]: search },
});

export const errataInstallUrl = ({ hostname, search }) => createJob({
export const errataInstallUrl = ({ hostname, search, hostSearch }) => createJob({
hostname,
hostSearch,
feature: REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH,
inputs: { [ERRATA_SEARCH_QUERY]: search },
});
Expand Down
11 changes: 11 additions & 0 deletions webpack/components/extensions/Hosts/ActionsBar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ const HostActionsBar = () => {
[
'bulk-change-cv-modal',
'bulk-packages-wizard',
'bulk-errata-wizard',
].forEach((id) => {
dispatch(addModal({ id }));
});
}, [dispatch]);
const { setModalOpen: openBulkChangeCVModal } = useForemanModal({ id: 'bulk-change-cv-modal' });
const { setModalOpen: openBulkPackagesWizardModal } = useForemanModal({ id: 'bulk-packages-wizard' });
const { setModalOpen: openBulkErrataWizardModal } = useForemanModal({ id: 'bulk-errata-wizard' });

const orgId = useForemanOrganization()?.id;

Expand Down Expand Up @@ -67,6 +69,15 @@ const HostActionsBar = () => {
>
{__('Manage packages')}
</DropdownItem>
<DropdownItem
ouiaId="bulk-errata-wizard-dropdown-item"
key="bulk-errata-wizard-dropdown-item"
onClick={openBulkErrataWizardModal}
isDisabled={selectedCount === 0}
>
{__('Manage errata')}
</DropdownItem>

</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import React, { useEffect, useContext } from 'react';
import {
Alert,
ToolbarItem,
Text,
TextContent,
TextVariants,
} from '@patternfly/react-core';
import { TableText } from '@patternfly/react-table';
import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
import { translate as __ } from 'foremanReact/common/I18n';
import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
import { STATUS, getControllerSearchProps } from 'foremanReact/constants';
import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
import { BulkErrataWizardContext, ERRATA_URL } from './BulkErrataWizard';
import { ErrataType, ErrataSeverity } from '../../../../../components/Errata';
import katelloApi from '../../../../../services/api';

const BulkErrataTable = () => {
const {
setShouldValidateStep2,
errataBulkSelect,
errataResults: results,
errataMetadata: {
total, per_page: perPage, page, subtotal,
},
errataResponse: response,
} = useContext(BulkErrataWizardContext);
const apiOptions = { key: 'BULK_HOST_ERRATA' };
const {
status: errataStatus,
} = response;


const origSearchProps = getControllerSearchProps('errata', 'searchBar-errata');
const customSearchProps = {
...origSearchProps,
autocomplete: {
...origSearchProps.autocomplete,
url: katelloApi.getApiUrl('/errata/auto_complete_search'),
},
};

const {
selectAll,
selectPage,
selectNone,
selectOne,
isSelected,
selectedCount,
areAllRowsSelected,
areAllRowsOnPageSelected,
updateSearchQuery,
hasInteracted,
} = errataBulkSelect;

useEffect(() => {
if (results?.length && hasInteracted) {
setShouldValidateStep2(true);
}
}, [setShouldValidateStep2, results, hasInteracted]);

const pageStats = getPageStats({ total: subtotal, page, perPage });
const selectionToolbar = (
<ToolbarItem key="selectAll">
<SelectAllCheckbox
{...{
selectNone,
selectPage,
selectedCount,
pageRowCount: pageStats.pageRowCount,
areAllRowsSelected,
areAllRowsOnPageSelected,
}}
selectAll={selectAll}
totalCount={total}
areAllRowsOnPageSelected={areAllRowsOnPageSelected()}
areAllRowsSelected={areAllRowsSelected()}
/>
</ToolbarItem>
);

const columns = {
id: {
title: __('Erratum'),
wrapper: ({ id, errata_id: errataId }) => (
<a target="_blank" href={`/errata/${id}`} rel="noreferrer">{errataId}</a>
),
isSorted: true,
weight: 10,
},
title: {
title: __('Title'),
wrapper: ({ title }) => <TableText wrapModifier="truncate">{title}</TableText>,
isSorted: true,
weight: 20,
},
type: {
title: __('Type'),
wrapper: erratum => <ErrataType {...erratum} />,
weight: 30,
isSorted: true,
},
severity: {
title: __('Severity'),
wrapper: erratum => <ErrataSeverity {...erratum} />,
weight: 40,
isSorted: true,
},
affectedHosts: {
title: __('Affected hosts'),
wrapper: ({ affected_hosts_count: affectedHostsCount }) => affectedHostsCount,
weight: 50,
},
};

return (
<>
<TextContent>
<Text ouiaId="mew-step-3-header" component={TextVariants.h3}>
{__('Apply errata')}
</Text>
<Text ouiaId="mew-step-3-content" component={TextVariants.p}>
{__('Select errata to apply on the selected hosts. Some errata may already be applied on some hosts.')}
</Text>
</TextContent>
{selectedCount === 0 && hasInteracted && (
<Alert
ouiaId="no-errata-alert"
variant="info"
isInline
title={__('Select at least one erratum.')}
style={{ marginBottom: '1rem' }}
/>
)}
{ errataStatus === STATUS.RESOLVED && !results?.length && (
<Alert
ouiaId="no-errata-found-alert"
variant="info"
isInline
title={__('No errata found.')}
style={{ marginBottom: '1rem' }}
/>
)}
<TableIndexPage
columns={columns}
showCheckboxes
apiUrl={ERRATA_URL}
apiOptions={apiOptions}
headerText={__('Errata')}
header={null}
controller="errata"
customSearchProps={customSearchProps}
creatable={false}
replacementResponse={response}
selectionToolbar={selectionToolbar}
updateSearchQuery={updateSearchQuery}
rowSelectTd={RowSelectTd}
selectOne={selectOne}
isSelected={isSelected}
idColumn="errata_id"
updateParamsByUrl={false}
bookmarksPosition="right"
/>
</>
);
};


export default BulkErrataTable;
Loading

0 comments on commit 231c41f

Please sign in to comment.