diff --git a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.test.tsx b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.test.tsx index 0e83701bc5e0d32ad44f6d980693168e645a5254..c0051a1399061d0eec637ee05873454cbb50f27d 100644 --- a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.test.tsx +++ b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.test.tsx @@ -8,6 +8,8 @@ import { act, render, screen } from '@testing-library/react'; import { CONTEXT_MENU_INITIAL_STATE } from '@/redux/contextMenu/contextMenu.constants'; import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { PluginsContextMenu } from '@/services/pluginsManager/pluginContextMenu/pluginsContextMenu'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { DEFAULT_ERROR } from '@/constants/errors'; import { ContextMenu } from './ContextMenu.component'; const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => { @@ -97,31 +99,40 @@ describe('ContextMenu - Component', () => { it('should display uniprot id as option if it is provided', () => { renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: bioEntityContentFixture.bioEntity.id.toString(), + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: 'BioEntity Full Name', - references: [ - { - ...bioEntityContentFixture.bioEntity.references[0], - type: 'UNIPROT', - }, - ], - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: modelElementFixture.id.toString(), + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: 'BioEntity Full Name', + references: [ + { + ...bioEntityContentFixture.bioEntity.references[0], + type: 'UNIPROT', + }, + ], + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, contextMenu: { ...CONTEXT_MENU_INITIAL_STATE, @@ -144,31 +155,40 @@ describe('ContextMenu - Component', () => { it('should open molart modal when clicking on uniprot', async () => { const { store } = renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: bioEntityContentFixture.bioEntity.id.toString(), + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: 'BioEntity Full Name', - references: [ - { - ...bioEntityContentFixture.bioEntity.references[0], - type: 'UNIPROT', - }, - ], - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: modelElementFixture.id.toString(), + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: 'BioEntity Full Name', + references: [ + { + ...bioEntityContentFixture.bioEntity.references[0], + type: 'UNIPROT', + }, + ], + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, contextMenu: { ...CONTEXT_MENU_INITIAL_STATE, diff --git a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx index 1e4d612b0297062a993227bdd18389bc5b9050b8..fe738b5116942a2141f039b5605d665425716360 100644 --- a/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx +++ b/src/components/FunctionalArea/ContextMenu/ContextMenu.component.tsx @@ -1,4 +1,3 @@ -import { searchedBioEntityElementUniProtIdSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { contextMenuSelector } from '@/redux/contextMenu/contextMenu.selector'; import { closeContextMenu } from '@/redux/contextMenu/contextMenu.slice'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; @@ -9,12 +8,13 @@ import { twMerge } from 'tailwind-merge'; import { FIRST_ARRAY_ELEMENT, SECOND_ARRAY_ELEMENT, ZERO } from '@/constants/common'; import { PluginsContextMenu } from '@/services/pluginsManager/pluginContextMenu/pluginsContextMenu'; -import { BioEntity, NewReaction } from '@/types/models'; +import { ModelElement, NewReaction } from '@/types/models'; import { ClickCoordinates } from '@/services/pluginsManager/pluginContextMenu/pluginsContextMenu.types'; import { currentModelSelector } from '@/redux/models/models.selectors'; import { mapDataLastPositionSelector } from '@/redux/map/map.selectors'; import { DEFAULT_ZOOM } from '@/constants/map'; import { OutsideClickWrapper } from '@/shared/OutsideClickWrapper'; +import { searchedModelElementUniProtIdSelector } from '@/redux/modelElements/modelElements.selector'; export const ContextMenu = (): React.ReactNode => { const pluginContextMenu = PluginsContextMenu.menuItems; @@ -22,7 +22,7 @@ export const ContextMenu = (): React.ReactNode => { const lastPosition = useAppSelector(mapDataLastPositionSelector); const dispatch = useAppDispatch(); const { isOpen, coordinates } = useAppSelector(contextMenuSelector); - const unitProtId = useAppSelector(searchedBioEntityElementUniProtIdSelector); + const unitProtId = useAppSelector(searchedModelElementUniProtIdSelector); const isUnitProtIdAvailable = (): boolean => unitProtId !== undefined; @@ -49,7 +49,10 @@ export const ContextMenu = (): React.ReactNode => { const modelId = model ? model.id : ZERO; const handleCallback = ( - callback: (coordinates: ClickCoordinates, element: BioEntity | NewReaction | undefined) => void, + callback: ( + coordinates: ClickCoordinates, + element: ModelElement | NewReaction | undefined, + ) => void, ) => { return () => { closeContextMenuFunction(); diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx index ea4fe1f6f76cc3fcfec45cb21decbbb4b02d693d..22beff1a724b8eb4d7da732ed1624e8deefe9179 100644 --- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx +++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.test.tsx @@ -5,7 +5,7 @@ import { apiPath } from '@/redux/apiPath'; import { DEFAULT_POSITION } from '@/redux/map/map.constants'; import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; import { AppDispatch, RootState } from '@/redux/store'; -import { BioEntity, MapModel } from '@/types/models'; +import { MapModel, PublicationElement } from '@/types/models'; import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; import { InitialStoreState, @@ -14,12 +14,12 @@ import { import { render, screen, waitFor } from '@testing-library/react'; import { HttpStatusCode } from 'axios'; import { MockStoreEnhanced } from 'redux-mock-store'; -import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity'; +import { isReactionElement } from '@/redux/reactions/isReactionElement'; import { ElementLink } from './ElementLink.component'; const mockedAxiosNewClient = mockNetworkNewAPIResponse(); -const TARGET_ELEMENT: BioEntity = { +const TARGET_ELEMENT: PublicationElement = { ...bioEntityResponseFixture.content[FIRST_ARRAY_ELEMENT].bioEntity, id: 123, model: 52, @@ -36,20 +36,20 @@ const OTHER_MODEL: MapModel = { }; interface Props { - target: BioEntity; + target: PublicationElement; } -const getElementText = (bioEntity: BioEntity): string => { - const isReaction = isReactionBioEntity(bioEntity); +const getElementText = (element: PublicationElement): string => { + const isReaction = isReactionElement(element); const prefix = isReaction ? 'Reaction: ' : 'Element: '; - return prefix + bioEntity.elementId; + return prefix + element.elementId; }; -const getSearchQuery = (bioEntity: BioEntity): string => { - const isReaction = isReactionBioEntity(bioEntity); +const getSearchQuery = (element: PublicationElement): string => { + const isReaction = isReactionElement(element); - return (isReaction ? 'reaction:' : 'element:') + bioEntity.id; + return (isReaction ? 'reaction:' : 'element:') + element.id; }; const renderComponent = ( @@ -86,10 +86,10 @@ describe('ElementLink - component', () => { }); it('should should show element id', async () => { - const bioEntity = TARGET_ELEMENT; + const element = TARGET_ELEMENT; await waitFor(() => { - expect(screen.getByText(getElementText(bioEntity))).toBeInTheDocument(); + expect(screen.getByText(getElementText(element))).toBeInTheDocument(); }); }); }); @@ -116,10 +116,10 @@ describe('ElementLink - component', () => { }, ); - const bioEntity = TARGET_ELEMENT; + const element = TARGET_ELEMENT; await waitFor(() => { - const link = screen.getByText(getElementText(bioEntity)); + const link = screen.getByText(getElementText(element)); link.click(); const actions = store.getActions(); @@ -148,7 +148,7 @@ describe('ElementLink - component', () => { expect(actions).toEqual( expect.arrayContaining([ expect.objectContaining({ - payload: getSearchQuery(bioEntity), + payload: getSearchQuery(element), type: 'drawer/openSearchDrawerWithSelectedTab', }), ]), @@ -206,10 +206,10 @@ describe('ElementLink - component', () => { }, ); - const bioEntity = TARGET_ELEMENT; + const element = TARGET_ELEMENT; await waitFor(() => { - const link = screen.getByText(getElementText(bioEntity)); + const link = screen.getByText(getElementText(element)); link.click(); const actions = store.getActions(); @@ -238,7 +238,7 @@ describe('ElementLink - component', () => { expect(actions).toEqual( expect.arrayContaining([ expect.objectContaining({ - payload: getSearchQuery(bioEntity), + payload: getSearchQuery(element), type: 'drawer/openSearchDrawerWithSelectedTab', }), ]), diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx index 8bf24727e7f2a7f8ba8254f7ffaed63fd9a635af..baad3d083e77076a7f428b5b9aaa2af099e6ee17 100644 --- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx +++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementLink/ElementLink.component.tsx @@ -13,11 +13,11 @@ import { closeModal } from '@/redux/modal/modal.slice'; import { modelsNameMapSelector } from '@/redux/models/models.selectors'; import { getSearchData } from '@/redux/search/search.thunks'; import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; -import { BioEntity } from '@/types/models'; -import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity'; +import { PublicationElement } from '@/types/models'; +import { isReactionElement } from '@/redux/reactions/isReactionElement'; interface Props { - target: BioEntity; + target: PublicationElement; } export const ElementLink = ({ target }: Props): JSX.Element => { @@ -26,7 +26,7 @@ export const ElementLink = ({ target }: Props): JSX.Element => { const currentModelId = useAppSelector(mapModelIdSelector); const mapsNames = useAppSelector(modelsNameMapSelector); - const isReaction = isReactionBioEntity(target); + const isReaction = isReactionElement(target); const isMapAlreadyOpened = (modelId: number): boolean => openedMaps.some(map => map.modelId === modelId); diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx index 2e7349c6eed66cc238eacfdfa4ccb8fcf9dd4950..84798d95e4a28641e9882ca2767116580ffc3984 100644 --- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx +++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.test.tsx @@ -1,18 +1,18 @@ import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; import { AppDispatch, RootState } from '@/redux/store'; -import { BioEntity } from '@/types/models'; +import { PublicationElement } from '@/types/models'; import { InitialStoreState, getReduxStoreWithActionsListener, } from '@/utils/testing/getReduxStoreActionsListener'; import { render, screen, waitFor } from '@testing-library/react'; import { MockStoreEnhanced } from 'redux-mock-store'; -import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture'; -import { isReactionBioEntity } from '@/redux/reactions/isReactionBioentity'; +import { isReactionElement } from '@/redux/reactions/isReactionElement'; +import { publicationElementFixture } from '@/models/fixtures/publicationElementFixture'; import { ElementsOnMapCell } from './ElementsOnMapCell.component'; interface Props { - targets: BioEntity[]; + targets: PublicationElement[]; } const renderComponent = ( @@ -33,8 +33,8 @@ const renderComponent = ( ); }; -const elementFixture = { ...bioEntityFixture, idReaction: undefined }; -const reactionFixture = { ...bioEntityFixture, idReaction: '123' }; +const elementFixture = { ...publicationElementFixture, idReaction: undefined }; +const reactionFixture = { ...publicationElementFixture, idReaction: '123' }; const mockTargets = [{ ...elementFixture }, { ...reactionFixture }]; @@ -49,7 +49,7 @@ describe('ElementsOnMapCell - component', () => { await waitFor(() => { // type as elementId - const isReaction = isReactionBioEntity(bioEntity); + const isReaction = isReactionElement(bioEntity); const prefix = isReaction ? 'Reaction: ' : 'Element: '; expect(screen.getByText(prefix + bioEntity.elementId)).toBeInTheDocument(); }); diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx index 13c1269f4bf4685edc700a21a4be05eaf9f69067..36d7a247d1f7f559b4e532ea8db386a5cc8947dd 100644 --- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx +++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/ElementsOnMapCell/ElementsOnMapCell.component.tsx @@ -1,9 +1,9 @@ import { ONE } from '@/constants/common'; -import { BioEntity } from '@/types/models'; +import { PublicationElement } from '@/types/models'; import { ElementLink } from './ElementLink'; interface Props { - targets: BioEntity[]; + targets: PublicationElement[]; } export const ElementsOnMapCell = ({ targets }: Props): JSX.Element => { diff --git a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx index cc0db919dcf46f8e33488d78755cedd014562755..562ccefac2268bb29b50aa78e5006ee1a2668e2a 100644 --- a/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx +++ b/src/components/FunctionalArea/Modal/PublicationsModal/PublicationsTable/PublicationsTable.component.tsx @@ -23,7 +23,7 @@ import { } from '@tanstack/react-table'; import { useRef, useState } from 'react'; import { z } from 'zod'; -import { bioEntitySchema } from '@/models/bioEntitySchema'; +import { publicationElementSchema } from '@/models/publicationElementSchema'; import { ElementsOnMapCell } from './ElementsOnMapCell'; import { FilterBySubmapHeader } from './FilterBySubmapHeader/FilterBySubmapHeader.component'; import { DEFAULT_PAGE_SIZE } from './PublicationsTable.constants'; @@ -74,9 +74,7 @@ const columns = [ cell: ({ getValue }): JSX.Element => { try { const valueObject: unknown = JSON.parse(getValue()); - // eslint-disable-next-line no-console - console.log(valueObject); - const targets = z.array(bioEntitySchema).parse(valueObject); + const targets = z.array(publicationElementSchema).parse(valueObject); return <ElementsOnMapCell targets={targets} />; } catch (error) { diff --git a/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.test.tsx b/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.test.tsx index b8bc885aedc1f6e0382d6355baf871510edc85cd..494e4e379f625b796d6f54af9a31a27f2b2453b8 100644 --- a/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.test.tsx +++ b/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.test.tsx @@ -49,7 +49,7 @@ describe('ClearAnchorsButton - component', () => { { payload: undefined, type: 'contextMenu/closeContextMenu' }, { payload: undefined, type: 'reactions/resetReactionsData' }, { payload: undefined, type: 'search/clearSearchData' }, - { payload: undefined, type: 'bioEntityContents/clearBioEntities' }, + { payload: undefined, type: 'modelElements/clearSearchModelElements' }, { payload: undefined, type: 'drugs/clearDrugsData' }, { payload: undefined, type: 'chemicals/clearChemicalsData' }, ]); @@ -75,7 +75,7 @@ describe('ClearAnchorsButton - component', () => { { payload: undefined, type: 'contextMenu/closeContextMenu' }, { payload: undefined, type: 'reactions/resetReactionsData' }, { payload: undefined, type: 'search/clearSearchData' }, - { payload: undefined, type: 'bioEntityContents/clearBioEntities' }, + { payload: undefined, type: 'modelElements/clearSearchModelElements' }, { payload: undefined, type: 'drugs/clearDrugsData' }, { payload: undefined, type: 'chemicals/clearChemicalsData' }, ]); diff --git a/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.tsx b/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.tsx index 0cb3417872af8ff8ebd0541c3f04d2e838c8fef1..c370829b6e042d715612ade79e56e127e0c2e300 100644 --- a/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.tsx +++ b/src/components/FunctionalArea/TopBar/ClearAnchorsButton/ClearAnchorsButton.component.tsx @@ -1,4 +1,3 @@ -import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice'; import { clearChemicalsData } from '@/redux/chemicals/chemicals.slice'; import { closeContextMenu } from '@/redux/contextMenu/contextMenu.slice'; import { resultDrawerOpen } from '@/redux/drawer/drawer.selectors'; @@ -11,6 +10,7 @@ import { Button } from '@/shared/Button'; import { Icon } from '@/shared/Icon'; import React from 'react'; import { useSelector } from 'react-redux'; +import { clearSearchModelElements } from '@/redux/modelElements/modelElements.slice'; export const ClearAnchorsButton = (): React.ReactNode => { const dispatch = useAppDispatch(); @@ -31,7 +31,7 @@ export const ClearAnchorsButton = (): React.ReactNode => { dispatch(clearSearchData()); // Reset old pins data - dispatch(clearBioEntities()); + dispatch(clearSearchModelElements()); dispatch(clearDrugsData()); dispatch(clearChemicalsData()); }; diff --git a/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.test.tsx b/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.test.tsx index 73231d8d0cb131410be7d075427705b50ce7459b..ed18ca49cc39a77540e24b73937955492c0cc989 100644 --- a/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.test.tsx +++ b/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.test.tsx @@ -1,11 +1,6 @@ import { SIZE_OF_ARRAY_WITH_ONE_ELEMENT, ZERO } from '@/constants/common'; -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock'; -import { - BIOENTITY_INITIAL_STATE_MOCK, - BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK, - BIO_ENTITY_LINKING_TO_SUBMAP, -} from '@/redux/bioEntity/bioEntity.mock'; +import { BIOENTITY_INITIAL_STATE_MOCK } from '@/redux/bioEntity/bioEntity.mock'; import { DRAWER_INITIAL_STATE } from '@/redux/drawer/drawer.constants'; import { initialMapDataFixture, @@ -21,6 +16,12 @@ import { import { act, render, screen } from '@testing-library/react'; import { HISTAMINE_MAP_ID, MAIN_MAP_ID } from '@/constants/mocks'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; +import { + MODEL_ELEMENT_LINKING_TO_SUBMAP, + MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK, +} from '@/redux/modelElements/modelElements.mock'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { AssociatedSubmap } from './AssociatedSubmap.component'; const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { @@ -43,21 +44,27 @@ describe('AssociatedSubmap - component', () => { renderComponent({ bioEntity: { ...BIOENTITY_INITIAL_STATE_MOCK, - data: BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK, }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { - bioentityId: bioEntityContentFixture.bioEntity.id, + bioentityId: modelElementFixture.id, drugs: {}, chemicals: {}, }, }, modelElements: { - [MAIN_MAP_ID]: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + [MAIN_MAP_ID]: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: { + data: MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK, + loading: 'idle', + error: DEFAULT_ERROR, }, } as ModelElementsState, models: { @@ -81,21 +88,27 @@ describe('AssociatedSubmap - component', () => { }, bioEntity: { ...BIOENTITY_INITIAL_STATE_MOCK, - data: BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK, }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { - bioentityId: bioEntityContentFixture.bioEntity.id, + bioentityId: modelElementFixture.id, drugs: {}, chemicals: {}, }, }, modelElements: { - [MAIN_MAP_ID]: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + [MAIN_MAP_ID]: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: { + data: MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK, + loading: 'idle', + error: DEFAULT_ERROR, }, } as ModelElementsState, models: { @@ -118,19 +131,25 @@ describe('AssociatedSubmap - component', () => { }, bioEntity: { ...BIOENTITY_INITIAL_STATE_MOCK, - data: BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK, }, modelElements: { - 0: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: { + data: MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK, + loading: 'idle', + error: DEFAULT_ERROR, }, } as ModelElementsState, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { - bioentityId: bioEntityContentFixture.bioEntity.id, + bioentityId: modelElementFixture.id, drugs: {}, chemicals: {}, }, @@ -151,7 +170,6 @@ describe('AssociatedSubmap - component', () => { modelName: 'Histamine signaling', lastPosition: { x: 0, y: 0, z: 0 }, }); - const openSubmapButton = screen.getByRole('button', { name: 'Open submap' }); await act(() => { openSubmapButton.click(); @@ -184,19 +202,25 @@ describe('AssociatedSubmap - component', () => { }, bioEntity: { ...BIOENTITY_INITIAL_STATE_MOCK, - data: BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK, }, modelElements: { - [MAIN_MAP_ID]: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + [MAIN_MAP_ID]: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: { + data: MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK, + loading: 'idle', + error: DEFAULT_ERROR, }, } as ModelElementsState, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { - bioentityId: bioEntityContentFixture.bioEntity.id, + bioentityId: modelElementFixture.id, drugs: {}, chemicals: {}, }, diff --git a/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx b/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx index ae4216066e9de25a9254ce5ddcc165a6e218728e..22c6c44926b303b080d720d9aa50369da179c525 100644 --- a/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx +++ b/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx @@ -1,10 +1,10 @@ import { useOpenSubmap } from '@/hooks/useOpenSubmaps'; -import { currentDrawerBioEntityRelatedSubmapSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { Button } from '@/shared/Button'; +import { currentDrawerModelElementRelatedSubmapSelector } from '@/redux/modelElements/modelElements.selector'; export const AssociatedSubmap = (): React.ReactNode => { - const relatedSubmap = useAppSelector(currentDrawerBioEntityRelatedSubmapSelector); + const relatedSubmap = useAppSelector(currentDrawerModelElementRelatedSubmapSelector); const { openSubmap } = useOpenSubmap({ modelId: relatedSubmap?.id, modelName: relatedSubmap?.name, diff --git a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.test.tsx b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.test.tsx index 7ae2a243928cae82231f3c7e4c0756a0d9018925..c0bb50583b1e19999dafd406aa4cadf0e9a7bbf5 100644 --- a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.test.tsx +++ b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.test.tsx @@ -1,6 +1,5 @@ /* eslint-disable no-magic-numbers */ import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock'; -import { BIO_ENTITY_LINKING_TO_SUBMAP } from '@/redux/bioEntity/bioEntity.mock'; import { DRAWER_INITIAL_STATE } from '@/redux/drawer/drawer.constants'; import { MODELS_INITIAL_STATE_MOCK } from '@/redux/models/models.mock'; import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; @@ -10,8 +9,11 @@ import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore'; import { act, render, screen } from '@testing-library/react'; import { MockStoreEnhanced } from 'redux-mock-store'; import { getTypeBySBOTerm } from '@/utils/bioEntity/getTypeBySBOTerm'; -import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { + MODEL_ELEMENT_LINKING_TO_SUBMAP, + MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, +} from '@/redux/modelElements/modelElements.mock'; import { BioEntityDrawer } from './BioEntityDrawer.component'; const renderComponent = ( @@ -43,10 +45,15 @@ describe('BioEntityDrawer - component', () => { describe("when there's NO matching bioEntity", () => { beforeEach(() => renderComponent({ - bioEntity: { - data: [], - loading: 'succeeded', - error: { message: '', name: '' }, + modelElements: { + data: { + 0: { + data: [], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, }, drawer: DRAWER_INITIAL_STATE, }), @@ -67,12 +74,15 @@ describe('BioEntityDrawer - component', () => { it('should show drawer header', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -91,12 +101,15 @@ describe('BioEntityDrawer - component', () => { it('should show drawer bioEntity full name', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: bioEntityFullName }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: bioEntityFullName }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -114,12 +127,15 @@ describe('BioEntityDrawer - component', () => { it("should not show drawer bioEntity full name if it doesn't exists", () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -136,12 +152,15 @@ describe('BioEntityDrawer - component', () => { it('should show list of annotations ', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -164,16 +183,19 @@ describe('BioEntityDrawer - component', () => { it('should display associated submaps if bio entity links to submap', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...BIO_ENTITY_LINKING_TO_SUBMAP, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...MODEL_ELEMENT_LINKING_TO_SUBMAP, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { - bioentityId: BIO_ENTITY_LINKING_TO_SUBMAP.id, + bioentityId: MODEL_ELEMENT_LINKING_TO_SUBMAP.id, drugs: {}, chemicals: {}, }, @@ -190,12 +212,15 @@ describe('BioEntityDrawer - component', () => { it('should display chemicals list header', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -212,12 +237,15 @@ describe('BioEntityDrawer - component', () => { it('should display drugs list header', () => { renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -234,12 +262,15 @@ describe('BioEntityDrawer - component', () => { it('should fetch chemicals on chemicals for target click', () => { const { store } = renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { @@ -263,12 +294,15 @@ describe('BioEntityDrawer - component', () => { it('should fetch drugs on drugs for target click', () => { const { store } = renderComponent({ modelElements: { - 0: { - data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [{ ...modelElementFixture, name: bioEntityName, fullName: null }], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, drawer: { ...DRAWER_INITIAL_STATE, bioEntityDrawerState: { diff --git a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx index 1cf3684dcbb82d21be5758154abdec567e6a9d6b..259e7ac69bc3abc1420022fa0440f892d2f5c67d 100644 --- a/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx +++ b/src/components/Map/Drawer/BioEntityDrawer/BioEntityDrawer.component.tsx @@ -1,8 +1,4 @@ import { ZERO } from '@/constants/common'; -import { - currentDrawerBioEntityRelatedSubmapSelector, - currentDrawerElementCommentsSelector, -} from '@/redux/bioEntity/bioEntity.selectors'; import { getChemicalsForBioEntityDrawerTarget, getDrugsForBioEntityDrawerTarget, @@ -18,6 +14,8 @@ import React from 'react'; import { AnnotationItemList } from '@/components/Map/Drawer/BioEntityDrawer/AnnotationItem/AnnotationItemList.component'; import { compartmentNameByIdSelector, + currentDrawerElementCommentsSelector, + currentDrawerModelElementRelatedSubmapSelector, currentDrawerModelElementSelector, } from '@/redux/modelElements/modelElements.selector'; import { CollapsibleSection } from '../ExportDrawer/CollapsibleSection'; @@ -32,7 +30,7 @@ export const BioEntityDrawer = (): React.ReactNode => { const dispatch = useAppDispatch(); const modelElement = useAppSelector(currentDrawerModelElementSelector); const commentsData = useAppSelector(currentDrawerElementCommentsSelector); - const relatedSubmap = useAppSelector(currentDrawerBioEntityRelatedSubmapSelector); + const relatedSubmap = useAppSelector(currentDrawerModelElementRelatedSubmapSelector); const currentTargetId = modelElement?.id ? `${TARGET_PREFIX}:${modelElement.id}` : ''; const fetchChemicalsForTarget = (): void => { dispatch(getChemicalsForBioEntityDrawerTarget(currentTargetId)); diff --git a/src/components/Map/Drawer/BioEntityDrawer/OverlayData/OverlayData.component.test.tsx b/src/components/Map/Drawer/BioEntityDrawer/OverlayData/OverlayData.component.test.tsx index c03ea1423ece0344fb6bdc0c508f8d4832dd2d76..80c68778991d3e5ae0dc1d1ce11a649e6cc56dde 100644 --- a/src/components/Map/Drawer/BioEntityDrawer/OverlayData/OverlayData.component.test.tsx +++ b/src/components/Map/Drawer/BioEntityDrawer/OverlayData/OverlayData.component.test.tsx @@ -1,6 +1,5 @@ /* eslint-disable no-magic-numbers */ import { ZERO } from '@/constants/common'; -import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { overlayFixture } from '@/models/fixtures/overlaysFixture'; import { GENE_VARIANTS_MOCK } from '@/models/mocks/geneVariantsMock'; import { CORE_PD_MODEL_MOCK } from '@/models/mocks/modelsMock'; @@ -61,26 +60,6 @@ describe('OverlayData - component', () => { ...INITIAL_STORE_STATE_MOCK.overlays, data: [{ ...overlayFixture, name: 'axis name' }], }, - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'pending', - error: { name: '', message: '' }, - data: [ - { - ...bioEntitiesContentFixture[0], - bioEntity: { - ...bioEntitiesContentFixture[0].bioEntity, - id: BIO_ENTITY.id, - }, - }, - ], - }, - ], - loading: 'pending', - error: { name: '', message: '' }, - }, overlayBioEntity: { ...OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK, overlaysId: [OVERLAY_ID], @@ -133,26 +112,6 @@ describe('OverlayData - component', () => { ...INITIAL_STORE_STATE_MOCK.overlays, data: [{ ...overlayFixture, name: 'overlay name' }], }, - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'pending', - error: { name: '', message: '' }, - data: [ - { - ...bioEntitiesContentFixture[0], - bioEntity: { - ...bioEntitiesContentFixture[0].bioEntity, - id: BIO_ENTITY.id, - }, - }, - ], - }, - ], - loading: 'pending', - error: { name: '', message: '' }, - }, overlayBioEntity: { ...OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK, overlaysId: [OVERLAY_ID], @@ -209,26 +168,6 @@ describe('OverlayData - component', () => { ...INITIAL_STORE_STATE_MOCK.overlays, data: [{ ...overlayFixture, name: 'overlay name' }], }, - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'pending', - error: { name: '', message: '' }, - data: [ - { - ...bioEntitiesContentFixture[0], - bioEntity: { - ...bioEntitiesContentFixture[0].bioEntity, - id: BIO_ENTITY.id, - }, - }, - ], - }, - ], - loading: 'pending', - error: { name: '', message: '' }, - }, overlayBioEntity: { ...OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK, overlaysId: [OVERLAY_ID], diff --git a/src/components/Map/Drawer/Drawer.component.test.tsx b/src/components/Map/Drawer/Drawer.component.test.tsx index b677519d0651aab559f7658225e9fd21f0188ea8..200c4fc417fcbbe907174934befc3e380599bd0c 100644 --- a/src/components/Map/Drawer/Drawer.component.test.tsx +++ b/src/components/Map/Drawer/Drawer.component.test.tsx @@ -1,4 +1,3 @@ -import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; import { openBioEntityDrawerById, openReactionDrawerById, @@ -12,10 +11,11 @@ import { getReduxWrapperWithStore, } from '@/utils/testing/getReduxWrapperWithStore'; import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; -import type {} from 'redux-thunk/extend-redux'; -import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { newReactionFixture } from '@/models/fixtures/newReactionFixture'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; import { Drawer } from './Drawer.component'; +import type {} from 'redux-thunk/extend-redux'; const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => { const { Wrapper, store } = getReduxWrapperWithStore(initialStore); @@ -121,20 +121,18 @@ describe('Drawer - component', () => { describe('bioEntity drawer', () => { it.skip('should open drawer and display bioEntity', async () => { - const { id } = bioEntitiesContentFixture[FIRST_ARRAY_ELEMENT].bioEntity; + const { id } = modelElementFixture; const { store } = renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, }, }); diff --git a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx index d0e0d9b6d40bcf3dd53303748a8779b0d6fba0db..12684db74a3fae1700e1d1423e24b85d5acb6be5 100644 --- a/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx +++ b/src/components/Map/Drawer/ExportDrawer/Elements/Elements.component.test.tsx @@ -16,6 +16,7 @@ import { MockStoreEnhanced } from 'redux-mock-store'; import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { COMPARTMENT_SBO_TERM } from '@/components/Map/MapViewer/MapViewer.constants'; +import { MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; import { ELEMENTS_COLUMNS } from '../ExportCompound/ExportCompound.constant'; import { Elements } from './Elements.component'; @@ -133,24 +134,27 @@ describe('Elements - component', () => { }, }, modelElements: { - 0: { - data: [ - { - ...modelElementFixture, - id: FIRST_COMPARMENT_PATHWAY_ID, - name: FIRST_COMPARMENT_PATHWAY_NAME, - sboTerm: COMPARTMENT_SBO_TERM, - }, - { - ...modelElementFixture, - id: SECOND_COMPARMENT_PATHWAY_ID, - name: SECOND_COMPARMENT_PATHWAY_NAME, - sboTerm: COMPARTMENT_SBO_TERM, - }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [ + { + ...modelElementFixture, + id: FIRST_COMPARMENT_PATHWAY_ID, + name: FIRST_COMPARMENT_PATHWAY_NAME, + sboTerm: COMPARTMENT_SBO_TERM, + }, + { + ...modelElementFixture, + id: SECOND_COMPARMENT_PATHWAY_ID, + name: SECOND_COMPARMENT_PATHWAY_NAME, + sboTerm: COMPARTMENT_SBO_TERM, + }, + ], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, } as ModelElementsState, }); diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx index 1a60d63dedff3a165c424ddf54228e8d5dc98b44..ce08ff152ee09b7337fbc5654f23fa543143c831 100644 --- a/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx +++ b/src/components/Map/Drawer/ExportDrawer/ExportCompound/ExportCompound.component.tsx @@ -24,7 +24,7 @@ import { ImageFormat } from './ImageFormat'; import { ImageSize } from './ImageSize'; import { DEFAULT_IMAGE_SIZE } from './ImageSize/ImageSize.constants'; import { ImageSize as ImageSizeType } from './ImageSize/ImageSize.types'; -import { IncludedCompartmentPathways } from './IncludedCompartmentPathways '; +import { IncludedCompartmentPathways } from './IncludedCompartmentPathways'; import { Submap } from './Submap'; import { getDownloadElementsBodyRequest } from './utils/getDownloadElementsBodyRequest'; import { getGraphicsDownloadUrl } from './utils/getGraphicsDownloadUrl'; diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/IncludedCompartmentPathways.component.test.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.test.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/IncludedCompartmentPathways.component.test.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/IncludedCompartmentPathways.component.tsx similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /IncludedCompartmentPathways.component.tsx rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/IncludedCompartmentPathways.component.tsx diff --git a/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /index.ts b/src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/index.ts similarity index 100% rename from src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways /index.ts rename to src/components/Map/Drawer/ExportDrawer/ExportCompound/IncludedCompartmentPathways/index.ts diff --git a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx index 88243df1272535cd78fa5a3a9dbd582963d58375..6241bcd266c87a42f2c64c1b6245e53221ad57ef 100644 --- a/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx +++ b/src/components/Map/Drawer/ExportDrawer/Network/Network.component.test.tsx @@ -16,6 +16,7 @@ import { MockStoreEnhanced } from 'redux-mock-store'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { COMPARTMENT_SBO_TERM } from '@/components/Map/MapViewer/MapViewer.constants'; +import { MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; import { NETWORK_COLUMNS } from '../ExportCompound/ExportCompound.constant'; import { Network } from './Network.component'; @@ -136,24 +137,27 @@ describe('Network - component', () => { }, }, modelElements: { - 0: { - data: [ - { - ...modelElementFixture, - id: FIRST_COMPARMENT_PATHWAY_ID, - name: FIRST_COMPARMENT_PATHWAY_NAME, - sboTerm: COMPARTMENT_SBO_TERM, - }, - { - ...modelElementFixture, - id: SECOND_COMPARMENT_PATHWAY_ID, - name: SECOND_COMPARMENT_PATHWAY_NAME, - sboTerm: COMPARTMENT_SBO_TERM, - }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [ + { + ...modelElementFixture, + id: FIRST_COMPARMENT_PATHWAY_ID, + name: FIRST_COMPARMENT_PATHWAY_NAME, + sboTerm: COMPARTMENT_SBO_TERM, + }, + { + ...modelElementFixture, + id: SECOND_COMPARMENT_PATHWAY_ID, + name: SECOND_COMPARMENT_PATHWAY_NAME, + sboTerm: COMPARTMENT_SBO_TERM, + }, + ], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, } as ModelElementsState, }); diff --git a/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.test.tsx b/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.test.tsx index 0fe3a588ecd06ed39cb31a05821f63f31d6a3ad4..96eea1f9f89db99ef53c8c45ee13bc593a86b217 100644 --- a/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.test.tsx +++ b/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.test.tsx @@ -3,8 +3,8 @@ import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithSto import { InitialStoreState } from '@/utils/testing/getReduxStoreActionsListener'; import { StoreType } from '@/redux/store'; import { render, screen } from '@testing-library/react'; -import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { BIOENTITY_INITIAL_STATE_MOCK } from '@/redux/bioEntity/bioEntity.mock'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { ConnectedBioEntitiesList } from './ConnectedBioEntitiesList.component'; const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { @@ -27,11 +27,21 @@ describe('ConnectedBioEntitiesList', () => { jest.clearAllMocks(); }); - it('renders loading indicator when bioEntityLoading is pending', () => { + it('renders loading indicator when searchModelElementLoading is pending', () => { renderComponent({ - bioEntity: { - ...BIOENTITY_INITIAL_STATE_MOCK, - loading: 'pending', + modelElements: { + data: { + 0: { + data: [modelElementFixture], + loading: 'pending', + error: { message: '', name: '' }, + }, + }, + search: { + data: [], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, }); @@ -41,23 +51,31 @@ describe('ConnectedBioEntitiesList', () => { }); it('renders list of bio entities when bioEntityData is available', () => { - const bioEntityData = [bioEntitiesContentFixture[0]]; - renderComponent({ - bioEntity: { - ...BIOENTITY_INITIAL_STATE_MOCK, - data: [ - { - searchQueryElement: '', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntityData, + error: { message: '', name: '' }, }, - ], + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'idle', + error: DEFAULT_ERROR, + data: [{ modelElement: modelElementFixture, perfect: true }], + }, + ], + loading: 'idle', + error: DEFAULT_ERROR, + }, }, }); expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument(); - expect(screen.queryByText(bioEntitiesContentFixture[0].bioEntity.name)).toBeVisible(); + expect(screen.queryByText(modelElementFixture.name)).toBeVisible(); }); }); diff --git a/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.tsx b/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.tsx index ea016f66f90120c15f6f9cd8524be5df020e48b8..28121e3b9a02128ed609dcb3ceb83d48421df90c 100644 --- a/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.tsx +++ b/src/components/Map/Drawer/ReactionDrawer/ConnectedBioEntitiesList/ConnectedBioEntitiesList.component.tsx @@ -1,15 +1,15 @@ -import { - bioEntityDataListSelector, - bioEntityLoadingSelector, -} from '@/redux/bioEntity/bioEntity.selectors'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { LoadingIndicator } from '@/shared/LoadingIndicator'; import React from 'react'; +import { + searchModelElementsListSelector, + searchModelElementsLoadingSelector, +} from '@/redux/modelElements/modelElements.selector'; import { BioEntitiesPinsListItem } from '../../SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem'; export const ConnectedBioEntitiesList = (): React.ReactNode => { - const bioEntityLoading = useAppSelector(bioEntityLoadingSelector); - const bioEntityData = useAppSelector(bioEntityDataListSelector); + const bioEntityLoading = useAppSelector(searchModelElementsLoadingSelector); + const searchModelElements = useAppSelector(searchModelElementsListSelector); const isPending = bioEntityLoading === 'pending'; if (isPending) { @@ -19,12 +19,12 @@ export const ConnectedBioEntitiesList = (): React.ReactNode => { return ( <div> <h3 className="mb-1 font-semibold">Reaction elements:</h3> - {bioEntityData && - bioEntityData.map(item => ( + {searchModelElements && + searchModelElements.map(item => ( <BioEntitiesPinsListItem - name={item.bioEntity.name} - pin={item.bioEntity} - key={item.bioEntity.name} + name={item.modelElement.name} + pin={item.modelElement} + key={item.modelElement.name} /> ))} </div> diff --git a/src/components/Map/Drawer/ReactionDrawer/ReactionDrawer.component.tsx b/src/components/Map/Drawer/ReactionDrawer/ReactionDrawer.component.tsx index 633c55a8b063830f4ae0fea575051d67ec0f8594..4d65a3b31174c2932d2adfe38db1824a9c4c64a2 100644 --- a/src/components/Map/Drawer/ReactionDrawer/ReactionDrawer.component.tsx +++ b/src/components/Map/Drawer/ReactionDrawer/ReactionDrawer.component.tsx @@ -1,12 +1,14 @@ import { DrawerHeading } from '@/shared/DrawerHeading'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { currentDrawerReactionCommentsSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { CommentItem } from '@/components/Map/Drawer/BioEntityDrawer/Comments/CommentItem.component'; import { ZERO } from '@/constants/common'; import ReactionTypeEnum from '@/utils/reaction/ReactionTypeEnum'; import React from 'react'; import { AnnotationItemList } from '@/components/Map/Drawer/BioEntityDrawer/AnnotationItem/AnnotationItemList.component'; -import { currentDrawerNewReactionSelector } from '@/redux/newReactions/newReactions.selectors'; +import { + currentDrawerNewReactionSelector, + currentDrawerReactionCommentsSelector, +} from '@/redux/newReactions/newReactions.selectors'; import { ConnectedBioEntitiesList } from './ConnectedBioEntitiesList'; export const ReactionDrawer = (): React.ReactNode => { diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsList.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsList.component.tsx index 1a45d10890ed519bf5bc9a3e65744643a1888431..bfe1f3657e1c5417aec0a82681366e3d98ff1bef 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsList.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsList.component.tsx @@ -1,21 +1,30 @@ import { BioEntityContent } from '@/types/models'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; import { BioEntitiesPinsListItem } from './BioEntitiesPinsListItem'; interface BioEntitiesPinsListProps { - bioEnititesPins: BioEntityContent[]; + bioEnititesPins: Array<BioEntityContent | SearchModelElementDataState>; } export const BioEntitiesPinsList = ({ bioEnititesPins }: BioEntitiesPinsListProps): JSX.Element => { return ( <ul className="h-[calc(100%-224px)] max-h-[calc(100%-224px)] overflow-auto px-6 py-2"> {bioEnititesPins && - bioEnititesPins.map(result => ( - <BioEntitiesPinsListItem - key={result.bioEntity.name} - name={result.bioEntity.name} - pin={result.bioEntity} - /> - ))} + bioEnititesPins.map(result => + 'bioEntity' in result ? ( + <BioEntitiesPinsListItem + key={result.bioEntity.name} + name={result.bioEntity.name} + pin={result.bioEntity} + /> + ) : ( + <BioEntitiesPinsListItem + key={result.modelElement.name} + name={result.modelElement.name} + pin={result.modelElement} + /> + ), + )} </ul> ); }; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx index f5f24509780ac842173be756e754697d0be0c17d..e56049b56c5ed3e51995b0cdbf200baebb05d858 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.test.tsx @@ -16,7 +16,7 @@ import { getTypeBySBOTerm } from '@/utils/bioEntity/getTypeBySBOTerm'; import { newReactionsFixture } from '@/models/fixtures/newReactionsFixture'; import { HISTAMINE_MAP_ID } from '@/constants/mocks'; import { BioEntitiesPinsListItem } from './BioEntitiesPinsListItem.component'; -import { PinListBioEntity } from './BioEntitiesPinsListItem.types'; +import { PinListModelElement } from './BioEntitiesPinsListItem.types'; const BIO_ENTITY = { ...bioEntitiesContentFixture[0].bioEntity, @@ -35,7 +35,7 @@ const INITIAL_STORE_WITH_ENTITY_NUMBER: InitialStoreState = { const renderComponent = ( name: string, - pin: PinListBioEntity, + pin: PinListModelElement, initialStoreState: InitialStoreState = {}, ): { store: StoreType } => { const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); @@ -54,7 +54,7 @@ const renderComponent = ( const renderComponentWithActionListener = ( name: string, - pin: PinListBioEntity, + pin: PinListModelElement, initialStoreState: InitialStoreState = {}, ): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => { const { Wrapper, store } = getReduxStoreWithActionsListener(initialStoreState); diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx index d5764b93b440275ee76a200b794dfe6791e6b0bc..e48cef381462d3f6355c90e9436983d0728c0e0e 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.component.tsx @@ -20,12 +20,12 @@ import { getTypeBySBOTerm } from '@/utils/bioEntity/getTypeBySBOTerm'; import { ZERO } from '@/constants/common'; import React from 'react'; import { AnnotationItemList } from '@/components/Map/Drawer/BioEntityDrawer/AnnotationItem/AnnotationItemList.component'; -import { PinListBioEntity } from './BioEntitiesPinsListItem.types'; +import { PinListModelElement } from './BioEntitiesPinsListItem.types'; import { isPinWithCoordinates } from './BioEntitiesPinsListItem.utils'; interface BioEntitiesPinsListItemProps { name: string; - pin: PinListBioEntity; + pin: PinListModelElement; } export const BioEntitiesPinsListItem = ({ @@ -38,7 +38,7 @@ export const BioEntitiesPinsListItem = ({ numberByEntityNumberIdSelector(state, pin.elementId || ''), ); const pinIconCanvas = getCanvasIcon({ - color: PINS_COLORS.bioEntity, + color: PINS_COLORS.modelElement, value: pinIconValue, }); diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts index a916a1dc7f9da06081d656579c979b307e6f010f..a2114d00c76d0a9a46dd0a55ee84525beb817ec3 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts +++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.types.ts @@ -1,15 +1,15 @@ -import { BioEntity } from '@/types/models'; +import { ModelElement } from '@/types/models'; -export type PinListBioEntity = Pick<BioEntity, 'synonyms' | 'references'> & { - symbol?: BioEntity['symbol']; - fullName?: BioEntity['fullName']; - x?: BioEntity['x']; - y?: BioEntity['y']; - elementId?: BioEntity['elementId']; - sboTerm?: BioEntity['sboTerm']; +export type PinListModelElement = Pick<ModelElement, 'synonyms' | 'references'> & { + symbol?: ModelElement['symbol']; + fullName?: ModelElement['fullName']; + x?: ModelElement['x']; + y?: ModelElement['y']; + elementId?: ModelElement['elementId']; + sboTerm?: ModelElement['sboTerm']; }; -export type PinListBioEntityWithCoords = PinListBioEntity & { - x: BioEntity['x']; - y: BioEntity['y']; +export type PinListModelElementWithCoords = PinListModelElement & { + x: ModelElement['x']; + y: ModelElement['y']; }; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts index af28a4c6b83e8b6b1d2ec7dec5f55e2f785b5f02..c1b483d205b55f586bac333bd275300b121ee227 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts +++ b/src/components/Map/Drawer/SearchDrawerWrapper/BioEntitiesResultsList/BioEntitiesPinsList/BioEntitiesPinsListItem/BioEntitiesPinsListItem.utils.ts @@ -1,5 +1,10 @@ -import { PinListBioEntity, PinListBioEntityWithCoords } from './BioEntitiesPinsListItem.types'; +import { + PinListModelElement, + PinListModelElementWithCoords, +} from './BioEntitiesPinsListItem.types'; -export const isPinWithCoordinates = (pin: PinListBioEntity): pin is PinListBioEntityWithCoords => { +export const isPinWithCoordinates = ( + pin: PinListModelElement, +): pin is PinListModelElementWithCoords => { return Boolean('x' in pin && 'y' in pin); }; 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 2f20b71dce6ab874779cbe8b735ec8fb90665143..ddd82ee268c17ee9ec8d790d4cdeef9636242f30 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,5 +1,4 @@ -import { FIRST_ARRAY_ELEMENT, ZERO } from '@/constants/common'; -import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; +import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; import { MODELS_MOCK } from '@/models/mocks/modelsMock'; import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; import { AppDispatch, RootState, StoreType } from '@/redux/store'; @@ -12,6 +11,8 @@ import { import { render, screen } from '@testing-library/react'; import { MockStoreEnhanced } from 'redux-mock-store'; import { HISTAMINE_MAP_ID, MAIN_MAP_ID, PRKN_SUBSTRATES_MAP_ID } from '@/constants/mocks'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { BioEntitiesAccordion } from './BioEntitiesAccordion.component'; const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { @@ -53,17 +54,26 @@ const renderComponentWithActionListener = ( describe('BioEntitiesAccordion - component', () => { it('should display loading indicator when bioEntity search is pending', () => { renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'pending', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, + modelElements: { + data: { + 0: { + data: [modelElementFixture], + loading: 'succeeded', + error: { message: '', name: '' }, }, - ], - loading: 'pending', - error: { name: '', message: '' }, + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'pending', + error: DEFAULT_ERROR, + data: [{ modelElement: modelElementFixture, perfect: true }], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, models: { data: [], @@ -77,17 +87,39 @@ describe('BioEntitiesAccordion - component', () => { it('should render list of maps with number of entities after succeeded bio entity search', () => { renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { name: '', message: '' }, + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { ...modelElementFixture, model: HISTAMINE_MAP_ID }, + perfect: true, + }, + { + modelElement: { ...modelElementFixture, model: MAIN_MAP_ID }, + perfect: true, + }, + { + modelElement: { ...modelElementFixture, model: PRKN_SUBSTRATES_MAP_ID }, + perfect: true, + }, + ], + }, + ], + loading: 'succeeded', + error: DEFAULT_ERROR, + }, }, models: { data: MODELS_MOCK, @@ -96,40 +128,16 @@ describe('BioEntitiesAccordion - component', () => { }, }); - const countHistamine = bioEntitiesContentFixture.filter( - content => content.bioEntity.model === HISTAMINE_MAP_ID, - ).length; - const countCore = bioEntitiesContentFixture.filter( - content => content.bioEntity.model === MAIN_MAP_ID, - ).length; - const countPrkn = bioEntitiesContentFixture.filter( - content => content.bioEntity.model === PRKN_SUBSTRATES_MAP_ID, - ).length; - - const countAll = bioEntitiesContentFixture.length; - - expect(screen.getByText(`Content (${countAll})`)).toBeInTheDocument(); - expect(screen.getByText(`Core PD map (${countCore})`)).toBeInTheDocument(); - if (countHistamine > ZERO) { - expect(screen.getByText(`Histamine signaling (${countHistamine})`)).toBeInTheDocument(); - } - expect(screen.getByText(`PRKN substrates (${countPrkn})`)).toBeInTheDocument(); + expect(screen.getByText(`Content (3)`)).toBeInTheDocument(); + expect(screen.getByText(`Core PD map (1)`)).toBeInTheDocument(); + expect(screen.getByText(`Histamine signaling (1)`)).toBeInTheDocument(); + expect(screen.getByText(`PRKN substrates (1)`)).toBeInTheDocument(); }); it('should fire toggleIsContentTabOpened on accordion item button click', () => { const { store } = renderComponentWithActionListener({ ...INITIAL_STORE_STATE_MOCK, bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, - }, - ], - loading: 'succeeded', - error: { name: '', message: '' }, isContentTabOpened: false, }, models: { diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx index 8754b663a1c714f0f8e3e4740ae012bc23c0ab3c..cc4d65aa1ca663e6425477e0d47f82cfeff4153c 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesAccordion.component.tsx @@ -1,9 +1,4 @@ -import { - bioEntitiesPerModelSelector, - bioEntityIsContentTabOpenedSelector, - loadingBioEntityStatusSelector, - numberOfBioEntitiesSelector, -} from '@/redux/bioEntity/bioEntity.selectors'; +import { bioEntityIsContentTabOpenedSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { toggleIsContentTabOpened } from '@/redux/bioEntity/bioEntity.slice'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; @@ -13,13 +8,18 @@ import { AccordionItemHeading, AccordionItemPanel, } from '@/shared/Accordion'; +import { + numberOfSearchModelElementsSelector, + searchModelElementsLoadingStatusSelector, + searchModelElementsPerModelSelector, +} from '@/redux/modelElements/modelElements.selector'; import { BioEntitiesSubmapItem } from './BioEntitiesSubmapItem'; export const BioEntitiesAccordion = (): JSX.Element => { const dispatch = useAppDispatch(); - const bioEntitiesNumber = useAppSelector(numberOfBioEntitiesSelector); - const bioEntitiesState = useAppSelector(loadingBioEntityStatusSelector); - const bioEntitiesPerModel = useAppSelector(bioEntitiesPerModelSelector); + const searchModelElementsNumber = useAppSelector(numberOfSearchModelElementsSelector); + const searchModelElementsLoadingStatus = useAppSelector(searchModelElementsLoadingStatusSelector); + const searchModelElementsPerModel = useAppSelector(searchModelElementsPerModelSelector); const isContentTabOpened = useAppSelector(bioEntityIsContentTabOpenedSelector); const toggleTabOpened = (): void => { @@ -30,18 +30,18 @@ export const BioEntitiesAccordion = (): JSX.Element => { <AccordionItem dangerouslySetExpanded={isContentTabOpened}> <AccordionItemHeading> <AccordionItemButton onClick={toggleTabOpened}> - Content {bioEntitiesState === 'pending' && ' (Loading...)'} - {bioEntitiesState === 'succeeded' && ` (${bioEntitiesNumber})`} + Content {searchModelElementsLoadingStatus === 'pending' && ' (Loading...)'} + {searchModelElementsLoadingStatus === 'succeeded' && ` (${searchModelElementsNumber})`} </AccordionItemButton> </AccordionItemHeading> <AccordionItemPanel> - {bioEntitiesPerModel.map(model => ( + {searchModelElementsPerModel.map(model => ( <BioEntitiesSubmapItem key={model.modelName} mapName={model.modelName} mapId={model.modelId} - numberOfEntities={model.numberOfEntities} - bioEntities={model.bioEntities} + numberOfModelElements={model.numberOfModelElements} + modelElements={model.modelElements} /> ))} </AccordionItemPanel> diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.test.tsx index a93282dbc8057e22d7db0fcdf38bb59f57290fa6..6b0d1c35bb9bcf9ca38f3243782797330af9e1a2 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.test.tsx @@ -1,7 +1,6 @@ /* eslint-disable no-magic-numbers */ import { act, render, screen } from '@testing-library/react'; import { StoreType } from '@/redux/store'; -import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { InitialStoreState, getReduxWrapperWithStore, @@ -14,6 +13,8 @@ import { openedMapsThreeSubmapsFixture, } from '@/redux/map/map.fixtures'; import { MAIN_MAP_ID } from '@/constants/mocks'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { BioEntitiesSubmapItem } from './BioEntitiesSubmapItem.component'; const SECOND_STEP = 2; @@ -27,8 +28,8 @@ const renderComponent = (initialStoreState: InitialStoreState = {}): { store: St <BioEntitiesSubmapItem mapName={MODELS_MOCK_SHORT[0].name} mapId={MODELS_MOCK_SHORT[0].id} - numberOfEntities={21} - bioEntities={bioEntitiesContentFixture} + numberOfModelElements={21} + modelElements={[{ modelElement: modelElementFixture, perfect: true }]} /> </Wrapper>, ), @@ -47,17 +48,26 @@ describe('BioEntitiesSubmapItem - component', () => { }); it('should navigate user to bio enitites results list after clicking button', async () => { const { store } = renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { name: '', message: '' }, + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'idle', + error: DEFAULT_ERROR, + data: [{ modelElement: modelElementFixture, perfect: true }], + }, + ], + loading: 'idle', + error: DEFAULT_ERROR, + }, }, drawer: drawerSearchStepOneFixture, }); @@ -73,25 +83,13 @@ describe('BioEntitiesSubmapItem - component', () => { }, } = store.getState(); - expect(stepType).toBe('bioEntity'); + expect(stepType).toBe('modelElement'); expect(selectedValue).toBe(undefined); expect(currentStep).toBe(SECOND_STEP); - expect(listOfBioEnitites).toBe(bioEntitiesContentFixture); + expect(listOfBioEnitites).toStrictEqual([{ modelElement: modelElementFixture, perfect: true }]); }); it("should open submap and set it to active if it's not already opened", async () => { const { store } = renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, - }, - ], - loading: 'succeeded', - error: { name: '', message: '' }, - }, drawer: drawerSearchStepOneFixture, models: { data: MODELS_MOCK_SHORT, loading: 'succeeded', error: { name: '', message: '' } }, map: { @@ -100,6 +98,27 @@ describe('BioEntitiesSubmapItem - component', () => { error: { name: '', message: '' }, openedMaps: openedMapsInitialValueFixture, }, + modelElements: { + data: { + 0: { + data: [modelElementFixture], + loading: 'succeeded', + error: { message: '', name: '' }, + }, + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'idle', + error: DEFAULT_ERROR, + data: [{ modelElement: modelElementFixture, perfect: true }], + }, + ], + loading: 'idle', + error: DEFAULT_ERROR, + }, + }, }); const { @@ -134,18 +153,6 @@ describe('BioEntitiesSubmapItem - component', () => { }); it("should set map active if it's already opened", async () => { const { store } = renderComponent({ - bioEntity: { - data: [ - { - searchQueryElement: '', - loading: 'succeeded', - error: { name: '', message: '' }, - data: bioEntitiesContentFixture, - }, - ], - loading: 'succeeded', - error: { name: '', message: '' }, - }, drawer: drawerSearchStepOneFixture, models: { data: MODELS_MOCK_SHORT, loading: 'succeeded', error: { name: '', message: '' } }, map: { diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.tsx index 47f2e4b205195d6f35e457fb5920f79e327c516a..086ae4ce450dc4183570f32a3006dac7e348b116 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/GroupedSearchResults/BioEntitiesAccordion/BioEntitiesSubmapItem/BioEntitiesSubmapItem.component.tsx @@ -7,20 +7,20 @@ import { mapModelIdSelector, mapOpenedMapsSelector } from '@/redux/map/map.selec import { openMapAndSetActive, setActiveMap } from '@/redux/map/map.slice'; import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; import { Icon } from '@/shared/Icon'; -import { BioEntityContent } from '@/types/models'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; export interface BioEntitiesSubmapItemProps { mapName: string; mapId: number; - numberOfEntities: string | number; - bioEntities: BioEntityContent[]; + numberOfModelElements: string | number; + modelElements: SearchModelElementDataState[]; } export const BioEntitiesSubmapItem = ({ mapName, mapId, - numberOfEntities, - bioEntities, + numberOfModelElements, + modelElements, }: BioEntitiesSubmapItemProps): JSX.Element => { const dispatch = useAppDispatch(); const openedMaps = useAppSelector(mapOpenedMapsSelector); @@ -43,7 +43,7 @@ export const BioEntitiesSubmapItem = ({ const onSubmapClick = (): void => { openSubmap(); - dispatch(displayBioEntitiesList(bioEntities)); + dispatch(displayBioEntitiesList(modelElements)); const locationButton = document.querySelector<HTMLButtonElement>(`#${LOCATION_BTN_ID}`); if (locationButton) { @@ -59,7 +59,7 @@ export const BioEntitiesSubmapItem = ({ data-testid="bio-entites-submap-button" > <p className="text-sm font-normal"> - {mapName} ({numberOfEntities}) + {mapName} ({numberOfModelElements}) </p> <Icon name="arrow" className="h-6 w-6 fill-font-500" data-testid="arrow-icon" /> </button> diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx index ec42327545d17bdddbf3fee361ee6597b717ea54..1835a35aa3b6f0f72b858aab5c99e6a641c20d48 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.test.tsx @@ -61,8 +61,8 @@ describe('PinsList - component ', () => { expect(screen.getByTestId('accordions-details')).toBeInTheDocument(); }); - it('should not display list of bio enities when bioEntity is searched', () => { - renderComponent([], 'bioEntity'); + it('should not display list of bio enities when modelElement is searched', () => { + renderComponent([], 'modelElement'); expect(screen.queryByTestId('pins-list')).toBeNull(); }); diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx index d612aae39c45cc2e5bd3bd258ab2e9a7775b2d4f..931d6f33a0a968c2421191ec5b9fdac1a81671dc 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.component.tsx @@ -37,7 +37,7 @@ export const PinsList = ({ pinsList, type }: PinsListProps): JSX.Element => { </div> ); } - case 'bioEntity': + case 'modelElement': return <div />; case 'comment': return <div />; diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx index a72f8629e2eb718e43e56b5471183f837f785aba..a72a61edcbfa4f7aac9a33e865bb8ac1a69071cb 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsList.types.tsx @@ -1,4 +1,4 @@ -import { BioEntity, Chemical, Drug, PinDetailsItem } from '@/types/models'; +import { Chemical, Drug, ModelElement, PinDetailsItem } from '@/types/models'; import { PinType } from '@/types/pin'; export type PinItem = { @@ -17,5 +17,5 @@ export type AvailableSubmaps = { export type TargetElement = { target: PinDetailsItem; - element: BioEntity; + element: ModelElement; }; 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 ce80ff1c3bee164941694df5993bc573e4bea953..d6a031e994ac91a7c94ccfd381cb805e217462c9 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 @@ -3,15 +3,15 @@ import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFi import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture'; import { drugsFixture } from '@/models/fixtures/drugFixtures'; import { AppDispatch, RootState } from '@/redux/store'; -import { BioEntity, PinDetailsItem } from '@/types/models'; +import { ModelElement, PinDetailsItem } from '@/types/models'; import { InitialStoreState } from '@/utils/testing/getReduxWrapperWithStore'; import { render, screen } from '@testing-library/react'; -// import { MODELS_MOCK_SHORT } from '@/models/mocks/modelsMock'; import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures'; import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock'; import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; import { MockStoreEnhanced } from 'redux-mock-store'; import { MAIN_MAP_ID } from '@/constants/mocks'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; import { PinTypeWithNone } from '../PinsList.types'; import { PinsListItem } from './PinsListItem.component'; @@ -26,10 +26,7 @@ const CHEMICALS_PIN = { }; const PIN_NUMBER = 10; -const BIO_ENTITY = { - ...bioEntitiesContentFixture[0].bioEntity, - model: 5053, -}; +const MODEL_ELEMENT = modelElementFixture; const INITIAL_STORE_STATE: InitialStoreState = { models: MODELS_DATA_MOCK_WITH_MAIN_MAP, @@ -48,7 +45,7 @@ const renderComponent = ( name: string, pin: PinDetailsItem, type: PinTypeWithNone, - element: BioEntity, + element: ModelElement, initialStoreState: InitialStoreState = {}, ): { store: MockStoreEnhanced<Partial<RootState>, AppDispatch> } => { const { Wrapper, store } = getReduxStoreWithActionsListener(initialStoreState); @@ -72,14 +69,14 @@ describe('PinsListItem - component ', () => { chemicalsFixture[0].targets[0].targetParticipants[1].link = 'https://example.com/plugin.js'; it('should display full name of pin', () => { - renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', BIO_ENTITY, INITIAL_STORE_STATE); + renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', MODEL_ELEMENT, INITIAL_STORE_STATE); const drugName = drugsFixture[0].targets[0].name; expect(screen.getByText(drugName)).toBeInTheDocument(); }); it('should display list of elements for pin for drugs', () => { - renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', BIO_ENTITY, INITIAL_STORE_STATE); + renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', MODEL_ELEMENT, INITIAL_STORE_STATE); const firstPinElementType = drugsFixture[0].targets[0].targetParticipants[0].type; const firstPinElementResource = drugsFixture[0].targets[0].targetParticipants[0].resource; @@ -95,7 +92,7 @@ describe('PinsListItem - component ', () => { } }); it('should display list of references for pin', () => { - renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', BIO_ENTITY, INITIAL_STORE_STATE); + renderComponent(DRUGS_PIN.name, DRUGS_PIN.pin, 'drugs', MODEL_ELEMENT, INITIAL_STORE_STATE); const firstPinReferenceType = drugsFixture[0].targets[0].references[0].type; const firstPinReferenceResource = drugsFixture[0].targets[0].references[0].resource; @@ -112,7 +109,7 @@ describe('PinsListItem - component ', () => { CHEMICALS_PIN.name, CHEMICALS_PIN.pin, 'chemicals', - BIO_ENTITY, + MODEL_ELEMENT, INITIAL_STORE_STATE, ); @@ -129,7 +126,7 @@ describe('PinsListItem - component ', () => { // TODO - it's probably flacky test it.skip('should not display list of elements for pin for bioentities', () => { - renderComponent(CHEMICALS_PIN.name, CHEMICALS_PIN.pin, 'drugs', BIO_ENTITY); + renderComponent(CHEMICALS_PIN.name, CHEMICALS_PIN.pin, 'drugs', MODEL_ELEMENT); const bioEntityName = bioEntitiesContentFixture[2].bioEntity.fullName ? bioEntitiesContentFixture[2].bioEntity.fullName @@ -147,7 +144,7 @@ describe('PinsListItem - component ', () => { CHEMICALS_PIN.name, chemicalWithoutSubmaps, 'chemicals', - BIO_ENTITY, + MODEL_ELEMENT, INITIAL_STORE_STATE, ); @@ -159,7 +156,7 @@ describe('PinsListItem - component ', () => { DRUGS_PIN.pin, 'drugs', { - ...BIO_ENTITY, + ...MODEL_ELEMENT, x: 1000, y: 500, }, @@ -168,7 +165,7 @@ describe('PinsListItem - component ', () => { map: { data: { ...initialMapDataFixture, - modelId: BIO_ENTITY.model, + modelId: MODEL_ELEMENT.model, }, loading: 'succeeded', error: { message: '', name: '' }, @@ -191,7 +188,7 @@ describe('PinsListItem - component ', () => { DRUGS_PIN.pin, 'drugs', { - ...BIO_ENTITY, + ...MODEL_ELEMENT, x: 1000, y: 500, model: 52, @@ -201,7 +198,7 @@ describe('PinsListItem - component ', () => { map: { data: { ...initialMapDataFixture, - modelId: BIO_ENTITY.model, + modelId: MODEL_ELEMENT.model, }, loading: 'succeeded', error: { message: '', name: '' }, diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx index 510763ad3763e75131c61b0bde95796dd9edd1d3..880561dabd92d6e104c71871d0a7d7752ad0373b 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.tsx @@ -9,7 +9,7 @@ import { mapModelIdSelector, mapOpenedMapsSelector } from '@/redux/map/map.selec import { openMapAndSetActive, setActiveMap, setMapPosition } from '@/redux/map/map.slice'; import { modelsDataSelector, modelsNameMapSelector } from '@/redux/models/models.selectors'; import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; -import { BioEntity, PinDetailsItem } from '@/types/models'; +import { ModelElement, PinDetailsItem } from '@/types/models'; import { AvailableSubmaps, PinTypeWithNone } from '../PinsList.types'; import { getListOfAvailableSubmaps } from './PinsListItem.component.utils'; @@ -17,7 +17,7 @@ interface PinsListItemProps { name: string; type: PinTypeWithNone; pin: PinDetailsItem; - element: BioEntity; + element: ModelElement; number: number; } diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts index 26f457761b94201d5e7c45aef0e0270376aef058..7a0bffd5d253e02239e44d9b9ec2f0eb175cd40a 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts +++ b/src/components/Map/Drawer/SearchDrawerWrapper/ResultsList/PinsList/PinsListItem/PinsListItem.component.utils.ts @@ -5,7 +5,7 @@ const MAIN_MAP_ID = 52; export const getPinColor = (type: PinTypeWithNone): string => { const pinColors: Record<PinTypeWithNone, string> = { - bioEntity: 'fill-primary-500', + modelElement: 'fill-primary-500', drugs: 'fill-orange', chemicals: 'fill-purple', comment: 'fill-blue', diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx index 3d5b627bc96d13a0b96a00150c8627afae1664f7..a55ff7807be96e614dd378aa698d9f00214b687c 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.test.tsx @@ -38,7 +38,7 @@ describe('SearchDrawerWrapper - component', () => { drawerName: 'search', searchDrawerState: { currentStep: 2, - stepType: 'bioEntity', + stepType: 'modelElement', selectedValue: undefined, listOfBioEnitites: [], selectedSearchElement: '', diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.tsx index 573435d06b78f5c47a9028078886e65112eadd67..66912c6d22d277753ed0cd1b9371f202cc3f4e6f 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerWrapper.component.tsx @@ -1,4 +1,4 @@ -import { BIO_ENTITY, DRUGS_CHEMICALS } from '@/constants'; +import { MODEL_ELEMENT, DRUGS_CHEMICALS } from '@/constants'; import { STEP } from '@/constants/searchDrawer'; import { currentStepDrawerStateSelector, @@ -15,7 +15,7 @@ export const SearchDrawerWrapper = (): JSX.Element => { const currentStep = useSelector(currentStepDrawerStateSelector); const stepType = useSelector(stepTypeDrawerSelector); - const isBioEntityType = stepType === BIO_ENTITY; + const isBioEntityType = stepType === MODEL_ELEMENT; const isChemicalsOrDrugsType = DRUGS_CHEMICALS.includes(stepType); return ( diff --git a/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts index 7cfb93047a9a73ad2edca9f6b92c8dde539c1120..0e377e4f3bd7f02cbf644dde62fb3d4298c27205 100644 --- a/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts +++ b/src/components/Map/MapAdditionalActions/utils/useVisibleBioEntitiesPolygonCoordinates.test.ts @@ -1,6 +1,5 @@ import { drugsFixture } from '@/models/fixtures/drugFixtures'; /* eslint-disable no-magic-numbers */ -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { chemicalsFixture } from '@/models/fixtures/chemicalsFixture'; import { modelsFixture } from '@/models/fixtures/modelsFixture'; import { BIOENTITY_INITIAL_STATE_MOCK } from '@/redux/bioEntity/bioEntity.mock'; @@ -10,6 +9,9 @@ import { RootState } from '@/redux/store'; import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; import { renderHook } from '@testing-library/react'; import { HISTAMINE_MAP_ID } from '@/constants/mocks'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { CHEMICALS_INITIAL_STATE_MOCK } from '../../../../redux/chemicals/chemicals.mock'; import { DRUGS_INITIAL_STATE_MOCK } from '../../../../redux/drugs/drugs.mock'; import { DEFAULT_POSITION, MAIN_MAP, MAP_INITIAL_STATE } from '../../../../redux/map/map.constants'; @@ -65,28 +67,39 @@ const getInitalState = ( { modelId: HISTAMINE_MAP_ID, modelName: MAIN_MAP, lastPosition: DEFAULT_POSITION }, ], }, - bioEntity: { - ...BIOENTITY_INITIAL_STATE_MOCK, - data: [ - { - searchQueryElement: 'search', - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - model: HISTAMINE_MAP_ID, - x: 16, - y: 16, - z: 1, - }, - }, - ].slice(0, elementsLimit), + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', error: { message: '', name: '' }, }, - ], - }, + }, + search: { + data: [ + { + searchQueryElement: 'search', + loading: 'pending', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + model: HISTAMINE_MAP_ID, + x: 16, + y: 16, + z: 1, + }, + perfect: true, + }, + ], + }, + ].slice(0, elementsLimit), + loading: 'pending', + error: DEFAULT_ERROR, + }, + } as ModelElementsState, + bioEntity: BIOENTITY_INITIAL_STATE_MOCK, chemicals: { ...CHEMICALS_INITIAL_STATE_MOCK, data: [ diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts index 7a0643c598657cf89b2a718680e8ef316b3bfe61..f8e49762d1f9b34d756a713b3683d3f051309641 100644 --- a/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts +++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/useBioEntitiesWithSubmapLinks.test.ts @@ -10,9 +10,10 @@ import { OVERLAY_BIO_ENTITY_INITIAL_STATE_MOCK, } from '@/redux/overlayBioEntity/overlayBioEntity.mock'; import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock'; -import { MAIN_MAP_ID } from '@/constants/mocks'; -import { BIO_ENTITY_LINKING_TO_SUBMAP } from '@/redux/bioEntity/bioEntity.mock'; -import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; +import { + MODEL_ELEMENT_LINKING_TO_SUBMAP, + MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, +} from '@/redux/modelElements/modelElements.mock'; import { useBioEntitiesWithSubmapsLinks } from './useBioEntitiesWithSubmapLinks'; const RESULT_SUBMAP_LINKS_DIFFERENT_VALUES = [ @@ -184,12 +185,15 @@ describe('useBioEntitiesWithSubmapsLinks', () => { }, configuration: CONFIGURATION_INITIAL_STORE_MOCKS, modelElements: { - [MAIN_MAP_ID]: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 52: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, map: mapStateWithCurrentlySelectedMainMapFixture, }); @@ -214,12 +218,15 @@ describe('useBioEntitiesWithSubmapsLinks', () => { }, }, modelElements: { - 52: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 52: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, configuration: CONFIGURATION_INITIAL_STORE_MOCKS, map: mapStateWithCurrentlySelectedMainMapFixture, @@ -262,12 +269,15 @@ describe('useBioEntitiesWithSubmapsLinks', () => { }, }, modelElements: { - 52: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 52: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, configuration: CONFIGURATION_INITIAL_STORE_MOCKS, map: mapStateWithCurrentlySelectedMainMapFixture, @@ -298,12 +308,15 @@ describe('useBioEntitiesWithSubmapsLinks', () => { }, }, modelElements: { - 52: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 52: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, configuration: CONFIGURATION_INITIAL_STORE_MOCKS, map: mapStateWithCurrentlySelectedMainMapFixture, @@ -346,12 +359,15 @@ describe('useBioEntitiesWithSubmapsLinks', () => { }, }, modelElements: { - 52: { - data: [BIO_ENTITY_LINKING_TO_SUBMAP], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 52: { + data: [MODEL_ELEMENT_LINKING_TO_SUBMAP], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, - } as ModelElementsState, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, + }, configuration: CONFIGURATION_INITIAL_STORE_MOCKS, map: mapStateWithCurrentlySelectedMainMapFixture, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts index 4103719aa1ac8767c06c9cce13cefbd4d65c035f..0514e367e2ad74f083346df932760ebceb0d269d 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts @@ -1,11 +1,11 @@ import { EntityNumber } from '@/redux/entityNumber/entityNumber.types'; -import { BioEntityWithPinType } from '@/types/bioEntity'; +import { ModelElementWithPinType } from '@/types/modelElement'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { Feature } from 'ol'; -import { getBioEntitySingleFeature } from './getBioEntitySingleFeature'; +import { getModelElementSingleFeature } from './getModelElementSingleFeature'; export const getBioEntitiesFeatures = ( - bioEntites: BioEntityWithPinType[], + bioEntites: ModelElementWithPinType[], { pointToProjection, entityNumber, @@ -17,7 +17,7 @@ export const getBioEntitiesFeatures = ( }, ): Feature[] => { return bioEntites.map(bioEntity => - getBioEntitySingleFeature(bioEntity, { + getModelElementSingleFeature(bioEntity, { pointToProjection, type: bioEntity.type, // pin's index number diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts index ea28c2543c3ca8e368b66490cf2b872f4e656d64..dc7c44c51ff5c2010b62433d9aa53f06da8fed47 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntititesFeatures.test.ts @@ -2,7 +2,7 @@ import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; import { bioEntitiesContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { initialMapStateFixture } from '@/redux/map/map.fixtures'; import { PinType } from '@/types/pin'; -import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection'; +import { usePointToProjection, UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { GetReduxWrapperUsingSliceReducer, getReduxWrapperWithStore, @@ -26,10 +26,9 @@ describe('getBioEntitiesFeatures - subUtil', () => { const { Wrapper } = getReduxWrapperWithStore({ map: initialMapStateFixture, }); - const bioEntititesContent = bioEntitiesContentFixture; - const bioEntities = bioEntititesContent.map(({ bioEntity }) => ({ + const bioEntities = bioEntitiesContentFixture.map(({ bioEntity }) => ({ ...bioEntity, - type: 'bioEntity' as PinType, + type: 'modelElement' as PinType, })); const pointToProjection = getPointToProjection(Wrapper); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts index c4114ff55e165d946b93c9733355bc4a69bc0bb9..2313616d12732d821f2ad31c5304772c3a119f19 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts @@ -13,7 +13,7 @@ export const getMarkerSingleFeature = ( pointToProjection: UsePointToProjectionResult; }, ): Feature => { - const feature = getPinFeature(marker, pointToProjection, 'bioEntity'); + const feature = getPinFeature(marker, pointToProjection, 'modelElement'); const style = getPinStyle({ color: addAlphaToHexString(marker.color, marker.opacity), value: marker.number, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.test.ts similarity index 83% rename from src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts rename to src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.test.ts index 2455acf1750809a890cb70699aff608d84a21b80..23b9cdd9a6f5838fbe9b569b3b84188d74056e42 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.test.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.test.ts @@ -1,6 +1,5 @@ /* eslint-disable no-magic-numbers */ import { PINS_COLORS, TEXT_COLOR } from '@/constants/canvas'; -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { initialMapStateFixture } from '@/redux/map/map.fixtures'; import { PinType } from '@/types/pin'; import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString'; @@ -12,7 +11,8 @@ import { import { renderHook } from '@testing-library/react'; import { Feature } from 'ol'; import Style from 'ol/style/Style'; -import { getBioEntitySingleFeature } from './getBioEntitySingleFeature'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { getModelElementSingleFeature } from './getModelElementSingleFeature'; import * as getPinStyle from './getPinStyle'; jest.mock('./getPinStyle', () => ({ @@ -30,18 +30,17 @@ const getPointToProjection = ( return usePointToProjectionHook.current; }; -describe('getBioEntitySingleFeature - subUtil', () => { +describe('getModelElementSingleFeature - subUtil', () => { const { Wrapper } = getReduxWrapperWithStore({ map: initialMapStateFixture, }); - const { bioEntity } = bioEntityContentFixture; const pointToProjection = getPointToProjection(Wrapper); const value = 1448; - const pinTypes: PinType[] = ['bioEntity', 'drugs', 'chemicals']; + const pinTypes: PinType[] = ['modelElement', 'drugs', 'chemicals']; it.each(pinTypes)('should return instance of Feature with Style type=%s', type => { - const result = getBioEntitySingleFeature(bioEntity, { + const result = getModelElementSingleFeature(modelElementFixture, { pointToProjection, type, value, @@ -57,7 +56,7 @@ describe('getBioEntitySingleFeature - subUtil', () => { it.each(pinTypes)('should run getPinStyle with valid args for type=%s', type => { const getPinStyleSpy = jest.spyOn(getPinStyle, 'getPinStyle'); - getBioEntitySingleFeature(bioEntity, { + getModelElementSingleFeature(modelElementFixture, { pointToProjection, type, value, @@ -76,7 +75,7 @@ describe('getBioEntitySingleFeature - subUtil', () => { type => { const getPinStyleSpy = jest.spyOn(getPinStyle, 'getPinStyle'); - getBioEntitySingleFeature(bioEntity, { + getModelElementSingleFeature(modelElementFixture, { pointToProjection, type, value, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.ts similarity index 83% rename from src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts rename to src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.ts index 4fd4447318e8f5e4ee9435f07c0b9fdf367b6f1c..18a6f33748e56529803991c30a989f13a5f47af2 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitySingleFeature.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getModelElementSingleFeature.ts @@ -1,5 +1,5 @@ import { PINS_COLORS, TEXT_COLOR } from '@/constants/canvas'; -import { BioEntity } from '@/types/models'; +import { ModelElement } from '@/types/models'; import { PinType } from '@/types/pin'; import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; @@ -9,8 +9,8 @@ import { getPinStyle } from './getPinStyle'; const INACTIVE_ELEMENT_OPACITY = 0.5; -export const getBioEntitySingleFeature = ( - bioEntity: BioEntity, +export const getModelElementSingleFeature = ( + modelElement: ModelElement, { pointToProjection, type, @@ -31,7 +31,7 @@ export const getBioEntitySingleFeature = ( ? TEXT_COLOR : addAlphaToHexString(TEXT_COLOR, INACTIVE_ELEMENT_OPACITY); - const feature = getPinFeature(bioEntity, pointToProjection, type); + const feature = getPinFeature(modelElement, pointToProjection, type); const style = getPinStyle({ color, value, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinCanvasArgs.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinCanvasArgs.ts index 61726c4926a67f6e0e48a21d8367f82509123e9b..104839b6e0197bf60f74c475df4186b13f8e2764 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinCanvasArgs.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinCanvasArgs.ts @@ -1,6 +1,6 @@ import { PINS_COLORS, TEXT_COLOR } from '@/constants/canvas'; import { EntityNumber } from '@/redux/entityNumber/entityNumber.types'; -import { BioEntityWithPinType } from '@/types/bioEntity'; +import { ModelElementWithPinType } from '@/types/modelElement'; import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString'; import { mix } from 'polished'; import { GetCanvasIconArgs } from '../getCanvasIcon'; @@ -15,7 +15,7 @@ interface Options { } export const getMultipinCanvasArgs = ( - { type, ...element }: BioEntityWithPinType, + { type, ...element }: ModelElementWithPinType, { entityNumber, activeIds, isDarkColor }: Options, ): GetCanvasIconArgs => { const value = entityNumber?.[element.elementId]; diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.test.ts index 10906ccf7ab8f950ad4ab1d773210424b1fec595..d4ffaacb98f019d20891b2b340a029a9ca4c2a21 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.test.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.test.ts @@ -2,7 +2,7 @@ import { FIRST_ARRAY_ELEMENT } from '@/constants/common'; import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { EntityNumber } from '@/redux/entityNumber/entityNumber.types'; import { initialMapStateFixture } from '@/redux/map/map.fixtures'; -import { MultiPinBioEntity } from '@/types/bioEntity'; +import { MultiPinModelElement } from '@/types/modelElement'; import { PinType } from '@/types/pin'; import { UsePointToProjectionResult, usePointToProjection } from '@/utils/map/usePointToProjection'; import { @@ -20,10 +20,10 @@ jest.mock('./getMultipinStyle', () => ({ ...jest.requireActual('./getMultipinStyle'), })); -const ONE_MULTI_BIO_ENTITIES: MultiPinBioEntity = [ +const ONE_MULTI_BIO_ENTITIES: MultiPinModelElement = [ { ...bioEntityContentFixture.bioEntity, - type: 'bioEntity' as PinType, + type: 'modelElement' as PinType, x: 100, y: 100, }, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.ts index d7280c47ee5ffcd745ab7f982e3347c788e47968..cc9e5a78bd5ac475af1ef5e2d357f74d583d9d64 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinSingleFeature.ts @@ -1,6 +1,6 @@ import { ONE, ZERO } from '@/constants/common'; import { EntityNumber } from '@/redux/entityNumber/entityNumber.types'; -import { BioEntityWithPinType, MultiPinBioEntity } from '@/types/bioEntity'; +import { ModelElementWithPinType, MultiPinModelElement } from '@/types/modelElement'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { Feature } from 'ol'; import { getMultipinCanvasArgs } from './getMultipinCanvasArgs'; @@ -8,7 +8,7 @@ import { getMultipinStyle } from './getMultipinStyle'; import { getPinFeature } from './getPinFeature'; export const getMultipinSingleFeature = ( - multipin: MultiPinBioEntity, + multipin: MultiPinModelElement, { pointToProjection, entityNumber, @@ -30,7 +30,7 @@ export const getMultipinSingleFeature = ( isDarkColor: true, }); - const canvasPinsArgs = sortedElements.map((element: BioEntityWithPinType) => + const canvasPinsArgs = sortedElements.map((element: ModelElementWithPinType) => getMultipinCanvasArgs(element, { activeIds, entityNumber: {}, // additional elements id's should be not visible diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.test.ts deleted file mode 100644 index 3c5778deb7d30cbad7c1f14e0d3f1f2c5b6185eb..0000000000000000000000000000000000000000 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { MultiPinBioEntity } from '@/types/bioEntity'; -import { PinType } from '@/types/pin'; -import { getMultipinsBioEntities } from './getMultipinsBioEntities'; - -const ZERO_MULTI_BIO_ENTITIES: MultiPinBioEntity = [ - { - ...bioEntityContentFixture.bioEntity, - type: 'bioEntity' as PinType, - }, - { - ...bioEntityContentFixture.bioEntity, - x: 1000, - type: 'bioEntity' as PinType, - }, -]; - -const ONE_MULTI_BIO_ENTITIES: MultiPinBioEntity = [ - { - ...bioEntityContentFixture.bioEntity, - type: 'bioEntity' as PinType, - x: 100, - y: 100, - }, - { - ...bioEntityContentFixture.bioEntity, - type: 'drugs' as PinType, - x: 100, - y: 100, - }, -]; - -const FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE: MultiPinBioEntity = [ - { - ...bioEntityContentFixture.bioEntity, - type: 'bioEntity' as PinType, - x: 100, - y: 100, - }, - { - ...bioEntityContentFixture.bioEntity, - type: 'drugs' as PinType, - x: 100, - y: 100, - }, - { - ...bioEntityContentFixture.bioEntity, - type: 'drugs' as PinType, - x: 100, - y: 100, - }, - { - ...bioEntityContentFixture.bioEntity, - type: 'drugs' as PinType, - x: 100, - y: 100, - }, -]; - -describe('getMultipinsBioEntities - util', () => { - it('should return empty array if theres no multi pins', () => { - expect(getMultipinsBioEntities({ bioEntities: ZERO_MULTI_BIO_ENTITIES })).toStrictEqual([]); - }); - - it('should return valid multi pins', () => { - expect(getMultipinsBioEntities({ bioEntities: ONE_MULTI_BIO_ENTITIES })).toStrictEqual([ - ONE_MULTI_BIO_ENTITIES, - ]); - }); - - it('should return valid multi pins if theres few types of pins', () => { - expect( - getMultipinsBioEntities({ bioEntities: FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE }), - ).toStrictEqual([ONE_MULTI_BIO_ENTITIES]); - }); -}); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntitiesIds.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntitiesIds.ts index ffe07c3a1c3a2189522a5246553a5e6e14af9d1c..385e0c956313efeebb5c4c5b2b52d6958f293bd4 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntitiesIds.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntitiesIds.ts @@ -1,4 +1,5 @@ -import { MultiPinBioEntity } from '@/types/bioEntity'; +import { MultiPinModelElement } from '@/types/modelElement'; -export const getMultipinBioEntititesIds = (multipins: MultiPinBioEntity[]): (string | number)[] => - multipins.flat().map(({ id }) => id); +export const getMultipinBioEntititesIds = ( + multipins: MultiPinModelElement[], +): (string | number)[] => multipins.flat().map(({ id }) => id); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsFeatures.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsFeatures.ts index 4ebcb067d4b7def348074cb366a97d4a656a1c72..01b26958d519cb1159546c6d135da1393cbe9815 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsFeatures.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsFeatures.ts @@ -1,11 +1,11 @@ import { EntityNumber } from '@/redux/entityNumber/entityNumber.types'; -import { MultiPinBioEntity } from '@/types/bioEntity'; +import { MultiPinModelElement } from '@/types/modelElement'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import { Feature } from 'ol'; import { getMultipinSingleFeature } from './getMultipinSingleFeature'; export const getMultipinFeatures = ( - multipins: MultiPinBioEntity[], + multipins: MultiPinModelElement[], { pointToProjection, entityNumber, diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5287405fddf50aa38b2f68fe49064567e6b507b --- /dev/null +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.test.ts @@ -0,0 +1,76 @@ +import { MultiPinModelElement } from '@/types/modelElement'; +import { PinType } from '@/types/pin'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { getMultipinsModelElements } from './getMultipinsModelElements'; + +const ZERO_MULTI_BIO_ENTITIES: MultiPinModelElement = [ + { + ...modelElementFixture, + type: 'modelElement' as PinType, + }, + { + ...modelElementFixture, + x: 1000, + type: 'modelElement' as PinType, + }, +]; + +const ONE_MULTI_BIO_ENTITIES: MultiPinModelElement = [ + { + ...modelElementFixture, + type: 'modelElement' as PinType, + x: 100, + y: 100, + }, + { + ...modelElementFixture, + type: 'drugs' as PinType, + x: 100, + y: 100, + }, +]; + +const FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE: MultiPinModelElement = [ + { + ...modelElementFixture, + type: 'modelElement' as PinType, + x: 100, + y: 100, + }, + { + ...modelElementFixture, + type: 'drugs' as PinType, + x: 100, + y: 100, + }, + { + ...modelElementFixture, + type: 'drugs' as PinType, + x: 100, + y: 100, + }, + { + ...modelElementFixture, + type: 'drugs' as PinType, + x: 100, + y: 100, + }, +]; + +describe('getMultipinsBioEntities - util', () => { + it('should return empty array if theres no multi pins', () => { + expect(getMultipinsModelElements({ modelElements: ZERO_MULTI_BIO_ENTITIES })).toStrictEqual([]); + }); + + it('should return valid multi pins', () => { + expect(getMultipinsModelElements({ modelElements: ONE_MULTI_BIO_ENTITIES })).toStrictEqual([ + ONE_MULTI_BIO_ENTITIES, + ]); + }); + + it('should return valid multi pins if theres few types of pins', () => { + expect( + getMultipinsModelElements({ modelElements: FEW_MULTI_BIO_ENTITIES_WITH_MULTIPLIED_TYPE }), + ).toStrictEqual([ONE_MULTI_BIO_ENTITIES]); + }); +}); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.ts similarity index 53% rename from src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.ts rename to src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.ts index 2ee7139cac0b9e48ae611fe3b0b66520fa79e2be..651bf6058a9c4f63d596d88635f5c0de84aa8448 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsBioEntities.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMultipinsModelElements.ts @@ -1,16 +1,16 @@ import { ONE } from '@/constants/common'; -import { BioEntityWithPinType, MultiPinBioEntity } from '@/types/bioEntity'; -import { BioEntity } from '@/types/models'; +import { ModelElementWithPinType, MultiPinModelElement } from '@/types/modelElement'; +import { ModelElement } from '@/types/models'; import { PinType } from '@/types/pin'; interface Args { - bioEntities: MultiPinBioEntity; + modelElements: MultiPinModelElement; } const SEPARATOR = '-'; const POSITION_PRESCISION_SEPERATOR = '.'; -const getUniqueKey = (element: Pick<BioEntity, 'x' | 'y'>): string => { +const getUniqueKey = (element: Pick<ModelElement, 'x' | 'y'>): string => { const [x] = `${element.x}`.split(POSITION_PRESCISION_SEPERATOR); const [y] = `${element.y}`.split(POSITION_PRESCISION_SEPERATOR); @@ -18,9 +18,9 @@ const getUniqueKey = (element: Pick<BioEntity, 'x' | 'y'>): string => { }; const groupByPosition = ( - accumulator: Record<string, MultiPinBioEntity>, - element: BioEntityWithPinType, -): Record<string, MultiPinBioEntity> => { + accumulator: Record<string, MultiPinModelElement>, + element: ModelElementWithPinType, +): Record<string, MultiPinModelElement> => { const key = getUniqueKey(element); return { @@ -29,25 +29,25 @@ const groupByPosition = ( }; }; -const toUniqueTypeMultipin = (multipin: MultiPinBioEntity): MultiPinBioEntity => { +const toUniqueTypeMultipin = (multipin: MultiPinModelElement): MultiPinModelElement => { const allTypes: PinType[] = multipin.map(pin => pin.type); const uniqueTypes = [...new Set(allTypes)]; return uniqueTypes .map(type => multipin.find(pin => pin.type === type)) - .filter((value): value is BioEntityWithPinType => value !== undefined); + .filter((value): value is ModelElementWithPinType => value !== undefined); }; -export const getMultipinsBioEntities = ({ bioEntities }: Args): MultiPinBioEntity[] => { - const multipiledBioEntities = bioEntities.filter( +export const getMultipinsModelElements = ({ modelElements }: Args): MultiPinModelElement[] => { + const multipiledModelElements = modelElements.filter( baseElement => - bioEntities.filter(element => getUniqueKey(baseElement) === getUniqueKey(element)).length > + modelElements.filter(element => getUniqueKey(baseElement) === getUniqueKey(element)).length > ONE, ); - const duplicatedMultipinsGroupedByPosition = multipiledBioEntities.reduce( + const duplicatedMultipinsGroupedByPosition = multipiledModelElements.reduce( groupByPosition, - {} as Record<string, MultiPinBioEntity>, + {} as Record<string, MultiPinModelElement>, ); const allGroupedMultipins = Object.values(duplicatedMultipinsGroupedByPosition); diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts index c6ab67812279340c3fdb67a4f92f1b7c2ab7c7b3..fd52572485f4ae7df3049d0cee0a65692e6510d7 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.test.ts @@ -17,7 +17,7 @@ describe('getPinFeature - subUtil', () => { wrapper: Wrapper, }); const pointToProjection = usePointToProjectionHook.current; - const result = getPinFeature(bioEntity, pointToProjection, 'bioEntity'); + const result = getPinFeature(bioEntity, pointToProjection, 'modelElement'); it('should return instance of Feature', () => { expect(result).toBeInstanceOf(Feature); @@ -38,7 +38,7 @@ describe('getPinFeature - subUtil', () => { }); describe('when is Marker Pin', () => { - const pinMarkerResult = getPinFeature(PIN_MARKER, pointToProjection, 'bioEntity'); + const pinMarkerResult = getPinFeature(PIN_MARKER, pointToProjection, 'modelElement'); it('should return point parsed with point to projection', () => { const [x, y] = pinMarkerResult.getGeometry()?.getExtent() || []; diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts index 5113acc7cb5976a82167d39750b3cd91409f1d9e..ae2e8d05f2856e2923a2752736c135be82a6de5b 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts @@ -1,7 +1,7 @@ import { ZERO } from '@/constants/common'; import { HALF } from '@/constants/dividers'; import { FEATURE_TYPE } from '@/constants/features'; -import { BioEntity, MarkerWithPosition } from '@/types/models'; +import { ModelElement, MarkerWithPosition } from '@/types/models'; import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection'; import isUUID from 'is-uuid'; import { Feature } from 'ol'; @@ -15,7 +15,7 @@ export const getPinFeature = ( width, height, id, - }: Pick<BioEntity, 'id' | 'width' | 'height' | 'x' | 'y'> | MarkerWithPosition, + }: Pick<ModelElement, 'id' | 'width' | 'height' | 'x' | 'y'> | MarkerWithPosition, pointToProjection: UsePointToProjectionResult, pinType: PinType, ): Feature => { diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts index c2e6d9082c948893a49999ac38869032597c129c..f7b6001c8936ad65c06f65dff888fb822c781831 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts @@ -5,7 +5,7 @@ import { } from '@/redux/bioEntity/bioEntity.selectors'; import { entityNumberDataSelector } from '@/redux/entityNumber/entityNumber.selectors'; import { markersPinsOfCurrentMapDataSelector } from '@/redux/markers/markers.selectors'; -import { BioEntity } from '@/types/models'; +import { ModelElement } from '@/types/models'; import { usePointToProjection } from '@/utils/map/usePointToProjection'; import Feature from 'ol/Feature'; import { Geometry } from 'ol/geom'; @@ -16,26 +16,26 @@ import { useSelector } from 'react-redux'; import { LAYER_TYPE } from '@/components/Map/MapViewer/MapViewer.constants'; import { getBioEntitiesFeatures } from './getBioEntitiesFeatures'; import { getMarkersFeatures } from './getMarkersFeatures'; -import { getMultipinsBioEntities } from './getMultipinsBioEntities'; +import { getMultipinsModelElements } from './getMultipinsModelElements'; import { getMultipinBioEntititesIds } from './getMultipinsBioEntitiesIds'; import { getMultipinFeatures } from './getMultipinsFeatures'; export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => { const pointToProjection = usePointToProjection(); const activeIds = useSelector(allVisibleBioEntitiesIdsSelector); - const bioEntities = useSelector(allBioEntitiesWithTypeOfCurrentMapSelector); + const modelElements = useSelector(allBioEntitiesWithTypeOfCurrentMapSelector); const markersEntities = useSelector(markersPinsOfCurrentMapDataSelector); const entityNumber = useSelector(entityNumberDataSelector); const multiPinsBioEntities = useMemo( () => - getMultipinsBioEntities({ - bioEntities, + getMultipinsModelElements({ + modelElements, }), - [bioEntities], + [modelElements], ); const multipinsIds = getMultipinBioEntititesIds(multiPinsBioEntities); const isMultiPin = useCallback( - (b: BioEntity): boolean => multipinsIds.includes(b.id), + (b: ModelElement): boolean => multipinsIds.includes(b.id), [multipinsIds], ); @@ -43,7 +43,7 @@ export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>> () => [ getBioEntitiesFeatures( - bioEntities.filter(b => !isMultiPin(b)), + modelElements.filter(b => !isMultiPin(b)), { pointToProjection, entityNumber, @@ -58,7 +58,7 @@ export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>> getMarkersFeatures(markersEntities, { pointToProjection }), ].flat(), [ - bioEntities, + modelElements, pointToProjection, entityNumber, activeIds, diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts index 360df8c0cb43c8e90ea7ed3c390fbf7a12601c02..503b0f6953b60d713fc7473269e458de6eac081a 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink.ts @@ -1,7 +1,7 @@ -import { BioEntity } from '@/types/models'; import { showToast } from '@/utils/showToast'; +import { ModelElement } from '@/types/models'; -export const handleOpenImmediateLink = (bioEntity: BioEntity): void => { +export const handleOpenImmediateLink = (bioEntity: ModelElement): void => { const link = bioEntity.immediateLink; if (link !== null) { const tab = window.open(link, '_blank'); diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/clickHandleReaction.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/clickHandleReaction.ts index 2cd86bfae5d72887a88c33e33e69252a4b05d0f2..9cca913507e20fc0a54dd35adff6ce189be325f4 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/clickHandleReaction.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/clickHandleReaction.ts @@ -2,21 +2,20 @@ import { openReactionDrawerById, selectTab } from '@/redux/drawer/drawer.slice'; import { AppDispatch } from '@/redux/store'; import { searchFitBounds } from '@/services/pluginsManager/map/triggerSearch/searchFitBounds'; import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; -import { BioEntity, ModelElement, NewReaction } from '@/types/models'; +import { ModelElement, NewReaction } from '@/types/models'; import { FEATURE_TYPE } from '@/constants/features'; -import { setMultipleBioEntityContents } from '@/redux/bioEntity/bioEntity.slice'; import { addNumbersToEntityNumberData } from '@/redux/entityNumber/entityNumber.slice'; import { setReactions } from '@/redux/reactions/reactions.slice'; -import { mapReactionToBioEntity } from '@/utils/bioEntity/mapReactionToBioEntity'; +import { mapReactionToModelElement } from '@/utils/bioEntity/mapReactionToModelElement'; import getModelElementsIdsFromReaction from '@/components/Map/MapViewer/utils/listeners/mouseClick/getModelElementsIdsFromReaction'; -import { mapModelElementToBioEntity } from '@/utils/bioEntity/mapModelElementToBioEntity'; +import { setMultipleModelElementSearch } from '@/redux/modelElements/modelElements.slice'; /* prettier-ignore */ export const clickHandleReaction = (dispatch: AppDispatch, hasFitBounds = false) => ( modelElements: Array<ModelElement>, reactions: Array<NewReaction>, reactionId: number, modelId: number): void => { - const reactionBioEntities: Array<BioEntity> = []; + const reactionModelElements: Array<ModelElement> = []; const reaction = reactions.find(newReaction => newReaction.id === reactionId); if(!reaction) { return; @@ -29,20 +28,20 @@ export const clickHandleReaction = if(!modelElement) { return; } - reactionBioEntities.push(mapModelElementToBioEntity(modelElement)); + reactionModelElements.push(modelElement); }); dispatch(openReactionDrawerById(reactionId)); dispatch(selectTab('')); - const bioEntityReaction = mapReactionToBioEntity(reaction); - dispatch(setMultipleBioEntityContents(reactionBioEntities)); - dispatch(addNumbersToEntityNumberData(reactionBioEntities.map(reactionBioEntity => reactionBioEntity.elementId))); + const reactionModelElement = mapReactionToModelElement(reaction); + dispatch(setMultipleModelElementSearch(reactionModelElements)); + dispatch(addNumbersToEntityNumberData(reactionModelElements.map(modelElement => modelElement.elementId))); dispatch(setReactions([reaction])); - const result = reactionBioEntities.map((bioEntity) => {return { bioEntity, perfect: true };}); - result.push({ bioEntity: bioEntityReaction, perfect: true }); + const result = reactionModelElements.map((modelElement) => {return { modelElement, perfect: true };}); + result.push({ modelElement: reactionModelElement, perfect: true }); PluginsEventBus.dispatchEvent('onSearch', { type: 'reaction', searchValues: [{ id: reactionId, modelId, type: FEATURE_TYPE.REACTION }], diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.test.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.test.ts index 17b253ef568f7cb05c66bcc5f2bd0f56fa3b5652..a27080bee6400739dfde7cab90fc53842f17a24b 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.test.ts @@ -37,9 +37,9 @@ describe('leftClickHandleAlias', () => { type: 'bioEntity', searchValues: [{ id: 1, modelId, type: FEATURE_TYPE.ALIAS }], results: [ - mockBioEntities.map(bioEntity => ({ + mockBioEntities.map(modelElement => ({ perfect: true, - bioEntity, + bioEntity: modelElement, })), ], }); diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.ts index 50d3f5b62a88953a4690469bcab8f26d245e863c..2ce079a2ccd381cda0f71b7a760325879f679d75 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias.ts @@ -5,8 +5,8 @@ import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; import { searchFitBounds } from '@/services/pluginsManager/map/triggerSearch/searchFitBounds'; import { FEATURE_TYPE } from '@/constants/features'; import { ModelElement } from '@/types/models'; -import { setMultipleBioEntityContents } from '@/redux/bioEntity/bioEntity.slice'; import { addNumbersToEntityNumberData } from '@/redux/entityNumber/entityNumber.slice'; +import { setModelElementSearch } from '@/redux/modelElements/modelElements.slice'; import { handleOpenImmediateLink } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleOpenImmediateLink'; /* prettier-ignore */ @@ -26,7 +26,7 @@ export const leftClickHandleAlias = dispatch(selectTab(`${id}`)); dispatch(openBioEntityDrawerById(id)); - dispatch(setMultipleBioEntityContents([modelElement])); + dispatch(setModelElementSearch({ modelElement, perfect: true })); dispatch(addNumbersToEntityNumberData([modelElement.elementId])); const searchValue = { id, modelId, type: FEATURE_TYPE.ALIAS }; diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.test.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.test.ts index 6cf59664d96a7a3def32e75f5980884d824c5ede..a47c88a2ee5b4af248049faaa3034cd26dc039e8 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.test.ts @@ -2,7 +2,6 @@ import { updateLastClick } from '@/redux/map/map.slice'; import { closeDrawer } from '@/redux/drawer/drawer.slice'; import { resetReactionsData } from '@/redux/reactions/reactions.slice'; -import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice'; import { handleFeaturesClick } from '@/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/handleFeaturesClick'; import Map from 'ol/Map'; import { onMapLeftClick } from '@/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick'; @@ -12,6 +11,7 @@ import { Feature } from 'ol'; import { FEATURE_TYPE } from '@/constants/features'; import VectorLayer from 'ol/layer/Vector'; import { LAYER_TYPE } from '@/components/Map/MapViewer/MapViewer.constants'; +import { clearSearchModelElements } from '@/redux/modelElements/modelElements.slice'; import * as leftClickHandleAlias from './leftClickHandleAlias'; import * as clickHandleReaction from '../clickHandleReaction'; @@ -69,7 +69,7 @@ describe('onMapLeftClick', () => { expect(dispatch).toHaveBeenCalledWith(updateLastClick(expect.any(Object))); expect(dispatch).toHaveBeenCalledWith(closeDrawer()); expect(dispatch).toHaveBeenCalledWith(resetReactionsData()); - expect(dispatch).toHaveBeenCalledWith(clearBioEntities()); + expect(dispatch).toHaveBeenCalledWith(clearSearchModelElements()); }); it('calls leftClickHandleAlias if feature type is ALIAS', async () => { diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts index c62b97bfd7e647b5f2b6b2ea020f5bf6f82f02b4..3502d52eb7566de2209df25e516bf6a9d9a4d470 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/onMapLeftClick.ts @@ -7,7 +7,6 @@ import { updateLastClick } from '@/redux/map/map.slice'; import { toLonLat } from 'ol/proj'; import { latLngToPoint } from '@/utils/map/latLngToPoint'; import { closeDrawer } from '@/redux/drawer/drawer.slice'; -import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice'; import { leftClickHandleAlias } from '@/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias'; import { handleFeaturesClick } from '@/components/Map/MapViewer/utils/listeners/mouseClick/mouseLeftClick/handleFeaturesClick'; import { resetReactionsData } from '@/redux/reactions/reactions.slice'; @@ -15,6 +14,7 @@ import { handleDataReset } from '@/components/Map/MapViewer/utils/listeners/mous import { FEATURE_TYPE } from '@/constants/features'; import { clickHandleReaction } from '@/components/Map/MapViewer/utils/listeners/mouseClick/clickHandleReaction'; import getFeatureAtCoordinate from '@/components/Map/MapViewer/utils/listeners/mouseClick/getFeatureAtCoordinate'; +import { clearSearchModelElements } from '@/redux/modelElements/modelElements.slice'; /* prettier-ignore */ export const onMapLeftClick = @@ -52,7 +52,7 @@ export const onMapLeftClick = } dispatch(resetReactionsData()); - dispatch(clearBioEntities()); + dispatch(clearSearchModelElements()); return; } diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.test.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.test.ts index ae53b95c6010adaab6744b7284e8be76ae7e2932..9aa9dea6ba85480fff6862e104705e10f7871cb7 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.test.ts @@ -1,9 +1,9 @@ /* eslint-disable no-magic-numbers */ import { rightClickHandleAlias } from '@/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias'; import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; -import { setBioEntityContents } from '@/redux/bioEntity/bioEntity.slice'; import { addNumbersToEntityNumberData } from '@/redux/entityNumber/entityNumber.slice'; import { setCurrentSelectedBioEntityId } from '@/redux/contextMenu/contextMenu.slice'; +import { setModelElementSearch } from '@/redux/modelElements/modelElements.slice'; jest.mock('../../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds'); @@ -19,7 +19,7 @@ describe('rightClickHandleAlias', () => { await rightClickHandleAlias(dispatch)(modelElementFixture.id, modelElementFixture); expect(dispatch).toHaveBeenCalledTimes(3); - expect(dispatch).toHaveBeenCalledWith(setBioEntityContents(expect.any(Object))); + expect(dispatch).toHaveBeenCalledWith(setModelElementSearch(expect.any(Object))); expect(dispatch).toHaveBeenCalledWith( addNumbersToEntityNumberData([modelElementFixture.elementId]), ); diff --git a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.ts b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.ts index 4968eea674bcc5190f28f3eb1ae4c16ff7209645..05acb8af5b6f992bb65085c75d9315eaa5516826 100644 --- a/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.ts +++ b/src/components/Map/MapViewer/utils/listeners/mouseClick/mouseRightClick/rightClickHandleAlias.ts @@ -1,16 +1,14 @@ import { setCurrentSelectedBioEntityId } from '@/redux/contextMenu/contextMenu.slice'; import { AppDispatch } from '@/redux/store'; import { ModelElement } from '@/types/models'; -import { setBioEntityContents } from '@/redux/bioEntity/bioEntity.slice'; import { addNumbersToEntityNumberData } from '@/redux/entityNumber/entityNumber.slice'; -import { mapModelElementToBioEntity } from '@/utils/bioEntity/mapModelElementToBioEntity'; +import { setModelElementSearch } from '@/redux/modelElements/modelElements.slice'; /* prettier-ignore */ export const rightClickHandleAlias = (dispatch: AppDispatch) => async (id: number, modelElement: ModelElement): Promise<void> => { - const bioEntity = mapModelElementToBioEntity(modelElement); - dispatch(setBioEntityContents({ bioEntity, perfect: true })); - dispatch(addNumbersToEntityNumberData([bioEntity.elementId])); + dispatch(setModelElementSearch({ modelElement, perfect: true })); + dispatch(addNumbersToEntityNumberData([modelElement.elementId])); dispatch(setCurrentSelectedBioEntityId(id)); }; diff --git a/src/components/Map/MapViewer/utils/listeners/pinIconClick/useHandlePinIconClick.test.ts b/src/components/Map/MapViewer/utils/listeners/pinIconClick/useHandlePinIconClick.test.ts index 9f65d1d9ff48ba94d13497f10a2c88902db1ea64..5f69920e411c9ee86e3793aa7a6e448c846a0f76 100644 --- a/src/components/Map/MapViewer/utils/listeners/pinIconClick/useHandlePinIconClick.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/pinIconClick/useHandlePinIconClick.test.ts @@ -1,9 +1,10 @@ import { ZERO } from '@/constants/common'; -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { initialStateFixture } from '@/redux/drawer/drawerFixture'; import { INITIAL_STORE_STATE_MOCK } from '@/redux/root/root.fixtures'; import { getReduxStoreWithActionsListener } from '@/utils/testing/getReduxStoreActionsListener'; import { renderHook } from '@testing-library/react'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { DEFAULT_ERROR } from '@/constants/errors'; import { useHandlePinIconClick } from './useHandlePinIconClick'; describe('useHandlePinIconClick - util', () => { @@ -12,27 +13,36 @@ describe('useHandlePinIconClick - util', () => { const pinId = 123; const { Wrapper, store } = getReduxStoreWithActionsListener({ ...INITIAL_STORE_STATE_MOCK, - bioEntity: { - data: [ - { - searchQueryElement: '', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: null, - id: pinId, - model: ZERO, - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: '', + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: null, + id: pinId, + model: ZERO, + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, }); @@ -64,27 +74,36 @@ describe('useHandlePinIconClick - util', () => { selectedSearchElement: 'search-tab', }, }, - bioEntity: { - data: [ - { - searchQueryElement: 'search-tab', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: null, - id: pinId, - model: ZERO, - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: 'search-tab', + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: null, + id: pinId, + model: ZERO, + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, }); @@ -104,7 +123,7 @@ describe('useHandlePinIconClick - util', () => { }); describe('when pin is marker', () => { - const pinId = 'af57c6ce-8b83-47e4-a7eb-9511634c7c5f'; + const pinId = 1; const { Wrapper, store } = getReduxStoreWithActionsListener({ ...INITIAL_STORE_STATE_MOCK, drawer: { @@ -116,27 +135,36 @@ describe('useHandlePinIconClick - util', () => { selectedSearchElement: 'search-tab', }, }, - bioEntity: { - data: [ - { - searchQueryElement: 'search-tab', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: null, - id: pinId, - model: ZERO, - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: 'search-tab', + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: null, + id: pinId, + model: ZERO, + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, }); @@ -168,27 +196,36 @@ describe('useHandlePinIconClick - util', () => { selectedSearchElement: 'search-tab-2', }, }, - bioEntity: { - data: [ - { - searchQueryElement: 'search-tab', + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - fullName: null, - id: pinId, - model: ZERO, - }, - }, - ], + error: { message: '', name: '' }, }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, + }, + search: { + data: [ + { + searchQueryElement: 'search-tab', + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { + ...modelElementFixture, + fullName: null, + id: pinId, + model: ZERO, + }, + perfect: true, + }, + ], + }, + ], + loading: 'pending', + error: DEFAULT_ERROR, + }, }, }); diff --git a/src/constants/canvas.ts b/src/constants/canvas.ts index e5ab204a5e6465bf226c874f336676ecc86637f8..ff6f42580a5287b9538b59299d4cd3ca061b6837 100644 --- a/src/constants/canvas.ts +++ b/src/constants/canvas.ts @@ -15,7 +15,7 @@ export const PIN_SIZE = { export const PINS_COLORS: Record<PinType, string> = { drugs: '#F48C41', chemicals: '#008325', - bioEntity: '#106AD7', + modelElement: '#106AD7', comment: '#106AD7', }; diff --git a/src/constants/index.ts b/src/constants/index.ts index 4cfb0b9bcae9f9aee3c0dc0b6e0781c35adc8db9..5f890d3f46f03364f10bcbd8756630e2bbb8f083 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -8,7 +8,7 @@ export const BASE_NEW_API_URL = getConfigValue('BASE_NEW_API_URL'); export const DEFAULT_PROJECT_ID = getConfigValue('DEFAULT_PROJECT_ID'); export const PROJECT_ID = getProjectIdFromUrl() || DEFAULT_PROJECT_ID; export const ZOD_SEED = parseInt(process.env.ZOD_SEED || '123', 10); -export const BIO_ENTITY = 'bioEntity'; +export const MODEL_ELEMENT = 'modelElement'; export const DRUGS_CHEMICALS = ['drugs', 'chemicals']; export const MINERVA_WEBSITE_URL = 'https://minerva.pages.uni.lu/doc/'; export const ADMIN_PANEL_URL = getConfigValue('ADMIN_PANEL_URL'); diff --git a/src/constants/pin.ts b/src/constants/pin.ts deleted file mode 100644 index 0af91625d8fdae1ec8f7a2a6417e96831f4f6b66..0000000000000000000000000000000000000000 --- a/src/constants/pin.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PinType } from '@/types/pin'; - -export const DEFAULT_PIN_TYPE: PinType = 'bioEntity'; diff --git a/src/models/bioEntitySchema.ts b/src/models/bioEntitySchema.ts index 8a347db6cf8d224d8875d4ada8e3f02b5c81736b..6d4d375dce954674cc05e1a971a7aabcc63476d5 100644 --- a/src/models/bioEntitySchema.ts +++ b/src/models/bioEntitySchema.ts @@ -1,17 +1,17 @@ import { ZERO } from '@/constants/common'; import { z } from 'zod'; import { reactionProduct } from '@/models/reactionProduct'; +import { modelElementModificationSchema } from '@/models/modelElementModificationSchema'; import { colorSchema } from './colorSchema'; import { glyphSchema } from './glyphSchema'; import { lineSchema } from './lineSchema'; -import { modificationResiduesSchema } from './modificationResiduesSchema'; import { operatorSchema } from './operatorSchema'; import { referenceSchema } from './referenceSchema'; import { structuralStateSchema } from './structuralStateSchema'; import { submodelSchema } from './submodelSchema'; export const bioEntitySchema = z.object({ - id: z.union([z.number().int().positive(), z.string()]), + id: z.number().int().positive(), immediateLink: z.string().nullable().optional(), name: z.string(), elementId: z.string(), @@ -21,12 +21,12 @@ export const bioEntitySchema = z.object({ notes: z.string(), symbol: z.string().nullable(), homodimer: z.number().optional(), - nameX: z.number().nullable().optional(), - nameY: z.number().nullable().optional(), - nameWidth: z.number().nullable().optional(), - nameHeight: z.number().nullable().optional(), - nameVerticalAlign: z.string().nullable().optional(), - nameHorizontalAlign: z.string().nullable().optional(), + nameX: z.number(), + nameY: z.number(), + nameWidth: z.number(), + nameHeight: z.number(), + nameVerticalAlign: z.enum(['TOP', 'MIDDLE', 'BOTTOM']), + nameHorizontalAlign: z.enum(['LEFT', 'RIGHT', 'CENTER', 'END', 'START']), width: z .number() .optional() @@ -35,15 +35,15 @@ export const bioEntitySchema = z.object({ .number() .optional() .transform(height => height ?? ZERO), - visibilityLevel: z.string().nullable(), - transparencyLevel: z.string().nullable().optional(), + visibilityLevel: z.string(), + transparencyLevel: z.string(), synonyms: z.array(z.string()), - formerSymbols: z.array(z.string()).nullable().optional(), - fullName: z.string().nullable().nullable().optional(), + formerSymbols: z.array(z.string()), + fullName: z.string().nullable(), compartmentName: z.string().nullable().optional(), abbreviation: z.string().nullable(), formula: z.string().nullable(), - glyph: glyphSchema.nullable().optional(), + glyph: glyphSchema.nullable(), activity: z.boolean().optional(), structuralState: z.optional(structuralStateSchema.nullable()), hypothetical: z.boolean().nullable().optional(), @@ -54,11 +54,11 @@ export const bioEntitySchema = z.object({ charge: z.number().nullable().optional(), substanceUnits: z.boolean().nullable().optional(), onlySubstanceUnits: z.boolean().optional().nullable(), - shape: z.string().nullable().optional(), - modificationResidues: z.optional(z.array(modificationResiduesSchema)), + shape: z.enum(['SQUARE_COMPARTMENT', 'OVAL_COMPARTMENT', 'PATHWAY']).optional(), + modificationResidues: z.array(modelElementModificationSchema).optional(), complex: z.number().nullable().optional(), - compartment: z.number().nullable().optional(), - submodel: submodelSchema.nullable().optional(), + compartment: z.number().nullable(), + submodel: submodelSchema.nullable(), x: z .number() .optional() @@ -68,10 +68,10 @@ export const bioEntitySchema = z.object({ .optional() .transform(y => y ?? ZERO), lineWidth: z.number().optional(), - fontColor: colorSchema.nullable().optional(), - fontSize: z.number().nullable().optional(), - fillColor: colorSchema.nullable().optional(), - borderColor: colorSchema.nullable().optional(), + fontColor: colorSchema, + fontSize: z.number(), + fillColor: colorSchema, + borderColor: colorSchema, smiles: z.optional(z.string()).nullable(), inChI: z.optional(z.string().nullable()), inChIKey: z.optional(z.string().nullable()), diff --git a/src/models/fixtures/bioEntityFixture.ts b/src/models/fixtures/publicationElementFixture.ts similarity index 55% rename from src/models/fixtures/bioEntityFixture.ts rename to src/models/fixtures/publicationElementFixture.ts index 652ee55c6445b76c6604577d9723d79f445f1c73..297630605a09b578886222f80a43798f55483688 100644 --- a/src/models/fixtures/bioEntityFixture.ts +++ b/src/models/fixtures/publicationElementFixture.ts @@ -1,9 +1,9 @@ import { ZOD_SEED } from '@/constants'; // eslint-disable-next-line import/no-extraneous-dependencies import { createFixture } from 'zod-fixture'; -import { bioEntitySchema } from '@/models/bioEntitySchema'; +import { publicationElementSchema } from '@/models/publicationElementSchema'; -export const bioEntityFixture = createFixture(bioEntitySchema, { +export const publicationElementFixture = createFixture(publicationElementSchema, { seed: ZOD_SEED, array: { min: 2, max: 2 }, }); diff --git a/src/models/mocks/publicationsResponseMock.ts b/src/models/mocks/publicationsResponseMock.ts index 01240a657bac40972c623c608a5383181a42e5ae..45ec7d9484f7a3c2580ad9060911830e115d09a8 100644 --- a/src/models/mocks/publicationsResponseMock.ts +++ b/src/models/mocks/publicationsResponseMock.ts @@ -1,12 +1,12 @@ import { FilteredPageOf, Publication } from '@/types/models'; -import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture'; +import { publicationElementFixture } from '@/models/fixtures/publicationElementFixture'; export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publication> = { content: [ { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 19519, model: 52, }, @@ -24,7 +24,7 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 16167, model: 61, }, @@ -55,12 +55,12 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 17823, model: 52, }, { - ...bioEntityFixture, + ...publicationElementFixture, id: 19461, model: 52, }, @@ -79,12 +79,12 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 18189, model: 52, }, { - ...bioEntityFixture, + ...publicationElementFixture, id: 18729, model: 52, }, @@ -102,12 +102,12 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 16077, model: 58, }, { - ...bioEntityFixture, + ...publicationElementFixture, id: 16135, model: 58, }, @@ -137,7 +137,7 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 15955, model: 55, }, @@ -166,12 +166,12 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 15937, model: 55, }, { - ...bioEntityFixture, + ...publicationElementFixture, id: 15955, model: 55, }, @@ -190,7 +190,7 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 15948, model: 55, }, @@ -209,7 +209,7 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 16286, model: 62, }, @@ -236,12 +236,12 @@ export const PUBLICATIONS_DEFAULT_SEARCH_FIRST_10_MOCK: FilteredPageOf<Publicati { elements: [ { - ...bioEntityFixture, + ...publicationElementFixture, id: 17780, model: 52, }, { - ...bioEntityFixture, + ...publicationElementFixture, id: 17937, model: 52, }, diff --git a/src/models/modelElementSchema.ts b/src/models/modelElementSchema.ts index 7f8cf7a5800c4f9fa66b9c79932aef7d9116ae0a..6037996586bed787370a8a0aa18953302fae0bbd 100644 --- a/src/models/modelElementSchema.ts +++ b/src/models/modelElementSchema.ts @@ -6,12 +6,12 @@ import { modelElementModificationSchema } from '@/models/modelElementModificatio import { glyphSchema } from '@/models/glyphSchema'; export const modelElementSchema = z.object({ - id: z.number(), + id: z.number().int().positive(), model: z.number(), glyph: glyphSchema.nullable(), submodel: submodelSchema.nullable(), compartment: z.number().nullable(), - immediateLink: z.string().nullable(), + immediateLink: z.string().nullable().optional(), elementId: z.string(), x: z.number(), y: z.number(), diff --git a/src/models/publicationElementSchema.ts b/src/models/publicationElementSchema.ts new file mode 100644 index 0000000000000000000000000000000000000000..9bd5e4f04f624e2daf7c882d67b13a3060826ca3 --- /dev/null +++ b/src/models/publicationElementSchema.ts @@ -0,0 +1,35 @@ +import { z } from 'zod'; +import { reactionProduct } from '@/models/reactionProduct'; +import { lineSchema } from './lineSchema'; +import { operatorSchema } from './operatorSchema'; +import { referenceSchema } from './referenceSchema'; + +export const publicationElementSchema = z.object({ + abbreviation: z.string().nullable(), + elementId: z.string(), + formula: z.string().nullable(), + geneProteinReaction: z.string().nullable().optional(), + id: z.union([z.number().int().positive(), z.string()]), + idReaction: z.string().optional(), + kinetics: z.null().optional(), + line: lineSchema.optional(), + lowerBound: z.boolean().nullable().optional(), + mechanicalConfidenceScore: z.boolean().nullable().optional(), + model: z.number(), + modifiers: z.array(reactionProduct).optional(), + name: z.string(), + notes: z.string(), + operators: z.array(operatorSchema).optional(), + processCoordinates: z.null().optional(), + products: z.array(reactionProduct).optional(), + reactants: z.array(reactionProduct).optional(), + references: z.array(referenceSchema), + reversible: z.boolean().optional(), + sboTerm: z.string(), + subsystem: z.string().nullable().optional(), + symbol: z.string().nullable(), + synonyms: z.array(z.string()), + upperBound: z.boolean().nullable().optional(), + visibilityLevel: z.string(), + z: z.number(), +}); diff --git a/src/models/publicationsSchema.ts b/src/models/publicationsSchema.ts index 14ac77ff60234eeed55cadd991fec4c8ce6a7018..8fff78d787bd47a7382f891bd7c5d31f26dfd72d 100644 --- a/src/models/publicationsSchema.ts +++ b/src/models/publicationsSchema.ts @@ -1,8 +1,8 @@ import { z } from 'zod'; -import { bioEntitySchema } from '@/models/bioEntitySchema'; +import { publicationElementSchema } from '@/models/publicationElementSchema'; import { articleSchema } from './articleSchema'; export const publicationSchema = z.object({ - elements: z.array(bioEntitySchema), + elements: z.array(publicationElementSchema), article: articleSchema, }); diff --git a/src/models/targetSchema.ts b/src/models/targetSchema.ts index 015626e16f4e06ce2276a5e9a597701b63c7a031..a9f480632fcfac48a0072af4f54433b87bf04d88 100644 --- a/src/models/targetSchema.ts +++ b/src/models/targetSchema.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { bioEntitySchema } from './bioEntitySchema'; +import { modelElementSchema } from '@/models/modelElementSchema'; import { referenceSchema } from './referenceSchema'; import { targetParticipantSchema } from './targetParticipantSchema'; @@ -9,7 +9,7 @@ export const targetSchema = z.object({ /** list of target references */ references: z.array(referenceSchema), /** list of elements on the map associated with this target */ - targetElements: z.array(bioEntitySchema), + targetElements: z.array(modelElementSchema), /** list of identifiers associated with this target */ targetParticipants: z.array(targetParticipantSchema), }); diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 93d49308b2e2b21a73a603a7b51871f79f4bb696..fcb92f409525d805897c8de9eb77c26bfccaf0d9 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -24,8 +24,6 @@ export const apiPath = { isPerfectMatch, }: PerfectSearchParams): string => `projects/${PROJECT_ID}/models/*/bioEntities/:search?query=${searchQuery}&size=1000&perfectMatch=${isPerfectMatch}`, - getReactionsWithIds: (ids: number[]): string => - `projects/${PROJECT_ID}/models/*/bioEntities/reactions/?id=${ids.join(',')}&size=1000`, getDrugsStringWithQuery: (searchQuery: string): string => `projects/${PROJECT_ID}/drugs:search?query=${searchQuery}`, getDrugsStringWithColumnsTarget: (columns: string, target: string): string => @@ -56,9 +54,9 @@ export const apiPath = { `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`, addLayerImageObject: (modelId: number, layerId: number): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/images/`, - updateLayerImageObject: (modelId: number, layerId: number, imageId: number): string => + updateLayerImageObject: (modelId: number, layerId: number, imageId: number | string): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/images/${imageId}`, - removeLayerImageObject: (modelId: number, layerId: number, imageId: number): string => + removeLayerImageObject: (modelId: number, layerId: number, imageId: number | string): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/images/${imageId}`, addLayerText: (modelId: number, layerId: number): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/`, @@ -118,7 +116,6 @@ export const apiPath = { registerPluign: (): string => `plugins/`, getPlugin: (pluginId: string): string => `plugins/${pluginId}/`, getAllPlugins: (): string => `/plugins/`, - getSubmapConnections: (): string => `projects/${PROJECT_ID}/submapConnections/`, logout: (): string => `doLogout`, user: (login: string): string => `users/${login}`, updateUser: (login: string): string => `users/${login}`, diff --git a/src/redux/bioEntity/bioEntity.constants.ts b/src/redux/bioEntity/bioEntity.constants.ts index 70b92fc4ec9863719d389c994002db131975e998..283283d5d66b10a0272f04973b8deeb0deb13d86 100644 --- a/src/redux/bioEntity/bioEntity.constants.ts +++ b/src/redux/bioEntity/bioEntity.constants.ts @@ -1,24 +1,7 @@ -import { FetchDataState } from '@/types/fetchDataState'; -import { BioEntity } from '@/types/models'; import { BioEntityContentsState } from './bioEntity.types'; -export const DEFAULT_BIOENTITY_PARAMS = { - perfectMatch: false, -}; - export const BIO_ENTITY_FETCHING_ERROR_PREFIX = 'Failed to fetch bio entity'; -export const MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX = 'Failed to fetch multi bio entity'; - -export const BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE: FetchDataState<BioEntity[]> = { - data: [], - loading: 'idle', - error: { name: '', message: '' }, -}; export const BIOENTITY_INITIAL_STATE: BioEntityContentsState = { - data: [], - loading: 'idle', - error: { name: '', message: '' }, - submapConnections: BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, isContentTabOpened: false, }; diff --git a/src/redux/bioEntity/bioEntity.mock.ts b/src/redux/bioEntity/bioEntity.mock.ts index 929790fa1834f0f2e07fe5fe9659b407c9a144e6..f104198e4c63549e58fc5d2c6c7085b91cb9ea03 100644 --- a/src/redux/bioEntity/bioEntity.mock.ts +++ b/src/redux/bioEntity/bioEntity.mock.ts @@ -1,34 +1,5 @@ -import { DEFAULT_ERROR } from '@/constants/errors'; -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { MultiSearchData } from '@/types/fetchDataState'; -import { BioEntity, BioEntityContent } from '@/types/models'; -import { HISTAMINE_MAP_ID } from '@/constants/mocks'; import { BioEntityContentsState } from './bioEntity.types'; export const BIOENTITY_INITIAL_STATE_MOCK: BioEntityContentsState = { - data: [], - loading: 'idle', - error: DEFAULT_ERROR, - submapConnections: { - data: [], - loading: 'idle', - error: DEFAULT_ERROR, - }, + isContentTabOpened: false, }; - -export const BIO_ENTITY_LINKING_TO_SUBMAP: BioEntity = { - ...bioEntityContentFixture.bioEntity, - submodel: { - mapId: HISTAMINE_MAP_ID, - type: 'DONWSTREAM_TARGETS', - }, -}; - -export const BIO_ENTITY_LINKING_TO_SUBMAP_DATA_MOCK: MultiSearchData<BioEntityContent[]>[] = [ - { - data: [{ bioEntity: BIO_ENTITY_LINKING_TO_SUBMAP, perfect: false }], - searchQueryElement: '', - loading: 'succeeded', - error: DEFAULT_ERROR, - }, -]; diff --git a/src/redux/bioEntity/bioEntity.reducers.test.ts b/src/redux/bioEntity/bioEntity.reducers.test.ts deleted file mode 100644 index 8fa2002f40d92211b93a63ff3f013c91560dc03a..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/bioEntity.reducers.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { DEFAULT_ERROR } from '@/constants/errors'; -import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { apiPath } from '@/redux/apiPath'; -import { - ToolkitStoreWithSingleSlice, - createStoreInstanceUsingSliceReducer, -} from '@/utils/createStoreInstanceUsingSliceReducer'; -import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; -import { unwrapResult } from '@reduxjs/toolkit'; -import { HttpStatusCode } from 'axios'; -import bioEntityContentsReducer from './bioEntity.slice'; -import { getBioEntity } from './bioEntity.thunks'; -import { BioEntityContentsState } from './bioEntity.types'; - -const mockedAxiosClient = mockNetworkNewAPIResponse(); -const SEARCH_QUERY = 'park7'; - -jest.mock('../../utils/error-report/errorReporting'); - -const INITIAL_STATE: BioEntityContentsState = { - data: [], - loading: 'idle', - isContentTabOpened: false, - error: { name: '', message: '' }, - submapConnections: { - data: [], - loading: 'idle', - error: { name: '', message: '' }, - }, -}; - -describe('bioEntity reducer', () => { - let store = {} as ToolkitStoreWithSingleSlice<BioEntityContentsState>; - beforeEach(() => { - store = createStoreInstanceUsingSliceReducer('bioEntity', bioEntityContentsReducer); - }); - - it('should match initial state', () => { - const action = { type: 'unknown' }; - - expect(bioEntityContentsReducer(undefined, action)).toEqual(INITIAL_STATE); - }); - - it('should update store after succesfull getBioEntity query', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, bioEntityResponseFixture); - - const { type } = await store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - const { data } = store.getState().bioEntity; - const bioEnityWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, - ); - - expect(type).toBe('project/getBioEntityContents/fulfilled'); - expect(bioEnityWithSearchElement).toEqual({ - searchQueryElement: SEARCH_QUERY, - data: bioEntityResponseFixture.content, - loading: 'succeeded', - error: DEFAULT_ERROR, - }); - }); - - it('should update store after failed getBioEntity query', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.NotFound, bioEntityResponseFixture); - - const action = await store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - const { data } = store.getState().bioEntity; - - const bioEntityWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, - ); - expect(action.type).toBe('project/getBioEntityContents/rejected'); - expect(() => unwrapResult(action)).toThrow( - "Failed to fetch bio entity: The page you're looking for doesn't exist. Please verify the URL and try again.", - ); - expect(bioEntityWithSearchElement).toEqual({ - searchQueryElement: SEARCH_QUERY, - data: undefined, - loading: 'failed', - error: DEFAULT_ERROR, - }); - }); - - it('should update store on loading getBioEntity query', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, bioEntityResponseFixture); - - const bioEntityContentsPromise = store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - - const { data } = store.getState().bioEntity; - const bioEntityWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, - ); - - expect(bioEntityWithSearchElement).toEqual({ - searchQueryElement: SEARCH_QUERY, - data: undefined, - loading: 'pending', - error: DEFAULT_ERROR, - }); - - bioEntityContentsPromise.then(() => { - const { data: dataPromiseFulfilled } = store.getState().bioEntity; - - const bioEntityWithSearchElementFulfilled = dataPromiseFulfilled.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, - ); - - expect(bioEntityWithSearchElementFulfilled).toEqual({ - searchQueryElement: SEARCH_QUERY, - data: bioEntityResponseFixture.content, - loading: 'succeeded', - error: DEFAULT_ERROR, - }); - }); - }); -}); diff --git a/src/redux/bioEntity/bioEntity.reducers.ts b/src/redux/bioEntity/bioEntity.reducers.ts index b24e17c1b8889e85fa13201210cee9d78e1ab312..f4406d501b6a50029a230996721dcf53c1f1954b 100644 --- a/src/redux/bioEntity/bioEntity.reducers.ts +++ b/src/redux/bioEntity/bioEntity.reducers.ts @@ -1,99 +1,9 @@ -import { DEFAULT_ERROR } from '@/constants/errors'; -import { ActionReducerMapBuilder, PayloadAction } from '@reduxjs/toolkit'; -import { BioEntity, BioEntityContent } from '@/types/models'; -import { getBioEntity, getMultiBioEntity } from './bioEntity.thunks'; +import { PayloadAction } from '@reduxjs/toolkit'; import { BioEntityContentsState } from './bioEntity.types'; -export const getBioEntityContentsReducer = ( - builder: ActionReducerMapBuilder<BioEntityContentsState>, -): void => { - builder.addCase(getBioEntity.pending, (state, action) => { - state.data.push({ - searchQueryElement: action.meta.arg.searchQuery, - data: undefined, - loading: 'pending', - error: DEFAULT_ERROR, - }); - }); - builder.addCase(getBioEntity.fulfilled, (state, action) => { - const bioEntities = state.data.find( - bioEntity => bioEntity.searchQueryElement === action.meta.arg.searchQuery, - ); - if (bioEntities) { - bioEntities.data = action.payload; - bioEntities.loading = 'succeeded'; - } - }); - builder.addCase(getBioEntity.rejected, (state, action) => { - const bioEntities = state.data.find( - bioEntity => bioEntity.searchQueryElement === action.meta.arg.searchQuery, - ); - if (bioEntities) { - bioEntities.loading = 'failed'; - // TODO: error management to be discussed in the team - } - }); -}; - -export const getMultiBioEntityContentsReducer = ( - builder: ActionReducerMapBuilder<BioEntityContentsState>, -): void => { - builder.addCase(getMultiBioEntity.pending, state => { - state.data = []; - state.loading = 'pending'; - }); - builder.addCase(getMultiBioEntity.fulfilled, state => { - state.loading = 'succeeded'; - }); - builder.addCase(getMultiBioEntity.rejected, state => { - state.loading = 'failed'; - // TODO: error management to be discussed in the team - }); -}; - -export const clearBioEntitiesReducer = (state: BioEntityContentsState): void => { - state.data = []; - state.loading = 'idle'; -}; - export const toggleIsContentTabOpenedReducer = ( state: BioEntityContentsState, action: PayloadAction<boolean>, ): void => { state.isContentTabOpened = action.payload; }; - -export const setBioEntityContentsReducer = ( - state: BioEntityContentsState, - action: PayloadAction<BioEntityContent>, -): void => { - state.data = [ - { - data: [action.payload], - loading: 'succeeded', - error: DEFAULT_ERROR, - searchQueryElement: action.payload.bioEntity.id.toString(), - }, - ]; - state.loading = 'succeeded'; -}; - -export const setMultipleBioEntityContentsReducer = ( - state: BioEntityContentsState, - action: PayloadAction<Array<BioEntity>>, -): void => { - state.data = action.payload.map(bioEntity => { - return { - data: [ - { - bioEntity, - perfect: true, - }, - ], - searchQueryElement: bioEntity.id.toString(), - loading: 'succeeded', - error: DEFAULT_ERROR, - }; - }); - state.loading = 'succeeded'; -}; diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts index d9c63a0a6ab297c775a0f251498eed4926a05e29..1abdb89dec884daff6e3938f89b6591a59ee461b 100644 --- a/src/redux/bioEntity/bioEntity.selectors.ts +++ b/src/redux/bioEntity/bioEntity.selectors.ts @@ -1,196 +1,58 @@ -import { ONE, SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common'; -import { allCommentsSelectorOfCurrentMap } from '@/redux/comment/comment.selectors'; +import { ONE, ZERO } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; -import { BioEntityWithPinType } from '@/types/bioEntity'; +import { ModelElementWithPinType } from '@/types/modelElement'; import { ElementIdTabObj } from '@/types/elements'; -import { MultiSearchData } from '@/types/fetchDataState'; -import { BioEntity, BioEntityContent, Comment, MapModel, ModelElement } from '@/types/models'; +import { ModelElement } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; import { - currentDrawerModelElementSelector, - modelElementsWithSubmapConnectionForCurrentModelSelector, + allModelElementsSubmapConnectionsForCurrentSubmapSelector, + allSearchModelElementForCurrentModelSelector, + allSearchModelElementsIdTabForCurrentModelSelector, + searchedModelElementsForCurrentModelSelector, + searchedModelElementsSelector, } from '@/redux/modelElements/modelElements.selector'; -import { currentDrawerNewReactionSelector } from '@/redux/newReactions/newReactions.selectors'; import { - allChemicalsBioEntitesOfCurrentMapSelector, + allDrugsElementsOfCurrentMapSelector, + allDrugsIdTabSelectorOfCurrentMap, + drugsElementsForSelectedSearchElementSelector, + searchedDrugsElementsOfCurrentMapSelector, +} from '@/redux/drugs/drugs.selectors'; +import { + allChemicalsElementsOfCurrentMapSelector, allChemicalsIdTabSelectorOfCurrentMap, - chemicalsBioEntitiesForSelectedSearchElementSelector, - searchedChemicalsBioEntitesOfCurrentMapSelector, + chemicalsElementsForSelectedSearchElementSelector, + searchedChemicalsElementsOfCurrentMapSelector, } from '../chemicals/chemicals.selectors'; -import { currentSelectedBioEntityIdSelector } from '../contextMenu/contextMenu.selector'; -import { currentSelectedSearchElement } from '../drawer/drawer.selectors'; -import { - allDrugsBioEntitesOfCurrentMapSelector, - allDrugsIdTabSelectorOfCurrentMap, - drugsBioEntitiesForSelectedSearchElementSelector, - searchedDrugsBioEntitesOfCurrentMapSelector, -} from '../drugs/drugs.selectors'; -import { currentModelIdSelector, modelsDataSelector } from '../models/models.selectors'; export const bioEntitySelector = createSelector(rootSelector, state => state.bioEntity); -export const bioEntityDataSelector = createSelector(bioEntitySelector, bioEntity => bioEntity.data); - export const bioEntityIsContentTabOpenedSelector = createSelector( bioEntitySelector, bioEntity => bioEntity.isContentTabOpened, ); -export const bioEntityLoadingSelector = createSelector( - bioEntitySelector, - bioEntity => bioEntity.loading, -); - -export const bioEntityDataListSelector = createSelector(bioEntityDataSelector, bioEntityData => - bioEntityData.map(b => b.data || []).flat(), -); - -export const allSubmapConnectionsBioEntityOfCurrentSubmapSelector = createSelector( - modelElementsWithSubmapConnectionForCurrentModelSelector, - currentModelIdSelector, - (submapConnectionsBioEntity, currentModel): ModelElement[] => - submapConnectionsBioEntity.filter(({ model }) => model === currentModel), -); - -export const bioEntitiesForSelectedSearchElement = createSelector( - bioEntitySelector, - currentSelectedSearchElement, - (bioEntitiesState, currentSearchElement): MultiSearchData<BioEntityContent[]> | undefined => - bioEntitiesState.data.find( - ({ searchQueryElement }) => searchQueryElement === currentSearchElement, - ), -); - -export const searchedBioEntityElementForContextMapSelector = createSelector( - bioEntitySelector, - currentSelectedBioEntityIdSelector, - (bioEntitiesState, currentBioEntityId): BioEntity | undefined => { - return bioEntitiesState.data - .find(({ searchQueryElement }) => searchQueryElement === currentBioEntityId.toString()) - ?.data?.find(({ bioEntity }) => bioEntity.id === currentBioEntityId)?.bioEntity; - }, -); - -export const searchedBioEntityElementUniProtIdSelector = createSelector( - searchedBioEntityElementForContextMapSelector, - (bioEntitiesState): string | undefined => { - return bioEntitiesState?.references.find(({ type }) => type === 'UNIPROT')?.resource; - }, -); - -export const loadingBioEntityStatusSelector = createSelector( - bioEntitiesForSelectedSearchElement, - state => state?.loading, -); - -export const searchedBioEntitesSelectorOfCurrentMap = createSelector( - bioEntitySelector, - currentSelectedSearchElement, - currentModelIdSelector, - (bioEntities, currentSearchElement, currentModelId): BioEntity[] => { - if (!bioEntities) { - return []; - } - - return (bioEntities?.data || []) - .filter(({ searchQueryElement }) => - currentSearchElement ? searchQueryElement === currentSearchElement : true, - ) - .map(({ data }) => data || []) - .flat() - .filter(({ bioEntity }) => bioEntity.model === currentModelId) - .map(({ bioEntity }) => bioEntity); - }, -); - -export const allBioEntitesSelectorOfCurrentMap = createSelector( - bioEntitySelector, - currentModelIdSelector, - (bioEntities, currentModelId): BioEntity[] => { - if (!bioEntities) { - return []; - } - - return (bioEntities?.data || []) - .map(({ data }) => data || []) - .flat() - .filter(({ bioEntity }) => bioEntity.model === currentModelId) - .map(({ bioEntity }) => bioEntity); - }, -); - -export const allBioEntitesIdTabSelectorOfCurrentMap = createSelector( - bioEntitySelector, - currentModelIdSelector, - (bioEntities, currentModelId): ElementIdTabObj => { - if (!bioEntities) { - return {}; - } - - return Object.fromEntries( - (bioEntities?.data || []) - .map(({ data, searchQueryElement }): [typeof data, string] => [data, searchQueryElement]) - .map(([data, tab]) => - (data || []) - .flat() - .filter(({ bioEntity }) => bioEntity.model === currentModelId) - .map(d => [d.bioEntity.id, tab]), - ) - .flat(), - ); - }, -); - -export const numberOfBioEntitiesSelector = createSelector( - bioEntitiesForSelectedSearchElement, - state => (state?.data ? state.data.length : SIZE_OF_EMPTY_ARRAY), -); - -export const bioEntitiesPerModelSelector = createSelector( - bioEntitiesForSelectedSearchElement, - modelsDataSelector, - (bioEntities, models) => { - const bioEntitiesPerModelPerSearchElement = (models || []).map(model => { - const bioEntitiesInGivenModel = (bioEntities?.data || []).filter( - entity => model.id === entity.bioEntity.model, - ); - - return { - modelName: model.name, - modelId: model.id, - numberOfEntities: bioEntitiesInGivenModel.length, - bioEntities: bioEntitiesInGivenModel, - }; - }); - - return bioEntitiesPerModelPerSearchElement.filter( - model => model.numberOfEntities !== SIZE_OF_EMPTY_ARRAY, - ); - }, -); - export const allVisibleBioEntitiesSelector = createSelector( - searchedBioEntitesSelectorOfCurrentMap, - searchedChemicalsBioEntitesOfCurrentMapSelector, - searchedDrugsBioEntitesOfCurrentMapSelector, - (content, chemicals, drugs): BioEntity[] => { + searchedModelElementsForCurrentModelSelector, + searchedChemicalsElementsOfCurrentMapSelector, + searchedDrugsElementsOfCurrentMapSelector, + (content, chemicals, drugs): Array<ModelElement> => { return [content, chemicals, drugs].flat(); }, ); -export const allElementsForSearchElementSelector = createSelector( - bioEntitiesForSelectedSearchElement, - chemicalsBioEntitiesForSelectedSearchElementSelector, - drugsBioEntitiesForSelectedSearchElementSelector, - (content, chemicals, drugs): BioEntity[] => { - const contentBioEntities = (content?.data || []).map(({ bioEntity }) => bioEntity); +export const allBioEntitiesForSearchElementSelector = createSelector( + searchedModelElementsSelector, + chemicalsElementsForSelectedSearchElementSelector, + drugsElementsForSelectedSearchElementSelector, + (content, chemicals, drugs): Array<ModelElement> => { + const contentBioEntities = (content?.data || []).map(({ modelElement }) => modelElement); return [contentBioEntities, chemicals || [], drugs || []].flat(); }, ); export const allElementsForSearchElementNumberByModelId = createSelector( - allElementsForSearchElementSelector, + allBioEntitiesForSearchElementSelector, (elements): Record<number, number> => { return elements.reduce( (acc, { model }) => ({ @@ -203,7 +65,7 @@ export const allElementsForSearchElementNumberByModelId = createSelector( ); export const allBioEntitiesElementsIdsSelector = createSelector( - allBioEntitesIdTabSelectorOfCurrentMap, + allSearchModelElementsIdTabForCurrentModelSelector, allChemicalsIdTabSelectorOfCurrentMap, allDrugsIdTabSelectorOfCurrentMap, (content, chemicals, drugs): ElementIdTabObj => { @@ -215,16 +77,9 @@ export const allBioEntitiesElementsIdsSelector = createSelector( }, ); -export const currentDrawerBioEntityRelatedSubmapSelector = createSelector( - currentDrawerModelElementSelector, - modelsDataSelector, - (bioEntity, models): MapModel | undefined => - models.find(({ id }) => id === bioEntity?.submodel?.mapId), -); - export const allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector = createSelector( - allSubmapConnectionsBioEntityOfCurrentSubmapSelector, + allModelElementsSubmapConnectionsForCurrentSubmapSelector, allElementsForSearchElementNumberByModelId, (submapConnectionsBioEntity, modelElementsNumber): ModelElement[] => { return submapConnectionsBioEntity.filter( @@ -234,16 +89,16 @@ export const allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSele ); export const allBioEntitiesWithTypeOfCurrentMapSelector = createSelector( - allBioEntitesSelectorOfCurrentMap, - allChemicalsBioEntitesOfCurrentMapSelector, - allDrugsBioEntitesOfCurrentMapSelector, + allSearchModelElementForCurrentModelSelector, + allChemicalsElementsOfCurrentMapSelector, + allDrugsElementsOfCurrentMapSelector, allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector, - (content, chemicals, drugs, submapConnections): BioEntityWithPinType[] => { + (content, chemicals, drugs, submapConnections): ModelElementWithPinType[] => { return [ - content.map(v => ({ ...v, type: 'bioEntity' as const })), + content.map(v => ({ ...v, type: 'modelElement' as const })), chemicals.map(v => ({ ...v, type: 'chemicals' as const })), drugs.map(v => ({ ...v, type: 'drugs' as const })), - submapConnections.map(v => ({ ...v, type: 'bioEntity' as const })), + submapConnections.map(v => ({ ...v, type: 'modelElement' as const })), ].flat(); }, ); @@ -255,35 +110,3 @@ export const allVisibleBioEntitiesIdsSelector = createSelector( return [...elements, ...submapConnections].map(e => e.id); }, ); - -export const currentDrawerElementCommentsSelector = createSelector( - currentDrawerModelElementSelector, - allCommentsSelectorOfCurrentMap, - (element, comments): Comment[] => { - if (element) { - return comments.filter( - comment => - comment.type === 'ALIAS' && - comment.modelId === element.model && - Number(comment.elementId) === element.id, - ); - } - return []; - }, -); - -export const currentDrawerReactionCommentsSelector = createSelector( - currentDrawerNewReactionSelector, - allCommentsSelectorOfCurrentMap, - (reaction, comments): Comment[] => { - if (reaction) { - return comments.filter( - comment => - comment.type === 'REACTION' && - comment.modelId === reaction.model && - Number(comment.elementId) === reaction.id, - ); - } - return []; - }, -); diff --git a/src/redux/bioEntity/bioEntity.slice.ts b/src/redux/bioEntity/bioEntity.slice.ts index 8e40b023c9c5100821ef1e1980a08143a100904a..45a1b7e721bb130c8c556c6e693140061a820f41 100644 --- a/src/redux/bioEntity/bioEntity.slice.ts +++ b/src/redux/bioEntity/bioEntity.slice.ts @@ -1,34 +1,15 @@ import { createSlice } from '@reduxjs/toolkit'; import { BIOENTITY_INITIAL_STATE } from './bioEntity.constants'; -import { - clearBioEntitiesReducer, - getBioEntityContentsReducer, - getMultiBioEntityContentsReducer, - setBioEntityContentsReducer, - setMultipleBioEntityContentsReducer, - toggleIsContentTabOpenedReducer, -} from './bioEntity.reducers'; +import { toggleIsContentTabOpenedReducer } from './bioEntity.reducers'; export const bioEntityContentsSlice = createSlice({ name: 'bioEntityContents', initialState: BIOENTITY_INITIAL_STATE, reducers: { - clearBioEntities: clearBioEntitiesReducer, toggleIsContentTabOpened: toggleIsContentTabOpenedReducer, - setBioEntityContents: setBioEntityContentsReducer, - setMultipleBioEntityContents: setMultipleBioEntityContentsReducer, - }, - extraReducers: builder => { - getBioEntityContentsReducer(builder); - getMultiBioEntityContentsReducer(builder); }, }); -export const { - clearBioEntities, - toggleIsContentTabOpened, - setBioEntityContents, - setMultipleBioEntityContents, -} = bioEntityContentsSlice.actions; +export const { toggleIsContentTabOpened } = bioEntityContentsSlice.actions; export default bioEntityContentsSlice.reducer; diff --git a/src/redux/bioEntity/bioEntity.thunks.test.ts b/src/redux/bioEntity/bioEntity.thunks.test.ts deleted file mode 100644 index fb433fb0fb0b18033b883c6fa8213432f5f3260b..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/bioEntity.thunks.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { apiPath } from '@/redux/apiPath'; -import { - ToolkitStoreWithSingleSlice, - createStoreInstanceUsingSliceReducer, -} from '@/utils/createStoreInstanceUsingSliceReducer'; -import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; -import { HttpStatusCode } from 'axios'; -import { unwrapResult } from '@reduxjs/toolkit'; -import contentsReducer from './bioEntity.slice'; -import { getBioEntity, getMultiBioEntity } from './bioEntity.thunks'; -import { BioEntityContentsState } from './bioEntity.types'; - -jest.mock('../../utils/error-report/errorReporting'); - -const mockedAxiosClient = mockNetworkNewAPIResponse(); -const SEARCH_QUERY = 'park7'; - -describe('bioEntityContents thunks', () => { - let store = {} as ToolkitStoreWithSingleSlice<BioEntityContentsState>; - beforeEach(() => { - store = createStoreInstanceUsingSliceReducer('bioEntityContents', contentsReducer); - }); - describe('getBioEntityContents', () => { - it('should return data when data response from API is valid', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, bioEntityResponseFixture); - - const { payload } = await store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - expect(payload).toEqual(bioEntityResponseFixture.content); - }); - it('should return undefined when data response from API is not valid ', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, { randomProperty: 'randomValue' }); - - const { payload } = await store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - expect(payload).toEqual(undefined); - }); - it('should handle error message when getBioEntityContents failed', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.NotFound, null); - - const action = await store.dispatch( - getBioEntity({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ); - expect(() => unwrapResult(action)).toThrow( - "Failed to fetch bio entity: The page you're looking for doesn't exist. Please verify the URL and try again.", - ); - }); - }); - describe('getMultiBioEntity', () => { - it('should return transformed bioEntityContent array', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, bioEntityResponseFixture); - - const data = await store - .dispatch( - getMultiBioEntity({ - searchQueries: [SEARCH_QUERY], - isPerfectMatch: false, - }), - ) - .unwrap(); - - expect(data).toEqual(bioEntityResponseFixture.content); - }); - it('should combine all returned bioEntityContent arrays and return array with all provided bioEntityContent elements', async () => { - mockedAxiosClient - .onGet( - apiPath.getBioEntityContentsStringWithQuery({ - searchQuery: SEARCH_QUERY, - isPerfectMatch: false, - }), - ) - .reply(HttpStatusCode.Ok, bioEntityResponseFixture); - - const data = await store - .dispatch( - getMultiBioEntity({ - searchQueries: [SEARCH_QUERY, SEARCH_QUERY], - isPerfectMatch: false, - }), - ) - .unwrap(); - - expect(data).toEqual([ - ...bioEntityResponseFixture.content, - ...bioEntityResponseFixture.content, - ]); - }); - }); -}); diff --git a/src/redux/bioEntity/bioEntity.thunks.ts b/src/redux/bioEntity/bioEntity.thunks.ts deleted file mode 100644 index 18fa812c93182be6346b9bff5f77a9168308a870..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/bioEntity.thunks.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { getBioEntity } from './thunks/getBioEntity'; -import { getMultiBioEntity } from './thunks/getMultiBioEntity'; - -export { getBioEntity, getMultiBioEntity }; diff --git a/src/redux/bioEntity/bioEntity.types.ts b/src/redux/bioEntity/bioEntity.types.ts index 9540daab08abcbe0efede2f8113e75ed81d2709c..07f11577cebfe10a899859f5e9c35850a6ba6534 100644 --- a/src/redux/bioEntity/bioEntity.types.ts +++ b/src/redux/bioEntity/bioEntity.types.ts @@ -1,19 +1,3 @@ -import { FetchDataState, MultiFetchDataState } from '@/types/fetchDataState'; -import { BioEntity, BioEntityContent } from '@/types/models'; -import { PayloadAction } from '@reduxjs/toolkit'; - -export type BioEntityContentsState = MultiFetchDataState<BioEntityContent[]> & { - submapConnections?: FetchDataState<BioEntity[]>; +export type BioEntityContentsState = { isContentTabOpened?: boolean; }; - -export type BioEntityContentSearchQuery = { - query: string | string[]; - params: { - perfectMatch: boolean; - }; -}; - -export type SetBioEntityContentActionPayload = BioEntityContent[]; - -export type SetBioEntityContentAction = PayloadAction<SetBioEntityContentActionPayload>; diff --git a/src/redux/bioEntity/thunks/getBioEntity.ts b/src/redux/bioEntity/thunks/getBioEntity.ts deleted file mode 100644 index bf54870a8db007d3785bb07606516fa293044a6f..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/thunks/getBioEntity.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { bioEntityResponseSchema } from '@/models/bioEntityResponseSchema'; -import { apiPath } from '@/redux/apiPath'; -import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; -import { BioEntityContent, BioEntityResponse } from '@/types/models'; -import { PerfectSearchParams } from '@/types/search'; -import { ThunkConfig } from '@/types/store'; -import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; -import { createAsyncThunk } from '@reduxjs/toolkit'; -import { getError } from '@/utils/error-report/getError'; -import { addNumbersToEntityNumberData } from '../../entityNumber/entityNumber.slice'; -import { BIO_ENTITY_FETCHING_ERROR_PREFIX } from '../bioEntity.constants'; - -type GetBioEntityProps = PerfectSearchParams; - -export const getBioEntity = createAsyncThunk< - BioEntityContent[] | undefined, - GetBioEntityProps, - ThunkConfig ->( - 'project/getBioEntityContents', - async ({ searchQuery, isPerfectMatch, addNumbersToEntityNumber = true }, { dispatch }) => { - try { - const response = await axiosInstanceNewAPI.get<BioEntityResponse>( - apiPath.getBioEntityContentsStringWithQuery({ searchQuery, isPerfectMatch }), - ); - - const isDataValidBioEnity = validateDataUsingZodSchema( - response.data, - bioEntityResponseSchema, - ); - - if (addNumbersToEntityNumber && response.data.content) { - const bioEntityIds = response.data.content.map(b => b.bioEntity.elementId); - dispatch(addNumbersToEntityNumberData(bioEntityIds)); - } - - return isDataValidBioEnity ? response.data.content : undefined; - } catch (error) { - return Promise.reject(getError({ error, prefix: BIO_ENTITY_FETCHING_ERROR_PREFIX })); - } - }, -); diff --git a/src/redux/bioEntity/thunks/getMultiBioEntity.ts b/src/redux/bioEntity/thunks/getMultiBioEntity.ts deleted file mode 100644 index cddf3ff17b9f335ab6f654365febfe99293e46ff..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/thunks/getMultiBioEntity.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ZERO } from '@/constants/common'; -import type { AppDispatch, store } from '@/redux/store'; -import { BioEntityContent } from '@/types/models'; -import { PerfectMultiSearchParams } from '@/types/search'; -import { ThunkConfig } from '@/types/store'; -import { PayloadAction, createAsyncThunk } from '@reduxjs/toolkit'; -import { getError } from '@/utils/error-report/getError'; -import { addNumbersToEntityNumberData } from '../../entityNumber/entityNumber.slice'; -import { MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX } from '../bioEntity.constants'; -import { getBioEntity } from './getBioEntity'; -import { fetchReactionsAndGetBioEntitiesIds } from './utils/fetchReactionsAndGetBioEntitiesIds'; - -type GetMultiBioEntityProps = PerfectMultiSearchParams; -type GetMultiBioEntityActions = PayloadAction<BioEntityContent[] | undefined | string>[]; // if error thrown, string containing error message is returned - -export const getMultiBioEntity = createAsyncThunk< - BioEntityContent[], - GetMultiBioEntityProps, - ThunkConfig ->( - 'project/getMultiBioEntity', - // eslint-disable-next-line consistent-return - async ({ searchQueries, isPerfectMatch }, { dispatch, getState }) => { - try { - const asyncGetBioEntityFunctions = searchQueries.map(searchQuery => - dispatch(getBioEntity({ searchQuery, isPerfectMatch, addNumbersToEntityNumber: false })), - ); - - const bioEntityContentsActions = (await Promise.all( - asyncGetBioEntityFunctions, - )) as GetMultiBioEntityActions; - - const bioEntityContents = bioEntityContentsActions - .map(bioEntityContentsAction => bioEntityContentsAction?.payload || []) - .flat() - .filter((payload): payload is BioEntityContent => typeof payload !== 'string') - .filter(payload => 'bioEntity' in payload || {}); - - const bioEntityIds = bioEntityContents.map(b => b.bioEntity.elementId); - dispatch(addNumbersToEntityNumberData(bioEntityIds)); - - const bioEntitiesIds = await fetchReactionsAndGetBioEntitiesIds({ - bioEntityContents, - dispatch: dispatch as AppDispatch, - getState: getState as typeof store.getState, - }); - const bioEntitiesStringIds = bioEntitiesIds.map(id => String(id)); - if (bioEntitiesIds.length > ZERO) { - await dispatch( - getMultiBioEntity({ searchQueries: bioEntitiesStringIds, isPerfectMatch: true }), - ); - } - - return bioEntityContents; - } catch (error) { - return Promise.reject(getError({ error, prefix: MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX })); - } - }, -); diff --git a/src/redux/bioEntity/thunks/utils/fetchReactionsAndGetBioEntitiesIds.ts b/src/redux/bioEntity/thunks/utils/fetchReactionsAndGetBioEntitiesIds.ts deleted file mode 100644 index a29317ed7c590388c192556d7763505226acf27d..0000000000000000000000000000000000000000 --- a/src/redux/bioEntity/thunks/utils/fetchReactionsAndGetBioEntitiesIds.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { FIRST_ARRAY_ELEMENT, SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; -import { openReactionDrawerById, selectTab } from '@/redux/drawer/drawer.slice'; -import { openMapAndOrSetActiveIfSelected } from '@/redux/map/map.slice'; -import { modelsNameMapSelector } from '@/redux/models/models.selectors'; -import { getReactionsByIds } from '@/redux/reactions/reactions.thunks'; -import type { AppDispatch, store } from '@/redux/store'; -import type { BioEntityContent, NewReaction } from '@/types/models'; -import getModelElementsIdsFromReaction from '@/components/Map/MapViewer/utils/listeners/mouseClick/getModelElementsIdsFromReaction'; - -interface Args { - bioEntityContents: BioEntityContent[]; - dispatch: AppDispatch; - getState: typeof store.getState; -} - -type ReactionId = { - id: number; - modelId: number; -}; - -const getReactionsIdsFromBioEntities = (bioEntites: BioEntityContent[]): ReactionId[] => { - return bioEntites - .filter(c => c?.bioEntity?.idReaction) - .filter(c => typeof c?.bioEntity?.id === 'number') - .map(c => { - let id: number; - if (typeof c.bioEntity.id === 'string') { - id = parseInt(c.bioEntity.id, 10); - } else { - id = c.bioEntity.id; - } - return { id, modelId: c.bioEntity.model }; - }); -}; - -const fetchReactions = async ( - reactionsIds: ReactionId[], - dispatch: AppDispatch, -): Promise<NewReaction[]> => { - const result = await dispatch( - getReactionsByIds({ - ids: reactionsIds, - shouldConcat: true, - }), - ); - - // if it has error (toast show should be handled by getReactionsByIds) - if (typeof result.payload === 'string') { - return []; - } - - const reactions = result.payload?.data; - if (!reactions) { - return []; - } - - return reactions; -}; - -const handleReactionShowInfoAndOpenMap = async ( - { dispatch, getState }: Args, - firstReaction: NewReaction, -): Promise<void> => { - const modelsNames = modelsNameMapSelector(getState()); - - dispatch(openReactionDrawerById(firstReaction.id)); - dispatch(selectTab('')); - dispatch( - openMapAndOrSetActiveIfSelected({ - modelId: firstReaction.model, - modelName: modelsNames[firstReaction.model], - }), - ); -}; - -export const fetchReactionsAndGetBioEntitiesIds = async (args: Args): Promise<number[]> => { - const { dispatch, bioEntityContents } = args; - - const bioEntityReactionsIds = getReactionsIdsFromBioEntities(bioEntityContents || []); - if (bioEntityReactionsIds.length === SIZE_OF_EMPTY_ARRAY) { - return []; - } - - const reactions = await fetchReactions(bioEntityReactionsIds, dispatch); - if (reactions.length === SIZE_OF_EMPTY_ARRAY) { - return []; - } - - const bioEntitiesIds = reactions - .map(reaction => getModelElementsIdsFromReaction(reaction)) - .flat(); - const firstReaction = reactions[FIRST_ARRAY_ELEMENT]; - if (firstReaction) { - handleReactionShowInfoAndOpenMap(args, firstReaction); - } - - return bioEntitiesIds; -}; diff --git a/src/redux/chemicals/chemicals.selectors.ts b/src/redux/chemicals/chemicals.selectors.ts index 7f11e09a16adb38b957f2b516be5afcdda901fde..b9443769ab482e316ad6ed0adeda29058b1bcd79 100644 --- a/src/redux/chemicals/chemicals.selectors.ts +++ b/src/redux/chemicals/chemicals.selectors.ts @@ -2,7 +2,7 @@ import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; import { ElementId, ElementIdTabObj, Tab } from '@/types/elements'; import { MultiSearchData } from '@/types/fetchDataState'; -import { BioEntity, Chemical } from '@/types/models'; +import { Chemical, ModelElement } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; import { currentSelectedSearchElement } from '../drawer/drawer.selectors'; import { currentModelIdSelector } from '../models/models.selectors'; @@ -24,10 +24,10 @@ export const chemicalsForSelectedSearchElementSelector = createSelector( ), ); -export const chemicalsBioEntitiesForSelectedSearchElementSelector = createSelector( +export const chemicalsElementsForSelectedSearchElementSelector = createSelector( chemicalsSelector, currentSelectedSearchElement, - (chemicalsState, currentSearchElement): BioEntity[] => { + (chemicalsState, currentSearchElement): ModelElement[] => { return (chemicalsState?.data || []) .filter(({ searchQueryElement }) => currentSearchElement ? searchQueryElement === currentSearchElement : true, @@ -40,25 +40,25 @@ export const chemicalsBioEntitiesForSelectedSearchElementSelector = createSelect }, ); -export const searchedChemicalsBioEntitesOfCurrentMapSelector = createSelector( - chemicalsBioEntitiesForSelectedSearchElementSelector, +export const searchedChemicalsElementsOfCurrentMapSelector = createSelector( + chemicalsElementsForSelectedSearchElementSelector, currentModelIdSelector, - (chemicalsBioEntities, currentModelId): BioEntity[] => { - return (chemicalsBioEntities || []).filter(bioEntity => bioEntity.model === currentModelId); + (chemicalsElements, currentModelId): ModelElement[] => { + return (chemicalsElements || []).filter(element => element.model === currentModelId); }, ); -export const allChemicalsBioEntitesOfCurrentMapSelector = createSelector( +export const allChemicalsElementsOfCurrentMapSelector = createSelector( chemicalsSelector, currentModelIdSelector, - (chemicalsState, currentModelId): BioEntity[] => { + (chemicalsState, currentModelId): ModelElement[] => { return (chemicalsState?.data || []) .map(({ data }) => data || []) .flat() .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) .flat() .flat() - .filter(bioEntity => bioEntity.model === currentModelId); + .filter(element => element.model === currentModelId); }, ); @@ -79,8 +79,8 @@ export const allChemicalsIdTabSelectorOfCurrentMap = createSelector( .map(({ targetElements }) => targetElements) .flat() .flat() - .filter(bioEntity => bioEntity.model === currentModelId) - .map(bioEntity => [bioEntity.id, tab]), + .filter(element => element.model === currentModelId) + .map(element => [element.id, tab]), ), ) .flat() @@ -89,18 +89,6 @@ export const allChemicalsIdTabSelectorOfCurrentMap = createSelector( }, ); -export const allChemicalsBioEntitesOfAllMapsSelector = createSelector( - chemicalsSelector, - (chemicalsState): BioEntity[] => { - return (chemicalsState?.data || []) - .map(({ data }) => data || []) - .flat() - .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) - .flat() - .flat(); - }, -); - export const loadingChemicalsStatusSelector = createSelector( chemicalsForSelectedSearchElementSelector, state => state?.loading, diff --git a/src/redux/comment/comment.types.ts b/src/redux/comment/comment.types.ts index 1e727562c842f4e3835c43f3ff18df3110a305fe..c0e77c4e218fcb4746cef614eeacdc246d612ddc 100644 --- a/src/redux/comment/comment.types.ts +++ b/src/redux/comment/comment.types.ts @@ -1,11 +1,11 @@ import { FetchDataState } from '@/types/fetchDataState'; -import { BioEntity, Comment, NewReaction } from '@/types/models'; +import { ModelElement, Comment, NewReaction } from '@/types/models'; import { PayloadAction } from '@reduxjs/toolkit'; import { Point } from '@/types/map'; export interface CommentsState extends FetchDataState<Comment[], []> { isOpen: boolean; - commentElement: BioEntity | null; + commentElement: ModelElement | null; commentReaction: NewReaction | null; } diff --git a/src/redux/contextMenu/contextMenu.selector.ts b/src/redux/contextMenu/contextMenu.selector.ts index 9c2db16a7bfd0824d0bb86093d8c756437a05de1..dc1222f8d5b026ad2fbafab431042ae7bd6a8e5c 100644 --- a/src/redux/contextMenu/contextMenu.selector.ts +++ b/src/redux/contextMenu/contextMenu.selector.ts @@ -3,8 +3,6 @@ import { rootSelector } from '../root/root.selectors'; export const contextMenuSelector = createSelector(rootSelector, state => state.contextMenu); -export const isContextMenuOpenSelector = createSelector(contextMenuSelector, state => state.isOpen); - export const currentSelectedBioEntityIdSelector = createSelector( contextMenuSelector, state => state.currentSelectedBioEntityId, diff --git a/src/redux/drawer/drawer.reducers.ts b/src/redux/drawer/drawer.reducers.ts index 88f1096c6e38f71dcc0442b506fa9a832e6e9434..b244295ab31926af8e77a3ac2e1a2bc9637ddf64 100644 --- a/src/redux/drawer/drawer.reducers.ts +++ b/src/redux/drawer/drawer.reducers.ts @@ -80,7 +80,7 @@ export const displayBioEntitiesListReducer = ( state.drawerName = 'search'; state.searchDrawerState.currentStep = STEP.SECOND; state.searchDrawerState.listOfBioEnitites = action.payload; - state.searchDrawerState.stepType = 'bioEntity'; + state.searchDrawerState.stepType = 'modelElement'; }; export const displayGroupedSearchResultsReducer = (state: DrawerState): void => { diff --git a/src/redux/drawer/drawer.selectors.ts b/src/redux/drawer/drawer.selectors.ts index a5f109ea50ed068bb49535e51bb3c9ec8a5eabed..26299df5e58059466425075913dca08a25b6387d 100644 --- a/src/redux/drawer/drawer.selectors.ts +++ b/src/redux/drawer/drawer.selectors.ts @@ -100,7 +100,7 @@ export const resultListSelector = createSelector( data: chemical, })); } - case 'bioEntity': + case 'modelElement': return undefined; case 'none': return undefined; diff --git a/src/redux/drawer/drawer.types.ts b/src/redux/drawer/drawer.types.ts index 4cf1440f73bc5b3fdb006c0dac47e1507503f298..4a80eea10a783e56b21c20561227e2c1b94f1ea1 100644 --- a/src/redux/drawer/drawer.types.ts +++ b/src/redux/drawer/drawer.types.ts @@ -2,12 +2,13 @@ import type { DrawerName } from '@/types/drawerName'; import { KeyedFetchDataState } from '@/types/fetchDataState'; import { BioEntityContent, Chemical, Drug } from '@/types/models'; import { PayloadAction } from '@reduxjs/toolkit'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; export type SearchDrawerState = { currentStep: number; - stepType: 'bioEntity' | 'drugs' | 'chemicals' | 'none'; + stepType: 'modelElement' | 'drugs' | 'chemicals' | 'none'; selectedValue: BioEntityContent | Drug | Chemical | undefined; - listOfBioEnitites: BioEntityContent[]; + listOfBioEnitites: Array<SearchModelElementDataState>; selectedSearchElement: string; }; @@ -49,8 +50,5 @@ export type OpenReactionDrawerByIdAction = PayloadAction<OpenReactionDrawerByIdP export type OpenBioEntityDrawerByIdPayload = number | string; export type OpenBioEntityDrawerByIdAction = PayloadAction<OpenBioEntityDrawerByIdPayload>; -export type SetSelectedSearchElementPayload = string; -export type SetSelectedSearchElementAction = PayloadAction<SetSelectedSearchElementPayload>; - export type OpenCommentDrawerByIdPayload = number; export type OpenCommentDrawerByIdAction = PayloadAction<OpenCommentDrawerByIdPayload>; diff --git a/src/redux/drugs/drugs.reducers.test.ts b/src/redux/drugs/drugs.reducers.test.ts index 69d29267ef92cdddead5846ce3655c0785b3c2d7..55af806f91a1b139bdd6fd7bf64916f68e98b756 100644 --- a/src/redux/drugs/drugs.reducers.test.ts +++ b/src/redux/drugs/drugs.reducers.test.ts @@ -40,7 +40,7 @@ describe('drugs reducer', () => { const { type } = await store.dispatch(getDrugs(SEARCH_QUERY)); const { data } = store.getState().drugs; const drugsWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, + searchModelElement => searchModelElement.searchQueryElement === SEARCH_QUERY, ); expect(type).toBe('project/getDrugs/fulfilled'); @@ -60,7 +60,7 @@ describe('drugs reducer', () => { const action = await store.dispatch(getDrugs(SEARCH_QUERY)); const { data } = store.getState().drugs; const drugsWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, + searchModelElement => searchModelElement.searchQueryElement === SEARCH_QUERY, ); expect(() => unwrapResult(action)).toThrow( @@ -84,7 +84,7 @@ describe('drugs reducer', () => { const { data } = store.getState().drugs; const drugsWithSearchElement = data.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, + searchModelElement => searchModelElement.searchQueryElement === SEARCH_QUERY, ); expect(drugsWithSearchElement).toEqual({ @@ -98,7 +98,7 @@ describe('drugs reducer', () => { const { data: dataPromiseFulfilled } = store.getState().drugs; const drugsWithSearchElementFulfilled = dataPromiseFulfilled.find( - bioEntity => bioEntity.searchQueryElement === SEARCH_QUERY, + searchModelElement => searchModelElement.searchQueryElement === SEARCH_QUERY, ); expect(drugsWithSearchElementFulfilled).toEqual({ searchQueryElement: SEARCH_QUERY, diff --git a/src/redux/drugs/drugs.selectors.ts b/src/redux/drugs/drugs.selectors.ts index ecaf082afd32d1c1a5e0724bc28250d71e9f39eb..a2a616c40db92fb1d6e43a6407be1c109fce8f1c 100644 --- a/src/redux/drugs/drugs.selectors.ts +++ b/src/redux/drugs/drugs.selectors.ts @@ -2,7 +2,7 @@ import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; import { ElementId, ElementIdTabObj, Tab } from '@/types/elements'; import { MultiSearchData } from '@/types/fetchDataState'; -import { BioEntity, Drug } from '@/types/models'; +import { Drug, ModelElement } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; import { currentSelectedSearchElement } from '../drawer/drawer.selectors'; import { currentModelIdSelector } from '../models/models.selectors'; @@ -38,10 +38,10 @@ export const numberOfDrugsSelector = createSelector( }, ); -export const drugsBioEntitiesForSelectedSearchElementSelector = createSelector( +export const drugsElementsForSelectedSearchElementSelector = createSelector( drugsSelector, currentSelectedSearchElement, - (drugsState, currentSearchElement): BioEntity[] => { + (drugsState, currentSearchElement): ModelElement[] => { return (drugsState?.data || []) .filter(({ searchQueryElement }) => currentSearchElement ? searchQueryElement === currentSearchElement : true, @@ -54,25 +54,25 @@ export const drugsBioEntitiesForSelectedSearchElementSelector = createSelector( }, ); -export const searchedDrugsBioEntitesOfCurrentMapSelector = createSelector( - drugsBioEntitiesForSelectedSearchElementSelector, +export const searchedDrugsElementsOfCurrentMapSelector = createSelector( + drugsElementsForSelectedSearchElementSelector, currentModelIdSelector, - (drugsBioEntities, currentModelId): BioEntity[] => { - return (drugsBioEntities || []).filter(bioEntity => bioEntity.model === currentModelId); + (drugsElements, currentModelId): ModelElement[] => { + return (drugsElements || []).filter(element => element.model === currentModelId); }, ); -export const allDrugsBioEntitesOfCurrentMapSelector = createSelector( +export const allDrugsElementsOfCurrentMapSelector = createSelector( drugsSelector, currentModelIdSelector, - (drugsState, currentModelId): BioEntity[] => { + (drugsState, currentModelId): ModelElement[] => { return (drugsState?.data || []) .map(({ data }) => data || []) .flat() .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) .flat() .flat() - .filter(bioEntity => bioEntity.model === currentModelId); + .filter(element => element.model === currentModelId); }, ); @@ -93,8 +93,8 @@ export const allDrugsIdTabSelectorOfCurrentMap = createSelector( .map(({ targetElements }) => targetElements) .flat() .flat() - .filter(bioEntity => bioEntity.model === currentModelId) - .map(bioEntity => [bioEntity.id, tab]), + .filter(element => element.model === currentModelId) + .map(element => [element.id, tab]), ), ) .flat() @@ -102,15 +102,3 @@ export const allDrugsIdTabSelectorOfCurrentMap = createSelector( ); }, ); - -export const allDrugsBioEntitesOfAllMapsSelector = createSelector( - drugsSelector, - (drugsState): BioEntity[] => { - return (drugsState?.data || []) - .map(({ data }) => data || []) - .flat() - .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) - .flat() - .flat(); - }, -); diff --git a/src/redux/modelElements/modelElements.constants.ts b/src/redux/modelElements/modelElements.constants.ts index 42427c11f62830690150e10913bfb1ea0c0ec2bc..0d017748a38a4f949893a95b5418d4b458b1bcdd 100644 --- a/src/redux/modelElements/modelElements.constants.ts +++ b/src/redux/modelElements/modelElements.constants.ts @@ -1,3 +1,7 @@ export const MODEL_ELEMENTS_FETCHING_ERROR_PREFIX = 'Failed to fetch model elements'; export const MODEL_ELEMENTS_DEFAULT_COMPARTMENT_NAME = 'default'; + +export const MULTI_MODEL_ELEMENTS_SEARCH_ERROR_PREFIX = 'Failed to search multi model elements'; + +export const MODEL_ELEMENT_SEARCH_ERROR_PREFIX = 'Failed to search model element'; diff --git a/src/redux/modelElements/modelElements.mock.ts b/src/redux/modelElements/modelElements.mock.ts index 583f03f397d76cd5f9e857f1f46cb64d8e2d6614..70dc3406202feddeb2d3a5327eb802d2292d5020 100644 --- a/src/redux/modelElements/modelElements.mock.ts +++ b/src/redux/modelElements/modelElements.mock.ts @@ -1,12 +1,47 @@ import { DEFAULT_ERROR } from '@/constants/errors'; -import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; -import { FetchDataState } from '@/types/fetchDataState'; +import { + ModelElementsState, + SearchModelElementDataState, +} from '@/redux/modelElements/modelElements.types'; +import { FetchDataState, MultiFetchDataState, MultiSearchData } from '@/types/fetchDataState'; import { ModelElement } from '@/types/models'; +import { HISTAMINE_MAP_ID } from '@/constants/mocks'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; -export const MODEL_ELEMENTS_INITIAL_STATE_MOCK: ModelElementsState = {}; +export const MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK: MultiFetchDataState< + SearchModelElementDataState[] +> = { + data: [], + loading: 'idle', + error: DEFAULT_ERROR, +}; + +export const MODEL_ELEMENTS_INITIAL_STATE_MOCK: ModelElementsState = { + data: {}, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, +}; export const MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK: FetchDataState<Array<ModelElement>> = { data: [], loading: 'idle', error: DEFAULT_ERROR, }; + +export const MODEL_ELEMENT_LINKING_TO_SUBMAP: ModelElement = { + ...modelElementFixture, + submodel: { + mapId: HISTAMINE_MAP_ID, + type: 'DONWSTREAM_TARGETS', + }, +}; + +export const MODEL_ELEMENTS_SEARCH_LINKING_TO_SUBMAP_DATA_MOCK: MultiSearchData< + SearchModelElementDataState[] +>[] = [ + { + data: [{ modelElement: MODEL_ELEMENT_LINKING_TO_SUBMAP, perfect: false }], + searchQueryElement: '', + loading: 'succeeded', + error: DEFAULT_ERROR, + }, +]; diff --git a/src/redux/modelElements/modelElements.reducers.test.ts b/src/redux/modelElements/modelElements.reducers.test.ts index 8c499a6dc5384cfa611805bf79ff1c831b24a860..9a3bc2a9e0052636b990c6682ed82723353c6345 100644 --- a/src/redux/modelElements/modelElements.reducers.test.ts +++ b/src/redux/modelElements/modelElements.reducers.test.ts @@ -9,10 +9,17 @@ import { HttpStatusCode } from 'axios'; import { unwrapResult } from '@reduxjs/toolkit'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import modelElementsReducer from '@/redux/modelElements/modelElements.slice'; -import { getModelElementsForModel } from '@/redux/modelElements/modelElements.thunks'; +import { + getModelElementsForModel, + searchModelElement, +} from '@/redux/modelElements/modelElements.thunks'; import { modelElementsFixture } from '@/models/fixtures/modelElementsFixture'; +import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { MODEL_ELEMENTS_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; const mockedAxiosClient = mockNetworkNewAPIResponse(); +const SEARCH_QUERY = 'park7'; describe('model elements reducer', () => { let store = {} as ToolkitStoreWithSingleSlice<ModelElementsState>; @@ -23,7 +30,7 @@ describe('model elements reducer', () => { it('should match initial state', () => { const action = { type: 'unknown' }; - expect(modelElementsReducer(undefined, action)).toEqual({}); + expect(modelElementsReducer(undefined, action)).toEqual(MODEL_ELEMENTS_INITIAL_STATE_MOCK); }); it('should update store after successful getModelElementsForModel query', async () => { @@ -32,7 +39,7 @@ describe('model elements reducer', () => { .reply(HttpStatusCode.Ok, modelElementsFixture); const { type } = await store.dispatch(getModelElementsForModel(0)); - const { data, loading, error } = store.getState().modelElements[0]; + const { data, loading, error } = store.getState().modelElements.data[0]; expect(type).toBe('modelElements/getModelElementsForModel/fulfilled'); expect(loading).toEqual('succeeded'); @@ -44,7 +51,7 @@ describe('model elements reducer', () => { mockedAxiosClient.onGet(apiPath.getModelElements(0)).reply(HttpStatusCode.NotFound, []); const action = await store.dispatch(getModelElementsForModel(0)); - const { data, loading, error } = store.getState().modelElements[0]; + const { data, loading, error } = store.getState().modelElements.data[0]; expect(action.type).toBe('modelElements/getModelElementsForModel/rejected'); expect(() => unwrapResult(action)).toThrow( @@ -62,16 +69,129 @@ describe('model elements reducer', () => { const modelElementsPromise = store.dispatch(getModelElementsForModel(0)); - const { data, loading } = store.getState().modelElements[0]; + const { data, loading } = store.getState().modelElements.data[0]; expect(data).toEqual([]); expect(loading).toEqual('pending'); modelElementsPromise.then(() => { const { data: dataPromiseFulfilled, loading: promiseFulfilled } = - store.getState().modelElements[0]; + store.getState().modelElements.data[0]; expect(dataPromiseFulfilled).toEqual(modelElementsFixture.content); expect(promiseFulfilled).toEqual('succeeded'); }); }); + + it('should update store after succesfull searchModelElement query', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, bioEntityResponseFixture); + + const { type } = await store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + const { search } = store.getState().modelElements; + const modelElementWithSearchQuery = search.data.find( + modelElement => modelElement.searchQueryElement === SEARCH_QUERY, + ); + + expect(type).toBe('modelElements/searchModelElement/fulfilled'); + expect(modelElementWithSearchQuery).toEqual({ + searchQueryElement: SEARCH_QUERY, + data: bioEntityResponseFixture.content.map(data => ({ + modelElement: data.bioEntity, + perfect: data.perfect, + })), + loading: 'succeeded', + error: DEFAULT_ERROR, + }); + }); + + it('should update store after failed getBioEntity query', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.NotFound, bioEntityResponseFixture); + + const action = await store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + const { search } = store.getState().modelElements; + + const modelElementWithSearchQuery = search.data.find( + modelElement => modelElement.searchQueryElement === SEARCH_QUERY, + ); + expect(action.type).toBe('modelElements/searchModelElement/rejected'); + expect(() => unwrapResult(action)).toThrow( + "Failed to search model element: The page you're looking for doesn't exist. Please verify the URL and try again.", + ); + expect(modelElementWithSearchQuery).toEqual({ + searchQueryElement: SEARCH_QUERY, + data: undefined, + loading: 'failed', + error: DEFAULT_ERROR, + }); + }); + + it('should update store on loading getBioEntity query', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, bioEntityResponseFixture); + + const searchModelElementPromise = store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + + const { search } = store.getState().modelElements; + const modelElementWithSearchQuery = search.data.find( + modelElement => modelElement.searchQueryElement === SEARCH_QUERY, + ); + + expect(modelElementWithSearchQuery).toEqual({ + searchQueryElement: SEARCH_QUERY, + data: undefined, + loading: 'pending', + error: DEFAULT_ERROR, + }); + + searchModelElementPromise.then(() => { + const { search: searchPromiseFulfilled } = store.getState().modelElements; + const modelElementWithSearchQueryFulfilled = searchPromiseFulfilled.data.find( + modelElement => modelElement.searchQueryElement === SEARCH_QUERY, + ); + + expect(modelElementWithSearchQueryFulfilled).toEqual({ + searchQueryElement: SEARCH_QUERY, + data: bioEntityResponseFixture.content.map(data => ({ + modelElement: data.bioEntity, + perfect: data.perfect, + })), + loading: 'succeeded', + error: DEFAULT_ERROR, + }); + }); + }); }); diff --git a/src/redux/modelElements/modelElements.reducers.ts b/src/redux/modelElements/modelElements.reducers.ts index 777295cf15053679c1d33127f58f2fbc8babc2b2..933f2e698ed77e6c3b96353e8ca799111d48b22f 100644 --- a/src/redux/modelElements/modelElements.reducers.ts +++ b/src/redux/modelElements/modelElements.reducers.ts @@ -1,36 +1,135 @@ -import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; -import { getModelElementsForModel } from '@/redux/modelElements/modelElements.thunks'; -import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; +import { ActionReducerMapBuilder, PayloadAction } from '@reduxjs/toolkit'; +import { + getModelElementsForModel, + searchModelElement, + searchMultiModelElements, +} from '@/redux/modelElements/modelElements.thunks'; +import { + ModelElementsState, + SearchModelElementDataState, +} from '@/redux/modelElements/modelElements.types'; import { MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK } from '@/redux/modelElements/modelElements.mock'; import { DEFAULT_ERROR } from '@/constants/errors'; +import { ModelElement } from '@/types/models'; export const getModelElementsReducer = ( builder: ActionReducerMapBuilder<ModelElementsState>, ): void => { builder.addCase(getModelElementsForModel.pending, (state, action) => { const modelId = action.meta.arg; - if (state[modelId]) { - state[modelId].loading = 'pending'; + if (state.data[modelId]) { + state.data[modelId].loading = 'pending'; } else { - state[modelId] = { ...MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK, loading: 'pending' }; + state.data[modelId] = { ...MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK, loading: 'pending' }; } }); builder.addCase(getModelElementsForModel.fulfilled, (state, action) => { const modelId = action.meta.arg; const data = action.payload || []; - if (state[modelId]) { - state[modelId].data = data; - state[modelId].loading = 'succeeded'; + if (state.data[modelId]) { + state.data[modelId].data = data; + state.data[modelId].loading = 'succeeded'; } else { - state[modelId] = { data, loading: 'pending', error: DEFAULT_ERROR }; + state.data[modelId] = { data, loading: 'pending', error: DEFAULT_ERROR }; } }); builder.addCase(getModelElementsForModel.rejected, (state, action) => { const modelId = action.meta.arg; - if (state[modelId]) { - state[modelId].loading = 'failed'; + if (state.data[modelId]) { + state.data[modelId].loading = 'failed'; } else { - state[modelId] = { ...MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK, loading: 'failed' }; + state.data[modelId] = { ...MODEL_ELEMENTS_STATE_INITIAL_MODEL_MOCK, loading: 'failed' }; } }); }; + +export const searchModelElementReducer = ( + builder: ActionReducerMapBuilder<ModelElementsState>, +): void => { + builder.addCase(searchModelElement.pending, (state, action) => { + state.search.data.push({ + searchQueryElement: action.meta.arg.searchQuery, + data: undefined, + loading: 'pending', + error: DEFAULT_ERROR, + }); + }); + builder.addCase(searchModelElement.fulfilled, (state, action) => { + const bioEntities = state.search.data.find( + bioEntity => bioEntity.searchQueryElement === action.meta.arg.searchQuery, + ); + if (bioEntities) { + bioEntities.data = action.payload?.map(data => ({ + modelElement: data.bioEntity, + perfect: data.perfect, + })); + bioEntities.loading = 'succeeded'; + } + }); + builder.addCase(searchModelElement.rejected, (state, action) => { + const bioEntities = state.search.data.find( + bioEntity => bioEntity.searchQueryElement === action.meta.arg.searchQuery, + ); + if (bioEntities) { + bioEntities.loading = 'failed'; + } + }); +}; + +export const searchMultiModelElementsReducer = ( + builder: ActionReducerMapBuilder<ModelElementsState>, +): void => { + builder.addCase(searchMultiModelElements.pending, state => { + state.search.data = []; + state.search.loading = 'pending'; + }); + builder.addCase(searchMultiModelElements.fulfilled, state => { + state.search.loading = 'succeeded'; + }); + builder.addCase(searchMultiModelElements.rejected, state => { + state.search.loading = 'failed'; + }); +}; + +export const setModelElementSearchReducer = ( + state: ModelElementsState, + action: PayloadAction<SearchModelElementDataState>, +): void => { + state.search = { + data: [ + { + data: [action.payload], + loading: 'succeeded', + error: DEFAULT_ERROR, + searchQueryElement: action.payload.modelElement.id.toString(), + }, + ], + loading: 'succeeded', + error: DEFAULT_ERROR, + }; +}; + +export const setMultipleModelElementSearchReducer = ( + state: ModelElementsState, + action: PayloadAction<ModelElement[]>, +): void => { + state.search.data = action.payload.map(modelElement => { + return { + data: [ + { + modelElement, + perfect: true, + }, + ], + loading: 'succeeded', + error: DEFAULT_ERROR, + searchQueryElement: modelElement.id.toString(), + }; + }); + state.search.loading = 'succeeded'; +}; + +export const clearSearchModelElementsReducer = (state: ModelElementsState): void => { + state.search.data = []; + state.search.loading = 'idle'; +}; diff --git a/src/redux/modelElements/modelElements.selector.ts b/src/redux/modelElements/modelElements.selector.ts index 55c08d7a0b13596f074c08a319c8d13bd0dfbb73..317aa053f9301b1f18dd39bc4968ff7c246aea2c 100644 --- a/src/redux/modelElements/modelElements.selector.ts +++ b/src/redux/modelElements/modelElements.selector.ts @@ -1,22 +1,39 @@ import { createSelector } from '@reduxjs/toolkit'; import { rootSelector } from '@/redux/root/root.selectors'; -import { currentModelIdSelector } from '@/redux/models/models.selectors'; -import { currentSearchedBioEntityId } from '@/redux/drawer/drawer.selectors'; -import { ModelElement } from '@/types/models'; +import { currentModelIdSelector, modelsDataSelector } from '@/redux/models/models.selectors'; +import { + currentSearchedBioEntityId, + currentSelectedSearchElement, +} from '@/redux/drawer/drawer.selectors'; +import { Comment, MapModel, ModelElement } from '@/types/models'; import { MODEL_ELEMENTS_DEFAULT_COMPARTMENT_NAME } from '@/redux/modelElements/modelElements.constants'; import { COMPARTMENT_SBO_TERM } from '@/components/Map/MapViewer/MapViewer.constants'; +import { MultiSearchData } from '@/types/fetchDataState'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; +import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; +import { currentSelectedBioEntityIdSelector } from '@/redux/contextMenu/contextMenu.selector'; +import { ElementIdTabObj } from '@/types/elements'; +import { allCommentsSelectorOfCurrentMap } from '@/redux/comment/comment.selectors'; + +export const modelElementsStateSelector = createSelector( + rootSelector, + state => state.modelElements, +); -export const modelElementsSelector = createSelector(rootSelector, state => state.modelElements); +export const modelElementsDataSelector = createSelector( + modelElementsStateSelector, + state => state.data, +); export const modelElementsStateForCurrentModelSelector = createSelector( - modelElementsSelector, + modelElementsDataSelector, currentModelIdSelector, - (state, currentModelId) => state[currentModelId], + (data, currentModelId) => data[currentModelId], ); export const modelElementsByModelIdSelector = createSelector( - [modelElementsSelector, (_state, modelId: number): number => modelId], - (state, modelId) => state[modelId]?.data || [], + [modelElementsDataSelector, (_state, modelId: number): number => modelId], + (data, modelId) => data[modelId]?.data || [], ); export const modelElementsCurrentModelLoadingSelector = createSelector( @@ -24,8 +41,9 @@ export const modelElementsCurrentModelLoadingSelector = createSelector( state => state?.loading, ); -export const modelElementsAnyModelLoadingSelector = createSelector(modelElementsSelector, state => - Object.values(state).some(modelElementState => modelElementState.loading === 'pending'), +export const modelElementsAnyModelLoadingSelector = createSelector( + modelElementsDataSelector, + state => Object.values(state).some(modelElementState => modelElementState.loading === 'pending'), ); export const modelElementsForCurrentModelSelector = createSelector( @@ -64,7 +82,7 @@ export const currentDrawerModelElementSelector = createSelector( ); export const compartmentPathwaysSelector = createSelector( - modelElementsSelector, + modelElementsDataSelector, (state): ModelElement[] => { const pathways: ModelElement[] = []; Object.values(state).forEach(modelState => { @@ -77,3 +95,158 @@ export const compartmentPathwaysSelector = createSelector( return pathways; }, ); + +export const allModelElementsSubmapConnectionsForCurrentSubmapSelector = createSelector( + modelElementsWithSubmapConnectionForCurrentModelSelector, + currentModelIdSelector, + (submapConnectionsModelElement, currentModel): ModelElement[] => + submapConnectionsModelElement.filter(({ model }) => model === currentModel), +); + +// ------SEARCH (OLD BIO ENTITIES)------ +export const modelElementsSearchSelector = createSelector( + modelElementsStateSelector, + state => state.search, +); + +export const modelElementsSearchDataSelector = createSelector( + modelElementsSearchSelector, + state => state.data, +); + +export const searchModelElementsListSelector = createSelector( + modelElementsSearchDataSelector, + modelElementsSearchData => modelElementsSearchData.map(b => b.data || []).flat(), +); + +export const allSearchModelElementForCurrentModelSelector = createSelector( + modelElementsSearchDataSelector, + currentModelIdSelector, + (modelElementsSearchData, currentModelId): ModelElement[] => { + return modelElementsSearchData + .map(({ data }) => data || []) + .flat() + .filter(({ modelElement }) => modelElement.model === currentModelId) + .map(({ modelElement }) => modelElement); + }, +); + +export const searchedModelElementsSelector = createSelector( + modelElementsSearchDataSelector, + currentSelectedSearchElement, + ( + modelElementsSearchData, + currentSearchElement, + ): MultiSearchData<SearchModelElementDataState[]> | undefined => + modelElementsSearchData.find( + ({ searchQueryElement }) => searchQueryElement === currentSearchElement, + ), +); + +export const searchedModelElementsForCurrentModelSelector = createSelector( + modelElementsSearchDataSelector, + currentModelIdSelector, + currentSelectedSearchElement, + (modelElementsSearchData, currentModelId, currentSearchElement): ModelElement[] => { + return modelElementsSearchData + .filter(({ searchQueryElement }) => + currentSearchElement ? searchQueryElement === currentSearchElement : true, + ) + .map(({ data }) => data || []) + .flat() + .filter(({ modelElement }) => modelElement.model === currentModelId) + .map(({ modelElement }) => modelElement); + }, +); + +export const searchModelElementsLoadingSelector = createSelector( + modelElementsSearchSelector, + search => search.loading, +); + +export const searchModelElementsLoadingStatusSelector = createSelector( + searchedModelElementsSelector, + state => state?.loading, +); + +export const numberOfSearchModelElementsSelector = createSelector( + searchedModelElementsSelector, + state => (state?.data ? state.data.length : SIZE_OF_EMPTY_ARRAY), +); + +export const searchedModelElementForContextMapSelector = createSelector( + modelElementsSearchDataSelector, + currentSelectedBioEntityIdSelector, + (modelElementsSearchData, currentBioEntityId): ModelElement | undefined => { + return modelElementsSearchData + .find(({ searchQueryElement }) => searchQueryElement === currentBioEntityId.toString()) + ?.data?.find(({ modelElement }) => modelElement.id === currentBioEntityId)?.modelElement; + }, +); + +export const searchedModelElementUniProtIdSelector = createSelector( + searchedModelElementForContextMapSelector, + (modelElement): string | undefined => { + return modelElement?.references.find(({ type }) => type === 'UNIPROT')?.resource; + }, +); + +export const allSearchModelElementsIdTabForCurrentModelSelector = createSelector( + modelElementsSearchDataSelector, + currentModelIdSelector, + (modelElementsSearchData, currentModelId): ElementIdTabObj => { + const entries = modelElementsSearchData.flatMap(({ data, searchQueryElement }) => + (data || []) + .flat() + .filter(({ modelElement }) => modelElement.model === currentModelId) + .map(({ modelElement }) => [modelElement.id, searchQueryElement]), + ); + return Object.fromEntries(entries); + }, +); + +export const searchModelElementsPerModelSelector = createSelector( + searchedModelElementsSelector, + modelsDataSelector, + (modelElements, models) => { + const modelElementsPerModelPerSearchElement = (models || []).map(model => { + const modelElementsInGivenModel = (modelElements?.data || []).filter( + entity => model.id === entity.modelElement.model, + ); + + return { + modelName: model.name, + modelId: model.id, + numberOfModelElements: modelElementsInGivenModel.length, + modelElements: modelElementsInGivenModel, + }; + }); + + return modelElementsPerModelPerSearchElement.filter( + model => model.numberOfModelElements !== SIZE_OF_EMPTY_ARRAY, + ); + }, +); + +export const currentDrawerModelElementRelatedSubmapSelector = createSelector( + currentDrawerModelElementSelector, + modelsDataSelector, + (bioEntity, models): MapModel | undefined => + models.find(({ id }) => id === bioEntity?.submodel?.mapId), +); + +export const currentDrawerElementCommentsSelector = createSelector( + currentDrawerModelElementSelector, + allCommentsSelectorOfCurrentMap, + (element, comments): Comment[] => { + if (element) { + return comments.filter( + comment => + comment.type === 'ALIAS' && + comment.modelId === element.model && + Number(comment.elementId) === element.id, + ); + } + return []; + }, +); diff --git a/src/redux/modelElements/modelElements.slice.ts b/src/redux/modelElements/modelElements.slice.ts index cbf16d002fe05a7ef90c2334d844106da209d4a5..d2130dec7ad749d9f908baa7ea04d0a23dee0334 100644 --- a/src/redux/modelElements/modelElements.slice.ts +++ b/src/redux/modelElements/modelElements.slice.ts @@ -1,14 +1,30 @@ import { createSlice } from '@reduxjs/toolkit'; -import { getModelElementsReducer } from '@/redux/modelElements/modelElements.reducers'; +import { + clearSearchModelElementsReducer, + getModelElementsReducer, + setModelElementSearchReducer, + setMultipleModelElementSearchReducer, + searchModelElementReducer, + searchMultiModelElementsReducer, +} from '@/redux/modelElements/modelElements.reducers'; import { MODEL_ELEMENTS_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; export const modelElements = createSlice({ name: 'modelElements', initialState: MODEL_ELEMENTS_INITIAL_STATE_MOCK, - reducers: {}, + reducers: { + setModelElementSearch: setModelElementSearchReducer, + setMultipleModelElementSearch: setMultipleModelElementSearchReducer, + clearSearchModelElements: clearSearchModelElementsReducer, + }, extraReducers: builder => { + searchModelElementReducer(builder); + searchMultiModelElementsReducer(builder); getModelElementsReducer(builder); }, }); +export const { setModelElementSearch, setMultipleModelElementSearch, clearSearchModelElements } = + modelElements.actions; + export default modelElements.reducer; diff --git a/src/redux/modelElements/modelElements.thunks.test.ts b/src/redux/modelElements/modelElements.thunks.test.ts index cb0c5c52b057ca7f95c6e09e1e3c7685778bfd1f..7fdf47a95bf60a555059241ff2765af5145660c6 100644 --- a/src/redux/modelElements/modelElements.thunks.test.ts +++ b/src/redux/modelElements/modelElements.thunks.test.ts @@ -8,9 +8,16 @@ import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; import { HttpStatusCode } from 'axios'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import modelElementsReducer from '@/redux/modelElements/modelElements.slice'; -import { getModelElementsForModel } from '@/redux/modelElements/modelElements.thunks'; +import { + getModelElementsForModel, + searchModelElement, + searchMultiModelElements, +} from '@/redux/modelElements/modelElements.thunks'; import { modelElementsFixture } from '@/models/fixtures/modelElementsFixture'; +import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture'; +import { unwrapResult } from '@reduxjs/toolkit'; +const SEARCH_QUERY = 'park7'; const mockedAxiosClient = mockNetworkNewAPIResponse(); describe('model elements thunks', () => { @@ -38,4 +45,112 @@ describe('model elements thunks', () => { expect(payload).toEqual(undefined); }); }); + + describe('searchMultiModelElements', () => { + it('should return transformed bioEntityContent array', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, bioEntityResponseFixture); + + const data = await store + .dispatch( + searchMultiModelElements({ + searchQueries: [SEARCH_QUERY], + isPerfectMatch: false, + }), + ) + .unwrap(); + + expect(data).toEqual(bioEntityResponseFixture.content); + }); + + it('should combine all returned bioEntityContent arrays and return array with all provided bioEntityContent elements', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, bioEntityResponseFixture); + + const data = await store + .dispatch( + searchMultiModelElements({ + searchQueries: [SEARCH_QUERY, SEARCH_QUERY], + isPerfectMatch: false, + }), + ) + .unwrap(); + + expect(data).toEqual([ + ...bioEntityResponseFixture.content, + ...bioEntityResponseFixture.content, + ]); + }); + }); + + describe('searchModelElement', () => { + it('should return data when data response from API is valid', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, bioEntityResponseFixture); + + const { payload } = await store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + expect(payload).toEqual(bioEntityResponseFixture.content); + }); + it('should return undefined when data response from API is not valid ', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.Ok, { randomProperty: 'randomValue' }); + + const { payload } = await store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + expect(payload).toEqual(undefined); + }); + it('should handle error message when getBioEntityContents failed', async () => { + mockedAxiosClient + .onGet( + apiPath.getBioEntityContentsStringWithQuery({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ) + .reply(HttpStatusCode.NotFound, null); + + const action = await store.dispatch( + searchModelElement({ + searchQuery: SEARCH_QUERY, + isPerfectMatch: false, + }), + ); + expect(() => unwrapResult(action)).toThrow( + "Failed to search model element: The page you're looking for doesn't exist. Please verify the URL and try again.", + ); + }); + }); }); diff --git a/src/redux/modelElements/modelElements.thunks.ts b/src/redux/modelElements/modelElements.thunks.ts index 68f2419e35f2033c0f271c96805d96f1037f451e..90eb0c9c8bd9f67a8823803ad07b2cc076fe9445 100644 --- a/src/redux/modelElements/modelElements.thunks.ts +++ b/src/redux/modelElements/modelElements.thunks.ts @@ -4,10 +4,21 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import { ThunkConfig } from '@/types/store'; import { getError } from '@/utils/error-report/getError'; import { axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; -import { ModelElement, ModelElements } from '@/types/models'; -import { MODEL_ELEMENTS_FETCHING_ERROR_PREFIX } from '@/redux/modelElements/modelElements.constants'; +import { BioEntityContent, BioEntityResponse, ModelElement, ModelElements } from '@/types/models'; +import { + MODEL_ELEMENT_SEARCH_ERROR_PREFIX, + MODEL_ELEMENTS_FETCHING_ERROR_PREFIX, + MULTI_MODEL_ELEMENTS_SEARCH_ERROR_PREFIX, +} from '@/redux/modelElements/modelElements.constants'; import { modelElementSchema } from '@/models/modelElementSchema'; import { pageableSchema } from '@/models/pageableSchema'; +import { addNumbersToEntityNumberData } from '@/redux/entityNumber/entityNumber.slice'; +import { + SearchModelElementProps, + SearchMultiModelElementsActions, + SearchMultiModelElementsProps, +} from '@/redux/modelElements/modelElements.types'; +import { bioEntityResponseSchema } from '@/models/bioEntityResponseSchema'; export const getModelElementsForModel = createAsyncThunk< Array<ModelElement> | undefined, @@ -24,3 +35,63 @@ export const getModelElementsForModel = createAsyncThunk< return Promise.reject(getError({ error, prefix: MODEL_ELEMENTS_FETCHING_ERROR_PREFIX })); } }); + +export const searchModelElement = createAsyncThunk< + BioEntityContent[] | undefined, + SearchModelElementProps, + ThunkConfig +>( + 'modelElements/searchModelElement', + async ({ searchQuery, isPerfectMatch, addNumbersToEntityNumber = true }, { dispatch }) => { + try { + const { data } = await axiosInstanceNewAPI.get<BioEntityResponse>( + apiPath.getBioEntityContentsStringWithQuery({ searchQuery, isPerfectMatch }), + ); + + const isDataValid = validateDataUsingZodSchema(data, bioEntityResponseSchema); + const { content } = data; + if (addNumbersToEntityNumber && content) { + const modelElementsIds = content.map(b => b.bioEntity.elementId); + dispatch(addNumbersToEntityNumberData(modelElementsIds)); + } + + return isDataValid ? content : undefined; + } catch (error) { + return Promise.reject(getError({ error, prefix: MODEL_ELEMENT_SEARCH_ERROR_PREFIX })); + } + }, +); + +export const searchMultiModelElements = createAsyncThunk< + BioEntityContent[], + SearchMultiModelElementsProps, + ThunkConfig +>( + 'modelElements/searchMultiModelElements', + async ({ searchQueries, isPerfectMatch }, { dispatch }) => { + try { + const asyncGetBioEntityFunctions = searchQueries.map(searchQuery => + dispatch( + searchModelElement({ searchQuery, isPerfectMatch, addNumbersToEntityNumber: false }), + ), + ); + + const multiModelElementsActions = (await Promise.all( + asyncGetBioEntityFunctions, + )) as SearchMultiModelElementsActions; + + const multiModelElements = multiModelElementsActions + .map(multiModelElementsAction => multiModelElementsAction?.payload || []) + .flat() + .filter((payload): payload is BioEntityContent => typeof payload !== 'string') + .filter(payload => 'bioEntity' in payload || {}); + + const modelElementsIds = multiModelElements.map(b => b.bioEntity.elementId); + dispatch(addNumbersToEntityNumberData(modelElementsIds)); + + return multiModelElements; + } catch (error) { + return Promise.reject(getError({ error, prefix: MULTI_MODEL_ELEMENTS_SEARCH_ERROR_PREFIX })); + } + }, +); diff --git a/src/redux/modelElements/modelElements.types.ts b/src/redux/modelElements/modelElements.types.ts index b2d4ee6861e60602de84d7b45a021a36d11b93d5..c240d572e914d1661bfa1d568f3d585339a333d7 100644 --- a/src/redux/modelElements/modelElements.types.ts +++ b/src/redux/modelElements/modelElements.types.ts @@ -1,4 +1,22 @@ -import { KeyedFetchDataState } from '@/types/fetchDataState'; -import { ModelElement } from '@/types/models'; +import { KeyedFetchDataState, MultiFetchDataState } from '@/types/fetchDataState'; +import { BioEntityContent, ModelElement } from '@/types/models'; +import { PerfectMultiSearchParams, PerfectSearchParams } from '@/types/search'; +import { PayloadAction } from '@reduxjs/toolkit'; -export type ModelElementsState = KeyedFetchDataState<Array<ModelElement>>; +export type SearchModelElementDataState = { + perfect: boolean; + modelElement: ModelElement; +}; + +export type ModelElementsState = { + data: KeyedFetchDataState<ModelElement[]>; + search: MultiFetchDataState<SearchModelElementDataState[]>; +}; + +export type SearchMultiModelElementsProps = PerfectMultiSearchParams; + +export type SearchMultiModelElementsActions = PayloadAction< + BioEntityContent[] | undefined | string +>[]; + +export type SearchModelElementProps = PerfectSearchParams; diff --git a/src/redux/newReactions/newReactions.selectors.ts b/src/redux/newReactions/newReactions.selectors.ts index b8ba305fae603e3cf75f6a6d4f4f530736ae83e6..a0ef6652d2f01a0f17a215fb70676c76daced78d 100644 --- a/src/redux/newReactions/newReactions.selectors.ts +++ b/src/redux/newReactions/newReactions.selectors.ts @@ -1,7 +1,8 @@ import { createSelector } from '@reduxjs/toolkit'; import { currentModelIdSelector } from '@/redux/models/models.selectors'; import { currentDrawerReactionIdSelector } from '@/redux/drawer/drawer.selectors'; -import { NewReaction } from '@/types/models'; +import { Comment, NewReaction } from '@/types/models'; +import { allCommentsSelectorOfCurrentMap } from '@/redux/comment/comment.selectors'; import { rootSelector } from '../root/root.selectors'; export const newReactionsSelector = createSelector(rootSelector, state => state.newReactions); @@ -34,3 +35,19 @@ export const currentDrawerNewReactionSelector = createSelector( return newReactions.find(newReaction => newReaction.id === currentDrawerReactionId); }, ); + +export const currentDrawerReactionCommentsSelector = createSelector( + currentDrawerNewReactionSelector, + allCommentsSelectorOfCurrentMap, + (reaction, comments): Comment[] => { + if (reaction) { + return comments.filter( + comment => + comment.type === 'REACTION' && + comment.modelId === reaction.model && + Number(comment.elementId) === reaction.id, + ); + } + return []; + }, +); diff --git a/src/redux/reactions/isReactionBioentity.ts b/src/redux/reactions/isReactionBioentity.ts deleted file mode 100644 index e4e673a2411855bd9b9355ba5b09017299575d88..0000000000000000000000000000000000000000 --- a/src/redux/reactions/isReactionBioentity.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { BioEntity } from '@/types/models'; - -export const isReactionBioEntity = (bioEntity: BioEntity): boolean => { - return bioEntity.idReaction !== undefined && bioEntity.idReaction !== null; -}; diff --git a/src/redux/reactions/isReactionElement.ts b/src/redux/reactions/isReactionElement.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9a3d781899e7f6750a6f00aa5d1efc673d915fb --- /dev/null +++ b/src/redux/reactions/isReactionElement.ts @@ -0,0 +1,5 @@ +import { PublicationElement } from '@/types/models'; + +export const isReactionElement = (element: PublicationElement): boolean => { + return element.idReaction !== undefined && element.idReaction !== null; +}; diff --git a/src/redux/search/search.thunks.ts b/src/redux/search/search.thunks.ts index b95730d28ef1660c6dca265e31f746822d7f4948..ddbfc4af081cf31554e63567e6f5dd0e6d6fe77a 100644 --- a/src/redux/search/search.thunks.ts +++ b/src/redux/search/search.thunks.ts @@ -1,10 +1,10 @@ -import { getMultiBioEntity } from '@/redux/bioEntity/bioEntity.thunks'; import { getMultiChemicals } from '@/redux/chemicals/chemicals.thunks'; import { getMultiDrugs } from '@/redux/drugs/drugs.thunks'; import { PerfectMultiSearchParams } from '@/types/search'; import { ThunkConfig } from '@/types/store'; import { createAsyncThunk } from '@reduxjs/toolkit'; import { getError } from '@/utils/error-report/getError'; +import { searchMultiModelElements } from '@/redux/modelElements/modelElements.thunks'; import { resetReactionsData } from '../reactions/reactions.slice'; import type { RootState } from '../store'; import { DATA_SEARCHING_ERROR_PREFIX } from './search.constants'; @@ -30,13 +30,13 @@ export const getSearchData = createAsyncThunk< } if (containsDisease) { await Promise.all([ - dispatch(getMultiBioEntity({ searchQueries, isPerfectMatch })), + dispatch(searchMultiModelElements({ searchQueries, isPerfectMatch })), dispatch(getMultiDrugs(searchQueries)), dispatch(getMultiChemicals(searchQueries)), ]); } else { await Promise.all([ - dispatch(getMultiBioEntity({ searchQueries, isPerfectMatch })), + dispatch(searchMultiModelElements({ searchQueries, isPerfectMatch })), dispatch(getMultiDrugs(searchQueries)), ]); } diff --git a/src/redux/search/search.thunks.utils.ts b/src/redux/search/search.thunks.utils.ts index 0744617c819c6b4a18db01dc8062a80085e0ae01..43e7504a4eccf1abb096dc7d07ed1e2a5cae2e8a 100644 --- a/src/redux/search/search.thunks.utils.ts +++ b/src/redux/search/search.thunks.utils.ts @@ -2,8 +2,17 @@ import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; import type { RootState } from '../store'; export const dispatchPluginsEvents = (searchQueries: string[], state: RootState): void => { - const bioEntities = state.bioEntity.data; - const bioEntitiesResults = bioEntities.map(bioEntity => (bioEntity.data ? bioEntity.data : [])); + const searchModelElements = state.modelElements.search.data; + const modelElementsResults = searchModelElements + .map(searchElement => (searchElement.data ? searchElement.data : [])) + .map(data => { + return data.map(result => { + return { + perfect: result.perfect, + bioEntity: result.modelElement, + }; + }); + }); const drugs = state.drugs.data; const drugsResults = drugs.map(drug => (drug.data ? drug.data : [])); @@ -14,7 +23,7 @@ export const dispatchPluginsEvents = (searchQueries: string[], state: RootState) PluginsEventBus.dispatchEvent('onSearch', { type: 'bioEntity', searchValues: searchQueries, - results: bioEntitiesResults, + results: modelElementsResults, }); PluginsEventBus.dispatchEvent('onSearch', { type: 'drugs', diff --git a/src/services/pluginsManager/bioEntities/clearAllElements.ts b/src/services/pluginsManager/bioEntities/clearAllElements.ts index ce8a4ee72e3f6d781d7dca40cffadffa729c51fc..f8dfe461c7ae11abafe48dd838f6b76d0da8444b 100644 --- a/src/services/pluginsManager/bioEntities/clearAllElements.ts +++ b/src/services/pluginsManager/bioEntities/clearAllElements.ts @@ -1,8 +1,8 @@ -import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice'; import { clearChemicalsData } from '@/redux/chemicals/chemicals.slice'; import { clearDrugsData } from '@/redux/drugs/drugs.slice'; import { setMarkersData } from '@/redux/markers/markers.slice'; import { store } from '@/redux/store'; +import { clearSearchModelElements } from '@/redux/modelElements/modelElements.slice'; type ElementName = 'drugs' | 'chemicals' | 'content' | 'marker'; @@ -10,7 +10,7 @@ export const clearAllElements = (elements: ElementName[]): void => { const { dispatch } = store; if (elements.includes('content')) { - dispatch(clearBioEntities()); + dispatch(clearSearchModelElements()); } if (elements.includes('chemicals')) { diff --git a/src/services/pluginsManager/bioEntities/getAllContent.ts b/src/services/pluginsManager/bioEntities/getAllContent.ts index af8f6d119499c61aea0ecaaa3c2c3bdd38d28c3d..ba999eca1896bd42972a917fca6c8f9dab5bca22 100644 --- a/src/services/pluginsManager/bioEntities/getAllContent.ts +++ b/src/services/pluginsManager/bioEntities/getAllContent.ts @@ -1,10 +1,10 @@ -import { bioEntityDataListSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { store } from '@/redux/store'; -import { BioEntityContent } from '@/types/models'; +import { searchModelElementsListSelector } from '@/redux/modelElements/modelElements.selector'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; -export const getAllBioEntities = (): BioEntityContent[] => { +export const getAllBioEntities = (): SearchModelElementDataState[] => { const { getState } = store; - const bioEntities = bioEntityDataListSelector(getState()); + const bioEntities = searchModelElementsListSelector(getState()); return bioEntities || []; }; diff --git a/src/services/pluginsManager/bioEntities/getShownElements.ts b/src/services/pluginsManager/bioEntities/getShownElements.ts index 89cf67bdd2ad961dc7bd660bc5e5046cacd3ece4..be9de04ad6dbbe4000eec3a28185648e66a1b1ed 100644 --- a/src/services/pluginsManager/bioEntities/getShownElements.ts +++ b/src/services/pluginsManager/bioEntities/getShownElements.ts @@ -1,16 +1,16 @@ -import { searchedBioEntitesSelectorOfCurrentMap } from '@/redux/bioEntity/bioEntity.selectors'; -import { searchedChemicalsBioEntitesOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors'; -import { searchedDrugsBioEntitesOfCurrentMapSelector } from '@/redux/drugs/drugs.selectors'; +import { searchedChemicalsElementsOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors'; +import { searchedDrugsElementsOfCurrentMapSelector } from '@/redux/drugs/drugs.selectors'; import { markersPinsOfCurrentMapDataSelector } from '@/redux/markers/markers.selectors'; import { store } from '@/redux/store'; +import { searchedModelElementsForCurrentModelSelector } from '@/redux/modelElements/modelElements.selector'; import { GetShownElementsPluginMethodResult } from './getShownElements.types'; export const getShownElements = (): GetShownElementsPluginMethodResult => { const { getState } = store; - const content = searchedBioEntitesSelectorOfCurrentMap(getState()); - const chemicals = searchedChemicalsBioEntitesOfCurrentMapSelector(getState()); - const drugs = searchedDrugsBioEntitesOfCurrentMapSelector(getState()); + const content = searchedModelElementsForCurrentModelSelector(getState()); + const chemicals = searchedChemicalsElementsOfCurrentMapSelector(getState()); + const drugs = searchedDrugsElementsOfCurrentMapSelector(getState()); const markers = markersPinsOfCurrentMapDataSelector(getState()); return { diff --git a/src/services/pluginsManager/bioEntities/getShownElements.types.ts b/src/services/pluginsManager/bioEntities/getShownElements.types.ts index 210a0e0194f54a7f0f1ecb6e49f17f01502c00a2..d0e71af064cdf80f1dc952aa024b31fe569ce37b 100644 --- a/src/services/pluginsManager/bioEntities/getShownElements.types.ts +++ b/src/services/pluginsManager/bioEntities/getShownElements.types.ts @@ -1,8 +1,8 @@ -import { BioEntity, Marker } from '@/types/models'; +import { ModelElement, Marker } from '@/types/models'; export interface GetShownElementsPluginMethodResult { - content: BioEntity[]; - drugs: BioEntity[]; - chemicals: BioEntity[]; + content: ModelElement[]; + drugs: ModelElement[]; + chemicals: ModelElement[]; markers: Marker[]; } diff --git a/src/services/pluginsManager/map/triggerSearch/getVisibleBioEntitiesPolygonCoordinates.test.ts b/src/services/pluginsManager/map/triggerSearch/getVisibleBioEntitiesPolygonCoordinates.test.ts index 35661b14ce73d5d232d649d773c72fdfe7acc45a..fd3f701882759c3c1550aaf56b04237836e8cc23 100644 --- a/src/services/pluginsManager/map/triggerSearch/getVisibleBioEntitiesPolygonCoordinates.test.ts +++ b/src/services/pluginsManager/map/triggerSearch/getVisibleBioEntitiesPolygonCoordinates.test.ts @@ -1,11 +1,14 @@ /* eslint-disable no-magic-numbers */ import { MAP_INITIAL_STATE } from '@/redux/map/map.constants'; import { RootState, store } from '@/redux/store'; -import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { DRAWER_INITIAL_STATE } from '@/redux/drawer/drawer.constants'; import { MODELS_DATA_MOCK_WITH_MAIN_MAP } from '@/redux/models/models.mock'; import { HISTAMINE_MAP_ID } from '@/constants/mocks'; +import { modelElementFixture } from '@/models/fixtures/modelElementFixture'; +import { DEFAULT_ERROR } from '@/constants/errors'; +import { MODEL_ELEMENTS_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; +import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { getVisibleBioEntitiesPolygonCoordinates } from './getVisibleBioEntitiesPolygonCoordinates'; jest.mock('../../../../redux/store'); @@ -35,10 +38,7 @@ describe('getVisibleBioEntitiesPolygonCoordinates', () => { }, }, }, - bioEntity: { - loading: 'succeeded', - error: { message: '', name: '' }, - }, + modelElements: MODEL_ELEMENTS_INITIAL_STATE_MOCK, drugs: { loading: 'succeeded', error: { message: '', name: '' }, @@ -65,7 +65,7 @@ describe('getVisibleBioEntitiesPolygonCoordinates', () => { ...MAP_INITIAL_STATE, data: { ...MAP_INITIAL_STATE.data, - modelId: 52, + modelId: 0, size: { width: 256, height: 256, @@ -75,39 +75,36 @@ describe('getVisibleBioEntitiesPolygonCoordinates', () => { }, }, }, - bioEntity: { - data: [ - { - searchQueryElement: bioEntityContentFixture.bioEntity.name, + modelElements: { + data: { + 0: { + data: [modelElementFixture], loading: 'succeeded', - error: { name: '', message: '' }, - data: [ - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - model: 52, - x: 97, - y: 53, - z: 1, + error: { message: '', name: '' }, + }, + }, + search: { + data: [ + { + searchQueryElement: modelElementFixture.id.toString(), + loading: 'succeeded', + error: DEFAULT_ERROR, + data: [ + { + modelElement: { ...modelElementFixture, model: 0, x: 97, y: 53, z: 1 }, + perfect: true, }, - }, - { - ...bioEntityContentFixture, - bioEntity: { - ...bioEntityContentFixture.bioEntity, - model: 52, - x: 12, - y: 25, - z: 1, + { + modelElement: { ...modelElementFixture, model: 0, x: 12, y: 25, z: 1 }, + perfect: true, }, - }, - ], - }, - ], - loading: 'succeeded', - error: { message: '', name: '' }, - }, + ], + }, + ], + loading: 'succeeded', + error: DEFAULT_ERROR, + }, + } as ModelElementsState, drugs: { data: [ { @@ -141,7 +138,7 @@ describe('getVisibleBioEntitiesPolygonCoordinates', () => { }, searchDrawerState: { ...DRAWER_INITIAL_STATE.searchDrawerState, - selectedSearchElement: bioEntityContentFixture.bioEntity.name, + selectedSearchElement: modelElementFixture.id.toString(), }, }, }) as RootState, diff --git a/src/services/pluginsManager/map/triggerSearch/searchByCoordinates.ts b/src/services/pluginsManager/map/triggerSearch/searchByCoordinates.ts index 4a1bcd16b2bea4b700b212551ba164d0857d5c25..a813ecf9206f5451481b743b9bc468438a621881 100644 --- a/src/services/pluginsManager/map/triggerSearch/searchByCoordinates.ts +++ b/src/services/pluginsManager/map/triggerSearch/searchByCoordinates.ts @@ -13,7 +13,7 @@ import { modelElementsByModelIdSelector } from '@/redux/modelElements/modelEleme import { newReactionsByModelIdSelector } from '@/redux/newReactions/newReactions.selectors'; import { closeDrawer } from '@/redux/drawer/drawer.slice'; import { resetReactionsData } from '@/redux/reactions/reactions.slice'; -import { clearBioEntities } from '@/redux/bioEntity/bioEntity.slice'; +import { clearSearchModelElements } from '@/redux/modelElements/modelElements.slice'; import { Coordinates } from './triggerSearch.types'; export const searchByCoordinates = async ( @@ -45,7 +45,7 @@ export const searchByCoordinates = async ( } dispatch(resetReactionsData()); - dispatch(clearBioEntities()); + dispatch(clearSearchModelElements()); return; } diff --git a/src/services/pluginsManager/map/triggerSearch/searchByQuery.test.ts b/src/services/pluginsManager/map/triggerSearch/searchByQuery.test.ts index 45c0e9dfdd8892ba3d44e2eb2391cdc1ff16fecd..b8e0c9fb99e64bdcfc65ae538a90f35acef812d7 100644 --- a/src/services/pluginsManager/map/triggerSearch/searchByQuery.test.ts +++ b/src/services/pluginsManager/map/triggerSearch/searchByQuery.test.ts @@ -30,10 +30,6 @@ const MOCK_SEARCH_BY_QUERY_STORE = { }, }, }, - bioEntity: { - loading: 'succeeded', - error: { message: '', name: '' }, - }, drugs: { loading: 'succeeded', error: { message: '', name: '' }, diff --git a/src/services/pluginsManager/map/triggerSearch/triggerSearch.test.ts b/src/services/pluginsManager/map/triggerSearch/triggerSearch.test.ts index 0b3e97df409d58f3f7145bd49959d7939993e4f1..9b591d8d9cb0602ed12811b25a8a7dfcf8e992c7 100644 --- a/src/services/pluginsManager/map/triggerSearch/triggerSearch.test.ts +++ b/src/services/pluginsManager/map/triggerSearch/triggerSearch.test.ts @@ -18,6 +18,7 @@ import { MapManager } from '@/services/pluginsManager/map/mapManager'; import { ModelElementsState } from '@/redux/modelElements/modelElements.types'; import { NewReactionsState } from '@/redux/newReactions/newReactions.types'; import { LAYER_TYPE } from '@/components/Map/MapViewer/MapViewer.constants'; +import { MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK } from '@/redux/modelElements/modelElements.mock'; import { ERROR_INVALID_MODEL_ID_TYPE } from '../../errorMessages'; import { triggerSearch } from './triggerSearch'; @@ -37,11 +38,14 @@ const MOCK_STATE = { openedMaps: openedMapsThreeSubmapsFixture, }, modelElements: { - 0: { - data: [], - loading: 'succeeded', - error: { message: '', name: '' }, + data: { + 0: { + data: [], + loading: 'succeeded', + error: { message: '', name: '' }, + }, }, + search: MODEL_ELEMENTS_SEARCH_INITIAL_STATE_MOCK, } as ModelElementsState, newReactions: { 0: { diff --git a/src/services/pluginsManager/pluginContextMenu/pluginsContextMenu.types.ts b/src/services/pluginsManager/pluginContextMenu/pluginsContextMenu.types.ts index 0ea6b81167c6eb565b6097aac0fef7c49008edc0..0c8231adbc33e439e5631440f6e21d868cf5fc20 100644 --- a/src/services/pluginsManager/pluginContextMenu/pluginsContextMenu.types.ts +++ b/src/services/pluginsManager/pluginContextMenu/pluginsContextMenu.types.ts @@ -1,4 +1,4 @@ -import { BioEntity, NewReaction } from '@/types/models'; +import { ModelElement, NewReaction } from '@/types/models'; export type ClickCoordinates = { modelId: number; @@ -13,7 +13,10 @@ export type PluginContextMenuItemType = { name: string; style: string; enabled: boolean; - callback: (coordinates: ClickCoordinates, element: BioEntity | NewReaction | undefined) => void; + callback: ( + coordinates: ClickCoordinates, + element: ModelElement | NewReaction | undefined, + ) => void; }; export type PluginsContextMenuType = { @@ -23,7 +26,10 @@ export type PluginsContextMenuType = { name: string, style: string, enabled: boolean, - callback: (coordinates: ClickCoordinates, element: BioEntity | NewReaction | undefined) => void, + callback: ( + coordinates: ClickCoordinates, + element: ModelElement | NewReaction | undefined, + ) => void, ) => string; removeMenu: (hash: string, id: string) => void; updateMenu: (hash: string, id: string, name: string, style: string, enabled: boolean) => void; diff --git a/src/services/pluginsManager/pluginsEventBus/pluginsEventBus.types.ts b/src/services/pluginsManager/pluginsEventBus/pluginsEventBus.types.ts index 935487c6838b64dcb4c8c2f6d6b4ccb3461000ba..c9e8f4fc962a4e42d0f1b462a009dee9eeeb8fa4 100644 --- a/src/services/pluginsManager/pluginsEventBus/pluginsEventBus.types.ts +++ b/src/services/pluginsManager/pluginsEventBus/pluginsEventBus.types.ts @@ -1,11 +1,12 @@ import { - BioEntityContent, Chemical, CreatedOverlay, Drug, ElementSearchResult, MapOverlay, + ModelElement, } from '@/types/models'; +import { SearchModelElementDataState } from '@/redux/modelElements/modelElements.types'; import { dispatchEvent } from './pluginsEventBus'; export type BackgroundEvents = 'onBackgroundOverlayChange'; @@ -56,13 +57,18 @@ export type ClickedSurfaceOverlay = { export type SearchDataReaction = { type: 'reaction'; searchValues: string[] | ElementSearchResult[]; - results: BioEntityContent[][]; + results: SearchModelElementDataState[][]; }; -export type SearchDataBioEntity = { +type SearchDataModelElementResults = { + perfect: boolean; + bioEntity: ModelElement; +}; + +export type SearchDataModelElement = { type: 'bioEntity'; searchValues: string[] | ElementSearchResult[]; - results: BioEntityContent[][]; + results: SearchDataModelElementResults[][]; }; export type SearchDataDrugs = { @@ -82,7 +88,7 @@ export type PluginUnloaded = { }; export type SearchData = - | SearchDataBioEntity + | SearchDataModelElement | SearchDataDrugs | SearchDataChemicals | SearchDataReaction; diff --git a/src/types/bioEntity.ts b/src/types/bioEntity.ts deleted file mode 100644 index 1d7984699daa6b6beddc0e655b10f537119f4eb0..0000000000000000000000000000000000000000 --- a/src/types/bioEntity.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BioEntity } from './models'; -import { PinType } from './pin'; - -export interface BioEntityWithPinType extends BioEntity { - type: PinType; -} - -export type MultiPinBioEntity = BioEntityWithPinType[]; diff --git a/src/types/modelElement.ts b/src/types/modelElement.ts new file mode 100644 index 0000000000000000000000000000000000000000..faa3d49b66f94ebc755fb4261bd34959eb74f3ba --- /dev/null +++ b/src/types/modelElement.ts @@ -0,0 +1,8 @@ +import { ModelElement } from './models'; +import { PinType } from './pin'; + +export interface ModelElementWithPinType extends ModelElement { + type: PinType; +} + +export type MultiPinModelElement = ModelElementWithPinType[]; diff --git a/src/types/models.ts b/src/types/models.ts index 756f345a748fd49fb34ce1bf0328d4e5910409d1..5abac9948af8d7c979c30fc9a2c651799fccb101 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -1,6 +1,5 @@ import { bioEntityContentSchema } from '@/models/bioEntityContentSchema'; import { bioEntityResponseSchema } from '@/models/bioEntityResponseSchema'; -import { bioEntitySchema } from '@/models/bioEntitySchema'; import { chemicalSchema } from '@/models/chemicalSchema'; import { colorSchema } from '@/models/colorSchema'; import { configurationOptionSchema } from '@/models/configurationOptionSchema'; @@ -70,6 +69,7 @@ import { modificationResiduesSchema } from '@/models/modificationResiduesSchema' import { segmentSchema } from '@/models/segmentSchema'; import { layerImageSchema } from '@/models/layerImageSchema'; import { glyphSchema } from '@/models/glyphSchema'; +import { publicationElementSchema } from '@/models/publicationElementSchema'; export type Project = z.infer<typeof projectSchema>; export type OverviewImageView = z.infer<typeof overviewImageView>; @@ -103,7 +103,6 @@ export type Modification = z.infer<typeof modelElementModificationSchema>; export type MapOverlay = z.infer<typeof mapOverlay>; export type Drug = z.infer<typeof drugSchema>; export type PinDetailsItem = z.infer<typeof targetSchema>; -export type BioEntity = z.infer<typeof bioEntitySchema>; export type BioEntityContent = z.infer<typeof bioEntityContentSchema>; export type BioEntityResponse = z.infer<typeof bioEntityResponseSchema>; export type Chemical = z.infer<typeof chemicalSchema>; @@ -133,6 +132,7 @@ export type CreatedOverlay = z.infer<typeof createdOverlaySchema>; export type Color = z.infer<typeof colorSchema>; export type Statistics = z.infer<typeof statisticsSchema>; export type Publication = z.infer<typeof publicationSchema>; +export type PublicationElement = z.infer<typeof publicationElementSchema>; export type ExportNetwork = z.infer<typeof exportNetworkchema>; export type ExportElements = z.infer<typeof exportElementsSchema>; export type MinervaPlugin = z.infer<typeof pluginSchema>; // Plugin type interferes with global Plugin type diff --git a/src/types/pin.ts b/src/types/pin.ts index 7310215f63f09860d9f84880f2fbf024063adff0..8c0e92172748128bdcee2c91e1541b9ea703503d 100644 --- a/src/types/pin.ts +++ b/src/types/pin.ts @@ -1 +1 @@ -export type PinType = 'chemicals' | 'drugs' | 'bioEntity' | 'comment'; +export type PinType = 'chemicals' | 'drugs' | 'modelElement' | 'comment'; diff --git a/src/utils/bioEntity/mapModelElementToBioEntity.ts b/src/utils/bioEntity/mapModelElementToBioEntity.ts deleted file mode 100644 index e8be81f2163ebdecd5034fee53d807cbf9d2fab0..0000000000000000000000000000000000000000 --- a/src/utils/bioEntity/mapModelElementToBioEntity.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { BioEntity, ModelElement } from '@/types/models'; - -export function mapModelElementToBioEntity(modelElement: ModelElement): BioEntity { - return { - id: modelElement.id, - name: modelElement.name, - model: modelElement.model, - elementId: modelElement.elementId, - references: modelElement.references, - z: modelElement.z, - notes: modelElement.notes, - symbol: modelElement.symbol, - homodimer: modelElement.homodimer, - nameX: modelElement.nameX, - nameY: modelElement.nameY, - nameWidth: modelElement.nameWidth, - nameHeight: modelElement.nameHeight, - nameVerticalAlign: modelElement.nameVerticalAlign, - nameHorizontalAlign: modelElement.nameHorizontalAlign, - width: modelElement.width, - height: modelElement.height, - visibilityLevel: modelElement.visibilityLevel, - transparencyLevel: modelElement.transparencyLevel, - synonyms: modelElement.synonyms, - formerSymbols: modelElement.formerSymbols, - fullName: modelElement.fullName, - abbreviation: modelElement.abbreviation, - formula: modelElement.formula, - glyph: modelElement.glyph, - activity: modelElement.activity, - hypothetical: modelElement.hypothetical, - boundaryCondition: modelElement.boundaryCondition, - constant: modelElement.constant, - initialAmount: modelElement.initialAmount, - initialConcentration: modelElement.initialConcentration, - charge: modelElement.charge, - substanceUnits: modelElement.substanceUnits, - onlySubstanceUnits: modelElement.onlySubstanceUnits, - modificationResidues: modelElement.modificationResidues, - complex: modelElement.complex, - submodel: modelElement.submodel, - x: modelElement.x, - y: modelElement.y, - lineWidth: modelElement.lineWidth, - fontColor: modelElement.fontColor, - fontSize: modelElement.fontSize, - fillColor: modelElement.fillColor, - borderColor: modelElement.borderColor, - sboTerm: modelElement.sboTerm, - } as BioEntity; -} diff --git a/src/utils/bioEntity/mapReactionToBioEntity.ts b/src/utils/bioEntity/mapReactionToModelElement.ts similarity index 72% rename from src/utils/bioEntity/mapReactionToBioEntity.ts rename to src/utils/bioEntity/mapReactionToModelElement.ts index 0aab81b7588933094cc21149a60c3a688db15e3e..2f2f2dc572aa6ce43f71b9e1ac58f95af9903bdc 100644 --- a/src/utils/bioEntity/mapReactionToBioEntity.ts +++ b/src/utils/bioEntity/mapReactionToModelElement.ts @@ -1,6 +1,6 @@ -import { BioEntity, NewReaction } from '@/types/models'; +import { ModelElement, NewReaction } from '@/types/models'; -export function mapReactionToBioEntity(reaction: NewReaction): BioEntity { +export function mapReactionToModelElement(reaction: NewReaction): ModelElement { return { id: reaction.id, name: reaction.name, @@ -15,5 +15,5 @@ export function mapReactionToBioEntity(reaction: NewReaction): BioEntity { abbreviation: reaction.abbreviation, formula: reaction.formula, sboTerm: reaction.sboTerm, - } as BioEntity; + } as ModelElement; }