From 2ce2b9dccf800a4ed4c275b8de5648eaf2a37a03 Mon Sep 17 00:00:00 2001
From: mateusz-winiarczyk <mateusz.winiarczyk@appunite.com>
Date: Mon, 4 Mar 2024 16:59:09 +0100
Subject: [PATCH] feat(project): add methods for plugins to retrieve data about
 project

---
 docs/plugins/project.md                       | 48 ++++++++++++++++++
 index.d.ts                                    | 14 ++++++
 src/services/pluginsManager/pluginsManager.ts | 14 ++++++
 .../project/data/getDisease.test.ts           | 50 +++++++++++++++++++
 .../pluginsManager/project/data/getDisease.ts | 16 ++++++
 .../project/data/getName.test.ts              | 50 +++++++++++++++++++
 .../pluginsManager/project/data/getName.ts    | 16 ++++++
 .../project/data/getOrganism.test.ts          | 50 +++++++++++++++++++
 .../project/data/getOrganism.ts               | 16 ++++++
 .../project/data/getProjectId.test.ts         | 50 +++++++++++++++++++
 .../project/data/getProjectId.ts              | 16 ++++++
 .../project/data/getVersion.test.ts           | 50 +++++++++++++++++++
 .../pluginsManager/project/data/getVersion.ts | 16 ++++++
 13 files changed, 406 insertions(+)
 create mode 100644 docs/plugins/project.md
 create mode 100644 src/services/pluginsManager/project/data/getDisease.test.ts
 create mode 100644 src/services/pluginsManager/project/data/getDisease.ts
 create mode 100644 src/services/pluginsManager/project/data/getName.test.ts
 create mode 100644 src/services/pluginsManager/project/data/getName.ts
 create mode 100644 src/services/pluginsManager/project/data/getOrganism.test.ts
 create mode 100644 src/services/pluginsManager/project/data/getOrganism.ts
 create mode 100644 src/services/pluginsManager/project/data/getProjectId.test.ts
 create mode 100644 src/services/pluginsManager/project/data/getProjectId.ts
 create mode 100644 src/services/pluginsManager/project/data/getVersion.test.ts
 create mode 100644 src/services/pluginsManager/project/data/getVersion.ts

diff --git a/docs/plugins/project.md b/docs/plugins/project.md
new file mode 100644
index 00000000..a972b4a6
--- /dev/null
+++ b/docs/plugins/project.md
@@ -0,0 +1,48 @@
+### Project Info
+
+Minerva provides an API that allows users to retrieve specific information about a project. This API exposes various methods to access details related to a project.
+
+**Get Project ID:**
+To get project ID, plugins can use the `getProjectId` method defined in `window.minerva.project.data` object.
+
+##### Example usage of getProjectId method:
+
+```javascript
+window.minerva.project.data.getProjectId();
+```
+
+**Get Project Name:**
+To get project name, plugins can use the `getName` method defined in `window.minerva.project.data` object.
+
+##### Example usage of getName method:
+
+```javascript
+window.minerva.project.data.getName();
+```
+
+**Get Project Version:**
+To get project version, plugins can use the `getVersion` method defined in `window.minerva.project.data` object.
+
+##### Example usage of getVersion method:
+
+```javascript
+window.minerva.project.data.getVersion();
+```
+
+**Get Disease:**
+To get disease identifier associated with the project, plugins can use the `getDisease` method defined in `window.minerva.project.data` object.
+
+##### Example usage of getDisease method:
+
+```javascript
+window.minerva.project.data.getDisease();
+```
+
+**Get Organism:**
+To get organism identifier associated with the project, plugins can use the `getOrganism` method defined in `window.minerva.project.data` object.
+
+##### Example usage of getOrganism method:
+
+```javascript
+window.minerva.project.data.getOrganism();
+```
diff --git a/index.d.ts b/index.d.ts
index 5cb2d025..fc841282 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,5 +1,10 @@
 import { triggerSearch } from '@/services/pluginsManager/map/triggerSearch';
 import { MinervaConfiguration } from '@/services/pluginsManager/pluginsManager';
+import { getDisease } from '@/services/pluginsManager/project/data/getDisease';
+import { getName } from '@/services/pluginsManager/project/data/getName';
+import { getOrganism } from '@/services/pluginsManager/project/data/getOrganism';
+import { getProjectId } from '@/services/pluginsManager/project/data/getProjectId';
+import { getVersion } from '@/services/pluginsManager/project/data/getVersion';
 
 type Plugin = {
   pluginName: string;
@@ -29,6 +34,15 @@ declare global {
       map: {
         triggerSearch: typeof triggerSearch;
       };
+      project: {
+        data: {
+          getProjectId: typeof getProjectId;
+          getName: typeof getName;
+          getVersion: typeof getVersion;
+          getDisease: typeof getDisease;
+          getOrganism: typeof getOrganism;
+        };
+      };
     };
   }
 }
