diff --git a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
index a72525c5..532c5a8a 100644
--- a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
+++ b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
@@ -5,17 +5,19 @@ import PatchSetWizard from '../../SmartComponents/PatchSetWizard/PatchSetWizard'
import UnassignSystemsModal from '../../SmartComponents/Modals/UnassignSystemsModal';
import AssignSystemsModal from '../../SmartComponents/Modals/AssignSystemsModal';
-const PatchSetWrapper = ({ patchSetState, setPatchSetState }) => {
+const PatchSetWrapper = ({ patchSetState, setPatchSetState, totalItems }) => {
return (<>
{(patchSetState.isUnassignSystemsModalOpen) && }
{(patchSetState.isPatchSetWizardOpen) &&
}
@@ -24,6 +26,7 @@ const PatchSetWrapper = ({ patchSetState, setPatchSetState }) => {
PatchSetWrapper.propTypes = {
patchSetState: propTypes.object,
- setPatchSetState: propTypes.func
+ setPatchSetState: propTypes.func,
+ totalItems: propTypes.number
};
export default PatchSetWrapper;
diff --git a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
index 2f55ca9e..0cddd0d4 100644
--- a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
+++ b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
@@ -5,6 +5,7 @@ import { mountWithRouterAndProviderAndIntl } from '../../../config/rtlwrapper';
jest.mock('../../SmartComponents/PatchSetWizard/PatchSetWizard', () => () =>
);
jest.mock('../../SmartComponents/Modals/UnassignSystemsModal', () => () => );
+jest.mock('../../SmartComponents/Modals/AssignSystemsModal', () => () => );
const mockState = {};
@@ -28,7 +29,8 @@ const testProps = {
isPatchSetWizardOpen: true,
systemsIDs: ['system-1', 'system-2']
},
- setPatchSetState: jest.fn()
+ setPatchSetState: jest.fn(),
+ totalItems: 101
};
describe('PatchSetWrapper', () => {
it('should display PatchSetWizard when isPatchSetWizardOpen prop is true', () => {
diff --git a/src/SmartComponents/Advisories/Advisories.js b/src/SmartComponents/Advisories/Advisories.js
index 6d27e2de..6144d2fb 100644
--- a/src/SmartComponents/Advisories/Advisories.js
+++ b/src/SmartComponents/Advisories/Advisories.js
@@ -100,7 +100,8 @@ const Advisories = () => {
{
endpoint: ID_API_ENDPOINTS.advisories,
queryParams,
- selectionDispatcher: selectAdvisoryRow
+ selectionDispatcher: selectAdvisoryRow,
+ totalItems: metadata?.total_items
}
);
diff --git a/src/SmartComponents/Advisories/Advisories.test.js b/src/SmartComponents/Advisories/Advisories.test.js
index f9c42a1d..9f865766 100644
--- a/src/SmartComponents/Advisories/Advisories.test.js
+++ b/src/SmartComponents/Advisories/Advisories.test.js
@@ -24,7 +24,7 @@ jest.mock('../../Utilities/api', () => ({
exportAdvisoriesCSV: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
fetchSystems: jest.fn(() => Promise.resolve({ data: { id: 'testId' } }).catch((err) => console.log(err))),
fetchViewAdvisoriesSystems: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchIDs: jest.fn(() => Promise.resolve({ ids: [] }).catch((err) => console.log(err))),
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_id-1' }] }).catch((err) => console.log(err))),
fetchApplicableAdvisoriesApi: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)))
}));
@@ -52,7 +52,7 @@ const mockState = { ...storeListDefaults,
metadata: {
limit: 25,
offset: 0,
- total_items: 10
+ total_items: 101
}
};
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystem.test.js b/src/SmartComponents/AdvisorySystems/AdvisorySystem.test.js
index cf7c415e..fd8fbe58 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystem.test.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystem.test.js
@@ -11,7 +11,7 @@ initMocks();
jest.mock('../../Utilities/api', () => ({
...jest.requireActual('../../Utilities/api'),
- fetchIDs: jest.fn(() => Promise.resolve({ ids: [] }).catch((err) => console.log(err)))
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_id-1' }] }).catch((err) => console.log(err)))
}));
jest.mock(
@@ -30,7 +30,7 @@ const mockState = {
selectedRows: { 'test-system-1': true },
error: {},
status: 'resolved',
- total: 2
+ total: 101
},
AdvisorySystemsStore: {
queryParams: {}
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystems.js b/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
index 0052b406..95709551 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
@@ -102,7 +102,8 @@ const AdvisorySystems = ({ advisoryName }) => {
{
endpoint: ID_API_ENDPOINTS.advisorySystems(advisoryName),
queryParams,
- selectionDispatcher: systemSelectAction
+ selectionDispatcher: systemSelectAction,
+ totalItems
}
);
diff --git a/src/SmartComponents/Modals/AssignSystemsModal.js b/src/SmartComponents/Modals/AssignSystemsModal.js
index 9893a85e..9d8f24a1 100644
--- a/src/SmartComponents/Modals/AssignSystemsModal.js
+++ b/src/SmartComponents/Modals/AssignSystemsModal.js
@@ -10,8 +10,10 @@ import { addNotification } from '@redhat-cloud-services/frontend-components-noti
import { patchSetAssignSystemsNotifications } from '../PatchSet/PatchSetAssets';
import { filterSelectedActiveSystemIDs } from '../../Utilities/Helpers';
import { filterSatelliteManagedSystems } from './Helpers';
+import { useFetchBatched } from '../../Utilities/hooks';
+import isEmpty from 'lodash/isEmpty';
-const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl }) => {
+const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl, totalItems }) => {
const dispatch = useDispatch();
const { systemsIDs, isAssignSystemsModalOpen } = patchSetState;
@@ -20,6 +22,7 @@ const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl }) => {
const [systemsNotManagedBySatellite, setSystemsNotManagedBySatellite] = useState([]);
const [systemsLoading, setSystemsLoading] = useState(true);
+ const { fetchBatched } = useFetchBatched();
const closeModal = () => {
setPatchSetState({
@@ -66,10 +69,13 @@ const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl }) => {
};
useEffect(() => {
- if (systemsIDs) {
+ if (systemsIDs && !isEmpty(systemsIDs)) {
setSystemsLoading(true);
-
- filterSatelliteManagedSystems(Object.keys(systemsIDs)).then(result => {
+ filterSatelliteManagedSystems(
+ Object.keys(systemsIDs),
+ fetchBatched,
+ totalItems
+ ).then(result => {
setSystemsNotManagedBySatellite(result);
setSystemsLoading(false);
});
@@ -144,7 +150,8 @@ const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl }) => {
AssignSystemsModal.propTypes = {
intl: propTypes.any,
setPatchSetState: propTypes.func,
- patchSetState: propTypes.object
+ patchSetState: propTypes.object,
+ totalItems: propTypes.number
};
export default injectIntl(AssignSystemsModal);
diff --git a/src/SmartComponents/Modals/Helpers.js b/src/SmartComponents/Modals/Helpers.js
index 8b1ea864..127c1b62 100644
--- a/src/SmartComponents/Modals/Helpers.js
+++ b/src/SmartComponents/Modals/Helpers.js
@@ -2,28 +2,37 @@ import React from 'react';
import { GridItem } from '@patternfly/react-core';
import messages from '../../Messages';
-import { fetchIDs, fetchSystems } from '../../Utilities/api';
+import { fetchIDs } from '../../Utilities/api';
-export const filterSystemsWithoutSets = (systemsIDs) => {
- return fetchSystems({
- limit: -1, 'filter[baseline_name]': 'neq:',
- filter: { stale: [true, false] }
- }).then((allSystemsWithPatchSet) => {
- return systemsIDs.filter(systemID =>
- allSystemsWithPatchSet?.data?.some(system => system.id === systemID)
+const filterChosenSystems = (urlFilter, systemsIDs, fetchBatched, totalItems) => {
+ return fetchBatched(
+ (filter) => fetchIDs(
+ '/ids/systems',
+ filter
+ ),
+ {
+ ...urlFilter,
+ filter: { stale: [true, false] }
+ },
+ totalItems,
+ 100
+ ).then((systemsNotManagedBySatellite) => {
+ const aggregatedResult = systemsNotManagedBySatellite.flatMap(({ data }) => data);
+ return systemsIDs.filter(systemID =>{
+ return aggregatedResult?.some(system => system.id === systemID);
+ }
);
});
};
-export const filterSatelliteManagedSystems = (systemsIDs) => {
- return fetchIDs('/ids/systems', {
- limit: -1, 'filter[satellite_managed]': 'false',
- filter: { stale: [true, false] }
- }).then((systemsNotManagedBySatellite) => {
- return systemsIDs.filter(systemID =>
- systemsNotManagedBySatellite?.data?.some(system => system.id === systemID)
- );
- });
+export const filterSystemsWithoutSets = (systemsIDs, fetchBatched, totalItems) => {
+ const urlFilter = { 'filter[baseline_name]': 'neq:' };
+ return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
+};
+
+export const filterSatelliteManagedSystems = (systemsIDs, fetchBatched, totalItems) => {
+ const urlFilter = { 'filter[satellite_managed]': 'false' };
+ return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
};
export const renderUnassignModalMessages = (bodyMessage, systemsCount, intl) => (
diff --git a/src/SmartComponents/Modals/UnassignSystemsModal.js b/src/SmartComponents/Modals/UnassignSystemsModal.js
index 95695730..600e8927 100644
--- a/src/SmartComponents/Modals/UnassignSystemsModal.js
+++ b/src/SmartComponents/Modals/UnassignSystemsModal.js
@@ -6,11 +6,13 @@ import { injectIntl } from 'react-intl';
import messages from '../../Messages';
import { useUnassignSystemsHook } from './useUnassignSystemsHook';
import { renderUnassignModalMessages, filterSystemsWithoutSets } from './Helpers';
+import { useFetchBatched } from '../../Utilities/hooks';
-const UnassignSystemsModal = ({ unassignSystemsModalState = {}, setUnassignSystemsModalOpen, intl }) => {
+const UnassignSystemsModal = ({ unassignSystemsModalState = {}, setUnassignSystemsModalOpen, intl, totalItems }) => {
const { systemsIDs, isUnassignSystemsModalOpen } = unassignSystemsModalState;
const [systemsWithPatchSet, setSystemWithPatchSet] = useState([]);
const [systemsLoading, setSystemsLoading] = useState(true);
+ const { fetchBatched } = useFetchBatched();
const handleModalToggle = (shouldRefresh) => {
setUnassignSystemsModalOpen({
@@ -29,7 +31,12 @@ const UnassignSystemsModal = ({ unassignSystemsModalState = {}, setUnassignSyste
useEffect(() => {
setSystemsLoading(true);
- filterSystemsWithoutSets(systemsIDs).then(result => {
+ filterSystemsWithoutSets(
+ systemsIDs,
+ fetchBatched,
+ totalItems
+ )
+ .then(result => {
setSystemWithPatchSet(result);
setSystemsLoading(false);
});
@@ -82,6 +89,7 @@ const UnassignSystemsModal = ({ unassignSystemsModalState = {}, setUnassignSyste
UnassignSystemsModal.propTypes = {
intl: propTypes.any,
setUnassignSystemsModalOpen: propTypes.func,
- unassignSystemsModalState: propTypes.object
+ unassignSystemsModalState: propTypes.object,
+ totalItems: propTypes.number
};
export default injectIntl(UnassignSystemsModal);
diff --git a/src/SmartComponents/Modals/UnassignSystemsModal.test.js b/src/SmartComponents/Modals/UnassignSystemsModal.test.js
index 1d5a76b8..693aac09 100644
--- a/src/SmartComponents/Modals/UnassignSystemsModal.test.js
+++ b/src/SmartComponents/Modals/UnassignSystemsModal.test.js
@@ -1,6 +1,6 @@
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import UnassignSystemsModal from './UnassignSystemsModal';
-import { unassignSystemFromPatchSet, fetchSystems } from '../../Utilities/api';
+import { unassignSystemFromPatchSet } from '../../Utilities/api';
import { initMocks } from '../../Utilities/unitTestingUtilities';
import { patchSetUnassignSystemsNotifications } from '../PatchSet/PatchSetAssets';
import { render, waitFor, screen } from '@testing-library/react';
@@ -12,7 +12,7 @@ initMocks();
jest.mock('../../Utilities/api', () => ({
...jest.requireActual('../../Utilities/api'),
unassignSystemFromPatchSet: jest.fn(),
- fetchSystems: jest.fn()
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_1' }] }))
}));
jest.mock('react-redux', () => ({
@@ -23,8 +23,6 @@ jest.mock('@redhat-cloud-services/frontend-components-notifications/redux', () =
addNotification: jest.fn(() => {})
}));
-fetchSystems.mockResolvedValue({ data: [{ id: 'test_1' }] });
-
let unassignSystemsModalState = {
isUnassignSystemsModalOpen: true,
systemsIDs: ['test_1', 'test_2', 'test_3']
diff --git a/src/SmartComponents/PackageSystems/PackageSystems.js b/src/SmartComponents/PackageSystems/PackageSystems.js
index 7c1a6b07..4ba3ac2b 100644
--- a/src/SmartComponents/PackageSystems/PackageSystems.js
+++ b/src/SmartComponents/PackageSystems/PackageSystems.js
@@ -100,7 +100,8 @@ const PackageSystems = ({ packageName }) => {
queryParams,
selectionDispatcher: systemSelectAction,
constructFilename,
- apiResponseTransformer: filterRemediatablePackageSystems
+ apiResponseTransformer: filterRemediatablePackageSystems,
+ totalItems
}
);
diff --git a/src/SmartComponents/PackageSystems/PackageSystems.test.js b/src/SmartComponents/PackageSystems/PackageSystems.test.js
index 09b8630b..f9ed8ce3 100644
--- a/src/SmartComponents/PackageSystems/PackageSystems.test.js
+++ b/src/SmartComponents/PackageSystems/PackageSystems.test.js
@@ -23,12 +23,11 @@ jest.mock('../../Utilities/api', () => ({
fetchPackageVersions: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
fetchIDs: jest.fn(() => Promise.resolve({
data: [{
- attributes: {
- advisory_type: 2,
- description: 'The tzdata penhancements.',
- public_date: '2020-10-19T15:02:38Z',
- synopsis: 'tzdata enhancement update'
- },
+ advisory_type: 2,
+ description: 'The tzdata penhancements.',
+ public_date: '2020-10-19T15:02:38Z',
+ synopsis: 'tzdata enhancement update',
+ updatable: true,
id: 'RHBA-2020:4282',
type: 'advisory'
}]
@@ -47,7 +46,7 @@ const mockState = {
selectedRows: { 'test-system-1': 'packageEvra' },
error: {},
status: 'resolved',
- total: 2
+ total: 101
},
PackageSystemsStore: {
queryParams: {}
diff --git a/src/SmartComponents/PatchSet/PatchSet.js b/src/SmartComponents/PatchSet/PatchSet.js
index d18ff445..2ce399f9 100644
--- a/src/SmartComponents/PatchSet/PatchSet.js
+++ b/src/SmartComponents/PatchSet/PatchSet.js
@@ -106,7 +106,8 @@ const PatchSet = () => {
{
endpoint: ID_API_ENDPOINTS.templates,
queryParams,
- selectionDispatcher: selectPatchSetRow
+ selectionDispatcher: selectPatchSetRow,
+ totalItems: metadata.total_items
}
);
diff --git a/src/SmartComponents/PatchSetDetail/PatchSetDetail.js b/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
index 05a463c3..8d95fc37 100644
--- a/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
+++ b/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
@@ -140,7 +140,8 @@ const PatchSetDetail = () => {
{
endpoint: ID_API_ENDPOINTS.templateSystems(patchSetId),
queryParams,
- selectionDispatcher: systemSelectAction
+ selectionDispatcher: systemSelectAction,
+ totalItems
}
);
diff --git a/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js b/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
index 1369f8e8..49b2ae1b 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
@@ -124,7 +124,8 @@ export const ReviewSystems = ({ systemsIDs = [], ...props }) => {
satellite_managed: false
}
},
- customSelector: selectRows
+ customSelector: selectRows,
+ totalItems: metadata.total_items
}
);
return (
diff --git a/src/SmartComponents/SystemAdvisories/SystemAdvisories.js b/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
index 2d7ac79a..a294e3b4 100644
--- a/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
+++ b/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
@@ -93,7 +93,8 @@ const SystemAdvisories = ({ handleNoSystemData, inventoryId, shouldRefresh }) =>
endpoint: ID_API_ENDPOINTS.systemAdvisories(inventoryId),
queryParams,
selectionDispatcher: selectSystemAdvisoryRow,
- constructFilename
+ constructFilename,
+ totalItems: metadata?.total_items
}
);
diff --git a/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js b/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
index 42f99f9c..be17668b 100644
--- a/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
+++ b/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
@@ -29,7 +29,7 @@ const mockState = {
metadata: {
limit: 25,
offset: 0,
- total_items: 10
+ total_items: 101
},
expandedRows: {},
selectedRows: {},
diff --git a/src/SmartComponents/SystemPackages/SystemPackages.js b/src/SmartComponents/SystemPackages/SystemPackages.js
index aff18361..4004cc68 100644
--- a/src/SmartComponents/SystemPackages/SystemPackages.js
+++ b/src/SmartComponents/SystemPackages/SystemPackages.js
@@ -78,7 +78,8 @@ const SystemPackages = ({ handleNoSystemData, inventoryId, shouldRefresh }) => {
queryParams,
selectionDispatcher: selectSystemPackagesRow,
constructFilename,
- transformKey
+ transformKey,
+ totalItems: metadata?.total_items
}
);
diff --git a/src/SmartComponents/SystemPackages/SystemPackages.test.js b/src/SmartComponents/SystemPackages/SystemPackages.test.js
index f9b88960..1941ea4e 100644
--- a/src/SmartComponents/SystemPackages/SystemPackages.test.js
+++ b/src/SmartComponents/SystemPackages/SystemPackages.test.js
@@ -53,7 +53,7 @@ const mockState = {
metadata: {
limit: 25,
offset: 0,
- total_items: 10
+ total_items: 101
}
};
diff --git a/src/SmartComponents/Systems/SystemsListAssets.js b/src/SmartComponents/Systems/SystemsListAssets.js
index 15d17dd4..413e9274 100644
--- a/src/SmartComponents/Systems/SystemsListAssets.js
+++ b/src/SmartComponents/Systems/SystemsListAssets.js
@@ -179,9 +179,9 @@ export const useActivateRemediationModal = (setRemediationIssues, setRemediation
);
fetchBatched(
- (__, pagination) => fetchApplicableSystemAdvisoriesApi({ ...filter, ...pagination }),
- totalCount,
- filter
+ (filterWithPagination) => fetchApplicableSystemAdvisoriesApi(filterWithPagination),
+ filter,
+ totalCount
).then(response => {
const advisories = response.flatMap(({ data }) => data);
const remediationIssues = remediationProvider(
diff --git a/src/SmartComponents/Systems/SystemsMainContent.js b/src/SmartComponents/Systems/SystemsMainContent.js
index 74214d1d..dac67ac8 100644
--- a/src/SmartComponents/Systems/SystemsMainContent.js
+++ b/src/SmartComponents/Systems/SystemsMainContent.js
@@ -58,7 +58,11 @@ const SystemsMainContent = () => {
return (
-
+
{isRemediationOpen &&
(input) => {
diff --git a/src/Utilities/TestingUtilities.js b/src/Utilities/TestingUtilities.js
index cb0ffb24..4e2e9fcb 100644
--- a/src/Utilities/TestingUtilities.js
+++ b/src/Utilities/TestingUtilities.js
@@ -78,12 +78,21 @@ export const testBulkSelection = (fetchAllCallback, fetchAllUrl, spyOnAction, se
it('should fetch all the data using limit=-1', async () => {
await user.click(screen.getByLabelText('Select'));
- await user.click(screen.getByText('Select all (10)'));
-
- expect(fetchAllCallback).toHaveBeenCalledWith(
- fetchAllUrl,
- expect.objectContaining({ limit: -1, offset: 0 })
+ await user.click(screen.getByText('Select all (101)'));
+ await waitFor(
+ () => {
+ expect(fetchAllCallback).toHaveBeenCalledTimes(2);
+ expect(fetchAllCallback).toHaveBeenCalledWith(
+ fetchAllUrl,
+ expect.objectContaining({ limit: 100, offset: 0 })
+ );
+ expect(fetchAllCallback).toHaveBeenCalledWith(
+ fetchAllUrl,
+ expect.objectContaining({ limit: 100, offset: 100 })
+ );
+ }
);
+
});
it('should unselect rows', async () => {
diff --git a/src/Utilities/hooks/useFetchBatched.js b/src/Utilities/hooks/useFetchBatched.js
index 63fd1fa8..87679d2d 100644
--- a/src/Utilities/hooks/useFetchBatched.js
+++ b/src/Utilities/hooks/useFetchBatched.js
@@ -5,14 +5,25 @@ export const useFetchBatched = () => {
return {
isLoading,
- fetchBatched: (fetchFunction, total, filter, batchSize = 50) => {
+ fetchBatched: async (fetchFunction, filter, total, batchSize = 50) => {
+ if (!total) {
+ total = await fetchFunction({ limit: 1 }).then(
+ response => response?.meta?.total_items || 0
+ );
+ }
+
const pages = Math.ceil(total / batchSize) || 1;
const results = resolve(
[...new Array(pages)].map(
// eslint-disable-next-line camelcase
- (_, pageIdx) => () =>
- fetchFunction(filter, { offset: pageIdx + 1, limit: batchSize })
+ (_, pageIdx) => () => {
+ return fetchFunction({
+ ...filter,
+ offset: pageIdx * batchSize,
+ limit: batchSize
+ });
+ }
)
);
diff --git a/src/Utilities/hooks/useOnSelect.js b/src/Utilities/hooks/useOnSelect.js
index 0c1f9c72..d2c1533a 100644
--- a/src/Utilities/hooks/useOnSelect.js
+++ b/src/Utilities/hooks/useOnSelect.js
@@ -3,6 +3,8 @@ import { useDispatch } from 'react-redux';
import { fetchIDs } from '../api';
import { toggleAllSelectedAction } from '../../store/Actions/Actions';
import { isObject } from '../Helpers';
+import { useFetchBatched } from './useFetchBatched';
+import isArray from 'lodash/isArray';
export const ID_API_ENDPOINTS = {
advisories: '/ids/advisories',
@@ -14,23 +16,43 @@ export const ID_API_ENDPOINTS = {
systemPackages: (systemID) => `/systems/${systemID}/packages`,
templateSystems: (templateId) => `/ids/baselines/${templateId}/systems`
};
+const isArrayWithData = (dataStructure) => {
+ return isArray(dataStructure) && dataStructure.length;
+};
const useFetchAllIDs = (
endpoint,
- apiResponseTransformer
-) =>
- useCallback((queryParams) =>
- fetchIDs(endpoint, { ...queryParams, limit: -1 })
- .then(response =>
- apiResponseTransformer ? apiResponseTransformer(response) : response
- ),
- []
- );
+ apiResponseTransformer,
+ totalItems
+) => {
+ const { fetchBatched } = useFetchBatched();
+ return useCallback(async (queryParams) => {
+ const response = await fetchBatched(
+ (filter) => fetchIDs(endpoint, filter),
+ queryParams,
+ totalItems,
+ 100
+ );
+
+ const aggregatedResponse = response.reduce((accumulator = {}, currentValue) => {
+ Object.keys(accumulator).forEach(key => {
+ if (isArrayWithData(currentValue[key])) {
+ accumulator[key] = accumulator[key].concat(currentValue[key]);
+ }
+ });
+
+ return accumulator;
+ }, { data: [], ids: [] });
+
+ return apiResponseTransformer ? apiResponseTransformer(aggregatedResponse) : aggregatedResponse;
+ },
+ [totalItems, endpoint, fetchBatched]);
+};
const useCreateSelectedRow = (transformKey, constructFilename) =>
useCallback((rows, toSelect = []) => {
const { ids, data } = rows;
- const shouldUseOnlyIDs = Array.isArray(ids);
+ const shouldUseOnlyIDs = !isArrayWithData(data);
const items = shouldUseOnlyIDs ? ids : data;
items.forEach((item) => {
@@ -79,9 +101,8 @@ const createSelectors = (
};
const selectAll = (fetchIDs, queryParams) => {
- queryParams.offset = 0;
return fetchIDs(queryParams).then(response => {
- if (Array.isArray(response.data)) {
+ if (isArrayWithData(response.data)) {
let rowsToSelect = response.data.filter(row => row.status !== 'Applicable');
dispatchSelection(createSelectedRow({ data: rowsToSelect }));
} else {
@@ -103,11 +124,12 @@ export const useOnSelect = (rawData, selectedRows, config) => {
transformKey,
apiResponseTransformer,
//TODO: get rid of this custom selector
- customSelector
+ customSelector,
+ totalItems
} = config;
const dispatch = useDispatch();
- const fetchIDs = useFetchAllIDs(endpoint, apiResponseTransformer);
+ const fetchIDs = useFetchAllIDs(endpoint, apiResponseTransformer, totalItems);
const createSelectedRow = useCreateSelectedRow(transformKey, constructFilename);
const toggleAllSystemsSelected = (flagState) => {
diff --git a/src/Utilities/hooks/useOnSelect.test.js b/src/Utilities/hooks/useOnSelect.test.js
index ae42e3ae..3b737460 100644
--- a/src/Utilities/hooks/useOnSelect.test.js
+++ b/src/Utilities/hooks/useOnSelect.test.js
@@ -1,4 +1,5 @@
import { act, renderHook } from '@testing-library/react-hooks';
+import { waitFor } from '@testing-library/react';
import { fetchIDs } from '../api';
import { useOnSelect } from './useOnSelect';
@@ -8,9 +9,11 @@ jest.mock('react-redux', () => ({
}));
jest.mock('../api', () => ({
...jest.requireActual('../api'),
- fetchIDs: jest.fn(() => Promise.resolve({
- data: [{ id: 'db-item' }]
- }))
+ fetchIDs: jest.fn(() => {
+ return Promise.resolve({
+ data: [{ id: 'db-item' }]
+ });
+ })
}));
const rows = [
@@ -127,16 +130,21 @@ describe('useOnSelect', () => {
]);
});
- it('Should select all items from db', () => {
+ it('Should select all items from db', async () => {
+ config.totalItems = 102;
const { result } = renderHook(() =>
useOnSelect(rows, {}, config)
);
- act(() => {
- result.current('all', {});
- });
+ result.current('all', {});
- expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', { limit: -1, offset: 0, search: 'test-search' });
+ await waitFor(
+ () => {
+ expect(fetchIDs).toHaveBeenCalledTimes(2);
+ expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', { limit: 100, offset: 0, search: 'test-search' });
+ expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', { limit: 100, offset: 100, search: 'test-search' });
+ }
+ );
});
it('Should skip invalid rows while selection', () => {
diff --git a/src/Utilities/hooks/usePatchSetState.js b/src/Utilities/hooks/usePatchSetState.js
index 0251b3b5..b730c0fb 100644
--- a/src/Utilities/hooks/usePatchSetState.js
+++ b/src/Utilities/hooks/usePatchSetState.js
@@ -14,7 +14,7 @@ export const usePatchSetState = (selectedRows) => {
isUnassignSystemsModalOpen: false,
isAssignSystemsModalOpen: false,
shouldRefresh: false,
- systemsIDs: []
+ systemsIDs: {}
});
const openPatchSetAssignWizard = (systemID) => {