diff --git a/packages/datagateway-common/src/api/dataPublications.test.tsx b/packages/datagateway-common/src/api/dataPublications.test.tsx
index 660515e45..d3d5e08c5 100644
--- a/packages/datagateway-common/src/api/dataPublications.test.tsx
+++ b/packages/datagateway-common/src/api/dataPublications.test.tsx
@@ -9,6 +9,7 @@ import {
useDataPublicationsInfinite,
useDataPublicationsPaginated,
useDataPublication,
+ useDataPublications,
} from './dataPublications';
jest.mock('../handleICATError');
@@ -276,7 +277,7 @@ describe('data publications api functions', () => {
describe('useDataPublication', () => {
it('sends axios request to fetch a single data publication and returns successful response', async () => {
(axios.get as jest.Mock).mockResolvedValue({
- data: mockData[0],
+ data: mockData,
});
const { result, waitFor } = renderHook(() => useDataPublication(1), {
@@ -292,18 +293,26 @@ describe('data publications api functions', () => {
id: { eq: 1 },
})
);
- params.append('include', JSON.stringify('users'));
params.append(
'include',
- JSON.stringify({
- content: {
- dataCollectionInvestigations: {
- investigation: {
- investigationInstruments: 'instrument',
+ JSON.stringify([
+ {
+ content: {
+ dataCollectionInvestigations: {
+ investigation: [
+ 'datasets',
+ {
+ datasets: 'type',
+ investigationInstruments: 'instrument',
+ },
+ ],
},
},
},
- })
+ 'users',
+ 'facility',
+ 'dates',
+ ])
);
expect(axios.get).toHaveBeenCalledWith(
@@ -335,20 +344,105 @@ describe('data publications api functions', () => {
id: { eq: 1 },
})
);
- params.append('include', JSON.stringify('users'));
params.append(
'include',
- JSON.stringify({
- content: {
- dataCollectionInvestigations: {
- investigation: {
- investigationInstruments: 'instrument',
+ JSON.stringify([
+ {
+ content: {
+ dataCollectionInvestigations: {
+ investigation: [
+ 'datasets',
+ {
+ datasets: 'type',
+ investigationInstruments: 'instrument',
+ },
+ ],
},
},
},
+ 'users',
+ 'facility',
+ 'dates',
+ ])
+ );
+
+ expect(axios.get).toHaveBeenCalledWith(
+ 'https://example.com/api/datapublications',
+ expect.objectContaining({
+ params,
+ })
+ );
+ expect((axios.get as jest.Mock).mock.calls[0][1].params.toString()).toBe(
+ params.toString()
+ );
+ expect(handleICATError).toHaveBeenCalledWith({ message: 'Test error' });
+ });
+ });
+
+ describe('useDataPublications', () => {
+ it('sends axios request to fetch a data publications with specified filters and returns successful response', async () => {
+ (axios.get as jest.Mock).mockResolvedValue({
+ data: mockData,
+ });
+
+ params.append('order', JSON.stringify('id asc'));
+ params.append(
+ 'where',
+ JSON.stringify({
+ name: { eq: 'test' },
})
);
+ const { result, waitFor } = renderHook(
+ () =>
+ useDataPublications([
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({ name: { eq: 'test' } }),
+ },
+ ]),
+ {
+ wrapper: createReactQueryWrapper(history),
+ }
+ );
+
+ await waitFor(() => result.current.isSuccess);
+
+ expect(axios.get).toHaveBeenCalledWith(
+ 'https://example.com/api/datapublications',
+ expect.objectContaining({
+ params,
+ })
+ );
+ expect((axios.get as jest.Mock).mock.calls[0][1].params.toString()).toBe(
+ params.toString()
+ );
+ expect(result.current.data).toEqual(mockData);
+ });
+
+ it('sends axios request to fetch a single data publication and calls handleICATError on failure', async () => {
+ (axios.get as jest.Mock).mockRejectedValue({
+ message: 'Test error',
+ });
+
+ params.append('order', JSON.stringify('id asc'));
+ params.append('include', '"type"');
+
+ const { result, waitFor } = renderHook(
+ () =>
+ useDataPublications([
+ {
+ filterType: 'include',
+ filterValue: '"type"',
+ },
+ ]),
+ {
+ wrapper: createReactQueryWrapper(history),
+ }
+ );
+
+ await waitFor(() => result.current.isError);
+
expect(axios.get).toHaveBeenCalledWith(
'https://example.com/api/datapublications',
expect.objectContaining({
diff --git a/packages/datagateway-common/src/api/dataPublications.tsx b/packages/datagateway-common/src/api/dataPublications.tsx
index 43226735a..3d2ba5f0b 100644
--- a/packages/datagateway-common/src/api/dataPublications.tsx
+++ b/packages/datagateway-common/src/api/dataPublications.tsx
@@ -9,6 +9,7 @@ import {
useQuery,
UseInfiniteQueryResult,
useInfiniteQuery,
+ UseQueryOptions,
} from 'react-query';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
@@ -144,16 +145,17 @@ export const useDataPublicationsInfinite = (
};
export const useDataPublication = (
- dataPublicationId: number
-): UseQueryResult => {
- const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl);
-
- return useQuery<
+ dataPublicationId: number,
+ queryOptions?: UseQueryOptions<
DataPublication[],
AxiosError,
- DataPublication[],
+ DataPublication,
[string, number]
- >(
+ >
+): UseQueryResult => {
+ const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl);
+
+ return useQuery(
['dataPublication', dataPublicationId],
() => {
return fetchDataPublications(apiUrl, { sort: {}, filters: {} }, [
@@ -165,22 +167,57 @@ export const useDataPublication = (
},
{
filterType: 'include',
- filterValue: JSON.stringify('users'),
- },
- {
- filterType: 'include',
- filterValue: JSON.stringify({
- content: {
- dataCollectionInvestigations: {
- investigation: {
- investigationInstruments: 'instrument',
+ filterValue: JSON.stringify([
+ {
+ content: {
+ dataCollectionInvestigations: {
+ investigation: [
+ 'datasets',
+ {
+ datasets: 'type',
+ investigationInstruments: 'instrument',
+ },
+ ],
},
},
},
- }),
+ 'users',
+ 'facility',
+ 'dates',
+ ]),
},
]);
},
+ {
+ onError: (error) => {
+ handleICATError(error);
+ },
+ retry: retryICATErrors,
+ select: (data) => data[0],
+ ...queryOptions,
+ }
+ );
+};
+
+export const useDataPublications = (
+ additionalFilters: AdditionalFilters
+): UseQueryResult => {
+ const apiUrl = useSelector((state: StateType) => state.dgcommon.urls.apiUrl);
+
+ return useQuery<
+ DataPublication[],
+ AxiosError,
+ DataPublication[],
+ [string, AdditionalFilters?]
+ >(
+ ['dataPublication', additionalFilters],
+ (params) => {
+ return fetchDataPublications(
+ apiUrl,
+ { sort: {}, filters: {} },
+ additionalFilters
+ );
+ },
{
onError: (error) => {
handleICATError(error);
diff --git a/packages/datagateway-common/src/app.types.tsx b/packages/datagateway-common/src/app.types.tsx
index 4fdfe2cb0..13b0a70a3 100644
--- a/packages/datagateway-common/src/app.types.tsx
+++ b/packages/datagateway-common/src/app.types.tsx
@@ -153,8 +153,8 @@ export interface DataCollectionDataset {
export interface DataCollectionInvestigation {
id: number;
- dataCollection: DataCollection;
- investigation: Investigation;
+ dataCollection?: DataCollection;
+ investigation?: Investigation;
}
export interface DataCollection {
@@ -171,16 +171,21 @@ export interface DataPublicationUser {
fullName: string;
}
+export interface DataPublicationType {
+ id: number;
+ name: string;
+}
+
export interface DataPublication {
id: number;
pid: string;
title: string;
- modTime: string;
- createTime: string;
+ facility?: Facility;
description?: string;
publicationDate?: string;
users?: DataPublicationUser[];
content?: DataCollection;
+ type?: DataPublicationType;
}
interface InstrumentScientist {
diff --git a/packages/datagateway-common/src/detailsPanels/isis/__snapshots__/investigationDetailsPanel.component.test.tsx.snap b/packages/datagateway-common/src/detailsPanels/isis/__snapshots__/investigationDetailsPanel.component.test.tsx.snap
index b7a0ee2bf..5d59a3455 100644
--- a/packages/datagateway-common/src/detailsPanels/isis/__snapshots__/investigationDetailsPanel.component.test.tsx.snap
+++ b/packages/datagateway-common/src/detailsPanels/isis/__snapshots__/investigationDetailsPanel.component.test.tsx.snap
@@ -143,9 +143,9 @@ exports[`Investigation details panel component should check if multiple publicat
- Data Publication Pid
+ Data Publication Study Pid
@@ -388,9 +388,9 @@ exports[`Investigation details panel component should check if multiple samples
- Data Publication Pid
+ Data Publication Study Pid
@@ -822,9 +822,9 @@ exports[`Investigation details panel component should render correctly 1`] = `
- Data Publication Pid
+ Data Publication Study Pid
@@ -1057,9 +1057,9 @@ exports[`Investigation details panel component should render user, sample and pu
- Data Publication Pid
+ Data Publication Study Pid
diff --git a/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.test.tsx b/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.test.tsx
index f1b47de56..9cd2bc9eb 100644
--- a/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.test.tsx
+++ b/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.test.tsx
@@ -1,6 +1,5 @@
import { render, RenderResult, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { UserEvent } from '@testing-library/user-event/dist/types/setup';
import axios from 'axios';
import * as React from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
@@ -40,7 +39,7 @@ function renderComponent({
describe('Investigation details panel component', () => {
let rowData: Investigation;
- let user: UserEvent;
+ let user: ReturnType;
beforeEach(() => {
user = userEvent.setup();
@@ -80,6 +79,36 @@ describe('Investigation details panel component', () => {
modTime: '2019-06-10',
createTime: '2019-06-11',
title: 'Data Publication',
+ type: {
+ id: 15,
+ name: 'investigation',
+ },
+ },
+ ],
+ },
+ },
+ {
+ id: 2,
+ investigation: {
+ id: 1,
+ title: 'Test 1',
+ name: 'Test 1',
+ visitId: '1',
+ },
+ dataCollection: {
+ id: 13,
+ dataPublications: [
+ {
+ id: 14,
+ pid: 'Data Publication Study Pid',
+ description: 'Data Publication description',
+ modTime: '2019-06-10',
+ createTime: '2019-06-11',
+ title: 'Data Publication Study',
+ type: {
+ id: 16,
+ name: 'study',
+ },
},
],
},
@@ -322,6 +351,16 @@ describe('Investigation details panel component', () => {
expect(link).toHaveTextContent('doi 1');
expect(link).toHaveAttribute('href', 'https://doi.org/doi 1');
+
+ const link2 = await screen.findByRole('link', {
+ name: /Data Publication Study Pid/,
+ });
+
+ expect(link2).toHaveTextContent('Data Publication Study Pid');
+ expect(link2).toHaveAttribute(
+ 'href',
+ 'https://doi.org/Data Publication Study Pid'
+ );
});
it('should gracefully handles dataCollectionInvestigations without dataPublications and InvestigationUsers without Users', () => {
diff --git a/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.tsx b/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.tsx
index 526fc145e..4a12ea725 100644
--- a/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.tsx
+++ b/packages/datagateway-common/src/detailsPanels/isis/investigationDetailsPanel.component.tsx
@@ -94,6 +94,11 @@ const InvestigationDetailsPanel = (
}
}, [data, selectedTab, changeTab]);
+ const studyDataPublication =
+ investigationData.dataCollectionInvestigations?.filter(
+ (dci) => dci.dataCollection?.dataPublications?.[0]?.type?.name === 'study'
+ )?.[0]?.dataCollection?.dataPublications?.[0];
+
return (
- {/* TODO: when datapublications are created for studies, need to pick the study datapublication */}
- {investigationData.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications &&
- investigationData.dataCollectionInvestigations[0].dataCollection.dataPublications.map(
- (dataPublication) => {
- if (dataPublication) {
- return (
-
-
- {t('investigations.details.pid')}
-
-
-
- {dataPublication.pid}
-
-
-
- );
- } else {
- return null;
- }
- }
- )}
+ {studyDataPublication && (
+
+
+ {t('investigations.details.pid')}
+
+
+
+ {studyDataPublication.pid}
+
+
+
+ )}
{t('investigations.details.doi')}
diff --git a/packages/datagateway-dataview/cypress/e2e/card/isis/dataPublications.cy.ts b/packages/datagateway-dataview/cypress/e2e/card/isis/dataPublications.cy.ts
deleted file mode 100644
index 918aa94dc..000000000
--- a/packages/datagateway-dataview/cypress/e2e/card/isis/dataPublications.cy.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-describe('ISIS - Data Publication Cards', () => {
- beforeEach(() => {
- cy.intercept('**/datapublications/count*').as('getDataPublicationsCount');
- cy.intercept('**/datapublications?order*').as('getDataPublicationsOrder');
- cy.login();
- cy.visit(
- '/browseDataPublications/instrument/8/dataPublication?view=card'
- ).wait(['@getDataPublicationsCount', '@getDataPublicationsOrder'], {
- timeout: 10000,
- });
- });
-
- it('should load correctly', () => {
- cy.title().should('equal', 'DataGateway DataView');
- cy.get('#datagateway-dataview').should('be.visible');
-
- cy.get('[data-testid="card"]')
- .first()
- .get('[data-testid="landing-datapublication-card-pid-link"]')
- .first()
- .then(($pid) => {
- const pid = $pid.text();
-
- const url = `https://doi.org/${pid}`;
-
- cy.get('[data-testid="card"]')
- .first()
- .get('[data-testid="landing-datapublication-card-pid-link"]')
- .first()
- .should('have.attr', 'href', url);
- });
-
- //Default sort
- cy.contains('[role="button"]', 'desc').should('exist');
- cy.get('.MuiTableSortLabel-iconDirectionDesc').should('be.visible');
- });
-
- it('should be able to click a datapublication to see its landing page', () => {
- cy.get('[data-testid="card"]')
- .first()
- .contains('Church')
- .click({ force: true });
- cy.location('pathname').should(
- 'eq',
- '/browseDataPublications/instrument/8/dataPublication/51'
- );
- });
-
- it('should be able to sort by one field or multiple', () => {
- //Revert the default sort
- cy.contains('[role="button"]', 'Publication Date')
- .as('dateSortButton')
- .click();
- cy.wait('@getDataPublicationsOrder', { timeout: 10000 });
-
- // ascending
- cy.get('@dateSortButton').click();
- cy.wait('@getDataPublicationsOrder', { timeout: 10000 });
- cy.contains('[role="button"]', 'asc').should('exist');
- cy.contains('[role="button"]', 'desc').should('not.exist');
- cy.get('[data-testid="card"]').first().contains('Article');
-
- // descending
- cy.get('@dateSortButton').click();
- cy.contains('[role="button"]', 'asc').should('not.exist');
- cy.contains('[role="button"]', 'desc').should('exist');
- cy.get('[data-testid="card"]').first().contains('Church');
-
- // no order
- cy.get('@dateSortButton').click();
- cy.contains('[role="button"]', 'asc').should('not.exist');
- cy.contains('[role="button"]', 'desc').should('not.exist');
- cy.get('[data-testid="card"]').first().contains('Article');
-
- // multiple fields (shift click)
- cy.contains('[role="button"]', 'Title').click();
- cy.get('@dateSortButton').click({ shiftKey: true });
- cy.wait('@getDataPublicationsOrder', { timeout: 10000 });
-
- cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('exist');
- cy.contains('[aria-label="Sort by PUBLICATION DATE"]', 'asc').should(
- 'exist'
- );
- cy.contains('[role="button"]', 'desc').should('not.exist');
- cy.get('[data-testid="card"]').first().contains('Article');
-
- // should replace current sort if clicked without shift
- cy.get('@dateSortButton').click();
- cy.wait('@getDataPublicationsOrder', { timeout: 10000 });
-
- cy.contains('[aria-label="Sort by PUBLICATION DATE"]', 'desc').should(
- 'exist'
- );
- cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('not.exist');
-
- cy.get('[data-testid="card"]').first().contains('Church');
- });
-
- it('should be able to filter by multiple fields', () => {
- cy.get('[data-testid="advanced-filters-link"]').click();
-
- cy.get('[aria-label="Filter by DOI"]').first().type('0');
- cy.wait(['@getDataPublicationsCount', '@getDataPublicationsOrder'], {
- timeout: 10000,
- });
- cy.get('[data-testid="card"]').first().contains('Consider');
-
- cy.get('[aria-label="Filter by Title"]').first().type('sub');
- cy.wait(['@getDataPublicationsCount', '@getDataPublicationsOrder'], {
- timeout: 10000,
- });
- cy.get('[data-testid="card"]').first().contains('Article');
- });
-});
diff --git a/packages/datagateway-dataview/cypress/e2e/card/isis/investigationDataPublications.cy.ts b/packages/datagateway-dataview/cypress/e2e/card/isis/investigationDataPublications.cy.ts
new file mode 100644
index 000000000..f5d74ec12
--- /dev/null
+++ b/packages/datagateway-dataview/cypress/e2e/card/isis/investigationDataPublications.cy.ts
@@ -0,0 +1,173 @@
+describe('ISIS - Study Data Publication Cards', () => {
+ beforeEach(() => {
+ cy.intercept(
+ /\/datapublications\/count\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22investigation%22%7D%7D.*/,
+ (req) => {
+ // delete type = investigation requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"investigation"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"investigation"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ // our count may have 1 extra at times, but it shouldn't matter too much...
+ req.continue();
+ }
+ ).as('getDataPublicationsCount');
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22investigation%22%7D%7D.*/,
+ (req) => {
+ // delete type = investigation requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"investigation"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"investigation"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ req.continue((res) => {
+ // remove the "study" datapublication i.e. the one whose ID is in the URL
+ const i = res.body.findIndex((dp) => dp.id === 57);
+ if (i !== -1) res.body.splice(i, 1);
+ });
+ }
+ ).as('getDataPublications');
+ cy.login();
+ cy.visit(
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation?view=card'
+ ).wait(['@getDataPublicationsCount', '@getDataPublications'], {
+ timeout: 10000,
+ });
+ });
+
+ it('should load correctly', () => {
+ cy.title().should('equal', 'DataGateway DataView');
+ cy.get('#datagateway-dataview').should('be.visible');
+
+ cy.get('[data-testid="card"]')
+ .first()
+ .get('[data-testid="landing-datapublication-card-pid-link"]')
+ .first()
+ .then(($pid) => {
+ const pid = $pid.text();
+
+ const url = `https://doi.org/${pid}`;
+
+ cy.get('[data-testid="card"]')
+ .first()
+ .get('[data-testid="landing-datapublication-card-pid-link"]')
+ .first()
+ .should('have.attr', 'href', url);
+ });
+
+ //Default sort
+ cy.contains('[role="button"]', 'desc').should('exist');
+ cy.get('.MuiTableSortLabel-iconDirectionDesc').should('be.visible');
+ });
+
+ it('should be able to click a datapublication to see its landing page', () => {
+ cy.get('[data-testid="card"]')
+ .first()
+ .contains('Leg')
+ .click({ force: true });
+ cy.location('pathname').should(
+ 'eq',
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/56'
+ );
+ });
+
+ it('should be able to sort by one field or multiple', () => {
+ //Revert the default sort
+ cy.contains('[role="button"]', 'Publication Date')
+ .as('dateSortButton')
+ .click();
+
+ // ascending
+ cy.get('@dateSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('exist');
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Because');
+
+ // descending
+ cy.get('@dateSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('not.exist');
+ cy.contains('[role="button"]', 'desc').should('exist');
+ cy.get('[data-testid="card"]').first().contains('Leg');
+
+ // no order
+ cy.get('@dateSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('not.exist');
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Because');
+
+ // multiple fields (shift click)
+ cy.contains('[role="button"]', 'Title').click();
+ cy.get('@dateSortButton').click({ shiftKey: true });
+
+ cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('exist');
+ cy.contains('[aria-label="Sort by PUBLICATION DATE"]', 'asc').should(
+ 'exist'
+ );
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Because');
+
+ // should replace current sort if clicked without shift
+ cy.get('@dateSortButton').click();
+
+ cy.contains('[aria-label="Sort by PUBLICATION DATE"]', 'desc').should(
+ 'exist'
+ );
+ cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('not.exist');
+
+ cy.get('[data-testid="card"]').first().contains('Leg');
+ });
+
+ it('should be able to filter by multiple fields', () => {
+ cy.get('[data-testid="advanced-filters-link"]').click();
+
+ cy.get('[aria-label="Filter by DOI"]').first().type('0');
+ cy.wait(['@getDataPublicationsCount', '@getDataPublications'], {
+ timeout: 10000,
+ });
+ cy.get('[data-testid="card"]').first().contains('Leg');
+
+ cy.get('[aria-label="Filter by Title"]').first().type('fin');
+ cy.wait(['@getDataPublicationsCount', '@getDataPublications'], {
+ timeout: 10000,
+ });
+ cy.get('[data-testid="card"]').first().contains('Because');
+ });
+});
diff --git a/packages/datagateway-dataview/cypress/e2e/card/isis/investigations.cy.ts b/packages/datagateway-dataview/cypress/e2e/card/isis/investigations.cy.ts
index 0c6cd802c..5299287f7 100644
--- a/packages/datagateway-dataview/cypress/e2e/card/isis/investigations.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/card/isis/investigations.cy.ts
@@ -1,7 +1,17 @@
describe('ISIS - Investigations Cards', () => {
beforeEach(() => {
cy.intercept('**/investigations/count*').as('getInvestigationsCount');
- cy.intercept('**/investigations?order*').as('getInvestigationsOrder');
+ cy.intercept('**/investigations?order*', (req) => {
+ req.continue((res) => {
+ // add type study to related data publication to emulate ISIS like data
+ if (
+ res.body?.[0]?.dataCollectionInvestigations?.[0]?.dataCollection
+ ?.dataPublications?.[0]
+ )
+ res.body[0].dataCollectionInvestigations[0].dataCollection.dataPublications[0].type =
+ { id: 1, name: 'study' };
+ });
+ }).as('getInvestigationsOrder');
cy.login();
cy.visit(
'/browse/instrument/13/facilityCycle/12/investigation?view=card'
diff --git a/packages/datagateway-dataview/cypress/e2e/card/isis/studyDataPublications.cy.ts b/packages/datagateway-dataview/cypress/e2e/card/isis/studyDataPublications.cy.ts
new file mode 100644
index 000000000..6d0427203
--- /dev/null
+++ b/packages/datagateway-dataview/cypress/e2e/card/isis/studyDataPublications.cy.ts
@@ -0,0 +1,162 @@
+describe('ISIS - Study Data Publication Cards', () => {
+ beforeEach(() => {
+ cy.intercept(
+ /\/datapublications\/count\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22study%22%7D%7D.*/,
+ (req) => {
+ // delete type = study requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"study"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"study"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ req.continue();
+ }
+ ).as('getDataPublicationsCount');
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22study%22%7D%7D.*/,
+ (req) => {
+ // delete type = study requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"study"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"study"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ req.continue();
+ }
+ ).as('getDataPublications');
+ cy.login();
+ cy.visit(
+ '/browseDataPublications/instrument/8/dataPublication?view=card'
+ ).wait(['@getDataPublicationsCount', '@getDataPublications'], {
+ timeout: 10000,
+ });
+ });
+
+ it('should load correctly', () => {
+ cy.title().should('equal', 'DataGateway DataView');
+ cy.get('#datagateway-dataview').should('be.visible');
+
+ cy.get('[data-testid="card"]')
+ .first()
+ .get('[data-testid="landing-datapublication-card-pid-link"]')
+ .first()
+ .then(($pid) => {
+ const pid = $pid.text();
+
+ const url = `https://doi.org/${pid}`;
+
+ cy.get('[data-testid="card"]')
+ .first()
+ .get('[data-testid="landing-datapublication-card-pid-link"]')
+ .first()
+ .should('have.attr', 'href', url);
+ });
+
+ //Default sort
+ cy.contains('[role="button"]', 'desc').should('exist');
+ cy.get('.MuiTableSortLabel-iconDirectionDesc').should('be.visible');
+ });
+
+ it('should be able to click a datapublication to see its landing page', () => {
+ cy.get('[data-testid="card"]')
+ .first()
+ .contains('Daughter')
+ .click({ force: true });
+ cy.location('pathname').should(
+ 'eq',
+ '/browseDataPublications/instrument/8/dataPublication/50'
+ );
+ });
+
+ it('should be able to sort by one field or multiple', () => {
+ //Revert the default sort
+ cy.contains('[role="button"]', 'Title').as('titleSortButton').click();
+
+ // ascending
+ cy.contains('[role="button"]', 'DOI').as('doiSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('exist');
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Article');
+
+ // descending
+ cy.get('@doiSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('not.exist');
+ cy.contains('[role="button"]', 'desc').should('exist');
+ cy.get('[data-testid="card"]').first().contains('Daughter');
+
+ // no order
+ cy.get('@doiSortButton').click();
+ cy.contains('[role="button"]', 'asc').should('not.exist');
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Article');
+
+ // multiple fields (shift click)
+ cy.get('@titleSortButton').click();
+ cy.get('@doiSortButton').click({ shiftKey: true });
+
+ cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('exist');
+ cy.contains('[aria-label="Sort by DOI"]', 'asc').should('exist');
+ cy.contains('[role="button"]', 'desc').should('not.exist');
+ cy.get('[data-testid="card"]').first().contains('Article');
+
+ // should replace current sort if clicked without shift
+ cy.get('@doiSortButton').click();
+
+ cy.contains('[aria-label="Sort by DOI"]', 'desc').should('exist');
+ cy.contains('[aria-label="Sort by TITLE"]', 'asc').should('not.exist');
+
+ cy.get('[data-testid="card"]').first().contains('Daughter');
+ });
+
+ it('should be able to filter by multiple fields', () => {
+ cy.get('[data-testid="advanced-filters-link"]').click();
+
+ cy.get('[aria-label="Filter by DOI"]').first().type('5');
+
+ cy.contains('Results: 2').should('exist');
+
+ cy.get('[data-testid="card"]').first().contains('Consider');
+
+ cy.get('[aria-label="Filter by Title"]').first().type('sub');
+
+ cy.contains('Results: 1').should('exist');
+
+ cy.get('[data-testid="card"]').first().contains('Article');
+ });
+});
diff --git a/packages/datagateway-dataview/cypress/e2e/datafilePreview.cy.ts b/packages/datagateway-dataview/cypress/e2e/datafilePreview.cy.ts
index a70879fd3..7a8757e2e 100644
--- a/packages/datagateway-dataview/cypress/e2e/datafilePreview.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/datafilePreview.cy.ts
@@ -2,6 +2,10 @@ import { join } from 'path';
describe('Datafile preview', () => {
beforeEach(() => {
+ cy.intercept('GET', '**/datafiles/findone*', {
+ statusCode: 200,
+ fixture: 'datafile.json',
+ });
cy.intercept('GET', '**/datafiles*', {
statusCode: 200,
fixture: 'datafile.json',
@@ -18,7 +22,7 @@ describe('Datafile preview', () => {
});
cy.login();
cy.visit(
- '/browse/instrument/1/facilityCycle/19/investigation/19/dataset/139/datafile/3484',
+ '/browse/instrument/1/facilityCycle/19/investigation/19/dataset/79/datafile/3484',
{
onBeforeLoad(win: Cypress.AUTWindow) {
cy.spy(win.navigator.clipboard, 'writeText').as('copy');
@@ -84,7 +88,7 @@ describe('Datafile preview', () => {
cy.contains('Copy link').click();
cy.get('@copy').should(
'be.calledOnceWithExactly',
- 'http://127.0.0.1:3000/browse/instrument/1/facilityCycle/19/investigation/19/dataset/139/datafile/3484'
+ 'http://127.0.0.1:3000/browse/instrument/1/facilityCycle/19/investigation/19/dataset/79/datafile/3484'
);
// should show a successful after copy is successful
cy.contains('Link copied to clipboard').should('exist');
diff --git a/packages/datagateway-dataview/cypress/e2e/landing/isis/investigation.cy.ts b/packages/datagateway-dataview/cypress/e2e/landing/isis/investigation.cy.ts
index 6ac5c88ca..7f47ee3e5 100644
--- a/packages/datagateway-dataview/cypress/e2e/landing/isis/investigation.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/landing/isis/investigation.cy.ts
@@ -1,5 +1,16 @@
describe('ISIS - Investigation Landing', () => {
beforeEach(() => {
+ cy.intercept('**/investigations?order*', (req) => {
+ req.continue((res) => {
+ // add type study to related data publication to emulate ISIS like data
+ if (
+ res.body?.[0]?.dataCollectionInvestigations?.[0]?.dataCollection
+ ?.dataPublications?.[0]
+ )
+ res.body[0].dataCollectionInvestigations[0].dataCollection.dataPublications[0].type =
+ { id: 1, name: 'study' };
+ });
+ });
cy.login();
cy.visit('/browse/instrument/13/facilityCycle/12/investigation/31');
});
@@ -86,6 +97,10 @@ describe('ISIS - Investigation Landing', () => {
modTime: '2019-06-10',
createTime: '2019-06-11',
title: 'Data Publication',
+ type: {
+ id: 1,
+ name: 'study',
+ },
},
],
},
diff --git a/packages/datagateway-dataview/cypress/e2e/landing/isis/investigationDataPublication.cy.ts b/packages/datagateway-dataview/cypress/e2e/landing/isis/investigationDataPublication.cy.ts
new file mode 100644
index 000000000..4a3863b55
--- /dev/null
+++ b/packages/datagateway-dataview/cypress/e2e/landing/isis/investigationDataPublication.cy.ts
@@ -0,0 +1,151 @@
+describe('ISIS - Investigation Data Publication Landing', () => {
+ beforeEach(() => {
+ cy.login();
+ cy.visit(
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/46'
+ );
+ });
+
+ it('should load correctly', () => {
+ cy.title().should('equal', 'DataGateway DataView');
+ cy.get('#datagateway-dataview').should('be.visible');
+ cy.get('#investigation-details-panel')
+ .contains('Because fine have business')
+ .should('be.visible');
+ cy.get('#investigation-details-panel')
+ .contains('a', '0-686-22941-X')
+ .should('have.attr', 'href', 'https://doi.org/0-686-22941-X');
+ cy.get('#investigation-details-panel')
+ .contains('INSTRUMENT 13')
+ .should('be.visible');
+
+ cy.get('[aria-label="landing-investigation-part-label"').should(
+ 'have.length',
+ 2
+ );
+ });
+
+ it('should be able to click tab to see datasets', () => {
+ cy.get('#investigation-datasets-tab').first().click({ force: true });
+ cy.location('pathname').should(
+ 'eq',
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/46/dataset'
+ );
+ cy.contains('Results: 2').should('be.visible');
+ });
+
+ it('should be able to click a specific dataset', () => {
+ cy.get('[aria-label="landing-investigation-part-label"')
+ .children()
+ .first()
+ .click({ force: true });
+ cy.location('pathname').should(
+ 'eq',
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/46/dataset/15'
+ );
+ });
+
+ it('should load correctly when investigation missing', () => {
+ cy.intercept('**/datapublications?order*', (req) => {
+ req.continue((res) => {
+ if (
+ res.body?.[0]?.content?.dataCollectionInvestigations?.[0]
+ ?.investigation
+ )
+ delete res.body[0].content.dataCollectionInvestigations[0]
+ .investigation;
+ });
+ });
+
+ cy.get('#investigation-details-panel')
+ .contains('Because fine have business')
+ .should('be.visible');
+ cy.get('#investigation-details-panel')
+ .contains('a', '0-686-22941-X')
+ .should('have.attr', 'href', 'https://doi.org/0-686-22941-X');
+ cy.get('#investigation-details-panel')
+ .contains('INSTRUMENT 13')
+ .should('not.exist');
+
+ cy.get('[aria-label="landing-investigation-part-label"').should(
+ 'not.exist'
+ );
+ });
+
+ it('should disable the hover tool tip by pressing escape', () => {
+ cy.intercept('**/datapublications?*', [
+ {
+ id: 36,
+ pid: '10.5286/ISIS.E.RB1810842',
+ },
+ ]);
+ cy.get('[data-testid="isis-investigations-landing-parent-doi-link"]')
+ .first()
+ .trigger('mouseover');
+ cy.get('[role="tooltip"]').should('exist');
+
+ cy.get('body').type('{esc}');
+
+ cy.get('[data-testid="isis-investigation-landing-doi-link"]')
+ .first()
+ .get('[role="tooltip"]')
+ .should('not.exist');
+ });
+
+ it('should be able to use the citation formatter', () => {
+ cy.intercept('**/datapublications?*', [
+ {
+ id: 101224979,
+ pid: '10.5286/ISIS.E.RB1810842',
+ },
+ ]);
+ cy.intercept('**/text/x-bibliography/10.5286/ISIS.E.RB1810842?*', [
+ '@misc{dr sabrina gaertner_mr vincent deguin_dr pierre ghesquiere_dr claire...}',
+ ]);
+
+ cy.contains('10.5286/ISIS.E.RB1810842').should('be.visible');
+ cy.get('[data-testid="citation-formatter-citation"]').contains(
+ 'STFC ISIS Neutron and Muon Source, https://doi.org/10.5286/ISIS.E.RB1810842'
+ );
+
+ cy.get('#citation-formatter').click();
+ cy.get('[role="listbox"]')
+ .find('[role="option"]')
+ .should('have.length.gte', 2);
+
+ cy.get('[role="option"][data-value="bibtex"]').click();
+ cy.get('[data-testid="citation-formatter-citation"]').contains(
+ '@misc{dr sabrina gaertner_mr vincent deguin_dr pierre ghesquiere_dr claire'
+ );
+ cy.get('#citation-formatter-error-message').should('not.exist');
+ });
+
+ it('citation formatter should give an error when there is a problem', () => {
+ cy.intercept('**/datapublications?*', [
+ {
+ id: 101224979,
+ pid: 'invaliddoi',
+ },
+ ]);
+ cy.intercept('**/text/x-bibliography/invaliddoi?*', {
+ statusCode: 503,
+ });
+
+ cy.contains('invaliddoi').should('be.visible');
+
+ //Default citation
+ cy.get('[data-testid="citation-formatter-citation"]').contains(
+ 'STFC ISIS Neutron and Muon Source, https://doi.org/invaliddoi'
+ );
+
+ cy.get('#citation-formatter').click();
+ cy.get('[role="listbox"]')
+ .find('[role="option"]')
+ .should('have.length.gte', 2);
+
+ cy.get('[role="option"][data-value="chicago-author-date"]').click();
+ cy.get('#citation-formatter-error-message', { timeout: 10000 }).should(
+ 'exist'
+ );
+ });
+});
diff --git a/packages/datagateway-dataview/cypress/e2e/landing/isis/dataPublication.cy.ts b/packages/datagateway-dataview/cypress/e2e/landing/isis/studyDataPublication.cy.ts
similarity index 58%
rename from packages/datagateway-dataview/cypress/e2e/landing/isis/dataPublication.cy.ts
rename to packages/datagateway-dataview/cypress/e2e/landing/isis/studyDataPublication.cy.ts
index 9e58009c4..944f1d5d8 100644
--- a/packages/datagateway-dataview/cypress/e2e/landing/isis/dataPublication.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/landing/isis/studyDataPublication.cy.ts
@@ -1,29 +1,60 @@
-describe('ISIS - Data Publication Landing', () => {
+describe('ISIS - Study Data Publication Landing', () => {
beforeEach(() => {
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22investigation%22%7D%7D.*/,
+ (req) => {
+ // delete type = investigation requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"investigation"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"investigation"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ req.continue((res) => {
+ // remove the "study" datapublication i.e. the one whose ID is in the URL
+ const i = res.body.findIndex((dp) => dp.id === 57);
+ if (i !== -1) res.body.splice(i, 1);
+ });
+ }
+ ).as('getDataPublications');
+
cy.login();
- cy.visit('/browseDataPublications/instrument/1/dataPublication/36');
+ cy.visit('/browseDataPublications/instrument/13/dataPublication/57');
});
it('should load correctly', () => {
cy.title().should('equal', 'DataGateway DataView');
cy.get('#datagateway-dataview').should('be.visible');
- cy.contains('Yourself good together red across.').should('be.visible');
- cy.contains('a', '0-7602-7584-X').should(
- 'have.attr',
- 'href',
- 'https://doi.org/0-7602-7584-X'
+ cy.contains('Dream he television').should('be.visible');
+ cy.get('[data-testid="isis-dataPublication-landing"]')
+ .contains('Because fine have business')
+ .should('be.visible');
+
+ cy.get('[data-testid="isis-dataPublication-landing"]')
+ .contains('a', '1-64379-596-1')
+ .should('have.attr', 'href', 'https://doi.org/1-64379-596-1');
+
+ cy.get('[data-testid="landing-datapublication-part-label"').should(
+ 'have.length',
+ 2
);
- cy.get('[data-testid="landing-dataPublication-pid-link"]')
- .first()
- .then(($pid) => {
- const pid = $pid.text();
-
- const url = `https://doi.org/${pid}`;
-
- cy.get('[data-testid="landing-dataPublication-pid-link"]')
- .first()
- .should('have.attr', 'href', url);
- });
});
it('should be able to click tab to see investigations', () => {
@@ -32,7 +63,7 @@ describe('ISIS - Data Publication Landing', () => {
.click({ force: true });
cy.location('pathname').should(
'eq',
- '/browseDataPublications/instrument/1/dataPublication/36/investigation'
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation'
);
});
@@ -43,20 +74,20 @@ describe('ISIS - Data Publication Landing', () => {
.click({ force: true });
cy.location('pathname').should(
'eq',
- '/browseDataPublications/instrument/1/dataPublication/36/investigation/38'
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/46'
);
});
it('should load correctly when investigation missing', () => {
- cy.intercept('**/datapublications?*', [
- {
- id: 101224979,
- pid: '10.5286/ISIS.E.RB1810842',
- },
- ]);
- cy.visit('/browseDataPublications/instrument/1/dataPublication/36');
- cy.get('#datagateway-dataview').should('be.visible');
- cy.contains('10.5286/ISIS.E.RB1810842').should('be.visible');
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22investigation%22%7D%7D.*/,
+ []
+ );
+
+ cy.contains('1-64379-596-1').should('be.visible');
+ cy.get('[data-testid="landing-datapublication-part-label"').should(
+ 'not.exist'
+ );
});
it('should disable the hover tool tip by pressing escape', () => {
diff --git a/packages/datagateway-dataview/cypress/e2e/table/isis/investigationDataPublications.cy.ts b/packages/datagateway-dataview/cypress/e2e/table/isis/investigationDataPublications.cy.ts
new file mode 100644
index 000000000..41b4cce8b
--- /dev/null
+++ b/packages/datagateway-dataview/cypress/e2e/table/isis/investigationDataPublications.cy.ts
@@ -0,0 +1,192 @@
+describe('ISIS - Investigation Data Publication Table', () => {
+ beforeEach(() => {
+ cy.intercept('**/datapublications/count*').as('getDataPublicationsCount');
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22investigation%22%7D%7D.*/,
+ (req) => {
+ // delete type = investigation requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"investigation"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"investigation"}}');
+ req.url = `${url}?${params.toString()}`;
+
+ req.continue((res) => {
+ // remove the "study" datapublication i.e. the one whose ID is in the URL
+ const i = res.body.findIndex((dp) => dp.id === 57);
+ if (i !== -1) res.body.splice(i, 1);
+ });
+ }
+ ).as('getDataPublications');
+ cy.login();
+ cy.visit(
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation'
+ ).wait(['@getDataPublicationsCount', '@getDataPublications'], {
+ timeout: 10000,
+ });
+ });
+
+ it('should load correctly', () => {
+ cy.title().should('equal', 'DataGateway DataView');
+ cy.get('#datagateway-dataview').should('be.visible');
+
+ //Default sort
+ cy.get('[aria-sort="descending"]').should('exist');
+ cy.get('.MuiTableSortLabel-iconDirectionDesc').should('be.visible');
+ });
+
+ it('should be able to click a data publication to see its landing page', () => {
+ cy.get('[role="gridcell"] a').first().click({ force: true });
+ cy.location('pathname').should(
+ 'eq',
+ '/browseDataPublications/instrument/13/dataPublication/57/investigation/56'
+ );
+ });
+
+ it('should have the correct url for the DOI link', () => {
+ cy.get('[data-testid="isis-datapublication-table-doi-link"]')
+ .first()
+ .then(($doi) => {
+ const doi = $doi.text();
+
+ const url = `https://doi.org/${doi}`;
+
+ cy.get('[data-testid="isis-datapublication-table-doi-link"]')
+ .first()
+ .should('have.attr', 'href', url);
+ });
+ });
+
+ // Not enough data in datapublications to load.
+ it.skip('should be able to scroll down and load more rows', () => {
+ cy.get('[aria-rowcount="50"]').should('exist');
+ cy.get('[aria-label="grid"]').scrollTo('bottom');
+ cy.get('[aria-rowcount="75"]').should('exist');
+ });
+
+ it('should be able to sort by all sort directions on single and multiple columns', () => {
+ //Revert the default sort
+ cy.contains('[role="button"]', 'Publication Date')
+ .as('dateSortButton')
+ .click();
+
+ // ascending order
+ cy.contains('[role="button"]', 'Title').as('titleSortButton').click();
+
+ cy.get('[aria-sort="ascending"]').should('exist');
+ cy.get('.MuiTableSortLabel-iconDirectionAsc').should('be.visible');
+ cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
+ 'Because fine have business'
+ );
+
+ // descending order
+ cy.get('@titleSortButton').click();
+
+ cy.get('[aria-sort="descending"]').should('exist');
+ cy.get('.MuiTableSortLabel-iconDirectionDesc').should(
+ 'not.have.css',
+ 'opacity',
+ '0'
+ );
+ cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
+ 'Leg can time eat'
+ );
+
+ // no order
+ cy.get('@titleSortButton').click();
+
+ cy.get('[aria-sort="ascending"]').should('not.exist');
+ cy.get('[aria-sort="descending"]').should('not.exist');
+ cy.get('.MuiTableSortLabel-iconDirectionAsc').should('not.exist');
+
+ cy.get('[data-testid="SortIcon"]').should('have.length', 3);
+ cy.get('[data-testid="ArrowUpwardIcon"]').should('not.exist');
+
+ cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
+ 'Because fine have business'
+ );
+
+ // multiple columns (shift click)
+ cy.get('@dateSortButton').click();
+ cy.get('@dateSortButton').click({ shiftKey: true });
+ cy.get('@titleSortButton').click({ shiftKey: true });
+
+ cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
+ 'Leg can time eat'
+ );
+
+ // should replace previous sort when clicked without shift
+ cy.get('@dateSortButton').click();
+ cy.get('[aria-sort="ascending"]').should('have.length', 1);
+ cy.get('[aria-rowindex="1"] [aria-colindex="3"]').contains('2014-12-02');
+ });
+
+ it('should change icons when sorting on a column', () => {
+ // clear default sort
+ cy.contains('[role="button"]', 'Publication Date').click();
+
+ cy.get('[data-testid="SortIcon"]').should('have.length', 3);
+
+ // check icon when clicking on a column
+ cy.contains('[role="button"]', 'DOI').click();
+ cy.get('[data-testid="ArrowDownwardIcon"]').should('have.length', 1);
+ cy.get('.MuiTableSortLabel-iconDirectionAsc').should('exist');
+
+ // check icon when clicking on a column again
+ cy.contains('[role="button"]', 'DOI').click();
+ cy.get('[data-testid="ArrowDownwardIcon"]').should('have.length', 1);
+ cy.get('.MuiTableSortLabel-iconDirectionAsc').should('not.exist');
+
+ // check icon when hovering over a column
+ cy.contains('[role="button"]', 'Title').trigger('mouseover');
+ cy.get('[data-testid="ArrowUpwardIcon"]').should('have.length', 1);
+ cy.get('[data-testid="ArrowDownwardIcon"]').should('have.length', 1);
+
+ // check icons when shift is held
+ cy.get('.App').trigger('keydown', { key: 'Shift' });
+ cy.get('[data-testid="AddIcon"]').should('have.length', 1);
+ });
+
+ it('should be able to filter with both text & date filters on multiple columns', () => {
+ // test date filter
+ cy.get('input[id="Publication Date filter to"]').type('2016-01-01');
+
+ cy.get('[aria-rowcount="1"]').should('exist');
+ cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
+ 'Because fine have business'
+ );
+
+ cy.get('input[id="Publication Date filter from"]').type('2015-01-01');
+
+ cy.get('[aria-rowcount="0"]').should('exist');
+
+ cy.get('input[id="Publication Date filter from"]').type(
+ '{ctrl}a{backspace}'
+ );
+ cy.get('input[id="Publication Date filter from"]').type('2014-01-01');
+
+ cy.get('[aria-rowcount="1"]').should('exist');
+
+ // test text filter
+ cy.get('[aria-label="Filter by Title"]').first().type('xy');
+
+ cy.get('[aria-rowcount="0"]').should('exist');
+ });
+});
diff --git a/packages/datagateway-dataview/cypress/e2e/table/isis/investigations.cy.ts b/packages/datagateway-dataview/cypress/e2e/table/isis/investigations.cy.ts
index 1ba9ec19c..fd63bc511 100644
--- a/packages/datagateway-dataview/cypress/e2e/table/isis/investigations.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/table/isis/investigations.cy.ts
@@ -1,7 +1,18 @@
describe('ISIS - Investigations Table', () => {
beforeEach(() => {
cy.intercept('**/investigations/count*').as('getInvestigationsCount');
- cy.intercept('**/investigations?order*').as('getInvestigationsOrder');
+ cy.intercept('**/investigations?order*', (req) => {
+ req.continue((res) => {
+ // add type study to related data publication to emulate ISIS like data
+ if (
+ res.body?.[0]?.dataCollectionInvestigations?.[0]?.dataCollection
+ ?.dataPublications?.[0]
+ )
+ res.body[0].dataCollectionInvestigations[0].dataCollection.dataPublications[0].type =
+ { id: 1, name: 'study' };
+ });
+ }).as('getInvestigationsOrder');
+
cy.login();
cy.visit('/browse/instrument/13/facilityCycle/12/investigation').wait(
['@getInvestigationsCount', '@getInvestigationsOrder'],
diff --git a/packages/datagateway-dataview/cypress/e2e/table/isis/myData.cy.ts b/packages/datagateway-dataview/cypress/e2e/table/isis/myData.cy.ts
index e4b2e6923..68624dbeb 100644
--- a/packages/datagateway-dataview/cypress/e2e/table/isis/myData.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/table/isis/myData.cy.ts
@@ -7,6 +7,17 @@ describe('ISIS - MyData Table', () => {
describe('Logged in tests', () => {
beforeEach(() => {
cy.intercept('**/investigations/count?*').as('getInvestigationCount');
+ cy.intercept('**/investigations?order*', (req) => {
+ req.continue((res) => {
+ // add type study to related data publication to emulate ISIS like data
+ if (
+ res.body?.[0]?.dataCollectionInvestigations?.[0]?.dataCollection
+ ?.dataPublications?.[0]
+ )
+ res.body[0].dataCollectionInvestigations[0].dataCollection.dataPublications[0].type =
+ { id: 1, name: 'study' };
+ });
+ });
cy.login(
{
username: 'root',
diff --git a/packages/datagateway-dataview/cypress/e2e/table/isis/dataPublications.cy.ts b/packages/datagateway-dataview/cypress/e2e/table/isis/studyDataPublications.cy.ts
similarity index 69%
rename from packages/datagateway-dataview/cypress/e2e/table/isis/dataPublications.cy.ts
rename to packages/datagateway-dataview/cypress/e2e/table/isis/studyDataPublications.cy.ts
index 0b0fee3ec..3dd208c23 100644
--- a/packages/datagateway-dataview/cypress/e2e/table/isis/dataPublications.cy.ts
+++ b/packages/datagateway-dataview/cypress/e2e/table/isis/studyDataPublications.cy.ts
@@ -1,10 +1,42 @@
-describe('ISIS - Data Publication Table', () => {
+describe('ISIS - Study Data Publication Table', () => {
beforeEach(() => {
cy.intercept('**/datapublications/count*').as('getDataPublicationsCount');
- cy.intercept('**/datapublications?order*').as('getDataPublicationsOrder');
+ cy.intercept(
+ /\/datapublications\?.*where=%7B%22type\.name%22%3A%7B%22eq%22%3A%22study%22%7D%7D.*/,
+ (req) => {
+ console.log('INTERCEPTING!!!!!');
+ // delete type = study requirement
+ const [url, search] = req.url.split('?');
+ const params = new URLSearchParams(search);
+ // params.delete with value is still a new standard, so use workaround for now until browser compat catches up
+ // params.delete('where', '{"type.name":{"eq":"study"}}');
+ const removeValue = (
+ params: URLSearchParams,
+ key: string,
+ valueToRemove: string
+ ): URLSearchParams => {
+ const values = params.getAll(key);
+ if (values.length) {
+ params.delete(key);
+ for (const value of values) {
+ if (value !== valueToRemove) {
+ params.append(key, value);
+ }
+ }
+ }
+ return params;
+ };
+ removeValue(params, 'where', '{"type.name":{"eq":"study"}}');
+ req.url = `${url}?${params.toString()}`;
+ console.log('req.url', req.url);
+
+ req.continue();
+ }
+ ).as('getDataPublications');
+
cy.login();
cy.visit('/browseDataPublications/instrument/8/dataPublication').wait(
- ['@getDataPublicationsCount', '@getDataPublicationsOrder'],
+ ['@getDataPublicationsCount', '@getDataPublications'],
{ timeout: 10000 }
);
});
@@ -22,7 +54,7 @@ describe('ISIS - Data Publication Table', () => {
cy.get('[role="gridcell"] a').first().click({ force: true });
cy.location('pathname').should(
'eq',
- '/browseDataPublications/instrument/8/dataPublication/51'
+ '/browseDataPublications/instrument/8/dataPublication/50'
);
});
@@ -49,12 +81,10 @@ describe('ISIS - Data Publication Table', () => {
it('should be able to sort by all sort directions on single and multiple columns', () => {
//Revert the default sort
- cy.contains('[role="button"]', 'Publication Date')
- .as('dateSortButton')
- .click();
+ cy.contains('[role="button"]', 'Title').as('titleSortButton').click();
// ascending order
- cy.contains('[role="button"]', 'Title').as('titleSortButton').click();
+ cy.contains('[role="button"]', 'DOI').as('doiSortButton').click();
cy.get('[aria-sort="ascending"]').should('exist');
cy.get('.MuiTableSortLabel-iconDirectionAsc').should('be.visible');
@@ -63,7 +93,7 @@ describe('ISIS - Data Publication Table', () => {
);
// descending order
- cy.get('@titleSortButton').click();
+ cy.get('@doiSortButton').click();
cy.get('[aria-sort="descending"]').should('exist');
cy.get('.MuiTableSortLabel-iconDirectionDesc').should(
@@ -76,13 +106,13 @@ describe('ISIS - Data Publication Table', () => {
);
// no order
- cy.get('@titleSortButton').click();
+ cy.get('@doiSortButton').click();
cy.get('[aria-sort="ascending"]').should('not.exist');
cy.get('[aria-sort="descending"]').should('not.exist');
cy.get('.MuiTableSortLabel-iconDirectionAsc').should('not.exist');
- cy.get('[data-testid="SortIcon"]').should('have.length', 3);
+ cy.get('[data-testid="SortIcon"]').should('have.length', 2);
cy.get('[data-testid="ArrowUpwardIcon"]').should('not.exist');
cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
@@ -90,25 +120,25 @@ describe('ISIS - Data Publication Table', () => {
);
// multiple columns (shift click)
- cy.get('@dateSortButton').click();
- cy.get('@dateSortButton').click({ shiftKey: true });
+ cy.get('@titleSortButton').click();
cy.get('@titleSortButton').click({ shiftKey: true });
+ cy.get('@doiSortButton').click({ shiftKey: true });
cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
- 'Church child time Congress'
+ 'Daughter experience discussion'
);
// should replace previous sort when clicked without shift
- cy.contains('[role="button"]', 'Publication Date').click();
+ cy.get('@titleSortButton').click();
cy.get('[aria-sort="ascending"]').should('have.length', 1);
- cy.get('[aria-rowindex="1"] [aria-colindex="3"]').contains('2010-02-24');
+ cy.get('[aria-rowindex="1"] [aria-colindex="2"]').contains('0-356-85165-6');
});
it('should change icons when sorting on a column', () => {
// clear default sort
- cy.contains('[role="button"]', 'Publication Date').click();
+ cy.contains('[role="button"]', 'Title').click();
- cy.get('[data-testid="SortIcon"]').should('have.length', 3);
+ cy.get('[data-testid="SortIcon"]').should('have.length', 2);
// check icon when clicking on a column
cy.contains('[role="button"]', 'DOI').click();
@@ -120,14 +150,14 @@ describe('ISIS - Data Publication Table', () => {
cy.get('[data-testid="ArrowDownwardIcon"]').should('have.length', 1);
cy.get('.MuiTableSortLabel-iconDirectionAsc').should('not.exist');
+ // check icons when shift is held
+ cy.get('.App').trigger('keydown', { key: 'Shift' });
+ cy.get('[data-testid="AddIcon"]').should('have.length', 1);
+
// check icon when hovering over a column
cy.contains('[role="button"]', 'Title').trigger('mouseover');
cy.get('[data-testid="ArrowUpwardIcon"]').should('have.length', 1);
cy.get('[data-testid="ArrowDownwardIcon"]').should('have.length', 1);
-
- // check icons when shift is held
- cy.get('.App').trigger('keydown', { key: 'Shift' });
- cy.get('[data-testid="AddIcon"]').should('have.length', 1);
});
it('should be able to filter with both text & date filters on multiple columns', () => {
@@ -137,19 +167,7 @@ describe('ISIS - Data Publication Table', () => {
cy.get('[aria-rowcount="3"]').should('exist');
cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
- 'Church child time Congress'
- );
-
- // test date filter
- cy.get('input[id="Publication Date filter to"]').type('2016-01-01');
-
- cy.get('[aria-rowcount="2"]').should('exist');
- cy.get('[aria-rowindex="1"] [aria-colindex="1"]').contains(
- 'Consider author watch'
+ 'Daughter experience discussion'
);
-
- cy.get('input[id="Publication Date filter from"]').type('2014-01-01');
-
- cy.get('[aria-rowcount="1"]').should('exist');
});
});
diff --git a/packages/datagateway-dataview/public/datagateway-dataview-settings.example.json b/packages/datagateway-dataview/public/datagateway-dataview-settings.example.json
index 8b48c10eb..6c9366bb4 100644
--- a/packages/datagateway-dataview/public/datagateway-dataview-settings.example.json
+++ b/packages/datagateway-dataview/public/datagateway-dataview-settings.example.json
@@ -153,5 +153,24 @@
"order": 6
}
],
+ "breadcrumbs": [
+ {
+ "matchEntity": "proposal",
+ "replaceEntity": "investigation",
+ "replaceEntityField": "title",
+ "replaceEntityQueryField": "name"
+ },
+ {
+ "matchEntity": "investigation",
+ "replaceEntityField": "visitId",
+ "parentEntity": "proposal"
+ },
+ {
+ "matchEntity": "investigation",
+ "replaceEntity": "dataPublication",
+ "replaceEntityField": "title",
+ "parentEntity": "dataPublication"
+ }
+ ],
"pluginHost": "http://localhost:3000"
}
diff --git a/packages/datagateway-dataview/public/res/default.json b/packages/datagateway-dataview/public/res/default.json
index 6f40ef68a..b97b1f7e5 100644
--- a/packages/datagateway-dataview/public/res/default.json
+++ b/packages/datagateway-dataview/public/res/default.json
@@ -20,6 +20,7 @@
"instrument_other": "Instruments",
"facilityCycle_other": "Facility Cycles",
"dataPublication_other": "Experiments",
+ "experiment_other": "Investigations",
"proposal_other": "Proposals",
"investigation_other": "Investigations",
"dataset_other": "Datasets",
@@ -329,13 +330,10 @@
"email": "isisdata@stfc.ac.uk",
"logo": "https://data.isis.stfc.ac.uk/doi/ISIS/images/dsLogo.png"
},
- "distribution": {
- "format": "RAW/Nexus",
- "content_url": "https://data.isis.stfc.ac.uk"
- },
"branding": {
"title": "ISIS Neutron and Muon Source",
"body": "This is a page describing data taken during an experiment at the ISIS Neutron and Muon Source. Information about the ISIS Neutron and Muon Source can be found at https://www.isis.stfc.ac.uk."
- }
+ },
+ "license": "https://www.isis.stfc.ac.uk/Pages/Data-Policy.aspx"
}
}
diff --git a/packages/datagateway-dataview/server/e2e-settings.json b/packages/datagateway-dataview/server/e2e-settings.json
index 62e07f93d..395b7be54 100644
--- a/packages/datagateway-dataview/server/e2e-settings.json
+++ b/packages/datagateway-dataview/server/e2e-settings.json
@@ -9,16 +9,25 @@
"idsUrl": "https://localhost:8181/ids",
"apiUrl": "http://localhost:5000",
"downloadApiUrl": "https://localhost:8181/topcat",
- "breadcrumbs": {
- "proposal": {
+ "breadcrumbs": [
+ {
+ "matchEntity": "proposal",
"replaceEntity": "investigation",
- "replaceEntityField": "title"
+ "replaceEntityField": "title",
+ "replaceEntityQueryField": "name"
},
- "investigation": {
+ {
+ "matchEntity": "investigation",
"replaceEntityField": "visitId",
"parentEntity": "proposal"
+ },
+ {
+ "matchEntity": "investigation",
+ "replaceEntity": "dataPublication",
+ "replaceEntityField": "title",
+ "parentEntity": "dataPublication"
}
- },
+ ],
"helpSteps": [
{
"target": "#plugin-link--browse-investigation",
diff --git a/packages/datagateway-dataview/src/index.test.tsx b/packages/datagateway-dataview/src/index.test.tsx
index 86e3210d0..9069caa31 100644
--- a/packages/datagateway-dataview/src/index.test.tsx
+++ b/packages/datagateway-dataview/src/index.test.tsx
@@ -25,11 +25,12 @@ describe('index - fetchSettings', () => {
features: {},
idsUrl: 'ids',
apiUrl: 'api',
- breadcrumbs: {
- test: {
+ breadcrumbs: [
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- },
+ ],
downloadApiUrl: 'download-api',
selectAllSetting: false,
routes: [
@@ -78,11 +79,12 @@ describe('index - fetchSettings', () => {
features: {},
idsUrl: 'ids',
apiUrl: 'api',
- breadcrumbs: {
- test: {
+ breadcrumbs: [
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- },
+ ],
downloadApiUrl: 'download-api',
selectAllSetting: false,
routes: [
diff --git a/packages/datagateway-dataview/src/page/breadcrumbs.component.test.tsx b/packages/datagateway-dataview/src/page/breadcrumbs.component.test.tsx
index 3d71d0e49..29c2a5394 100644
--- a/packages/datagateway-dataview/src/page/breadcrumbs.component.test.tsx
+++ b/packages/datagateway-dataview/src/page/breadcrumbs.component.test.tsx
@@ -23,17 +23,29 @@ jest.mock('loglevel');
const genericRoutes = {
investigations: '/browse/investigation',
datasets: '/browse/investigation/1/dataset',
- datafiles: '/browse/investigation/1/dataset/1/datafile',
+ datafiles: '/browse/investigation/1/dataset/2/datafile',
};
// The ISIS routes to test.
const ISISRoutes = {
instruments: '/browse/instrument',
facilityCycles: '/browse/instrument/1/facilityCycle',
- investigations: '/browse/instrument/1/facilityCycle/1/investigation',
- datasets: '/browse/instrument/1/facilityCycle/1/investigation/1/dataset',
+ investigations: '/browse/instrument/1/facilityCycle/2/investigation',
+ datasets: '/browse/instrument/1/facilityCycle/2/investigation/3/dataset',
datafiles:
- '/browse/instrument/1/facilityCycle/1/investigation/1/dataset/1/datafile',
+ '/browse/instrument/1/facilityCycle/2/investigation/3/dataset/4/datafile',
+};
+
+// The ISIS experiments
+const ISISExperimentsRoutes = {
+ instruments: '/browseDataPublications/instrument',
+ studyDataPublications: '/browseDataPublications/instrument/1/dataPublication',
+ investigationDataPublications:
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation',
+ datasets:
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/3/dataset',
+ datafiles:
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/3/dataset/4/datafile',
};
// The DLS routes to test.
@@ -42,7 +54,7 @@ const DLSRoutes = {
investigations: '/browse/proposal/INVESTIGATION 1/investigation',
datasets: '/browse/proposal/INVESTIGATION 1/investigation/1/dataset',
datafiles:
- '/browse/proposal/INVESTIGATION 1/investigation/1/dataset/1/datafile',
+ '/browse/proposal/INVESTIGATION 1/investigation/1/dataset/2/datafile',
};
describe('PageBreadcrumbs tests (Generic, DLS, ISIS)', () => {
@@ -74,16 +86,27 @@ describe('PageBreadcrumbs tests (Generic, DLS, ISIS)', () => {
...dgDataViewInitialState,
// Set up the breadcrumb settings.
- breadcrumbSettings: {
- proposal: {
+ breadcrumbSettings: [
+ // DLS settings
+ {
+ matchEntity: 'proposal',
replaceEntity: 'investigation',
replaceEntityField: 'title',
+ replaceEntityQueryField: 'name',
},
- investigation: {
+ {
+ matchEntity: 'investigation',
replaceEntityField: 'visitId',
parentEntity: 'proposal',
},
- },
+ // ISIS settings
+ {
+ matchEntity: 'investigation',
+ replaceEntity: 'dataPublication',
+ replaceEntityField: 'title',
+ parentEntity: 'dataPublication',
+ },
+ ],
},
dgcommon: dGCommonInitialState,
@@ -95,449 +118,675 @@ describe('PageBreadcrumbs tests (Generic, DLS, ISIS)', () => {
})
);
- (axios.get as jest.Mock).mockImplementation(() =>
- Promise.resolve({
+ (axios.get as jest.Mock).mockImplementation((url) => {
+ const potentialId = parseInt(url.split('/').at(-1));
+ let id = 1;
+ if (!Number.isNaN(potentialId)) {
+ id = potentialId;
+ }
+ return Promise.resolve({
data: {
- id: 1,
- name: 'Name 1',
- title: 'Title 1',
- visitId: '1',
+ id: id,
+ name: `Name ${id}`,
+ title: `Title ${id}`,
+ visitId: `${id}`,
},
- })
- );
+ });
+ });
});
afterEach(() => {
(axios.get as jest.Mock).mockClear();
});
- it('generic route renders correctly at the base route and does not request', async () => {
- // Set up test state pathname.
- history.replace(createLocation(genericRoutes['investigations']));
+ describe('Generic', () => {
+ it('generic route renders correctly at the base route and does not request', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(genericRoutes['investigations']));
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
- // Expect the axios.get to not have been made.
- expect(axios.get).not.toBeCalled();
+ // Expect the axios.get to not have been made.
+ expect(axios.get).not.toBeCalled();
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- expect(screen.getByTestId('Breadcrumb-base')).toHaveTextContent(
- 'breadcrumbs.investigation'
- );
- });
-
- it('generic route renders correctly at the dataset level and requests the investigation entity', async () => {
- // Set up test state pathname.
- history.replace(
- createLocation({
- pathname: genericRoutes['datasets'],
- search: '?view=card',
- })
- );
-
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ expect(screen.getByTestId('Breadcrumb-base')).toHaveTextContent(
+ 'breadcrumbs.investigation'
+ );
+ });
- // Expect the axios.get to have been called once to get the investigation.
- expect(axios.get).toBeCalledTimes(1);
- expect(axios.get).toHaveBeenCalledWith('/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ it('generic route renders correctly at the dataset level and requests the investigation entity', async () => {
+ // Set up test state pathname.
+ history.replace(
+ createLocation({
+ pathname: genericRoutes['datasets'],
+ search: '?view=card',
+ })
+ );
+
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
+
+ // Expect the axios.get to have been called once to get the investigation.
+ expect(axios.get).toBeCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith('/investigations/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute(
+ 'href',
+ '/browse/investigation?view=card'
+ );
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.investigation');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.dataset'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute(
- 'href',
- '/browse/investigation?view=card'
- );
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.investigation');
+ it('generic route renders correctly at the datafile level and requests the investigation & dataset entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(genericRoutes['datafiles']));
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.dataset'
- )
- ).toBeInTheDocument();
+ // Expect the axios.get to have been called twice; first to get the investigation
+ // and second to get the dataset.
+ expect(axios.get).toBeCalledTimes(2);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/investigations/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/datasets/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/investigation');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.investigation');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
+ expect(within(breadcrumbs[1]).getByText('Name 2')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.datafile'
+ )
+ ).toBeInTheDocument();
+ });
});
- it('generic route renders correctly at the datafile level and requests the investigation & dataset entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(genericRoutes['datafiles']));
+ describe('DLS', () => {
+ it('DLS route renders correctly at the base level and does not request', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(DLSRoutes['proposals']));
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
- // Expect the axios.get to have been called twice; first to get the investigation
- // and second to get the dataset.
- expect(axios.get).toBeCalledTimes(2);
- expect(axios.get).toHaveBeenNthCalledWith(1, '/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(2, '/datasets/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ // Expect the axios.get to not have been called.
+ expect(axios.get).not.toBeCalled();
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/investigation');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.investigation');
+ it('DLS route renders correctly at the investigation level and requests the proposal entity', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(DLSRoutes['investigations']));
+
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
+
+ // Expect the axios.get to have been called twice.
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith(
+ '/investigations/findone?where=' +
+ JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
+ {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ }
+ );
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
- expect(within(breadcrumbs[1]).getByText('Name 1')).toBeInTheDocument();
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
+ });
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.datafile'
- )
- ).toBeInTheDocument();
+ it('DLS route renders correctly at the dataset level and requests the proposal & investigation entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(DLSRoutes['datasets']));
+
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
+
+ // Expect the axios.get to have been called twice.
+ expect(axios.get).toHaveBeenCalledTimes(2);
+ expect(axios.get).toHaveBeenNthCalledWith(
+ 1,
+ '/investigations/findone?where=' +
+ JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
+ {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ }
+ );
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/investigations/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browse/proposal/INVESTIGATION 1/investigation'
+ );
+ expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
+ expect(within(breadcrumbs[1]).getByText('1')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.dataset'
+ )
+ ).toBeInTheDocument();
+ });
+
+ it('DLS route renders correctly at the datafile level and requests the proposal, investigation and dataset entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(DLSRoutes['datafiles']));
+
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state);
+
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(3);
+ expect(axios.get).toHaveBeenNthCalledWith(
+ 1,
+ '/investigations/findone?where=' +
+ JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
+ {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ }
+ );
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/investigations/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(3, '/datasets/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browse/proposal/INVESTIGATION 1/investigation'
+ );
+ expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
+ expect(breadcrumbs[1]).toHaveAttribute(
+ 'href',
+ '/browse/proposal/INVESTIGATION 1/investigation/1/dataset'
+ );
+ expect(within(breadcrumbs[1]).getByText('1')).toBeInTheDocument();
+ expect(within(breadcrumbs[2]).getByText('Name 2')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.datafile'
+ )
+ ).toBeInTheDocument();
+ });
});
- it('DLS route renders correctly at the base level and does not request', async () => {
- // Set up test state pathname.
- history.replace(createLocation(DLSRoutes['proposals']));
+ describe('ISIS', () => {
+ it('ISIS route renders correctly at the base level and does not request', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISRoutes['instruments']));
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
- // Expect the axios.get to not have been called.
- expect(axios.get).not.toBeCalled();
+ // Expect the axios.get not to have been called
+ expect(axios.get).not.toHaveBeenCalled();
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
- });
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ expect(screen.getByTestId('Breadcrumb-base')).toHaveTextContent(
+ 'breadcrumbs.instrument'
+ );
+ });
- it('DLS route renders correctly at the investigation level and requests the proposal entity', async () => {
- // Set up test state pathname.
- history.replace(createLocation(DLSRoutes['investigations']));
+ it('ISIS route renders correctly at the facility cycle level and requests the instrument entity', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISRoutes['facilityCycles']));
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
- // Expect the axios.get to have been called twice.
- expect(axios.get).toHaveBeenCalledTimes(1);
- expect(axios.get).toHaveBeenCalledWith(
- '/investigations/findone?where=' +
- JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
- {
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith('/instruments/1', {
headers: {
Authorization: 'Bearer null',
},
- }
- );
+ });
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
- });
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
- it('DLS route renders correctly at the dataset level and requests the proposal & investigation entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(DLSRoutes['datasets']));
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.facilityCycle'
+ )
+ ).toBeInTheDocument();
+ });
- // Expect the axios.get to have been called twice.
- expect(axios.get).toHaveBeenCalledTimes(2);
- expect(axios.get).toHaveBeenNthCalledWith(
- 1,
- '/investigations/findone?where=' +
- JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
- {
+ it('ISIS route renders correctly at the investigation level and requests the instrument and facility cycle entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISRoutes['investigations']));
+
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
+
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(2);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
headers: {
Authorization: 'Bearer null',
},
- }
- );
- expect(axios.get).toHaveBeenNthCalledWith(2, '/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(within(breadcrumbs[1]).getByText('Name 2')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.investigation'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
+ it('ISIS route renders correctly at the dataset level and requests the instrument, facility cycle and investigation entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISRoutes['datasets']));
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(breadcrumbs[0]).toHaveAttribute(
- 'href',
- '/browse/proposal/INVESTIGATION 1/investigation'
- );
- expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
- expect(within(breadcrumbs[1]).getByText('1')).toBeInTheDocument();
-
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.dataset'
- )
- ).toBeInTheDocument();
- });
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
- it('DLS route renders correctly at the datafile level and requests the proposal, investigation and dataset entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(DLSRoutes['datafiles']));
-
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state);
-
- // Expect the axios.get to have been called three times.
- expect(axios.get).toHaveBeenCalledTimes(3);
- expect(axios.get).toHaveBeenNthCalledWith(
- 1,
- '/investigations/findone?where=' +
- JSON.stringify({ name: { eq: 'INVESTIGATION 1' } }),
- {
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(3);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
headers: {
Authorization: 'Bearer null',
},
- }
- );
- expect(axios.get).toHaveBeenNthCalledWith(2, '/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(3, '/datasets/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(3, '/investigations/3', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(breadcrumbs[1]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle/2/investigation'
+ );
+ expect(within(breadcrumbs[1]).getByText('Name 2')).toBeInTheDocument();
+ expect(breadcrumbs[2]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle/2/investigation/3'
+ );
+ expect(within(breadcrumbs[2]).getByText('Title 3')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.dataset'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/proposal');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.proposal');
-
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(breadcrumbs[0]).toHaveAttribute(
- 'href',
- '/browse/proposal/INVESTIGATION 1/investigation'
- );
- expect(within(breadcrumbs[0]).getByText('Title 1')).toBeInTheDocument();
- expect(breadcrumbs[1]).toHaveAttribute(
- 'href',
- '/browse/proposal/INVESTIGATION 1/investigation/1/dataset'
- );
- expect(within(breadcrumbs[1]).getByText('1')).toBeInTheDocument();
- expect(within(breadcrumbs[2]).getByText('Name 1')).toBeInTheDocument();
-
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.datafile'
- )
- ).toBeInTheDocument();
- });
-
- it('ISIS route renders correctly at the base level and does not request', async () => {
- // Set up test state pathname.
- history.replace(createLocation(ISISRoutes['instruments']));
-
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state, ['investigation', 'dataset']);
-
- // Expect the axios.get not to have been called
- expect(axios.get).not.toHaveBeenCalled();
+ it('ISIS route renders correctly at the datafile level and requests the instrument, facility cycle, investigation and dataset entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISRoutes['datafiles']));
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- expect(screen.getByTestId('Breadcrumb-base')).toHaveTextContent(
- 'breadcrumbs.instrument'
- );
- });
-
- it('ISIS route renders correctly at the facility cycle level and requests the instrument entity', async () => {
- // Set up test state pathname.
- history.replace(createLocation(ISISRoutes['facilityCycles']));
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state, ['investigation', 'dataset']);
-
- // Expect the axios.get to have been called three times.
- expect(axios.get).toHaveBeenCalledTimes(1);
- expect(axios.get).toHaveBeenCalledWith('/instruments/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(4);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(3, '/investigations/3', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(4, '/datasets/4', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(breadcrumbs[1]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle/2/investigation'
+ );
+ expect(within(breadcrumbs[1]).getByText('Name 2')).toBeInTheDocument();
+ expect(breadcrumbs[2]).toHaveAttribute(
+ 'href',
+ '/browse/instrument/1/facilityCycle/2/investigation/3'
+ );
+ expect(within(breadcrumbs[2]).getByText('Title 3')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.datafile'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
-
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
-
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.facilityCycle'
- )
- ).toBeInTheDocument();
- });
+ it('ISIS experiments route renders correctly at the base level and does not request', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISExperimentsRoutes['instruments']));
- it('ISIS route renders correctly at the investigation level and requests the instrument and facility cycle entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(ISISRoutes['investigations']));
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['investigation', 'dataset']);
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state, ['investigation', 'dataset']);
+ // Expect the axios.get not to have been called
+ expect(axios.get).not.toHaveBeenCalled();
- // Expect the axios.get to have been called three times.
- expect(axios.get).toHaveBeenCalledTimes(2);
- expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ expect(screen.getByTestId('Breadcrumb-base')).toHaveTextContent(
+ 'breadcrumbs.instrument'
+ );
});
- expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
-
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(breadcrumbs[0]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle'
- );
- expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
- expect(within(breadcrumbs[1]).getByText('Name 1')).toBeInTheDocument();
+ it('ISIS experiments route renders correctly at the study datapublications level and requests the instrument entity', async () => {
+ // Set up test state pathname.
+ history.replace(
+ createLocation(ISISExperimentsRoutes['studyDataPublications'])
+ );
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.investigation'
- )
- ).toBeInTheDocument();
- });
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['dataPublication', 'investigation', 'dataset']);
- it('ISIS route renders correctly at the dataset level and requests the instrument, facility cycle and investigation entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(ISISRoutes['datasets']));
-
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state, ['investigation', 'dataset']);
-
- // Expect the axios.get to have been called three times.
- expect(axios.get).toHaveBeenCalledTimes(3);
- expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(3, '/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ // Expect the axios.get to have been called 1 time.
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith('/instruments/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument'
+ );
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.dataPublication'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+ it('ISIS experiments route renders correctly at the data publication investigation level and requests the instrument and datapublication entities', async () => {
+ // Set up test state pathname.
+ history.replace(
+ createLocation(ISISExperimentsRoutes['investigationDataPublications'])
+ );
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(breadcrumbs[0]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle'
- );
- expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
- expect(breadcrumbs[1]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle/1/investigation'
- );
- expect(within(breadcrumbs[1]).getByText('Name 1')).toBeInTheDocument();
- expect(breadcrumbs[2]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle/1/investigation/1'
- );
- expect(within(breadcrumbs[2]).getByText('Title 1')).toBeInTheDocument();
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['dataPublication', 'investigation', 'dataset']);
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.dataset'
- )
- ).toBeInTheDocument();
- });
+ // Expect the axios.get to have been called 2 times.
+ expect(axios.get).toHaveBeenCalledTimes(2);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/datapublications/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument'
+ );
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(within(breadcrumbs[1]).getByText('Title 2')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.investigation'
+ )
+ ).toBeInTheDocument();
+ });
- it('ISIS route renders correctly at the datafile level and requests the instrument, facility cycle, investigation and dataset entities', async () => {
- // Set up test state pathname.
- history.replace(createLocation(ISISRoutes['datafiles']));
+ it('ISIS experiments route renders correctly at the dataset level and requests the instrument, data publication and investigation entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISExperimentsRoutes['datasets']));
- // Set up store with test state and mount the breadcrumb.
- renderComponent(state, ['investigation', 'dataset']);
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['dataPublication', 'investigation', 'dataset']);
- // Expect the axios.get to have been called three times.
- expect(axios.get).toHaveBeenCalledTimes(4);
- expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(2, '/facilitycycles/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(3, '/investigations/1', {
- headers: {
- Authorization: 'Bearer null',
- },
- });
- expect(axios.get).toHaveBeenNthCalledWith(4, '/datasets/1', {
- headers: {
- Authorization: 'Bearer null',
- },
+ // Expect the axios.get to have been called three times.
+ expect(axios.get).toHaveBeenCalledTimes(3);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/datapublications/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(3, '/datapublications/3', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument'
+ );
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(breadcrumbs[1]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2'
+ );
+ expect(within(breadcrumbs[1]).getByText('Title 2')).toBeInTheDocument();
+ expect(breadcrumbs[2]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/3'
+ );
+ expect(within(breadcrumbs[2]).getByText('Title 3')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.dataset'
+ )
+ ).toBeInTheDocument();
});
- expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
- const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
- expect(baseBreadcrumb).toHaveAttribute('href', '/browse/instrument');
- expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+ it('ISIS experiments route renders correctly at the datafile level and requests the instrument, data publication, investigation and dataset entities', async () => {
+ // Set up test state pathname.
+ history.replace(createLocation(ISISExperimentsRoutes['datafiles']));
- const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
- expect(breadcrumbs[0]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle'
- );
- expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
- expect(breadcrumbs[1]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle/1/investigation'
- );
- expect(within(breadcrumbs[1]).getByText('Name 1')).toBeInTheDocument();
- expect(breadcrumbs[2]).toHaveAttribute(
- 'href',
- '/browse/instrument/1/facilityCycle/1/investigation/1'
- );
- expect(within(breadcrumbs[2]).getByText('Title 1')).toBeInTheDocument();
+ // Set up store with test state and mount the breadcrumb.
+ renderComponent(state, ['dataPublication', 'investigation', 'dataset']);
- expect(
- within(screen.getByTestId('Breadcrumb-last')).getByText(
- 'breadcrumbs.datafile'
- )
- ).toBeInTheDocument();
+ // Expect the axios.get to have been called four times.
+ expect(axios.get).toHaveBeenCalledTimes(4);
+ expect(axios.get).toHaveBeenNthCalledWith(1, '/instruments/1', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(2, '/datapublications/2', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(3, '/datapublications/3', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+ expect(axios.get).toHaveBeenNthCalledWith(4, '/datasets/4', {
+ headers: {
+ Authorization: 'Bearer null',
+ },
+ });
+
+ expect(await screen.findByText('breadcrumbs.home')).toBeInTheDocument();
+ const baseBreadcrumb = screen.getByTestId('Breadcrumb-base');
+ expect(baseBreadcrumb).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument'
+ );
+ expect(baseBreadcrumb).toHaveTextContent('breadcrumbs.instrument');
+
+ const breadcrumbs = screen.getAllByTestId(/^Breadcrumb-hierarchy-\d+$/);
+ expect(breadcrumbs[0]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication'
+ );
+ expect(within(breadcrumbs[0]).getByText('Name 1')).toBeInTheDocument();
+ expect(breadcrumbs[1]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2'
+ );
+ expect(within(breadcrumbs[1]).getByText('Title 2')).toBeInTheDocument();
+ expect(breadcrumbs[2]).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/3'
+ );
+ expect(within(breadcrumbs[2]).getByText('Title 3')).toBeInTheDocument();
+
+ expect(
+ within(screen.getByTestId('Breadcrumb-last')).getByText(
+ 'breadcrumbs.datafile'
+ )
+ ).toBeInTheDocument();
+ });
});
});
diff --git a/packages/datagateway-dataview/src/page/breadcrumbs.component.tsx b/packages/datagateway-dataview/src/page/breadcrumbs.component.tsx
index a8629a115..59ea7d58d 100644
--- a/packages/datagateway-dataview/src/page/breadcrumbs.component.tsx
+++ b/packages/datagateway-dataview/src/page/breadcrumbs.component.tsx
@@ -107,36 +107,42 @@ const useEntityInformation = (
let apiEntity = entity;
// If the entity is a investigation or a data publication, we can't use name field as the default
- // TODO: what do we want to show for a datapublication breadcrumb?
let requestEntityField =
entity === 'investigation'
? 'title'
: entity === 'dataPublication'
- ? 'pid'
+ ? 'title'
: 'name';
+ // this is the field we use to lookup the relevant entity in ICAT - it's usually ID
+ // but for DLS proposals this will be name
+ let requestQueryField = 'id';
+
// Use breadcrumb settings in state to customise API call for entities.
- if (
- Object.entries(breadcrumbSettings).length !== 0 &&
- entity in breadcrumbSettings
- ) {
- const entitySettings = breadcrumbSettings[entity];
-
- // Check for a parent entity.
- if (
- !entitySettings.parentEntity ||
- (entitySettings.parentEntity &&
- currentPathnames.includes(entitySettings.parentEntity))
- ) {
- // Get the defined replace entity field.
- requestEntityField = entitySettings.replaceEntityField;
-
- // Get the replace entity, if one has been defined.
- if (entitySettings.replaceEntity) {
- apiEntity = entitySettings.replaceEntity;
+ breadcrumbSettings
+ .filter(
+ (breadcrumbSetting) => breadcrumbSetting.matchEntity === entity
+ )
+ .forEach((entitySettings) => {
+ // Check for a parent entity.
+ if (
+ !entitySettings.parentEntity ||
+ (entitySettings.parentEntity &&
+ currentPathnames.includes(entitySettings.parentEntity))
+ ) {
+ // Get the defined replace entity field.
+ requestEntityField = entitySettings.replaceEntityField;
+
+ // Get the replace entity, if one has been defined.
+ if (entitySettings.replaceEntity) {
+ apiEntity = entitySettings.replaceEntity;
+ }
+
+ if (entitySettings.replaceEntityQueryField) {
+ requestQueryField = entitySettings.replaceEntityQueryField;
+ }
}
- }
- }
+ });
// Create the entity url to request the name, this is pluralised to get the API endpoint.
let requestEntityUrl: string;
@@ -156,7 +162,7 @@ const useEntityInformation = (
requestEntityUrl =
pluralisedApiEntity.toLowerCase() +
'/findone?where=' +
- JSON.stringify({ name: { eq: entityId } });
+ JSON.stringify({ [requestQueryField]: { eq: entityId } });
}
queryConfigs.push({
diff --git a/packages/datagateway-dataview/src/page/idCheckFunctions.test.ts b/packages/datagateway-dataview/src/page/idCheckFunctions.test.ts
index 07672be8b..75f2cb441 100644
--- a/packages/datagateway-dataview/src/page/idCheckFunctions.test.ts
+++ b/packages/datagateway-dataview/src/page/idCheckFunctions.test.ts
@@ -4,8 +4,8 @@ import {
checkInstrumentAndFacilityCycleId,
saveApiUrlMiddleware,
checkInstrumentId,
- checkDataPublicationId,
- checkDatafileId,
+ checkStudyDataPublicationId,
+ checkDatasetId,
} from './idCheckFunctions';
import axios from 'axios';
import { handleICATError, ConfigureURLsType } from 'datagateway-common';
@@ -74,7 +74,7 @@ describe('ID check functions', () => {
expect.assertions(2);
(axios.get as jest.Mock).mockImplementation(() =>
Promise.resolve({
- data: { id: 2, name: 'Test dataset', investigation: { id: 1 } },
+ data: { id: 2, name: 'Test dataset' },
})
);
@@ -281,16 +281,16 @@ describe('ID check functions', () => {
});
});
- describe('checkDataPublicationId', () => {
- it('returns true on valid datapublication + investigation pair', async () => {
+ describe('checkStudyDataPublicationId', () => {
+ it('returns true on valid study datapublication + investigation data publication pair', async () => {
expect.assertions(3);
(axios.get as jest.Mock).mockImplementation(() =>
Promise.resolve({
- data: [{ id: 3, name: 'Test investigation' }],
+ data: [{ id: 3, title: 'Test DataPublication' }],
})
);
- const result = await checkDataPublicationId(2, 3);
+ const result = await checkStudyDataPublicationId(2, 3);
expect(result).toBe(true);
const params = new URLSearchParams();
params.append(
@@ -302,13 +302,14 @@ describe('ID check functions', () => {
params.append(
'where',
JSON.stringify({
- 'dataCollectionInvestigations.dataCollection.dataPublications.id': {
- eq: 2,
- },
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: 2,
+ },
})
);
expect(axios.get).toHaveBeenCalledWith(
- '/investigations/',
+ '/datapublications',
expect.objectContaining({
params,
})
@@ -317,7 +318,7 @@ describe('ID check functions', () => {
params.toString()
);
});
- it('returns false on invalid data publication + investigation pair', async () => {
+ it('returns false on invalid study datapublication + investigation data publication pair', async () => {
expect.assertions(1);
(axios.get as jest.Mock).mockImplementation(() =>
Promise.resolve({
@@ -325,7 +326,7 @@ describe('ID check functions', () => {
})
);
- const result = await checkDataPublicationId(2, 3);
+ const result = await checkStudyDataPublicationId(2, 3);
expect(result).toBe(false);
});
it('returns false on HTTP error', async () => {
@@ -336,70 +337,66 @@ describe('ID check functions', () => {
})
);
- const result = await checkDataPublicationId(2, 3);
+ const result = await checkStudyDataPublicationId(2, 3);
expect(result).toBe(false);
expect(handleICATError).toHaveBeenCalledWith({
message: 'Test error message',
});
});
});
-});
-
-describe('checkDatafileId', () => {
- it('should return true when the given investigation + dataset + datafile id matches', async () => {
- (axios.get as jest.Mock).mockResolvedValue({
- data: [
- {
- id: 123,
- dataset: {
- id: 234,
- investigation: {
- id: 456,
- },
- },
- },
- ],
- });
- expect(await checkDatafileId(456, 234, 123)).toBe(true);
- });
+ describe('checkDatasetId', () => {
+ it('returns true on valid dataset + datafile pair', async () => {
+ expect.assertions(2);
+ (axios.get as jest.Mock).mockImplementation(() =>
+ Promise.resolve({
+ data: { id: 2, name: 'Test datafile' },
+ })
+ );
- it('should return false when the given investigation + dataset + datafile id does not match', async () => {
- // datafile id and dataset id matches but not investigation
- (axios.get as jest.Mock).mockResolvedValue({
- data: [
- {
- id: 123,
- dataset: {
- id: 234,
- investigation: {
- id: 456,
- },
+ const result = await checkDatasetId(1, 2);
+ expect(result).toBe(true);
+ const params = new URLSearchParams();
+ params.append(
+ 'where',
+ JSON.stringify({
+ id: {
+ eq: 2,
},
- },
- ],
+ })
+ );
+ params.append('where', JSON.stringify({ 'dataset.id': { eq: 1 } }));
+ expect(axios.get).toHaveBeenCalledWith('/datafiles/findone', {
+ params,
+ headers: { Authorization: 'Bearer null' },
+ });
});
+ it('returns false on invalid dataset + datafile pair', async () => {
+ expect.assertions(2);
+ (axios.get as jest.Mock).mockImplementation(() =>
+ Promise.reject({
+ response: { status: 404 },
+ isAxiosError: true,
+ })
+ );
- // dataset & datafile matches but not investigation
- expect(await checkDatafileId(100, 234, 123)).toBe(false);
- // investigation & datafile matches but not dataset
- expect(await checkDatafileId(456, 199, 123)).toBe(false);
- // only datafile matches
- expect(await checkDatafileId(199, 200, 123)).toBe(false);
- // no match at all
- expect(await checkDatafileId(1, 2, 0)).toBe(false);
- });
+ const result = await checkDatasetId(1, 2);
+ expect(result).toBe(false);
+ expect(handleICATError).not.toHaveBeenCalled();
+ });
+ it('returns false on HTTP error', async () => {
+ expect.assertions(2);
+ (axios.get as jest.Mock).mockImplementation(() =>
+ Promise.reject({
+ message: 'Test error message',
+ })
+ );
- it('should return false when an http error is encountered', async () => {
- (axios.get as jest.Mock).mockImplementation(() =>
- Promise.reject({
+ const result = await checkDatasetId(1, 2);
+ expect(result).toBe(false);
+ expect(handleICATError).toHaveBeenCalledWith({
message: 'Test error message',
- })
- );
-
- expect(await checkDatafileId(456, 234, 123)).toBe(false);
- expect(handleICATError).toHaveBeenCalledWith({
- message: 'Test error message',
+ });
});
});
});
diff --git a/packages/datagateway-dataview/src/page/idCheckFunctions.ts b/packages/datagateway-dataview/src/page/idCheckFunctions.ts
index 3bfd5c0af..23b5a605b 100644
--- a/packages/datagateway-dataview/src/page/idCheckFunctions.ts
+++ b/packages/datagateway-dataview/src/page/idCheckFunctions.ts
@@ -2,8 +2,6 @@ import axios, { AxiosResponse } from 'axios';
import {
handleICATError,
Investigation,
- Dataset,
- Datafile,
ConfigureURLsType,
readSciGatewayToken,
} from 'datagateway-common';
@@ -106,27 +104,28 @@ export const checkInstrumentAndFacilityCycleId = memoize(
(...args) => JSON.stringify(args)
);
-const unmemoizedCheckDataPublicationId = (
- dataPublicationId: number,
- investigationId: number
+const unmemoizedCheckStudyDataPublicationId = (
+ studyDataPublicationId: number,
+ investigationDataPublicationId: number
): Promise => {
const params = new URLSearchParams();
params.append(
'where',
JSON.stringify({
- id: { eq: investigationId },
+ id: { eq: investigationDataPublicationId },
})
);
params.append(
'where',
JSON.stringify({
- 'dataCollectionInvestigations.dataCollection.dataPublications.id': {
- eq: dataPublicationId,
- },
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: studyDataPublicationId,
+ },
})
);
return axios
- .get(`${apiUrl}/investigations/`, {
+ .get(`${apiUrl}/datapublications`, {
params,
headers: {
Authorization: `Bearer ${readSciGatewayToken().sessionId}`,
@@ -141,8 +140,8 @@ const unmemoizedCheckDataPublicationId = (
});
};
-export const checkDataPublicationId = memoize(
- unmemoizedCheckDataPublicationId,
+export const checkStudyDataPublicationId = memoize(
+ unmemoizedCheckStudyDataPublicationId,
(...args) => JSON.stringify(args)
);
@@ -211,35 +210,40 @@ export const checkProposalName = memoize(
(...args) => JSON.stringify(args)
);
-export const unmemoizedCheckDatafileId = (
- investigationId: Investigation['id'],
- datasetId: Dataset['id'],
- datafileId: Datafile['id']
-): Promise =>
- axios
- .get(`${apiUrl}/datafiles`, {
- params: {
- include: JSON.stringify(['dataset', 'dataset.investigation']),
- where: JSON.stringify({ id: { eq: datafileId } }),
+const unmemoizedCheckDatasetId = (
+ datasetId: number,
+ datafileId: number
+): Promise => {
+ const params = new URLSearchParams();
+ params.append(
+ 'where',
+ JSON.stringify({
+ id: {
+ eq: datafileId,
},
+ })
+ );
+ params.append('where', JSON.stringify({ 'dataset.id': { eq: datasetId } }));
+ return axios
+ .get(`${apiUrl}/datafiles/findone`, {
+ params,
headers: {
Authorization: `Bearer ${readSciGatewayToken().sessionId}`,
},
})
- .then((response: AxiosResponse) => {
- if (response.data.length <= 0) return false;
- const datafile = response.data[0];
- return (
- datafile.id === datafileId &&
- datafile.dataset?.id === datasetId &&
- datafile.dataset?.investigation?.id === investigationId
- );
+ .then(() => {
+ return true;
})
.catch((error) => {
+ // 404 is valid response from API saying the investigation id is invalid
+ if (axios.isAxiosError(error) && error.response?.status === 404)
+ return false;
+ // handle other API errors
handleICATError(error);
return false;
});
+};
-export const checkDatafileId = memoize(unmemoizedCheckDatafileId, (...args) =>
+export const checkDatasetId = memoize(unmemoizedCheckDatasetId, (...args) =>
JSON.stringify(args)
);
diff --git a/packages/datagateway-dataview/src/page/pageContainer.component.tsx b/packages/datagateway-dataview/src/page/pageContainer.component.tsx
index 163e606c8..af6cbc8bb 100644
--- a/packages/datagateway-dataview/src/page/pageContainer.component.tsx
+++ b/packages/datagateway-dataview/src/page/pageContainer.component.tsx
@@ -124,10 +124,12 @@ export const paths = {
root: '/browseDataPublications',
toggle: {
isisInstrument: '/browseDataPublications/instrument',
+ isisStudyDataPublication:
+ '/browseDataPublications/instrument/:instrumentId/dataPublication',
+ isisInvestigationDataPublication:
+ '/browseDataPublications/instrument/:instrumentId/dataPublication/:studyDataPublicationId/investigation',
isisDataPublication:
'/browseDataPublications/instrument/:instrumentId/dataPublication',
- isisInvestigation:
- '/browseDataPublications/instrument/:instrumentId/dataPublication/:dataPublicationId/investigation',
isisDataset:
'/browseDataPublications/instrument/:instrumentId/dataPublication/:dataPublicationId/investigation/:investigationId/dataset',
},
@@ -148,6 +150,8 @@ export const paths = {
preview: {
isisDatafilePreview:
'/browse/instrument/:instrumentId/facilityCycle/:facilityCycleId/investigation/:investigationId/dataset/:datasetId/datafile/:datafileId',
+ isisDataPublicationDatafilePreview:
+ '/browseDataPublications/instrument/:instrumentId/dataPublication/:dataPublicationId/investigation/:investigationId/dataset/:datasetId/datafile/:datafileId',
},
};
diff --git a/packages/datagateway-dataview/src/page/pageRouting.component.test.tsx b/packages/datagateway-dataview/src/page/pageRouting.component.test.tsx
index 5fddd51e2..d9e975f49 100644
--- a/packages/datagateway-dataview/src/page/pageRouting.component.test.tsx
+++ b/packages/datagateway-dataview/src/page/pageRouting.component.test.tsx
@@ -7,14 +7,15 @@ import { Router } from 'react-router-dom';
import PageRouting from './pageRouting.component';
import { Provider } from 'react-redux';
import { initialState as dgDataViewInitialState } from '../state/reducers/dgdataview.reducer';
-import { dGCommonInitialState } from 'datagateway-common';
+import { DataPublication, dGCommonInitialState } from 'datagateway-common';
import {
- checkDataPublicationId,
+ checkDatasetId,
checkInstrumentAndFacilityCycleId,
checkInstrumentId,
checkInvestigationId,
checkProposalName,
+ checkStudyDataPublicationId,
} from './idCheckFunctions';
import { findColumnHeaderByName, flushPromises } from '../setupTests';
import { act } from 'react-dom/test-utils';
@@ -46,6 +47,8 @@ const ISISRoutes = {
investigation: '/browse/instrument/1/facilityCycle/1/investigation/1',
dataset: '/browse/instrument/1/facilityCycle/1/investigation/1/dataset/1',
},
+ datafilePreview:
+ '/browse/instrument/1/facilityCycle/1/investigation/1/dataset/1/datafile/1',
};
// The ISIS DataPublications routes to test.
@@ -65,6 +68,8 @@ const ISISDataPublicationsRoutes = {
dataset:
'/browseDataPublications/instrument/1/dataPublication/1/investigation/1/dataset/1',
},
+ datafilePreview:
+ '/browseDataPublications/instrument/1/dataPublication/1/investigation/1/dataset/1/datafile/1',
};
// The DLS routes to test.
@@ -110,6 +115,31 @@ describe('PageTable', () => {
(axios.get as jest.Mock).mockImplementation((url: string) => {
if (url.includes('count')) {
return Promise.resolve({ data: 0 });
+ } else if (url.includes('datapublications')) {
+ // this is so that routes can convert from data pub id -> investigation id
+ return Promise.resolve({
+ data: [
+ {
+ id: 1,
+ pid: 'pid.1',
+ title: 'test',
+ content: {
+ id: 2,
+ dataCollectionInvestigations: [
+ {
+ id: 3,
+ investigation: {
+ id: 4,
+ title: 'Test',
+ name: 'test',
+ visitId: '1',
+ },
+ },
+ ],
+ },
+ } satisfies DataPublication,
+ ],
+ });
} else {
return Promise.resolve({ data: [] });
}
@@ -120,7 +150,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(true)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(true)
);
(checkInvestigationId as jest.Mock).mockImplementation(() =>
@@ -129,6 +159,9 @@ describe('PageTable', () => {
(checkProposalName as jest.Mock).mockImplementation(() =>
Promise.resolve(true)
);
+ (checkDatasetId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(true)
+ );
});
afterEach(() => {
@@ -726,6 +759,48 @@ describe('PageTable', () => {
expect(await screen.findByText('loading.oops')).toBeInTheDocument();
});
+
+ it('renders DatafilePreviewer for ISIS datafiles previewer route', async () => {
+ history.push(ISISRoutes.datafilePreview);
+
+ render(
+ ,
+ { wrapper: Wrapper }
+ );
+
+ expect(
+ await screen.findByText('datafiles.preview.invalid_datafile')
+ ).toBeInTheDocument();
+ });
+
+ it('does not render DatafilePreviewer for incorrect ISIS datafiles previewer route', async () => {
+ (checkInstrumentAndFacilityCycleId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+ (checkInvestigationId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+ (checkDatasetId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+
+ history.push(ISISRoutes.datafilePreview);
+
+ render(
+ ,
+ { wrapper: Wrapper }
+ );
+
+ expect(await screen.findByText('loading.oops')).toBeInTheDocument();
+ });
});
describe('ISIS Data Publication Hierarchy', () => {
@@ -784,9 +859,6 @@ describe('PageTable', () => {
expect(
await findColumnHeaderByName('datapublications.pid')
).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('datapublications.publication_date')
- ).toBeInTheDocument();
});
it('renders ISISDataPublicationsCardView for ISIS dataPublications route in Data Publication Hierarchy', async () => {
@@ -855,25 +927,13 @@ describe('PageTable', () => {
);
expect(
- await findColumnHeaderByName('investigations.title')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('investigations.name')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('investigations.doi')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('investigations.size')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('investigations.principal_investigators')
+ await findColumnHeaderByName('datapublications.title')
).toBeInTheDocument();
expect(
- await findColumnHeaderByName('investigations.start_date')
+ await findColumnHeaderByName('datapublications.pid')
).toBeInTheDocument();
expect(
- await findColumnHeaderByName('investigations.end_date')
+ await findColumnHeaderByName('datapublications.publication_date')
).toBeInTheDocument();
});
@@ -890,7 +950,7 @@ describe('PageTable', () => {
);
expect(
- await screen.findByTestId('isis-investigations-card-view')
+ await screen.findByTestId('isis-dataPublications-card-view')
).toBeInTheDocument();
});
@@ -920,7 +980,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
@@ -959,7 +1019,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
@@ -998,7 +1058,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
@@ -1037,7 +1097,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
@@ -1085,7 +1145,7 @@ describe('PageTable', () => {
(checkInstrumentId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
- (checkDataPublicationId as jest.Mock).mockImplementation(() =>
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
Promise.resolve(false)
);
(checkInvestigationId as jest.Mock).mockImplementation(() =>
@@ -1105,6 +1165,51 @@ describe('PageTable', () => {
expect(await screen.findByText('loading.oops')).toBeInTheDocument();
});
+
+ it('renders DatafilePreviewer for ISIS datafile preview route in Data Publication Hierarchy', async () => {
+ history.push(ISISDataPublicationsRoutes.datafilePreview);
+
+ render(
+ ,
+ { wrapper: Wrapper }
+ );
+
+ expect(
+ await screen.findByText('datafiles.preview.invalid_datafile')
+ ).toBeInTheDocument();
+ });
+
+ it('does not render DatafilePreviewer for incorrect ISIS datafile preview route in Data Publication Hierarchy', async () => {
+ (checkInstrumentId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+ (checkStudyDataPublicationId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+ (checkInvestigationId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+ (checkDatasetId as jest.Mock).mockImplementation(() =>
+ Promise.resolve(false)
+ );
+
+ history.push(ISISDataPublicationsRoutes.datafilePreview);
+
+ render(
+ ,
+ { wrapper: Wrapper }
+ );
+
+ expect(await screen.findByText('loading.oops')).toBeInTheDocument();
+ });
});
describe('DLS', () => {
diff --git a/packages/datagateway-dataview/src/page/pageRouting.component.tsx b/packages/datagateway-dataview/src/page/pageRouting.component.tsx
index d4895d650..fec453efc 100644
--- a/packages/datagateway-dataview/src/page/pageRouting.component.tsx
+++ b/packages/datagateway-dataview/src/page/pageRouting.component.tsx
@@ -50,12 +50,12 @@ import {
checkInvestigationId,
checkInstrumentAndFacilityCycleId,
checkInstrumentId,
- checkDataPublicationId,
- checkDatafileId,
+ checkStudyDataPublicationId,
+ checkDatasetId,
} from './idCheckFunctions';
import { paths } from './pageContainer.component';
-import type { ViewsType } from 'datagateway-common';
+import { useDataPublication, ViewsType } from 'datagateway-common';
const SafeDatafileTable = React.memo(
(props: {
@@ -78,164 +78,258 @@ const SafeDatafileTable = React.memo(
);
SafeDatafileTable.displayName = 'SafeDatafileTable';
-const SafeISISDatafilesTable = React.memo(
- (props: {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
- datasetId: string;
- dataPublication: boolean;
- }): React.ReactElement => {
- const SafeISISDatafilesTable = props.dataPublication
- ? withIdCheck(
- Promise.all([
- checkInstrumentId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId)
- ),
- checkDataPublicationId(
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- ),
- checkInvestigationId(
- parseInt(props.investigationId),
- parseInt(props.datasetId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatafilesTable)
- : withIdCheck(
- Promise.all([
+const SafeISISDatafilesTable = (props: {
+ instrumentId: string;
+ instrumentChildId: string;
+ investigationId: string;
+ datasetId: string;
+ dataPublication: boolean;
+}): React.ReactElement => {
+ const { data, isLoading } = useDataPublication(
+ parseInt(props.investigationId),
+ {
+ enabled: props.dataPublication,
+ }
+ );
+ const dataPublicationInvestigationId =
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation?.id;
+
+ const SafeISISDatafilesTable = React.useMemo(
+ () =>
+ props.dataPublication
+ ? withIdCheck(
+ Promise.all([
+ checkInstrumentId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId)
+ ),
+ checkStudyDataPublicationId(
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ dataPublicationInvestigationId ?? -1,
+ parseInt(props.datasetId)
+ ),
+ ...(isLoading ? [new Promise(() => undefined)] : []),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatafilesTable)
+ : withIdCheck(
+ Promise.all([
+ checkInstrumentAndFacilityCycleId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ parseInt(props.investigationId),
+ parseInt(props.datasetId)
+ ),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatafilesTable),
+ [
+ dataPublicationInvestigationId,
+ isLoading,
+ props.dataPublication,
+ props.datasetId,
+ props.instrumentChildId,
+ props.instrumentId,
+ props.investigationId,
+ ]
+ );
+
+ return (
+
+ );
+};
+
+const SafeISISDatasetLanding = (props: {
+ instrumentId: string;
+ instrumentChildId: string;
+ investigationId: string;
+ datasetId: string;
+ dataPublication: boolean;
+}): React.ReactElement => {
+ const { data, isLoading } = useDataPublication(
+ parseInt(props.investigationId),
+ {
+ enabled: props.dataPublication,
+ }
+ );
+ const dataPublicationInvestigationId =
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation?.id;
+
+ const SafeISISDatasetLanding = React.useMemo(
+ () =>
+ props.dataPublication
+ ? withIdCheck(
+ Promise.all([
+ checkInstrumentId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId)
+ ),
+ checkStudyDataPublicationId(
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ dataPublicationInvestigationId ?? -1,
+ parseInt(props.datasetId)
+ ),
+ ...(isLoading ? [new Promise(() => undefined)] : []),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatasetLanding)
+ : withIdCheck(
+ Promise.all([
+ checkInstrumentAndFacilityCycleId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ parseInt(props.investigationId),
+ parseInt(props.datasetId)
+ ),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatasetLanding),
+ [
+ dataPublicationInvestigationId,
+ isLoading,
+ props.dataPublication,
+ props.datasetId,
+ props.instrumentChildId,
+ props.instrumentId,
+ props.investigationId,
+ ]
+ );
+
+ return ;
+};
+
+const SafeISISDatasetsTable = (props: {
+ instrumentId: string;
+ instrumentChildId: string;
+ investigationId: string;
+ dataPublication: boolean;
+}): React.ReactElement => {
+ const { data, isLoading } = useDataPublication(
+ parseInt(props.investigationId),
+ {
+ enabled: props.dataPublication,
+ }
+ );
+
+ const dataPublicationInvestigationId =
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation?.id;
+
+ const SafeISISDatasetsTable = React.useMemo(
+ () =>
+ props.dataPublication
+ ? withIdCheck(
+ Promise.all([
+ checkInstrumentId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId)
+ ),
+ checkStudyDataPublicationId(
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ ...(isLoading ? [new Promise(() => undefined)] : []),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatasetsTable)
+ : withIdCheck(
checkInstrumentAndFacilityCycleId(
parseInt(props.instrumentId),
parseInt(props.instrumentChildId),
parseInt(props.investigationId)
- ),
- checkInvestigationId(
- parseInt(props.investigationId),
- parseInt(props.datasetId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatafilesTable);
-
- return (
-
- );
- }
-);
-SafeISISDatafilesTable.displayName = 'SafeISISDatafilesTable';
-
-const SafeISISDatasetLanding = React.memo(
- (props: {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
- datasetId: string;
- dataPublication: boolean;
- }): React.ReactElement => {
- const SafeISISDatasetLanding = props.dataPublication
- ? withIdCheck(
- Promise.all([
- checkInstrumentId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId)
- ),
- checkDataPublicationId(
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- ),
- checkInvestigationId(
- parseInt(props.investigationId),
- parseInt(props.datasetId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatasetLanding)
- : withIdCheck(
- Promise.all([
+ )
+ )(ISISDatasetsTable),
+ [
+ isLoading,
+ props.dataPublication,
+ props.instrumentChildId,
+ props.instrumentId,
+ props.investigationId,
+ ]
+ );
+
+ return (
+
+ );
+};
+
+const SafeISISDatasetsCardView = (props: {
+ instrumentId: string;
+ instrumentChildId: string;
+ investigationId: string;
+ dataPublication: boolean;
+}): React.ReactElement => {
+ const { data, isLoading } = useDataPublication(
+ parseInt(props.investigationId),
+ {
+ enabled: props.dataPublication,
+ }
+ );
+
+ const dataPublicationInvestigationId =
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation?.id;
+
+ const SafeISISDatasetsCardView = React.useMemo(
+ () =>
+ props.dataPublication
+ ? withIdCheck(
+ Promise.all([
+ checkInstrumentId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId)
+ ),
+ checkStudyDataPublicationId(
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ ...(isLoading ? [new Promise(() => undefined)] : []),
+ ]).then((values) => !values.includes(false))
+ )(ISISDatasetsCardView)
+ : withIdCheck(
checkInstrumentAndFacilityCycleId(
parseInt(props.instrumentId),
parseInt(props.instrumentChildId),
parseInt(props.investigationId)
- ),
- checkInvestigationId(
- parseInt(props.investigationId),
- parseInt(props.datasetId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatasetLanding);
-
- return ;
- }
-);
-SafeISISDatasetLanding.displayName = 'SafeISISDatasetLanding';
-
-const SafeISISDatasetsTable = React.memo(
- (props: {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
- dataPublication: boolean;
- }): React.ReactElement => {
- const SafeISISDatasetsTable = props.dataPublication
- ? withIdCheck(
- Promise.all([
- checkInstrumentId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId)
- ),
- checkDataPublicationId(
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatasetsTable)
- : withIdCheck(
- checkInstrumentAndFacilityCycleId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- )
- )(ISISDatasetsTable);
-
- return ;
- }
-);
-SafeISISDatasetsTable.displayName = 'SafeISISDatasetsTable';
-
-const SafeISISDatasetsCardView = React.memo(
- (props: {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
- dataPublication: boolean;
- }): React.ReactElement => {
- const SafeISISDatasetsCardView = props.dataPublication
- ? withIdCheck(
- Promise.all([
- checkInstrumentId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId)
- ),
- checkDataPublicationId(
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- ),
- ]).then((values) => !values.includes(false))
- )(ISISDatasetsCardView)
- : withIdCheck(
- checkInstrumentAndFacilityCycleId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- )
- )(ISISDatasetsCardView);
-
- return ;
- }
-);
-SafeISISDatasetsCardView.displayName = 'SafeISISDatasetsCardView';
+ )
+ )(ISISDatasetsCardView),
+ [
+ isLoading,
+ props.dataPublication,
+ props.instrumentChildId,
+ props.instrumentId,
+ props.investigationId,
+ ]
+ );
+
+ return (
+
+ );
+};
const SafeISISInvestigationLanding = React.memo(
(props: {
@@ -251,7 +345,7 @@ const SafeISISInvestigationLanding = React.memo(
parseInt(props.instrumentId),
parseInt(props.instrumentChildId)
),
- checkDataPublicationId(
+ checkStudyDataPublicationId(
parseInt(props.instrumentChildId),
parseInt(props.investigationId)
),
@@ -265,7 +359,13 @@ const SafeISISInvestigationLanding = React.memo(
)
)(ISISInvestigationLanding);
- return ;
+ return (
+
+ );
}
);
SafeISISInvestigationLanding.displayName = 'SafeISISInvestigationLanding';
@@ -351,33 +451,79 @@ const SafeDLSDatasetsCardView = React.memo(
);
SafeDLSDatasetsCardView.displayName = 'SafeDLSDatasetsCardView';
-const SafeDatafilePreviewer = React.memo(
- (props: {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
- datasetId: string;
- datafileId: string;
- }): React.ReactElement => {
- const SafeDatafilePreviewer = withIdCheck(
- Promise.all([
- checkInstrumentAndFacilityCycleId(
- parseInt(props.instrumentId),
- parseInt(props.instrumentChildId),
- parseInt(props.investigationId)
- ),
- checkDatafileId(
- parseInt(props.investigationId),
- parseInt(props.datasetId),
- parseInt(props.datafileId)
- ),
- ]).then((checks) => checks.every((passes) => passes))
- )(DatafilePreviewer);
-
- return ;
- }
-);
-SafeDatafilePreviewer.displayName = 'SafeDatafilePreviewer';
+const SafeDatafilePreviewer = (props: {
+ dataPublication: boolean;
+ instrumentId: string;
+ instrumentChildId: string;
+ investigationId: string;
+ datasetId: string;
+ datafileId: string;
+}): React.ReactElement => {
+ const { data, isLoading } = useDataPublication(
+ parseInt(props.investigationId),
+ {
+ enabled: props.dataPublication,
+ }
+ );
+
+ const dataPublicationInvestigationId =
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation?.id;
+
+ const SafeDatafilePreviewer = React.useMemo(
+ () =>
+ props.dataPublication
+ ? withIdCheck(
+ Promise.all([
+ checkInstrumentId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId)
+ ),
+ checkStudyDataPublicationId(
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ dataPublicationInvestigationId ?? -1,
+ parseInt(props.datasetId)
+ ),
+ checkDatasetId(
+ parseInt(props.datasetId),
+ parseInt(props.datafileId)
+ ),
+ ...(isLoading ? [new Promise(() => undefined)] : []),
+ ]).then((values) => !values.includes(false))
+ )(DatafilePreviewer)
+ : withIdCheck(
+ Promise.all([
+ checkInstrumentAndFacilityCycleId(
+ parseInt(props.instrumentId),
+ parseInt(props.instrumentChildId),
+ parseInt(props.investigationId)
+ ),
+ checkInvestigationId(
+ parseInt(props.investigationId),
+ parseInt(props.datasetId)
+ ),
+ checkDatasetId(
+ parseInt(props.datasetId),
+ parseInt(props.datafileId)
+ ),
+ ]).then((checks) => checks.every((passes) => passes))
+ )(DatafilePreviewer),
+ [
+ dataPublicationInvestigationId,
+ isLoading,
+ props.dataPublication,
+ props.datafileId,
+ props.datasetId,
+ props.instrumentChildId,
+ props.instrumentId,
+ props.investigationId,
+ ]
+ );
+
+ return ;
+};
interface PageRoutingProps {
view: ViewsType;
@@ -493,7 +639,7 @@ class PageRouting extends React.PureComponent {
/>
this.props.view === 'card' ? (
{
/>
this.props.view === 'card' ? (
-
) : (
-
)
}
@@ -594,6 +742,20 @@ class PageRouting extends React.PureComponent {
/>
)}
/>
+ (
+
+ )}
+ />
{/* ISIS routes */}
{
render={({ match }) =>
this.props.view === 'card' ? (
) : (
)
}
@@ -705,6 +865,7 @@ class PageRouting extends React.PureComponent {
path={paths.preview.isisDatafilePreview}
render={({ match }) => (
{
});
it('given JSON loadBreadcrumbSettings returns a ConfigureBreadcrumbSettingsType with ConfigureBreadcrumbSettingsPayload', () => {
- const action = loadBreadcrumbSettings({
- test: {
+ const action = loadBreadcrumbSettings([
+ {
+ matchEntity: 'test',
replaceEntity: 'testEntity',
replaceEntityField: 'testField',
},
- });
+ ]);
expect(action.type).toEqual(ConfigureBreadcrumbSettingsType);
expect(action.payload).toEqual({
- settings: {
- test: {
+ settings: [
+ {
+ matchEntity: 'test',
replaceEntity: 'testEntity',
replaceEntityField: 'testField',
},
- },
+ ],
});
});
@@ -95,11 +97,12 @@ describe('Actions', () => {
features: {},
idsUrl: 'ids',
apiUrl: 'api',
- breadcrumbs: {
- test: {
+ breadcrumbs: [
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- },
+ ],
downloadApiUrl: 'download-api',
selectAllSetting: false,
routes: [
@@ -127,11 +130,12 @@ describe('Actions', () => {
})
);
expect(actions).toContainEqual(
- loadBreadcrumbSettings({
- test: {
+ loadBreadcrumbSettings([
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- })
+ ])
);
expect(actions).toContainEqual(settingsLoaded());
expect(actions).toContainEqual(loadSelectAllSetting(false));
diff --git a/packages/datagateway-dataview/src/state/actions/actions.types.tsx b/packages/datagateway-dataview/src/state/actions/actions.types.tsx
index 4e25d3eaa..b3b04ddf1 100644
--- a/packages/datagateway-dataview/src/state/actions/actions.types.tsx
+++ b/packages/datagateway-dataview/src/state/actions/actions.types.tsx
@@ -19,7 +19,7 @@ export interface FeatureSwitchesPayload {
export interface FeatureSwitches {}
export interface ConfigureBreadcrumbSettingsPayload {
- settings: BreadcrumbSettings;
+ settings: BreadcrumbSettings[];
}
export interface ConfigureSelectAllSettingPayload {
@@ -35,9 +35,9 @@ export interface ConfigureFacilityImageSettingPayload {
}
export interface BreadcrumbSettings {
- [matchEntity: string]: {
- replaceEntityField: string;
- replaceEntity?: string;
- parentEntity?: string;
- };
+ matchEntity: string;
+ replaceEntityField: string;
+ replaceEntityQueryField?: string;
+ replaceEntity?: string;
+ parentEntity?: string;
}
diff --git a/packages/datagateway-dataview/src/state/actions/index.tsx b/packages/datagateway-dataview/src/state/actions/index.tsx
index fa8bb63b9..0e93bee90 100644
--- a/packages/datagateway-dataview/src/state/actions/index.tsx
+++ b/packages/datagateway-dataview/src/state/actions/index.tsx
@@ -32,7 +32,7 @@ export const loadFeatureSwitches = (
});
export const loadBreadcrumbSettings = (
- breadcrumbSettings: BreadcrumbSettings
+ breadcrumbSettings: BreadcrumbSettings[]
): ActionType => ({
type: ConfigureBreadcrumbSettingsType,
payload: {
diff --git a/packages/datagateway-dataview/src/state/app.types.tsx b/packages/datagateway-dataview/src/state/app.types.tsx
index 55b9611de..8fcfaed39 100644
--- a/packages/datagateway-dataview/src/state/app.types.tsx
+++ b/packages/datagateway-dataview/src/state/app.types.tsx
@@ -10,7 +10,7 @@ import type {
export interface DGDataViewState {
facilityImageURL: string;
features: FeatureSwitches;
- breadcrumbSettings: BreadcrumbSettings;
+ breadcrumbSettings: BreadcrumbSettings[];
settingsLoaded: boolean;
selectAllSetting: boolean;
pluginHost: string;
diff --git a/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.test.tsx b/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.test.tsx
index bbad966e7..3189f26cc 100644
--- a/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.test.tsx
+++ b/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.test.tsx
@@ -46,22 +46,24 @@ describe('dgdataview reducer', () => {
});
it('should set breadcrumb settings property when configure breadcrumb settings action is sent', () => {
- expect(state.dgdataview.breadcrumbSettings).toEqual({});
+ expect(state.dgdataview.breadcrumbSettings).toEqual([]);
const updatedState = DGDataViewReducer(
state,
- loadBreadcrumbSettings({
- test: {
+ loadBreadcrumbSettings([
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- })
+ ])
);
- expect(updatedState.breadcrumbSettings).toEqual({
- test: {
+ expect(updatedState.breadcrumbSettings).toEqual([
+ {
+ matchEntity: 'test',
replaceEntityField: 'title',
},
- });
+ ]);
});
it('should set selectAllSetting when configuring action is sent', () => {
diff --git a/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.tsx b/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.tsx
index 14c3eed80..d7d3099b0 100644
--- a/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.tsx
+++ b/packages/datagateway-dataview/src/state/reducers/dgdataview.reducer.tsx
@@ -20,7 +20,7 @@ import {
export const initialState: DGDataViewState = {
features: {},
- breadcrumbSettings: {},
+ breadcrumbSettings: [],
settingsLoaded: false,
selectAllSetting: true,
pluginHost: '',
diff --git a/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.test.tsx b/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.test.tsx
index 77d48a1f7..c262dada8 100644
--- a/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.test.tsx
+++ b/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.test.tsx
@@ -1,7 +1,7 @@
import { type DataPublication, dGCommonInitialState } from 'datagateway-common';
import * as React from 'react';
import { Provider } from 'react-redux';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import type { StateType } from '../../../state/app.types';
@@ -21,6 +21,7 @@ import {
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import axios, { AxiosResponse } from 'axios';
+import { paths } from '../../../page/pageContainer.component';
describe('ISIS Data Publication - Card View', () => {
let mockStore;
@@ -28,16 +29,30 @@ describe('ISIS Data Publication - Card View', () => {
let cardData: DataPublication[];
let history: History;
- const renderComponent = (): RenderResult =>
- render(
+ const renderComponent = (studyDataPublicationId?: string): RenderResult => {
+ if (studyDataPublicationId)
+ history.replace(
+ generatePath(
+ paths.dataPublications.toggle.isisInvestigationDataPublication,
+ {
+ instrumentId: 1,
+ studyDataPublicationId,
+ }
+ )
+ );
+ return render(
-
+
);
+ };
beforeEach(() => {
cardData = [
@@ -67,7 +82,13 @@ describe('ISIS Data Publication - Card View', () => {
},
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.dataPublications.toggle.isisStudyDataPublication, {
+ instrumentId: 1,
+ }),
+ ],
+ });
mockStore = configureStore([thunk]);
state = JSON.parse(
@@ -101,122 +122,167 @@ describe('ISIS Data Publication - Card View', () => {
jest.clearAllMocks();
});
- it('renders correctly', async () => {
- renderComponent();
+ describe('Study Data Publication', () => {
+ it('renders correctly', async () => {
+ renderComponent();
+
+ const cards = await screen.findAllByTestId(
+ 'isis-dataPublications-card-view'
+ );
+ expect(cards).toHaveLength(1);
+
+ const card = cards[0];
+ // card id should be rendered as link to data publication
+ expect(
+ within(card).getByRole('link', { name: 'Test 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/14'
+ );
+ expect(within(card).getByLabelText('card-description')).toHaveTextContent(
+ 'Data Publication Description'
+ );
+ expect(within(card).getByRole('link', { name: 'doi' })).toHaveAttribute(
+ 'href',
+ 'https://doi.org/doi'
+ );
+ });
- const cards = await screen.findAllByTestId(
- 'isis-dataPublications-card-view'
- );
- expect(cards).toHaveLength(1);
+ it('uses default sort', () => {
+ renderComponent();
+ expect(history.length).toBe(1);
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"title":"desc"}')}`
+ );
+
+ // check that the data request is sent only once after mounting
+ const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
+ (call) => call[0] === '/datapublications'
+ );
+ expect(datafilesCalls).toHaveLength(1);
+ });
- const card = cards[0];
- // card id should be rendered as link to data publication
- expect(within(card).getByRole('link', { name: 'Test 1' })).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/1/dataPublication/14'
- );
- expect(within(card).getByLabelText('card-description')).toHaveTextContent(
- 'Data Publication Description'
- );
- expect(within(card).getByRole('link', { name: 'doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/doi'
- );
- expect(within(card).getByText('2001-01-01')).toBeInTheDocument();
- });
+ it('updates filter query params on text filter', async () => {
+ jest.useFakeTimers();
+ const user = userEvent.setup({
+ advanceTimers: jest.advanceTimersByTime,
+ });
- it('uses default sort', () => {
- renderComponent();
- expect(history.length).toBe(1);
- expect(history.location.search).toBe(
- `?sort=${encodeURIComponent('{"publicationDate":"desc"}')}`
- );
+ renderComponent();
- // check that the data request is sent only once after mounting
- const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
- (call) => call[0] === '/datapublications'
- );
- expect(datafilesCalls).toHaveLength(1);
- });
+ // click on button to show advanced filters
+ await user.click(
+ await screen.findByRole('button', { name: 'advanced_filters.show' })
+ );
- it('updates filter query params on text filter', async () => {
- jest.useFakeTimers();
- const user = userEvent.setup({
- advanceTimers: jest.advanceTimersByTime,
- });
+ const filter = await screen.findByRole('textbox', {
+ name: 'Filter by datapublications.title',
+ hidden: true,
+ });
- renderComponent();
+ await user.type(filter, 'Test');
- // click on button to show advanced filters
- await user.click(
- await screen.findByRole('button', { name: 'advanced_filters.show' })
- );
+ expect(history.location.search).toBe(
+ `?filters=${encodeURIComponent(
+ '{"title":{"value":"Test","type":"include"}}'
+ )}`
+ );
- const filter = await screen.findByRole('textbox', {
- name: 'Filter by datapublications.title',
- hidden: true,
- });
+ await user.clear(filter);
- await user.type(filter, 'Test');
+ expect(history.location.search).toBe('?');
- expect(history.location.search).toBe(
- `?filters=${encodeURIComponent(
- '{"title":{"value":"Test","type":"include"}}'
- )}`
- );
-
- await user.clear(filter);
+ jest.useRealTimers();
+ });
- expect(history.location.search).toBe('?');
+ it('updates sort query params on sort', async () => {
+ const user = userEvent.setup();
- jest.useRealTimers();
- });
+ renderComponent();
- it('updates filter query params on date filter', async () => {
- const user = userEvent.setup();
- applyDatePickerWorkaround();
+ await user.click(
+ await screen.findByRole('button', {
+ name: 'Sort by DATAPUBLICATIONS.PID',
+ })
+ );
- renderComponent();
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"pid":"asc"}')}`
+ );
+ });
+ });
- // open advanced filter
- await user.click(
- await screen.findByRole('button', { name: 'advanced_filters.show' })
- );
+ describe('Investigation Data Publication', () => {
+ it('renders correctly', async () => {
+ renderComponent('2');
+
+ const cards = await screen.findAllByTestId(
+ 'isis-dataPublications-card-view'
+ );
+ expect(cards).toHaveLength(1);
+
+ const card = cards[0];
+ // card id should be rendered as link to data publication
+ expect(
+ within(card).getByRole('link', { name: 'Test 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/14'
+ );
+ expect(within(card).getByLabelText('card-description')).toHaveTextContent(
+ 'Data Publication Description'
+ );
+ expect(within(card).getByRole('link', { name: 'doi' })).toHaveAttribute(
+ 'href',
+ 'https://doi.org/doi'
+ );
+ expect(within(card).getByText('2001-01-01')).toBeInTheDocument();
+ });
- const filterInput = screen.getByRole('textbox', {
- name: 'datapublications.publication_date filter to',
+ it('uses default sort', () => {
+ renderComponent('2');
+ expect(history.length).toBe(1);
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"publicationDate":"desc"}')}`
+ );
+
+ // check that the data request is sent only once after mounting
+ const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
+ (call) => call[0] === '/datapublications'
+ );
+ expect(datafilesCalls).toHaveLength(1);
});
- await user.type(filterInput, '2019-08-06');
- expect(history.location.search).toBe(
- `?filters=${encodeURIComponent(
- '{"publicationDate":{"endDate":"2019-08-06"}}'
- )}`
- );
+ it('updates filter query params on date filter', async () => {
+ const user = userEvent.setup();
+ applyDatePickerWorkaround();
- // await user.clear(filterInput);
- await user.click(filterInput);
- await user.keyboard('{Control}a{/Control}');
- await user.keyboard('{Delete}');
+ renderComponent('2');
- expect(history.location.search).toBe('?');
+ // open advanced filter
+ await user.click(
+ await screen.findByRole('button', { name: 'advanced_filters.show' })
+ );
- cleanupDatePickerWorkaround();
- });
+ const filterInput = screen.getByRole('textbox', {
+ name: 'datapublications.publication_date filter to',
+ });
- it('updates sort query params on sort', async () => {
- const user = userEvent.setup();
+ await user.type(filterInput, '2019-08-06');
+ expect(history.location.search).toBe(
+ `?filters=${encodeURIComponent(
+ '{"publicationDate":{"endDate":"2019-08-06"}}'
+ )}`
+ );
- renderComponent();
+ // await user.clear(filterInput);
+ await user.click(filterInput);
+ await user.keyboard('{Control}a{/Control}');
+ await user.keyboard('{Delete}');
- await user.click(
- await screen.findByRole('button', {
- name: 'Sort by DATAPUBLICATIONS.TITLE',
- })
- );
+ expect(history.location.search).toBe('?');
- expect(history.location.search).toBe(
- `?sort=${encodeURIComponent('{"title":"asc"}')}`
- );
+ cleanupDatePickerWorkaround();
+ });
});
});
diff --git a/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.tsx b/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.tsx
index 4d97aa2d5..3024fefbd 100644
--- a/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.tsx
+++ b/packages/datagateway-dataview/src/views/card/isis/isisDataPublicationsCardView.component.tsx
@@ -21,12 +21,13 @@ import { Link as MuiLink } from '@mui/material';
interface ISISDataPublicationsCVProps {
instrumentId: string;
+ studyDataPublicationId?: string;
}
const ISISDataPublicationsCardView = (
props: ISISDataPublicationsCVProps
): React.ReactElement => {
- const { instrumentId } = props;
+ const { instrumentId, studyDataPublicationId } = props;
const [t] = useTranslation();
const location = useLocation();
@@ -62,6 +63,36 @@ const ISISDataPublicationsCardView = (
},
}),
},
+ ...(studyDataPublicationId
+ ? [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: studyDataPublicationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'investigation' },
+ }),
+ },
+ ]
+ : [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'study' },
+ }),
+ },
+ {
+ filterType: 'distinct',
+ filterValue: JSON.stringify(['id', 'title', 'pid']),
+ },
+ ]),
]);
const { isLoading: dataLoading, data } = useDataPublicationsPaginated(
@@ -75,26 +106,54 @@ const ISISDataPublicationsCardView = (
},
}),
},
+ ...(studyDataPublicationId
+ ? [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: studyDataPublicationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'investigation' },
+ }),
+ },
+ ]
+ : [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'study' },
+ }),
+ },
+ {
+ filterType: 'distinct',
+ filterValue: JSON.stringify(['id', 'title', 'pid']),
+ },
+ ]),
],
isMounted
);
- const title = React.useMemo(() => {
- const pathRoot = 'browseDataPublications';
- const instrumentChild = 'dataPublication';
-
+ const title: CardViewDetails = React.useMemo(() => {
return {
label: t('datapublications.title'),
dataKey: 'title',
content: (dataPublication: DataPublication) =>
tableLink(
- `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${dataPublication.id}`,
+ `${location.pathname}/${dataPublication.id}`,
dataPublication.title,
view
),
filterComponent: textFilter,
+ defaultSort: studyDataPublicationId ? undefined : 'desc',
};
- }, [t, textFilter, instrumentId, view]);
+ }, [t, textFilter, studyDataPublicationId, location.pathname, view]);
const description: CardViewDetails = React.useMemo(
() => ({
@@ -125,17 +184,21 @@ const ISISDataPublicationsCardView = (
dataKey: 'pid',
filterComponent: textFilter,
},
- {
- icon: CalendarToday,
- label: t('datapublications.publication_date'),
- dataKey: 'publicationDate',
- content: (dataPublication: DataPublication) =>
- dataPublication.publicationDate?.slice(0, 10) ?? '',
- filterComponent: dateFilter,
- defaultSort: 'desc',
- },
+ ...(studyDataPublicationId
+ ? ([
+ {
+ icon: CalendarToday,
+ label: t('datapublications.publication_date'),
+ dataKey: 'publicationDate',
+ content: (dataPublication: DataPublication) =>
+ dataPublication.publicationDate?.slice(0, 10) ?? '',
+ filterComponent: dateFilter,
+ defaultSort: 'desc',
+ },
+ ] as CardViewDetails[])
+ : []),
],
- [dateFilter, t, textFilter]
+ [dateFilter, studyDataPublicationId, t, textFilter]
);
return (
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 755d7f7eb..cdcc2f787 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
@@ -6,7 +6,7 @@ import {
} from 'datagateway-common';
import * as React from 'react';
import { Provider } from 'react-redux';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import type { StateType } from '../../../state/app.types';
@@ -21,6 +21,7 @@ import {
import { render, type RenderResult, screen } from '@testing-library/react';
import type { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
+import { paths } from '../../../page/pageContainer.component';
jest.mock('datagateway-common', () => {
const originalModule = jest.requireActual('datagateway-common');
@@ -45,12 +46,7 @@ describe('ISIS Datasets - Card View', () => {
-
+
@@ -66,7 +62,15 @@ describe('ISIS Datasets - Card View', () => {
createTime: '2019-07-23',
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.toggle.isisDataset, {
+ instrumentId: '1',
+ investigationId: '1',
+ facilityCycleId: '1',
+ }),
+ ],
+ });
user = userEvent.setup();
mockStore = configureStore([thunk]);
@@ -103,20 +107,16 @@ describe('ISIS Datasets - Card View', () => {
});
it('correct link used for dataPublication hierarchy', async () => {
- render(
-
-
-
-
-
-
-
+ history.replace(
+ generatePath(paths.dataPublications.toggle.isisDataset, {
+ instrumentId: '1',
+ investigationId: '1',
+ dataPublicationId: '1',
+ })
);
+
+ renderComponent();
+
expect(await screen.findByRole('link', { name: 'Test 1' })).toHaveAttribute(
'href',
'/browseDataPublications/instrument/1/dataPublication/1/investigation/1/dataset/1'
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 fbec76bbc..8e0dad841 100644
--- a/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx
+++ b/packages/datagateway-dataview/src/views/card/isis/isisDatasetsCardView.component.tsx
@@ -33,17 +33,13 @@ const ActionButtonsContainer = styled('div')(({ theme }) => ({
}));
interface ISISDatasetCardViewProps {
- instrumentId: string;
- instrumentChildId: string;
investigationId: string;
- dataPublication: boolean;
}
const ISISDatasetsCardView = (
props: ISISDatasetCardViewProps
): React.ReactElement => {
- const { instrumentId, instrumentChildId, investigationId, dataPublication } =
- props;
+ const { investigationId } = props;
const [t] = useTranslation();
const location = useLocation();
@@ -89,10 +85,6 @@ const ISISDatasetsCardView = (
isMounted
);
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation/${investigationId}/dataset`;
-
const title: CardViewDetails = React.useMemo(
() => ({
// Provide label for filter component.
@@ -100,10 +92,10 @@ const ISISDatasetsCardView = (
// Provide both the dataKey (for tooltip) and content to render.
dataKey: 'name',
content: (dataset: Dataset) =>
- tableLink(`${urlPrefix}/${dataset.id}`, dataset.name, view),
+ tableLink(`${location.pathname}/${dataset.id}`, dataset.name, view),
filterComponent: textFilter,
}),
- [t, textFilter, urlPrefix, view]
+ [t, textFilter, location.pathname, view]
);
const description: CardViewDetails = React.useMemo(
@@ -172,13 +164,13 @@ const ISISDatasetsCardView = (
rowData={dataset}
viewDatafiles={(id: number) => {
const url = view
- ? `${urlPrefix}/${id}/datafile?view=${view}`
- : `${urlPrefix}/${id}/datafile`;
+ ? `${location.pathname}/${id}/datafile?view=${view}`
+ : `${location.pathname}/${id}/datafile`;
push(url);
}}
/>
),
- [push, urlPrefix, view]
+ [push, location.pathname, view]
);
return (
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 b35b0f14c..4bf3b500c 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
@@ -1,7 +1,7 @@
import { dGCommonInitialState, type Investigation } from 'datagateway-common';
import * as React from 'react';
import { Provider } from 'react-redux';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import type { StateType } from '../../../state/app.types';
@@ -23,6 +23,7 @@ import {
import type { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
import axios, { type AxiosResponse } from 'axios';
+import { paths } from '../../../page/pageContainer.component';
describe('ISIS Investigations - Card View', () => {
let mockStore;
@@ -32,7 +33,7 @@ describe('ISIS Investigations - Card View', () => {
let replaceSpy: jest.SpyInstance;
let user: UserEvent;
- const renderComponent = (dataPublication = false): RenderResult =>
+ const renderComponent = (): RenderResult =>
render(
@@ -43,11 +44,7 @@ describe('ISIS Investigations - Card View', () => {
})
}
>
-
+
@@ -67,12 +64,24 @@ describe('ISIS Investigations - Card View', () => {
dataCollectionInvestigations: [
{
id: 1,
- investigation: {
- id: 1,
- title: 'Test 1',
- name: 'Test 1',
- visitId: '1',
+ dataCollection: {
+ id: 14,
+ dataPublications: [
+ {
+ id: 15,
+ pid: 'Investigation.Data.Publication.Pid',
+ description: 'Investigation Data Publication description',
+ title: 'Investigation Data Publication',
+ type: {
+ id: 16,
+ name: 'investigation',
+ },
+ },
+ ],
},
+ },
+ {
+ id: 1,
dataCollection: {
id: 11,
dataPublications: [
@@ -80,9 +89,11 @@ describe('ISIS Investigations - Card View', () => {
id: 12,
pid: 'Data.Publication.Pid',
description: 'Data Publication description',
- modTime: '2019-06-10',
- createTime: '2019-06-11',
title: 'Data Publication',
+ type: {
+ id: 13,
+ name: 'study',
+ },
},
],
},
@@ -102,7 +113,14 @@ describe('ISIS Investigations - Card View', () => {
],
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.toggle.isisInvestigation, {
+ instrumentId: '1',
+ facilityCycleId: '1',
+ }),
+ ],
+ });
replaceSpy = jest.spyOn(history, 'replace');
user = userEvent.setup();
@@ -232,16 +250,6 @@ describe('ISIS Investigations - Card View', () => {
);
});
- it('correct link used for studyHierarchy', async () => {
- renderComponent(true);
- expect(
- await screen.findByRole('link', { name: 'Test title 1' })
- ).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/1/dataPublication/1/investigation/1'
- );
- });
-
it('updates filter query params on text filter', async () => {
renderComponent();
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 e54517fff..f73770e4a 100644
--- a/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx
+++ b/packages/datagateway-dataview/src/views/card/isis/isisInvestigationsCardView.component.tsx
@@ -43,14 +43,13 @@ const ActionButtonsContainer = styled('div')(({ theme }) => ({
interface ISISInvestigationsCardViewProps {
instrumentId: string;
- instrumentChildId: string;
- dataPublication: boolean;
+ facilityCycleId: string;
}
const ISISInvestigationsCardView = (
props: ISISInvestigationsCardViewProps
): React.ReactElement => {
- const { instrumentId, instrumentChildId, dataPublication } = props;
+ const { instrumentId, facilityCycleId } = props;
const [t] = useTranslation();
const location = useLocation();
@@ -81,10 +80,8 @@ const ISISInvestigationsCardView = (
{
filterType: 'where',
filterValue: JSON.stringify({
- [dataPublication
- ? 'dataCollectionInvestigations.dataCollection.dataPublications.id'
- : 'investigationFacilityCycles.facilityCycle.id']: {
- eq: parseInt(instrumentChildId),
+ 'investigationFacilityCycles.facilityCycle.id': {
+ eq: parseInt(facilityCycleId),
},
}),
},
@@ -111,7 +108,7 @@ const ISISInvestigationsCardView = (
},
{
dataCollectionInvestigations: {
- dataCollection: 'dataPublications',
+ dataCollection: { dataPublications: 'type' },
},
},
{
@@ -124,24 +121,20 @@ const ISISInvestigationsCardView = (
isMounted
);
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation`;
-
const title: CardViewDetails = React.useMemo(
() => ({
label: t('investigations.title'),
dataKey: 'title',
content: (investigation: Investigation) =>
tableLink(
- `${urlPrefix}/${investigation.id}`,
+ `${location.pathname}/${investigation.id}`,
investigation.title,
view,
'isis-investigations-card-title'
),
filterComponent: textFilter,
}),
- [t, textFilter, urlPrefix, view]
+ [location.pathname, t, textFilter, view]
);
const description: CardViewDetails = React.useMemo(
@@ -162,18 +155,17 @@ const ISISInvestigationsCardView = (
filterComponent: textFilter,
},
{
- // TODO: this was previously the Study DOI - currently there are no datapublication
- // representations of Studies, only of Investigations themselves
- // should this be showing the study DOI or the investigation DOI anyway?
content: function doiFormat(entity: Investigation) {
- if (
- entity?.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications?.[0]
- ) {
+ const studyDataPublication =
+ entity.dataCollectionInvestigations?.filter(
+ (dci) =>
+ dci.dataCollection?.dataPublications?.[0]?.type?.name ===
+ 'study'
+ )?.[0]?.dataCollection?.dataPublications?.[0];
+ if (studyDataPublication) {
return externalSiteLink(
- `https://doi.org/${entity.dataCollectionInvestigations?.[0]?.dataCollection?.dataPublications?.[0].pid}`,
- entity.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications?.[0].pid,
+ `https://doi.org/${studyDataPublication.pid}`,
+ studyDataPublication.pid,
'isis-investigations-card-doi-link'
);
} else {
@@ -258,13 +250,13 @@ const ISISInvestigationsCardView = (
rowData={investigation}
viewDatasets={(id: number) => {
const url = view
- ? `${urlPrefix}/${id}/dataset?view=${view}`
- : `${urlPrefix}/${id}/dataset`;
+ ? `${location.pathname}/${id}/dataset?view=${view}`
+ : `${location.pathname}/${id}/dataset`;
push(url);
}}
/>
),
- [push, urlPrefix, view]
+ [location.pathname, push, view]
);
return (
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.test.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.test.tsx
index 665e4daaa..940869691 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.test.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.test.tsx
@@ -2,16 +2,22 @@ import * as React from 'react';
import { initialState as dgDataViewInitialState } from '../../../state/reducers/dgdataview.reducer';
import configureStore from 'redux-mock-store';
import { StateType } from '../../../state/app.types';
-import { dGCommonInitialState, useDataPublication } from 'datagateway-common';
+import {
+ DataPublication,
+ dGCommonInitialState,
+ useDataPublication,
+ useDataPublications,
+} from 'datagateway-common';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createMemoryHistory, History } from 'history';
import { QueryClient, QueryClientProvider } from 'react-query';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import { render, type RenderResult, screen } from '@testing-library/react';
import { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
import ISISDataPublicationLanding from './isisDataPublicationLanding.component';
+import { paths } from '../../../page/pageContainer.component';
jest.mock('datagateway-common', () => {
const originalModule = jest.requireActual('datagateway-common');
@@ -20,6 +26,7 @@ jest.mock('datagateway-common', () => {
__esModule: true,
...originalModule,
useDataPublication: jest.fn(),
+ useDataPublications: jest.fn(),
};
});
@@ -34,10 +41,7 @@ describe('ISIS Data Publication Landing page', () => {
-
+
@@ -60,7 +64,7 @@ describe('ISIS Data Publication Landing page', () => {
fullName: 'Jesse Smith',
},
{
- id: 4,
+ id: 6,
contributorType: 'experimenter',
fullName: '',
},
@@ -70,10 +74,17 @@ describe('ISIS Data Publication Landing page', () => {
{
id: 1,
instrument: {
- id: 3,
+ id: 4,
name: 'LARMOR',
},
},
+ {
+ id: 2,
+ instrument: {
+ id: 5,
+ name: 'ALF',
+ },
+ },
];
const investigation = {
@@ -82,30 +93,36 @@ describe('ISIS Data Publication Landing page', () => {
name: 'Name 1',
summary: 'foo bar',
visitId: '1',
- doi: 'doi 1',
- size: 1,
- investigationInstruments: investigationInstrument,
+ doi: 'investigation doi 1.1',
+ fileSize: 1,
+ investigationInstruments: [investigationInstrument[0]],
startDate: '2019-06-10',
endDate: '2019-06-11',
+ releaseDate: '2019-06-12',
};
- const initialData = [
- {
- id: 7,
- pid: 'doi 1',
- description: 'foo bar',
- users: users,
- content: {
- dataCollectionInvestigations: [
- {
- investigation: investigation,
- },
- ],
- },
- startDate: '2019-06-10',
- endDate: '2019-06-11',
- },
- ];
+ const investigation2 = {
+ id: 2,
+ title: 'Title 2',
+ name: 'Name 2',
+ summary: 'foo bar',
+ visitId: '2',
+ doi: 'investigation doi 1.2',
+ fileSize: 2,
+ investigationInstruments: [investigationInstrument[1]],
+ startDate: '2019-06-10',
+ endDate: '2019-06-11',
+ };
+
+ // dummy data to stop TS from complaining, gets overwritten in beforeEach
+ let initialStudyDataPublicationData: DataPublication = {
+ id: 1,
+ pid: '1',
+ title: '1',
+ modTime: '1',
+ createTime: '1',
+ };
+ let initialInvestigationDataPublicationsData: DataPublication[] = [];
beforeEach(() => {
state = JSON.parse(
@@ -115,11 +132,71 @@ describe('ISIS Data Publication Landing page', () => {
})
);
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(
+ paths.dataPublications.landing.isisDataPublicationLanding,
+ {
+ instrumentId: '4',
+ dataPublicationId: '5',
+ }
+ ),
+ ],
+ });
user = userEvent.setup();
+ initialStudyDataPublicationData = {
+ id: 5,
+ pid: 'doi 1',
+ users: users,
+ publicationDate: '2019-06-10',
+ title: 'Study title',
+ modTime: '2019-06-10',
+ createTime: '2019-06-11',
+ };
+ initialInvestigationDataPublicationsData = [
+ {
+ id: 8,
+ pid: 'investigation doi 1.1',
+ title: 'Title 1',
+ description: 'foo bar',
+ content: {
+ id: 21,
+ dataCollectionInvestigations: [
+ {
+ id: 19,
+ investigation: investigation,
+ },
+ ],
+ },
+ modTime: '2019-06-10',
+ createTime: '2019-06-11',
+ publicationDate: '2019-06-11',
+ },
+ {
+ id: 9,
+ pid: 'investigation doi 1.2',
+ title: 'Title 2',
+ content: {
+ id: 22,
+ dataCollectionInvestigations: [
+ {
+ id: 20,
+ investigation: investigation2,
+ },
+ ],
+ },
+ modTime: '2019-06-10',
+ createTime: '2019-06-11',
+ },
+ ];
+
(useDataPublication as jest.Mock).mockReturnValue({
- data: initialData,
+ data: initialStudyDataPublicationData,
+ });
+
+ (useDataPublications as jest.Mock).mockReturnValue({
+ data: initialInvestigationDataPublicationsData,
});
});
@@ -143,7 +220,7 @@ describe('ISIS Data Publication Landing page', () => {
});
it('in cards view', async () => {
- history.replace('/?view=card');
+ history.replace({ search: '?view=card' });
renderComponent();
await user.click(
@@ -159,9 +236,22 @@ describe('ISIS Data Publication Landing page', () => {
});
});
- it('users displayed correctly', async () => {
+ it('renders correctly', async () => {
renderComponent();
+ // displays doi + link correctly
+ expect(await screen.findByRole('link', { name: 'doi 1' })).toHaveAttribute(
+ 'href',
+ 'https://doi.org/doi 1'
+ );
+ expect(
+ screen.getByText('datapublications.publication_date:')
+ ).toBeInTheDocument();
+ expect(screen.getByText('2019-06-10')).toBeInTheDocument();
+ expect(screen.getByText('Title 1')).toBeInTheDocument();
+ expect(screen.getByText('foo bar')).toBeInTheDocument();
+
+ // renders users correctly
expect(
await screen.findByTestId('landing-dataPublication-user-0')
).toHaveTextContent('Principal Investigator: John Smith');
@@ -171,14 +261,114 @@ describe('ISIS Data Publication Landing page', () => {
expect(
await screen.findByTestId('landing-dataPublication-user-2')
).toHaveTextContent('Experimenter: Jesse Smith');
+
+ // renders parts (investigations) correctly
+ expect(
+ screen.getByRole('link', { name: 'Part DOI: investigation doi 1.1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/8'
+ );
+ expect(
+ screen.getByText(
+ (_, element) =>
+ element.textContent === 'investigations.instrument:LARMOR'
+ )
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ (_, element) =>
+ element.textContent === 'investigations.release_date:2019-06-11'
+ )
+ ).toBeInTheDocument();
+
+ expect(
+ screen.getByRole('link', { name: 'Part DOI: investigation doi 1.2' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/9'
+ );
+ expect(
+ screen.getByText(
+ (_, element) => element.textContent === 'investigations.instrument:ALF'
+ )
+ ).toBeInTheDocument();
+
+ // actions for investigations should be visible
+ expect(
+ document.getElementById('add-to-cart-btn-investigation-1')
+ ).toBeInTheDocument();
+ expect(document.getElementById('download-btn-1')).toBeInTheDocument();
+ expect(
+ document.getElementById('add-to-cart-btn-investigation-2')
+ ).toBeInTheDocument();
+ expect(document.getElementById('download-btn-2')).toBeInTheDocument();
});
- it('displays DOI and renders the expected link', async () => {
+ it('renders correctly when info is missing', async () => {
+ // missing description
+ initialInvestigationDataPublicationsData[0].description = undefined;
+ initialStudyDataPublicationData.users = [];
+ // missing investigations - i.e. investigations not public yet
+ if (
+ initialInvestigationDataPublicationsData[0].content
+ ?.dataCollectionInvestigations?.[0]
+ )
+ initialInvestigationDataPublicationsData[0].content.dataCollectionInvestigations[0].investigation =
+ undefined;
+ if (
+ initialInvestigationDataPublicationsData[1].content
+ ?.dataCollectionInvestigations?.[0]
+ )
+ initialInvestigationDataPublicationsData[1].content.dataCollectionInvestigations[0].investigation =
+ undefined;
+
renderComponent();
- expect(await screen.findByRole('link', { name: 'doi 1' })).toHaveAttribute(
+ expect(screen.getByText('Description not provided')).toBeInTheDocument();
+
+ expect(screen.queryByText('investigations.details.users.label')).toBeNull();
+
+ // renders parts (investigations) correctly
+ expect(
+ screen.getByRole('link', { name: 'Part DOI: investigation doi 1.1' })
+ ).toHaveAttribute(
'href',
- 'https://doi.org/doi 1'
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/8'
);
+
+ expect(
+ screen.getByRole('link', { name: 'Part DOI: investigation doi 1.2' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/9'
+ );
+
+ // actions for investigations should not be visible
+ expect(
+ document.getElementById('add-to-cart-btn-investigation-1')
+ ).not.toBeInTheDocument();
+ expect(document.getElementById('download-btn-1')).not.toBeInTheDocument();
+ expect(
+ document.getElementById('add-to-cart-btn-investigation-2')
+ ).not.toBeInTheDocument();
+ expect(document.getElementById('download-btn-2')).not.toBeInTheDocument();
+ });
+
+ it('renders structured data correctly', async () => {
+ renderComponent();
+
+ expect(
+ await screen.findByTestId('landing-dataPublication-user-0')
+ ).toBeInTheDocument();
+
+ expect(document.getElementById('dataPublication-5')).toMatchInlineSnapshot(`
+
+ `);
});
});
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.tsx
index d431e78a0..158ad8e64 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisDataPublicationLanding.component.tsx
@@ -12,7 +12,6 @@ import {
import {
Assessment,
CalendarToday,
- Fingerprint,
Public,
Storage,
} from '@mui/icons-material';
@@ -21,11 +20,12 @@ import {
useDataPublication,
ArrowTooltip,
getTooltipText,
- Investigation,
tableLink,
AddToCartButton,
ViewsType,
parseSearchToQuery,
+ useDataPublications,
+ DownloadButton,
} from 'datagateway-common';
import React from 'react';
import { useTranslation } from 'react-i18next';
@@ -75,11 +75,10 @@ export interface FormattedUser {
interface LandingPageProps {
dataPublicationId: string;
- instrumentId: string;
}
interface LinkedInvestigationProps {
- investigation: Investigation;
+ investigation: DataPublication;
urlPrefix: string;
view: ViewsType;
}
@@ -93,18 +92,15 @@ const LinkedInvestigation = (
const shortInvestigationInfo = [
{
- content: (entity: Investigation) => entity.name,
- label: t('investigations.name'),
- icon: ,
- },
- {
- content: (entity: Investigation) =>
- entity.investigationInstruments?.[0]?.instrument?.name,
+ content: (entity: DataPublication) =>
+ entity.content?.dataCollectionInvestigations?.[0]?.investigation
+ ?.investigationInstruments?.[0]?.instrument?.name,
label: t('investigations.instrument'),
icon: ,
},
{
- content: (entity: Investigation) => entity.releaseDate?.slice(0, 10),
+ content: (entity: DataPublication) =>
+ entity.publicationDate?.slice(0, 10),
label: t('investigations.release_date'),
icon: ,
},
@@ -119,7 +115,7 @@ const LinkedInvestigation = (
>
{tableLink(
`${props.urlPrefix}/investigation/${investigation.id}`,
- `${t('investigations.visit_id')}: ${investigation.visitId}`,
+ `${'Part DOI'}: ${investigation.pid}`,
props.view
)}
@@ -134,13 +130,37 @@ const LinkedInvestigation = (
))}
-
-
-
+ {investigation.content?.dataCollectionInvestigations?.[0]?.investigation
+ ?.id && (
+
+
+
+
+ )}
);
};
@@ -155,22 +175,53 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
);
const [value, setValue] = React.useState<'details'>('details');
- const { instrumentId, dataPublicationId } = props;
+ const { dataPublicationId } = props;
- const pathRoot = 'browseDataPublications';
- const instrumentChild = 'dataPublication';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${dataPublicationId}`;
+ const { data: studyDataPublication } = useDataPublication(
+ parseInt(dataPublicationId)
+ );
- const { data } = useDataPublication(parseInt(dataPublicationId));
+ const { data: investigationDataPublications } = useDataPublications([
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: dataPublicationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': {
+ eq: 'investigation',
+ },
+ }),
+ },
+ {
+ filterType: 'include',
+ filterValue: JSON.stringify({
+ content: {
+ dataCollectionInvestigations: {
+ investigation: {
+ investigationInstruments: 'instrument',
+ },
+ },
+ },
+ }),
+ },
+ ]);
- const pid = data?.[0]?.pid;
- const title = data?.[0]?.title;
+ const pid = studyDataPublication?.pid;
+ const title = investigationDataPublications?.[0]?.title;
const description = React.useMemo(
() =>
- data?.[0]?.description && data?.[0]?.description !== 'null'
- ? data[0]?.description
+ investigationDataPublications?.[0]?.description &&
+ investigationDataPublications?.[0]?.description !== 'null'
+ ? investigationDataPublications?.[0]?.description
: 'Description not provided',
- [data]
+ [investigationDataPublications]
);
const formattedUsers = React.useMemo(() => {
@@ -178,40 +229,38 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
const contacts: FormattedUser[] = [];
const experimenters: FormattedUser[] = [];
- if (data?.[0]?.users) {
- const dataPublicationUsers = data[0]?.users;
- dataPublicationUsers.forEach((user) => {
- // Only keep users where we have their fullName
- const fullname = user.fullName;
- if (fullname) {
- switch (user.contributorType) {
- case 'principal_experimenter':
- principals.push({
- fullName: fullname,
- contributorType: 'Principal Investigator',
- });
- break;
- case 'local_contact':
- contacts.push({
- fullName: fullname,
- contributorType: 'Local Contact',
- });
- break;
- default:
- experimenters.push({
- fullName: fullname,
- contributorType: 'Experimenter',
- });
- }
+ studyDataPublication?.users?.forEach((user) => {
+ // Only keep users where we have their fullName
+ const fullname = user.fullName;
+ if (fullname) {
+ switch (user.contributorType) {
+ case 'principal_experimenter':
+ principals.push({
+ fullName: fullname,
+ contributorType: 'Principal Investigator',
+ });
+ break;
+ case 'local_contact':
+ contacts.push({
+ fullName: fullname,
+ contributorType: 'Local Contact',
+ });
+ break;
+ default:
+ experimenters.push({
+ fullName: fullname,
+ contributorType: 'Experimenter',
+ });
}
- });
- }
+ }
+ });
+
// Ensure PIs are listed first, and sort within roles for consistency
principals.sort((a, b) => a.fullName.localeCompare(b.fullName));
contacts.sort((a, b) => a.fullName.localeCompare(b.fullName));
experimenters.sort((a, b) => a.fullName.localeCompare(b.fullName));
return principals.concat(contacts, experimenters);
- }, [data]);
+ }, [studyDataPublication]);
React.useEffect(() => {
const scriptId = `dataPublication-${dataPublicationId}`;
@@ -246,18 +295,14 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
url: t('doi_constants.publisher.url'),
},
},
+ creator: formattedUsers.map((user) => {
+ return { '@type': 'Person', name: user.fullName };
+ }),
includedInDataCatalog: {
'@type': 'DataCatalog',
url: t('doi_constants.distribution.content_url'),
},
- distribution: [
- {
- '@type': 'DataDownload',
- encodingFormat: t('doi_constants.distribution.format'),
- // TODO format contentUrl with and actual download link if possible
- contentUrl: t('doi_constants.distribution.content_url'),
- },
- ],
+ license: t('doi_constants.distribution.license'),
});
return () => {
@@ -266,7 +311,7 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
currentScript.remove();
}
};
- }, [t, title, pid, dataPublicationId, description]);
+ }, [t, title, pid, dataPublicationId, description, formattedUsers]);
const shortInfo = [
{
@@ -333,8 +378,8 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
onClick={() =>
push(
view
- ? `${urlPrefix}/investigation?view=${view}`
- : `${urlPrefix}/investigation`
+ ? `${location.pathname}/investigation?view=${view}`
+ : `${location.pathname}/investigation`
)
}
/>
@@ -384,7 +429,7 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
doi={pid}
formattedUsers={formattedUsers}
title={title}
- startDate={data?.[0]?.createTime}
+ startDate={studyDataPublication?.publicationDate}
/>
@@ -393,8 +438,8 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
{shortInfo.map(
(field, i) =>
- data?.[0] &&
- field.content(data[0] as DataPublication) && (
+ studyDataPublication &&
+ field.content(studyDataPublication as DataPublication) && (
{field.icon}
@@ -402,31 +447,25 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
- {field.content(data[0] as DataPublication)}
+ {field.content(studyDataPublication as DataPublication)}
)
)}
{/* Parts */}
- {data?.map((dataPublication, i) => (
+ {investigationDataPublications?.map((dataPublication, i) => (
- {dataPublication?.content?.dataCollectionInvestigations?.[0]
- ?.investigation && (
-
- )}
+
))}
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.test.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.test.tsx
index f8b950451..a5dccc6ba 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.test.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.test.tsx
@@ -12,10 +12,11 @@ import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createMemoryHistory, History } from 'history';
import { QueryClient, QueryClientProvider } from 'react-query';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import { render, type RenderResult, screen } from '@testing-library/react';
import { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
+import { paths } from '../../../page/pageContainer.component';
jest.mock('datagateway-common', () => {
const originalModule = jest.requireActual('datagateway-common');
@@ -34,18 +35,12 @@ describe('ISIS Dataset Landing page', () => {
let history: History;
let user: UserEvent;
- const renderComponent = (dataPublication = false): RenderResult =>
+ const renderComponent = (): RenderResult =>
render(
-
+
@@ -75,7 +70,16 @@ describe('ISIS Dataset Landing page', () => {
dgcommon: dGCommonInitialState,
})
);
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.landing.isisDatasetLanding, {
+ instrumentId: '4',
+ investigationId: '1',
+ facilityCycleId: '5',
+ datasetId: '87',
+ }),
+ ],
+ });
user = userEvent.setup();
(useDatasetDetails as jest.Mock).mockReturnValue({
@@ -101,7 +105,7 @@ describe('ISIS Dataset Landing page', () => {
});
it('for facility cycle hierarchy and cards view', async () => {
- history.replace('/?view=card');
+ history.replace({ search: '?view=card' });
renderComponent();
await user.click(
@@ -115,7 +119,15 @@ describe('ISIS Dataset Landing page', () => {
});
it('for data publication hierarchy and normal view', async () => {
- renderComponent(true);
+ history.replace(
+ generatePath(paths.dataPublications.landing.isisDatasetLanding, {
+ instrumentId: '4',
+ investigationId: '1',
+ dataPublicationId: '5',
+ datasetId: '87',
+ })
+ );
+ renderComponent();
await user.click(
await screen.findByRole('tab', { name: 'datasets.details.datafiles' })
@@ -127,8 +139,19 @@ describe('ISIS Dataset Landing page', () => {
});
it('for data publication hierarchy and cards view', async () => {
- history.replace('/?view=card');
- renderComponent(true);
+ history.replace({
+ pathname: generatePath(
+ paths.dataPublications.landing.isisDatasetLanding,
+ {
+ instrumentId: '4',
+ investigationId: '1',
+ dataPublicationId: '5',
+ datasetId: '87',
+ }
+ ),
+ search: '?view=card',
+ });
+ renderComponent();
await user.click(
await screen.findByRole('tab', { name: 'datasets.details.datafiles' })
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.tsx
index 6e5b93425..4bf307fdc 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisDatasetLanding.component.tsx
@@ -60,11 +60,7 @@ const ActionButtonsContainer = styled('div')(({ theme }) => ({
}));
interface LandingPageProps {
- instrumentId: string;
- instrumentChildId: string;
- investigationId: string;
datasetId: string;
- dataPublication: boolean;
}
const LandingPage = (props: LandingPageProps): React.ReactElement => {
@@ -76,17 +72,7 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
[location.search]
);
const [value, setValue] = React.useState<'details'>('details');
- const {
- instrumentId,
- instrumentChildId,
- investigationId,
- datasetId,
- dataPublication,
- } = props;
-
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation/${investigationId}/dataset/${datasetId}`;
+ const { datasetId } = props;
const { data } = useDatasetDetails(parseInt(datasetId));
@@ -158,8 +144,8 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
onClick={() =>
push(
view
- ? `${urlPrefix}/datafile?view=${view}`
- : `${urlPrefix}/datafile`
+ ? `${location.pathname}/datafile?view=${view}`
+ : `${location.pathname}/datafile`
)
}
/>
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.test.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.test.tsx
index 261fbaef3..333126516 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.test.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.test.tsx
@@ -3,19 +3,26 @@ import ISISInvestigationLanding from './isisInvestigationLanding.component';
import { initialState as dgDataViewInitialState } from '../../../state/reducers/dgdataview.reducer';
import configureStore from 'redux-mock-store';
import { StateType } from '../../../state/app.types';
-import { dGCommonInitialState, useInvestigation } from 'datagateway-common';
+import {
+ DataPublication,
+ dGCommonInitialState,
+ Investigation,
+ useDataPublication,
+ useDataPublications,
+ useInvestigation,
+} from 'datagateway-common';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createMemoryHistory, History } from 'history';
import { QueryClient, QueryClientProvider } from 'react-query';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import {
render,
- type RenderResult,
screen,
within,
+ type RenderResult,
} from '@testing-library/react';
-import { UserEvent } from '@testing-library/user-event/setup/setup';
+import { paths } from '../../../page/pageContainer.component';
import userEvent from '@testing-library/user-event';
jest.mock('datagateway-common', () => {
@@ -25,7 +32,8 @@ jest.mock('datagateway-common', () => {
__esModule: true,
...originalModule,
useInvestigation: jest.fn(),
- useInvestigationSizes: jest.fn(),
+ useDataPublication: jest.fn(),
+ useDataPublications: jest.fn(),
};
});
@@ -33,7 +41,7 @@ describe('ISIS Investigation Landing page', () => {
const mockStore = configureStore([thunk]);
let state: StateType;
let history: History;
- let user: UserEvent;
+ let user: ReturnType;
const renderComponent = (dataPublication = false): RenderResult =>
render(
@@ -41,8 +49,6 @@ describe('ISIS Investigation Landing page', () => {
@@ -51,73 +57,9 @@ describe('ISIS Investigation Landing page', () => {
);
- const initialData = [
- {
- id: 1,
- title: 'Test title 1',
- name: 'Test 1',
- fileSize: 1,
- fileCount: 1,
- summary: 'foo bar',
- visitId: 'visit id 1',
- doi: 'doi 1',
- size: 1,
- facility: {
- name: 'LILS',
- },
- investigationInstruments: [
- {
- id: 1,
- instrument: {
- id: 3,
- name: 'LARMOR',
- },
- investigation: {
- id: 1,
- },
- },
- ],
- dataCollectionInvestigations: [
- {
- id: 1,
- investigation: {
- id: 1,
- title: 'Test title 1',
- name: 'Test 1',
- visitId: 'visit id 1',
- },
- dataCollection: {
- id: 11,
- dataPublications: [
- {
- id: 7,
- pid: 'Data Publication Pid',
- description: 'Data Publication description',
- modTime: '2019-06-10',
- createTime: '2019-06-11',
- title: 'Data Publication',
- },
- ],
- },
- },
- ],
- startDate: '2019-06-10',
- endDate: '2019-06-11',
- datasets: [
- {
- id: 1,
- name: 'dataset 1',
- doi: 'dataset doi',
- },
- ],
- },
- ];
const investigationUser = [
{
id: 1,
- investigation: {
- id: 1,
- },
role: 'principal_experimenter',
user: {
id: 1,
@@ -127,9 +69,6 @@ describe('ISIS Investigation Landing page', () => {
},
{
id: 2,
- investigation: {
- id: 1,
- },
role: 'local_contact',
user: {
id: 2,
@@ -139,9 +78,6 @@ describe('ISIS Investigation Landing page', () => {
},
{
id: 3,
- investigation: {
- id: 1,
- },
role: 'experimenter',
user: {
id: 3,
@@ -151,9 +87,6 @@ describe('ISIS Investigation Landing page', () => {
},
{
id: 4,
- investigation: {
- id: 1,
- },
role: 'experimenter',
user: {
id: 4,
@@ -177,8 +110,41 @@ describe('ISIS Investigation Landing page', () => {
fullReference: 'Journal, Author, Date, DOI',
},
];
- const noSamples: never[] = [];
- const noPublication: never[] = [];
+
+ let initialInvestigationData: Investigation[] = [];
+
+ const users = [
+ {
+ id: 1,
+ contributorType: 'principal_experimenter',
+ fullName: 'John Smith',
+ },
+ {
+ id: 2,
+ contributorType: 'local_contact',
+ fullName: 'Jane Smith',
+ },
+ {
+ id: 3,
+ contributorType: 'experimenter',
+ fullName: 'Jesse Smith',
+ },
+ {
+ id: 6,
+ contributorType: 'experimenter',
+ fullName: '',
+ },
+ ];
+
+ // dummy data to stop TS from complaining, gets overwritten in beforeEach
+ let initialDataPublicationData: DataPublication = {
+ id: 1,
+ pid: '1',
+ title: '1',
+ modTime: '1',
+ createTime: '1',
+ };
+ let initialStudyDataPublicationData: DataPublication[] = [];
beforeEach(() => {
state = JSON.parse(
@@ -187,11 +153,121 @@ describe('ISIS Investigation Landing page', () => {
dgcommon: dGCommonInitialState,
})
);
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.landing.isisInvestigationLanding, {
+ instrumentId: '4',
+ facilityCycleId: '5',
+ investigationId: '1',
+ }),
+ ],
+ });
user = userEvent.setup();
+ initialInvestigationData = [
+ {
+ id: 1,
+ title: 'Test title 1',
+ name: 'Test 1',
+ fileSize: 1,
+ fileCount: 1,
+ summary: 'foo bar',
+ visitId: 'visit id 1',
+ doi: 'doi 1',
+ size: 1,
+ facility: {
+ id: 17,
+ name: 'LILS',
+ },
+ investigationInstruments: [
+ {
+ id: 1,
+ instrument: {
+ id: 3,
+ name: 'LARMOR',
+ },
+ },
+ ],
+ dataCollectionInvestigations: [
+ {
+ id: 1,
+ dataCollection: {
+ id: 11,
+ dataPublications: [
+ {
+ id: 7,
+ pid: 'Data Publication Pid',
+ description: 'Data Publication description',
+ modTime: '2019-06-10',
+ createTime: '2019-06-11',
+ title: 'Data Publication',
+ type: { id: 12, name: 'study' },
+ },
+ ],
+ },
+ },
+ ],
+ startDate: '2019-06-10',
+ endDate: '2019-06-11',
+ datasets: [
+ {
+ id: 1,
+ name: 'dataset 1',
+ doi: 'dataset doi',
+ modTime: '2019-06-10',
+ createTime: '2019-06-10',
+ },
+ ],
+ investigationUsers: investigationUser,
+ publications: publication,
+ samples: sample,
+ },
+ ];
+
+ initialStudyDataPublicationData = [
+ {
+ id: 5,
+ pid: '10.1234/ISIS.E.RB123456',
+ title: 'Title 1',
+ publicationDate: '2019-06-10',
+ modTime: '2019-06-10',
+ createTime: '2019-06-10',
+ },
+ ];
+ initialDataPublicationData = {
+ id: 8,
+ pid: '10.1234/ISIS.E.RB123456-1',
+ title: 'Title 1.1',
+ description: 'foo bar',
+ publicationDate: '2019-06-10',
+ content: {
+ id: 10,
+ dataCollectionInvestigations: [
+ {
+ id: 9,
+ investigation: initialInvestigationData[0],
+ },
+ ],
+ },
+ users,
+ facility: {
+ id: 17,
+ name: 'LILS',
+ },
+ modTime: '2019-06-10',
+ createTime: '2019-06-10',
+ };
+
(useInvestigation as jest.Mock).mockReturnValue({
- data: initialData,
+ data: initialInvestigationData,
+ });
+
+ (useDataPublication as jest.Mock).mockReturnValue({
+ data: initialDataPublicationData,
+ });
+
+ (useDataPublications as jest.Mock).mockReturnValue({
+ data: initialStudyDataPublicationData,
});
});
@@ -199,7 +275,7 @@ describe('ISIS Investigation Landing page', () => {
jest.clearAllMocks();
});
- it('renders landing for investigation correctly', () => {
+ it('renders correctly for facility cycle hierarchy', () => {
renderComponent();
// branding should be visible
@@ -221,27 +297,27 @@ describe('ISIS Investigation Landing page', () => {
screen.getByText('doi_constants.publisher.name')
).toBeInTheDocument();
- // investigation samples should be hidden (initial data does not have samples)
+ // investigation samples should displayed correctly
expect(
- screen.queryByText('investigations.details.samples.label')
- ).toBeNull();
- expect(
- screen.queryByText('investigations.details.samples.no_samples')
- ).toBeNull();
+ screen.getByText('investigations.details.samples.label')
+ ).toBeInTheDocument();
expect(
screen.queryAllByLabelText(/landing-investigation-sample-\d+$/)
- ).toHaveLength(0);
-
- // publication section should be hidden (initial data does not have publications)
+ ).toHaveLength(1);
expect(
- screen.queryByText('investigations.details.publications.label')
- ).toBeNull();
+ screen.getByLabelText('landing-investigation-sample-0')
+ ).toHaveTextContent('Sample');
+
+ // publications should be displayed correctly
expect(
- screen.queryByText('investigations.details.publications.no_publications')
- ).toBeNull();
+ screen.getByText('investigations.details.publications.label')
+ ).toBeInTheDocument();
expect(
screen.queryAllByLabelText(/landing-investigation-reference-\d+$/)
- ).toHaveLength(0);
+ ).toHaveLength(1);
+ expect(
+ screen.getByLabelText('landing-investigation-reference-0')
+ ).toHaveTextContent('Journal, Author, Date, DOI');
// short format information should be visible
expect(screen.getByText('investigations.visit_id:')).toBeInTheDocument();
@@ -291,126 +367,237 @@ describe('ISIS Investigation Landing page', () => {
name: 'buttons.add_to_cart',
})
).toBeInTheDocument();
+ expect(
+ within(actionButtonContainer).getByRole('button', {
+ name: 'buttons.download',
+ })
+ ).toBeInTheDocument();
+
+ // datasets should be visible
+
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browse/instrument/4/facilityCycle/5/investigation/1/dataset/1'
+ );
+ expect(screen.getByText('datasets.doi:')).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'dataset doi' })).toHaveAttribute(
+ 'href',
+ 'https://doi.org/dataset doi'
+ );
+
+ // actions for datasets should be visible
+ const actionContainer = screen.getByTestId(
+ 'investigation-landing-dataset-0-action-container'
+ );
+ expect(actionContainer).toBeInTheDocument();
+ expect(
+ within(actionContainer).getByRole('button', {
+ name: 'buttons.add_to_cart',
+ })
+ ).toBeInTheDocument();
});
- describe('renders datasets for the investigation correctly', () => {
- it('for facility cycle hierarchy and normal view', () => {
- renderComponent();
+ it('renders correctly for facility cycle hierarchy when no description, users, samples or publications', async () => {
+ initialInvestigationData[0].summary = undefined;
+ initialInvestigationData[0].publications = [];
+ initialInvestigationData[0].samples = [];
+ initialInvestigationData[0].investigationUsers = undefined;
- expect(
- screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
- ).toHaveAttribute(
- 'href',
- '/browse/instrument/4/facilityCycle/5/investigation/1/dataset/1'
- );
- expect(screen.getByText('datasets.doi:')).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'dataset doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/dataset doi'
- );
+ renderComponent();
- // actions for datasets should be visible
- const actionContainer = screen.getByTestId(
- 'investigation-landing-dataset-0-action-container'
- );
- expect(actionContainer).toBeInTheDocument();
- expect(
- within(actionContainer).getByRole('button', {
- name: 'buttons.add_to_cart',
- })
- ).toBeInTheDocument();
- });
+ expect(screen.getByText('Test title 1')).toBeInTheDocument();
+ expect(screen.getByText('Description not provided')).toBeInTheDocument();
- it('for facility cycle hierarchy and card view', () => {
- history.replace('/?view=card');
+ // no investigation samples, so show no samples message
+ expect(
+ screen.getByText('investigations.details.samples.no_samples')
+ ).toBeInTheDocument();
- renderComponent();
+ // no investigation publications, so show no publications message
+ expect(
+ screen.getByText('investigations.details.publications.no_publications')
+ );
- expect(
- screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
- ).toHaveAttribute(
- 'href',
- '/browse/instrument/4/facilityCycle/5/investigation/1/dataset/1?view=card'
- );
- expect(screen.getByText('datasets.doi:')).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'dataset doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/dataset doi'
- );
+ // no users, so should hide users section
+ expect(screen.queryByText('investigations.details.users.label')).toBeNull();
+ });
- // actions for datasets should be visible
- const actionContainer = screen.getByTestId(
- 'investigation-landing-dataset-0-action-container'
- );
- expect(actionContainer).toBeInTheDocument();
- expect(
- within(actionContainer).getByRole('button', {
- name: 'buttons.add_to_cart',
- })
- ).toBeInTheDocument();
- });
+ it('renders correctly for data publication hierarchy', () => {
+ history.replace(
+ generatePath(paths.dataPublications.landing.isisInvestigationLanding, {
+ instrumentId: '4',
+ dataPublicationId: '5',
+ investigationId: '1',
+ })
+ );
+ renderComponent(true);
- it('for data publication hierarchy and normal view', () => {
- renderComponent(true);
+ // branding should be visible
+ expect(screen.getByRole('img', { name: 'STFC Logo' })).toBeInTheDocument();
+ expect(
+ screen.getByText('doi_constants.branding.title')
+ ).toBeInTheDocument();
+ expect(screen.getByText('doi_constants.branding.body')).toBeInTheDocument();
- expect(
- screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
- ).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/4/dataPublication/5/investigation/1/dataset/1'
- );
- expect(screen.getByText('datasets.doi:')).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'dataset doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/dataset doi'
- );
+ // investigation details should be visible
+ expect(screen.getByText('Title 1.1')).toBeInTheDocument();
+ expect(screen.getByText('foo bar')).toBeInTheDocument();
- // actions for datasets should be visible
- const actionContainer = screen.getByTestId(
- 'investigation-landing-dataset-0-action-container'
- );
- expect(actionContainer).toBeInTheDocument();
- expect(
- within(actionContainer).getByRole('button', {
- name: 'buttons.add_to_cart',
- })
- ).toBeInTheDocument();
- });
+ // publisher section should be visible
+ expect(
+ screen.getByText('datapublications.details.publisher')
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText('doi_constants.publisher.name')
+ ).toBeInTheDocument();
- it('for data publication hierarchy and card view', () => {
- history.push('/?view=card');
+ // investigation samples should be hidden
+ expect(
+ screen.queryByText('investigations.details.samples.label')
+ ).toBeNull();
+ expect(
+ screen.queryByText('investigations.details.samples.no_samples')
+ ).toBeNull();
+ expect(
+ screen.queryAllByLabelText(/landing-investigation-sample-\d+$/)
+ ).toHaveLength(0);
- renderComponent(true);
+ // publication section should be hidden
+ expect(
+ screen.queryByText('investigations.details.publications.label')
+ ).toBeNull();
+ expect(
+ screen.queryByText('investigations.details.publications.no_publications')
+ ).toBeNull();
+ expect(
+ screen.queryAllByLabelText(/landing-investigation-reference-\d+$/)
+ ).toHaveLength(0);
- expect(
- screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
- ).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/4/dataPublication/5/investigation/1/dataset/1?view=card'
- );
- expect(screen.getByText('datasets.doi:')).toBeInTheDocument();
- expect(screen.getByRole('link', { name: 'dataset doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/dataset doi'
- );
+ // short format information should be visible
+ expect(screen.getByText('investigations.visit_id:')).toBeInTheDocument();
+ expect(screen.getByText('visit id 1')).toBeInTheDocument();
+ expect(screen.getByText('investigations.doi:')).toBeInTheDocument();
+ expect(
+ screen.getByRole('link', { name: '10.1234/ISIS.E.RB123456-1' })
+ ).toHaveAttribute('href', 'https://doi.org/10.1234/ISIS.E.RB123456-1');
+ expect(screen.getByText('investigations.parent_doi:')).toBeInTheDocument();
+ expect(
+ screen.getByRole('link', { name: '10.1234/ISIS.E.RB123456' })
+ ).toHaveAttribute('href', 'https://doi.org/10.1234/ISIS.E.RB123456');
+ expect(screen.getByText('investigations.name:')).toBeInTheDocument();
+ expect(screen.getByText('Title 1')).toBeInTheDocument();
+ expect(
+ screen.getByText('investigations.details.facility:')
+ ).toBeInTheDocument();
+ expect(screen.getByText('LILS')).toBeInTheDocument();
+ expect(screen.getByText('investigations.instrument:')).toBeInTheDocument();
+ expect(screen.getByText('LARMOR')).toBeInTheDocument();
+ expect(
+ screen.getByText('datapublications.details.format:')
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole('link', { name: 'doi_constants.distribution.format' })
+ ).toHaveAttribute(
+ 'href',
+ 'https://www.isis.stfc.ac.uk/Pages/ISIS-Raw-File-Format.aspx'
+ );
+ expect(
+ screen.getByText('investigations.release_date:')
+ ).toBeInTheDocument();
+ expect(screen.getByText('2019-06-10')).toBeInTheDocument();
- // actions for datasets should be visible
- const actionContainer = screen.getByTestId(
- 'investigation-landing-dataset-0-action-container'
- );
- expect(actionContainer).toBeInTheDocument();
- expect(
- within(actionContainer).getByRole('button', {
- name: 'buttons.add_to_cart',
- })
- ).toBeInTheDocument();
- });
+ const actionButtonContainer = screen.getByTestId(
+ 'investigation-landing-action-container'
+ );
+
+ // actions should be visible
+ expect(actionButtonContainer).toBeInTheDocument();
+ expect(
+ within(actionButtonContainer).getByRole('button', {
+ name: 'buttons.add_to_cart',
+ })
+ ).toBeInTheDocument();
+ expect(
+ within(actionButtonContainer).getByRole('button', {
+ name: 'buttons.download',
+ })
+ ).toBeInTheDocument();
+
+ // datasets should be visible
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/1/dataset/1'
+ );
+
+ // actions for datasets should be visible
+ const actionContainer = screen.getByTestId(
+ 'investigation-landing-dataset-0-action-container'
+ );
+ expect(actionContainer).toBeInTheDocument();
+ expect(
+ within(actionContainer).getByRole('button', {
+ name: 'buttons.add_to_cart',
+ })
+ ).toBeInTheDocument();
+ });
+
+ it('renders correctly for data publication hierarchy when no investigations or description', () => {
+ initialDataPublicationData.description = undefined;
+ if (initialDataPublicationData.content?.dataCollectionInvestigations?.[0])
+ initialDataPublicationData.content.dataCollectionInvestigations[0].investigation =
+ undefined;
+
+ history.replace(
+ generatePath(paths.dataPublications.landing.isisInvestigationLanding, {
+ instrumentId: '4',
+ dataPublicationId: '5',
+ investigationId: '1',
+ })
+ );
+ renderComponent(true);
+
+ expect(screen.getByText('Description not provided')).toBeInTheDocument();
+
+ expect(
+ screen.getByText(
+ (_, element) => element.textContent === 'investigations.visit_id:1'
+ )
+ ).toBeInTheDocument();
+
+ // should not display missing info
+
+ expect(
+ screen.queryByText('investigations.instrument')
+ ).not.toBeInTheDocument();
+
+ expect(
+ screen.queryByRole('tab', { name: 'investigation-datasets-tab' })
+ ).not.toBeInTheDocument();
+
+ expect(
+ screen.queryByTestId('investigation-landing-action-container')
+ ).not.toBeInTheDocument();
+
+ expect(
+ screen.queryByLabelText('landing-investigation-part-label')
+ ).not.toBeInTheDocument();
});
describe('links to the correct url in the datafiles tab', () => {
it('for facility cycle hierarchy and normal view', async () => {
renderComponent();
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browse/instrument/4/facilityCycle/5/investigation/1/dataset/1'
+ );
+
await user.click(
await screen.findByRole('tab', {
name: 'investigations.details.datasets',
@@ -423,9 +610,16 @@ describe('ISIS Investigation Landing page', () => {
});
it('for facility cycle hierarchy and cards view', async () => {
- history.replace('/?view=card');
+ history.replace({ search: '?view=card' });
renderComponent();
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browse/instrument/4/facilityCycle/5/investigation/1/dataset/1?view=card'
+ );
+
await user.click(
await screen.findByRole('tab', {
name: 'investigations.details.datasets',
@@ -439,9 +633,22 @@ describe('ISIS Investigation Landing page', () => {
});
it('for data publication hierarchy and normal view', async () => {
- history.replace('/?view=card');
+ history.replace(
+ generatePath(paths.dataPublications.landing.isisInvestigationLanding, {
+ instrumentId: '4',
+ dataPublicationId: '5',
+ investigationId: '1',
+ })
+ );
renderComponent(true);
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/1/dataset/1'
+ );
+
await user.click(
await screen.findByRole('tab', {
name: 'investigations.details.datasets',
@@ -454,9 +661,26 @@ describe('ISIS Investigation Landing page', () => {
});
it('for data publication hierarchy and cards view', async () => {
- history.replace('/?view=card');
+ history.replace({
+ pathname: generatePath(
+ paths.dataPublications.landing.isisInvestigationLanding,
+ {
+ instrumentId: '4',
+ dataPublicationId: '5',
+ investigationId: '1',
+ }
+ ),
+ search: '?view=card',
+ });
renderComponent(true);
+ expect(
+ screen.getByRole('link', { name: 'datasets.dataset: dataset 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/4/dataPublication/5/investigation/1/dataset/1?view=card'
+ );
+
await user.click(
await screen.findByRole('tab', {
name: 'investigations.details.datasets',
@@ -469,119 +693,4 @@ describe('ISIS Investigation Landing page', () => {
expect(history.location.search).toBe('?view=card');
});
});
-
- it('users displayed correctly', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], investigationUsers: investigationUser }],
- });
- renderComponent();
-
- expect(
- await screen.findByLabelText('landing-investigation-user-0')
- ).toHaveTextContent('Principal Investigator: John Smith');
- expect(
- await screen.findByLabelText('landing-investigation-user-1')
- ).toHaveTextContent('Local Contact: Jane Smith');
- expect(
- await screen.findByLabelText('landing-investigation-user-2')
- ).toHaveTextContent('Experimenter: Jesse Smith');
- });
-
- it('renders text "No samples" when no data is present', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], samples: noSamples }],
- });
- renderComponent();
-
- expect(
- await screen.findByText('investigations.details.samples.no_samples')
- ).toBeInTheDocument();
- });
-
- it('renders text "No publications" when no data is present', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], publications: noPublication }],
- });
- renderComponent();
-
- expect(
- await screen.findByText(
- 'investigations.details.publications.no_publications'
- )
- ).toBeInTheDocument();
- });
-
- it('publications displayed correctly', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], publications: publication }],
- });
- renderComponent();
-
- expect(
- await screen.findByText('Journal, Author, Date, DOI')
- ).toBeInTheDocument();
- });
-
- it('samples displayed correctly', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], samples: sample }],
- });
- renderComponent();
-
- expect(await screen.findByText('Sample')).toBeInTheDocument();
- });
-
- it('displays citation correctly when study missing', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], studyInvestigations: undefined }],
- });
- renderComponent();
-
- expect(
- await screen.findByText(
- '2019: Test title 1, doi_constants.publisher.name, https://doi.org/doi 1'
- )
- ).toBeInTheDocument();
- });
-
- it('displays citation correctly with one user', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], investigationUsers: [investigationUser[0]] }],
- });
- renderComponent();
-
- expect(
- await screen.findByText(
- 'John Smith; 2019: Test title 1, doi_constants.publisher.name, https://doi.org/doi 1'
- )
- ).toBeInTheDocument();
- });
-
- it('displays citation correctly with multiple users', async () => {
- (useInvestigation as jest.Mock).mockReturnValue({
- data: [{ ...initialData[0], investigationUsers: investigationUser }],
- });
- renderComponent();
-
- expect(
- await screen.findByText(
- 'John Smith et al; 2019: Test title 1, doi_constants.publisher.name, https://doi.org/doi 1'
- )
- ).toBeInTheDocument();
- });
-
- it('displays DOI and renders the expected Link ', async () => {
- renderComponent();
- expect(await screen.findByRole('link', { name: 'doi 1' })).toHaveAttribute(
- 'href',
- 'https://doi.org/doi 1'
- );
- });
-
- it('displays Experiment DOI (PID) and renders the expected Link ', async () => {
- renderComponent();
- expect(
- await screen.findByRole('link', { name: 'Data Publication Pid' })
- ).toHaveAttribute('href', 'https://doi.org/Data Publication Pid');
- });
});
diff --git a/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.tsx b/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.tsx
index a3b69dfb4..06c67814f 100644
--- a/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.tsx
+++ b/packages/datagateway-dataview/src/views/landing/isis/isisInvestigationLanding.component.tsx
@@ -20,7 +20,6 @@ import {
import {
Dataset,
Investigation,
- InvestigationUser,
parseSearchToQuery,
Publication,
Sample,
@@ -32,6 +31,9 @@ import {
getTooltipText,
formatBytes,
externalSiteLink,
+ useDataPublication,
+ DataPublication,
+ useDataPublications,
} from 'datagateway-common';
import React from 'react';
import { useTranslation } from 'react-i18next';
@@ -76,32 +78,56 @@ const ActionButtonsContainer = styled('div')(({ theme }) => ({
interface FormattedUser {
role?: string;
+ contributorType?: string;
fullName: string;
}
interface LandingPageProps {
- instrumentId: string;
- instrumentChildId: string;
investigationId: string;
dataPublication: boolean;
}
-const LandingPage = (props: LandingPageProps): React.ReactElement => {
- const [t] = useTranslation();
- const { push } = useHistory();
- const location = useLocation();
- const { view } = React.useMemo(
- () => parseSearchToQuery(location.search),
- [location.search]
- );
- const [value, setValue] = React.useState<'details'>('details');
- const { instrumentId, instrumentChildId, investigationId, dataPublication } =
- props;
+const InvestigationDataPublicationLandingPage = (
+ props: LandingPageProps
+): React.ReactElement => {
+ const { investigationId } = props;
+
+ const { data } = useDataPublication(parseInt(investigationId));
+
+ const { data: studyDataPublications } = useDataPublications([
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: investigationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': {
+ eq: 'study',
+ },
+ }),
+ },
+ ]);
+
+ const studyDataPublication = studyDataPublications?.[0];
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation/${investigationId}`;
+ return (
+
+ );
+};
+const InvestigationLandingPage = (
+ props: LandingPageProps
+): React.ReactElement => {
+ const { investigationId } = props;
const { data } = useInvestigation(parseInt(investigationId), [
{
filterType: 'include',
@@ -113,7 +139,9 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
'publications',
'datasets',
{
- dataCollectionInvestigations: { dataCollection: 'dataPublications' },
+ dataCollectionInvestigations: {
+ dataCollection: { dataPublications: 'type' },
+ },
},
{
investigationInstruments: 'instrument',
@@ -122,19 +150,51 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
},
]);
- const title = React.useMemo(() => data?.[0]?.title, [data]);
- const doi = React.useMemo(() => data?.[0]?.doi, [data]);
+ return ;
+};
+
+interface CommonLandingPageProps {
+ data?: DataPublication | Investigation[];
+ studyDataPublication?: DataPublication;
+}
+
+const CommonLandingPage = (
+ props: CommonLandingPageProps
+): React.ReactElement => {
+ const [t] = useTranslation();
+ const { push } = useHistory();
+ const location = useLocation();
+ const { view } = React.useMemo(
+ () => parseSearchToQuery(location.search),
+ [location.search]
+ );
+ const [value, setValue] = React.useState<'details'>('details');
+ const { data, studyDataPublication } = props;
+
+ const title = React.useMemo(
+ () => (Array.isArray(data) ? data?.[0]?.title : data?.title),
+ [data]
+ );
+ const doi = React.useMemo(
+ () => (Array.isArray(data) ? data?.[0]?.doi : data?.pid),
+ [data]
+ );
const formattedUsers = React.useMemo(() => {
const principals: FormattedUser[] = [];
const contacts: FormattedUser[] = [];
const experimenters: FormattedUser[] = [];
- if (data?.[0]?.investigationUsers) {
- const investigationUsers = data?.[0]
- .investigationUsers as InvestigationUser[];
- investigationUsers.forEach((user) => {
+ const users = Array.isArray(data)
+ ? data?.[0]?.investigationUsers
+ : data?.users;
+ if (users) {
+ users.forEach((u) => {
+ let user: { role?: string; fullName?: string } = {};
+ if ('user' in u) user = { fullName: u.user?.fullName, role: u.role };
+ if ('contributorType' in u)
+ user = { fullName: u.fullName, role: u.contributorType };
// Only keep users where we have their fullName
- const fullname = user.user?.fullName;
+ const fullname = user.fullName;
if (fullname) {
switch (user.role) {
case 'principal_experimenter':
@@ -160,7 +220,7 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
}, [data]);
const formattedPublications = React.useMemo(() => {
- if (data?.[0]?.publications) {
+ if (Array.isArray(data) && data?.[0]?.publications) {
return (data[0].publications as Publication[]).map(
(publication) => publication.fullReference
);
@@ -168,114 +228,191 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
}, [data]);
const formattedSamples = React.useMemo(() => {
- if (data?.[0]?.samples) {
+ if (Array.isArray(data) && data?.[0]?.samples) {
return (data[0].samples as Sample[]).map((sample) => sample.name);
}
}, [data]);
- const shortInfo = [
- {
- content: (entity: Investigation) => entity.visitId,
- label: t('investigations.visit_id'),
- icon: ,
- },
- {
- content: function doiFormat(entity: Investigation) {
- return (
- entity?.doi &&
- externalSiteLink(
- `https://doi.org/${entity.doi}`,
- entity.doi,
- 'isis-investigation-landing-doi-link'
- )
- );
- },
- label: t('investigations.doi'),
- icon: ,
- },
- // TODO: when datapublications are created for studies, need to pick the study datapublication
- {
- content: function parentDoiFormat(entity: Investigation) {
- return (
- entity.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications?.[0] &&
- externalSiteLink(
- `https://doi.org/${entity.dataCollectionInvestigations?.[0]?.dataCollection?.dataPublications?.[0].pid}`,
- entity.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications?.[0].pid,
- 'isis-investigations-landing-parent-doi-link'
- )
- );
- },
- label: t('investigations.parent_doi'),
- icon: ,
- },
- {
- content: (entity: Investigation) => entity.name,
- label: t('investigations.name'),
- icon: ,
- },
- {
- content: (entity: Investigation) => {
- return formatBytes(entity.fileSize);
- },
- label: t('investigations.size'),
- icon: ,
- },
- {
- content: (entity: Investigation) => entity.facility?.name,
- label: t('investigations.details.facility'),
- icon: ,
- },
- {
- content: (entity: Investigation) =>
- entity.investigationInstruments?.[0]?.instrument?.name,
- label: t('investigations.instrument'),
- icon: ,
- },
- {
- content: function distributionFormat(entity: Investigation) {
- return externalSiteLink(
- 'https://www.isis.stfc.ac.uk/Pages/ISIS-Raw-File-Format.aspx',
- t('doi_constants.distribution.format')
- );
- },
- label: t('datapublications.details.format'),
- icon: ,
- },
- {
- content: (entity: Investigation) => entity.releaseDate?.slice(0, 10),
- label: t('investigations.release_date'),
- icon: ,
- },
- {
- content: (entity: Investigation) => entity.startDate?.slice(0, 10),
- label: t('investigations.start_date'),
- icon: ,
- },
- {
- content: (entity: Investigation) => entity.endDate?.slice(0, 10),
- label: t('investigations.end_date'),
- icon: ,
- },
- ];
+ const shortInfo = Array.isArray(data)
+ ? [
+ {
+ content: () => data?.[0]?.visitId,
+ label: t('investigations.visit_id'),
+ icon: ,
+ },
+ {
+ content: function doiFormat() {
+ return (
+ data?.[0]?.doi &&
+ externalSiteLink(
+ `https://doi.org/${data[0].doi}`,
+ data[0].doi,
+ 'isis-investigation-landing-doi-link'
+ )
+ );
+ },
+ label: t('investigations.doi'),
+ icon: ,
+ },
+ {
+ content: function parentDoiFormat() {
+ const studyDataPublication =
+ data?.[0]?.dataCollectionInvestigations?.filter(
+ (dci) =>
+ dci.dataCollection?.dataPublications?.[0]?.type?.name ===
+ 'study'
+ )?.[0]?.dataCollection?.dataPublications?.[0];
+ return (
+ studyDataPublication &&
+ externalSiteLink(
+ `https://doi.org/${studyDataPublication.pid}`,
+ studyDataPublication.pid,
+ 'isis-investigations-landing-parent-doi-link'
+ )
+ );
+ },
+ label: t('investigations.parent_doi'),
+ icon: ,
+ },
+ {
+ content: () => data?.[0]?.name,
+ label: t('investigations.name'),
+ icon: ,
+ },
+ {
+ content: () => {
+ return formatBytes(data?.[0]?.fileSize);
+ },
+ label: t('investigations.size'),
+ icon: ,
+ },
+ {
+ content: () => data?.[0]?.facility?.name,
+ label: t('investigations.details.facility'),
+ icon: ,
+ },
+ {
+ content: () =>
+ data?.[0]?.investigationInstruments?.[0]?.instrument?.name,
+ label: t('investigations.instrument'),
+ icon: ,
+ },
+ {
+ content: function distributionFormat() {
+ return externalSiteLink(
+ 'https://www.isis.stfc.ac.uk/Pages/ISIS-Raw-File-Format.aspx',
+ t('doi_constants.distribution.format')
+ );
+ },
+ label: t('datapublications.details.format'),
+ icon: ,
+ },
+ {
+ content: () => data?.[0]?.releaseDate?.slice(0, 10),
+ label: t('investigations.release_date'),
+ icon: ,
+ },
+ {
+ content: () => data?.[0]?.startDate?.slice(0, 10),
+ label: t('investigations.start_date'),
+ icon: ,
+ },
+ {
+ content: () => data?.[0]?.endDate?.slice(0, 10),
+ label: t('investigations.end_date'),
+ icon: ,
+ },
+ ]
+ : [
+ {
+ content: function doiFormat() {
+ return (
+ data?.pid &&
+ externalSiteLink(
+ `https://doi.org/${data.pid}`,
+ data.pid,
+ 'isis-investigation-landing-doi-link'
+ )
+ );
+ },
+ label: t('investigations.doi'),
+ icon: ,
+ },
+ {
+ content: function doiFormat() {
+ return (
+ studyDataPublication &&
+ studyDataPublication?.pid &&
+ externalSiteLink(
+ `https://doi.org/${studyDataPublication.pid}`,
+ studyDataPublication.pid,
+ 'isis-investigations-landing-parent-doi-link'
+ )
+ );
+ },
+ label: t('investigations.parent_doi'),
+ icon: ,
+ },
+ {
+ content: () => studyDataPublication && studyDataPublication.title,
+ label: t('investigations.name'),
+ icon: ,
+ },
+ {
+ content: () =>
+ data?.content?.dataCollectionInvestigations?.[0].investigation
+ ?.visitId ??
+ (data?.pid.includes('-') && data.pid.split('-')[1]),
+ label: t('investigations.visit_id'),
+ icon: ,
+ },
+ {
+ content: () => data?.facility?.name,
+ label: t('investigations.details.facility'),
+ icon: ,
+ },
+ {
+ content: () =>
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation
+ ?.investigationInstruments?.[0]?.instrument?.name,
+ label: t('investigations.instrument'),
+ icon: ,
+ },
+ {
+ content: function distributionFormat() {
+ return externalSiteLink(
+ 'https://www.isis.stfc.ac.uk/Pages/ISIS-Raw-File-Format.aspx',
+ t('doi_constants.distribution.format')
+ );
+ },
+ label: t('datapublications.details.format'),
+ icon: ,
+ },
+ {
+ content: () => data?.publicationDate?.slice(0, 10),
+ label: t('investigations.release_date'),
+ icon: ,
+ },
+ ];
- const shortDatasetInfo = [
- {
- content: function doiFormat(entity: Dataset) {
- return (
- entity?.doi &&
- externalSiteLink(
- `https://doi.org/${entity.doi}`,
- entity.doi,
- 'landing-study-doi-link'
- )
- );
- },
- label: t('datasets.doi'),
- icon: ,
- },
- ];
+ const shortDatasetInfo = Array.isArray(data)
+ ? [
+ {
+ content: function doiFormat(entity: Dataset) {
+ return (
+ entity?.doi &&
+ externalSiteLink(
+ `https://doi.org/${entity.doi}`,
+ entity.doi,
+ 'landing-study-doi-link'
+ )
+ );
+ },
+ label: t('datasets.doi'),
+ icon: ,
+ },
+ ]
+ : [];
return (
{
label={t('investigations.details.label')}
value="details"
/>
-
- push(
- view
- ? `${urlPrefix}/dataset?view=${view}`
- : `${urlPrefix}/dataset`
- )
- }
- />
+ {typeof data !== 'undefined' &&
+ (Array.isArray(data) ||
+ data?.content?.dataCollectionInvestigations?.[0]
+ ?.investigation) && (
+
+ push(
+ view
+ ? `${location.pathname}/dataset?view=${view}`
+ : `${location.pathname}/dataset`
+ )
+ }
+ />
+ )}
@@ -319,12 +461,16 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
{/* Long format information */}
- {data?.[0]?.title}
+ {Array.isArray(data) ? data?.[0]?.title : data?.title}
- {data?.[0]?.summary && data[0].summary !== 'null'
- ? data[0].summary
+ {Array.isArray(data)
+ ? data?.[0]?.summary && data[0].summary !== 'null'
+ ? data[0].summary
+ : 'Description not provided'
+ : data?.description && data.description !== 'null'
+ ? data.description
: 'Description not provided'}
{formattedUsers.length > 0 && (
@@ -359,7 +505,11 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
doi={doi}
formattedUsers={formattedUsers}
title={title}
- startDate={data?.[0]?.startDate}
+ startDate={
+ Array.isArray(data)
+ ? data?.[0]?.startDate
+ : data?.publicationDate
+ }
/>
{formattedSamples && (
@@ -415,35 +565,68 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
{shortInfo.map(
(field, i) =>
- data?.[0] &&
- field.content(data[0] as Investigation) && (
+ field.content() && (
{field.icon}
{field.label}:
-
-
- {field.content(data[0] as Investigation)}
-
+
+ {field.content()}
)
)}
{/* Actions */}
-
-
-
+ {(Array.isArray(data) ||
+ data?.content?.dataCollectionInvestigations?.[0]?.investigation
+ ?.id) && (
+
+
+
+
+ )}
{/* Parts */}
- {(data?.[0] as Investigation)?.datasets?.map((dataset, i) => (
+ {(Array.isArray(data)
+ ? data?.[0]
+ : data?.content?.dataCollectionInvestigations?.[0]?.investigation
+ )?.datasets?.map((dataset, i) => (
{
aria-label="landing-investigation-part-label"
>
{tableLink(
- `${urlPrefix}/dataset/${dataset.id}`,
+ `${location.pathname}/dataset/${dataset.id}`,
`${t('datasets.dataset')}: ${dataset.name}`,
view
)}
@@ -501,4 +684,12 @@ const LandingPage = (props: LandingPageProps): React.ReactElement => {
);
};
+const LandingPage = (props: LandingPageProps): React.ReactElement => {
+ if (props.dataPublication) {
+ return ;
+ } else {
+ return ;
+ }
+};
+
export default LandingPage;
diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.test.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.test.tsx
index cf47cedfe..6306d488e 100644
--- a/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.test.tsx
+++ b/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.test.tsx
@@ -7,7 +7,7 @@ import configureStore from 'redux-mock-store';
import { QueryClient, QueryClientProvider } from 'react-query';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import { createMemoryHistory, type History } from 'history';
import { parse } from 'date-fns';
import {
@@ -28,6 +28,7 @@ import { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
import ISISDataPublicationsTable from './isisDataPublicationsTable.component';
import axios, { AxiosResponse } from 'axios';
+import { paths } from '../../../page/pageContainer.component';
jest
.useFakeTimers('modern')
@@ -40,13 +41,26 @@ describe('ISIS Data Publication table component', () => {
let history: History;
let user: UserEvent;
- const renderComponent = (): RenderResult => {
+ const renderComponent = (studyDataPublicationId?: string): RenderResult => {
+ if (studyDataPublicationId)
+ history.replace(
+ generatePath(
+ paths.dataPublications.toggle.isisInvestigationDataPublication,
+ {
+ instrumentId: 1,
+ studyDataPublicationId,
+ }
+ )
+ );
const store = mockStore(state);
return render(
-
+
@@ -81,7 +95,13 @@ describe('ISIS Data Publication table component', () => {
},
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.dataPublications.toggle.isisStudyDataPublication, {
+ instrumentId: 1,
+ }),
+ ],
+ });
user = userEvent.setup({
delay: null,
});
@@ -119,153 +139,222 @@ describe('ISIS Data Publication table component', () => {
jest.clearAllMocks();
});
- it('renders correctly', async () => {
- renderComponent();
-
- const rows = await screen.findAllByRole('row');
- //should have 1 row in the table
- expect(rows).toHaveLength(1);
-
- expect(
- await findColumnHeaderByName('datapublications.title')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('datapublications.pid')
- ).toBeInTheDocument();
- expect(
- await findColumnHeaderByName('datapublications.publication_date')
- ).toBeInTheDocument();
-
- const row = await findRowAt(0);
-
- // check that every cell contains the correct values
- expect(
- within(
- findCellInRow(row, {
- columnIndex: await findColumnIndexByName('datapublications.title'),
- })
- ).getByText('Test 1')
- ).toBeInTheDocument();
- expect(
- within(
- findCellInRow(row, {
- columnIndex: await findColumnIndexByName('datapublications.pid'),
- })
- ).getByText('doi')
- ).toBeInTheDocument();
- });
+ describe('Study Data Publication', () => {
+ it('renders correctly', async () => {
+ renderComponent();
+
+ const rows = await screen.findAllByRole('row');
+ //should have 1 row in the table
+ expect(rows).toHaveLength(1);
+
+ expect(
+ await findColumnHeaderByName('datapublications.title')
+ ).toBeInTheDocument();
+ expect(
+ await findColumnHeaderByName('datapublications.pid')
+ ).toBeInTheDocument();
+
+ const row = await findRowAt(0);
+
+ // check that every cell contains the correct values
+ expect(
+ within(
+ findCellInRow(row, {
+ columnIndex: await findColumnIndexByName('datapublications.title'),
+ })
+ ).getByText('Test 1')
+ ).toBeInTheDocument();
+ expect(
+ within(
+ findCellInRow(row, {
+ columnIndex: await findColumnIndexByName('datapublications.pid'),
+ })
+ ).getByText('doi')
+ ).toBeInTheDocument();
+ });
- it('updates filter query params on text filter', async () => {
- renderComponent();
+ it('updates filter query params on text filter', async () => {
+ renderComponent();
- const filterInput = await screen.findByRole('textbox', {
- name: 'Filter by datapublications.title',
- hidden: true,
- });
+ const filterInput = await screen.findByRole('textbox', {
+ name: 'Filter by datapublications.title',
+ hidden: true,
+ });
- await user.type(filterInput, 'test');
+ await user.type(filterInput, 'test');
- // user.type inputs the given string character by character to simulate user typing
- // each keystroke of user.type creates a new entry in the history stack
- // so the initial entry + 4 characters in "test" = 5 entries
- expect(history.length).toBe(5);
- expect(history.location.search).toBe(
- `?filters=${encodeURIComponent(
- '{"title":{"value":"test","type":"include"}}'
- )}`
- );
+ // user.type inputs the given string character by character to simulate user typing
+ // each keystroke of user.type creates a new entry in the history stack
+ // so the initial entry + 4 characters in "test" = 5 entries
+ expect(history.length).toBe(5);
+ expect(history.location.search).toBe(
+ `?filters=${encodeURIComponent(
+ '{"title":{"value":"test","type":"include"}}'
+ )}`
+ );
- await user.clear(filterInput);
+ await user.clear(filterInput);
- expect(history.length).toBe(6);
- expect(history.location.search).toBe('?');
- });
+ expect(history.length).toBe(6);
+ expect(history.location.search).toBe('?');
+ });
- it('updates filter query params on date filter', async () => {
- applyDatePickerWorkaround();
+ it('uses default sort', () => {
+ renderComponent();
+ expect(history.length).toBe(1);
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"title":"desc"}')}`
+ );
+
+ // check that the data request is sent only once after mounting
+ const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
+ (call) => call[0] === '/datapublications'
+ );
+ expect(datafilesCalls).toHaveLength(1);
+ });
+
+ it('updates sort query params on sort', async () => {
+ renderComponent();
- renderComponent();
+ await user.click(
+ await screen.findByRole('button', { name: 'datapublications.pid' })
+ );
- const filterInput = await screen.findByRole('textbox', {
- name: 'datapublications.publication_date filter to',
+ expect(history.length).toBe(2);
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"pid":"asc"}')}`
+ );
});
- await user.type(filterInput, '2019-08-06');
+ it('renders data publication name as a link', async () => {
+ renderComponent();
- expect(history.length).toBe(2);
- expect(history.location.search).toBe(
- `?filters=${encodeURIComponent(
- '{"publicationDate":{"endDate":"2019-08-06"}}'
- )}`
- );
+ const dataPublicationIdColIndex = await findColumnIndexByName(
+ 'datapublications.title'
+ );
+ const row = await findRowAt(0);
+ const dataPublicationIdCell = findCellInRow(row, {
+ columnIndex: dataPublicationIdColIndex,
+ });
- // await user.clear(filterInput);
- await user.click(filterInput);
- await user.keyboard('{Control}a{/Control}');
- await user.keyboard('{Delete}');
+ expect(
+ within(dataPublicationIdCell).getByRole('link', { name: 'Test 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/1'
+ );
+ });
+
+ it('displays Experiment DOI (PID) and renders the expected Link ', async () => {
+ renderComponent();
- expect(history.length).toBe(3);
- expect(history.location.search).toBe('?');
+ const pidColIndex = await findColumnIndexByName('datapublications.pid');
+ const row = await findRowAt(0);
+ const pidCell = findCellInRow(row, { columnIndex: pidColIndex });
- cleanupDatePickerWorkaround();
+ expect(
+ within(pidCell).getByRole('link', { name: 'doi' })
+ ).toHaveAttribute('href', 'https://doi.org/doi');
+ });
});
- it('uses default sort', () => {
- renderComponent();
- expect(history.length).toBe(1);
- expect(history.location.search).toBe(
- `?sort=${encodeURIComponent('{"publicationDate":"desc"}')}`
- );
+ describe('Investigation Data Publication', () => {
+ it('renders correctly', async () => {
+ renderComponent('2');
+
+ const rows = await screen.findAllByRole('row');
+ //should have 1 row in the table
+ expect(rows).toHaveLength(1);
+
+ expect(
+ await findColumnHeaderByName('datapublications.title')
+ ).toBeInTheDocument();
+ expect(
+ await findColumnHeaderByName('datapublications.pid')
+ ).toBeInTheDocument();
+ expect(
+ await findColumnHeaderByName('datapublications.publication_date')
+ ).toBeInTheDocument();
+
+ const row = await findRowAt(0);
+
+ // check that every cell contains the correct values
+ expect(
+ within(
+ findCellInRow(row, {
+ columnIndex: await findColumnIndexByName('datapublications.title'),
+ })
+ ).getByText('Test 1')
+ ).toBeInTheDocument();
+ expect(
+ within(
+ findCellInRow(row, {
+ columnIndex: await findColumnIndexByName('datapublications.pid'),
+ })
+ ).getByText('doi')
+ ).toBeInTheDocument();
+ });
- // check that the data request is sent only once after mounting
- const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
- (call) => call[0] === '/datapublications'
- );
- expect(datafilesCalls).toHaveLength(1);
- });
+ it('updates filter query params on date filter', async () => {
+ applyDatePickerWorkaround();
- it('updates sort query params on sort', async () => {
- renderComponent();
+ renderComponent('2');
- await user.click(
- await screen.findByRole('button', { name: 'datapublications.title' })
- );
+ const filterInput = await screen.findByRole('textbox', {
+ name: 'datapublications.publication_date filter to',
+ });
- expect(history.length).toBe(2);
- expect(history.location.search).toBe(
- `?sort=${encodeURIComponent('{"title":"asc"}')}`
- );
- });
+ await user.type(filterInput, '2019-08-06');
- it('renders data publication name as a link', async () => {
- renderComponent();
+ expect(history.length).toBe(2);
+ expect(history.location.search).toBe(
+ `?filters=${encodeURIComponent(
+ '{"publicationDate":{"endDate":"2019-08-06"}}'
+ )}`
+ );
- const dataPublicationIdColIndex = await findColumnIndexByName(
- 'datapublications.title'
- );
- const row = await findRowAt(0);
- const dataPublicationIdCell = findCellInRow(row, {
- columnIndex: dataPublicationIdColIndex,
+ // await user.clear(filterInput);
+ await user.click(filterInput);
+ await user.keyboard('{Control}a{/Control}');
+ await user.keyboard('{Delete}');
+
+ expect(history.length).toBe(3);
+ expect(history.location.search).toBe('?');
+
+ cleanupDatePickerWorkaround();
});
- expect(
- within(dataPublicationIdCell).getByRole('link', { name: 'Test 1' })
- ).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/1/dataPublication/1'
- );
- });
+ it('uses default sort', () => {
+ renderComponent('2');
+ expect(history.length).toBe(1);
+ expect(history.location.search).toBe(
+ `?sort=${encodeURIComponent('{"publicationDate":"desc"}')}`
+ );
+
+ // check that the data request is sent only once after mounting
+ const datafilesCalls = (axios.get as jest.Mock).mock.calls.filter(
+ (call) => call[0] === '/datapublications'
+ );
+ expect(datafilesCalls).toHaveLength(1);
+ });
- it('displays Experiment DOI (PID) and renders the expected Link ', async () => {
- renderComponent();
+ it('renders data publication name as a link', async () => {
+ renderComponent('2');
- const pidColIndex = await findColumnIndexByName('datapublications.pid');
- const row = await findRowAt(0);
- const pidCell = findCellInRow(row, { columnIndex: pidColIndex });
+ const dataPublicationIdColIndex = await findColumnIndexByName(
+ 'datapublications.title'
+ );
+ const row = await findRowAt(0);
+ const dataPublicationIdCell = findCellInRow(row, {
+ columnIndex: dataPublicationIdColIndex,
+ });
- expect(within(pidCell).getByRole('link', { name: 'doi' })).toHaveAttribute(
- 'href',
- 'https://doi.org/doi'
- );
+ expect(
+ within(dataPublicationIdCell).getByRole('link', { name: 'Test 1' })
+ ).toHaveAttribute(
+ 'href',
+ '/browseDataPublications/instrument/1/dataPublication/2/investigation/1'
+ );
+ });
});
});
diff --git a/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.tsx b/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.tsx
index 5a5104c4b..1f82260ea 100644
--- a/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.tsx
+++ b/packages/datagateway-dataview/src/views/table/isis/isisDataPublicationsTable.component.tsx
@@ -20,12 +20,13 @@ import { useLocation } from 'react-router-dom';
interface ISISDataPublicationsTableProps {
instrumentId: string;
+ studyDataPublicationId?: string;
}
const ISISDataPublicationsTable = (
props: ISISDataPublicationsTableProps
): React.ReactElement => {
- const { instrumentId } = props;
+ const { instrumentId, studyDataPublicationId } = props;
const location = useLocation();
const [t] = useTranslation();
@@ -45,6 +46,36 @@ const ISISDataPublicationsTable = (
},
}),
},
+ ...(studyDataPublicationId
+ ? [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: studyDataPublicationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'investigation' },
+ }),
+ },
+ ]
+ : [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'study' },
+ }),
+ },
+ {
+ filterType: 'distinct',
+ filterValue: JSON.stringify(['id', 'title', 'pid']),
+ },
+ ]),
]);
// isMounted is used to disable queries when the component isn't fully mounted.
@@ -66,6 +97,36 @@ const ISISDataPublicationsTable = (
},
}),
},
+ ...(studyDataPublicationId
+ ? [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'content.dataCollectionInvestigations.investigation.dataCollectionInvestigations.dataCollection.dataPublications.id':
+ {
+ eq: studyDataPublicationId,
+ },
+ }),
+ },
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'investigation' },
+ }),
+ },
+ ]
+ : [
+ {
+ filterType: 'where',
+ filterValue: JSON.stringify({
+ 'type.name': { eq: 'study' },
+ }),
+ },
+ {
+ filterType: 'distinct',
+ filterValue: JSON.stringify(['id', 'title', 'pid']),
+ },
+ ]),
],
isMounted
);
@@ -93,8 +154,6 @@ const ISISDataPublicationsTable = (
);
const columns: ColumnType[] = React.useMemo(() => {
- const pathRoot = 'browseDataPublications';
- const instrumentChild = 'dataPublication';
return [
{
icon: Fingerprint,
@@ -102,12 +161,14 @@ const ISISDataPublicationsTable = (
dataKey: 'title',
cellContentRenderer: (cellProps: TableCellProps) =>
tableLink(
- `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${cellProps.rowData.id}`,
+ `${location.pathname}/${cellProps.rowData.id}`,
cellProps.rowData.title,
view,
'isis-datapublication-table-id'
),
+
filterComponent: textFilter,
+ defaultSort: studyDataPublicationId ? undefined : 'desc',
},
{
icon: Public,
@@ -125,20 +186,31 @@ const ISISDataPublicationsTable = (
},
filterComponent: textFilter,
},
- {
- icon: CalendarToday,
- label: t('datapublications.publication_date'),
- dataKey: 'publicationDate',
- cellContentRenderer: (cellProps: TableCellProps) =>
- (cellProps.rowData as DataPublication).publicationDate?.slice(
- 0,
- 10
- ) ?? '',
- filterComponent: dateFilter,
- defaultSort: 'desc',
- },
+ ...(studyDataPublicationId
+ ? ([
+ {
+ icon: CalendarToday,
+ label: t('datapublications.publication_date'),
+ dataKey: 'publicationDate',
+ cellContentRenderer: (cellProps: TableCellProps) =>
+ (cellProps.rowData as DataPublication).publicationDate?.slice(
+ 0,
+ 10
+ ) ?? '',
+ filterComponent: dateFilter,
+ defaultSort: 'desc',
+ },
+ ] as ColumnType[])
+ : []),
];
- }, [t, textFilter, dateFilter, instrumentId, view]);
+ }, [
+ t,
+ textFilter,
+ studyDataPublicationId,
+ dateFilter,
+ location.pathname,
+ view,
+ ]);
return (
{
const originalModule = jest.requireActual('datagateway-common');
@@ -44,7 +44,6 @@ jest.mock('datagateway-common', () => {
useCart: jest.fn(),
useAddToCart: jest.fn(),
useRemoveFromCart: jest.fn(),
- useDatasetSizes: jest.fn(),
};
});
@@ -61,12 +60,7 @@ describe('ISIS Dataset table component', () => {
-
+
@@ -83,7 +77,15 @@ describe('ISIS Dataset table component', () => {
createTime: '2019-07-23',
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.toggle.isisDataset, {
+ instrumentId: '1',
+ investigationId: '3',
+ facilityCycleId: '2',
+ }),
+ ],
+ });
user = userEvent.setup();
mockStore = configureStore([thunk]);
@@ -117,7 +119,6 @@ describe('ISIS Dataset table component', () => {
mutate: jest.fn(),
isLoading: false,
});
- (useDatasetSizes as jest.Mock).mockReturnValue({ data: 1 });
});
afterEach(() => {
@@ -320,21 +321,14 @@ describe('ISIS Dataset table component', () => {
});
it('renders dataset name as a link in data publication hierarchy', () => {
- const store = mockStore(state);
- render(
-
-
-
-
-
-
-
+ history.replace(
+ generatePath(paths.dataPublications.toggle.isisDataset, {
+ instrumentId: '1',
+ investigationId: '3',
+ dataPublicationId: '2',
+ })
);
+ renderComponent();
expect(screen.getByText('Test 1')).toMatchSnapshot();
});
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 33a409361..498dae595 100644
--- a/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx
+++ b/packages/datagateway-dataview/src/views/table/isis/isisDatasetsTable.component.tsx
@@ -29,21 +29,13 @@ import { useSelector } from 'react-redux';
import { StateType } from '../../../state/app.types';
interface ISISDatasetsTableProps {
- instrumentId: string;
- instrumentChildId: string;
investigationId: string;
- dataPublication: boolean;
}
const ISISDatasetsTable = (
props: ISISDatasetsTableProps
): React.ReactElement => {
- const { investigationId, instrumentChildId, instrumentId, dataPublication } =
- props;
-
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation/${investigationId}/dataset`;
+ const { investigationId } = props;
const [t] = useTranslation();
@@ -145,7 +137,7 @@ const ISISDatasetsTable = (
dataKey: 'name',
cellContentRenderer: (cellProps: TableCellProps) =>
tableLink(
- `${urlPrefix}/${cellProps.rowData.id}`,
+ `${location.pathname}/${cellProps.rowData.id}`,
cellProps.rowData.name,
view
),
@@ -173,7 +165,7 @@ const ISISDatasetsTable = (
filterComponent: dateFilter,
},
],
- [t, textFilter, dateFilter, urlPrefix, view]
+ [t, textFilter, dateFilter, view, location.pathname]
);
const selectedRows = React.useMemo(
@@ -195,10 +187,12 @@ const ISISDatasetsTable = (
push(`${urlPrefix}/${id}/datafile`)}
+ viewDatafiles={(id: number) =>
+ push(`${location.pathname}/${id}/datafile`)
+ }
/>
),
- [push, urlPrefix]
+ [location.pathname, push]
);
return (
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 435b6106e..9c5d75a09 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
@@ -10,7 +10,7 @@ import {
} from 'datagateway-common';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
-import { Router } from 'react-router-dom';
+import { generatePath, Router } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import { createMemoryHistory, type History } from 'history';
import {
@@ -32,6 +32,7 @@ import {
import type { UserEvent } from '@testing-library/user-event/setup/setup';
import userEvent from '@testing-library/user-event';
import axios, { AxiosResponse } from 'axios';
+import { paths } from '../../../page/pageContainer.component';
describe('ISIS Investigations table component', () => {
let mockStore;
@@ -43,17 +44,13 @@ describe('ISIS Investigations table component', () => {
let cartItems: DownloadCartItem[];
let holder: HTMLElement;
- const renderComponent = (dataPublication = false): RenderResult => {
+ const renderComponent = (): RenderResult => {
const store = mockStore(state);
return render(
-
+
@@ -88,12 +85,24 @@ describe('ISIS Investigations table component', () => {
dataCollectionInvestigations: [
{
id: 1,
- investigation: {
- id: 1,
- title: 'Test 1',
- name: 'Test 1',
- visitId: '1',
+ dataCollection: {
+ id: 14,
+ dataPublications: [
+ {
+ id: 15,
+ pid: 'Investigation Data Publication Pid',
+ description: 'Investigation Data Publication description',
+ title: 'Investigation Data Publication',
+ type: {
+ id: 16,
+ name: 'investigation',
+ },
+ },
+ ],
},
+ },
+ {
+ id: 1,
dataCollection: {
id: 11,
dataPublications: [
@@ -101,9 +110,11 @@ describe('ISIS Investigations table component', () => {
id: 12,
pid: 'Data Publication Pid',
description: 'Data Publication description',
- modTime: '2019-06-10',
- createTime: '2019-06-11',
title: 'Data Publication',
+ type: {
+ id: 13,
+ name: 'study',
+ },
},
],
},
@@ -113,7 +124,14 @@ describe('ISIS Investigations table component', () => {
endDate: '2019-06-11',
},
];
- history = createMemoryHistory();
+ history = createMemoryHistory({
+ initialEntries: [
+ generatePath(paths.toggle.isisInvestigation, {
+ instrumentId: '4',
+ facilityCycleId: '5',
+ }),
+ ],
+ });
replaceSpy = jest.spyOn(history, 'replace');
user = userEvent.setup();
@@ -477,17 +495,6 @@ describe('ISIS Investigations table component', () => {
).toHaveAttribute('href', 'https://doi.org/Data Publication Pid');
});
- it('renders title and DOI as links in Data Publication Hierarchy', async () => {
- renderComponent(true);
- expect(await screen.findByRole('link', { name: 'Test 1' })).toHaveAttribute(
- 'href',
- '/browseDataPublications/instrument/4/dataPublication/5/investigation/1'
- );
- expect(
- await screen.findByRole('link', { name: 'Data Publication Pid' })
- ).toHaveAttribute('href', 'https://doi.org/Data Publication Pid');
- });
-
it('displays the correct user as the PI ', async () => {
renderComponent();
@@ -518,7 +525,7 @@ describe('ISIS Investigations table component', () => {
});
});
- it('gracefully handles missing Study from Study Investigation object and missing User from investigationUsers object', async () => {
+ it('gracefully handles missing data collection from data collection Investigations object and missing User from investigationUsers object', async () => {
rowData = [
{
...rowData[0],
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 53688f5b5..327f46472 100644
--- a/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx
+++ b/packages/datagateway-dataview/src/views/table/isis/isisInvestigationsTable.component.tsx
@@ -38,14 +38,13 @@ import { StateType } from '../../../state/app.types';
interface ISISInvestigationsTableProps {
instrumentId: string;
- instrumentChildId: string;
- dataPublication: boolean;
+ facilityCycleId: string;
}
const ISISInvestigationsTable = (
props: ISISInvestigationsTableProps
): React.ReactElement => {
- const { instrumentId, instrumentChildId, dataPublication } = props;
+ const { instrumentId, facilityCycleId } = props;
const selectAllSetting = useSelector(
(state: StateType) => state.dgdataview.selectAllSetting
);
@@ -70,10 +69,8 @@ const ISISInvestigationsTable = (
{
filterType: 'where',
filterValue: JSON.stringify({
- [dataPublication
- ? 'dataCollectionInvestigations.dataCollection.dataPublications.id'
- : 'investigationFacilityCycles.facilityCycle.id']: {
- eq: parseInt(instrumentChildId),
+ 'investigationFacilityCycles.facilityCycle.id': {
+ eq: parseInt(facilityCycleId),
},
}),
},
@@ -101,7 +98,7 @@ const ISISInvestigationsTable = (
},
{
dataCollectionInvestigations: {
- dataCollection: 'dataPublications',
+ dataCollection: { dataPublications: 'type' },
},
},
{
@@ -161,19 +158,17 @@ const ISISInvestigationsTable = (
[fetchNextPage]
);
- const pathRoot = dataPublication ? 'browseDataPublications' : 'browse';
- const instrumentChild = dataPublication ? 'dataPublication' : 'facilityCycle';
- const urlPrefix = `/${pathRoot}/instrument/${instrumentId}/${instrumentChild}/${instrumentChildId}/investigation`;
-
const detailsPanel = React.useCallback(
({ rowData, detailsPanelResize }) => (
push(`${urlPrefix}/${id}/dataset`)}
+ viewDatasets={(id: number) =>
+ push(`${location.pathname}/${id}/dataset`)
+ }
/>
),
- [push, urlPrefix]
+ [push, location.pathname]
);
const columns: ColumnType[] = React.useMemo(
@@ -185,7 +180,7 @@ const ISISInvestigationsTable = (
cellContentRenderer: (cellProps: TableCellProps) => {
const investigationData = cellProps.rowData as Investigation;
return tableLink(
- `${urlPrefix}/${investigationData.id}`,
+ `${location.pathname}/${investigationData.id}`,
investigationData.title,
view,
'isis-investigations-table-title'
@@ -204,19 +199,18 @@ const ISISInvestigationsTable = (
label: t('investigations.doi'),
dataKey:
'dataCollectionInvestigations.dataCollection.dataPublications.pid',
- // TODO: this was previously the Study DOI - currently there are no datapublication
- // representations of Studies, only of Investigations themselves
- // should this be showing the study DOI or the investigation DOI anyway?
cellContentRenderer: (cellProps: TableCellProps) => {
const investigationData = cellProps.rowData as Investigation;
- if (
- investigationData?.dataCollectionInvestigations?.[0]?.dataCollection
- ?.dataPublications?.[0]
- ) {
+ const studyDataPublication =
+ investigationData.dataCollectionInvestigations?.filter(
+ (dci) =>
+ dci.dataCollection?.dataPublications?.[0]?.type?.name ===
+ 'study'
+ )?.[0]?.dataCollection?.dataPublications?.[0];
+ if (studyDataPublication) {
return externalSiteLink(
- `https://doi.org/${investigationData.dataCollectionInvestigations?.[0]?.dataCollection?.dataPublications?.[0].pid}`,
- investigationData.dataCollectionInvestigations?.[0]
- ?.dataCollection?.dataPublications?.[0].pid,
+ `https://doi.org/${studyDataPublication.pid}`,
+ studyDataPublication.pid,
'isis-investigations-table-doi-link'
);
} else {
@@ -267,7 +261,14 @@ const ISISInvestigationsTable = (
filterComponent: dateFilter,
},
],
- [t, textFilter, principalExperimenterFilter, dateFilter, urlPrefix, view]
+ [
+ t,
+ textFilter,
+ principalExperimenterFilter,
+ dateFilter,
+ location.pathname,
+ view,
+ ]
);
return (