diff --git a/src/components/FunctionalArea/NavBar/NavBar.component.tsx b/src/components/FunctionalArea/NavBar/NavBar.component.tsx
index fbc5c000ee41e1dd810219d5d9cf181263fc02a7..830131c1ac047fd046c01ee9e585b48d876cf8c5 100644
--- a/src/components/FunctionalArea/NavBar/NavBar.component.tsx
+++ b/src/components/FunctionalArea/NavBar/NavBar.component.tsx
@@ -15,7 +15,7 @@ export const NavBar = (): JSX.Element => {
   };
 
   const openDrawerPlugins = (): void => {
-    dispatch(openDrawer('plugins'));
+    dispatch(openDrawer('available-plugins'));
   };
 
   const openDrawerExport = (): void => {
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..06d70d35abe59da6cf05b3c3700d991746cc3db8
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.test.tsx
@@ -0,0 +1,53 @@
+import { PLUGINS_MOCK } from '@/models/mocks/pluginsMock';
+import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
+import { StoreType } from '@/redux/store';
+import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { render, screen } from '@testing-library/react';
+import { AvailablePluginsDrawer } from './AvailablePluginsDrawer.component';
+
+const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
+  const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
+  return (
+    render(
+      <Wrapper>
+        <AvailablePluginsDrawer />
+      </Wrapper>,
+    ),
+    {
+      store,
+    }
+  );
+};
+
+describe('AvailablePluginsDrawer - component', () => {
+  describe('when always', () => {
+    it('should render drawer heading', () => {
+      renderComponent(INITIAL_STORE_STATE_MOCK);
+      const drawerTitle = screen.getByText('Available plugins');
+      expect(drawerTitle).toBeInTheDocument();
+    });
+
+    it('should render load plugin from url', () => {
+      renderComponent(INITIAL_STORE_STATE_MOCK);
+      const loadPluginFromUrlInput = screen.getByTestId('load-plugin-input-url');
+      expect(loadPluginFromUrlInput).toBeInTheDocument();
+    });
+
+    it.each(PLUGINS_MOCK)('should render render all public plugins', currentPlugin => {
+      renderComponent({
+        ...INITIAL_STORE_STATE_MOCK,
+        plugins: {
+          ...INITIAL_STORE_STATE_MOCK.plugins,
+          list: {
+            ...INITIAL_STORE_STATE_MOCK.plugins.list,
+            data: PLUGINS_MOCK,
+          },
+        },
+      });
+
+      const pluginLabel = screen.getByText(currentPlugin.name);
+      expect(pluginLabel).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..d1343d91bbf51f36f926c2af248d596790155f04
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/AvailablePluginsDrawer.component.tsx
@@ -0,0 +1,21 @@
+import { publicPluginsListSelector } from '@/redux/plugins/plugins.selectors';
+import { DrawerHeading } from '@/shared/DrawerHeading';
+import { useSelector } from 'react-redux';
+import { LoadPlugin } from './LoadPlugin';
+import { LoadPluginFromUrl } from './LoadPluginFromUrl';
+
+export const AvailablePluginsDrawer = (): JSX.Element => {
+  const publicPlugins = useSelector(publicPluginsListSelector);
+
+  return (
+    <div className="h-full max-h-full" data-testid="available-plugins-drawer">
+      <DrawerHeading title="Available plugins" />
+      <div className="flex flex-col gap-6 p-6">
+        <LoadPluginFromUrl />
+        {publicPlugins.map(plugin => (
+          <LoadPlugin key={plugin.hash} plugin={plugin} />
+        ))}
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..92c659ac76bde94184d4324be245989f7c8f4dec
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.test.tsx
@@ -0,0 +1,29 @@
+import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { PLUGINS_MOCK } from '@/models/mocks/pluginsMock';
+import { render, screen } from '@testing-library/react';
+import { LoadPlugin, Props } from './LoadPlugin.component';
+
+const renderComponent = ({ plugin }: Props): void => {
+  render(<LoadPlugin plugin={plugin} />);
+};
+
+describe('LoadPlugin - component', () => {
+  describe('when always', () => {
+    const plugin = PLUGINS_MOCK[FIRST_ARRAY_ELEMENT];
+
+    it('renders plugin name', () => {
+      renderComponent({ plugin });
+
+      const title = screen.getByText(plugin.name);
+      expect(title).toBeInTheDocument();
+    });
+
+    it('renders plugin load button', () => {
+      renderComponent({ plugin });
+
+      const loadButton = screen.getByText('Load');
+      expect(loadButton.tagName).toBe('BUTTON');
+      expect(loadButton).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..fee403ca18cb34195aaf42a559ba618eb68f821e
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/LoadPlugin.component.tsx
@@ -0,0 +1,25 @@
+import { Button } from '@/shared/Button';
+import { MinervaPlugin } from '@/types/models';
+
+export interface Props {
+  plugin: MinervaPlugin;
+}
+
+export const LoadPlugin = ({ plugin }: Props): JSX.Element => {
+  const handleLoadPlugin = (): void => {
+    // TODO: handleLoadPlugin
+  };
+
+  return (
+    <div className="flex w-full items-center justify-between">
+      <span className="text-cetacean-blue">{plugin.name}</span>
+      <Button
+        variantStyles="secondary"
+        className="h-10 self-end rounded-e rounded-s"
+        onClick={handleLoadPlugin}
+      >
+        Load
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e27e6ba35e4443188bf5a6e08a655ddb97b3262c
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPlugin/index.ts
@@ -0,0 +1 @@
+export { LoadPlugin } from './LoadPlugin.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e1d83a8ba9fde4258d36ad1d5df8629ac583ce57
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.test.tsx
@@ -0,0 +1,32 @@
+import { render, screen } from '@testing-library/react';
+import { LoadPluginFromUrl } from './LoadPluginFromUrl.component';
+
+const renderComponent = (): void => {
+  render(<LoadPluginFromUrl />);
+};
+
+describe('LoadPluginFromUrl - component', () => {
+  describe('when always', () => {
+    it('renders plugin input label', () => {
+      renderComponent();
+
+      const pluginInputLabel = screen.getByLabelText('URL:');
+      expect(pluginInputLabel).toBeInTheDocument();
+    });
+
+    it('renders plugin input', () => {
+      renderComponent();
+
+      const pluginInput = screen.getByTestId('load-plugin-input-url');
+      expect(pluginInput).toBeInTheDocument();
+    });
+
+    it('renders plugin load button', () => {
+      renderComponent();
+
+      const loadButton = screen.getByText('Load');
+      expect(loadButton.tagName).toBe('BUTTON');
+      expect(loadButton).toBeInTheDocument();
+    });
+  });
+});
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..de486ad2bb19462bca3674a24f9a72a126d1f75c
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/LoadPluginFromUrl.component.tsx
@@ -0,0 +1,32 @@
+import { Button } from '@/shared/Button';
+import { useState } from 'react';
+
+export const LoadPluginFromUrl = (): JSX.Element => {
+  const [url, setUrl] = useState<string>('');
+
+  const handleLoadPlugin = (): void => {
+    // TODO: handleLoadPlugin
+  };
+
+  return (
+    <div className="flex w-full">
+      <label className="flex w-full flex-col gap-2 text-sm text-cetacean-blue">
+        <span>URL:</span>
+        <input
+          className="h-10 w-full bg-cultured p-3"
+          type="url"
+          value={url}
+          onChange={(e): void => setUrl(e.target.value)}
+          data-testid="load-plugin-input-url"
+        />
+      </label>
+      <Button
+        variantStyles="secondary"
+        className="h-10 self-end rounded-e rounded-s"
+        onClick={handleLoadPlugin}
+      >
+        Load
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cedb0f665553574022fb55f4f00ef9678b546f1d
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/LoadPluginFromUrl/index.ts
@@ -0,0 +1 @@
+export { LoadPluginFromUrl } from './LoadPluginFromUrl.component';
diff --git a/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts b/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..85f2fe7f30853779b57a030199940cd3055f8e3a
--- /dev/null
+++ b/src/components/Map/Drawer/AvailablePluginsDrawer/index.ts
@@ -0,0 +1 @@
+export { AvailablePluginsDrawer } from './AvailablePluginsDrawer.component';
diff --git a/src/components/Map/Drawer/Drawer.component.tsx b/src/components/Map/Drawer/Drawer.component.tsx
index 4403fe9b6c719c971445feb36dafcd0d55f60329..de1aa94ea44f6f9e2203ea3a386e373cbce620d6 100644
--- a/src/components/Map/Drawer/Drawer.component.tsx
+++ b/src/components/Map/Drawer/Drawer.component.tsx
@@ -2,14 +2,14 @@ import { DRAWER_ROLE } from '@/components/Map/Drawer/Drawer.constants';
 import { drawerSelector } from '@/redux/drawer/drawer.selectors';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { twMerge } from 'tailwind-merge';
-import { ReactionDrawer } from './ReactionDrawer';
-import { SearchDrawerWrapper as SearchDrawerContent } from './SearchDrawerWrapper';
-import { SubmapsDrawer } from './SubmapsDrawer';
-import { OverlaysDrawer } from './OverlaysDrawer';
+import { AvailablePluginsDrawer } from './AvailablePluginsDrawer';
 import { BioEntityDrawer } from './BioEntityDrawer/BioEntityDrawer.component';
 import { ExportDrawer } from './ExportDrawer';
+import { OverlaysDrawer } from './OverlaysDrawer';
 import { ProjectInfoDrawer } from './ProjectInfoDrawer';
-import { PluginsDrawer } from './PluginDrawer';
+import { ReactionDrawer } from './ReactionDrawer';
+import { SearchDrawerWrapper as SearchDrawerContent } from './SearchDrawerWrapper';
+import { SubmapsDrawer } from './SubmapsDrawer';
 
 export const Drawer = (): JSX.Element => {
   const { isOpen, drawerName } = useAppSelector(drawerSelector);
@@ -29,7 +29,7 @@ export const Drawer = (): JSX.Element => {
       {isOpen && drawerName === 'bio-entity' && <BioEntityDrawer />}
       {isOpen && drawerName === 'project-info' && <ProjectInfoDrawer />}
       {isOpen && drawerName === 'export' && <ExportDrawer />}
-      {isOpen && drawerName === 'plugins' && <PluginsDrawer />}
+      {isOpen && drawerName === 'available-plugins' && <AvailablePluginsDrawer />}
     </div>
   );
 };
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..74f6839491421bf93129b446cc6d543636b7961f
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.test.ts
@@ -0,0 +1,91 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { initialMapStateFixture } from '@/redux/map/map.fixtures';
+import { LinePoint } from '@/types/reactions';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
+import { Feature } from 'ol';
+import { Geometry } from 'ol/geom';
+import { createOverlayLineFeature } from './createOverlayLineFeature';
+
+/* eslint-disable no-magic-numbers */
+const CASES: [LinePoint, number[]][] = [
+  [
+    [
+      { x: 0, y: 0 },
+      { x: 0, y: 0 },
+    ],
+    [0, 0, 0, 0],
+  ],
+  [
+    [
+      { x: 0, y: 0 },
+      { x: 100, y: 100 },
+    ],
+    [0, -238107693, Infinity, 0],
+  ],
+  [
+    [
+      { x: 100, y: 100 },
+      { x: 0, y: 0 },
+    ],
+    [0, -238107693, Infinity, 0],
+  ],
+  [
+    [
+      { x: 100, y: 0 },
+      { x: 0, y: 100 },
+    ],
+    [0, 0, 0, 0],
+  ],
+  [
+    [
+      { x: -50, y: 0 },
+      { x: 0, y: -50 },
+    ],
+    [0, 0, 0, 0],
+  ],
+];
+
+const COLOR = '#FFB3B3cc';
+
+const getFeature = (linePoint: LinePoint): Feature<Geometry> => {
+  const { Wrapper } = getReduxWrapperWithStore({
+    map: initialMapStateFixture,
+  });
+  const {
+    result: { current: pointToProjection },
+  } = renderHook(() => usePointToProjection(), {
+    wrapper: Wrapper,
+  });
+
+  return createOverlayLineFeature(linePoint, { pointToProjection, color: COLOR });
+};
+
+describe('createOverlayLineFeature - util', () => {
+  it.each(CASES)('should return Feature instance', linePoint => {
+    const feature = getFeature(linePoint);
+
+    expect(feature).toBeInstanceOf(Feature);
+  });
+
+  it.each(CASES)('should return Feature instance with valid style and stroke', linePoint => {
+    const feature = getFeature(linePoint);
+    const style = feature.getStyle();
+
+    expect(style).toMatchObject({
+      fill_: { color_: COLOR },
+      stroke_: {
+        color_: COLOR,
+        width_: LINE_WIDTH,
+      },
+    });
+  });
+
+  it.each(CASES)('should return Feature instance with valid geometry', (linePoint, extent) => {
+    const feature = getFeature(linePoint);
+    const geometry = feature.getGeometry();
+
+    expect(geometry?.getExtent()).toEqual(extent);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b38d603bbb793c6578722f2c8170cd8f5c895b51
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/createOverlayLineFeature.ts
@@ -0,0 +1,22 @@
+import { LinePoint } from '@/types/reactions';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import { Feature } from 'ol';
+import { SimpleGeometry } from 'ol/geom';
+import { getLineFeature } from '../reactionsLayer/getLineFeature';
+import { getOverlayLineFeatureStyle } from './getOverlayLineFeatureStyle';
+
+interface Options {
+  color: string;
+  pointToProjection: UsePointToProjectionResult;
+}
+
+export const createOverlayLineFeature = (
+  points: LinePoint,
+  { color, pointToProjection }: Options,
+): Feature<SimpleGeometry> => {
+  const feature = getLineFeature(points, pointToProjection);
+
+  feature.setStyle(getOverlayLineFeatureStyle(color));
+
+  return feature;
+};
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..174c620d5c12b95a9033da7cf11a04a942302c91
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.test.ts
@@ -0,0 +1,27 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { Fill, Stroke, Style } from 'ol/style';
+import { getOverlayLineFeatureStyle } from './getOverlayLineFeatureStyle';
+
+const COLORS = ['#000000', '#FFFFFF', '#F5F5F5', '#C0C0C0', '#C0C0C0aa', '#C0C0C0bb'];
+
+describe('getOverlayLineFeatureStyle - util', () => {
+  it.each(COLORS)('should return Style object', color => {
+    const result = getOverlayLineFeatureStyle(color);
+    expect(result).toBeInstanceOf(Style);
+  });
+
+  it.each(COLORS)('should set valid color values for Fill', color => {
+    const result = getOverlayLineFeatureStyle(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 = getOverlayLineFeatureStyle(color);
+    const stroke = result.getStroke();
+    expect(stroke).toBeInstanceOf(Stroke);
+    expect(stroke?.getColor()).toBe(color);
+    expect(stroke?.getWidth()).toBe(LINE_WIDTH);
+  });
+});
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts
new file mode 100644
index 0000000000000000000000000000000000000000..407c2416bbcee994a3d954d866520e0f2d65064c
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/getOverlayLineFeatureStyle.ts
@@ -0,0 +1,5 @@
+import { LINE_WIDTH } from '@/constants/canvas';
+import { Fill, Stroke, Style } from 'ol/style';
+
+export const getOverlayLineFeatureStyle = (color: string): Style =>
+  new Style({ fill: new Fill({ color }), stroke: new Stroke({ color, width: LINE_WIDTH }) });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
index b580a998904b2975b82c0a527aa805c748c38288..61841611e83b4818cf7c1382cc0ff8795e85996e 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useGetOverlayColor.test.ts
@@ -1,7 +1,7 @@
-import { renderHook } from '@testing-library/react';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
 import { useGetOverlayColor } from './useGetOverlayColor';
 
 describe('useOverlayFeatures - hook', () => {
@@ -20,6 +20,7 @@ describe('useOverlayFeatures - hook', () => {
 
   describe('getOverlayBioEntityColorByAvailableProperties - function', () => {
     const ENTITY: OverlayBioEntityRender = {
+      type: 'rectangle',
       id: 0,
       modelId: 0,
       x1: 0,
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
index 19c9b309415c6943c7c86e8b1fe477c606affe81..15c9cf3e5e9820d3d3f9d604bc19a7e5dad1c383 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.test.ts
@@ -1,11 +1,11 @@
 /* eslint-disable no-magic-numbers */
-import { renderHook } from '@testing-library/react';
-import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
 import { CONFIGURATION_INITIAL_STORE_MOCKS } from '@/redux/configuration/configuration.mock';
-import { OVERLAYS_PUBLIC_FETCHED_STATE_MOCK } from '@/redux/overlays/overlays.mock';
 import { mapStateWithCurrentlySelectedMainMapFixture } from '@/redux/map/map.fixtures';
 import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock';
 import { MOCKED_OVERLAY_BIO_ENTITY_RENDER } from '@/redux/overlayBioEntity/overlayBioEntity.mock';
+import { OVERLAYS_PUBLIC_FETCHED_STATE_MOCK } from '@/redux/overlays/overlays.mock';
+import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
+import { renderHook } from '@testing-library/react';
 import { useOverlayFeatures } from './useOverlayFeatures';
 
 /**
@@ -52,7 +52,9 @@ describe('useOverlayFeatures', () => {
       wrapper: Wrapper,
     });
 
-    expect(features).toHaveLength(6);
+    expect(features).toHaveLength(10);
+
+    // type: rectangle
     expect(features[0].getGeometry()?.getCoordinates()).toEqual([
       [
         [-13149141, 18867005],
@@ -65,5 +67,19 @@ describe('useOverlayFeatures', () => {
     // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-ignore
     expect(features[0].getStyle().getFill().getColor()).toBe('#FFFFFFcc');
+
+    // type: line
+    expect(features[7].getGeometry()?.getCoordinates()).toEqual([
+      [
+        [-13149141, 18867005],
+        [-13149141, 18881970],
+        [-13141659, 18881970],
+        [-13141659, 18867005],
+        [-13149141, 18867005],
+      ],
+    ]);
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
+    expect(features[7].getStyle().getFill().getColor()).toBe('#ff0000cc');
   });
 });
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
index 06985195eb9dafe82dbf23f616b3214945c9aff2..477a95dd324f06f8099d88db81055e7324b77d5f 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useOverlayFeatures.ts
@@ -1,18 +1,21 @@
-import { useMemo } from 'react';
-import { usePointToProjection } from '@/utils/map/usePointToProjection';
-import type Feature from 'ol/Feature';
-import type Polygon from 'ol/geom/Polygon';
 import { ZERO } from '@/constants/common';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import {
   getOverlayOrderSelector,
   overlayBioEntitiesForCurrentModelSelector,
 } from '@/redux/overlayBioEntity/overlayBioEntity.selector';
+import { LinePoint } from '@/types/reactions';
+import { usePointToProjection } from '@/utils/map/usePointToProjection';
+import type Feature from 'ol/Feature';
+import { SimpleGeometry } from 'ol/geom';
+import type Polygon from 'ol/geom/Polygon';
+import { useMemo } from 'react';
 import { createOverlayGeometryFeature } from './createOverlayGeometryFeature';
+import { createOverlayLineFeature } from './createOverlayLineFeature';
 import { getPolygonLatitudeCoordinates } from './getPolygonLatitudeCoordinates';
 import { useGetOverlayColor } from './useGetOverlayColor';
 
-export const useOverlayFeatures = (): Feature<Polygon>[] => {
+export const useOverlayFeatures = (): Feature<Polygon>[] | Feature<SimpleGeometry>[] => {
   const pointToProjection = usePointToProjection();
   const { getOverlayBioEntityColorByAvailableProperties } = useGetOverlayColor();
   const overlaysOrder = useAppSelector(getOverlayOrderSelector);
@@ -34,12 +37,27 @@ export const useOverlayFeatures = (): Feature<Polygon>[] => {
             overlaysOrder.find(({ id }) => id === entity.overlayId)?.index || ZERO,
         });
 
-        return createOverlayGeometryFeature(
+        const color = getOverlayBioEntityColorByAvailableProperties(entity);
+
+        if (entity.type === 'rectangle') {
+          return createOverlayGeometryFeature(
+            [
+              ...pointToProjection({ x: xMin, y: entity.y1 }),
+              ...pointToProjection({ x: xMax, y: entity.y2 }),
+            ],
+            color,
+          );
+        }
+
+        return createOverlayLineFeature(
           [
-            ...pointToProjection({ x: xMin, y: entity.y1 }),
-            ...pointToProjection({ x: xMax, y: entity.y2 }),
-          ],
-          getOverlayBioEntityColorByAvailableProperties(entity),
+            { x: entity.x1, y: entity.y1 },
+            { x: entity.x2, y: entity.y2 },
+          ] as LinePoint,
+          {
+            color,
+            pointToProjection,
+          },
         );
       }),
     [overlaysOrder, bioEntities, pointToProjection, getOverlayBioEntityColorByAvailableProperties],
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
index 40211171605c35ff87995e6ed9abf02bc300c76b..b7ce166ad5bf96b39976fc6d08fabb8fae5e6f1a 100644
--- a/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/getLineFeature.ts
@@ -1,12 +1,12 @@
 import { LinePoint } from '@/types/reactions';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
-import { LineString } from 'ol/geom';
+import { LineString, SimpleGeometry } from 'ol/geom';
 
 export const getLineFeature = (
   linePoints: LinePoint,
   pointToProjection: UsePointToProjectionResult,
-): Feature => {
+): Feature<SimpleGeometry> => {
   const points = linePoints.map(pointToProjection);
 
   return new Feature({
diff --git a/src/models/fixtures/overlayBioEntityFixture.ts b/src/models/fixtures/overlayBioEntityFixture.ts
index da0c6da654ba996874863860034ebf6856762054..4cdeaebfde4d08c304d56de8d8db889a385b7c85 100644
--- a/src/models/fixtures/overlayBioEntityFixture.ts
+++ b/src/models/fixtures/overlayBioEntityFixture.ts
@@ -2,9 +2,21 @@ import { ZOD_SEED } from '@/constants';
 import { z } from 'zod';
 // eslint-disable-next-line import/no-extraneous-dependencies
 import { createFixture } from 'zod-fixture';
-import { overlayBioEntitySchema } from '../overlayBioEntitySchema';
+import {
+  overlayBioEntitySchema,
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+} from '../overlayBioEntitySchema';
 
 export const overlayBioEntityFixture = createFixture(z.array(overlayBioEntitySchema), {
   seed: ZOD_SEED,
   array: { min: 3, max: 3 },
 });
+
+export const overlayElementWithReactionFixture = createFixture(overlayElementWithReactionSchema, {
+  seed: ZOD_SEED,
+});
+
+export const overlayElementWithBioEntityFixture = createFixture(overlayElementWithBioEntitySchema, {
+  seed: ZOD_SEED,
+});
diff --git a/src/models/mocks/pluginsMock.ts b/src/models/mocks/pluginsMock.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5c91eafdb32833dff36caedddfc4b85d9bac2f6
--- /dev/null
+++ b/src/models/mocks/pluginsMock.ts
@@ -0,0 +1,44 @@
+import { MinervaPlugin } from '@/types/models';
+
+export const PLUGINS_MOCK: MinervaPlugin[] = [
+  {
+    hash: '5e3fcb59588cc311ef9839feea6382eb',
+    name: 'Disease-variant associations',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/disease-associations/plugin.js'],
+  },
+  {
+    hash: '20df86476c311824bbfe73d1034af89e',
+    name: 'GSEA',
+    version: '0.9.2',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/gsea/plugin.js'],
+  },
+  {
+    hash: '5314b9f996e56e67f0dad65e7df8b73b',
+    name: 'PD map guide',
+    version: '1.0.2',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/guide/plugin.js'],
+  },
+  {
+    hash: 'b85ae2f4cd67736489b5fd2b635b1013',
+    name: 'Map exploation',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/exploration/plugin.js'],
+  },
+  {
+    hash: '77c32edf387652dfaad8a20f2a0ce76b',
+    name: 'Drug reactions',
+    version: '1.0.0',
+    isPublic: true,
+    isDefault: false,
+    urls: ['https://minerva-service.lcsb.uni.lu/plugins/drug-reactions/plugin.js'],
+  },
+];
diff --git a/src/models/overlayBioEntitySchema.ts b/src/models/overlayBioEntitySchema.ts
index d9dd58950b85a6d21bdde12e38e668af4d9b30e4..ffa8f5847d578da84236314ce036d5bc425d123c 100644
--- a/src/models/overlayBioEntitySchema.ts
+++ b/src/models/overlayBioEntitySchema.ts
@@ -1,8 +1,19 @@
 import { z } from 'zod';
 import { overlayLeftBioEntitySchema } from './overlayLeftBioEntitySchema';
+import { overlayLeftReactionSchema } from './overlayLeftReactionSchema';
 import { overlayRightBioEntitySchema } from './overlayRightBioEntitySchema';
 
-export const overlayBioEntitySchema = z.object({
+export const overlayElementWithBioEntitySchema = z.object({
   left: overlayLeftBioEntitySchema,
   right: overlayRightBioEntitySchema,
 });
+
+export const overlayElementWithReactionSchema = z.object({
+  left: overlayLeftReactionSchema,
+  right: overlayRightBioEntitySchema,
+});
+
+export const overlayBioEntitySchema = z.union([
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+]);
diff --git a/src/models/overlayLeftReactionSchema.ts b/src/models/overlayLeftReactionSchema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c47febcff7136233ac38e7d4c41c6eb3d85c2144
--- /dev/null
+++ b/src/models/overlayLeftReactionSchema.ts
@@ -0,0 +1,34 @@
+import { z } from 'zod';
+import { lineSchema } from './lineSchema';
+import { reactionProduct } from './reactionProduct';
+import { referenceSchema } from './referenceSchema';
+
+export const overlayLeftReactionSchema = z.object({
+  id: z.number(),
+  notes: z.string(),
+  idReaction: z.string(),
+  name: z.string(),
+  reversible: z.boolean(),
+  symbol: z.null(),
+  abbreviation: z.null(),
+  formula: z.null(),
+  mechanicalConfidenceScore: z.null(),
+  lowerBound: z.null(),
+  upperBound: z.null(),
+  subsystem: z.null(),
+  geneProteinReaction: z.null(),
+  visibilityLevel: z.string(),
+  z: z.number(),
+  synonyms: z.array(z.unknown()),
+  model: z.number(),
+  kinetics: z.null(),
+  line: lineSchema,
+  processCoordinates: z.null(),
+  stringType: z.string(),
+  modifiers: z.array(reactionProduct),
+  reactants: z.array(reactionProduct),
+  products: z.array(reactionProduct),
+  elementId: z.string(),
+  operators: z.array(z.unknown()),
+  references: z.array(referenceSchema),
+});
diff --git a/src/models/reactionProduct.ts b/src/models/reactionProduct.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96905877910e382f1736d595351286f5fa636807
--- /dev/null
+++ b/src/models/reactionProduct.ts
@@ -0,0 +1,9 @@
+import { z } from 'zod';
+import { lineSchema } from './lineSchema';
+
+export const reactionProduct = z.object({
+  id: z.number(),
+  line: lineSchema,
+  stoichiometry: z.null(),
+  element: z.number(),
+});
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index 1638e3328327a0791d63f174dea299d029ae0d3a..5193c5e4865e5ad7d21c71896c3e666f27392ed9 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -1,6 +1,6 @@
 import { PROJECT_ID } from '@/constants';
-import { PerfectSearchParams } from '@/types/search';
 import { Point } from '@/types/map';
+import { PerfectSearchParams } from '@/types/search';
 
 export const apiPath = {
   getBioEntityContentsStringWithQuery: ({
@@ -65,4 +65,5 @@ export const apiPath = {
   getTaxonomy: (taxonomyId: string): string => `taxonomy/${taxonomyId}`,
   registerPluign: (): string => `plugins/`,
   getPlugin: (pluginId: string): string => `plugins/${pluginId}/`,
+  getAllPlugins: (): string => `/plugins/`,
 };
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
index 84fab91d714d1acdbb49aa3275b6b5fe13cc668c..9b093c3eeaecee77b8fc2923f37f8cd3da8c5eec 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.mock.ts
@@ -8,6 +8,7 @@ export const OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK: OverlaysBioEntityState = {
 
 export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
   {
+    type: 'rectangle',
     id: 1,
     modelId: 52,
     width: 30,
@@ -21,6 +22,7 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     color: null,
   },
   {
+    type: 'rectangle',
     id: 2,
     modelId: 52,
     width: 30,
@@ -34,6 +36,7 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     color: null,
   },
   {
+    type: 'rectangle',
     id: 3,
     modelId: 52,
     width: 40,
@@ -46,4 +49,32 @@ export const MOCKED_OVERLAY_BIO_ENTITY_RENDER: OverlayBioEntityRender[] = [
     value: null,
     color: { rgb: -65536, alpha: 0 },
   },
+  {
+    type: 'line',
+    id: 66143,
+    modelId: 52,
+    x1: 4462.61826820353,
+    x2: 4571.99387254902,
+    y1: 7105.89040426431,
+    y2: 6979.823529411765,
+    width: 109.3756043454905,
+    height: 126.06687485254497,
+    value: null,
+    overlayId: 20,
+    color: null,
+  },
+  {
+    type: 'line',
+    id: 66144,
+    modelId: 52,
+    x1: 4454.850442288663,
+    x2: 4463.773636826477,
+    y1: 7068.434324866321,
+    y2: 7112.188429617157,
+    width: 8.923194537814197,
+    height: 43.75410475083663,
+    value: null,
+    overlayId: 20,
+    color: null,
+  },
 ];
diff --git a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
index 7c92f7a20080e78660bcf391194990c13940451b..6656d725badcafef167e19d63226804077ca4a21 100644
--- a/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
+++ b/src/redux/overlayBioEntity/overlayBioEntity.utils.ts
@@ -2,6 +2,8 @@ import { ONE } from '@/constants/common';
 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 { z } from 'zod';
 
 export const parseOverlayBioEntityToOlRenderingFormat = (
@@ -9,8 +11,16 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
   overlayId: number,
 ): OverlayBioEntityRender[] =>
   data.reduce((acc: OverlayBioEntityRender[], entity: OverlayBioEntity) => {
-    if (entity.left.x && entity.left.y) {
+    /**
+     * The're two types of entities - bioentity and reaction
+     * Bioentity comes with the single only element
+     * And reaction comes with many different lines that needs to be merged together
+     * Every reaction line is a different entity after reduce
+     */
+
+    if (isBioEntity(entity)) {
       acc.push({
+        type: 'rectangle',
         id: entity.left.id,
         modelId: entity.left.model,
         x1: entity.left.x,
@@ -24,6 +34,31 @@ export const parseOverlayBioEntityToOlRenderingFormat = (
         color: entity.right.color,
       });
     }
+
+    if (isReaction(entity)) {
+      const { products, reactants, modifiers } = entity.left;
+      const lines = [products, reactants, modifiers].flat().map(element => element.line);
+      const coords = lines.map(getOverlayReactionCoordsFromLine).flat();
+      const elements = coords.map(
+        ({ x1, x2, y1, y2, id, width, height }): OverlayBioEntityRender => ({
+          type: 'line',
+          id,
+          modelId: entity.left.model,
+          x1,
+          x2,
+          y1,
+          y2,
+          width,
+          height: Math.abs(height),
+          value: entity.right.value,
+          overlayId,
+          color: entity.right.color,
+        }),
+      );
+
+      acc.push(...elements);
+    }
+
     return acc;
   }, []);
 
diff --git a/src/redux/plugins/plugins.constants.ts b/src/redux/plugins/plugins.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0aa77a3a906e4ecbfaf61cd980008a2a1ed7a397
--- /dev/null
+++ b/src/redux/plugins/plugins.constants.ts
@@ -0,0 +1,9 @@
+import { PluginsState } from './plugins.types';
+
+export const PLUGINS_INITIAL_STATE: PluginsState = {
+  list: {
+    data: [],
+    loading: 'idle',
+    error: { name: '', message: '' },
+  },
+};
diff --git a/src/redux/plugins/plugins.mock.ts b/src/redux/plugins/plugins.mock.ts
index 63cae1392973ceefc6234e54248670450dbb1137..6cbfcf5594d0f65536392a3db11e3135224fdf25 100644
--- a/src/redux/plugins/plugins.mock.ts
+++ b/src/redux/plugins/plugins.mock.ts
@@ -1,6 +1,18 @@
-import { PluginsState } from './plugins.types';
+import { DEFAULT_ERROR } from '@/constants/errors';
+import { ActivePlugins, PluginsList, PluginsState } from './plugins.types';
 
-export const PLUGINS_INITIAL_STATE_MOCK: PluginsState = {
+export const PLUGINS_INITIAL_STATE__ACTIVE_PLUGINS_MOCK: ActivePlugins = {
   data: {},
   pluginsId: [],
 };
+
+export const PLUGINS_INITIAL_STATE_LIST_MOCK: PluginsList = {
+  data: [],
+  loading: 'idle',
+  error: DEFAULT_ERROR,
+};
+
+export const PLUGINS_INITIAL_STATE_MOCK: PluginsState = {
+  list: PLUGINS_INITIAL_STATE_LIST_MOCK,
+  activePlugins: PLUGINS_INITIAL_STATE__ACTIVE_PLUGINS_MOCK,
+};
diff --git a/src/redux/plugins/plugins.reducers.ts b/src/redux/plugins/plugins.reducers.ts
index af01fcfcd7d2ba2ea63be763e828ea1cea6cc4ba..31c0b6f96c04f683f32bbb6f90400c7e40c03b25 100644
--- a/src/redux/plugins/plugins.reducers.ts
+++ b/src/redux/plugins/plugins.reducers.ts
@@ -1,26 +1,40 @@
 import type { ActionReducerMapBuilder } from '@reduxjs/toolkit';
 import type { PluginsState, RemovePluginAction } from './plugins.types';
-import { registerPlugin } from './plugins.thunk';
+import { registerPlugin, getAllPlugins } from './plugins.thunk';
 
 export const removePluginReducer = (state: PluginsState, action: RemovePluginAction): void => {
   const { pluginId } = action.payload;
-  state.pluginsId = state.pluginsId.filter(id => id !== pluginId);
-  delete state.data[pluginId];
+  state.activePlugins.pluginsId = state.activePlugins.pluginsId.filter(id => id !== pluginId);
+  delete state.activePlugins.data[pluginId];
 };
 
 export const registerPluginReducer = (builder: ActionReducerMapBuilder<PluginsState>): void => {
   builder.addCase(registerPlugin.pending, (state, action) => {
     const { hash } = action.meta.arg;
-    state.pluginsId.push(hash);
+    state.activePlugins.pluginsId.push(hash);
   });
   builder.addCase(registerPlugin.fulfilled, (state, action) => {
     if (action.payload) {
       const { hash } = action.meta.arg;
 
-      state.data[hash] = action.payload;
+      state.activePlugins.data[hash] = action.payload;
     }
   });
   builder.addCase(registerPlugin.rejected, state => {
-    state.pluginsId = [];
+    state.activePlugins.pluginsId = [];
+  });
+};
+
+export const getAllPluginsReducer = (builder: ActionReducerMapBuilder<PluginsState>): void => {
+  builder.addCase(getAllPlugins.pending, state => {
+    state.list.loading = 'pending';
+  });
+  builder.addCase(getAllPlugins.fulfilled, (state, action) => {
+    state.list.data = action.payload || [];
+    state.list.loading = 'succeeded';
+  });
+  builder.addCase(getAllPlugins.rejected, state => {
+    state.list.loading = 'failed';
+    // TODO to discuss manage state of failure
   });
 };
diff --git a/src/redux/plugins/plugins.selectors.ts b/src/redux/plugins/plugins.selectors.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ece3dd2e529230dd8f85c413703675ebd7de90d
--- /dev/null
+++ b/src/redux/plugins/plugins.selectors.ts
@@ -0,0 +1,19 @@
+import { createSelector } from '@reduxjs/toolkit';
+import { rootSelector } from '../root/root.selectors';
+
+export const pluginsSelector = createSelector(rootSelector, state => state.plugins);
+
+export const pluginsListSelector = createSelector(pluginsSelector, plugins => {
+  return plugins.list;
+});
+
+export const pluginsListDataSelector = createSelector(pluginsListSelector, pluginsList => {
+  return pluginsList.data;
+});
+
+export const publicPluginsListSelector = createSelector(
+  pluginsListDataSelector,
+  pluginsListData => {
+    return (pluginsListData || []).filter(plugin => plugin.isPublic);
+  },
+);
diff --git a/src/redux/plugins/plugins.slice.ts b/src/redux/plugins/plugins.slice.ts
index be87d49638c587e2fafd19bc709daad157c72476..aeb408420001e991c41e1a060c280880450af4af 100644
--- a/src/redux/plugins/plugins.slice.ts
+++ b/src/redux/plugins/plugins.slice.ts
@@ -1,23 +1,23 @@
 import { createSlice } from '@reduxjs/toolkit';
-import type { PluginsState } from './plugins.types';
-import { registerPluginReducer, removePluginReducer } from './plugins.reducers';
+import {
+  registerPluginReducer,
+  removePluginReducer,
+  getAllPluginsReducer,
+} from './plugins.reducers';
 
-const initialState: PluginsState = {
-  pluginsId: [],
-  data: {},
-};
+import { PLUGINS_INITIAL_STATE } from './plugins.constants';
 
-export const pluginsSlice = createSlice({
+const pluginsSlice = createSlice({
   name: 'plugins',
-  initialState,
+  initialState: PLUGINS_INITIAL_STATE,
   reducers: {
     removePlugin: removePluginReducer,
   },
   extraReducers: builder => {
     registerPluginReducer(builder);
+    getAllPluginsReducer(builder);
   },
 });
 
 export const { removePlugin } = pluginsSlice.actions;
-
 export default pluginsSlice.reducer;
diff --git a/src/redux/plugins/plugins.thunks.ts b/src/redux/plugins/plugins.thunks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..732cfdcb4fcadb1b83a804bb51c8f581d2269f50
--- /dev/null
+++ b/src/redux/plugins/plugins.thunks.ts
@@ -0,0 +1,18 @@
+import { pluginSchema } from '@/models/pluginSchema';
+import { axiosInstance } from '@/services/api/utils/axiosInstance';
+import { MinervaPlugin } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+import { createAsyncThunk } from '@reduxjs/toolkit';
+import { z } from 'zod';
+import { apiPath } from '../apiPath';
+
+export const getAllPlugins = createAsyncThunk(
+  'plugins/getAllPlugins',
+  async (): Promise<MinervaPlugin[]> => {
+    const response = await axiosInstance.get<MinervaPlugin[]>(apiPath.getAllPlugins());
+
+    const isDataValid = validateDataUsingZodSchema(response.data, z.array(pluginSchema));
+
+    return isDataValid ? response.data : [];
+  },
+);
diff --git a/src/redux/plugins/plugins.types.ts b/src/redux/plugins/plugins.types.ts
index 903fe01c45c8d564cf1ebaf3c286c8b159db3e9b..2569f12845cc3394a7b8897e9133745a52cb9fa6 100644
--- a/src/redux/plugins/plugins.types.ts
+++ b/src/redux/plugins/plugins.types.ts
@@ -1,12 +1,20 @@
 import { PayloadAction } from '@reduxjs/toolkit';
-import { Plugin } from '@/types/models';
 
-export type PluginsState = {
+import { FetchDataState } from '@/types/fetchDataState';
+import { MinervaPlugin } from '@/types/models';
+
+export type RemovePluginPayload = { pluginId: string };
+export type RemovePluginAction = PayloadAction<RemovePluginPayload>;
+
+export type PluginsList = FetchDataState<MinervaPlugin[]>;
+export type ActivePlugins = {
   pluginsId: string[];
   data: {
-    [pluginId: string]: Plugin | undefined;
+    [pluginId: string]: MinervaPlugin;
   };
 };
 
-export type RemovePluginPayload = { pluginId: string };
-export type RemovePluginAction = PayloadAction<RemovePluginPayload>;
+export type PluginsState = {
+  list: PluginsList;
+  activePlugins: ActivePlugins;
+};
diff --git a/src/redux/root/init.thunks.ts b/src/redux/root/init.thunks.ts
index a04a5a92496b0b54075b5a852e147636d7eea1cc..e193bf73c656e1ad8dbb25097dc217a6e4ea3060 100644
--- a/src/redux/root/init.thunks.ts
+++ b/src/redux/root/init.thunks.ts
@@ -1,27 +1,28 @@
-import { openSearchDrawerWithSelectedTab } from '@/redux/drawer/drawer.slice';
-import { createAsyncThunk } from '@reduxjs/toolkit';
 import { PROJECT_ID } from '@/constants';
+import { openSearchDrawerWithSelectedTab } from '@/redux/drawer/drawer.slice';
 import { AppDispatch } from '@/redux/store';
 import { QueryData } from '@/types/query';
 import { getDefaultSearchTab } from '@/components/FunctionalArea/TopBar/SearchBar/SearchBar.utils';
 import { PluginsManager } from '@/services/pluginsManager';
+import { createAsyncThunk } from '@reduxjs/toolkit';
 import { getAllBackgroundsByProjectId } from '../backgrounds/backgrounds.thunks';
-import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
-import { getModels } from '../models/models.thunks';
-import { getProjectById } from '../project/project.thunks';
+import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks';
 import {
   initMapBackground,
   initMapPosition,
   initMapSizeAndModelId,
   initOpenedMaps,
 } from '../map/map.thunks';
-import { getSearchData } from '../search/search.thunks';
-import { setPerfectMatch } from '../search/search.slice';
-import { getSessionValid } from '../user/user.thunks';
+import { getModels } from '../models/models.thunks';
 import { getInitOverlays } from '../overlayBioEntity/overlayBioEntity.thunk';
-import { getConfiguration, getConfigurationOptions } from '../configuration/configuration.thunks';
+import { getAllPublicOverlaysByProjectId } from '../overlays/overlays.thunks';
+import { getAllPlugins } from '../plugins/plugins.thunks';
+import { getProjectById } from '../project/project.thunks';
+import { setPerfectMatch } from '../search/search.slice';
+import { getSearchData } from '../search/search.thunks';
 import { getStatisticsById } from '../statistics/statistics.thunks';
 import { getInitPlugins } from '../plugins/plugins.thunk';
+import { getSessionValid } from '../user/user.thunks';
 
 interface InitializeAppParams {
   queryData: QueryData;
@@ -57,6 +58,9 @@ export const fetchInitialAppData = createAsyncThunk<
   dispatch(getStatisticsById(PROJECT_ID));
   dispatch(getConfiguration());
 
+  // Fetch plugins list
+  dispatch(getAllPlugins());
+
   /** Trigger search */
   if (queryData.searchValue) {
     dispatch(setPerfectMatch(queryData.perfectMatch));
diff --git a/src/redux/root/root.fixtures.ts b/src/redux/root/root.fixtures.ts
index bfb6570be66aa04a3c47be5f9c9a26a46451b25f..8bfe3f1bcafc071a633a9da208708244fb101015 100644
--- a/src/redux/root/root.fixtures.ts
+++ b/src/redux/root/root.fixtures.ts
@@ -1,26 +1,26 @@
 import { BACKGROUND_INITIAL_STATE_MOCK } from '../backgrounds/background.mock';
 import { BIOENTITY_INITIAL_STATE_MOCK } from '../bioEntity/bioEntity.mock';
 import { CHEMICALS_INITIAL_STATE_MOCK } from '../chemicals/chemicals.mock';
+import { COMPARTMENT_PATHWAYS_INITIAL_STATE_MOCK } from '../compartmentPathways/compartmentPathways.mock';
 import { CONFIGURATION_INITIAL_STATE } from '../configuration/configuration.adapter';
 import { CONTEXT_MENU_INITIAL_STATE } from '../contextMenu/contextMenu.constants';
 import { COOKIE_BANNER_INITIAL_STATE_MOCK } from '../cookieBanner/cookieBanner.mock';
 import { initialStateFixture as drawerInitialStateMock } from '../drawer/drawerFixture';
 import { DRUGS_INITIAL_STATE_MOCK } from '../drugs/drugs.mock';
+import { EXPORT_INITIAL_STATE_MOCK } from '../export/export.mock';
 import { LEGEND_INITIAL_STATE_MOCK } from '../legend/legend.mock';
 import { initialMapStateFixture } from '../map/map.fixtures';
 import { MODAL_INITIAL_STATE_MOCK } from '../modal/modal.mock';
 import { MODELS_INITIAL_STATE_MOCK } from '../models/models.mock';
 import { OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK } from '../overlayBioEntity/overlayBioEntity.mock';
 import { OVERLAYS_INITIAL_STATE_MOCK } from '../overlays/overlays.mock';
+import { PLUGINS_INITIAL_STATE_MOCK } from '../plugins/plugins.mock';
 import { PROJECT_STATE_INITIAL_MOCK } from '../project/project.mock';
 import { REACTIONS_STATE_INITIAL_MOCK } from '../reactions/reactions.mock';
 import { SEARCH_STATE_INITIAL_MOCK } from '../search/search.mock';
+import { STATISTICS_STATE_INITIAL_MOCK } from '../statistics/statistics.mock';
 import { RootState } from '../store';
 import { USER_INITIAL_STATE_MOCK } from '../user/user.mock';
-import { STATISTICS_STATE_INITIAL_MOCK } from '../statistics/statistics.mock';
-import { COMPARTMENT_PATHWAYS_INITIAL_STATE_MOCK } from '../compartmentPathways/compartmentPathways.mock';
-import { EXPORT_INITIAL_STATE_MOCK } from '../export/export.mock';
-import { PLUGINS_INITIAL_STATE_MOCK } from '../plugins/plugins.mock';
 
 export const INITIAL_STORE_STATE_MOCK: RootState = {
   search: SEARCH_STATE_INITIAL_MOCK,
diff --git a/src/redux/store.ts b/src/redux/store.ts
index a515461172f3468e39668a4b5606a4df24528938..4e7447eba76d7e6d33cb5f70ffc8fc9b096ade8a 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -22,12 +22,12 @@ import {
   TypedStartListening,
   configureStore,
 } from '@reduxjs/toolkit';
-import legendReducer from './legend/legend.slice';
-import { mapListenerMiddleware } from './map/middleware/map.middleware';
-import statisticsReducer from './statistics/statistics.slice';
 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';
 
 export const reducers = {
   search: searchReducer,
diff --git a/src/types/OLrendering.ts b/src/types/OLrendering.ts
index 11ab030c2ca0dd67874f94da6b29309e81f52e1c..6aee24d703ddc7ab5c39bf21644ad91895886891 100644
--- a/src/types/OLrendering.ts
+++ b/src/types/OLrendering.ts
@@ -1,5 +1,7 @@
 import { Color } from './models';
 
+export type OverlayBioEntityRenderType = 'line' | 'rectangle';
+
 export type OverlayBioEntityRender = {
   id: number;
   modelId: number;
@@ -16,4 +18,15 @@ export type OverlayBioEntityRender = {
   value: number | null;
   overlayId: number;
   color: Color | null;
+  type: OverlayBioEntityRenderType;
 };
+
+export interface OverlayReactionCoords {
+  x1: number;
+  x2: number;
+  y1: number;
+  y2: number;
+  id: number;
+  height: number;
+  width: number;
+}
diff --git a/src/types/drawerName.ts b/src/types/drawerName.ts
index a5f3e3d2ff2f0155c67bdb1a458fc2ce64c5764f..3715c57ddd45995b4c8194a917bf0ad8a129b5f4 100644
--- a/src/types/drawerName.ts
+++ b/src/types/drawerName.ts
@@ -8,4 +8,5 @@ export type DrawerName =
   | 'submaps'
   | 'reaction'
   | 'overlays'
-  | 'bio-entity';
+  | 'bio-entity'
+  | 'available-plugins';
diff --git a/src/types/models.ts b/src/types/models.ts
index d46b347f7d6e3fa6c0f12b87a9949d3f94d82271..293fd8ffe08e9930c8d2b88385a697b16834106e 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -12,7 +12,8 @@ import { configurationSchema, formatSchema, miriamTypesSchema } from '@/models/c
 import { disease } from '@/models/disease';
 import { drugSchema } from '@/models/drugSchema';
 import { elementSearchResult, elementSearchResultType } from '@/models/elementSearchResult';
-import { exportNetworkchema, exportElementsSchema } from '@/models/exportSchema';
+import { exportElementsSchema, exportNetworkchema } from '@/models/exportSchema';
+import { lineSchema } from '@/models/lineSchema';
 import { loginSchema } from '@/models/loginSchema';
 import { mapBackground } from '@/models/mapBackground';
 import {
@@ -23,7 +24,13 @@ import {
 } from '@/models/mapOverlay';
 import { mapModelSchema } from '@/models/modelSchema';
 import { organism } from '@/models/organism';
-import { overlayBioEntitySchema } from '@/models/overlayBioEntitySchema';
+import {
+  overlayBioEntitySchema,
+  overlayElementWithBioEntitySchema,
+  overlayElementWithReactionSchema,
+} from '@/models/overlayBioEntitySchema';
+import { overlayLeftBioEntitySchema } from '@/models/overlayLeftBioEntitySchema';
+import { overlayLeftReactionSchema } from '@/models/overlayLeftReactionSchema';
 import {
   overviewImageLink,
   overviewImageLinkImage,
@@ -68,6 +75,11 @@ export type Configuration = z.infer<typeof configurationSchema>;
 export type ConfigurationFormatSchema = z.infer<typeof formatSchema>;
 export type ConfigurationMiramiTypes = z.infer<typeof miriamTypesSchema>;
 export type OverlayBioEntity = z.infer<typeof overlayBioEntitySchema>;
+export type OverlayElementWithReaction = z.infer<typeof overlayElementWithReactionSchema>;
+export type OverlayElementWithBioEntity = z.infer<typeof overlayElementWithBioEntitySchema>;
+export type OverlayLeftBioEntity = z.infer<typeof overlayLeftBioEntitySchema>;
+export type OverlayLeftReaction = z.infer<typeof overlayLeftReactionSchema>;
+export type Line = z.infer<typeof lineSchema>;
 export type CreatedOverlayFile = z.infer<typeof createdOverlayFileSchema>;
 export type UploadedOverlayFileContent = z.infer<typeof uploadedOverlayFileContentSchema>;
 export type CreatedOverlay = z.infer<typeof createdOverlaySchema>;
@@ -77,4 +89,4 @@ export type CompartmentPathway = z.infer<typeof compartmentPathwaySchema>;
 export type CompartmentPathwayDetails = z.infer<typeof compartmentPathwayDetailsSchema>;
 export type ExportNetwork = z.infer<typeof exportNetworkchema>;
 export type ExportElements = z.infer<typeof exportElementsSchema>;
-export type Plugin = z.infer<typeof pluginSchema>;
+export type MinervaPlugin = z.infer<typeof pluginSchema>; // Plugin type interfers with global Plugin type
diff --git a/src/utils/overlays/getOverlayReactionCoords.test.ts b/src/utils/overlays/getOverlayReactionCoords.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6d5d2ea1b023364c6ad7d5e06b0a5f062d5cec1c
--- /dev/null
+++ b/src/utils/overlays/getOverlayReactionCoords.test.ts
@@ -0,0 +1,85 @@
+import { OverlayReactionCoords } from '@/types/OLrendering';
+import { Line } from '@/types/models';
+import { getOverlayReactionCoordsFromLine } from './getOverlayReactionCoords';
+
+const LINE_DATA_BASE: Line = {
+  id: 66141,
+  width: 1,
+  color: {
+    alpha: 255,
+    rgb: -16777216,
+  },
+  z: 0,
+  segments: [
+    {
+      x1: 4457.375604345491,
+      y1: 7111.933125147456,
+      x2: 4462.61826820353,
+      y2: 7105.89040426431,
+    },
+  ],
+  startArrow: {
+    arrowType: 'NONE',
+    angle: 2.748893571891069,
+    lineType: 'SOLID',
+    length: 15,
+  },
+  endArrow: {
+    arrowType: 'NONE',
+    angle: 2.748893571891069,
+    lineType: 'SOLID',
+    length: 15,
+  },
+  lineType: 'SOLID',
+};
+
+describe('getOverlayReactionCoords - util', () => {
+  const cases: [Line, OverlayReactionCoords[]][] = [
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 10,
+            y1: 10,
+            x2: 100,
+            y2: 100,
+          },
+        ],
+      },
+      [{ height: -90, id: 66141, width: 90, x1: 10, x2: 100, y1: 10, y2: 100 }],
+    ],
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 10,
+            y1: 10,
+            x2: 2000,
+            y2: 0,
+          },
+        ],
+      },
+      [{ height: 10, id: 66141, width: 1990, x1: 10, x2: 2000, y1: 10, y2: 0 }],
+    ],
+    [
+      {
+        ...LINE_DATA_BASE,
+        segments: [
+          {
+            x1: 0,
+            y1: 0,
+            x2: 0,
+            y2: 0,
+          },
+        ],
+      },
+      [{ height: 0, id: 66141, width: 0, x1: 0, x2: 0, y1: 0, y2: 0 }],
+    ],
+  ];
+
+  it.each(cases)('should return valid result', (line, result) => {
+    expect(getOverlayReactionCoordsFromLine(line)).toStrictEqual(result);
+  });
+});
diff --git a/src/utils/overlays/getOverlayReactionCoords.ts b/src/utils/overlays/getOverlayReactionCoords.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c607fcde6e01f08334f0a38122646ec145fe17cc
--- /dev/null
+++ b/src/utils/overlays/getOverlayReactionCoords.ts
@@ -0,0 +1,14 @@
+import { OverlayReactionCoords } from '@/types/OLrendering';
+import { Line } from '@/types/models';
+
+export const getOverlayReactionCoordsFromLine = (line: Line): OverlayReactionCoords[] =>
+  line.segments.map(segment => {
+    const { x1, y1, x2, y2 } = segment;
+
+    return {
+      ...segment,
+      id: line.id,
+      width: x2 - x1,
+      height: y1 - y2,
+    };
+  });
diff --git a/src/utils/overlays/overlaysElementsTypeGuards.test.ts b/src/utils/overlays/overlaysElementsTypeGuards.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19028e2c88aa16431ee269d267a531998004d189
--- /dev/null
+++ b/src/utils/overlays/overlaysElementsTypeGuards.test.ts
@@ -0,0 +1,35 @@
+import {
+  overlayElementWithBioEntityFixture,
+  overlayElementWithReactionFixture,
+} from '@/models/fixtures/overlayBioEntityFixture';
+import { isBioEntity, isReaction } from './overlaysElementsTypeGuards';
+
+describe('overlaysElementsTypeGruards - utils', () => {
+  describe('isReaction', () => {
+    describe('when is reaction', () => {
+      it('should return true', () => {
+        expect(isReaction(overlayElementWithReactionFixture)).toBe(true);
+      });
+    });
+
+    describe('when is bioentity', () => {
+      it('should return false', () => {
+        expect(isReaction(overlayElementWithBioEntityFixture)).toBe(false);
+      });
+    });
+  });
+
+  describe('isBioEntity', () => {
+    describe('when is reaction', () => {
+      it('should return false', () => {
+        expect(isBioEntity(overlayElementWithReactionFixture)).toBe(false);
+      });
+    });
+
+    describe('when is bioentity', () => {
+      it('should return true', () => {
+        expect(isBioEntity(overlayElementWithBioEntityFixture)).toBe(true);
+      });
+    });
+  });
+});
diff --git a/src/utils/overlays/overlaysElementsTypeGuards.ts b/src/utils/overlays/overlaysElementsTypeGuards.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6997b141f5d627b5d4641ee23c2f7b902f17a1af
--- /dev/null
+++ b/src/utils/overlays/overlaysElementsTypeGuards.ts
@@ -0,0 +1,14 @@
+import {
+  OverlayBioEntity,
+  OverlayElementWithBioEntity,
+  OverlayElementWithReaction,
+  OverlayLeftBioEntity,
+  OverlayLeftReaction,
+} from '@/types/models';
+
+export const isReaction = (e: OverlayBioEntity): e is OverlayElementWithReaction =>
+  (e.left as OverlayLeftReaction).line !== undefined;
+
+export const isBioEntity = (e: OverlayBioEntity): e is OverlayElementWithBioEntity =>
+  (e.left as OverlayLeftBioEntity).x !== undefined &&
+  (e.left as OverlayLeftBioEntity).y !== undefined;