diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.test.tsx
index 4df51d1e1fd12dbfe315b8e639981c44d7ea554a..15f359d2ec7d78fe77b1cb949295f00e48ddac58 100644
--- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.test.tsx
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModal.test.tsx
@@ -1,3 +1,13 @@
+import { mockNetworkResponse } from '@/utils/mockNetworkResponse';
+
+mockNetworkResponse();
+
+/**
+ * Since data to table is passed down from Publications Modal component
+ * this test will be covered in the integration test for the Publications Table component
+ * and interactions beetween filtering, sorting, searching and pagination
+ */
+
 describe('Publications Modal - component', () => {
   it('should render number of publications', () => {});
   it('should render download csv button', () => {});
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..87c74c952d1b55098f4a69cf602717d00301573f
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsModalLayout/PublicationsModalLayout.test.tsx
@@ -0,0 +1,45 @@
+import {
+  InitialStoreState,
+  getReduxWrapperWithStore,
+} from '@/utils/testing/getReduxWrapperWithStore';
+import { StoreType } from '@/redux/store';
+import { render, screen } from '@testing-library/react';
+import { PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_STATE_MOCK } from '@/redux/publications/publications.mock';
+import { PublicationsModalLayout } from './PublicationsModalLayout.component';
+
+const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <PublicationsModalLayout>
+          <div>children</div>
+        </PublicationsModalLayout>
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('Publications Modal Layout - component', () => {
+  it('should render number of publications', () => {
+    renderComponent({ publications: PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_STATE_MOCK });
+
+    expect(screen.getByText('Publications (1586 results)')).toBeInTheDocument();
+  });
+  it.skip('should render download csv button', () => {});
+  it.skip('should trigger download on csv button click', () => {});
+  it('should render search input', () => {
+    renderComponent({ publications: PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_STATE_MOCK });
+
+    expect(screen.getByTestId('search-input')).toBeInTheDocument();
+  });
+  it('should render children', () => {
+    renderComponent({ publications: PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_STATE_MOCK });
+
+    expect(screen.getByText('children')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsSearch/PublicationsSearch.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsSearch/PublicationsSearch.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..00fc8e08ea0c632674984998cbac9b55801cf535
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsSearch/PublicationsSearch.test.tsx
@@ -0,0 +1,11 @@
+// remember to mock api call
+
+describe('PublicationsSearch', () => {
+  it('should render the input field', () => {});
+
+  it('should update the value when the input field changes', () => {});
+
+  it('should dispatch getPublications action when the input field changes', () => {});
+
+  it('should disable the input and button when isLoading is true', () => {});
+});
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx
index 6049a6e29f28c13c4d6f67e3995a86cacee3994e..c5e4e4029fa87e2bed4477c4666c8d41729959e6 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx
@@ -1,19 +1,24 @@
 /* eslint-disable no-magic-numbers */
+import { DEFAULT_MAX_ZOOM } from '@/constants/map';
 import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
-import { StoreType } from '@/redux/store';
-import { BioEntity } from '@/types/models';
+import { MAP_INITIAL_STATE } from '@/redux/map/map.constants';
+import { AppDispatch, RootState, StoreType } from '@/redux/store';
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
 import {
   InitialStoreState,
   getReduxWrapperWithStore,
 } from '@/utils/testing/getReduxWrapperWithStore';
 import { render, screen } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import { MockStoreEnhanced } from 'redux-mock-store';
 import { BioEntitiesPinsListItem } from './BioEntitiesPinsListItem.component';
+import { PinListBioEntity } from './BioEntitiesPinsListItem.types';
 
 const BIO_ENTITY = bioEntitiesContentFixture[0].bioEntity;
 
 const renderComponent = (
   name: string,
-  pin: BioEntity,
+  pin: PinListBioEntity,
   initialStoreState: InitialStoreState = {},
 ): { store: StoreType } => {
   const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState);
@@ -30,6 +35,25 @@ const renderComponent = (
   );
 };
 
+const renderComponentWithActionListener = (
+  name: string,
+  pin: PinListBioEntity,
+  initialStoreState: InitialStoreState = {},
+): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => {
+  const { Wrapper, store } = getReduxStoreWithActionsListener(initialStoreState);
+
+  return (
+    render(
+      <Wrapper>
+        <BioEntitiesPinsListItem name={name} pin={pin} />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
 describe('BioEntitiesPinsListItem - component ', () => {
   it('should display name of bio entity element', () => {
     renderComponent(BIO_ENTITY.name, BIO_ENTITY);
@@ -84,4 +108,162 @@ describe('BioEntitiesPinsListItem - component ', () => {
     expect(screen.getByText(secondPinReferenceType, { exact: false })).toBeInTheDocument();
     expect(screen.getByText(secondPinReferenceResource, { exact: false })).toBeInTheDocument();
   });
+  it('should center map to pin coordinates after click on pin icon', async () => {
+    const { store } = renderComponent(BIO_ENTITY.name, BIO_ENTITY, {
+      map: {
+        ...MAP_INITIAL_STATE,
+        data: {
+          ...MAP_INITIAL_STATE.data,
+          modelId: 5052,
+          size: {
+            width: 256,
+            height: 256,
+            tileSize: 256,
+            minZoom: 1,
+            maxZoom: 1,
+          },
+          position: {
+            initial: {
+              x: 0,
+              y: 0,
+              z: 2,
+            },
+            last: {
+              x: 1,
+              y: 1,
+              z: 3,
+            },
+          },
+        },
+      },
+    });
+    const button = screen.getByTestId('center-to-pin-button');
+    expect(button).toBeInTheDocument();
+
+    act(() => {
+      button.click();
+    });
+
+    expect(store.getState().map.data.position.last).toEqual({
+      x: BIO_ENTITY.x,
+      y: BIO_ENTITY.y,
+      z: DEFAULT_MAX_ZOOM,
+    });
+  });
+
+  it('should not center map to pin coordinates after click on pin icon if pin has no coords', async () => {
+    const { store } = renderComponent(
+      BIO_ENTITY.name,
+      {
+        ...BIO_ENTITY,
+        x: undefined,
+        y: undefined,
+      },
+      {
+        map: {
+          ...MAP_INITIAL_STATE,
+          data: {
+            ...MAP_INITIAL_STATE.data,
+            modelId: 5052,
+            size: {
+              width: 256,
+              height: 256,
+              tileSize: 256,
+              minZoom: 1,
+              maxZoom: 1,
+            },
+            position: {
+              initial: {
+                x: 0,
+                y: 0,
+                z: 2,
+              },
+              last: {
+                x: 1,
+                y: 1,
+                z: 3,
+              },
+            },
+          },
+        },
+      },
+    );
+    const button = screen.getByTestId('center-to-pin-button');
+    expect(button).toBeInTheDocument();
+
+    act(() => {
+      button.click();
+    });
+
+    expect(store.getState().map.data.position.last).toEqual({
+      x: 1,
+      y: 1,
+      z: 3,
+    });
+  });
+
+  it('should dispatch get search data and open drawer on fullName click', async () => {
+    const { store } = renderComponentWithActionListener(
+      BIO_ENTITY.name,
+      {
+        ...BIO_ENTITY,
+        x: undefined,
+        y: undefined,
+      },
+      {
+        map: {
+          ...MAP_INITIAL_STATE,
+          data: {
+            ...MAP_INITIAL_STATE.data,
+            modelId: 5052,
+            size: {
+              width: 256,
+              height: 256,
+              tileSize: 256,
+              minZoom: 1,
+              maxZoom: 1,
+            },
+            position: {
+              initial: {
+                x: 0,
+                y: 0,
+                z: 2,
+              },
+              last: {
+                x: 1,
+                y: 1,
+                z: 3,
+              },
+            },
+          },
+        },
+      },
+    );
+    const button = screen.getByText(BIO_ENTITY.name);
+    expect(button).toBeInTheDocument();
+
+    act(() => {
+      button.click();
+    });
+
+    const actions = store.getActions();
+
+    expect(actions).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          payload: undefined,
+          type: 'project/getSearchData/pending',
+        }),
+      ]),
+    );
+
+    expect(actions).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          payload: BIO_ENTITY.name,
+          type: 'drawer/openSearchDrawerWithSelectedTab',
+        }),
+      ]),
+    );
+  });
 });
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx
index 8dc3049031ee14f1962e99de8879daf1492950bc..ceff8eb02308d091e466e63055f2a09211bbd4a5 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx
@@ -1,7 +1,19 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
+import {
+  getDefaultSearchTab,
+  getSearchValuesArrayAndTrimToSeven,
+} from '@/components/FunctionalArea/TopBar/SearchBar/SearchBar.utils';
+import { DEFAULT_MAX_ZOOM } from '@/constants/map';
+import { openSearchDrawerWithSelectedTab } from '@/redux/drawer/drawer.slice';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { setMapPosition } from '@/redux/map/map.slice';
+import { getSearchData } from '@/redux/search/search.thunks';
 import { Icon } from '@/shared/Icon';
 import { twMerge } from 'tailwind-merge';
 import { getPinColor } from '../../../ResultsList/PinsList/PinsListItem/PinsListItem.component.utils';
 import { PinListBioEntity } from './BioEntitiesPinsListItem.types';
+import { isPinWithCoordinates } from './BioEntitiesPinsListItem.utils';
 
 interface BioEntitiesPinsListItemProps {
   name: string;
@@ -12,13 +24,48 @@ export const BioEntitiesPinsListItem = ({
   name,
   pin,
 }: BioEntitiesPinsListItemProps): JSX.Element => {
+  const dispatch = useAppDispatch();
+  const pinHasCoords = isPinWithCoordinates(pin);
+
+  const handleCenterMapToPin = (): void => {
+    if (!pinHasCoords) {
+      return;
+    }
+
+    dispatch(
+      setMapPosition({
+        x: pin.x,
+        y: pin.y,
+        z: DEFAULT_MAX_ZOOM,
+      }),
+    );
+  };
+
+  const handleSearchMapForPin = (): void => {
+    const searchValues = getSearchValuesArrayAndTrimToSeven(name);
+    dispatch(getSearchData({ searchQueries: searchValues, isPerfectMatch: true }));
+    dispatch(openSearchDrawerWithSelectedTab(getDefaultSearchTab(searchValues)));
+  };
+
   return (
     <div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
       <div className="flex w-full flex-row items-center gap-2">
-        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor('bioEntity'))} />
+        <button
+          type="button"
+          onClick={handleCenterMapToPin}
+          className={twMerge('mr-2 shrink-0', !pinHasCoords && 'cursor-default')}
+          data-testid="center-to-pin-button"
+        >
+          <Icon name="pin" className={getPinColor('bioEntity')} />
+        </button>
         <p>
           {pin.stringType ? `${pin.stringType}: ` : ''}
-          <span className="w-full font-bold">{name}</span>
+          <span
+            className="w-full cursor-pointer font-bold underline"
+            onClick={handleSearchMapForPin}
+          >
+            {name}
+          </span>
         </p>
       </div>
       {pin.fullName && (
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts
index 03cfcae8114c6447b5a64bab66521d72f10c7a71..e1e6cce5b1aa6d7af4cf29fde5c4626ebe230335 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts
@@ -4,4 +4,11 @@ export type PinListBioEntity = Pick<BioEntity, 'synonyms' | 'references'> & {
   symbol?: BioEntity['symbol'];
   stringType?: BioEntity['stringType'];
   fullName?: BioEntity['fullName'];
+  x?: BioEntity['x'];
+  y?: BioEntity['y'];
+};
+
+export type PinListBioEntityWithCoords = PinListBioEntity & {
+  x: BioEntity['x'];
+  y: BioEntity['y'];
 };
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ac04a9083867762cc3aedeabc3804c3c3bccdb03
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts
@@ -0,0 +1,5 @@
+import { PinListBioEntity, PinListBioEntityWithCoords } from './BioEntitiesPinsListItem.types';
+
+export const isPinWithCoordinates = (pin: PinListBioEntity): pin is PinListBioEntityWithCoords => {
+  return Boolean(pin?.x && pin?.y);
+};
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.test.tsx
index fdc457a0a2a6b776dcf6fb1381e79468c8624c4f..cff97d8b721a5e7023a8e26504afcc747174e606 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.test.tsx
@@ -10,8 +10,27 @@ import {
 } from '@/utils/testing/getReduxWrapperWithStore';
 import { render, screen } from '@testing-library/react';
 // import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock';
+import { act } from 'react-dom/test-utils';
 import { PinTypeWithNone } from '../PinsList.types';
 import { PinsListItem } from './PinsListItem.component';
+import { useVisiblePinsPolygonCoordinates } from './hooks/useVisiblePinsPolygonCoordinates';
+
+const setBounds = jest.fn();
+
+setBounds.mockImplementation(() => {});
+jest.mock('../../../../../../../utils/map/useSetBounds', () => ({
+  _esModule: true,
+  useSetBounds: (): jest.Mock => setBounds,
+}));
+
+const useVisiblePinsPolygonCoordinatesMock = useVisiblePinsPolygonCoordinates as jest.Mock;
+
+jest.mock('./hooks/useVisiblePinsPolygonCoordinates', () => ({
+  _esModule: true,
+  useVisiblePinsPolygonCoordinates: jest.fn(),
+}));
+
+setBounds.mockImplementation(() => {});
 
 const DRUGS_PIN = {
   name: drugsFixture[0].targets[0].name,
@@ -111,4 +130,37 @@ describe('PinsListItem - component ', () => {
 
     expect(screen.queryByText('Available in submaps:')).toBeNull();
   });
+  it('should not call setBounds if coordinates do not exist', () => {
+    useVisiblePinsPolygonCoordinatesMock.mockImplementation(() => undefined);
+
+    renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs');
+
+    const buttonCenterMapToPin = screen.getByTestId('center-to-pin');
+
+    expect(buttonCenterMapToPin).toBeInTheDocument();
+
+    act(() => {
+      buttonCenterMapToPin.click();
+    });
+
+    expect(setBounds).not.toHaveBeenCalled();
+  });
+  it('should call setBounds if coordinates exist', () => {
+    useVisiblePinsPolygonCoordinatesMock.mockImplementation(() => [
+      [292, 333],
+      [341, 842],
+    ]);
+
+    renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs');
+
+    const buttonCenterMapToPin = screen.getByTestId('center-to-pin');
+
+    expect(buttonCenterMapToPin).toBeInTheDocument();
+
+    act(() => {
+      buttonCenterMapToPin.click();
+    });
+
+    expect(setBounds).toHaveBeenCalled();
+  });
 });
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx
index d87156efe2be89368063d16df26f41b49ced4d48..1f5ec270c52f3f3b55a3ab99055801c0e3deed67 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx
@@ -1,14 +1,15 @@
 import { Icon } from '@/shared/Icon';
 import { PinDetailsItem } from '@/types/models';
-import { twMerge } from 'tailwind-merge';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { modelsDataSelector } from '@/redux/models/models.selectors';
 import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { openMapAndSetActive, setActiveMap } from '@/redux/map/map.slice';
 import { mapOpenedMapsSelector } from '@/redux/map/map.selectors';
+import { useSetBounds } from '@/utils/map/useSetBounds';
 import { getListOfAvailableSubmaps, getPinColor } from './PinsListItem.component.utils';
 import { AvailableSubmaps, PinTypeWithNone } from '../PinsList.types';
+import { useVisiblePinsPolygonCoordinates } from './hooks/useVisiblePinsPolygonCoordinates';
 
 interface PinsListItemProps {
   name: string;
@@ -21,6 +22,8 @@ export const PinsListItem = ({ name, type, pin }: PinsListItemProps): JSX.Elemen
   const openedMaps = useAppSelector(mapOpenedMapsSelector);
   const models = useAppSelector(modelsDataSelector);
   const availableSubmaps = getListOfAvailableSubmaps(pin, models);
+  const coordinates = useVisiblePinsPolygonCoordinates(pin.targetElements);
+  const setBounds = useSetBounds();
 
   const isMapAlreadyOpened = (modelId: number): boolean =>
     openedMaps.some(map => map.modelId === modelId);
@@ -33,10 +36,22 @@ export const PinsListItem = ({ name, type, pin }: PinsListItemProps): JSX.Elemen
     }
   };
 
+  const handleCenterMapToPin = (): void => {
+    if (!coordinates) return;
+    setBounds(coordinates);
+  };
+
   return (
     <div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
       <div className="flex w-full flex-row items-center gap-2">
-        <Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor(type))} />
+        <button
+          type="button"
+          className="mr-2 shrink-0"
+          onClick={handleCenterMapToPin}
+          data-testid="center-to-pin"
+        >
+          <Icon name="pin" className={getPinColor(type)} />
+        </button>
         <p>
           Full name: <span className="w-full font-bold">{name}</span>
         </p>
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.test.ts b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f45826095806be323410a5ce0176199c35d1786d
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.test.ts
@@ -0,0 +1,123 @@
+/* eslint-disable no-magic-numbers */
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { MAP_INITIAL_STATE } from '@/redux/map/map.constants';
+import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
+import { useVisiblePinsPolygonCoordinates } from './useVisiblePinsPolygonCoordinates';
+
+describe('useVisiblePinsPolygonCoordinates - hook', () => {
+  it('should return undefined if receives empty array', () => {
+    const { Wrapper } = getReduxWrapperWithStore({
+      map: {
+        ...MAP_INITIAL_STATE,
+        data: {
+          ...MAP_INITIAL_STATE.data,
+          modelId: 5052,
+          size: {
+            width: 256,
+            height: 256,
+            tileSize: 256,
+            minZoom: 1,
+            maxZoom: 1,
+          },
+        },
+      },
+    });
+
+    const { result } = renderHook(() => useVisiblePinsPolygonCoordinates([]), {
+      wrapper: Wrapper,
+    });
+
+    expect(result.current).toBe(undefined);
+  });
+  it('should return undefined if received array does not contain bioEntities with current map id', () => {
+    const { Wrapper } = getReduxWrapperWithStore({
+      map: {
+        ...MAP_INITIAL_STATE,
+        data: {
+          ...MAP_INITIAL_STATE.data,
+          modelId: 5052,
+          size: {
+            width: 256,
+            height: 256,
+            tileSize: 256,
+            minZoom: 1,
+            maxZoom: 1,
+          },
+        },
+      },
+    });
+
+    const { result } = renderHook(
+      () =>
+        useVisiblePinsPolygonCoordinates([
+          {
+            ...bioEntityContentFixture.bioEntity,
+            model: 52,
+          },
+          {
+            ...bioEntityContentFixture.bioEntity,
+            model: 51,
+          },
+        ]),
+      {
+        wrapper: Wrapper,
+      },
+    );
+
+    expect(result.current).toBe(undefined);
+  });
+  it('should return coordinates if received array contain bioEntities with current map id', () => {
+    const { Wrapper } = getReduxWrapperWithStore({
+      map: {
+        ...MAP_INITIAL_STATE,
+        data: {
+          ...MAP_INITIAL_STATE.data,
+          modelId: 5052,
+          size: {
+            width: 256,
+            height: 256,
+            tileSize: 256,
+            minZoom: 1,
+            maxZoom: 1,
+          },
+        },
+      },
+    });
+
+    const { result } = renderHook(
+      () =>
+        useVisiblePinsPolygonCoordinates([
+          {
+            ...bioEntityContentFixture.bioEntity,
+            model: 5051,
+            x: 97,
+            y: 53,
+            z: 1,
+          },
+          {
+            ...bioEntityContentFixture.bioEntity,
+            model: 5052,
+            x: 12,
+            y: 25,
+            z: 1,
+          },
+          {
+            ...bioEntityContentFixture.bioEntity,
+            model: 5052,
+            x: 16,
+            y: 16,
+            z: 1,
+          },
+        ]),
+      {
+        wrapper: Wrapper,
+      },
+    );
+
+    expect(result.current).toEqual([
+      [-18158992, 16123932],
+      [-17532820, 17532820],
+    ]);
+  });
+});
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.ts b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dfd253522558c46f65ca8da64cbfa9da9f254a36
--- /dev/null
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/hooks/useVisiblePinsPolygonCoordinates.ts
@@ -0,0 +1,54 @@
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { mapModelIdSelector } from '@/redux/map/map.selectors';
+import { Point } from '@/types/map';
+import { PinDetailsItem } from '@/types/models';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { isPointValid } from '@/utils/point/isPointValid';
+import { Coordinate } from 'ol/coordinate';
+import { useMemo } from 'react';
+
+const VALID_POLYGON_COORDINATES_LENGTH = 2;
+
+export const useVisiblePinsPolygonCoordinates = (
+  pinTargetElements: PinDetailsItem['targetElements'],
+): Coordinate[] | undefined => {
+  const pointToProjection = usePointToProjection();
+  const currentModelId = useAppSelector(mapModelIdSelector);
+  const currentMapPinElements = useMemo(
+    () => pinTargetElements.filter(el => el.model === currentModelId),
+    [currentModelId, pinTargetElements],
+  );
+
+  const polygonPoints = useMemo((): Point[] => {
+    const allX = currentMapPinElements.map(({ x }) => x);
+    const allY = currentMapPinElements.map(({ y }) => y);
+    const minX = Math.min(...allX);
+    const maxX = Math.max(...allX);
+
+    const minY = Math.min(...allY);
+    const maxY = Math.max(...allY);
+
+    const points = [
+      {
+        x: minX,
+        y: maxY,
+      },
+      {
+        x: maxX,
+        y: minY,
+      },
+    ];
+    return points.filter(isPointValid);
+  }, [currentMapPinElements]);
+
+  const polygonCoordinates = useMemo(
+    () => polygonPoints.map(point => pointToProjection(point)),
+    [polygonPoints, pointToProjection],
+  );
+
+  if (polygonCoordinates.length !== VALID_POLYGON_COORDINATES_LENGTH) {
+    return undefined;
+  }
+
+  return polygonCoordinates;
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createFeatureFromExtent.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createFeatureFromExtent.ts
new file mode 100644
index 0000000000000000000000000000000000000000..121bfe2bb2b3c25f79ecb2f0dd7809a4378ace40
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createFeatureFromExtent.ts
@@ -0,0 +1,5 @@
+import Polygon, { fromExtent } from 'ol/geom/Polygon';
+import Feature from 'ol/Feature';
+
+export const createFeatureFromExtent = ([xMin, yMin, xMax, yMax]: number[]): Feature<Polygon> =>
+  new Feature({ geometry: fromExtent([xMin, yMin, xMax, yMax]) });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
index 9f27f8567185a59c2a6bffb5a94a56ca857d8ec4..b294d492153d7f74aea80a7836f30c0557032ba5 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayGeometryFeature.ts
@@ -1,10 +1,7 @@
 import { Fill, Stroke, Style } from 'ol/style';
-import { fromExtent } from 'ol/geom/Polygon';
 import Feature from 'ol/Feature';
 import type Polygon from 'ol/geom/Polygon';
-
-const createFeatureFromExtent = ([xMin, yMin, xMax, yMax]: number[]): Feature<Polygon> =>
-  new Feature({ geometry: fromExtent([xMin, yMin, xMax, yMax]) });
+import { createFeatureFromExtent } from './createFeatureFromExtent';
 
 const getBioEntityOverlayFeatureStyle = (color: string): Style =>
   new Style({ fill: new Fill({ color }), stroke: new Stroke({ color: 'black', width: 1 }) });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..06d6074af86160a0318c919e1cda4a95105be466
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.test.ts
@@ -0,0 +1,67 @@
+/* eslint-disable no-magic-numbers */
+import Feature from 'ol/Feature';
+import { createOverlaySubmapLinkRectangleFeature } from './createOverlaySubmapLinkRectangleFeature';
+
+const COLOR = '#FFFFFFcc';
+
+const CASES = [
+  [
+    [0, 0, 0, 0],
+    [0, 0, 0, 0],
+  ],
+  [
+    [0, 0, 100, 100],
+    [0, 0, 100, 100],
+  ],
+  [
+    [100, 0, 230, 100],
+    [100, 0, 230, 100],
+  ],
+  [
+    [-50, 0, 0, 50],
+    [-50, 0, 0, 50],
+  ],
+];
+
+describe('createOverlaySubmapLinkRectangleFeature - util', () => {
+  it.each(CASES)('should return Feature instance', points => {
+    const feature = createOverlaySubmapLinkRectangleFeature(points, COLOR);
+
+    expect(feature).toBeInstanceOf(Feature);
+  });
+
+  it.each(CASES)('should return Feature instance with valid style and stroke', points => {
+    const feature = createOverlaySubmapLinkRectangleFeature(points, COLOR);
+    const style = feature.getStyle();
+
+    expect(style).toMatchObject({
+      fill_: { color_: COLOR },
+      stroke_: {
+        color_: COLOR,
+        width_: 1,
+      },
+    });
+  });
+  it('should return object with transparent fill and black stroke color when color is null', () => {
+    const feature = createOverlaySubmapLinkRectangleFeature([0, 0, 0, 0], null);
+    const style = feature.getStyle();
+
+    expect(style).toMatchObject({
+      fill_: { color_: 'transparent' },
+      stroke_: {
+        color_: 'black',
+        width_: 1,
+      },
+    });
+  });
+  it.each(CASES)('should return Feature instance with valid geometry', (points, extent) => {
+    const feature = createOverlaySubmapLinkRectangleFeature(points, COLOR);
+    const geometry = feature.getGeometry();
+
+    expect(geometry?.getExtent()).toEqual(extent);
+  });
+
+  it('should throw error if extent is not valid', () => {
+    expect(() => createOverlaySubmapLinkRectangleFeature([100, 100, 0, 0], COLOR)).toThrow();
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cef983542a7777c57a8c551ed6e9d96aa1dcb35c
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlaySubmapLinkRectangleFeature.ts
@@ -0,0 +1,14 @@
+/* eslint-disable no-magic-numbers */
+import Feature from 'ol/Feature';
+import type Polygon from 'ol/geom/Polygon';
+import { createFeatureFromExtent } from './createFeatureFromExtent';
+import { getOverlaySubmapLinkRectangleFeatureStyle } from './getOverlaySubmapLinkRectangleFeatureStyle';
+
+export const createOverlaySubmapLinkRectangleFeature = (
+  [xMin, yMin, xMax, yMax]: number[],
+  color: string | null,
+): Feature<Polygon> => {
+  const feature = createFeatureFromExtent([xMin, yMin, xMax, yMax]);
+  feature.setStyle(getOverlaySubmapLinkRectangleFeatureStyle(color));
+  return feature;
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90bb4af947e8dc4e7978b62ae4135bec61841c3f
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.test.ts
@@ -0,0 +1,37 @@
+/* eslint-disable no-magic-numbers */
+import { Fill, Stroke, Style } from 'ol/style';
+import { getOverlaySubmapLinkRectangleFeatureStyle } from './getOverlaySubmapLinkRectangleFeatureStyle';
+
+const COLORS = ['#000000', '#FFFFFF', '#F5F5F5', '#C0C0C0', '#C0C0C0aa', '#C0C0C0bb'];
+
+describe('getOverlaySubmapLinkRectangleFeatureStyle - util', () => {
+  it.each(COLORS)('should return Style object', color => {
+    const result = getOverlaySubmapLinkRectangleFeatureStyle(color);
+    expect(result).toBeInstanceOf(Style);
+  });
+
+  it.each(COLORS)('should set valid color values for fill', color => {
+    const result = getOverlaySubmapLinkRectangleFeatureStyle(color);
+    const fill = result.getFill();
+    expect(fill).toBeInstanceOf(Fill);
+    expect(fill?.getColor()).toBe(color);
+  });
+
+  it.each(COLORS)('should set valid color values for fill', color => {
+    const result = getOverlaySubmapLinkRectangleFeatureStyle(color);
+    const stroke = result.getStroke();
+    expect(stroke).toBeInstanceOf(Stroke);
+    expect(stroke?.getColor()).toBe(color);
+    expect(stroke?.getWidth()).toBe(1);
+  });
+  it('should set transparent fill and black stroke if color is null', () => {
+    const result = getOverlaySubmapLinkRectangleFeatureStyle(null);
+    const stroke = result.getStroke();
+    expect(stroke).toBeInstanceOf(Stroke);
+    expect(stroke?.getColor()).toBe('black');
+    expect(stroke?.getWidth()).toBe(1);
+    const fill = result.getFill();
+    expect(fill).toBeInstanceOf(Fill);
+    expect(fill?.getColor()).toBe('transparent');
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b597c42d4849e21c85b1e0a84e0ede947961df1b
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlaySubmapLinkRectangleFeatureStyle.ts
@@ -0,0 +1,9 @@
+/* eslint-disable no-magic-numbers */
+import { Fill, Stroke, Style } from 'ol/style';
+
+export const getOverlaySubmapLinkRectangleFeatureStyle = (color: string | null): Style =>
+  new Style({
+    fill: new Fill({ color: color || 'transparent' }),
+    stroke: new Stroke({ color: color || 'black', width: 1 }),
+    zIndex: color ? 0 : 1,
+  });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getSubmapLinkRectangle.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getSubmapLinkRectangle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..eab42ae4016d8fbfbf6883d79b963624bf764df3
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getSubmapLinkRectangle.ts
@@ -0,0 +1,26 @@
+/* eslint-disable no-magic-numbers, no-param-reassign */
+import type { SubmapLinkRectangle } from './useBioEntitiesWithSubmapLinks';
+
+export const getSubmapLinkRectangle = (
+  submapsLinksRectangles: SubmapLinkRectangle[],
+  submapLinkRectangle: SubmapLinkRectangle,
+  index: number,
+  submapLinksRectanglesGroup: SubmapLinkRectangle[],
+  rectangleHeight: number,
+): void => {
+  if (index === 0) {
+    submapsLinksRectangles.push({
+      ...submapLinkRectangle,
+      amount: 0,
+      value: Infinity,
+    });
+  }
+
+  if (index !== 0) {
+    submapLinkRectangle.y2 = submapLinksRectanglesGroup[index - 1].y1;
+  }
+  submapLinkRectangle.y1 = submapLinkRectangle.y2 + rectangleHeight;
+  submapLinkRectangle.height = rectangleHeight;
+
+  submapsLinksRectangles.push(submapLinkRectangle);
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/groupSubmapLinksRectanglesById.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/groupSubmapLinksRectanglesById.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e1691c06812c6db4e3f46300e9d58c06e623cad9
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/groupSubmapLinksRectanglesById.ts
@@ -0,0 +1,45 @@
+import type { OverlayBioEntityRender } from '@/types/OLrendering';
+import type { GroupedSubmapsLinksRectangles } from './useBioEntitiesWithSubmapLinks';
+
+export const groupSubmapLinksRectanglesById = (
+  data: OverlayBioEntityRender[],
+): GroupedSubmapsLinksRectangles => {
+  const submapsLinksRectangles = [...data];
+  const groupedSubmapsLinksRectanglesById: GroupedSubmapsLinksRectangles = {};
+
+  submapsLinksRectangles.forEach(submapLinkRectangle => {
+    const { id, overlayId } = submapLinkRectangle;
+    const groupId = `${id}-${overlayId}`;
+
+    if (!groupedSubmapsLinksRectanglesById[groupId]) {
+      groupedSubmapsLinksRectanglesById[groupId] = [];
+    }
+
+    const matchedSubmapLinkRectangle = groupedSubmapsLinksRectanglesById[groupId].find(element => {
+      const hasAllRequiredValueProperties = element.value && submapLinkRectangle.value;
+      const isValueEqual =
+        hasAllRequiredValueProperties && element.value === submapLinkRectangle.value;
+
+      const hasAllRequiredColorProperties = element.color && submapLinkRectangle.color;
+      const isColorEqual =
+        hasAllRequiredColorProperties &&
+        element.color?.alpha === submapLinkRectangle?.color?.alpha &&
+        element.color?.rgb === submapLinkRectangle?.color?.rgb;
+
+      if (isValueEqual || isColorEqual) return true;
+
+      return false;
+    });
+
+    if (!matchedSubmapLinkRectangle) {
+      groupedSubmapsLinksRectanglesById[groupId].push({
+        ...submapLinkRectangle,
+        amount: 1,
+      });
+    } else {
+      matchedSubmapLinkRectangle.amount += 1;
+    }
+  });
+
+  return groupedSubmapsLinksRectanglesById;
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..788b89f248c1afb9a64d4d39b420c18b8a39c40a
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts
@@ -0,0 +1,331 @@
+/* eslint-disable no-magic-numbers */
+import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener';
+import { renderHook } from '@testing-library/react';
+import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock';
+import { PUBLIC_OVERLAYS_MOCK } from '@/redux/overlays/overlays.mock';
+import { mapStateWithCurrentlySelectedMainMapFixture } from '@/redux/map/map.fixtures';
+import {
+  MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_DIFFERENT_COLORS,
+  MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_SAME_COLORS,
+  OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK,
+} from '@/redux/overlayBioEntity/overlayBioEntity.mock';
+import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
+import { useBioEntitiesWithSubmapsLinks } from './useBioEntitiesWithSubmapLinks';
+
+const RESULT_SUBMAP_LINKS_DIFFERENT_VALUES = [
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    amount: 0,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: Infinity,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 1,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2025.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 25,
+    value: 0.8,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 1,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2050.5,
+    y2: 2025.5,
+    overlayId: 12,
+    height: 25,
+    value: 0.5,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 1,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2075.5,
+    y2: 2050.5,
+    overlayId: 12,
+    height: 25,
+    value: 0.4,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 1,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2075.5,
+    overlayId: 12,
+    height: 25,
+    value: null,
+    color: {
+      alpha: 255,
+      rgb: -2348283,
+    },
+  },
+  {
+    type: 'rectangle',
+    id: 1,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 3128.653195488725,
+    y2: 3088.653195488725,
+    overlayId: 12,
+    height: 10,
+    value: 0,
+    color: null,
+  },
+];
+
+export const RESULT_SUBMAP_LINKS_SAME_COLORS = [
+  {
+    type: 'submap-link',
+    amount: 0,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: Infinity,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 2,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2050.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 50,
+    value: 23,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    amount: 2,
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2050.5,
+    overlayId: 12,
+    height: 50,
+    value: null,
+    color: {
+      alpha: 255,
+      rgb: -2348283,
+    },
+  },
+  {
+    type: 'rectangle',
+    id: 1,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 3128.653195488725,
+    y2: 3088.653195488725,
+    overlayId: 12,
+    height: 10,
+    value: 0,
+    color: null,
+  },
+];
+
+describe('useBioEntitiesWithSubmapsLinks', () => {
+  it('should return bioEntities without submaps links if no submaps links are present', () => {
+    const { Wrapper } = getReduxStoreWithActionsListener({
+      overlayBioEntity: {
+        ...OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK,
+        overlaysId: PUBLIC_OVERLAYS_MOCK.map(o => o.idObject),
+      },
+      configuration: CONFIGURATION_INITIAL_STORE_MOCKS,
+      map: mapStateWithCurrentlySelectedMainMapFixture,
+    });
+
+    const {
+      result: { current },
+    } = renderHook(() => useBioEntitiesWithSubmapsLinks(), {
+      wrapper: Wrapper,
+    });
+
+    expect(current).toEqual([]);
+  });
+
+  describe('submap links with the same ID and overlayID but different values or colors', () => {
+    it('should create submap link with Infinity value, for displaying black border of submap link', () => {
+      const { Wrapper } = getReduxStoreWithActionsListener({
+        overlayBioEntity: {
+          overlaysId: [12],
+          data: {
+            12: {
+              52: MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_DIFFERENT_COLORS,
+            },
+          },
+        },
+        configuration: CONFIGURATION_INITIAL_STORE_MOCKS,
+        map: mapStateWithCurrentlySelectedMainMapFixture,
+
+        models: {
+          ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
+        },
+      });
+
+      const {
+        result: { current },
+      } = renderHook(() => useBioEntitiesWithSubmapsLinks(), {
+        wrapper: Wrapper,
+      });
+
+      expect(current[0]).toEqual({
+        type: 'submap-link',
+        amount: 0,
+        id: 97,
+        modelId: 52,
+        width: 30,
+        x1: 18412,
+        x2: 18492,
+        y1: 2100.5,
+        y2: 2000.5,
+        overlayId: 12,
+        height: 100,
+        value: Infinity,
+        color: null,
+      });
+    });
+    it('should modify height, coordinates and return in sorted order to create submap link from several submap link rectangles', () => {
+      const { Wrapper } = getReduxStoreWithActionsListener({
+        overlayBioEntity: {
+          overlaysId: [12],
+          data: {
+            12: {
+              52: MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_DIFFERENT_COLORS,
+            },
+          },
+        },
+        configuration: CONFIGURATION_INITIAL_STORE_MOCKS,
+        map: mapStateWithCurrentlySelectedMainMapFixture,
+
+        models: {
+          ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
+        },
+      });
+
+      const {
+        result: { current },
+      } = renderHook(() => useBioEntitiesWithSubmapsLinks(), {
+        wrapper: Wrapper,
+      });
+
+      expect(current).toStrictEqual(RESULT_SUBMAP_LINKS_DIFFERENT_VALUES);
+    });
+  });
+  describe('submap links with the same ID and overlayID and the same values or colors', () => {
+    it('should create submap link with Infinity value, for displaying black border of submap link', () => {
+      const { Wrapper } = getReduxStoreWithActionsListener({
+        overlayBioEntity: {
+          overlaysId: [12],
+          data: {
+            12: {
+              52: MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_SAME_COLORS,
+            },
+          },
+        },
+        configuration: CONFIGURATION_INITIAL_STORE_MOCKS,
+        map: mapStateWithCurrentlySelectedMainMapFixture,
+
+        models: {
+          ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
+        },
+      });
+
+      const {
+        result: { current },
+      } = renderHook(() => useBioEntitiesWithSubmapsLinks(), {
+        wrapper: Wrapper,
+      });
+
+      expect(current[0]).toEqual({
+        type: 'submap-link',
+        amount: 0,
+        id: 97,
+        modelId: 52,
+        width: 30,
+        x1: 18412,
+        x2: 18492,
+        y1: 2100.5,
+        y2: 2000.5,
+        overlayId: 12,
+        height: 100,
+        value: Infinity,
+        color: null,
+      });
+    });
+    it('should modify height, coordinates and return in sorted order to create submap link from several submap link rectangles', () => {
+      const { Wrapper } = getReduxStoreWithActionsListener({
+        overlayBioEntity: {
+          overlaysId: [12],
+          data: {
+            12: {
+              52: MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_SAME_COLORS,
+            },
+          },
+        },
+        configuration: CONFIGURATION_INITIAL_STORE_MOCKS,
+        map: mapStateWithCurrentlySelectedMainMapFixture,
+
+        models: {
+          ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
+        },
+      });
+
+      const {
+        result: { current },
+      } = renderHook(() => useBioEntitiesWithSubmapsLinks(), {
+        wrapper: Wrapper,
+      });
+
+      expect(current).toStrictEqual(RESULT_SUBMAP_LINKS_SAME_COLORS);
+    });
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fd9ef50e007133e8339f9952c3b3bfd54b491a39
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.ts
@@ -0,0 +1,92 @@
+/* eslint-disable no-magic-numbers */
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { overlayBioEntitiesForCurrentModelSelector } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
+import { useCallback, useMemo } from 'react';
+import type { OverlayBioEntityRender } from '@/types/OLrendering';
+import { useGetOverlayColor } from './useGetOverlayColor';
+import { getSubmapLinkRectangle } from './getSubmapLinkRectangle';
+import { groupSubmapLinksRectanglesById } from './groupSubmapLinksRectanglesById';
+
+export type SubmapLinkRectangle = OverlayBioEntityRender & {
+  amount: number;
+};
+
+export type GroupedSubmapsLinksRectangles = {
+  [id: string]: SubmapLinkRectangle[];
+};
+
+export const useBioEntitiesWithSubmapsLinks = (): OverlayBioEntityRender[] => {
+  const { getOverlayBioEntityColorByAvailableProperties } = useGetOverlayColor();
+  const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector);
+  const submapsLinks = useMemo(
+    () => bioEntities.filter(bioEntity => bioEntity.type === 'submap-link'),
+    [bioEntities],
+  );
+  const bioEntitiesWithoutSubmapsLinks = useMemo(
+    () => bioEntities.filter(bioEntity => bioEntity.type !== 'submap-link'),
+    [bioEntities],
+  );
+
+  const sortSubmapLinksRectanglesByColor = useCallback(
+    (submapLinksRectangles: SubmapLinkRectangle[]): void => {
+      submapLinksRectangles.sort((a, b) => {
+        const firstSubmapLinkRectangleColor = getOverlayBioEntityColorByAvailableProperties(a);
+        const secondSubmapLinkRectangleColor = getOverlayBioEntityColorByAvailableProperties(b);
+
+        if (firstSubmapLinkRectangleColor === secondSubmapLinkRectangleColor) {
+          return 0;
+        }
+
+        return firstSubmapLinkRectangleColor < secondSubmapLinkRectangleColor ? -1 : 1;
+      });
+    },
+    [getOverlayBioEntityColorByAvailableProperties],
+  );
+
+  const calculateSubmapsLinksRectanglesPosition = useCallback(
+    (
+      groupedSubmapsLinksRectanglesById: GroupedSubmapsLinksRectangles,
+    ): OverlayBioEntityRender[] => {
+      const submapsLinksRectangles: SubmapLinkRectangle[] = [];
+      // eslint-disable-next-line no-restricted-syntax, guard-for-in
+      for (const id in groupedSubmapsLinksRectanglesById) {
+        const submapLinksRectanglesGroup = groupedSubmapsLinksRectanglesById[id];
+
+        sortSubmapLinksRectanglesByColor(submapLinksRectanglesGroup);
+
+        const submapLinkRectanglesTotalHeight = submapLinksRectanglesGroup[0].height;
+        const submapLinkRectanglesAmount = submapLinksRectanglesGroup.reduce(
+          (accumulator: number, currentValue) => accumulator + currentValue.amount,
+          0,
+        );
+
+        submapLinksRectanglesGroup.forEach((submapLinkRectangle, index) => {
+          const ratio = submapLinkRectangle.amount / submapLinkRectanglesAmount;
+          const rectangleHeight = ratio * submapLinkRectanglesTotalHeight;
+
+          getSubmapLinkRectangle(
+            submapsLinksRectangles,
+            submapLinkRectangle,
+            index,
+            submapLinksRectanglesGroup,
+            rectangleHeight,
+          );
+        });
+      }
+
+      return submapsLinksRectangles;
+    },
+    [sortSubmapLinksRectanglesByColor],
+  );
+
+  const groupedSubmapLinksRectanglesById = useMemo(
+    () => groupSubmapLinksRectanglesById(submapsLinks),
+    [submapsLinks],
+  );
+  const submapsLinksRectangles = useMemo(
+    () => calculateSubmapsLinksRectanglesPosition(groupedSubmapLinksRectanglesById),
+    [groupedSubmapLinksRectanglesById, calculateSubmapsLinksRectanglesPosition],
+  );
+
+  return [...submapsLinksRectangles, ...bioEntitiesWithoutSubmapsLinks];
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
index 477a95dd324f06f8099d88db81055e7324b77d5f..98e528f393c900d3716cbfb5814fca0db056ddb0 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
@@ -1,9 +1,6 @@
 import { ZERO } from '@/constants/common';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
-import {
-  getOverlayOrderSelector,
-  overlayBioEntitiesForCurrentModelSelector,
-} from '@/redux/overlayBioEntity/overlayBioEntity.selector';
+import { getOverlayOrderSelector } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
 import { LinePoint } from '@/types/reactions';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import type Feature from 'ol/Feature';
@@ -14,12 +11,14 @@ import { createOverlayGeometryFeature } from './createOverlayGeometryFeature';
 import { createOverlayLineFeature } from './createOverlayLineFeature';
 import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates';
 import { useGetOverlayColor } from './useGetOverlayColor';
+import { useBioEntitiesWithSubmapsLinks } from './useBioEntitiesWithSubmapLinks';
+import { createOverlaySubmapLinkRectangleFeature } from './createOverlaySubmapLinkRectangleFeature';
 
 export const useOverlayFeatures = (): Feature<Polygon>[] | Feature<SimpleGeometry>[] => {
   const pointToProjection = usePointToProjection();
   const { getOverlayBioEntityColorByAvailableProperties } = useGetOverlayColor();
   const overlaysOrder = useAppSelector(getOverlayOrderSelector);
-  const bioEntities = useAppSelector(overlayBioEntitiesForCurrentModelSelector);
+  const bioEntities = useBioEntitiesWithSubmapsLinks();
 
   const features = useMemo(
     () =>
@@ -39,6 +38,16 @@ export const useOverlayFeatures = (): Feature<Polygon>[] | Feature<SimpleGeometr
 
         const color = getOverlayBioEntityColorByAvailableProperties(entity);
 
+        if (entity.type === 'submap-link') {
+          return createOverlaySubmapLinkRectangleFeature(
+            [
+              ...pointToProjection({ x: xMin, y: entity.y1 }),
+              ...pointToProjection({ x: xMax, y: entity.y2 }),
+            ],
+            entity.value === Infinity ? null : color,
+          );
+        }
+
         if (entity.type === 'rectangle') {
           return createOverlayGeometryFeature(
             [
@@ -60,7 +69,7 @@ export const useOverlayFeatures = (): Feature<Polygon>[] | Feature<SimpleGeometr
           },
         );
       }),
-    [overlaysOrder, bioEntities, pointToProjection, getOverlayBioEntityColorByAvailableProperties],
+    [overlaysOrder, pointToProjection, getOverlayBioEntityColorByAvailableProperties, bioEntities],
   );
 
   return features;
diff --git a/src/models/mocks/publicationsResponseMock.ts b/src/models/mocks/publicationsResponseMock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..09021f4ed644552f37e1fa98ccbd0240f424ee00
--- /dev/null
+++ b/src/models/mocks/publicationsResponseMock.ts
@@ -0,0 +1,281 @@
+export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK = {
+  data: [
+    {
+      elements: [
+        {
+          id: 19519,
+          modelId: 52,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 16167,
+          modelId: 61,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 17823,
+          modelId: 52,
+          type: 'REACTION',
+        },
+        {
+          id: 19461,
+          modelId: 52,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 18189,
+          modelId: 52,
+          type: 'REACTION',
+        },
+        {
+          id: 18729,
+          modelId: 52,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 16077,
+          modelId: 58,
+          type: 'REACTION',
+        },
+        {
+          id: 16135,
+          modelId: 58,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 15955,
+          modelId: 55,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 15937,
+          modelId: 55,
+          type: 'REACTION',
+        },
+        {
+          id: 15955,
+          modelId: 55,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 15948,
+          modelId: 55,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 16286,
+          modelId: 62,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+    {
+      elements: [
+        {
+          id: 17780,
+          modelId: 52,
+          type: 'REACTION',
+        },
+        {
+          id: 17937,
+          modelId: 52,
+          type: 'REACTION',
+        },
+      ],
+      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,
+        },
+      },
+    },
+  ],
+  totalSize: 159,
+  filteredSize: 1586,
+  length: 10,
+  page: 0,
+};
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 5051aa2ab98167bbfef888206ea98cd431d6ccb2..19aac51cbd7e5a42dad6e5cb907a10053e14b038 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -55,7 +55,7 @@ export const apiPath = {
   getConfigurationOptions: (): string => 'configuration/options/',
   getConfiguration: (): string => 'configuration/',
   getOverlayBioEntity: ({ overlayId, modelId }: { overlayId: number; modelId: number }): string =>
-    `projects/${PROJECT_ID}/overlays/${overlayId}/models/${modelId}/bioEntities/`,
+    `projects/${PROJECT_ID}/overlays/${overlayId}/models/${modelId}/bioEntities/?includeIndirect=true`,
   createOverlay: (projectId: string): string => `projects/${projectId}/overlays/`,
   createOverlayFile: (): string => `files/`,
   uploadOverlayFileContent: (fileId: number): string => `files/${fileId}:uploadContent`,
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
index 9b093c3eeaecee77b8fc2923f37f8cd3da8c5eec..bd2d8522533e66f539c0cd656fee9ab239ea2202 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
@@ -78,3 +78,159 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     color: null,
   },
 ];
+
+export const MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_SAME_COLORS: OverlayBioEntityRender[] = [
+  {
+    type: 'rectangle',
+    id: 1,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 3128.653195488725,
+    y2: 3088.653195488725,
+    overlayId: 12,
+    height: 10,
+    value: 0,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: 23,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: 23,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: null,
+    color: {
+      alpha: 255,
+      rgb: -2348283,
+    },
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: null,
+    color: {
+      alpha: 255,
+      rgb: -2348283,
+    },
+  },
+];
+
+export const MOCKED_OVERLAY_SUBMAPS_LINKS_WITH_DIFFERENT_COLORS: OverlayBioEntityRender[] = [
+  {
+    type: 'rectangle',
+    id: 1,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 3128.653195488725,
+    y2: 3088.653195488725,
+    overlayId: 12,
+    height: 10,
+    value: 0,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: 0.4,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: 0.5,
+    color: null,
+  },
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: 0.8,
+    color: null,
+  },
+
+  {
+    type: 'submap-link',
+    id: 97,
+    modelId: 52,
+    width: 30,
+    x1: 18412,
+    x2: 18492,
+    y1: 2100.5,
+    y2: 2000.5,
+    overlayId: 12,
+    height: 100,
+    value: null,
+    color: {
+      alpha: 255,
+      rgb: -2348283,
+    },
+  },
+];
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
index b765ff8de4471783e7eca9ffa73ec405b9829118..becf2d2ab94699294879668994a6b5c88cf73f62 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
@@ -3,7 +3,7 @@ import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
 import { OverlayBioEntity } from '@/types/models';
 import { getOverlayReactionCoordsFromLine } from '@/utils/overlays/getOverlayReactionCoords';
-import { isBioEntity, isReaction } from '@/utils/overlays/overlaysElementsTypeGuards';
+import { isBioEntity, isReaction, isSubmapLink } from '@/utils/overlays/overlaysElementsTypeGuards';
 import { z } from 'zod';
 
 export const parseOverlayBioEntityToOlRenderingFormat = (
@@ -18,6 +18,24 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
      * Every reaction line is a different entity after reduce
      */
 
+    if (isSubmapLink(entity)) {
+      acc.push({
+        type: 'submap-link',
+        id: entity.left.id,
+        modelId: entity.left.model,
+        x1: entity.left.x,
+        y1: entity.left.y + entity.left.height,
+        x2: entity.left.x + entity.left.width,
+        y2: entity.left.y,
+        width: entity.left.width,
+        height: entity.left.height,
+        value: entity.right.value,
+        overlayId,
+        color: entity.right.color,
+      });
+      return acc;
+    }
+
     if (isBioEntity(entity)) {
       acc.push({
         type: 'rectangle',
diff --git a/src/redux/publications/publications.mock.ts b/src/redux/publications/publications.mock.ts
index 3ae459cd1a5e4a1bad2f273d6c20bb6336d46cd7..97f88fd95e2cbb33e23e78331541b88f44f5ad3b 100644
--- a/src/redux/publications/publications.mock.ts
+++ b/src/redux/publications/publications.mock.ts
@@ -1,3 +1,4 @@
+import { PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK } from '@/models/mocks/publicationsResponseMock';
 import { PublicationsState } from './publications.types';
 
 export const PUBLICATIONS_INITIAL_STATE_MOCK: PublicationsState = {
@@ -9,3 +10,13 @@ export const PUBLICATIONS_INITIAL_STATE_MOCK: PublicationsState = {
   searchValue: '',
   selectedModelId: undefined,
 };
+
+export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_STATE_MOCK: PublicationsState = {
+  data: PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK,
+  loading: 'idle',
+  error: { name: '', message: '' },
+  sortColumn: '',
+  sortOrder: 'asc',
+  searchValue: '',
+  selectedModelId: undefined,
+};
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 925fb4094256ffe3ccd792ba655e0d24e717e919..6aa4c44501acd537ce6d49ff63f4a9aba1c3e894 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -22,12 +22,12 @@ import {
   TypedStartListening,
   configureStore,
 } from '@reduxjs/toolkit';
-import compartmentPathwaysReducer from './compartmentPathways/compartmentPathways.slice';
 import exportReducer from './export/export.slice';
 import legendReducer from './legend/legend.slice';
 import { mapListenerMiddleware } from './map/middleware/map.middleware';
 import pluginsReducer from './plugins/plugins.slice';
 import statisticsReducer from './statistics/statistics.slice';
+import compartmentPathwaysReducer from './compartmentPathways/compartmentPathways.slice';
 import publicationsReducer from './publications/publications.slice';
 
 export const reducers = {
diff --git a/src/types/OLrendering.ts b/src/types/OLrendering.ts
index 18075b437e4f2f7e91f7de2cbe1955f8851feaf4..9769064d9bada810382fe653e7df432030f9f94b 100644
--- a/src/types/OLrendering.ts
+++ b/src/types/OLrendering.ts
@@ -1,6 +1,6 @@
 import { Color, GeneVariant } from './models';
 
-export type OverlayBioEntityRenderType = 'line' | 'rectangle';
+export type OverlayBioEntityRenderType = 'line' | 'rectangle' | 'submap-link';
 
 export type OverlayBioEntityRender = {
   id: number;
diff --git a/src/utils/overlays/overlaysElementsTypeGuards.ts b/src/utils/overlays/overlaysElementsTypeGuards.ts
index 6997b141f5d627b5d4641ee23c2f7b902f17a1af..fdd3f1938b4021b29c610671c6e5225b6b97d082 100644
--- a/src/utils/overlays/overlaysElementsTypeGuards.ts
+++ b/src/utils/overlays/overlaysElementsTypeGuards.ts
@@ -12,3 +12,8 @@ export const isReaction = (e: OverlayBioEntity): e is OverlayElementWithReaction
 export const isBioEntity = (e: OverlayBioEntity): e is OverlayElementWithBioEntity =>
   (e.left as OverlayLeftBioEntity).x !== undefined &&
   (e.left as OverlayLeftBioEntity).y !== undefined;
+
+export const isSubmapLink = (e: OverlayBioEntity): e is OverlayElementWithBioEntity =>
+  (e.left as OverlayLeftBioEntity).x !== undefined &&
+  (e.left as OverlayLeftBioEntity).y !== undefined &&
+  (e.left as OverlayLeftBioEntity).submodel !== undefined;