diff --git a/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx b/src/components/Map/Drawer/BioEntityDrawer/AssociatedSubmap/AssociatedSubmap.component.tsx index 43047b388dd26229181fe95e102154fac6c12c71..c14fbdd9a32d7b94b30633de79fcc71c688d7fb4 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 { searchedFromMapBioEntityElementRelatedSubmapSelector } from '@/redux/bioEntity/bioEntity.selectors'; +import { currentDrawerBioEntityRelatedSubmapSelector } from '@/redux/bioEntity/bioEntity.selectors'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { Button } from '@/shared/Button'; export const AssociatedSubmap = (): React.ReactNode => { - const relatedSubmap = useAppSelector(searchedFromMapBioEntityElementRelatedSubmapSelector); + const relatedSubmap = useAppSelector(currentDrawerBioEntityRelatedSubmapSelector); const { openSubmap } = useOpenSubmap({ modelId: relatedSubmap?.idObject, modelName: relatedSubmap?.name, 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 6447864167fa0759a12d4ca0c95ca98671a0291b..2c62fa09c0e73a4074af78ff745fb7a745018f1d 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 @@ -277,6 +277,15 @@ describe('BioEntitiesPinsListItem - component ', () => { }), ]), ); + + expect(actions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + payload: undefined, + type: 'project/getSubmapConnectionsBioEntity/pending', + }), + ]), + ); }); it('should reset reactions on fullName click', async () => { diff --git a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerHeader/PerfectMatchSwitch/PerfectMatchSwitch.component.test.tsx b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerHeader/PerfectMatchSwitch/PerfectMatchSwitch.component.test.tsx index c08187dc9d36cbc6197a92f9dc4ea29711aadbca..36a6ed7275a80972dd576480cef990bfaf0bf0cb 100644 --- a/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerHeader/PerfectMatchSwitch/PerfectMatchSwitch.component.test.tsx +++ b/src/components/Map/Drawer/SearchDrawerWrapper/SearchDrawerHeader/PerfectMatchSwitch/PerfectMatchSwitch.component.test.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-magic-numbers */ import { FIRST_ARRAY_ELEMENT, SECOND_ARRAY_ELEMENT, THIRD_ARRAY_ELEMENT } from '@/constants/common'; import { SEARCH_STATE_INITIAL_MOCK } from '@/redux/search/search.mock'; import { AppDispatch, RootState, StoreType } from '@/redux/store'; diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts index 4e11dc14663c8ae279cfdf3b1e2eef12fd0c46f5..c6ae99fb8406a32056296741c76bd766043e493c 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getBioEntitiesFeatures.ts @@ -16,7 +16,7 @@ export const getBioEntitiesFeatures = ( pointToProjection: UsePointToProjectionResult; type: PinType; entityNumber: EntityNumber; - activeIds: (string | number)[]; + activeIds?: (string | number)[]; }, ): Feature[] => { return bioEntites.map(bioEntity => @@ -25,7 +25,7 @@ export const getBioEntitiesFeatures = ( type, // pin's index number value: entityNumber?.[bioEntity.elementId], - isActive: activeIds.includes(bioEntity.id), + isActive: activeIds ? activeIds.includes(bioEntity.id) : true, }), ); }; diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts index dc96896b5dcfc8147f732096d12dba202fe5a3ce..30a9e0e1db0c483e6b74f291262a29e58eedb8e9 100644 --- a/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts +++ b/src/components/Map/MapViewer/utils/config/pinsLayer/useOlMapPinsLayer.ts @@ -1,6 +1,7 @@ /* eslint-disable no-magic-numbers */ import { allBioEntitesSelectorOfCurrentMap, + allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector, allVisibleBioEntitiesIdsSelector, } from '@/redux/bioEntity/bioEntity.selectors'; import { allChemicalsBioEntitesOfCurrentMapSelector } from '@/redux/chemicals/chemicals.selectors'; @@ -25,6 +26,9 @@ export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>> const drugsBioEntities = useSelector(allDrugsBioEntitesOfCurrentMapSelector); const markersEntities = useSelector(markersPinsOfCurrentMapDataSelector); const entityNumber = useSelector(entityNumberDataSelector); + const submapConnections = useSelector( + allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector, + ); const elementsFeatures = useMemo( () => @@ -47,6 +51,11 @@ export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>> entityNumber, activeIds, }), + getBioEntitiesFeatures(submapConnections, { + pointToProjection, + type: 'bioEntity', + entityNumber, + }), getMarkersFeatures(markersEntities, { pointToProjection }), ].flat(), [ @@ -57,6 +66,7 @@ export const useOlMapPinsLayer = (): VectorLayer<VectorSource<Feature<Geometry>> markersEntities, entityNumber, activeIds, + submapConnections, ], ); diff --git a/src/models/submapConnection.ts b/src/models/submapConnection.ts new file mode 100644 index 0000000000000000000000000000000000000000..609cbadb2395994f04cb041c63f8a166a9497311 --- /dev/null +++ b/src/models/submapConnection.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; +import { targetElementSchema } from './targetElementSchema'; + +export const submapConnection = z.object({ + from: targetElementSchema, + to: z.object({ modelId: z.number() }), +}); diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 19aac51cbd7e5a42dad6e5cb907a10053e14b038..4522d03465930649fe4865d3a61049c6f56e4707 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -91,4 +91,5 @@ export const apiPath = { registerPluign: (): string => `plugins/`, getPlugin: (pluginId: string): string => `plugins/${pluginId}/`, getAllPlugins: (): string => `/plugins/`, + getSubmapConnections: (): string => `projects/${PROJECT_ID}/submapConnections/`, }; diff --git a/src/redux/bioEntity/bioEntity.constants.ts b/src/redux/bioEntity/bioEntity.constants.ts index b719afdedbecef74f12b3712ae166430ab7d20f1..14f1bdc1ad572a72495c24393fb65f0c2276f94c 100644 --- a/src/redux/bioEntity/bioEntity.constants.ts +++ b/src/redux/bioEntity/bioEntity.constants.ts @@ -1,6 +1,23 @@ +import { FetchDataState } from '@/types/fetchDataState'; +import { BioEntityContent } 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<BioEntityContent[]> = { + data: [], + loading: 'idle', + error: { name: '', message: '' }, +}; + +export const BIOENTITY_INITIAL_STATE: BioEntityContentsState = { + data: [], + loading: 'idle', + error: { name: '', message: '' }, + submapConnections: BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, +}; diff --git a/src/redux/bioEntity/bioEntity.mock.ts b/src/redux/bioEntity/bioEntity.mock.ts index 7c86d068bf8c00d2e376c66af8aa1a3739f2ae3a..dbc164d28b70e92c40e6192050db8029e044defc 100644 --- a/src/redux/bioEntity/bioEntity.mock.ts +++ b/src/redux/bioEntity/bioEntity.mock.ts @@ -1,13 +1,18 @@ import { DEFAULT_ERROR } from '@/constants/errors'; -import { BioEntity, BioEntityContent } from '@/types/models'; import { bioEntityContentFixture } from '@/models/fixtures/bioEntityContentsFixture'; import { MultiSearchData } from '@/types/fetchDataState'; +import { BioEntity, BioEntityContent } from '@/types/models'; 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, + }, }; export const BIO_ENTITY_LINKING_TO_SUBMAP: BioEntity = { diff --git a/src/redux/bioEntity/bioEntity.reducers.test.ts b/src/redux/bioEntity/bioEntity.reducers.test.ts index 78482731a21eb2acf4c47279fc272f8a236dec44..d48998d83951e3289f1da610ff3f62915a5c3281 100644 --- a/src/redux/bioEntity/bioEntity.reducers.test.ts +++ b/src/redux/bioEntity/bioEntity.reducers.test.ts @@ -1,14 +1,14 @@ -import { bioEntityResponseFixture } from '@/models/fixtures/bioEntityContentsFixture'; -import { mockNetworkNewAPIResponse } from '@/utils/mockNetworkResponse'; 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 { HttpStatusCode } from 'axios'; -import { apiPath } from '@/redux/apiPath'; -import { getBioEntity } from './bioEntity.thunks'; import bioEntityContentsReducer from './bioEntity.slice'; +import { getBioEntity } from './bioEntity.thunks'; import { BioEntityContentsState } from './bioEntity.types'; const mockedAxiosClient = mockNetworkNewAPIResponse(); @@ -18,6 +18,11 @@ const INITIAL_STATE: BioEntityContentsState = { data: [], loading: 'idle', error: { name: '', message: '' }, + submapConnections: { + data: [], + loading: 'idle', + error: { name: '', message: '' }, + }, }; describe('bioEntity reducer', () => { diff --git a/src/redux/bioEntity/bioEntity.reducers.ts b/src/redux/bioEntity/bioEntity.reducers.ts index 7eb3b66c996baf7ea37060e06ce501b4b53558d6..fb6f1d36efc67b164f595a37de24a026984ec283 100644 --- a/src/redux/bioEntity/bioEntity.reducers.ts +++ b/src/redux/bioEntity/bioEntity.reducers.ts @@ -1,7 +1,9 @@ import { DEFAULT_ERROR } from '@/constants/errors'; import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; +import { BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE } from './bioEntity.constants'; import { getBioEntity, getMultiBioEntity } from './bioEntity.thunks'; import { BioEntityContentsState } from './bioEntity.types'; +import { getSubmapConnectionsBioEntity } from './thunks/getSubmapConnectionsBioEntity'; export const getBioEntityContentsReducer = ( builder: ActionReducerMapBuilder<BioEntityContentsState>, @@ -50,7 +52,37 @@ export const getMultiBioEntityContentsReducer = ( }); }; +export const getSubmapConnectionsBioEntityReducer = ( + builder: ActionReducerMapBuilder<BioEntityContentsState>, +): void => { + builder.addCase(getSubmapConnectionsBioEntity.pending, state => { + state.submapConnections = { + ...BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, + ...(state?.submapConnections ? state?.submapConnections : {}), + data: [], + loading: 'pending', + }; + }); + builder.addCase(getSubmapConnectionsBioEntity.fulfilled, (state, action) => { + state.submapConnections = { + ...BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, + ...(state?.submapConnections ? state?.submapConnections : {}), + data: action.payload, + loading: 'succeeded', + }; + }); + builder.addCase(getSubmapConnectionsBioEntity.rejected, state => { + state.submapConnections = { + ...BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE, + ...(state?.submapConnections ? state?.submapConnections : {}), + loading: 'failed', + }; + }); +}; + export const clearBioEntitiesDataReducer = (state: BioEntityContentsState): void => { state.data = []; state.loading = 'idle'; + + state.submapConnections = BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE; }; diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts index 337737dcf5954ca6334911cff64e681d082a6b0c..25479877fe57e2a9a3a7cdbd7ee80fc545759a49 100644 --- a/src/redux/bioEntity/bioEntity.selectors.ts +++ b/src/redux/bioEntity/bioEntity.selectors.ts @@ -1,4 +1,4 @@ -import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common'; +import { ONE, SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; import { ElementIdTabObj } from '@/types/elements'; import { MultiSearchData } from '@/types/fetchDataState'; @@ -7,6 +7,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { allChemicalsBioEntitesOfAllMapsSelector, allChemicalsIdTabSelectorOfCurrentMap, + chemicalsBioEntitiesForSelectedSearchElementSelector, searchedChemicalsBioEntitesOfCurrentMapSelector, } from '../chemicals/chemicals.selectors'; import { currentSelectedBioEntityIdSelector } from '../contextMenu/contextMenu.selector'; @@ -17,6 +18,7 @@ import { import { allDrugsBioEntitesOfAllMapsSelector, allDrugsIdTabSelectorOfCurrentMap, + drugsBioEntitiesForSelectedSearchElementSelector, searchedDrugsBioEntitesOfCurrentMapSelector, } from '../drugs/drugs.selectors'; import { currentModelIdSelector, modelsDataSelector } from '../models/models.selectors'; @@ -34,6 +36,19 @@ export const bioEntityDataListSelector = createSelector(bioEntityDataSelector, b bioEntityData.map(b => b.data || []).flat(), ); +export const allSubmapConnectionsBioEntitySelector = createSelector( + bioEntitySelector, + (bioEntityData): BioEntity[] => + (bioEntityData?.submapConnections?.data || []).map(({ bioEntity }) => bioEntity), +); + +export const allSubmapConnectionsBioEntityOfCurrentSubmapSelector = createSelector( + allSubmapConnectionsBioEntitySelector, + currentModelIdSelector, + (submapConnectionsBioEntity, currentModel): BioEntity[] => + submapConnectionsBioEntity.filter(({ model }) => model === currentModel), +); + export const bioEntitiesForSelectedSearchElement = createSelector( bioEntitySelector, currentSelectedSearchElement, @@ -175,6 +190,30 @@ export const allVisibleBioEntitiesSelector = createSelector( }, ); +export const allElementsForSearchElementSelector = createSelector( + bioEntitiesForSelectedSearchElement, + chemicalsBioEntitiesForSelectedSearchElementSelector, + drugsBioEntitiesForSelectedSearchElementSelector, + (content, chemicals, drugs): BioEntity[] => { + const contentBioEntities = (content?.data || []).map(({ bioEntity }) => bioEntity); + + return [contentBioEntities, chemicals || [], drugs || []].flat(); + }, +); + +export const allElementsForSearchElementNumberByModelId = createSelector( + allElementsForSearchElementSelector, + (elements): Record<number, number> => { + return elements.reduce( + (acc, { model }) => ({ + ...acc, + [model]: (acc?.[model] || ZERO) + ONE, + }), + {} as Record<number, number>, + ); + }, +); + export const allVisibleBioEntitiesIdsSelector = createSelector( allVisibleBioEntitiesSelector, (elements): (string | number)[] => { @@ -200,8 +239,9 @@ export const allBioEntitiesSelector = createSelector( allContentBioEntitesSelectorOfAllMaps, allChemicalsBioEntitesOfAllMapsSelector, allDrugsBioEntitesOfAllMapsSelector, - (content, chemicals, drugs): BioEntity[] => { - return [content, chemicals, drugs].flat(); + allSubmapConnectionsBioEntitySelector, + (content, chemicals, drugs, submapConnections): BioEntity[] => { + return [content, chemicals, drugs, submapConnections].flat(); }, ); @@ -231,3 +271,14 @@ export const currentDrawerBioEntityRelatedSubmapSelector = createSelector( (bioEntity, models): MapModel | undefined => models.find(({ idObject }) => idObject === bioEntity?.submodel?.mapId), ); + +export const allSubmapConnectionsBioEntityOfCurrentSubmapWithRealConnectionsSelector = + createSelector( + allSubmapConnectionsBioEntityOfCurrentSubmapSelector, + allElementsForSearchElementNumberByModelId, + (submapConnectionsBioEntity, modelElementsNumber): BioEntity[] => { + return submapConnectionsBioEntity.filter( + ({ submodel }) => submodel && modelElementsNumber?.[submodel.mapId] > ZERO, + ); + }, + ); diff --git a/src/redux/bioEntity/bioEntity.slice.ts b/src/redux/bioEntity/bioEntity.slice.ts index 428e00ce2025d4881622332cf6cb2adb82909b88..55d1c4ae344fa00d627447482ef60ba0dee58b1a 100644 --- a/src/redux/bioEntity/bioEntity.slice.ts +++ b/src/redux/bioEntity/bioEntity.slice.ts @@ -1,26 +1,22 @@ -import { BioEntityContentsState } from '@/redux/bioEntity/bioEntity.types'; import { createSlice } from '@reduxjs/toolkit'; +import { BIOENTITY_INITIAL_STATE } from './bioEntity.constants'; import { clearBioEntitiesDataReducer, getBioEntityContentsReducer, getMultiBioEntityContentsReducer, + getSubmapConnectionsBioEntityReducer, } from './bioEntity.reducers'; -const initialState: BioEntityContentsState = { - data: [], - loading: 'idle', - error: { name: '', message: '' }, -}; - export const bioEntityContentsSlice = createSlice({ name: 'bioEntityContents', - initialState, + initialState: BIOENTITY_INITIAL_STATE, reducers: { clearBioEntitiesData: clearBioEntitiesDataReducer, }, extraReducers: builder => { getBioEntityContentsReducer(builder); getMultiBioEntityContentsReducer(builder); + getSubmapConnectionsBioEntityReducer(builder); }, }); diff --git a/src/redux/bioEntity/bioEntity.types.ts b/src/redux/bioEntity/bioEntity.types.ts index ed504183480e1990309fb51e9c9f90d5fa89b1b1..65e8d8aa8997240924ed10d851058d45126b6a98 100644 --- a/src/redux/bioEntity/bioEntity.types.ts +++ b/src/redux/bioEntity/bioEntity.types.ts @@ -1,11 +1,10 @@ -import { MultiFetchDataState } from '@/types/fetchDataState'; +import { FetchDataState, MultiFetchDataState } from '@/types/fetchDataState'; import { BioEntityContent } from '@/types/models'; import { PayloadAction } from '@reduxjs/toolkit'; -export type BioEntityContentsState = MultiFetchDataState<BioEntityContent[]>; - -// Previous Change from Mateusz B. PR, leaving it here for case of solving merge conflicts -// export type BioEntityContentsState = FetchDataState<BioEntityContent[]>; +export type BioEntityContentsState = MultiFetchDataState<BioEntityContent[]> & { + submapConnections?: FetchDataState<BioEntityContent[]>; +}; export type BioEntityContentSearchQuery = { query: string | string[]; diff --git a/src/redux/bioEntity/thunks/getSubmapConnectionsBioEntity.ts b/src/redux/bioEntity/thunks/getSubmapConnectionsBioEntity.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfda62b8ed94d82ddb73c8991053aac611b5f725 --- /dev/null +++ b/src/redux/bioEntity/thunks/getSubmapConnectionsBioEntity.ts @@ -0,0 +1,50 @@ +import { bioEntityContentSchema } from '@/models/bioEntityContentSchema'; +import { submapConnection } from '@/models/submapConnection'; +import { apiPath } from '@/redux/apiPath'; +import { axiosInstance, axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; +import { BioEntityContent, BioEntityResponse, SubmapConnection } from '@/types/models'; +import { getErrorMessage } from '@/utils/getErrorMessage'; +import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { z } from 'zod'; +import { MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX } from '../bioEntity.constants'; + +export const getSubmapConnectionsBioEntity = createAsyncThunk<BioEntityContent[]>( + 'project/getSubmapConnectionsBioEntity', + // eslint-disable-next-line consistent-return + async (_, { rejectWithValue }) => { + try { + const response = await axiosInstance.get<SubmapConnection[]>(apiPath.getSubmapConnections()); + + const isDataValid = validateDataUsingZodSchema(response.data, z.array(submapConnection)); + if (!isDataValid) { + throw new Error('Submap connections validation error'); + } + + const searchQueries = response.data.map(({ from }) => `${from.id}`); + + const asyncFetchBioEntityFunctions = searchQueries.map(searchQuery => + axiosInstanceNewAPI.get<BioEntityResponse>( + apiPath.getBioEntityContentsStringWithQuery({ searchQuery, isPerfectMatch: true }), + ), + ); + + const bioEntityContentResponse = await Promise.all(asyncFetchBioEntityFunctions); + + const bioEntityContents = bioEntityContentResponse + .map(contentResponse => contentResponse?.data?.content || []) + .flat() + .filter(content => bioEntityContentSchema.safeParse(content).success) + .filter(payload => 'bioEntity' in payload || {}); + + return bioEntityContents; + } catch (error) { + const errorMessage = getErrorMessage({ + error, + prefix: MULTI_BIO_ENTITY_FETCHING_ERROR_PREFIX, + }); + + return rejectWithValue(errorMessage); + } + }, +); diff --git a/src/redux/chemicals/chemicals.selectors.ts b/src/redux/chemicals/chemicals.selectors.ts index d8394dc480cb1fe0658208af6150714356fe2c09..7f11e09a16adb38b957f2b516be5afcdda901fde 100644 --- a/src/redux/chemicals/chemicals.selectors.ts +++ b/src/redux/chemicals/chemicals.selectors.ts @@ -24,11 +24,10 @@ export const chemicalsForSelectedSearchElementSelector = createSelector( ), ); -export const searchedChemicalsBioEntitesOfCurrentMapSelector = createSelector( +export const chemicalsBioEntitiesForSelectedSearchElementSelector = createSelector( chemicalsSelector, currentSelectedSearchElement, - currentModelIdSelector, - (chemicalsState, currentSearchElement, currentModelId): BioEntity[] => { + (chemicalsState, currentSearchElement): BioEntity[] => { return (chemicalsState?.data || []) .filter(({ searchQueryElement }) => currentSearchElement ? searchQueryElement === currentSearchElement : true, @@ -37,8 +36,15 @@ export const searchedChemicalsBioEntitesOfCurrentMapSelector = createSelector( .flat() .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) .flat() - .flat() - .filter(bioEntity => bioEntity.model === currentModelId); + .flat(); + }, +); + +export const searchedChemicalsBioEntitesOfCurrentMapSelector = createSelector( + chemicalsBioEntitiesForSelectedSearchElementSelector, + currentModelIdSelector, + (chemicalsBioEntities, currentModelId): BioEntity[] => { + return (chemicalsBioEntities || []).filter(bioEntity => bioEntity.model === currentModelId); }, ); diff --git a/src/redux/drugs/drugs.selectors.ts b/src/redux/drugs/drugs.selectors.ts index df2b10ae0234c8f0cacc3d67ef80f75c2ee806e0..ecaf082afd32d1c1a5e0724bc28250d71e9f39eb 100644 --- a/src/redux/drugs/drugs.selectors.ts +++ b/src/redux/drugs/drugs.selectors.ts @@ -38,11 +38,10 @@ export const numberOfDrugsSelector = createSelector( }, ); -export const searchedDrugsBioEntitesOfCurrentMapSelector = createSelector( +export const drugsBioEntitiesForSelectedSearchElementSelector = createSelector( drugsSelector, currentSelectedSearchElement, - currentModelIdSelector, - (drugsState, currentSearchElement, currentModelId): BioEntity[] => { + (drugsState, currentSearchElement): BioEntity[] => { return (drugsState?.data || []) .filter(({ searchQueryElement }) => currentSearchElement ? searchQueryElement === currentSearchElement : true, @@ -51,8 +50,15 @@ export const searchedDrugsBioEntitesOfCurrentMapSelector = createSelector( .flat() .map(({ targets }) => targets.map(({ targetElements }) => targetElements)) .flat() - .flat() - .filter(bioEntity => bioEntity.model === currentModelId); + .flat(); + }, +); + +export const searchedDrugsBioEntitesOfCurrentMapSelector = createSelector( + drugsBioEntitiesForSelectedSearchElementSelector, + currentModelIdSelector, + (drugsBioEntities, currentModelId): BioEntity[] => { + return (drugsBioEntities || []).filter(bioEntity => bioEntity.model === currentModelId); }, ); diff --git a/src/redux/search/search.thunks.ts b/src/redux/search/search.thunks.ts index eaa9b6c811b6e2b79b27be9348b550cb25aa8fc4..cd89b30faf6737c159a67e2c406ad8fbeb44cbe9 100644 --- a/src/redux/search/search.thunks.ts +++ b/src/redux/search/search.thunks.ts @@ -9,6 +9,7 @@ import { resetReactionsData } from '../reactions/reactions.slice'; import type { RootState } from '../store'; import { DATA_SEARCHING_ERROR_PREFIX } from './search.constants'; import { dispatchPluginsEvents } from './search.thunks.utils'; +import { getSubmapConnectionsBioEntity } from '../bioEntity/thunks/getSubmapConnectionsBioEntity'; type GetSearchDataProps = PerfectMultiSearchParams; @@ -27,6 +28,7 @@ export const getSearchData = createAsyncThunk< dispatch(getMultiBioEntity({ searchQueries, isPerfectMatch })), dispatch(getMultiDrugs(searchQueries)), dispatch(getMultiChemicals(searchQueries)), + dispatch(getSubmapConnectionsBioEntity()), ]); dispatchPluginsEvents(searchQueries, getState()); diff --git a/src/types/models.ts b/src/types/models.ts index 65ea2cf6af5a796f33b25cacb9f9adf8fcf42af3..39fada22f2a548136555a69f8e10d10a130f28b4 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -47,6 +47,7 @@ import { reactionLineSchema } from '@/models/reactionLineSchema'; import { referenceSchema } from '@/models/referenceSchema'; import { sessionSchemaValid } from '@/models/sessionValidSchema'; import { statisticsSchema } from '@/models/statisticsSchema'; +import { submapConnection } from '@/models/submapConnection'; import { targetElementSchema } from '@/models/targetElementSchema'; import { targetSchema } from '@/models/targetSchema'; import { targetSearchNameResult } from '@/models/targetSearchNameResult'; @@ -100,3 +101,4 @@ export type MinervaPlugin = z.infer<typeof pluginSchema>; // Plugin type interfe export type GeneVariant = z.infer<typeof geneVariant>; export type TargetSearchNameResult = z.infer<typeof targetSearchNameResult>; export type TargetElement = z.infer<typeof targetElementSchema>; +export type SubmapConnection = z.infer<typeof submapConnection>;