From df9dfdc8a0bc3e509b3f47eeef3c326f5e277863 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Fri, 20 Dec 2024 11:46:33 +0100
Subject: [PATCH 1/3] download button should download selected map

---
 CHANGELOG                                        |  1 +
 .../DownloadSubmap.component.test.tsx            |  4 ++--
 .../DownloadSubmap/DownloadSubmap.component.tsx  |  8 ++++++--
 .../utils/useGetSubmapDownloadUrl.test.ts        |  4 ++--
 .../utils/useGetSubmapDownloadUrl.ts             | 16 ++++++++++------
 .../SubmapItem/SubmapItem.component.tsx          |  5 +++--
 .../Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx   |  1 +
 7 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 93c128e9..c918ec8a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,6 @@
 minerva-front (18.0.8) stable; urgency=medium
   * Bug fix: data overlay removal did not work (#333)
+  * Bug fix: submap download did not download selected map (#337)
 
 -- Piotr Gawron <piotr.gawron@uni.lu>  Fri, 13 Dec 2024 13:00:00 +0200
 
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx
index a30986f5..d90df2bb 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.test.tsx
@@ -87,7 +87,7 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St
   return (
     render(
       <Wrapper>
-        <DownloadSubmap />
+        <DownloadSubmap modelId={VALID_MODEL_ID} />
       </Wrapper>,
     ),
     {
@@ -136,7 +136,7 @@ describe('DownloadSubmap - component', () => {
     const list = screen.getByTestId('download-submap-list');
 
     const validHrefs = CONFIGURATION_FORMATS_MOCK.map(({ handler }) =>
-      getSubmapDownloadUrl({ handler }),
+      getSubmapDownloadUrl({ handler, modelId: VALID_MODEL_ID }),
     );
     const validNames = CONFIGURATION_FORMATS_TYPES_MOCK;
     const allAnchors = [...list.getElementsByTagName('a')];
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx
index 31652812..5f047bc2 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/DownloadSubmap.component.tsx
@@ -9,7 +9,11 @@ import { downloadFileFromUrl } from '@/redux/export/export.utils';
 import { SUBMAP_DOWNLOAD_HANDLERS_NAMES } from './DownloadSubmap.constants';
 import { useGetSubmapDownloadUrl } from './utils/useGetSubmapDownloadUrl';
 
-export const DownloadSubmap = (): React.ReactNode => {
+interface DownloadSubmapProps {
+  modelId: number;
+}
+
+export const DownloadSubmap = ({ modelId }: DownloadSubmapProps): React.ReactNode => {
   const formatsHandlers = useSelector(formatsHandlersSelector);
   const formatsHandlersItems = Object.entries(formatsHandlers);
   const getSubmapDownloadUrl = useGetSubmapDownloadUrl();
@@ -24,7 +28,7 @@ export const DownloadSubmap = (): React.ReactNode => {
     return function () {
       closeMenu();
       setIsDownloading(true);
-      downloadFileFromUrl(getSubmapDownloadUrl({ handler })).finally(function () {
+      downloadFileFromUrl(getSubmapDownloadUrl({ handler, modelId })).finally(function () {
         setIsDownloading(false);
       });
     };
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts
index c8f335bf..5a911656 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.test.ts
@@ -91,7 +91,7 @@ describe('useGetSubmapDownloadUrl - hook', () => {
         result: { current: getSubmapDownloadUrl },
       } = renderHook(() => useGetSubmapDownloadUrl(), { wrapper: Wrapper });
 
-      expect(getSubmapDownloadUrl({ handler })).toBe('');
+      expect(getSubmapDownloadUrl({ handler, modelId: 0 })).toBe('');
     });
   });
 
@@ -109,7 +109,7 @@ describe('useGetSubmapDownloadUrl - hook', () => {
         result: { current: getSubmapDownloadUrl },
       } = renderHook(() => useGetSubmapDownloadUrl(), { wrapper: Wrapper });
 
-      expect(getSubmapDownloadUrl({ handler: VALID_HANDLER })).toBe(
+      expect(getSubmapDownloadUrl({ handler: VALID_HANDLER, modelId: 5052 })).toBe(
         `${BASE_API_URL}/projects/${PROJECT_ID}/models/5052:downloadModel?backgroundOverlayId=53&handlerClass=lcsb.mapviewer.wikipathway.GpmlParser&zoomLevel=9`,
       );
     });
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts
index e003af36..34c33260 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/DownloadSubmap/utils/useGetSubmapDownloadUrl.ts
@@ -1,18 +1,22 @@
 import { BASE_API_URL, PROJECT_ID } from '@/constants';
 import { currentBackgroundSelector } from '@/redux/backgrounds/background.selectors';
 import { mapDataSizeSelector } from '@/redux/map/map.selectors';
-import { currentModelSelector } from '@/redux/models/models.selectors';
 import { useSelector } from 'react-redux';
 
-export type GetSubmapDownloadUrl = ({ handler }: { handler: string }) => string;
+export type GetSubmapDownloadUrl = ({
+  handler,
+  modelId,
+}: {
+  handler: string;
+  modelId: number;
+}) => string;
 
 export const useGetSubmapDownloadUrl = (): GetSubmapDownloadUrl => {
-  const model = useSelector(currentModelSelector);
   const background = useSelector(currentBackgroundSelector);
   const mapSize = useSelector(mapDataSizeSelector);
 
-  const getSubmapDownloadUrl: GetSubmapDownloadUrl = ({ handler }) => {
-    const allParamsValid = [model?.idObject, background?.id, mapSize.maxZoom, handler].reduce(
+  const getSubmapDownloadUrl: GetSubmapDownloadUrl = ({ handler, modelId }) => {
+    const allParamsValid = [modelId, background?.id, mapSize.maxZoom, handler].reduce(
       (a, b) => Boolean(a) && Boolean(b),
       true,
     );
@@ -20,7 +24,7 @@ export const useGetSubmapDownloadUrl = (): GetSubmapDownloadUrl => {
       return '';
     }
 
-    return `${BASE_API_URL}/projects/${PROJECT_ID}/models/${model?.idObject}:downloadModel?backgroundOverlayId=${background?.id}&handlerClass=${handler}&zoomLevel=${mapSize.maxZoom}`;
+    return `${BASE_API_URL}/projects/${PROJECT_ID}/models/${modelId}:downloadModel?backgroundOverlayId=${background?.id}&handlerClass=${handler}&zoomLevel=${mapSize.maxZoom}`;
   };
 
   return getSubmapDownloadUrl;
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
index a7a38dfa..d766af5e 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapItem/SubmapItem.component.tsx
@@ -2,15 +2,16 @@ import { IconButton } from '@/shared/IconButton';
 import { DownloadSubmap } from './DownloadSubmap';
 
 interface SubmapItemProps {
+  modelId: number;
   modelName: string;
   onOpenClick: () => void;
 }
 
-export const SubmpamItem = ({ modelName, onOpenClick }: SubmapItemProps): JSX.Element => (
+export const SubmpamItem = ({ modelName, onOpenClick, modelId }: SubmapItemProps): JSX.Element => (
   <div className="flex flex-row flex-nowrap items-center justify-between border-b py-6">
     {modelName}
     <div className="flex flex-row flex-nowrap items-center">
-      <DownloadSubmap />
+      <DownloadSubmap modelId={modelId} />
       <IconButton
         icon="chevron-right"
         className="h-6 w-6 bg-white-pearl"
diff --git a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
index eb15bad6..185dbdc5 100644
--- a/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
+++ b/src/components/Map/Drawer/SubmapsDrawer/SubmapsDrawer.tsx
@@ -36,6 +36,7 @@ export const SubmapsDrawer = (): JSX.Element => {
         {models.map(model => (
           <SubmpamItem
             key={model.idObject}
+            modelId={model.idObject}
             modelName={model.name}
             onOpenClick={(): void => onSubmapOpenClick(model)}
           />
-- 
GitLab


From 71c79bc3ec2cc0b3b8b23427bbd371e2866cf6dd Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Mon, 30 Dec 2024 14:26:40 +0100
Subject: [PATCH 2/3] Update .gitlab-ci.yml

---
 .gitlab-ci.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 323a668f..fbe21171 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -55,6 +55,7 @@ jest:
     - npm run test:ci
   only:
     - development
+    - main
     - merge_requests
     - tags
   artifacts:
@@ -83,6 +84,7 @@ build:deb:
   only:
     - tags
     - development
+    - main
   before_script:
     - apt-get update
     - DEBIAN_FRONTEND=noninteractive apt-get install -y dh-make build-essential lintian devscripts xsltproc fakeroot xsltproc docbook-xsl curl gnupg git zip
-- 
GitLab


From 580e8ac0922867e9d1afa2d656fffe258acdea10 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Wed, 22 Jan 2025 15:14:58 +0100
Subject: [PATCH 3/3] open link automatically on element click when the link is
 in the model

---
 CHANGELOG                                       |  2 ++
 public/config.js                                |  5 +++--
 .../ProjectInfoDrawer.component.tsx             |  3 ---
 .../BioEntitiesAccordion.component.test.tsx     |  6 ++++--
 .../PinsListItem.component.test.tsx             |  5 ++++-
 .../mapSingleClick/handleAliasResults.ts        |  5 ++++-
 .../mapSingleClick/handleOpenImmediateLink.ts   | 17 +++++++++++++++++
 src/models/bioEntitySchema.ts                   |  1 +
 8 files changed, 35 insertions(+), 9 deletions(-)
 create mode 100644 src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts

diff --git a/CHANGELOG b/CHANGELOG
index c918ec8a..902cddca 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,6 @@
 minerva-front (18.0.8) stable; urgency=medium
+  * Small improvement: support for links that should be opened immediately
+    (#342)
   * Bug fix: data overlay removal did not work (#333)
   * Bug fix: submap download did not download selected map (#337)
 
diff --git a/public/config.js b/public/config.js
index 4d245aa0..b9e38b92 100644
--- a/public/config.js
+++ b/public/config.js
@@ -1,11 +1,12 @@
 // const root = 'https://minerva-dev.lcsb.uni.lu';
 // const root = 'https://scimap.lcsb.uni.lu';
 
-const root = 'https://lux1.atcomp.pl';
+// const root = 'https://lux1.atcomp.pl';
+const root = 'http://localhost:8080';
 window.config = {
   BASE_API_URL: `${root}/minerva/api`,
   BASE_NEW_API_URL: `${root}/minerva/new_api/`,
-  BASE_MAP_IMAGES_URL: `${root}/`,
+  BASE_MAP_IMAGES_URL: `${root}`,
   DEFAULT_PROJECT_ID: 'sample',
   ADMIN_PANEL_URL: `${root}/minerva/admin.xhtml`,
 };
diff --git a/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.tsx b/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.tsx
index 80c6cd35..f1a8a2b8 100644
--- a/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.tsx
+++ b/src/components/Map/Drawer/ProjectInfoDrawer/ProjectInfoDrawer.component.tsx
@@ -31,9 +31,6 @@ export const ProjectInfoDrawer = (): JSX.Element => {
 
   const sourceDownloadLink = BASE_API_URL + apiPath.getSourceFile();
 
-  // eslint-disable-next-line no-console
-  console.log(sourceDownloadLink);
-
   let licenseName: string = '';
   if (project) {
     licenseName = project.license ? project.license.name : project.customLicenseName;
diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
index 64d82fab..2f20b71d 100644
--- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
+++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.test.tsx
@@ -1,4 +1,4 @@
-import { FIRST_ARRAY_ELEMENT } from '@/constants/common';
+import { FIRST_ARRAY_ELEMENT, ZERO } from '@/constants/common';
 import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture';
 import { MODELS_MOCK } from '@/models/mocks/modelsMock';
 import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures';
@@ -110,7 +110,9 @@ describe('BioEntitiesAccordion - component', () => {
 
     expect(screen.getByText(`Content (${countAll})`)).toBeInTheDocument();
     expect(screen.getByText(`Core PD map (${countCore})`)).toBeInTheDocument();
-    expect(screen.getByText(`Histamine signaling (${countHistamine})`)).toBeInTheDocument();
+    if (countHistamine > ZERO) {
+      expect(screen.getByText(`Histamine signaling (${countHistamine})`)).toBeInTheDocument();
+    }
     expect(screen.getByText(`PRKN substrates (${countPrkn})`)).toBeInTheDocument();
   });
 
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 589688c9..75723b88 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
@@ -25,7 +25,10 @@ const CHEMICALS_PIN = {
 };
 
 const PIN_NUMBER = 10;
-const BIO_ENTITY = bioEntitiesContentFixture[0].bioEntity;
+const BIO_ENTITY = {
+  ...bioEntitiesContentFixture[0].bioEntity,
+  model: 5053,
+};
 
 const INITIAL_STORE_STATE: InitialStoreState = {
   models: MODELS_DATA_MOCK_WITH_MAIN_MAP,
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts
index c3d05aba..a0f97e16 100644
--- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleAliasResults.ts
@@ -6,6 +6,8 @@ import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
 import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice';
 import { Point } from '@/types/map';
 import { getMultiBioEntityByIds } from '@/redux/bioEntity/thunks/getMultiBioEntity';
+import { handleOpenImmediateLink } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink';
+import { ZERO } from '@/constants/common';
 import { findClosestBioEntityPoint } from './findClosestBioEntityPoint';
 
 type SearchConfig = {
@@ -40,12 +42,13 @@ export const handleAliasResults =
           dispatch(clearBioEntities());
           return;
         }
+
+        handleOpenImmediateLink(bioEntities[ZERO]);
       }
 
       dispatch(selectTab(`${id}`));
       dispatch(openBioEntityDrawerById(id));
 
-
       PluginsEventBus.dispatchEvent('onSearch', {
         type: 'bioEntity',
         searchValues: [closestSearchResult],
diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts
new file mode 100644
index 00000000..360df8c0
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts
@@ -0,0 +1,17 @@
+import { BioEntity } from '@/types/models';
+import { showToast } from '@/utils/showToast';
+
+export const handleOpenImmediateLink = (bioEntity: BioEntity): void => {
+  const link = bioEntity.immediateLink;
+  if (link !== null) {
+    const tab = window.open(link, '_blank');
+    if (tab) {
+      tab.focus();
+    } else {
+      showToast({
+        type: 'error',
+        message: `Browser prevented minerva from opening link: <a href="${link}" target="_blank">${link}</a>`,
+      });
+    }
+  }
+};
diff --git a/src/models/bioEntitySchema.ts b/src/models/bioEntitySchema.ts
index 1e01a1d5..bd96f4c6 100644
--- a/src/models/bioEntitySchema.ts
+++ b/src/models/bioEntitySchema.ts
@@ -13,6 +13,7 @@ import { submodelSchema } from './submodelSchema';
 export const bioEntitySchema = z.object({
   id: z.union([z.number().int().positive(), z.string()]),
   stringType: z.string(),
+  immediateLink: z.string().nullable(),
   name: z.string(),
   elementId: z.string(),
   model: z.number(),
-- 
GitLab