diff --git a/CHANGELOG.md b/CHANGELOG.md index 46577b0a8..ed66c0e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [v1.1.2](https://github.com/ral-facilities/datagateway/tree/v1.1.2) (2023-09-28) + +[Full Changelog](https://github.com/ral-facilities/datagateway/compare/v1.1.1...v1.1.2) + +**Fixed bugs:** + +- \#1582 - Fix double requests on default sort [\#1583](https://github.com/ral-facilities/datagateway/pull/1583) ([kaperoo](https://github.com/kaperoo)) + ## [v1.1.1](https://github.com/ral-facilities/datagateway/tree/v1.1.1) (2022-08-24) [Full Changelog](https://github.com/ral-facilities/datagateway/compare/v1.1.0...v1.1.1) diff --git a/lerna.json b/lerna.json index aee0bbd24..d60e435fc 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "1.1.1", + "version": "1.1.2", "npmClient": "yarn", "useWorkspaces": true } diff --git a/package.json b/package.json index a0e9bafc3..3028e8013 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "datagateway", "private": true, - "version": "1.1.0", + "version": "1.1.2", "workspaces": [ "packages/*" ], @@ -24,4 +24,4 @@ "postinstall": "husky install" }, "dependencies": {} -} \ No newline at end of file +} diff --git a/packages/datagateway-common/package.json b/packages/datagateway-common/package.json index 34d2fab4e..b0256375e 100644 --- a/packages/datagateway-common/package.json +++ b/packages/datagateway-common/package.json @@ -1,6 +1,6 @@ { "name": "datagateway-common", - "version": "1.1.1", + "version": "1.1.2", "private": true, "files": [ "lib" diff --git a/packages/datagateway-common/src/api/datafiles.tsx b/packages/datagateway-common/src/api/datafiles.tsx index 25afebc76..8612ef72d 100644 --- a/packages/datagateway-common/src/api/datafiles.tsx +++ b/packages/datagateway-common/src/api/datafiles.tsx @@ -56,7 +56,8 @@ const fetchDatafiles = ( }; export const useDatafilesPaginated = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -96,12 +97,14 @@ export const useDatafilesPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useDatafilesInfinite = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -129,6 +132,7 @@ export const useDatafilesInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-common/src/api/datasets.tsx b/packages/datagateway-common/src/api/datasets.tsx index 08c274f01..2b0dd1b1c 100644 --- a/packages/datagateway-common/src/api/datasets.tsx +++ b/packages/datagateway-common/src/api/datasets.tsx @@ -95,7 +95,8 @@ export const useDataset = ( }; export const useDatasetsPaginated = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -135,12 +136,14 @@ export const useDatasetsPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useDatasetsInfinite = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -168,6 +171,7 @@ export const useDatasetsInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-common/src/api/facilityCycles.tsx b/packages/datagateway-common/src/api/facilityCycles.tsx index 750a4e5c4..e77accae9 100644 --- a/packages/datagateway-common/src/api/facilityCycles.tsx +++ b/packages/datagateway-common/src/api/facilityCycles.tsx @@ -126,7 +126,8 @@ export const useFacilityCyclesByInvestigation = ( }; export const useFacilityCyclesPaginated = ( - instrumentId: number + instrumentId: number, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -171,12 +172,14 @@ export const useFacilityCyclesPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useFacilityCyclesInfinite = ( - instrumentId: number + instrumentId: number, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -204,6 +207,7 @@ export const useFacilityCyclesInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-common/src/api/instruments.tsx b/packages/datagateway-common/src/api/instruments.tsx index e2822d446..bc50c2d7f 100644 --- a/packages/datagateway-common/src/api/instruments.tsx +++ b/packages/datagateway-common/src/api/instruments.tsx @@ -56,7 +56,8 @@ const fetchInstruments = ( }; export const useInstrumentsPaginated = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -91,12 +92,14 @@ export const useInstrumentsPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useInstrumentsInfinite = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -124,6 +127,7 @@ export const useInstrumentsInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-common/src/api/investigations.tsx b/packages/datagateway-common/src/api/investigations.tsx index 8b639ec82..e774e32d9 100644 --- a/packages/datagateway-common/src/api/investigations.tsx +++ b/packages/datagateway-common/src/api/investigations.tsx @@ -97,7 +97,8 @@ export const useInvestigation = ( export const useInvestigationsPaginated = ( additionalFilters?: AdditionalFilters, - ignoreIDSort?: boolean + ignoreIDSort?: boolean, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -145,13 +146,15 @@ export const useInvestigationsPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useInvestigationsInfinite = ( additionalFilters?: AdditionalFilters, - ignoreIDSort?: boolean + ignoreIDSort?: boolean, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -185,6 +188,7 @@ export const useInvestigationsInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; @@ -558,7 +562,8 @@ const fetchISISInvestigations = ( export const useISISInvestigationsPaginated = ( instrumentId: number, instrumentChildId: number, - studyHierarchy: boolean + studyHierarchy: boolean, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -652,6 +657,7 @@ export const useISISInvestigationsPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; @@ -659,7 +665,8 @@ export const useISISInvestigationsPaginated = ( export const useISISInvestigationsInfinite = ( instrumentId: number, instrumentChildId: number, - studyHierarchy: boolean + studyHierarchy: boolean, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -730,6 +737,7 @@ export const useISISInvestigationsInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-common/src/api/studies.tsx b/packages/datagateway-common/src/api/studies.tsx index facc2b10b..1d67094ba 100644 --- a/packages/datagateway-common/src/api/studies.tsx +++ b/packages/datagateway-common/src/api/studies.tsx @@ -54,7 +54,8 @@ const fetchStudies = ( }; export const useStudiesPaginated = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -94,12 +95,14 @@ export const useStudiesPaginated = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; export const useStudiesInfinite = ( - additionalFilters?: AdditionalFilters + additionalFilters?: AdditionalFilters, + isMounted?: boolean ): UseInfiniteQueryResult => { const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl); const location = useLocation(); @@ -127,6 +130,7 @@ export const useStudiesInfinite = ( handleICATError(error); }, retry: retryICATErrors, + enabled: isMounted ?? true, } ); }; diff --git a/packages/datagateway-dataview/cypress/integration/card/isis/instruments.spec.ts b/packages/datagateway-dataview/cypress/integration/card/isis/instruments.spec.ts index aeb2ebff1..68edf347f 100644 --- a/packages/datagateway-dataview/cypress/integration/card/isis/instruments.spec.ts +++ b/packages/datagateway-dataview/cypress/integration/card/isis/instruments.spec.ts @@ -96,9 +96,7 @@ describe('ISIS - Instruments Cards', () => { .first() .contains('With piece reason late model.'); - cy.contains('[role="button"]', 'Name') - .click() - .wait('@getInstrumentsOrder', { timeout: 10000 }); + cy.contains('[role="button"]', 'Name').click(); cy.contains('[role="button"]', 'asc').should('not.exist'); cy.contains('[role="button"]', 'desc').should('not.exist'); cy.get('[data-testid="card"]') diff --git a/packages/datagateway-dataview/cypress/integration/card/isis/studies.spec.ts b/packages/datagateway-dataview/cypress/integration/card/isis/studies.spec.ts index 848576414..b98d45f9f 100644 --- a/packages/datagateway-dataview/cypress/integration/card/isis/studies.spec.ts +++ b/packages/datagateway-dataview/cypress/integration/card/isis/studies.spec.ts @@ -98,11 +98,7 @@ describe('ISIS - Studies Cards', () => { cy.contains('[role="button"]', 'desc').should('exist'); cy.get('[data-testid="card"]').first().contains('STUDY 314'); - cy.contains('[role="button"]', 'Start Date') - .click() - .wait('@getStudiesOrder', { - timeout: 10000, - }); + cy.contains('[role="button"]', 'Start Date').click(); cy.contains('[role="button"]', 'asc').should('not.exist'); cy.contains('[role="button"]', 'desc').should('not.exist'); cy.get('[data-testid="card"]').first().contains('STUDY 4'); diff --git a/packages/datagateway-dataview/cypress/integration/table/isis/datasets.spec.ts b/packages/datagateway-dataview/cypress/integration/table/isis/datasets.spec.ts index 87d60fdb2..36d958ac5 100644 --- a/packages/datagateway-dataview/cypress/integration/table/isis/datasets.spec.ts +++ b/packages/datagateway-dataview/cypress/integration/table/isis/datasets.spec.ts @@ -5,7 +5,7 @@ describe('ISIS - Datasets Table', () => { cy.login(); cy.visit( '/browse/instrument/1/facilityCycle/16/investigation/97/dataset' - ).wait(['@datasetsCount', '@datasetsOrder', '@datasetsOrder'], { + ).wait(['@datasetsCount', '@datasetsOrder'], { timeout: 10000, }); // Check that we have received the size from the API as this will produce diff --git a/packages/datagateway-dataview/package.json b/packages/datagateway-dataview/package.json index d0696330a..9d8cac9d4 100644 --- a/packages/datagateway-dataview/package.json +++ b/packages/datagateway-dataview/package.json @@ -1,6 +1,6 @@ { "name": "datagateway-dataview", - "version": "1.1.1", + "version": "1.1.2", "private": true, "dependencies": { "@material-ui/core": "^4.11.3", @@ -14,7 +14,7 @@ "axios": "^0.26.0", "connected-react-router": "^6.9.1", "custom-event-polyfill": "^1.0.7", - "datagateway-common": "^1.1.1", + "datagateway-common": "^1.1.2", "date-fns": "^2.28.0", "history": "^4.10.1", "i18next": "^21.6.13", diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.test.tsx index 2f0348231..b5f71418c 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.test.tsx @@ -106,14 +106,17 @@ describe('DLS Datasets - Card View', () => { }), }, ]); - expect(useDatasetsPaginated).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatasetsPaginated).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); }); it('updates filter query params on text filter', () => { @@ -170,6 +173,14 @@ describe('DLS Datasets - Card View', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"createTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatasetsPaginated).toHaveBeenCalledTimes(2); + expect(useDatasetsPaginated).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatasetsPaginated).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.tsx index 04c93531d..40d17caed 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsDatasetsCardView.component.tsx @@ -46,6 +46,14 @@ const DLSDatasetsCardView = (props: DLSDatasetsCVProps): React.ReactElement => { const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading } = useDatasetCount([ { filterType: 'where', @@ -54,14 +62,17 @@ const DLSDatasetsCardView = (props: DLSDatasetsCVProps): React.ReactElement => { }), }, ]); - const { data, isLoading: dataLoading } = useDatasetsPaginated([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + const { data, isLoading: dataLoading } = useDatasetsPaginated( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const datafileCountQueries = useDatasetsDatafileCount(data); diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.test.tsx index 14943b408..c280e6261 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.test.tsx @@ -108,7 +108,8 @@ describe('DLS Proposals - Card View', () => { filterValue: JSON.stringify(['name', 'title']), }, ], - true + true, + expect.any(Boolean) ); }); @@ -144,6 +145,19 @@ describe('DLS Proposals - Card View', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"title":"asc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInvestigationsPaginated).toHaveBeenCalledTimes(2); + expect(useInvestigationsPaginated).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + false + ); + expect(useInvestigationsPaginated).toHaveBeenLastCalledWith( + expect.anything(), + expect.anything(), + true + ); }); it('renders fine with incomplete data', () => { diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.tsx index 96ac083db..6830e1ffa 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsProposalsCardView.component.tsx @@ -31,6 +31,14 @@ const DLSProposalsCardView = (): React.ReactElement => { const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading, @@ -49,7 +57,8 @@ const DLSProposalsCardView = (): React.ReactElement => { ], // Do not add order by id as id is not a distinct field above and will otherwise // cause missing results - true + true, + isMounted ); const title: CardViewDetails = React.useMemo( diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.test.tsx index 7b5728e61..912d977e8 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.test.tsx @@ -106,18 +106,22 @@ describe('DLS Visits - Card View', () => { filterValue: JSON.stringify({ name: { eq: proposalName } }), }, ]); - expect(useInvestigationsPaginated).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ name: { eq: proposalName } }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - investigationInstruments: 'instrument', - }), - }, - ]); + expect(useInvestigationsPaginated).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ name: { eq: proposalName } }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + investigationInstruments: 'instrument', + }), + }, + ], + undefined, + expect.any(Boolean) + ); expect(useInvestigationsDatasetCount).toHaveBeenCalledWith(cardData); }); @@ -175,6 +179,19 @@ describe('DLS Visits - Card View', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"startDate":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInvestigationsPaginated).toHaveBeenCalledTimes(2); + expect(useInvestigationsPaginated).toHaveBeenCalledWith( + expect.anything(), + undefined, + false + ); + expect(useInvestigationsPaginated).toHaveBeenLastCalledWith( + expect.anything(), + undefined, + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.tsx index 7ad808e7d..a442f51b6 100644 --- a/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/dls/dlsVisitsCardView.component.tsx @@ -51,6 +51,14 @@ const DLSVisitsCardView = (props: DLSVisitsCVProps): React.ReactElement => { const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading, @@ -60,18 +68,22 @@ const DLSVisitsCardView = (props: DLSVisitsCVProps): React.ReactElement => { filterValue: JSON.stringify({ name: { eq: proposalName } }), }, ]); - const { isLoading: dataLoading, data } = useInvestigationsPaginated([ - { - filterType: 'where', - filterValue: JSON.stringify({ name: { eq: proposalName } }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - investigationInstruments: 'instrument', - }), - }, - ]); + const { isLoading: dataLoading, data } = useInvestigationsPaginated( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ name: { eq: proposalName } }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + investigationInstruments: 'instrument', + }), + }, + ], + undefined, + isMounted + ); const countQueries = useInvestigationsDatasetCount(data); const title = React.useMemo( diff --git a/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.test.tsx index cd3fe4043..9a9c75735 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.test.tsx @@ -113,14 +113,17 @@ describe('ISIS Datasets - Card View', () => { }), }, ]); - expect(useDatasetsPaginated).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatasetsPaginated).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); }); it('correct link used when NOT in studyHierarchy', () => { @@ -207,6 +210,14 @@ describe('ISIS Datasets - Card View', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"createTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatasetsPaginated).toHaveBeenCalledTimes(2); + expect(useDatasetsPaginated).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatasetsPaginated).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx index 111321113..26e13aa48 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx @@ -70,6 +70,14 @@ const ISISDatasetsCardView = ( const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading } = useDatasetCount([ { filterType: 'where', @@ -78,14 +86,17 @@ const ISISDatasetsCardView = ( }), }, ]); - const { data, isLoading: dataLoading } = useDatasetsPaginated([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + const { data, isLoading: dataLoading } = useDatasetsPaginated( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const sizeQueries = useDatasetSizes(data); const pathRoot = studyHierarchy ? 'browseStudyHierarchy' : 'browse'; diff --git a/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.test.tsx index f86854747..c222b9496 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.test.tsx @@ -98,7 +98,8 @@ describe('ISIS Facility Cycles - Card View', () => { createWrapper(); expect(useFacilityCycleCount).toHaveBeenCalledWith(parseInt(instrumentId)); expect(useFacilityCyclesPaginated).toHaveBeenCalledWith( - parseInt(instrumentId) + parseInt(instrumentId), + expect.any(Boolean) ); }); @@ -156,6 +157,17 @@ describe('ISIS Facility Cycles - Card View', () => { expect(replaceSpy).toHaveBeenCalledWith({ search: `?sort=${encodeURIComponent('{"startDate":"desc"}')}`, }); + + // check that the data request is sent only once after mounting + expect(useFacilityCyclesPaginated).toHaveBeenCalledTimes(2); + expect(useFacilityCyclesPaginated).toHaveBeenCalledWith( + expect.anything(), + false + ); + expect(useFacilityCyclesPaginated).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.tsx index 240273a87..d9f55752e 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisFacilityCyclesCardView.component.tsx @@ -41,12 +41,21 @@ const ISISFacilityCyclesCardView = ( const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading, } = useFacilityCycleCount(parseInt(instrumentId)); const { isLoading: dataLoading, data } = useFacilityCyclesPaginated( - parseInt(instrumentId) + parseInt(instrumentId), + isMounted ); const title: CardViewDetails = React.useMemo( diff --git a/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.test.tsx index 56c26e2d1..7cbf68aa0 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.test.tsx @@ -153,6 +153,11 @@ describe('ISIS Instruments - Card View', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"fullName":"asc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInstrumentsPaginated).toHaveBeenCalledTimes(2); + expect(useInstrumentsPaginated).toHaveBeenCalledWith(undefined, false); + expect(useInstrumentsPaginated).toHaveBeenLastCalledWith(undefined, true); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.tsx index 5fc12d675..cc3dd2c4b 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisInstrumentsCardView.component.tsx @@ -41,11 +41,22 @@ const ISISInstrumentsCardView = ( const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading, } = useInstrumentCount(); - const { isLoading: dataLoading, data } = useInstrumentsPaginated(); + const { isLoading: dataLoading, data } = useInstrumentsPaginated( + undefined, + isMounted + ); const title: CardViewDetails = React.useMemo(() => { const pathRoot = studyHierarchy ? 'browseStudyHierarchy' : 'browse'; diff --git a/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.test.tsx index 6005083ce..a42ed9a8a 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.test.tsx @@ -133,7 +133,8 @@ describe('ISIS Investigations - Card View', () => { expect(useISISInvestigationsPaginated).toHaveBeenCalledWith( parseInt(instrumentId), parseInt(instrumentChildId), - studyHierarchy + studyHierarchy, + expect.any(Boolean) ); expect(useInvestigationSizes).toHaveBeenCalledWith(cardData); }); @@ -236,6 +237,25 @@ describe('ISIS Investigations - Card View', () => { expect(replaceSpy).toHaveBeenCalledWith({ search: `?sort=${encodeURIComponent('{"startDate":"desc"}')}`, }); + + const instrumentId = '1'; + const instrumentChildId = '1'; + const studyHierarchy = false; + + // check that the data request is sent only once after mounting + expect(useISISInvestigationsPaginated).toHaveBeenCalledTimes(2); + expect(useISISInvestigationsPaginated).toHaveBeenCalledWith( + parseInt(instrumentId), + parseInt(instrumentChildId), + studyHierarchy, + false + ); + expect(useISISInvestigationsPaginated).toHaveBeenCalledWith( + parseInt(instrumentId), + parseInt(instrumentChildId), + studyHierarchy, + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx index 4ecf497a7..1497801b3 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx @@ -73,6 +73,14 @@ const ISISInvestigationsCardView = ( const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { data: totalDataCount, isLoading: countLoading, @@ -84,7 +92,8 @@ const ISISInvestigationsCardView = ( const { data, isLoading: dataLoading } = useISISInvestigationsPaginated( parseInt(instrumentId), parseInt(instrumentChildId), - studyHierarchy + studyHierarchy, + isMounted ); const sizeQueries = useInvestigationSizes(data); diff --git a/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.test.tsx index e9de877ff..60395ec49 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.test.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.test.tsx @@ -120,30 +120,33 @@ describe('ISIS Studies - Card View', () => { }), }, ]); - expect(useStudiesPaginated).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.investigationInstruments.instrument.id': { - eq: instrumentId, - }, - }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.releaseDate': { - lt: '2021-10-27 00:00:00', - }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - studyInvestigations: 'investigation', - }), - }, - ]); + expect(useStudiesPaginated).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.investigationInstruments.instrument.id': { + eq: instrumentId, + }, + }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.releaseDate': { + lt: '2021-10-27 00:00:00', + }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + studyInvestigations: 'investigation', + }), + }, + ], + expect.any(Boolean) + ); }); it('displays Experiment DOI (PID) and renders the expected Link ', () => { @@ -170,6 +173,14 @@ describe('ISIS Studies - Card View', () => { '{"studyInvestigations.investigation.startDate":"desc"}' )}` ); + + // check that the data request is sent only once after mounting + expect(useStudiesPaginated).toHaveBeenCalledTimes(2); + expect(useStudiesPaginated).toHaveBeenCalledWith(expect.anything(), false); + expect(useStudiesPaginated).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates filter query params on text filter', () => { diff --git a/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.tsx index d49b23ec2..366ebb7ca 100644 --- a/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.tsx +++ b/packages/datagateway-dataview/src/views/card/isis/isisStudiesCardView.component.tsx @@ -44,6 +44,14 @@ const ISISStudiesCardView = (props: ISISStudiesCVProps): React.ReactElement => { const pushPage = usePushPage(); const pushResults = usePushResults(); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const unembargoDate = format( // set s and ms to 0 to escape recursive loop of fetching data every time they change set(new Date(), { seconds: 0, milliseconds: 0 }), @@ -69,31 +77,34 @@ const ISISStudiesCardView = (props: ISISStudiesCVProps): React.ReactElement => { }), }, ]); - const { isLoading: dataLoading, data } = useStudiesPaginated([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.investigationInstruments.instrument.id': { - eq: instrumentId, - }, - }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - // this matches the ISIS ICAT rule - 'studyInvestigations.investigation.releaseDate': { - lt: unembargoDate, - }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - studyInvestigations: 'investigation', - }), - }, - ]); + const { isLoading: dataLoading, data } = useStudiesPaginated( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.investigationInstruments.instrument.id': { + eq: instrumentId, + }, + }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + // this matches the ISIS ICAT rule + 'studyInvestigations.investigation.releaseDate': { + lt: unembargoDate, + }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + studyInvestigations: 'investigation', + }), + }, + ], + isMounted + ); const title = React.useMemo(() => { const pathRoot = 'browseStudyHierarchy'; diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.test.tsx index 8c5824cde..73ebee47d 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.test.tsx @@ -128,18 +128,21 @@ describe('DLS datafiles table component', () => { }), }, ]); - expect(useDatafilesInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'dataset.investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatafilesInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'dataset.investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); expect(useIds).toHaveBeenCalledWith( 'datafile', [ @@ -233,6 +236,14 @@ describe('DLS datafiles table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"createTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatafilesInfinite).toHaveBeenCalledTimes(2); + expect(useDatafilesInfinite).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatafilesInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.tsx index 53121cd12..ab541e321 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsDatafilesTable.component.tsx @@ -91,18 +91,29 @@ const DLSDatafilesTable = ( }, ]); - const { fetchNextPage, data } = useDatafilesInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'dataset.investigation.id': { eq: investigationId }, - }), - }, - ]); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useDatafilesInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'dataset.investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const loadMoreRows = React.useCallback( (offsetParams: IndexRange) => fetchNextPage({ pageParam: offsetParams }), diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.test.tsx index e8b232644..4cd0057b9 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.test.tsx @@ -125,14 +125,17 @@ describe('DLS Dataset table component', () => { }), }, ]); - expect(useDatasetsInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatasetsInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); expect(useDatasetsDatafileCount).toHaveBeenCalledWith({ pages: [rowData], }); @@ -223,6 +226,14 @@ describe('DLS Dataset table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"createTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatasetsInfinite).toHaveBeenCalledTimes(2); + expect(useDatasetsInfinite).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatasetsInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.tsx index b42544240..1a917f13b 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsDatasetsTable.component.tsx @@ -82,14 +82,25 @@ const DLSDatasetsTable = (props: DLSDatasetsTableProps): React.ReactElement => { }, ]); - const { fetchNextPage, data } = useDatasetsInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useDatasetsInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const loadMoreRows = React.useCallback( (offsetParams: IndexRange) => fetchNextPage({ pageParam: offsetParams }), diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.test.tsx index 7aa6fb94e..ae2dbbf05 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.test.tsx @@ -127,22 +127,26 @@ describe('DLS MyData table component', () => { }), }, ]); - expect(useInvestigationsInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigationUsers.user.name': { eq: 'testUser' }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify([ - { - investigationInstruments: 'instrument', - }, - ]), - }, - ]); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigationUsers.user.name': { eq: 'testUser' }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify([ + { + investigationInstruments: 'instrument', + }, + ]), + }, + ], + undefined, + expect.any(Boolean) + ); expect(useInvestigationsDatasetCount).toHaveBeenCalledWith({ pages: [rowData], }); diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.tsx index 07deb492e..9f8279884 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsMyDataTable.component.tsx @@ -44,22 +44,35 @@ const DLSMyDataTable = (): React.ReactElement => { }), }, ]); - const { fetchNextPage, data } = useInvestigationsInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigationUsers.user.name': { eq: username }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify([ - { - investigationInstruments: 'instrument', - }, - ]), - }, - ]); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useInvestigationsInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigationUsers.user.name': { eq: username }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify([ + { + investigationInstruments: 'instrument', + }, + ]), + }, + ], + undefined, + isMounted + ); const datasetCountQueries = useInvestigationsDatasetCount(data); diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.test.tsx index b00b593a0..7ccdf2058 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.test.tsx @@ -117,7 +117,8 @@ describe('DLS Proposals table component', () => { filterValue: JSON.stringify(['name', 'title']), }, ], - true + true, + expect.any(Boolean) ); }); @@ -168,6 +169,19 @@ describe('DLS Proposals table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"title":"asc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInvestigationsInfinite).toHaveBeenCalledTimes(2); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + false + ); + expect(useInvestigationsInfinite).toHaveBeenLastCalledWith( + expect.anything(), + expect.anything(), + true + ); }); it('renders title and name as links', () => { diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.tsx index 5f185b508..55d6d008a 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsProposalsTable.component.tsx @@ -30,6 +30,15 @@ const DLSProposalsTable = (): React.ReactElement => { filterValue: JSON.stringify(['name', 'title']), }, ]); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { fetchNextPage, data } = useInvestigationsInfinite( [ { @@ -39,7 +48,8 @@ const DLSProposalsTable = (): React.ReactElement => { ], // Do not add order by id as id is not a distinct field above and will otherwise // cause missing results - true + true, + isMounted ); const aggregatedData: Investigation[] = React.useMemo( diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.test.tsx index cb28db435..a2dbdaf87 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.test.tsx @@ -115,18 +115,22 @@ describe('DLS Visits table component', () => { filterValue: JSON.stringify({ name: { eq: proposalName } }), }, ]); - expect(useInvestigationsInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ name: { eq: proposalName } }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - investigationInstruments: 'instrument', - }), - }, - ]); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ name: { eq: proposalName } }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + investigationInstruments: 'instrument', + }), + }, + ], + undefined, + expect.any(Boolean) + ); expect(useInvestigationsDatasetCount).toHaveBeenCalledWith(rowData); }); @@ -200,6 +204,19 @@ describe('DLS Visits table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"startDate":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInvestigationsInfinite).toHaveBeenCalledTimes(2); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + expect.anything(), + undefined, + false + ); + expect(useInvestigationsInfinite).toHaveBeenLastCalledWith( + expect.anything(), + undefined, + true + ); }); it('updates sort query params on sort', () => { @@ -233,17 +250,17 @@ describe('DLS Visits table component', () => { }); it('renders fine with incomplete data', () => { - (useInvestigationCount as jest.Mock).mockReturnValueOnce({}); - (useInvestigationsInfinite as jest.Mock).mockReturnValueOnce({}); - (useInvestigationsDatasetCount as jest.Mock).mockReturnValueOnce([]); + (useInvestigationCount as jest.Mock).mockReturnValue({}); + (useInvestigationsInfinite as jest.Mock).mockReturnValue({}); + (useInvestigationsDatasetCount as jest.Mock).mockReturnValue([]); expect(() => createWrapper()).not.toThrowError(); - (useInvestigationCount as jest.Mock).mockReturnValueOnce({ + (useInvestigationCount as jest.Mock).mockReturnValue({ data: 1, isLoading: false, }); - (useInvestigationsInfinite as jest.Mock).mockReturnValueOnce({ + (useInvestigationsInfinite as jest.Mock).mockReturnValue({ data: [ { ...rowData[0], @@ -252,11 +269,11 @@ describe('DLS Visits table component', () => { ], isLoading: false, }); - (useInvestigationsDatasetCount as jest.Mock).mockReturnValueOnce([1]); + (useInvestigationsDatasetCount as jest.Mock).mockReturnValue([1]); expect(() => createWrapper()).not.toThrowError(); - (useInvestigationsInfinite as jest.Mock).mockReturnValueOnce({ + (useInvestigationsInfinite as jest.Mock).mockReturnValue({ data: [ { ...rowData[0], diff --git a/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.tsx b/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.tsx index 08a3b59e5..a3b6832b7 100644 --- a/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/dls/dlsVisitsTable.component.tsx @@ -43,18 +43,31 @@ const DLSVisitsTable = (props: DLSVisitsTableProps): React.ReactElement => { filterValue: JSON.stringify({ name: { eq: proposalName } }), }, ]); - const { fetchNextPage, data } = useInvestigationsInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ name: { eq: proposalName } }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - investigationInstruments: 'instrument', - }), - }, - ]); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useInvestigationsInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ name: { eq: proposalName } }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + investigationInstruments: 'instrument', + }), + }, + ], + undefined, + isMounted + ); const datasetCountQueries = useInvestigationsDatasetCount(data); diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.test.tsx index 4e7f33ca9..7efd7b9f8 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.test.tsx @@ -128,18 +128,21 @@ describe('ISIS datafiles table component', () => { }), }, ]); - expect(useDatafilesInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'dataset.investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatafilesInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'dataset.investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); expect(useIds).toHaveBeenCalledWith( 'datafile', [ @@ -231,6 +234,14 @@ describe('ISIS datafiles table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"modTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatafilesInfinite).toHaveBeenCalledTimes(2); + expect(useDatafilesInfinite).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatafilesInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.tsx index 590a60de2..7c78899f1 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisDatafilesTable.component.tsx @@ -93,18 +93,29 @@ const ISISDatafilesTable = ( }, ]); - const { fetchNextPage, data } = useDatafilesInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'dataset.investigation.id': { eq: investigationId }, - }), - }, - ]); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useDatafilesInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ 'dataset.id': { eq: datasetId } }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'dataset.investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const loadMoreRows = React.useCallback( (offsetParams: IndexRange) => fetchNextPage({ pageParam: offsetParams }), diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.test.tsx index 1ed842acf..362fd33d6 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.test.tsx @@ -136,14 +136,17 @@ describe('ISIS Dataset table component', () => { }), }, ]); - expect(useDatasetsInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + expect(useDatasetsInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + expect.any(Boolean) + ); expect(useDatasetSizes).toHaveBeenCalledWith({ pages: [rowData], }); @@ -234,6 +237,14 @@ describe('ISIS Dataset table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"createTime":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useDatasetsInfinite).toHaveBeenCalledTimes(2); + expect(useDatasetsInfinite).toHaveBeenCalledWith(expect.anything(), false); + expect(useDatasetsInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx index bd5ad98c0..02cd0fa62 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx @@ -99,14 +99,25 @@ const ISISDatasetsTable = ( }, ]); - const { fetchNextPage, data } = useDatasetsInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigation.id': { eq: investigationId }, - }), - }, - ]); + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useDatasetsInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigation.id': { eq: investigationId }, + }), + }, + ], + isMounted + ); const loadMoreRows = React.useCallback( (offsetParams: IndexRange) => fetchNextPage({ pageParam: offsetParams }), diff --git a/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.test.tsx index d921e858b..ce2d83508 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.test.tsx @@ -96,7 +96,8 @@ describe('ISIS FacilityCycles table component', () => { createWrapper(); expect(useFacilityCycleCount).toHaveBeenCalledWith(parseInt(instrumentId)); expect(useFacilityCyclesInfinite).toHaveBeenCalledWith( - parseInt(instrumentId) + parseInt(instrumentId), + expect.any(Boolean) ); }); @@ -170,6 +171,17 @@ describe('ISIS FacilityCycles table component', () => { expect(replaceSpy).toHaveBeenCalledWith({ search: `?sort=${encodeURIComponent('{"startDate":"desc"}')}`, }); + + // check that the data request is sent only once after mounting + expect(useFacilityCyclesInfinite).toHaveBeenCalledTimes(2); + expect(useFacilityCyclesInfinite).toHaveBeenCalledWith( + expect.anything(), + false + ); + expect(useFacilityCyclesInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.tsx index 0f61170fd..fed442967 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisFacilityCyclesTable.component.tsx @@ -37,8 +37,18 @@ const ISISFacilityCyclesTable = ( const { data: totalDataCount } = useFacilityCycleCount( parseInt(instrumentId) ); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { fetchNextPage, data } = useFacilityCyclesInfinite( - parseInt(instrumentId) + parseInt(instrumentId), + isMounted ); const aggregatedData: FacilityCycle[] = React.useMemo( diff --git a/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.test.tsx index a88c665c6..a90f25034 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.test.tsx @@ -149,6 +149,11 @@ describe('ISIS Instruments table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"fullName":"asc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInstrumentsInfinite).toHaveBeenCalledTimes(2); + expect(useInstrumentsInfinite).toHaveBeenCalledWith(undefined, false); + expect(useInstrumentsInfinite).toHaveBeenLastCalledWith(undefined, true); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.tsx index 106b94fe7..3d2545339 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisInstrumentsTable.component.tsx @@ -34,7 +34,16 @@ const ISISInstrumentsTable = ( ); const { data: totalDataCount } = useInstrumentCount(); - const { fetchNextPage, data } = useInstrumentsInfinite(); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useInstrumentsInfinite(undefined, isMounted); const aggregatedData: Instrument[] = React.useMemo( () => (data ? ('pages' in data ? data.pages.flat() : data) : []), diff --git a/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.test.tsx index 281ce55b1..72761debd 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.test.tsx @@ -173,7 +173,8 @@ describe('ISIS Investigations table component', () => { expect(useISISInvestigationsInfinite).toHaveBeenCalledWith( parseInt(instrumentId), parseInt(instrumentChildId), - studyHierarchy + studyHierarchy, + expect.any(Boolean) ); expect(useInvestigationSizes).toHaveBeenCalledWith({ pages: [rowData], @@ -278,6 +279,25 @@ describe('ISIS Investigations table component', () => { expect(replaceSpy).toHaveBeenCalledWith({ search: `?sort=${encodeURIComponent('{"startDate":"desc"}')}`, }); + + const studyHierarchy = false; + const instrumentId = '4'; + const instrumentChildId = '5'; + + // check that the data request is sent only once after mounting + expect(useISISInvestigationsInfinite).toHaveBeenCalledTimes(2); + expect(useISISInvestigationsInfinite).toHaveBeenCalledWith( + parseInt(instrumentId), + parseInt(instrumentChildId), + studyHierarchy, + false + ); + expect(useISISInvestigationsInfinite).toHaveBeenCalledWith( + parseInt(instrumentId), + parseInt(instrumentChildId), + studyHierarchy, + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx index 0b71993ae..5a73bf9fc 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx @@ -62,10 +62,20 @@ const ISISInvestigationsTable = ( parseInt(instrumentChildId), studyHierarchy ); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + const { fetchNextPage, data } = useISISInvestigationsInfinite( parseInt(instrumentId), parseInt(instrumentChildId), - studyHierarchy + studyHierarchy, + isMounted ); const { data: allIds } = useISISInvestigationIds( parseInt(instrumentId), diff --git a/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.test.tsx index 70a6e1cb3..c64e819d9 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.test.tsx @@ -190,23 +190,27 @@ describe('ISIS MyData table component', () => { }), }, ]); - expect(useInvestigationsInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigationUsers.user.name': { eq: 'testUser' }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify([ - { - investigationInstruments: 'instrument', - }, - { studyInvestigations: 'study' }, - ]), - }, - ]); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigationUsers.user.name': { eq: 'testUser' }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify([ + { + investigationInstruments: 'instrument', + }, + { studyInvestigations: 'study' }, + ]), + }, + ], + undefined, + expect.any(Boolean) + ); expect(useInvestigationSizes).toHaveBeenCalledWith({ pages: [rowData], }); @@ -308,6 +312,19 @@ describe('ISIS MyData table component', () => { expect(history.location.search).toBe( `?sort=${encodeURIComponent('{"startDate":"desc"}')}` ); + + // check that the data request is sent only once after mounting + expect(useInvestigationsInfinite).toHaveBeenCalledTimes(2); + expect(useInvestigationsInfinite).toHaveBeenCalledWith( + expect.anything(), + undefined, + false + ); + expect(useInvestigationsInfinite).toHaveBeenLastCalledWith( + expect.anything(), + undefined, + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.tsx index a35f335ae..102d43799 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisMyDataTable.component.tsx @@ -56,23 +56,36 @@ const ISISMyDataTable = (): React.ReactElement => { }), }, ]); - const { fetchNextPage, data } = useInvestigationsInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'investigationUsers.user.name': { eq: username }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify([ - { - investigationInstruments: 'instrument', - }, - { studyInvestigations: 'study' }, - ]), - }, - ]); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useInvestigationsInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'investigationUsers.user.name': { eq: username }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify([ + { + investigationInstruments: 'instrument', + }, + { studyInvestigations: 'study' }, + ]), + }, + ], + undefined, + isMounted + ); const { data: allIds } = useIds( 'investigation', [ diff --git a/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.test.tsx index f171e5f38..befb27a48 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.test.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.test.tsx @@ -117,30 +117,33 @@ describe('ISIS Studies table component', () => { }), }, ]); - expect(useStudiesInfinite).toHaveBeenCalledWith([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.investigationInstruments.instrument.id': { - eq: instrumentId, - }, - }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.releaseDate': { - lt: '2021-10-27 00:00:00', - }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - studyInvestigations: 'investigation', - }), - }, - ]); + expect(useStudiesInfinite).toHaveBeenCalledWith( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.investigationInstruments.instrument.id': { + eq: instrumentId, + }, + }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.releaseDate': { + lt: '2021-10-27 00:00:00', + }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + studyInvestigations: 'investigation', + }), + }, + ], + expect.any(Boolean) + ); }); it('calls useStudiesInfinite when loadMoreRows is called', () => { @@ -214,6 +217,14 @@ describe('ISIS Studies table component', () => { '{"studyInvestigations.investigation.startDate":"desc"}' )}` ); + + // check that the data request is sent only once after mounting + expect(useStudiesInfinite).toHaveBeenCalledTimes(2); + expect(useStudiesInfinite).toHaveBeenCalledWith(expect.anything(), false); + expect(useStudiesInfinite).toHaveBeenLastCalledWith( + expect.anything(), + true + ); }); it('updates sort query params on sort', () => { diff --git a/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.tsx index 2c34c1358..a25f701cd 100644 --- a/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.tsx +++ b/packages/datagateway-dataview/src/views/table/isis/isisStudiesTable.component.tsx @@ -63,31 +63,43 @@ const ISISStudiesTable = (props: ISISStudiesTableProps): React.ReactElement => { }), }, ]); - const { fetchNextPage, data } = useStudiesInfinite([ - { - filterType: 'where', - filterValue: JSON.stringify({ - 'studyInvestigations.investigation.investigationInstruments.instrument.id': { - eq: instrumentId, - }, - }), - }, - { - filterType: 'where', - filterValue: JSON.stringify({ - // this matches the ISIS ICAT rule - 'studyInvestigations.investigation.releaseDate': { - lt: unembargoDate, - }, - }), - }, - { - filterType: 'include', - filterValue: JSON.stringify({ - studyInvestigations: 'investigation', - }), - }, - ]); + + // isMounted is used to disable queries when the component isn't fully mounted. + // It prevents the request being sent twice if default sort is set. + // It is not needed for cards/tables that don't have default sort. + const [isMounted, setIsMounted] = React.useState(false); + React.useEffect(() => { + setIsMounted(true); + }, []); + + const { fetchNextPage, data } = useStudiesInfinite( + [ + { + filterType: 'where', + filterValue: JSON.stringify({ + 'studyInvestigations.investigation.investigationInstruments.instrument.id': { + eq: instrumentId, + }, + }), + }, + { + filterType: 'where', + filterValue: JSON.stringify({ + // this matches the ISIS ICAT rule + 'studyInvestigations.investigation.releaseDate': { + lt: unembargoDate, + }, + }), + }, + { + filterType: 'include', + filterValue: JSON.stringify({ + studyInvestigations: 'investigation', + }), + }, + ], + isMounted + ); const aggregatedData: Study[] = React.useMemo( () => (data ? ('pages' in data ? data.pages.flat() : data) : []), diff --git a/packages/datagateway-download/package.json b/packages/datagateway-download/package.json index 868d2a831..2138e37c9 100644 --- a/packages/datagateway-download/package.json +++ b/packages/datagateway-download/package.json @@ -1,6 +1,6 @@ { "name": "datagateway-download", - "version": "1.1.1", + "version": "1.1.2", "private": true, "dependencies": { "@material-ui/core": "^4.11.3", @@ -11,7 +11,7 @@ "@types/react": "^17.0.2", "@types/react-dom": "^17.0.1", "axios": "^0.26.0", - "datagateway-common": "^1.1.1", + "datagateway-common": "^1.1.2", "date-fns": "^2.28.0", "date-fns-tz": "^1.1.6", "history": "^4.10.1", diff --git a/packages/datagateway-search/package.json b/packages/datagateway-search/package.json index 930146f89..c16cb3f59 100644 --- a/packages/datagateway-search/package.json +++ b/packages/datagateway-search/package.json @@ -1,6 +1,6 @@ { "name": "datagateway-search", - "version": "1.1.1", + "version": "1.1.2", "private": true, "dependencies": { "@date-io/date-fns": "^1.3.13", @@ -14,7 +14,7 @@ "axios": "^0.26.0", "connected-react-router": "^6.9.1", "custom-event-polyfill": "^1.0.7", - "datagateway-common": "^1.1.1", + "datagateway-common": "^1.1.2", "date-fns": "^2.28.0", "history": "^4.10.1", "i18next": "^21.6.13", diff --git a/packages/datagateway-search/src/__snapshots__/searchPageCardView.component.test.tsx.snap b/packages/datagateway-search/src/__snapshots__/searchPageCardView.component.test.tsx.snap index c6098f6e7..e34a5cfa8 100644 --- a/packages/datagateway-search/src/__snapshots__/searchPageCardView.component.test.tsx.snap +++ b/packages/datagateway-search/src/__snapshots__/searchPageCardView.component.test.tsx.snap @@ -1583,6 +1583,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` }, "currentResultOptions": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -1628,6 +1629,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` ], "options": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -1665,6 +1667,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` ], "options": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -2659,6 +2662,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` }, "currentResultOptions": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -2704,6 +2708,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` ], "options": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -2741,6 +2746,7 @@ exports[`SearchPageCardView renders correctly when request received 1`] = ` ], "options": Object { "_defaulted": true, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], diff --git a/packages/datagateway-search/src/__snapshots__/searchPageTable.component.test.tsx.snap b/packages/datagateway-search/src/__snapshots__/searchPageTable.component.test.tsx.snap index 2eac199de..d7f8ce281 100644 --- a/packages/datagateway-search/src/__snapshots__/searchPageTable.component.test.tsx.snap +++ b/packages/datagateway-search/src/__snapshots__/searchPageTable.component.test.tsx.snap @@ -1592,6 +1592,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -1640,6 +1641,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -1678,6 +1680,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -3148,6 +3151,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -3196,6 +3200,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function], @@ -3234,6 +3239,7 @@ exports[`SearchPageTable renders correctly when request received 1`] = ` "behavior": Object { "onFetch": [Function], }, + "enabled": true, "onError": [Function], "optimisticResults": true, "queryFn": [Function],