From a9bc74d071aa7e6f72151bdbf5a08aecc103fa77 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Tue, 31 Dec 2024 14:32:47 +0100
Subject: [PATCH 1/2] use new publication endpoint

---
 .../PublicationsModal/PublicationsModal.tsx   |  12 +-
 ...PublicationsModalLayout.component.test.tsx |  20 +-
 .../utils/getBasePublications.test.ts         |  16 +-
 .../utils/getBasePublications.ts              |  16 +-
 .../utils/getStandarizedPublications.ts       |   8 +-
 .../mapBasePublicationToStandarized.test.ts   |  14 +-
 .../utils/mapBasePublicationToStandarized.ts  |   7 +-
 .../utils/useDownloadPublicationsAsCSVFile.ts |   4 +-
 .../FilterBySubmapHeader.test.tsx             |   4 +-
 src/models/mocks/publicationsResponseMock.ts  | 351 +++++++++---------
 src/models/pageableSchema.ts                  |   2 +-
 src/models/publicationsResponseSchema.ts      |  10 -
 src/models/publicationsSchema.ts              |   8 +-
 .../publications/publications.selectors.ts    |  11 +-
 src/redux/publications/publications.thunks.ts |  18 +-
 src/redux/publications/publications.types.ts  |   4 +-
 src/types/models.ts                           |   6 +-
 17 files changed, 248 insertions(+), 263 deletions(-)
 delete mode 100644 src/models/publicationsResponseSchema.ts

diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.tsx
index 69cbc09b..e37d378e 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.tsx
@@ -19,13 +19,13 @@ export const PublicationsModal = (): JSX.Element => {
 
   const parsedData: PublicationsTableData[] | undefined = useMemo(() => {
     const dd = data?.map(item => ({
-      pubmedId: item.publication.article.pubmedId,
-      title: item.publication.article.title,
-      authors: item.publication.article.authors,
-      journal: item.publication.article.journal,
-      year: item.publication.article.year,
+      pubmedId: item.article.pubmedId,
+      title: item.article.title,
+      authors: item.article.authors,
+      journal: item.article.journal,
+      year: item.article.year,
       elementsOnMap: JSON.stringify(item.elements) || EMPTY_ARRAY_STRING, // table data accepts only string | string[]
-      submaps: mapsNames[item.elements[FIRST_ARRAY_ELEMENT].modelId],
+      submaps: mapsNames[item.elements[FIRST_ARRAY_ELEMENT].model],
     }));
     return dd || [];
   }, [data, mapsNames]);
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.component.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.component.test.tsx
index aa7755b5..95bf0cd7 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.component.test.tsx
@@ -8,7 +8,7 @@ import { apiPath } from '@/redux/apiPath';
 import { downloadFileFromBlob } from '@/redux/export/export.utils';
 import { StoreType } from '@/redux/store';
 import { BioEntityContent, Publication } from '@/types/models';
-import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
 import {
   InitialStoreState,
   getReduxWrapperWithStore,
@@ -28,7 +28,7 @@ const THIRD_ELEMENT_ID = 300;
 const FOURTH_ELEMENT_ID = 400;
 
 const BASE_PUBLICATION: Publication =
-  PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.data[FIRST_ARRAY_ELEMENT];
+  PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.content[FIRST_ARRAY_ELEMENT];
 const BASE_ELEMENT = BASE_PUBLICATION.elements[FIRST_ARRAY_ELEMENT];
 const PUBLICATION: Publication = {
   ...BASE_PUBLICATION,
@@ -36,22 +36,22 @@ const PUBLICATION: Publication = {
     {
       ...BASE_ELEMENT,
       id: FIRST_ELEMENT_ID,
-      modelId: FIRST_MODEL_ID,
+      model: FIRST_MODEL_ID,
     },
     {
       ...BASE_ELEMENT,
       id: SECOND_ELEMENT_ID,
-      modelId: SECOND_MODEL_ID,
+      model: SECOND_MODEL_ID,
     },
     {
       ...BASE_ELEMENT,
       id: THIRD_ELEMENT_ID,
-      modelId: THIRD_MODEL_ID, // model id duplicate
+      model: THIRD_MODEL_ID, // model id duplicate
     },
     {
       ...BASE_ELEMENT,
       id: FOURTH_ELEMENT_ID,
-      modelId: THIRD_MODEL_ID, // model id duplicate
+      model: THIRD_MODEL_ID, // model id duplicate
     },
   ],
 };
@@ -77,7 +77,7 @@ jest.mock('../utils/fetchElementData');
     })[id] as BioEntityContent,
 );
 
-const mockedAxiosClient = mockNetworkResponse();
+const mockedAxiosNewClient = mockNetworkNewAPIResponse();
 
 const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
