Skip to content
Snippets Groups Projects
Commit c6467620 authored by Adrian Orłów's avatar Adrian Orłów
Browse files

feat: upgrade fetch reactions from bioentities side effect

parent a5c9560b
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!156feat: publications modal elements links + reaction search (MIN-241, MIN-229)
Pipeline #87863 failed
......@@ -2,8 +2,8 @@ import { Reaction } from '@/types/models';
export const getBioEntitiesIdsFromReaction = (reaction: Reaction): string[] => {
const { products, reactants, modifiers } = reaction;
const productsIds = products.map(p => p.aliasId);
const reactantsIds = reactants.map(r => r.aliasId);
const modifiersIds = modifiers.map(m => m.aliasId);
const productsIds = products.map(p => ('aliasId' in p ? p.aliasId : p.element));
const reactantsIds = reactants.map(r => ('aliasId' in r ? r.aliasId : r.element));
const modifiersIds = modifiers.map(m => ('aliasId' in m ? m.aliasId : m.element));
return [...productsIds, ...reactantsIds, ...modifiersIds].map(identifier => String(identifier));
};
import { ZERO } from '@/constants/common';
import { z } from 'zod';
import { colorSchema } from './colorSchema';
import { glyphSchema } from './glyphSchema';
......@@ -20,23 +21,29 @@ export const bioEntitySchema = z.object({
notes: z.string(),
symbol: z.string().nullable(),
homodimer: z.number().optional(),
nameX: z.number(),
nameY: z.number(),
nameWidth: z.number(),
nameHeight: z.number(),
nameVerticalAlign: z.string(),
nameHorizontalAlign: z.string(),
width: z.number(),
height: z.number(),
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(),
width: z
.number()
.optional()
.transform(width => width ?? ZERO),
height: z
.number()
.optional()
.transform(height => height ?? ZERO),
visibilityLevel: z.string(),
transparencyLevel: z.string(),
transparencyLevel: z.string().nullable().optional(),
synonyms: z.array(z.string()),
formerSymbols: z.array(z.string()),
fullName: z.string().nullable(),
formerSymbols: z.array(z.string()).nullable().optional(),
fullName: z.string().nullable().nullable().optional(),
compartmentName: z.string().nullable().optional(),
abbreviation: z.string().nullable(),
formula: z.string().nullable(),
glyph: glyphSchema.nullable(),
glyph: glyphSchema.nullable().optional(),
activity: z.boolean().optional(),
structuralState: z.optional(structuralStateSchema.nullable()),
hypothetical: z.boolean().nullable().optional(),
......@@ -49,15 +56,21 @@ export const bioEntitySchema = z.object({
onlySubstanceUnits: z.boolean().optional(),
modificationResidues: z.optional(z.array(modificationResiduesSchema)),
complex: z.number().nullable().optional(),
compartment: z.number().nullable(),
submodel: submodelSchema.nullable(),
x: z.number(),
y: z.number(),
compartment: z.number().nullable().optional(),
submodel: submodelSchema.nullable().optional(),
x: z
.number()
.optional()
.transform(x => x ?? ZERO),
y: z
.number()
.optional()
.transform(y => y ?? ZERO),
lineWidth: z.number().optional(),
fontColor: colorSchema,
fontSize: z.number(),
fillColor: colorSchema,
borderColor: colorSchema,
fontColor: colorSchema.nullable().optional(),
fontSize: z.number().nullable().optional(),
fillColor: colorSchema.nullable().optional(),
borderColor: colorSchema.nullable().optional(),
smiles: z.optional(z.string()).nullable(),
inChI: z.optional(z.string().nullable()),
inChIKey: z.optional(z.string().nullable()),
......@@ -66,11 +79,11 @@ export const bioEntitySchema = z.object({
innerWidth: z.optional(z.number()),
idReaction: z.optional(z.string()),
reversible: z.optional(z.boolean()),
mechanicalConfidenceScore: z.optional(z.boolean()),
lowerBound: z.optional(z.boolean()),
upperBound: z.optional(z.boolean()),
subsystem: z.optional(z.string()),
geneProteinReaction: z.optional(z.string()),
mechanicalConfidenceScore: z.optional(z.boolean()).nullable().optional(),
lowerBound: z.optional(z.boolean()).nullable().optional(),
upperBound: z.optional(z.boolean()).nullable().optional(),
subsystem: z.optional(z.string()).nullable().optional(),
geneProteinReaction: z.optional(z.string()).nullable().optional(),
kinetics: z.optional(z.null()),
products: z.optional(z.array(productsSchema)),
reactants: z.optional(z.array(productsSchema)),
......
......@@ -5,7 +5,7 @@ export const operatorSchema = z.object({
id: z.number(),
line: lineSchema,
inputs: z.array(z.object({ id: z.number() })),
outputs: z.undefined(),
outputs: z.any().optional(),
operatorText: z.string(),
reactantOperator: z.boolean(),
productOperator: z.boolean(),
......
import { z } from 'zod';
export const productsSchema = z.object({
aliasId: z.number(),
stoichiometry: z.number().nullable(),
type: z.optional(z.string()),
});
export const productsSchema = z.union([
z.object({
aliasId: z.number(),
stoichiometry: z.number().nullable(),
type: z.optional(z.string()),
}),
z.object({
element: z.number(),
stoichiometry: z.number().nullable(),
type: z.optional(z.string()),
}),
]);
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';
......@@ -18,7 +20,7 @@ export const getMultiBioEntity = createAsyncThunk<
>(
'project/getMultiBioEntity',
// eslint-disable-next-line consistent-return
async ({ searchQueries, isPerfectMatch }, { dispatch, rejectWithValue }) => {
async ({ searchQueries, isPerfectMatch }, { dispatch, rejectWithValue, getState }) => {
try {
const asyncGetBioEntityFunctions = searchQueries.map(searchQuery =>
dispatch(getBioEntity({ searchQuery, isPerfectMatch, addNumbersToEntityNumber: false })),
......@@ -39,9 +41,12 @@ export const getMultiBioEntity = createAsyncThunk<
const bioEntitiesIds = await fetchReactionsAndGetBioEntitiesIds({
bioEntityContents,
dispatch,
dispatch: dispatch as AppDispatch,
getState: getState as typeof store.getState,
});
getMultiBioEntity({ searchQueries: bioEntitiesIds, isPerfectMatch: true });
if (bioEntitiesIds.length > ZERO) {
await dispatch(getMultiBioEntity({ searchQueries: bioEntitiesIds, isPerfectMatch: true }));
}
return bioEntityContents;
} catch (error) {
......
import { getBioEntitiesIdsFromReaction } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/getBioEntitiesIdsFromReaction';
import { SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common';
import { selectTab } from '@/redux/drawer/drawer.slice';
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 } from '@/redux/store';
import type { BioEntityContent } from '@/types/models';
import type { AppDispatch, store } from '@/redux/store';
import type { BioEntityContent, Reaction } from '@/types/models';
interface Args {
bioEntityContents: BioEntityContent[];
dispatch: AppDispatch;
getState: typeof store.getState;
}
export const fetchReactionsAndGetBioEntitiesIds = async ({
dispatch,
bioEntityContents,
}: Args): Promise<string[]> => {
const bioEntityReactionsIds = (bioEntityContents || [])
const getReactionsIdsFromBioEntities = (bioEntites: BioEntityContent[]): number[] => {
return bioEntites
.filter(c => c?.bioEntity?.idReaction)
.map(c => c?.bioEntity?.id)
.filter((id): id is number => typeof id === 'number');
};
if (bioEntityReactionsIds.length === ZERO) {
return [];
}
const fetchReactions = async (
reactionsIds: number[],
dispatch: AppDispatch,
): Promise<Reaction[]> => {
const result = await dispatch(
getReactionsByIds({
ids: bioEntityReactionsIds,
ids: reactionsIds,
shouldConcat: true,
}),
);
// if has error (toast show should be handled by getReactionsByIds)
if (typeof result.payload === 'string') {
return [];
}
const reactions = result.payload?.data;
if (!reactions || reactions.length === SIZE_OF_EMPTY_ARRAY) {
if (!reactions) {
return [];
}
const bioEntitiesIds = reactions.map(reaction => getBioEntitiesIdsFromReaction(reaction)).flat();
// dispatch(openReactionDrawerById(reactions[FIRST_ARRAY_ELEMENT].id));
return reactions;
};
const handleReactionShowInfoAndOpenMap = async (
{ dispatch, getState }: Args,
firstReaction: Reaction,
): Promise<void> => {
const modelsNames = modelsNameMapSelector(getState());
dispatch(openReactionDrawerById(firstReaction.id));
dispatch(selectTab(''));
dispatch(
openMapAndOrSetActiveIfSelected({
modelId: firstReaction.modelId,
modelName: modelsNames[firstReaction.modelId],
}),
);
};
export const fetchReactionsAndGetBioEntitiesIds = async (args: Args): Promise<string[]> => {
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 => getBioEntitiesIdsFromReaction(reaction)).flat();
const firstReaction = reactions[FIRST_ARRAY_ELEMENT];
if (firstReaction) {
handleReactionShowInfoAndOpenMap(args, firstReaction);
}
return bioEntitiesIds;
};
import { DEFAULT_ZOOM } from '@/constants/map';
import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
import { ActionReducerMapBuilder } from '@reduxjs/toolkit';
import { getPointMerged } from '../../utils/object/getPointMerged';
import {
initMapBackground,
......@@ -90,6 +90,34 @@ export const openMapAndSetActiveReducer = (
state.data.modelId = action.payload.modelId;
};
export const openMapAndOrSetActiveIfSelectedReducer = (
state: MapState,
action: OpenMapAndSetActiveAction,
): void => {
const { modelId, modelName } = action.payload;
const { openedMaps, data } = state;
const isMapAlreadyOpened = openedMaps.some(map => map.modelId === modelId);
const currentMapModelId = data.modelId;
if (currentMapModelId !== modelId) {
PluginsEventBus.dispatchEvent('onSubmapClose', currentMapModelId);
PluginsEventBus.dispatchEvent('onSubmapOpen', modelId);
}
if (isMapAlreadyOpened) {
setActiveMapReducer(state, { payload: { modelId }, type: 'map/setActiveMapReducer' });
return;
}
openMapAndSetActiveReducer(state, {
payload: {
modelId,
modelName,
},
type: 'map/openMapAndSetActiveReducer',
});
};
export const closeMapReducer = (state: MapState, action: CloseMapAction): void => {
state.openedMaps = state.openedMaps.filter(
openedMap => openedMap.modelId !== action.payload.modelId,
......
......@@ -7,6 +7,7 @@ import {
initMapPositionReducers,
initMapSizeAndModelIdReducer,
initOpenedMapsReducer,
openMapAndOrSetActiveIfSelectedReducer,
openMapAndSetActiveReducer,
setActiveMapReducer,
setMapBackgroundReducer,
......@@ -27,6 +28,7 @@ const mapSlice = createSlice({
setMapPosition: setMapPositionReducer,
varyPositionZoom: varyPositionZoomReducer,
setMapBackground: setMapBackgroundReducer,
openMapAndOrSetActiveIfSelected: openMapAndOrSetActiveIfSelectedReducer,
},
extraReducers: builder => {
initMapPositionReducers(builder);
......@@ -45,6 +47,7 @@ export const {
setMapPosition,
setMapBackground,
varyPositionZoom,
openMapAndOrSetActiveIfSelected,
} = mapSlice.actions;
export default mapSlice.reducer;
......@@ -5,6 +5,7 @@ import { Action, createListenerMiddleware, isAnyOf } from '@reduxjs/toolkit';
import { mapOpenedMapPositionByIdSelector } from '../map.selectors';
import {
closeMapAndSetMainMapActive,
openMapAndOrSetActiveIfSelected,
openMapAndSetActive,
setActiveMap,
setMapBackground,
......@@ -49,6 +50,7 @@ startListening({
openMapAndSetActive,
closeMapAndSetMainMapActive,
setMapBackground,
openMapAndOrSetActiveIfSelected,
),
effect: mapDataMiddlewareListener,
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment