diff --git a/src/Components/SmartComponents/SystemsPage/SystemTableToolbar.test.js b/src/Components/SmartComponents/SystemsPage/SystemTableToolbar.test.js
deleted file mode 100644
index 277160006..000000000
--- a/src/Components/SmartComponents/SystemsPage/SystemTableToolbar.test.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import SystemsTableToolbar from './SystemsTableToolbar';
-import toJson from 'enzyme-to-json';
-import { mountWithIntl } from '../../../Helpers/MiscHelper';
-import { BrowserRouter as Router } from 'react-router-dom';
-import configureStore from 'redux-mock-store';
-import { Provider } from 'react-redux';
-import { intl } from '../../../Utilities/IntlProvider';
-import useOsVersionFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/OsVersionFilter';
-import { systems } from '../../../Helpers/fixtures';
-
-const mockStore = configureStore([store => next => action => { }]);
-let store = mockStore({});
-
-const applyMock = jest.fn();
-const handleSelectMock = jest.fn();
-const doOptOutMock = jest.fn();
-
-jest.mock('../../PresentationalComponents/Filters/PrimaryToolbarFilters/OsVersionFilter')
-
-let wrapper;
-
-beforeEach(() => {
- wrapper = mountWithIntl(
-
-
-
-
-
- );
-});
-
-describe('SystemsTableToolbar component', () => {
- it("Renders toolbar", () => {
- expect(
- wrapper.find({
- ouiaId: "PrimaryToolbar",
- })
- ).toHaveLength(1);
- });
-
- it('Should match snapshot', () => {
- expect(toJson(wrapper.find('Toolbar'))).toMatchSnapshot();
- });
-
- it('Select all systems', () => {
- const selectAllToggle = wrapper.find('DropdownToggle button').first();
- selectAllToggle.simulate('click');
-
- wrapper.find('Dropdown').first().find("button").at(2).simulate('click');
- const bulkSelectedSystems = systems.data.map((system) => {
- return {
- display_name: system.display_name,
- id: system.id,
- opt_out: system.attributes.opt_out,
- culled_timestamp: system.culled_timestamp,
- cve_count: system.cve_count,
- insights_id: system.insights_id,
- last_evaluation: system.last_evaluation,
- last_upload: system.last_upload,
- os: system.os,
- rules_evaluation: system.rules_evaluation,
- stale_timestamp: system.stale_timestamp,
- stale_warning_timestamp: system.stale_warning_timestamp,
- tags: system.tags,
- type: system.type,
- updated: system.updated,
- remediation: system.remediation,
- selected: true
- };
- });
-
- expect(handleSelectMock).toHaveBeenCalledWith(bulkSelectedSystems, true);
-
- });
-
- it('Should exclude the selected system', () => {
- wrapper = mountWithIntl(
-
-
-
-
-
- );
-
- const actionsToggle = wrapper.find('KebabToggle button');
- actionsToggle.simulate('click');
-
- const exclude = wrapper.find('Dropdown').at(3).find("DropdownItem button").at(0)
- const include = wrapper.find('Dropdown').at(3).find("DropdownItem button").at(1);
-
- exclude.simulate('click');
-
- expect(include.props('disabled')).toBeTruthy();
- expect(exclude.text()).toBe('Disable Vulnerability analysis on system');
- expect(doOptOutMock).toHaveBeenCalled();
- })
-
- it('Should include the excluded selected system', () => {
- wrapper = mountWithIntl(
-
-
-
-
-
- );
-
- const actionsToggle = wrapper.find('KebabToggle button');
- actionsToggle.simulate('click');
-
- const exclude = wrapper.find('Dropdown').at(3).find("DropdownItem button").at(0)
- const include = wrapper.find('Dropdown').at(3).find("DropdownItem button").at(1);
-
- include.simulate('click');
-
- expect(exclude.props('disabled')).toBeTruthy();
- expect(include.text()).toBe('Enable Vulnerability analysis on system');
- expect(doOptOutMock).toHaveBeenCalled();
- })
-
- it("The default filter is set by name", () => {
- const container = wrapper.find('button[data-ouia-component-id="ConditionalFilter"]');
- expect(container).toHaveLength(1);
- expect(container.text()).toBe('Name');
- })
-});
diff --git a/src/Components/SmartComponents/SystemsPage/SystemsPage.js b/src/Components/SmartComponents/SystemsPage/SystemsPage.js
index 928de4abb..8903f6047 100644
--- a/src/Components/SmartComponents/SystemsPage/SystemsPage.js
+++ b/src/Components/SmartComponents/SystemsPage/SystemsPage.js
@@ -1,9 +1,8 @@
-import React, { useEffect, useState, Fragment } from 'react';
+import React, { useEffect, useState, Fragment, useMemo } from 'react';
import { useIntl } from 'react-intl';
import messages from '../../../Messages';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
-import SystemsTableToolbar from './SystemsTableToolbar';
-import { PERMISSIONS, SYSTEMS_ALLOWED_PARAMS } from '../../../Helpers/constants';
+import { PERMISSIONS, SYSTEMS_ALLOWED_PARAMS, SYSTEMS_DEFAULT_FILTERS, SYSTEMS_FILTER_PARAMS } from '../../../Helpers/constants';
import ReducerRegistry from '../../../Utilities/ReducerRegistry';
import { Main } from '@redhat-cloud-services/frontend-components/Main';
import { systemTableRowActions } from '../../../Helpers/CVEHelper';
@@ -14,36 +13,45 @@ import {
clearSystemStore,
clearInventoryStore,
selectRows,
- changeColumnsSystemList
+ changeColumnsSystemList,
+ fetchSystems,
+ fetchSystemsIds
} from '../../../Store/Actions/Actions';
import { useUrlParams } from '../../../Helpers/MiscHelper';
import { InventoryTable } from '@redhat-cloud-services/frontend-components/Inventory';
import ErrorHandler from '../../PresentationalComponents/ErrorHandler/ErrorHandler';
import { TableVariant } from '@patternfly/react-table';
-import { useColumnManagement, useGetEntities, useOptOutSystems, useRbac } from '../../../Helpers/Hooks';
+import { useBulkSelect, useColumnManagement, useGetEntities, useOptOutSystems, useRbac } from '../../../Helpers/Hooks';
import * as APIHelper from '../../../Helpers/APIHelper';
import { EmptyStateNoSystems } from '../../PresentationalComponents/EmptyStates/EmptyStates';
-import { clearNotifications } from '@redhat-cloud-services/frontend-components-notifications/redux';
+import { addNotification, clearNotifications } from '@redhat-cloud-services/frontend-components-notifications/redux';
import NoAccessPage from '../../PresentationalComponents/StaticPages/NoAccessPage';
import Spinner from '@redhat-cloud-services/frontend-components/Spinner';
+import DownloadSystemsReport from '../Reports/DownloadSystemsReport';
+import { kebabItemDownloadPDF } from '../../PresentationalComponents/Kebab/KebabItems';
+import { buildActiveFilters, exportConfig, isFilterInDefaultState, removeFilters } from '../../../Helpers/TableToolbarHelper';
+import DownloadReport from '../../../Helpers/DownloadReport';
+import useOsVersionFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/OsVersionFilter';
+import useSearchFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/SearchFilter';
+import excludedFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/ExcludedFilter';
const SystemsPage = () => {
- const [[canReadVulnerabilityResults,
+ const [[
+ canReadVulnerabilityResults,
canSetExcludedIncluded,
canExport,
- canReadExcluded],
- isLoading] = useRbac([
+ canReadExcluded
+ ], isLoading
+ ] = useRbac([
PERMISSIONS.readVulnerabilityResults,
PERMISSIONS.setExcludedIncluded,
PERMISSIONS.basicReporting,
PERMISSIONS.readExcluded
]);
- const [[
- canReadHostsInventory],
- isLoadingInventory] = useRbac([
- PERMISSIONS.readHosts
- ], 'inventory');
+ const [[canReadHostsInventory], isLoadingInventory] = useRbac([PERMISSIONS.readHosts], 'inventory');
+
+ const [exportPDF, setExportPDF] = useState(false);
const inventoryRef = React.createRef();
const dispatch = useDispatch();
@@ -90,12 +98,10 @@ const SystemsPage = () => {
const handleSelect = (payload, selecting) => dispatch(selectRows(payload, selecting));
- const onRefreshInventory = () => {
- dispatch(clearInventoryStore());
- // timestamp is used to force inventory to refresh
- // if it wasn't there inventory might ignore request to refresh because parameters are the same
- inventoryRef.current.onRefreshData(({ timestamp: Date.now(), page: 1 }));
- };
+ const onRefreshInventory = () => (
+ dispatch(clearInventoryStore()),
+ inventoryRef.current.onRefreshData(({ page: 1 }))
+ );
const doOptOut = useOptOutSystems(onRefreshInventory);
const getEntities = useGetEntities(APIHelper.getSystems, {});
@@ -103,17 +109,82 @@ const SystemsPage = () => {
const [columnCounter, setColumnCount] = useState(0);
useEffect(() => setColumnCount(columnCounter + 1), [columns]);
- // TODO: let InventoryTable render its own toolbar instead of using custom one
+ const downloadReport = format => {
+ let params = { ...parameters };
+ DownloadReport.exec(
+ fetchSystems,
+ params,
+ format,
+ 'system-list',
+ notification => dispatch(
+ addNotification(notification)
+ ),
+ () => dispatch(clearNotifications())
+ );
+ };
+
+ const kebabProps = useMemo(() => {
+ return {
+ selectedExcluded: selectedRows.some(({ opt_out: optOut }) => optOut === true),
+ selectedIncluded: selectedRows.some(({ opt_out: optOut }) => optOut === false)
+ };
+ }, [selectedRows]);
+
+ const kebabOptions = [
+ '',
+ ...canSetExcludedIncluded ? [{
+ label: intl.formatMessage(messages.systemKebabDisableAnalysis, { count: selectedRowsCount }),
+ onClick: () => doOptOut(selectedRows, selectedRows?.[0].display_name, true),
+ props: { isDisabled: !selectedRowsCount || !kebabProps.selectedIncluded }
+ },
+ {
+ label: intl.formatMessage(messages.systemKebabEnableAnalysis, { count: selectedRowsCount }),
+ onClick: () => doOptOut(selectedRows, selectedRows?.[0].display_name, false, selectedRows),
+ props: { isDisabled: !selectedRowsCount || !kebabProps.selectedExcluded }
+ }] : [],
+ {
+ label: intl.formatMessage(messages.columnManagementModalTitle),
+ onClick: () => setColumnManagementModalOpen(true)
+ }
+ ];
+
+ const rawData = { data: items, meta: { totalItems }, isLoaded };
+
+ const bulkSelectProps = useBulkSelect({
+ rawData,
+ selectedRows,
+ selectedRowsCount,
+ handleSelect,
+ fetchResource: ops => fetchSystemsIds({ ...parameters, ...ops })
+ });
+
+ const osVersionFilter = useOsVersionFilter(
+ parameters.rhel_version,
+ apply
+ );
+
+ const filterConfigItems = [
+ useSearchFilter(
+ 'filter',
+ messages.systemsSearchName,
+ messages.searchFilterByName,
+ parameters.filter,
+ apply
+ ),
+ ...(canReadExcluded ? [excludedFilter(apply, parameters)] : []),
+ ...osVersionFilter
+ ];
+
return (
- isLoading ? :
+ isLoading ? :
canReadVulnerabilityResults ?
- { ColumnManagementModal }
+ {ColumnManagementModal}
-
+
- {isLoadingInventory ? :
+ {isLoadingInventory ? :
hasError && !canReadHostsInventory
- ?
+ ?
: (
{
columns={defaultColumns => mergeColumns(defaultColumns)}
getEntities={getEntities}
hideFilters={{ all: true }}
- noSystemsTable={}
+ showTags
+ noSystemsTable={}
+ exportConfig={canExport ? {
+ isDisabled: items?.meta?.totalItems === 0,
+ extraItems: [kebabItemDownloadPDF(exportPDF, setExportPDF)],
+ ouiaId: 'export',
+ ...exportConfig({ downloadReport })
+ } : null}
+ bulkSelect={bulkSelectProps}
+ actionsConfig={{
+ actions: kebabOptions,
+ dropdownProps: { ouiaId: 'toolbar-actions' }
+ }}
+ filterConfig={{
+ items: filterConfigItems
+ }}
+ activeFiltersConfig={{
+ filters: buildActiveFilters(parameters),
+ onDelete: (_, chips, reset) =>
+ removeFilters(chips, apply, reset, SYSTEMS_DEFAULT_FILTERS),
+ deleteTitle: intl.formatMessage(messages.resetFilters),
+ showDeleteButton: !isFilterInDefaultState(
+ parameters,
+ canReadExcluded ? SYSTEMS_DEFAULT_FILTERS : {},
+ SYSTEMS_FILTER_PARAMS)
+ }}
>
-
+ {exportPDF &&
+ setExportPDF(false)}
+ />
+ }
)}
- :
+ :
);
};
diff --git a/src/Components/SmartComponents/SystemsPage/SystemsTableToolbar.js b/src/Components/SmartComponents/SystemsPage/SystemsTableToolbar.js
deleted file mode 100644
index 025d3f064..000000000
--- a/src/Components/SmartComponents/SystemsPage/SystemsTableToolbar.js
+++ /dev/null
@@ -1,160 +0,0 @@
-import React, { Fragment, useState, useMemo } from 'react';
-import propTypes from 'prop-types';
-import { injectIntl } from 'react-intl';
-import messages from '../../../Messages';
-import { useDispatch } from 'react-redux';
-import { dataShape } from '../../../Helpers/MiscHelper';
-import { fetchSystems, fetchSystemsIds } from '../../../Store/Actions/Actions';
-import { PrimaryToolbar } from '@redhat-cloud-services/frontend-components/PrimaryToolbar';
-import useSearchFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/SearchFilter';
-import { exportConfig, buildActiveFilters, removeFilters, isFilterInDefaultState } from '../../../Helpers/TableToolbarHelper';
-import DownloadReport from '../../../Helpers/DownloadReport';
-import DownloadSystemsReport from '../Reports/DownloadSystemsReport';
-import { kebabItemDownloadPDF } from '../../PresentationalComponents/Kebab/KebabItems';
-import excludedFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/ExcludedFilter';
-import { SYSTEMS_DEFAULT_FILTERS, SYSTEMS_FILTER_PARAMS } from '../../../Helpers/constants';
-import { useBulkSelect } from '../../../Helpers/Hooks';
-import {
- addNotification,
- clearNotifications
-} from '@redhat-cloud-services/frontend-components-notifications/redux';
-import useOsVersionFilter from '../../PresentationalComponents/Filters/PrimaryToolbarFilters/OsVersionFilter';
-
-const SystemsTableToolbar = ({
- selectedRows,
- selectedRowsCount,
- intl,
- canExport,
- canSetExcludedIncluded,
- canReadExcluded,
- parameters,
- rawData,
- methods
-}) => {
- const [exportPDF, setExportPDF] = useState(false);
- const { apply, handleSelect, doOptOut, setColumnManagementModalOpen } = methods;
- const dispatch = useDispatch();
-
- const downloadReport = format => {
- let params = { ...parameters };
- DownloadReport.exec(
- fetchSystems,
- params,
- format,
- 'system-list',
- notification => dispatch(
- addNotification(notification)
- ),
- () => dispatch(clearNotifications())
- );
- };
-
- const kebabProps = useMemo(() => {
- return {
- selectedExcluded: selectedRows.some(({ opt_out: optOut }) => optOut === true),
- selectedIncluded: selectedRows.some(({ opt_out: optOut }) => optOut === false)
- };
- }, [selectedRows]);
-
- const kebabOptions = [
- '',
- ...canSetExcludedIncluded ? [{
- label: intl.formatMessage(messages.systemKebabDisableAnalysis, { count: selectedRowsCount }),
- onClick: () => doOptOut(selectedRows, selectedRows?.[0].display_name, true),
- props: { isDisabled: !selectedRowsCount || !kebabProps.selectedIncluded }
- },
- {
- label: intl.formatMessage(messages.systemKebabEnableAnalysis, { count: selectedRowsCount }),
- onClick: () => doOptOut(selectedRows, selectedRows?.[0].display_name, false, selectedRows),
- props: { isDisabled: !selectedRowsCount || !kebabProps.selectedExcluded }
- }] : [],
- {
- label: intl.formatMessage(messages.columnManagementModalTitle),
- onClick: () => setColumnManagementModalOpen(true)
- }
- ];
-
- const bulkSelectProps = useBulkSelect({
- rawData,
- selectedRows,
- selectedRowsCount,
- handleSelect,
- fetchResource: ops => fetchSystemsIds({ ...parameters, ...ops })
- });
-
- const osVersionFilter = useOsVersionFilter(
- parameters.rhel_version,
- apply
- );
-
- const filterConfigItems = [
- useSearchFilter(
- 'filter',
- messages.systemsSearchName,
- messages.searchFilterByName,
- parameters.filter,
- apply
- ),
- ...(canReadExcluded ? [excludedFilter(apply, parameters)] : []),
- ...osVersionFilter
- ];
-
- return
- removeFilters(chips, apply, reset, SYSTEMS_DEFAULT_FILTERS),
- deleteTitle: intl.formatMessage(messages.resetFilters),
- showDeleteButton: !isFilterInDefaultState(
- parameters,
- canReadExcluded ? SYSTEMS_DEFAULT_FILTERS : {},
- SYSTEMS_FILTER_PARAMS)
- }}
- exportConfig={canExport ? {
- isDisabled: rawData.meta.totalItems === 0,
- extraItems: [kebabItemDownloadPDF(exportPDF, setExportPDF)],
- ouiaId: 'export',
- ...exportConfig({ downloadReport })
- } : null}
- />
-
- {exportPDF &&
- setExportPDF(false)}
- />
- }
-
- ;
-
-};
-
-SystemsTableToolbar.propTypes = {
- rawData: dataShape,
- canExport: propTypes.bool,
- canSetExcludedIncluded: propTypes.bool,
- canReadExcluded: propTypes.bool,
- parameters: propTypes.object,
- selectedRows: propTypes.array,
- selectedRowsCount: propTypes.number,
- methods: propTypes.shape({
- doOptOut: propTypes.func,
- apply: propTypes.func,
- handleSelect: propTypes.func,
- setColumnManagementModalOpen: propTypes.func
- }),
- intl: propTypes.any
-};
-
-export default injectIntl(SystemsTableToolbar);