@@ -96,11 +96,11 @@ const renderComponent = (initialStore?: InitialStoreState): { store: StoreType }
 
 describe('PublicationsModalLayout - component', () => {
   const length = 1;
-  mockedAxiosClient
+  mockedAxiosNewClient
     .onGet(apiPath.getPublications({ params: { length } }))
     .reply(HttpStatusCode.Ok, {
       ...PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK,
-      data: [PUBLICATION],
+      content: [PUBLICATION],
     });
 
   it('should render download csv button', () => {
@@ -114,7 +114,7 @@ describe('PublicationsModalLayout - component', () => {
       publications: {
         data: {
           ...PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK,
-          data: [PUBLICATION],
+          content: [PUBLICATION],
           filteredSize: length,
         },
         loading: 'succeeded',
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
index ffa8191a..ca246ead 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.test.ts
@@ -1,11 +1,11 @@
 import { apiPath } from '@/redux/apiPath';
-import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
 import { HttpStatusCode } from 'axios';
 import { showToast } from '@/utils/showToast';
 import { PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK } from '../../../../../../models/mocks/publicationsResponseMock';
 import { getBasePublications } from './getBasePublications';
 
-const mockedAxiosClient = mockNetworkResponse();
+const mockedAxiosNewClient = mockNetworkNewAPIResponse();
 
 jest.mock('./../../../../../../utils/showToast');
 
@@ -13,17 +13,19 @@ describe('getBasePublications - util', () => {
   const length = 10;
 
   it('should return valid data if provided', async () => {
-    mockedAxiosClient
+    mockedAxiosNewClient
       .onGet(apiPath.getPublications({ params: { length } }))
-      .reply(HttpStatusCode.Ok, PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK);
+      .reply(HttpStatusCode.Ok, JSON.stringify(PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK));
 
     const result = await getBasePublications({ length });
 
-    expect(result).toStrictEqual(PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.data);
+    expect(result).toStrictEqual(
+      JSON.parse(JSON.stringify(PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.content)),
+    );
   });
 
   it('should return empty array if data structure is invalid', async () => {
-    mockedAxiosClient
+    mockedAxiosNewClient
       .onGet(apiPath.getPublications({ params: { length } }))
       .reply(HttpStatusCode.Ok, { randomObject: true });
 
@@ -33,7 +35,7 @@ describe('getBasePublications - util', () => {
   });
 
   it('should return empty array and show toast error if http error', async () => {
-    mockedAxiosClient
+    mockedAxiosNewClient
       .onGet(apiPath.getPublications({ params: { length } }))
       .reply(HttpStatusCode.BadRequest);
 
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
index d149d031..e58c2f9f 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getBasePublications.ts
@@ -1,11 +1,12 @@
-import { publicationsResponseSchema } from '@/models/publicationsResponseSchema';
 import { apiPath } from '@/redux/apiPath';
 import { PUBLICATIONS_FETCHING_ERROR_PREFIX } from '@/redux/publications/publications.constatns';
-import { axiosInstance } from '@/services/api/utils/axiosInstance';
-import { Publication, PublicationsResponse } from '@/types/models';
+import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance';
+import { FilteredPageOf, Publication } from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { getErrorMessage } from '@/utils/getErrorMessage';
 import { showToast } from '@/utils/showToast';
+import { pageableSchema } from '@/models/pageableSchema';
+import { publicationSchema } from '@/models/publicationsSchema';
 
 interface Args {
   length: number;
@@ -13,13 +14,16 @@ interface Args {
 
 export const getBasePublications = async ({ length }: Args): Promise<Publication[]> => {
   try {
-    const response = await axiosInstance.get<PublicationsResponse>(
+    const response = await axiosInstanceNewAPI.get<FilteredPageOf<Publication>>(
       apiPath.getPublications({ params: { length } }),
     );
 
-    const isDataValid = validateDataUsingZodSchema(response.data, publicationsResponseSchema);
+    const isDataValid = validateDataUsingZodSchema(
+      response.data,
+      pageableSchema(publicationSchema),
+    );
 
-    return isDataValid ? response.data.data : [];
+    return isDataValid ? response.data.content : [];
   } catch (error) {
     const errorMessage = getErrorMessage({ error, prefix: PUBLICATIONS_FETCHING_ERROR_PREFIX });
     showToast({
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getStandarizedPublications.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getStandarizedPublications.ts
index c59d2e00..894f194b 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getStandarizedPublications.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/getStandarizedPublications.ts
@@ -14,17 +14,17 @@ export const getStandarizedPublications = async ({
   publications,
   modelNameIdMap,
 }: Args): Promise<StandarizedPublication[]> => {
-  const getStandarizedPublicationsFuncs = publications.map(
+  const getStandardizedPublicationsFuncs = publications.map(
     publication => () =>
       mapBasePublicationToStandarized(publication, {
         modelNameIdMap,
       }),
   );
 
-  const standarizedPublications = await runInSequence<StandarizedPublication>(
-    getStandarizedPublicationsFuncs,
+  const standardizedPublications = await runInSequence<StandarizedPublication>(
+    getStandardizedPublicationsFuncs,
     SEQUENCE_CHUNK_SIZE,
   );
 
-  return standarizedPublications;
+  return standardizedPublications;
 };
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.test.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.test.ts
index 3a556eff..05cbe84f 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.test.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.test.ts
@@ -23,7 +23,7 @@ const MODEL_NAME_ID_MAP: Record<number, string> = {
 };
 
 const BASE_PUBLICATION: Publication =
-  PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.data[FIRST_ARRAY_ELEMENT];
+  PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK.content[FIRST_ARRAY_ELEMENT];
 const BASE_ELEMENT = BASE_PUBLICATION.elements[FIRST_ARRAY_ELEMENT];
 const PUBLICATION: Publication = {
   ...BASE_PUBLICATION,
@@ -31,22 +31,22 @@ const PUBLICATION: Publication = {
     {
       ...BASE_ELEMENT,
       id: FIRST_ELEMENT_ID,
-      modelId: FIRST_MODEL_ID,
+      model: FIRST_MODEL_ID,
     },
     {
       ...BASE_ELEMENT,
       id: SECOND_ELEMENT_ID,
-      modelId: SECOND_MODEL_ID,
+      model: SECOND_MODEL_ID,
     },
     {
       ...BASE_ELEMENT,
       id: THIRD_ELEMENT_ID,
-      modelId: THIRD_MODEL_ID, // model id duplicate
+      model: THIRD_MODEL_ID, // model id duplicate
     },
     {
       ...BASE_ELEMENT,
       id: FOURTH_ELEMENT_ID,
-      modelId: THIRD_MODEL_ID, // model id duplicate
+      model: THIRD_MODEL_ID, // model id duplicate
     },
   ],
 };
@@ -80,7 +80,7 @@ const getFuncResult = async (
 describe('mapBasePublicationToStandarized - util', () => {
   it('should return valid pubmedId, journal, year and title', async () => {
     const results = await getFuncResult(PUBLICATION);
-    const { pubmedId, journal, year, title } = PUBLICATION.publication.article;
+    const { pubmedId, journal, year, title } = PUBLICATION.article;
 
     expect(results.pubmedId).toBe(pubmedId);
     expect(results.journal).toBe(journal);
@@ -90,7 +90,7 @@ describe('mapBasePublicationToStandarized - util', () => {
 
   it('should return joined authors', async () => {
     const results = await getFuncResult(PUBLICATION);
-    const { authors } = PUBLICATION.publication.article;
+    const { authors } = PUBLICATION.article;
 
     expect(results.authors).toBe(authors.join(','));
   });
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.ts
index 84b7d269..dea109c1 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/mapBasePublicationToStandarized.ts
@@ -13,13 +13,10 @@ export const mapBasePublicationToStandarized = async (
   publication: Publication,
   options: Options,
 ): Promise<StandarizedPublication> => {
-  const {
-    publication: { article },
-    elements,
-  } = publication;
+  const { article, elements } = publication;
   const { modelNameIdMap } = options;
   const { title, authors, journal, year, pubmedId } = article;
-  const modelNames = elements.map(({ modelId }) => modelNameIdMap[modelId]);
+  const modelNames = elements.map(({ model }) => modelNameIdMap[model]);
   const elementsData = await Promise.all(elements.map(async ({ id }) => fetchElementData(`${id}`)));
   const elementsIds = elementsData
     .filter((element): element is BioEntityContent => element !== undefined)
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/useDownloadPublicationsAsCSVFile.ts b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/useDownloadPublicationsAsCSVFile.ts
index 531faf9c..cdd58d24 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/useDownloadPublicationsAsCSVFile.ts
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/utils/useDownloadPublicationsAsCSVFile.ts
@@ -41,12 +41,12 @@ export const useDownloadPublicationsAsCSVFile = (): UseDownloadPublicationsAsCSV
         ? searchedPublicationsList
         : await getAllBasePublications();
 
-    const standarizedPublications = await getStandarizedPublications({
+    const standardizedPublications = await getStandarizedPublications({
       publications,
       modelNameIdMap,
     });
 
-    return standarizedPublications;
+    return standardizedPublications;
   };
 
   const downloadPublicationsAsCSVFile = async (): Promise<void> => {
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/FilterBySubmapHeader/FilterBySubmapHeader.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/FilterBySubmapHeader/FilterBySubmapHeader.test.tsx
index f238cef3..237c4c98 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/FilterBySubmapHeader/FilterBySubmapHeader.test.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/FilterBySubmapHeader/FilterBySubmapHeader.test.tsx
@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
 import configureMockStore from 'redux-mock-store';
 import thunk from 'redux-thunk';
 import { act } from 'react-dom/test-utils';
-import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
 import {
   InitialStoreState,
   getReduxWrapperWithStore,
@@ -16,7 +16,7 @@ import { MODELS_MOCK } from '@/models/mocks/modelsMock';
 import { FIRST_ARRAY_ELEMENT, ZERO } from '@/constants/common';
 import { FilterBySubmapHeader } from './FilterBySubmapHeader.component';
 
-mockNetworkResponse();
+mockNetworkNewAPIResponse();
 
 const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
diff --git a/src/models/mocks/publicationsResponseMock.ts b/src/models/mocks/publicationsResponseMock.ts
index c165eb98..01240a65 100644
--- a/src/models/mocks/publicationsResponseMock.ts
+++ b/src/models/mocks/publicationsResponseMock.ts
@@ -1,283 +1,266 @@
-import { PublicationsResponse } from '@/types/models';
+import { FilteredPageOf, Publication } from '@/types/models';
+import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture';
 
-export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: PublicationsResponse = {
-  data: [
+export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publication> = {
+  content: [
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 19519,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
       ],
-      publication: {
-        article: {
-          title: 'The glutamate receptor ion channels.',
-          authors: ['Dingledine R', ' Borges K', ' Bowie D', ' Traynelis SF.'],
-          journal: 'Pharmacological reviews',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10049997',
-          pubmedId: '10049997',
-          citationCount: 2458,
-        },
+      article: {
+        title: 'The glutamate receptor ion channels.',
+        authors: ['Dingledine R', ' Borges K', ' Bowie D', ' Traynelis SF.'],
+        journal: 'Pharmacological reviews',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10049997',
+        pubmedId: '10049997',
+        citationCount: 2458,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 16167,
-          modelId: 61,
-          type: 'REACTION',
+          model: 61,
         },
       ],
-      publication: {
-        article: {
-          title: 'Regulation of JNK signaling by GSTp.',
-          authors: [
-            'Adler V',
-            ' Yin Z',
-            ' Fuchs SY',
-            ' Benezra M',
-            ' Rosario L',
-            ' Tew KD',
-            ' Pincus MR',
-            ' Sardana M',
-            ' Henderson CJ',
-            ' Wolf CR',
-            ' Davis RJ',
-            ' Ronai Z.',
-          ],
-          journal: 'The EMBO journal',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10064598',
-          pubmedId: '10064598',
-          citationCount: 656,
-        },
+      article: {
+        title: 'Regulation of JNK signaling by GSTp.',
+        authors: [
+          'Adler V',
+          ' Yin Z',
+          ' Fuchs SY',
+          ' Benezra M',
+          ' Rosario L',
+          ' Tew KD',
+          ' Pincus MR',
+          ' Sardana M',
+          ' Henderson CJ',
+          ' Wolf CR',
+          ' Davis RJ',
+          ' Ronai Z.',
+        ],
+        journal: 'The EMBO journal',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10064598',
+        pubmedId: '10064598',
+        citationCount: 656,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 17823,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
         {
+          ...bioEntityFixture,
           id: 19461,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
       ],
-      publication: {
-        article: {
-          title:
-            'Generic signals and specific outcomes: signaling through Ca2+, calcineurin, and NF-AT.',
-          authors: ['Crabtree GR.'],
-          journal: 'Cell',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10089876',
-          pubmedId: '10089876',
-          citationCount: 454,
-        },
+      article: {
+        title:
+          'Generic signals and specific outcomes: signaling through Ca2+, calcineurin, and NF-AT.',
+        authors: ['Crabtree GR.'],
+        journal: 'Cell',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10089876',
+        pubmedId: '10089876',
+        citationCount: 454,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 18189,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
         {
+          ...bioEntityFixture,
           id: 18729,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
       ],
-      publication: {
-        article: {
-          title: 'G protein regulation of adenylate cyclase.',
-          authors: ['Simonds WF.'],
-          journal: 'Trends in pharmacological sciences',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10101967',
-          pubmedId: '10101967',
-          citationCount: 139,
-        },
+      article: {
+        title: 'G protein regulation of adenylate cyclase.',
+        authors: ['Simonds WF.'],
+        journal: 'Trends in pharmacological sciences',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10101967',
+        pubmedId: '10101967',
+        citationCount: 139,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 16077,
-          modelId: 58,
-          type: 'REACTION',
+          model: 58,
         },
         {
+          ...bioEntityFixture,
           id: 16135,
-          modelId: 58,
-          type: 'REACTION',
+          model: 58,
         },
       ],
-      publication: {
-        article: {
-          title:
-            'Akt promotes cell survival by phosphorylating and inhibiting a Forkhead transcription factor.',
-          authors: [
-            'Brunet A',
-            ' Bonni A',
-            ' Zigmond MJ',
-            ' Lin MZ',
-            ' Juo P',
-            ' Hu LS',
-            ' Anderson MJ',
-            ' Arden KC',
-            ' Blenis J',
-            ' Greenberg ME.',
-          ],
-          journal: 'Cell',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10102273',
-          pubmedId: '10102273',
-          citationCount: 4019,
-        },
+      article: {
+        title:
+          'Akt promotes cell survival by phosphorylating and inhibiting a Forkhead transcription factor.',
+        authors: [
+          'Brunet A',
+          ' Bonni A',
+          ' Zigmond MJ',
+          ' Lin MZ',
+          ' Juo P',
+          ' Hu LS',
+          ' Anderson MJ',
+          ' Arden KC',
+          ' Blenis J',
+          ' Greenberg ME.',
+        ],
+        journal: 'Cell',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10102273',
+        pubmedId: '10102273',
+        citationCount: 4019,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 15955,
-          modelId: 55,
-          type: 'REACTION',
+          model: 55,
         },
       ],
-      publication: {
-        article: {
-          title: 'Ca2+-induced apoptosis through calcineurin dephosphorylation of BAD.',
-          authors: [
-            'Wang HG',
-            ' Pathan N',
-            ' Ethell IM',
-            ' Krajewski S',
-            ' Yamaguchi Y',
-            ' Shibasaki F',
-            ' McKeon F',
-            ' Bobo T',
-            ' Franke TF',
-            ' Reed JC.',
-          ],
-          journal: 'Science (New York, N.Y.)',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10195903',
-          pubmedId: '10195903',
-          citationCount: 708,
-        },
+      article: {
+        title: 'Ca2+-induced apoptosis through calcineurin dephosphorylation of BAD.',
+        authors: [
+          'Wang HG',
+          ' Pathan N',
+          ' Ethell IM',
+          ' Krajewski S',
+          ' Yamaguchi Y',
+          ' Shibasaki F',
+          ' McKeon F',
+          ' Bobo T',
+          ' Franke TF',
+          ' Reed JC.',
+        ],
+        journal: 'Science (New York, N.Y.)',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10195903',
+        pubmedId: '10195903',
+        citationCount: 708,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 15937,
-          modelId: 55,
-          type: 'REACTION',
+          model: 55,
         },
         {
+          ...bioEntityFixture,
           id: 15955,
-          modelId: 55,
-          type: 'REACTION',
+          model: 55,
         },
       ],
-      publication: {
-        article: {
-          title:
-            'The proapoptotic activity of the Bcl-2 family member Bim is regulated by interaction with the dynein motor complex.',
-          authors: ['Puthalakath H', ' Huang DC', " O'Reilly LA", ' King SM', ' Strasser A.'],
-          journal: 'Molecular cell',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10198631',
-          pubmedId: '10198631',
-          citationCount: 662,
-        },
+      article: {
+        title:
+          'The proapoptotic activity of the Bcl-2 family member Bim is regulated by interaction with the dynein motor complex.',
+        authors: ['Puthalakath H', ' Huang DC', " O'Reilly LA", ' King SM', ' Strasser A.'],
+        journal: 'Molecular cell',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10198631',
+        pubmedId: '10198631',
+        citationCount: 662,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 15948,
-          modelId: 55,
-          type: 'REACTION',
+          model: 55,
         },
       ],
-      publication: {
-        article: {
-          title:
-            'An APAF-1.cytochrome c multimeric complex is a functional apoptosome that activates procaspase-9.',
-          authors: ['Zou H', ' Li Y', ' Liu X', ' Wang X.'],
-          journal: 'The Journal of biological chemistry',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10206961',
-          pubmedId: '10206961',
-          citationCount: 1162,
-        },
+      article: {
+        title:
+          'An APAF-1.cytochrome c multimeric complex is a functional apoptosome that activates procaspase-9.',
+        authors: ['Zou H', ' Li Y', ' Liu X', ' Wang X.'],
+        journal: 'The Journal of biological chemistry',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10206961',
+        pubmedId: '10206961',
+        citationCount: 1162,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 16286,
-          modelId: 62,
-          type: 'REACTION',
+          model: 62,
         },
       ],
-      publication: {
-        article: {
-          title:
-            'Biochemical characterization and crystal structure determination of human heart short chain L-3-hydroxyacyl-CoA dehydrogenase provide insights into catalytic mechanism.',
-          authors: [
-            'Barycki JJ',
-            " O'Brien LK",
-            ' Bratt JM',
-            ' Zhang R',
-            ' Sanishvili R',
-            ' Strauss AW',
-            ' Banaszak LJ.',
-          ],
-          journal: 'Biochemistry',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10231530',
-          pubmedId: '10231530',
-          citationCount: 56,
-        },
+      article: {
+        title:
+          'Biochemical characterization and crystal structure determination of human heart short chain L-3-hydroxyacyl-CoA dehydrogenase provide insights into catalytic mechanism.',
+        authors: [
+          'Barycki JJ',
+          " O'Brien LK",
+          ' Bratt JM',
+          ' Zhang R',
+          ' Sanishvili R',
+          ' Strauss AW',
+          ' Banaszak LJ.',
+        ],
+        journal: 'Biochemistry',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10231530',
+        pubmedId: '10231530',
+        citationCount: 56,
       },
     },
     {
       elements: [
         {
+          ...bioEntityFixture,
           id: 17780,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
         {
+          ...bioEntityFixture,
           id: 17937,
-          modelId: 52,
-          type: 'REACTION',
+          model: 52,
         },
       ],
-      publication: {
-        article: {
-          title: 'The Ca-calmodulin-dependent protein kinase cascade.',
-          authors: ['Soderling TR.'],
-          journal: 'Trends in biochemical sciences',
-          year: 1999,
-          link: 'https://www.ncbi.nlm.nih.gov/pubmed/10366852',
-          pubmedId: '10366852',
-          citationCount: 322,
-        },
+      article: {
+        title: 'The Ca-calmodulin-dependent protein kinase cascade.',
+        authors: ['Soderling TR.'],
+        journal: 'Trends in biochemical sciences',
+        year: 1999,
+        link: 'https://www.ncbi.nlm.nih.gov/pubmed/10366852',
+        pubmedId: '10366852',
+        citationCount: 322,
       },
     },
   ],
-  totalSize: 159,
+  totalElements: 159,
   filteredSize: 1586,
-  length: 10,
-  page: 0,
+  size: 10,
+  number: 0,
+  numberOfElements: 10,
+  totalPages: 16,
 };
diff --git a/src/models/pageableSchema.ts b/src/models/pageableSchema.ts
index 9ec3a540..4e772ffc 100644
--- a/src/models/pageableSchema.ts
+++ b/src/models/pageableSchema.ts
@@ -7,7 +7,7 @@ export const pageableSchema = <T extends ZodTypeAny>(type: T) =>
     totalPages: z.number().nonnegative(),
     totalElements: z.number().nonnegative(),
     numberOfElements: z.number().nonnegative(),
-    size: z.number().positive(),
+    size: z.number().nonnegative(),
     number: z.number().nonnegative(),
     content: z.array(type),
   });
diff --git a/src/models/publicationsResponseSchema.ts b/src/models/publicationsResponseSchema.ts
deleted file mode 100644
index 5bdcca5b..00000000
--- a/src/models/publicationsResponseSchema.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { z } from 'zod';
-import { publicationSchema } from './publicationsSchema';
-
-export const publicationsResponseSchema = z.object({
-  data: z.array(publicationSchema),
-  totalSize: z.number(),
-  filteredSize: z.number(),
-  length: z.number(),
-  page: z.number(),
-});
diff --git a/src/models/publicationsSchema.ts b/src/models/publicationsSchema.ts
index b1574088..14ac77ff 100644
--- a/src/models/publicationsSchema.ts
+++ b/src/models/publicationsSchema.ts
@@ -1,10 +1,8 @@
 import { z } from 'zod';
-import { targetElementSchema } from './targetElementSchema';
+import { bioEntitySchema } from '@/models/bioEntitySchema';
 import { articleSchema } from './articleSchema';
 
 export const publicationSchema = z.object({
-  elements: z.array(targetElementSchema),
-  publication: z.object({
-    article: articleSchema,
-  }),
+  elements: z.array(bioEntitySchema),
+  article: articleSchema,
 });
diff --git a/src/redux/publications/publications.selectors.ts b/src/redux/publications/publications.selectors.ts
index 8ed16fac..202156a9 100644
--- a/src/redux/publications/publications.selectors.ts
+++ b/src/redux/publications/publications.selectors.ts
@@ -11,20 +11,23 @@ export const publicationsDataSelector = createSelector(
 
 export const publicationsListDataSelector = createSelector(
   publicationsDataSelector,
-  data => data?.data,
+  data => data?.content,
 );
 
 /** totalSize is number of pages */
-export const totalSizeSelector = createSelector(publicationsDataSelector, data => data?.totalSize);
+export const totalSizeSelector = createSelector(
+  publicationsDataSelector,
+  data => data?.totalElements,
+);
 
 export const filteredSizeSelector = createSelector(
   publicationsDataSelector,
   data => data?.filteredSize,
 );
 
-export const currentPageSelector = createSelector(publicationsDataSelector, data => data?.page);
+export const currentPageSelector = createSelector(publicationsDataSelector, data => data?.number);
 export const paginationSelector = createSelector(publicationsDataSelector, data => ({
-  pageIndex: data?.page || ZERO,
+  pageIndex: data?.number || ZERO,
   pageSize: 10,
 }));
 
diff --git a/src/redux/publications/publications.thunks.ts b/src/redux/publications/publications.thunks.ts
index 4c03def9..c173c620 100644
--- a/src/redux/publications/publications.thunks.ts
+++ b/src/redux/publications/publications.thunks.ts
@@ -1,23 +1,29 @@
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
-import { axiosInstance } from '@/services/api/utils/axiosInstance';
-import { PublicationsResponse } from '@/types/models';
-import { publicationsResponseSchema } from '@/models/publicationsResponseSchema';
+import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance';
 import { ThunkConfig } from '@/types/store';
 import { getError } from '@/utils/error-report/getError';
+import { FilteredPageOf, Publication } from '@/types/models';
+import { pageableSchema } from '@/models/pageableSchema';
+import { publicationSchema } from '@/models/publicationsSchema';
 import { GetPublicationsParams } from './publications.types';
 import { apiPath } from '../apiPath';
 import { PUBLICATIONS_FETCHING_ERROR_PREFIX } from './publications.constatns';
 
 export const getPublications = createAsyncThunk<
-  PublicationsResponse | undefined,
+  FilteredPageOf<Publication> | undefined,
   GetPublicationsParams,
   ThunkConfig
 >('publications/getPublications', async params => {
   try {
-    const response = await axiosInstance.get<PublicationsResponse>(apiPath.getPublications(params));
+    const response = await axiosInstanceNewAPI.get<FilteredPageOf<Publication>>(
+      apiPath.getPublications(params),
+    );
 
-    const isDataValid = validateDataUsingZodSchema(response.data, publicationsResponseSchema);
+    const isDataValid = validateDataUsingZodSchema(
+      response.data,
+      pageableSchema(publicationSchema),
+    );
 
     return isDataValid ? response.data : undefined;
   } catch (error) {
diff --git a/src/redux/publications/publications.types.ts b/src/redux/publications/publications.types.ts
index 2654b800..792e7544 100644
--- a/src/redux/publications/publications.types.ts
+++ b/src/redux/publications/publications.types.ts
@@ -1,10 +1,10 @@
 import { FetchDataState } from '@/types/fetchDataState';
-import { PublicationsResponse } from '@/types/models';
+import { FilteredPageOf, Publication } from '@/types/models';
 
 export type SortColumn = '' | 'pubmedId' | 'title' | 'authors' | 'journal' | 'year' | 'level';
 export type SortOrder = 'asc' | 'desc';
 
-export type PublicationsState = FetchDataState<PublicationsResponse> & {
+export type PublicationsState = FetchDataState<FilteredPageOf<Publication>> & {
   sortColumn: SortColumn;
   sortOrder: SortOrder;
   selectedModelId?: string;
diff --git a/src/types/models.ts b/src/types/models.ts
index af20167b..b01270f9 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -49,7 +49,6 @@ import {
 import { overviewImageView } from '@/models/overviewImageView';
 import { pluginSchema } from '@/models/pluginSchema';
 import { projectSchema } from '@/models/projectSchema';
-import { publicationsResponseSchema } from '@/models/publicationsResponseSchema';
 import { publicationSchema } from '@/models/publicationsSchema';
 import { referenceSchema } from '@/models/referenceSchema';
 import { sessionSchemaValid } from '@/models/sessionValidSchema';
@@ -150,7 +149,6 @@ export type Color = z.infer<typeof colorSchema>;
 export type Statistics = z.infer<typeof statisticsSchema>;
 export type CompartmentPathway = z.infer<typeof compartmentPathwaySchema>;
 export type CompartmentPathwayDetails = z.infer<typeof compartmentPathwayDetailsSchema>;
-export type PublicationsResponse = z.infer<typeof publicationsResponseSchema>;
 export type Publication = z.infer<typeof publicationSchema>;
 export type ExportNetwork = z.infer<typeof exportNetworkchema>;
 export type ExportElements = z.infer<typeof exportElementsSchema>;
@@ -180,4 +178,8 @@ export type PageOf<T> = {
   content: T[];
 };
 
+export type FilteredPageOf<T> = PageOf<T> & {
+  filteredSize: number;
+};
+
 export type OAuth = z.infer<typeof oauthSchema>;
-- 
GitLab


From 66ceeb98dd1cf29a51fe18d0cb123874703fd7d7 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Thu, 2 Jan 2025 10:12:46 +0100
Subject: [PATCH 2/2] use new api for fetching publication list

---
 .../ElementLink.component.test.tsx            | 96 +++++++++----------
 .../ElementLink/ElementLink.component.tsx     | 57 ++++-------
 .../ElementsOnMapCell.component.test.tsx      | 72 +++-----------
 .../ElementsOnMapCell.component.tsx           |  4 +-
 .../PublicationsTable.component.tsx           | 11 ++-
 .../mapSingleClick/handleAliasResults.test.ts |  3 +-
 src/redux/apiPath.ts                          |  2 +-
 .../publications/publications.selectors.ts    |  3 +
 src/redux/reactions/isReactionBioentity.ts    |  5 +
 9 files changed, 98 insertions(+), 155 deletions(-)
 create mode 100644 src/redux/reactions/isReactionBioentity.ts

diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx
index 97d2050f..cdd2e42f 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx
@@ -5,7 +5,7 @@ import { apiPath } from '@/redux/apiPath';
 import { DEFAULT_POSITION } from '@/redux/map/map.constants';
 import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
 import { AppDispatch, RootState } from '@/redux/store';
-import { TargetElement } from '@/types/models';
+import { BioEntity, MapModel } from '@/types/models';
 import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
 import {
   InitialStoreState,
@@ -15,20 +15,44 @@ import { render, screen, waitFor } from '@testing-library/react';
 import { HttpStatusCode } from 'axios';
 import { MockStoreEnhanced } from 'redux-mock-store';
 import MapBackgroundsEnum from '@/redux/map/map.enums';
+import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity';
 import { ElementLink } from './ElementLink.component';
 
 const mockedAxiosNewClient = mockNetworkNewAPIResponse();
 
-const TARGET_ELEMENT: TargetElement = {
+const TARGET_ELEMENT: BioEntity = {
+  ...bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity,
   id: 123,
-  modelId: 52,
-  type: 'REACTION',
+  model: 52,
+  idReaction: 're1234',
+};
+
+const MODEL: MapModel = {
+  ...modelsFixture[FIRST_ARRAY_ELEMENT],
+  id: TARGET_ELEMENT.model,
+};
+
+const OTHER_MODEL: MapModel = {
+  ...modelsFixture[FIRST_ARRAY_ELEMENT],
 };
 
 interface Props {
-  target: TargetElement;
+  target: BioEntity;
 }
 
+const getElementText = (bioEntity: BioEntity): string => {
+  const isReaction = isReactionBioEntity(bioEntity);
+  const prefix = isReaction ? 'Reaction: ' : 'Element: ';
+
+  return prefix + bioEntity.elementId;
+};
+
+const getSearchQuery = (bioEntity: BioEntity): string => {
+  const isReaction = isReactionBioEntity(bioEntity);
+
+  return (isReaction ? 'reaction:' : 'element:') + bioEntity.id;
+};
+
 const renderComponent = (
   props: Props,
   initialStoreState: InitialStoreState = {},
@@ -48,18 +72,6 @@ const renderComponent = (
 };
 
 describe('ElementLink - component', () => {
-  describe('when initialized', () => {
-    beforeEach(() => {
-      renderComponent({ target: TARGET_ELEMENT }, INITIAL_STORE_STATE_MOCK);
-    });
-
-    it('should show loading indicator', () => {
-      const loadingIndicator = screen.getByAltText('spinner icon');
-
-      expect(loadingIndicator).toBeInTheDocument();
-    });
-  });
-
   describe('when loaded', () => {
     mockedAxiosNewClient
       .onGet(
@@ -74,19 +86,11 @@ describe('ElementLink - component', () => {
       renderComponent({ target: TARGET_ELEMENT }, INITIAL_STORE_STATE_MOCK);
     });
 
-    it('should not show loading indicator', async () => {
-      const loadingIndicator = screen.getByAltText('spinner icon');
-
-      await waitFor(() => {
-        expect(loadingIndicator).not.toBeInTheDocument();
-      });
-    });
-
     it('should should show element id', async () => {
-      const { elementId } = bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity;
+      const bioEntity = TARGET_ELEMENT;
 
       await waitFor(() => {
-        expect(screen.getByText(elementId)).toBeInTheDocument();
+        expect(screen.getByText(getElementText(bioEntity))).toBeInTheDocument();
       });
     });
   });
@@ -108,20 +112,15 @@ describe('ElementLink - component', () => {
           ...INITIAL_STORE_STATE_MOCK,
           models: {
             ...INITIAL_STORE_STATE_MOCK.models,
-            data: [
-              {
-                ...modelsFixture[FIRST_ARRAY_ELEMENT],
-                id: TARGET_ELEMENT.modelId,
-              },
-            ],
+            data: [MODEL],
           },
         },
       );
 
-      const { elementId } = bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity;
+      const bioEntity = TARGET_ELEMENT;
 
       await waitFor(() => {
-        const link = screen.getByText(elementId);
+        const link = screen.getByText(getElementText(bioEntity));
         link.click();
 
         const actions = store.getActions();
@@ -150,7 +149,7 @@ describe('ElementLink - component', () => {
         expect(actions).toEqual(
           expect.arrayContaining([
             expect.objectContaining({
-              payload: elementId,
+              payload: getSearchQuery(bioEntity),
               type: 'drawer/openSearchDrawerWithSelectedTab',
             }),
           ]),
@@ -161,8 +160,8 @@ describe('ElementLink - component', () => {
           expect.arrayContaining([
             expect.objectContaining({
               payload: {
-                modelId: TARGET_ELEMENT.modelId,
-                modelName: modelsFixture[FIRST_ARRAY_ELEMENT].name,
+                modelId: TARGET_ELEMENT.model,
+                modelName: MODEL.name,
               },
               type: 'map/openMapAndSetActive',
             }),
@@ -189,23 +188,18 @@ describe('ElementLink - component', () => {
           ...INITIAL_STORE_STATE_MOCK,
           models: {
             ...INITIAL_STORE_STATE_MOCK.models,
-            data: [
-              {
-                ...modelsFixture[FIRST_ARRAY_ELEMENT],
-                id: TARGET_ELEMENT.modelId,
-              },
-            ],
+            data: [MODEL, OTHER_MODEL],
           },
           map: {
             ...INITIAL_STORE_STATE_MOCK.map,
             data: {
               ...INITIAL_STORE_STATE_MOCK.map.data,
-              modelId: modelsFixture[FIRST_ARRAY_ELEMENT].id,
+              modelId: OTHER_MODEL.id,
             },
             openedMaps: [
               {
-                modelId: TARGET_ELEMENT.modelId,
-                modelName: modelsFixture[FIRST_ARRAY_ELEMENT].name,
+                modelId: TARGET_ELEMENT.model,
+                modelName: MODEL.name,
                 lastPosition: DEFAULT_POSITION,
               },
             ],
@@ -214,10 +208,10 @@ describe('ElementLink - component', () => {
         },
       );
 
-      const { elementId } = bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity;
+      const bioEntity = TARGET_ELEMENT;
 
       await waitFor(() => {
-        const link = screen.getByText(elementId);
+        const link = screen.getByText(getElementText(bioEntity));
         link.click();
 
         const actions = store.getActions();
@@ -246,7 +240,7 @@ describe('ElementLink - component', () => {
         expect(actions).toEqual(
           expect.arrayContaining([
             expect.objectContaining({
-              payload: elementId,
+              payload: getSearchQuery(bioEntity),
               type: 'drawer/openSearchDrawerWithSelectedTab',
             }),
           ]),
@@ -257,7 +251,7 @@ describe('ElementLink - component', () => {
           expect.arrayContaining([
             expect.objectContaining({
               payload: {
-                modelId: TARGET_ELEMENT.modelId,
+                modelId: TARGET_ELEMENT.model,
               },
               type: 'map/setActiveMap',
             }),
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx
index a3f28f15..8bf24727 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx
@@ -13,55 +13,46 @@ import { closeModal } from '@/redux/modal/modal.slice';
 import { modelsNameMapSelector } from '@/redux/models/models.selectors';
 import { getSearchData } from '@/redux/search/search.thunks';
 import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
-import { LoadingIndicator } from '@/shared/LoadingIndicator';
-import { BioEntityContent, TargetElement } from '@/types/models';
-import { useEffect, useState } from 'react';
-import { fetchElementData } from '../../../utils/fetchElementData';
+import { BioEntity } from '@/types/models';
+import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity';
 
 interface Props {
-  target: TargetElement;
+  target: BioEntity;
 }
 
 export const ElementLink = ({ target }: Props): JSX.Element => {
   const dispatch = useAppDispatch();
   const openedMaps = useAppSelector(mapOpenedMapsSelector);
   const currentModelId = useAppSelector(mapModelIdSelector);
-  const [isLoading, setIsLoading] = useState<boolean>(true);
-  const [data, setData] = useState<BioEntityContent | undefined>(undefined);
-  const elementId = data?.bioEntity.elementId;
   const mapsNames = useAppSelector(modelsNameMapSelector);
 
+  const isReaction = isReactionBioEntity(target);
+
   const isMapAlreadyOpened = (modelId: number): boolean =>
     openedMaps.some(map => map.modelId === modelId);
 
-  const getElementLinkData = async (searchQuery: string): Promise<void> => {
-    const fetchedData = await fetchElementData(searchQuery).finally(() => setIsLoading(false));
-
-    if (fetchedData) {
-      setData(fetchedData);
-    }
-  };
-
   const searchForElementAndOpenDrawer = (): void => {
-    if (!elementId) return;
-
-    const searchValues = getSearchValuesArrayAndTrimToSeven(elementId);
-    dispatch(getSearchData({ searchQueries: searchValues, isPerfectMatch: false }));
+    let query = '';
+    if (isReaction) {
+      query = `reaction:${target.id}`;
+    } else {
+      query = `element:${target.id}`;
+    }
+    const searchValues = getSearchValuesArrayAndTrimToSeven(query);
+    dispatch(getSearchData({ searchQueries: searchValues, isPerfectMatch: true }));
     dispatch(openSearchDrawerWithSelectedTab(getDefaultSearchTab(searchValues)));
   };
 
   const openSubmap = (): void => {
-    if (isMapAlreadyOpened(target.modelId)) {
-      dispatch(setActiveMap({ modelId: target.modelId }));
+    if (isMapAlreadyOpened(target.model)) {
+      dispatch(setActiveMap({ modelId: target.model }));
     } else {
-      dispatch(
-        openMapAndSetActive({ modelId: target.modelId, modelName: mapsNames[target.modelId] }),
-      );
+      dispatch(openMapAndSetActive({ modelId: target.model, modelName: mapsNames[target.model] }));
     }
 
-    if (currentModelId !== target.modelId) {
+    if (currentModelId !== target.model) {
       PluginsEventBus.dispatchEvent('onSubmapClose', currentModelId);
-      PluginsEventBus.dispatchEvent('onSubmapOpen', target.modelId);
+      PluginsEventBus.dispatchEvent('onSubmapOpen', target.model);
     }
   };
 
@@ -71,21 +62,15 @@ export const ElementLink = ({ target }: Props): JSX.Element => {
     openSubmap();
   };
 
-  useEffect(() => {
-    getElementLinkData(`${target.id}`);
-  }, [target.id]);
-
-  if (isLoading || !elementId) {
-    return <LoadingIndicator />;
-  }
-
   return (
     <button
       type="button"
       className="inline-block cursor-pointer underline"
       onClick={handleElementLinkClick}
     >
-      {elementId}
+      {isReaction && 'Reaction: '}
+      {!isReaction && 'Element: '}
+      {target.elementId}
     </button>
   );
 };
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx
index 8c8c0fe7..2e7349c6 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx
@@ -1,21 +1,18 @@
-import { FIRST_ARRAY_ELEMENT, SECOND_ARRAY_ELEMENT, THIRD_ARRAY_ELEMENT } from '@/constants/common';
-import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture';
-import { apiPath } from '@/redux/apiPath';
 import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
 import { AppDispatch, RootState } from '@/redux/store';
-import { BioEntityContent, TargetElement } from '@/types/models';
-import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse';
+import { BioEntity } from '@/types/models';
 import {
   InitialStoreState,
   getReduxStoreWithActionsListener,
 } from '@/utils/testing/getReduxStoreActionsListener';
 import { render, screen, waitFor } from '@testing-library/react';
-import { HttpStatusCode } from 'axios';
 import { MockStoreEnhanced } from 'redux-mock-store';
+import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture';
+import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity';
 import { ElementsOnMapCell } from './ElementsOnMapCell.component';
 
 interface Props {
-  targets: TargetElement[];
+  targets: BioEntity[];
 }
 
 const renderComponent = (
@@ -36,62 +33,13 @@ const renderComponent = (
   );
 };
 
-const mockedAxiosNewClient = mockNetworkNewAPIResponse();
+const elementFixture = { ...bioEntityFixture, idReaction: undefined };
+const reactionFixture = { ...bioEntityFixture, idReaction: '123' };
 
-const mockTargets = [
-  { id: 1, modelId: 2, type: 'target-1' },
-  { id: 2, modelId: 3, type: 'target-2' },
-  { id: 3, modelId: 4, type: 'target-3' },
-];
-
-const getBioEntityContent = (elementId: string): BioEntityContent[] => [
-  {
-    ...bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT],
-    bioEntity: {
-      ...bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity,
-      elementId,
-    },
-  },
-];
+const mockTargets = [{ ...elementFixture }, { ...reactionFixture }];
 
 describe('ElementsOnMapCell - component', () => {
-  mockedAxiosNewClient
-    .onGet(
-      apiPath.getBioEntityContentsStringWithQuery({
-        searchQuery: mockTargets[FIRST_ARRAY_ELEMENT].id.toString(),
-        isPerfectMatch: true,
-      }),
-    )
-    .reply(HttpStatusCode.Ok, {
-      ...bioEntityResponseFixture,
-      content: getBioEntityContent(mockTargets[FIRST_ARRAY_ELEMENT].type),
-    });
-
-  mockedAxiosNewClient
-    .onGet(
-      apiPath.getBioEntityContentsStringWithQuery({
-        searchQuery: mockTargets[SECOND_ARRAY_ELEMENT].id.toString(),
-        isPerfectMatch: true,
-      }),
-    )
-    .reply(HttpStatusCode.Ok, {
-      ...bioEntityResponseFixture,
-      content: getBioEntityContent(mockTargets[SECOND_ARRAY_ELEMENT].type),
-    });
-
-  mockedAxiosNewClient
-    .onGet(
-      apiPath.getBioEntityContentsStringWithQuery({
-        searchQuery: mockTargets[THIRD_ARRAY_ELEMENT].id.toString(),
-        isPerfectMatch: true,
-      }),
-    )
-    .reply(HttpStatusCode.Ok, {
-      ...bioEntityResponseFixture,
-      content: getBioEntityContent(mockTargets[THIRD_ARRAY_ELEMENT].type),
-    });
-
-  test.each(mockTargets)('should render correctly', async ({ type }) => {
+  test.each(mockTargets)('should render correctly', async bioEntity => {
     renderComponent(
       {
         targets: mockTargets,
@@ -101,7 +49,9 @@ describe('ElementsOnMapCell - component', () => {
 
     await waitFor(() => {
       // type as elementId
-      expect(screen.getByText(type)).toBeInTheDocument();
+      const isReaction = isReactionBioEntity(bioEntity);
+      const prefix = isReaction ? 'Reaction: ' : 'Element: ';
+      expect(screen.getByText(prefix + bioEntity.elementId)).toBeInTheDocument();
     });
   });
 });
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx
index 36cffdd4..13c1269f 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx
@@ -1,9 +1,9 @@
 import { ONE } from '@/constants/common';
-import { TargetElement } from '@/types/models';
+import { BioEntity } from '@/types/models';
 import { ElementLink } from './ElementLink';
 
 interface Props {
-  targets: TargetElement[];
+  targets: BioEntity[];
 }
 
 export const ElementsOnMapCell = ({ targets }: Props): JSX.Element => {
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx
index 5e720570..cc0db919 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx
@@ -1,9 +1,9 @@
 import { ONE, ZERO } from '@/constants/common';
-import { targetElementSchema } from '@/models/targetElementSchema';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import {
   isLoadingSelector,
+  pageSizeSelector,
   paginationSelector,
   searchValueSelector,
   selectedModelIdSelector,
@@ -23,6 +23,7 @@ import {
 } from '@tanstack/react-table';
 import { useRef, useState } from 'react';
 import { z } from 'zod';
+import { bioEntitySchema } from '@/models/bioEntitySchema';
 import { ElementsOnMapCell } from './ElementsOnMapCell';
 import { FilterBySubmapHeader } from './FilterBySubmapHeader/FilterBySubmapHeader.component';
 import { DEFAULT_PAGE_SIZE } from './PublicationsTable.constants';
@@ -73,7 +74,9 @@ const columns = [
     cell: ({ getValue }): JSX.Element => {
       try {
         const valueObject: unknown = JSON.parse(getValue());
-        const targets = z.array(targetElementSchema).parse(valueObject);
+        // eslint-disable-next-line no-console
+        console.log(valueObject);
+        const targets = z.array(bioEntitySchema).parse(valueObject);
 
         return <ElementsOnMapCell targets={targets} />;
       } catch (error) {
@@ -95,7 +98,9 @@ type PublicationsTableProps = {
 
 export const PublicationsTable = ({ data }: PublicationsTableProps): JSX.Element => {
   const dispatch = useAppDispatch();
-  const pagesCount = useAppSelector(totalSizeSelector);
+  const totalSize = useAppSelector(totalSizeSelector);
+  const pageSize = useAppSelector(pageSizeSelector);
+  const pagesCount = totalSize && pageSize ? Math.ceil(totalSize / pageSize) : ONE;
   const isPublicationsLoading = useAppSelector(isLoadingSelector);
   const sortColumn = useAppSelector(sortColumnSelector);
   const sortOrder = useAppSelector(sortOrderSelector);
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts
index 20ef29c9..a1dacb26 100644
--- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.test.ts
@@ -10,6 +10,7 @@ import { waitFor } from '@testing-library/react';
 import { HttpStatusCode } from 'axios';
 import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture';
 import { ZOOM_RESCALING_FACTOR } from '@/constants/map';
+import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity';
 import { handleAliasResults } from './handleAliasResults';
 
 jest.mock('../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds');
@@ -32,7 +33,7 @@ describe('handleAliasResults - util', () => {
     jest.clearAllMocks();
 
     const bioEntityWithIdReaction = bioEntityResponseFixture.content
-      .filter(c => Boolean(c.bioEntity.idReaction))
+      .filter(c => isReactionBioEntity(c.bioEntity))
       ?.map(b => b.bioEntity || { id: ZERO });
 
     mockedAxiosOldClient
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 7fce4e2c..174debec 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -111,7 +111,7 @@ export const apiPath = {
   getMesh: (meshId: string): string => `mesh/${meshId}`,
   getTaxonomy: (taxonomyId: string): string => `taxonomy/${taxonomyId}`,
   getPublications: ({ params, modelId = '*' }: GetPublicationsParams): string =>
-    `/projects/${PROJECT_ID}/models/${modelId}/publications/?${getPublicationsURLSearchParams(
+    `/projects/${PROJECT_ID}/maps/${modelId}/publications/?${getPublicationsURLSearchParams(
       params,
     )}`,
   registerPluign: (): string => `plugins/`,
diff --git a/src/redux/publications/publications.selectors.ts b/src/redux/publications/publications.selectors.ts
index 202156a9..f9aa8291 100644
--- a/src/redux/publications/publications.selectors.ts
+++ b/src/redux/publications/publications.selectors.ts
@@ -20,6 +20,9 @@ export const totalSizeSelector = createSelector(
   data => data?.totalElements,
 );
 
+/** totalSize is number of pages */
+export const pageSizeSelector = createSelector(publicationsDataSelector, data => data?.size);
+
 export const filteredSizeSelector = createSelector(
   publicationsDataSelector,
   data => data?.filteredSize,
diff --git a/src/redux/reactions/isReactionBioentity.ts b/src/redux/reactions/isReactionBioentity.ts
new file mode 100644
index 00000000..e4e673a2
--- /dev/null
+++ b/src/redux/reactions/isReactionBioentity.ts
@@ -0,0 +1,5 @@
+import { BioEntity } from '@/types/models';
+
+export const isReactionBioEntity = (bioEntity: BioEntity): boolean => {
+  return bioEntity.idReaction !== undefined && bioEntity.idReaction !== null;
+};
-- 
GitLab