diff --git a/src/services/pluginsManager/pluginsManager.ts b/src/services/pluginsManager/pluginsManager.ts
index a38faee9..63e46d12 100644
--- a/src/services/pluginsManager/pluginsManager.ts
+++ b/src/services/pluginsManager/pluginsManager.ts
@@ -5,6 +5,11 @@ import md5 from 'crypto-js/md5';
 import { bioEntitiesMethods } from './bioEntities';
 import { triggerSearch } from './map/triggerSearch';
 import { PluginsEventBus } from './pluginsEventBus';
+import { getProjectId } from './project/data/getProjectId';
+import { getName } from './project/data/getName';
+import { getVersion } from './project/data/getVersion';
+import { getDisease } from './project/data/getDisease';
+import { getOrganism } from './project/data/getOrganism';
 import type { PluginsManagerType } from './pluginsManager.types';
 import { configurationMapper } from './pluginsManager.utils';
 
@@ -28,6 +33,15 @@ export const PluginsManager: PluginsManagerType = {
       map: {
         triggerSearch,
       },
+      project: {
+        data: {
+          getProjectId,
+          getName,
+          getVersion,
+          getDisease,
+          getOrganism,
+        },
+      },
     };
 
     const unsubscribe = store.subscribe(() => {
diff --git a/src/services/pluginsManager/project/data/getDisease.test.ts b/src/services/pluginsManager/project/data/getDisease.test.ts
new file mode 100644
index 00000000..0f80e378
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getDisease.test.ts
@@ -0,0 +1,50 @@
+import { RootState, store } from '@/redux/store';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import { getDisease } from './getDisease';
+
+jest.mock('../../../../redux/store');
+
+describe('getDisease', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+  it('should return the disease from project if project exists and data is valid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: projectFixture,
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getDisease()).toEqual(projectFixture.disease);
+  });
+  it('should throw error if project does not exist', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(() => getDisease()).toThrow('Project does not exist');
+  });
+  it('returns undefined if project data is invalid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: {},
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getDisease()).toEqual(undefined);
+  });
+});
diff --git a/src/services/pluginsManager/project/data/getDisease.ts b/src/services/pluginsManager/project/data/getDisease.ts
new file mode 100644
index 00000000..6d7e0ad7
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getDisease.ts
@@ -0,0 +1,16 @@
+import { projectSchema } from '@/models/projectSchema';
+import { store } from '@/redux/store';
+import { Project } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+type GetDiseaseReturnType = Project['disease'] | undefined;
+
+export const getDisease = (): GetDiseaseReturnType => {
+  const project = store.getState().project.data;
+
+  if (!project) throw new Error('Project does not exist');
+
+  const isDataValid = validateDataUsingZodSchema(project, projectSchema);
+
+  return isDataValid ? project.disease : undefined;
+};
diff --git a/src/services/pluginsManager/project/data/getName.test.ts b/src/services/pluginsManager/project/data/getName.test.ts
new file mode 100644
index 00000000..f53903fe
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getName.test.ts
@@ -0,0 +1,50 @@
+import { RootState, store } from '@/redux/store';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import { getName } from './getName';
+
+jest.mock('../../../../redux/store');
+
+describe('getName', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+  it('should return the project name from project if project exists and data is valid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: projectFixture,
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getName()).toEqual(projectFixture.name);
+  });
+  it('should throw error if project does not exist', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(() => getName()).toThrow('Project does not exist');
+  });
+  it('should return undefined if project data is invalid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: {},
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getName()).toEqual(undefined);
+  });
+});
diff --git a/src/services/pluginsManager/project/data/getName.ts b/src/services/pluginsManager/project/data/getName.ts
new file mode 100644
index 00000000..c024ee22
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getName.ts
@@ -0,0 +1,16 @@
+import { projectSchema } from '@/models/projectSchema';
+import { store } from '@/redux/store';
+import { Project } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+type GetNameReturnType = Project['name'] | undefined;
+
+export const getName = (): GetNameReturnType => {
+  const project = store.getState().project.data;
+
+  if (!project) throw new Error('Project does not exist');
+
+  const isDataValid = validateDataUsingZodSchema(project, projectSchema);
+
+  return isDataValid ? project.name : undefined;
+};
diff --git a/src/services/pluginsManager/project/data/getOrganism.test.ts b/src/services/pluginsManager/project/data/getOrganism.test.ts
new file mode 100644
index 00000000..6ddf8e64
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getOrganism.test.ts
@@ -0,0 +1,50 @@
+import { RootState, store } from '@/redux/store';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import { getOrganism } from './getOrganism';
+
+jest.mock('../../../../redux/store');
+
+describe('getOrganism', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+  it('should return the project organism from project if project exists and data is valid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: projectFixture,
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getOrganism()).toEqual(projectFixture.organism);
+  });
+  it('should throw error if project does not exist', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(() => getOrganism()).toThrow('Project does not exist');
+  });
+  it('should return undefined if project data is invalid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: {},
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getOrganism()).toEqual(undefined);
+  });
+});
diff --git a/src/services/pluginsManager/project/data/getOrganism.ts b/src/services/pluginsManager/project/data/getOrganism.ts
new file mode 100644
index 00000000..a19fe476
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getOrganism.ts
@@ -0,0 +1,16 @@
+import { projectSchema } from '@/models/projectSchema';
+import { store } from '@/redux/store';
+import { Project } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+type GetOrganismReturnType = Project['organism'] | undefined;
+
+export const getOrganism = (): GetOrganismReturnType => {
+  const project = store.getState().project.data;
+
+  if (!project) throw new Error('Project does not exist');
+
+  const isDataValid = validateDataUsingZodSchema(project, projectSchema);
+
+  return isDataValid ? project.organism : undefined;
+};
diff --git a/src/services/pluginsManager/project/data/getProjectId.test.ts b/src/services/pluginsManager/project/data/getProjectId.test.ts
new file mode 100644
index 00000000..cc7cccdc
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getProjectId.test.ts
@@ -0,0 +1,50 @@
+import { RootState, store } from '@/redux/store';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import { getProjectId } from './getProjectId';
+
+jest.mock('../../../../redux/store');
+
+describe('getProjectId', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+  it('should return the project id from project if project exists and data is valid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: projectFixture,
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getProjectId()).toEqual(projectFixture.projectId);
+  });
+  it('should throw error if project does not exist', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(() => getProjectId()).toThrow('Project does not exist');
+  });
+  it('should return undefined if project data is invalid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: {},
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getProjectId()).toEqual(undefined);
+  });
+});
diff --git a/src/services/pluginsManager/project/data/getProjectId.ts b/src/services/pluginsManager/project/data/getProjectId.ts
new file mode 100644
index 00000000..2a8fd53f
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getProjectId.ts
@@ -0,0 +1,16 @@
+import { projectSchema } from '@/models/projectSchema';
+import { store } from '@/redux/store';
+import { Project } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+type GetProjectIdReturnType = Project['projectId'] | undefined;
+
+export const getProjectId = (): GetProjectIdReturnType => {
+  const project = store.getState().project.data;
+
+  if (!project) throw new Error('Project does not exist');
+
+  const isDataValid = validateDataUsingZodSchema(project, projectSchema);
+
+  return isDataValid ? project.projectId : undefined;
+};
diff --git a/src/services/pluginsManager/project/data/getVersion.test.ts b/src/services/pluginsManager/project/data/getVersion.test.ts
new file mode 100644
index 00000000..ca35d3cb
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getVersion.test.ts
@@ -0,0 +1,50 @@
+import { RootState, store } from '@/redux/store';
+import { projectFixture } from '@/models/fixtures/projectFixture';
+import { getVersion } from './getVersion';
+
+jest.mock('../../../../redux/store');
+
+describe('getVersion', () => {
+  const getStateSpy = jest.spyOn(store, 'getState');
+  it('should return the project id from project if project exists and data is valid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: projectFixture,
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getVersion()).toEqual(projectFixture.version);
+  });
+  it('should throw error if project does not exist', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(() => getVersion()).toThrow('Project does not exist');
+  });
+  it('should return undefined if project data is invalid', () => {
+    getStateSpy.mockImplementation(
+      () =>
+        ({
+          project: {
+            data: {},
+            loading: 'succeeded',
+            error: { message: '', name: '' },
+          },
+        }) as RootState,
+    );
+
+    expect(getVersion()).toEqual(undefined);
+  });
+});
diff --git a/src/services/pluginsManager/project/data/getVersion.ts b/src/services/pluginsManager/project/data/getVersion.ts
new file mode 100644
index 00000000..882735f4
--- /dev/null
+++ b/src/services/pluginsManager/project/data/getVersion.ts
@@ -0,0 +1,16 @@
+import { projectSchema } from '@/models/projectSchema';
+import { store } from '@/redux/store';
+import { Project } from '@/types/models';
+import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
+
+type GetVersionReturnType = Project['version'] | undefined;
+
+export const getVersion = (): GetVersionReturnType => {
+  const project = store.getState().project.data;
+
+  if (!project) throw new Error('Project does not exist');
+
+  const isDataValid = validateDataUsingZodSchema(project, projectSchema);
+
+  return isDataValid ? project.version : undefined;
+};
-- 
GitLab