Skip to content
Snippets Groups Projects
Commit 477cd7d9 authored by Miłosz Grocholewski's avatar Miłosz Grocholewski
Browse files

Merge branch 'feat/MIN-70-context-menu' into 'development'

feature(vector-map): implement context menu

Closes MIN-70

See merge request !304
parents 2b60848c cbdc5d73
No related branches found
No related tags found
1 merge request!304feature(vector-map): implement context menu
Pipeline #97894 failed
Showing
with 353 additions and 36 deletions
import { Color, ShapeRelAbs, ShapeRelAbsBezierPoint } from '@/types/models';
export const VECTOR_MAP_LAYER_TYPE = 'vectorMapLayer';
export const WHITE_COLOR: Color = {
alpha: 255,
rgb: 16777215,
......
/* eslint-disable no-magic-numbers */
import { leftClickHandleReaction } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/leftClickHandleReaction';
import { openReactionDrawerById, selectTab } from '@/redux/drawer/drawer.slice';
import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
import { searchFitBounds } from '@/services/pluginsManager/map/triggerSearch/searchFitBounds';
......@@ -10,12 +9,13 @@ import { apiPath } from '@/redux/apiPath';
import { HttpStatusCode } from 'axios';
import { bioEntityFixture } from '@/models/fixtures/bioEntityFixture';
import { FEATURE_TYPE } from '@/constants/features';
import { clickHandleReaction } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/clickHandleReaction';
const mockedAxiosClient = mockNetworkNewAPIResponse();
jest.mock('../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds');
const eventBusDispatchEventSpy = jest.spyOn(PluginsEventBus, 'dispatchEvent');
describe('leftClickHandleReaction', () => {
describe('clickHandleReaction', () => {
let dispatch: jest.Mock;
let modelId = 1;
let reactionId = 1;
......@@ -54,7 +54,7 @@ describe('leftClickHandleReaction', () => {
)
.reply(HttpStatusCode.Ok, bioEntityFixture);
});
await leftClickHandleReaction(dispatch, hasFitBounds)(feature, modelId);
await clickHandleReaction(dispatch, hasFitBounds)(feature, modelId);
expect(dispatch).toHaveBeenCalledTimes(4);
expect(dispatch).toHaveBeenCalledWith(openReactionDrawerById(reactionId));
expect(dispatch).toHaveBeenCalledWith(selectTab(''));
......@@ -68,7 +68,7 @@ describe('leftClickHandleReaction', () => {
unwrap: jest.fn().mockResolvedValue(mockBioEntities),
}));
await leftClickHandleReaction(dispatch, false)(feature, modelId);
await clickHandleReaction(dispatch, false)(feature, modelId);
expect(searchFitBounds).not.toHaveBeenCalled();
});
......
......@@ -15,7 +15,7 @@ import { getBioEntitiesIdsFromReaction } from '@/components/Map/MapViewer/utils/
import { FEATURE_TYPE } from '@/constants/features';
/* prettier-ignore */
export const leftClickHandleReaction =
export const clickHandleReaction =
(dispatch: AppDispatch, hasFitBounds = false) =>
async (feature: FeatureLike, modelId: number): Promise<void> => {
const id = feature.get('id');
......
/* eslint-disable no-magic-numbers */
import { leftClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/leftClickHandleAlias';
import { leftClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias';
import { openBioEntityDrawerById, selectTab } from '@/redux/drawer/drawer.slice';
import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus';
import { searchFitBounds } from '@/services/pluginsManager/map/triggerSearch/searchFitBounds';
import { Feature } from 'ol';
import { FEATURE_TYPE } from '@/constants/features';
jest.mock('../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds');
jest.mock('../../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds');
const eventBusDispatchEventSpy = jest.spyOn(PluginsEventBus, 'dispatchEvent');
describe('leftClickHandleAlias', () => {
......
......@@ -5,16 +5,16 @@ import { resetReactionsData } from '@/redux/reactions/reactions.slice';
import { clearBioEntitiesData } from '@/redux/bioEntity/bioEntity.slice';
import { handleFeaturesClick } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick';
import Map from 'ol/Map';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/onMapLeftClick';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick';
import { Comment } from '@/types/models';
import { Layer } from 'ol/layer';
import SimpleGeometry from 'ol/geom/SimpleGeometry';
import { Feature } from 'ol';
import { FEATURE_TYPE } from '@/constants/features';
import * as leftClickHandleAlias from './leftClickHandleAlias';
import * as leftClickHandleReaction from './leftClickHandleReaction';
import * as clickHandleReaction from '../clickHandleReaction';
jest.mock('../../../utils/listeners/mapSingleClick/handleFeaturesClick', () => ({
jest.mock('../../../../utils/listeners/mapSingleClick/handleFeaturesClick', () => ({
handleFeaturesClick: jest.fn(),
}));
jest.mock('./leftClickHandleAlias', () => ({
......@@ -22,11 +22,11 @@ jest.mock('./leftClickHandleAlias', () => ({
...jest.requireActual('./leftClickHandleAlias'),
}));
const leftClickHandleAliasSpy = jest.spyOn(leftClickHandleAlias, 'leftClickHandleAlias');
jest.mock('./leftClickHandleReaction', () => ({
jest.mock('../clickHandleReaction', () => ({
__esModule: true,
...jest.requireActual('./leftClickHandleReaction'),
...jest.requireActual('../clickHandleReaction'),
}));
const leftClickHandleReactionSpy = jest.spyOn(leftClickHandleReaction, 'leftClickHandleReaction');
const clickHandleReactionSpy = jest.spyOn(clickHandleReaction, 'clickHandleReaction');
describe('onMapLeftClick', () => {
const modelId = 1;
......@@ -89,7 +89,7 @@ describe('onMapLeftClick', () => {
expect(leftClickHandleAliasSpy).toHaveBeenCalledWith(dispatch);
});
it('calls leftClickHandleReaction if feature type is REACTION', async () => {
it('calls clickHandleReaction if feature type is REACTION', async () => {
const mockBioEntities = [{ id: 1, name: 'BioEntity 1' }];
const dispatch = jest.fn(() => ({
unwrap: jest.fn().mockResolvedValue(mockBioEntities),
......@@ -108,6 +108,6 @@ describe('onMapLeftClick', () => {
comments,
)(event, mapInstance);
expect(leftClickHandleReactionSpy).toHaveBeenCalledWith(dispatch);
expect(clickHandleReactionSpy).toHaveBeenCalledWith(dispatch);
});
});
......@@ -8,12 +8,12 @@ import { latLngToPoint } from '@/utils/map/latLngToPoint';
import { FeatureLike } from 'ol/Feature';
import { closeDrawer } from '@/redux/drawer/drawer.slice';
import { clearBioEntitiesData } from '@/redux/bioEntity/bioEntity.slice';
import { leftClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/leftClickHandleAlias';
import { leftClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/leftClickHandleAlias';
import { handleFeaturesClick } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick';
import { resetReactionsData } from '@/redux/reactions/reactions.slice';
import { leftClickHandleReaction } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/leftClickHandleReaction';
import { handleDataReset } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset';
import { FEATURE_TYPE } from '@/constants/features';
import { clickHandleReaction } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/clickHandleReaction';
/* prettier-ignore */
export const onMapLeftClick =
......@@ -25,7 +25,7 @@ export const onMapLeftClick =
dispatch(updateLastClick({ coordinates: point, modelId }));
let featureAtPixel: FeatureLike | undefined;
mapInstance.forEachFeatureAtPixel(pixel, (feature) => {
mapInstance.forEachFeatureAtPixel(pixel, (feature, ) => {
if(feature.get('id') && [...Object.values(FEATURE_TYPE)].includes(feature.get('type'))) {
featureAtPixel = feature;
return true;
......@@ -55,6 +55,6 @@ export const onMapLeftClick =
if(type === FEATURE_TYPE.ALIAS) {
await leftClickHandleAlias(dispatch)(featureAtPixel, modelId);
} else if (type === FEATURE_TYPE.REACTION) {
await leftClickHandleReaction(dispatch)(featureAtPixel, modelId);
await clickHandleReaction(dispatch)(featureAtPixel, modelId);
}
};
/* eslint-disable no-magic-numbers */
import { updateLastRightClick } from '@/redux/map/map.slice';
import Map from 'ol/Map';
import { onMapRightClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick';
import { Layer } from 'ol/layer';
import { openContextMenu } from '@/redux/contextMenu/contextMenu.slice';
import { Source } from 'ol/source';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import { Feature } from 'ol';
import { FEATURE_TYPE } from '@/constants/features';
import { modelElementsFixture } from '@/models/fixtures/modelElementsFixture';
import { VECTOR_MAP_LAYER_TYPE } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
import * as rightClickHandleAlias from './rightClickHandleAlias';
import * as clickHandleReaction from '../clickHandleReaction';
jest.mock('./rightClickHandleAlias', () => ({
__esModule: true,
...jest.requireActual('./rightClickHandleAlias'),
}));
const rightClickHandleAliasSpy = jest.spyOn(rightClickHandleAlias, 'rightClickHandleAlias');
jest.mock('../clickHandleReaction', () => ({
__esModule: true,
...jest.requireActual('../clickHandleReaction'),
}));
const clickHandleReactionSpy = jest.spyOn(clickHandleReaction, 'clickHandleReaction');
describe('onMapRightClick', () => {
const modelId = 1;
let mapInstance: Map;
const event = { coordinate: [100, 50], pixel: [200, 100] };
const mapSize = {
width: 90,
height: 90,
tileSize: 256,
minZoom: 2,
maxZoom: 9,
};
let vectorLayer: VectorLayer;
let vectorSource: VectorSource;
beforeEach(() => {
const dummyElement = document.createElement('div');
mapInstance = new Map({ target: dummyElement });
vectorSource = new VectorSource({});
vectorLayer = new VectorLayer({
source: vectorSource,
});
vectorLayer.set('type', VECTOR_MAP_LAYER_TYPE);
jest.clearAllMocks();
});
it('calls rightClickHandleAlias if feature type is ALIAS', async () => {
const dispatch = jest.fn();
const modelElement = modelElementsFixture.content[0];
jest.spyOn(mapInstance, 'getAllLayers').mockImplementation((): Layer<Source>[] => {
return [vectorLayer];
});
jest.spyOn(vectorLayer, 'isVisible').mockImplementation((): boolean => {
return true;
});
jest.spyOn(vectorLayer, 'getSource').mockImplementation((): VectorSource => {
return vectorSource;
});
jest.spyOn(vectorSource, 'getClosestFeatureToCoordinate').mockImplementation((): Feature => {
return new Feature({ id: modelElement.id, type: FEATURE_TYPE.ALIAS });
});
await onMapRightClick(mapSize, modelId, dispatch, [modelElement])(event, mapInstance);
expect(dispatch).toHaveBeenCalledWith(updateLastRightClick(expect.any(Object)));
expect(dispatch).toHaveBeenCalledWith(openContextMenu(event.pixel));
expect(rightClickHandleAliasSpy).toHaveBeenCalledWith(dispatch);
});
it('calls rightClickHandleAlias if feature type is REACTION', async () => {
const dispatch = jest.fn();
jest.spyOn(mapInstance, 'getAllLayers').mockImplementation((): Layer<Source>[] => {
return [vectorLayer];
});
jest.spyOn(vectorLayer, 'isVisible').mockImplementation((): boolean => {
return true;
});
jest.spyOn(vectorLayer, 'getSource').mockImplementation((): VectorSource => {
return vectorSource;
});
jest.spyOn(vectorSource, 'getClosestFeatureToCoordinate').mockImplementation((): Feature => {
return new Feature({ id: 1, type: FEATURE_TYPE.REACTION });
});
await onMapRightClick(mapSize, modelId, dispatch, [])(event, mapInstance);
expect(dispatch).toHaveBeenCalledWith(updateLastRightClick(expect.any(Object)));
expect(dispatch).toHaveBeenCalledWith(openContextMenu(event.pixel));
expect(clickHandleReactionSpy).toHaveBeenCalledWith(dispatch);
});
});
import { MapSize } from '@/redux/map/map.types';
import { AppDispatch } from '@/redux/store';
import { Feature, Map, MapBrowserEvent } from 'ol';
import { updateLastRightClick } from '@/redux/map/map.slice';
import { toLonLat } from 'ol/proj';
import { latLngToPoint } from '@/utils/map/latLngToPoint';
import { handleDataReset } from '@/components/Map/MapViewer/utils/listeners/mapSingleClick/handleDataReset';
import { FEATURE_TYPE } from '@/constants/features';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import { openContextMenu } from '@/redux/contextMenu/contextMenu.slice';
import { ModelElement } from '@/types/models';
import { rightClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/rightClickHandleAlias';
import { clickHandleReaction } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/clickHandleReaction';
import { VECTOR_MAP_LAYER_TYPE } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
/* prettier-ignore */
export const onMapRightClick =
(mapSize: MapSize, modelId: number, dispatch: AppDispatch, modelElements: Array<ModelElement>) =>
async ({ coordinate, pixel }: Pick<MapBrowserEvent<UIEvent>, 'coordinate' | 'pixel'>, mapInstance: Map): Promise<void> => {
const [lng, lat] = toLonLat(coordinate);
const point = latLngToPoint([lat, lng], mapSize);
dispatch(updateLastRightClick({ coordinates: point, modelId }));
let foundFeature: Feature | undefined;
mapInstance.getAllLayers().forEach(layer => {
if(layer.isVisible() && layer instanceof VectorLayer) {
if (layer.get('type') === VECTOR_MAP_LAYER_TYPE) {
const source = layer.getSource();
if (source instanceof VectorSource) {
foundFeature = source.getClosestFeatureToCoordinate(coordinate, (feature) => {
return [FEATURE_TYPE.ALIAS, FEATURE_TYPE.REACTION].includes(feature.get('type'));
});
}
}
}
});
if(!foundFeature) {
return;
}
dispatch(handleDataReset);
dispatch(openContextMenu(pixel));
const type = foundFeature.get('type');
const id = foundFeature.get('id');
if(type === FEATURE_TYPE.ALIAS) {
const modelElement = modelElements.find(element => element.id === id);
if(!modelElement) {
return;
}
await rightClickHandleAlias(dispatch)(id, modelElement);
} else if (type === FEATURE_TYPE.REACTION) {
await clickHandleReaction(dispatch)(foundFeature, modelId);
}
};
/* eslint-disable no-magic-numbers */
import { rightClickHandleAlias } from '@/components/Map/MapViewer/MapViewerVector/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';
jest.mock('../../../../../../../services/pluginsManager/map/triggerSearch/searchFitBounds');
describe('rightClickHandleAlias', () => {
let dispatch: jest.Mock;
beforeEach(() => {
jest.clearAllMocks();
dispatch = jest.fn();
});
it('dispatches setBioEntityContents, addNumbersToEntityNumberData and setCurrentSelectedBioEntityId', async () => {
await rightClickHandleAlias(dispatch)(modelElementFixture.id, modelElementFixture);
expect(dispatch).toHaveBeenCalledTimes(3);
expect(dispatch).toHaveBeenCalledWith(setBioEntityContents(expect.any(Object)));
expect(dispatch).toHaveBeenCalledWith(
addNumbersToEntityNumberData([modelElementFixture.elementId]),
);
expect(dispatch).toHaveBeenCalledWith(setCurrentSelectedBioEntityId(modelElementFixture.id));
});
});
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';
/* 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(setCurrentSelectedBioEntityId(id));
};
......@@ -4,9 +4,9 @@ import { View } from 'ol';
import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore';
import { initialMapDataFixture, openedMapsThreeSubmapsFixture } from '@/redux/map/map.fixtures';
import { useOlMapVectorListeners } from '@/components/Map/MapViewer/MapViewerVector/listeners/useOlMapVectorListeners';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/onMapLeftClick';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick';
jest.mock('./mapLeftClick/onMapLeftClick', () => ({
jest.mock('./mouseClick/mouseLeftClick/onMapLeftClick', () => ({
__esModule: true,
onMapLeftClick: jest.fn(),
}));
......
......@@ -5,22 +5,29 @@ import { mapDataSizeSelector } from '@/redux/map/map.selectors';
import { currentModelIdSelector, vectorRenderingSelector } from '@/redux/models/models.selectors';
import { MapInstance } from '@/types/map';
import { unByKey } from 'ol/Observable';
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
import { useDebouncedCallback } from 'use-debounce';
import { allCommentsSelectorOfCurrentMap } from '@/redux/comment/comment.selectors';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mapLeftClick/onMapLeftClick';
import { onMapLeftClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseLeftClick/onMapLeftClick';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { Coordinate } from 'ol/coordinate';
import { Pixel } from 'ol/pixel';
import { onMapRightClick } from '@/components/Map/MapViewer/MapViewerVector/listeners/mouseClick/mouseRightClick/onMapRightClick';
import { modelElementsSelector } from '@/redux/modelElements/modelElements.selector';
interface UseOlMapListenersInput {
interface UseOlMapVectorListenersInput {
mapInstance: MapInstance;
}
export const useOlMapVectorListeners = ({ mapInstance }: UseOlMapListenersInput): void => {
export const useOlMapVectorListeners = ({ mapInstance }: UseOlMapVectorListenersInput): void => {
const mapSize = useSelector(mapDataSizeSelector);
const modelId = useSelector(currentModelIdSelector);
const isResultDrawerOpen = useSelector(resultDrawerOpen);
const modelElements = useSelector(modelElementsSelector);
const dispatch = useAppDispatch();
const coordinate = useRef<Coordinate>([]);
const pixel = useRef<Pixel>([]);
const comments = useSelector(allCommentsSelectorOfCurrentMap);
const vectorRendering = useAppSelector(vectorRenderingSelector);
......@@ -31,6 +38,14 @@ export const useOlMapVectorListeners = ({ mapInstance }: UseOlMapListenersInput)
{ leading: false },
);
const handleRightClick = useDebouncedCallback(
onMapRightClick(mapSize, modelId, dispatch, modelElements?.content || []),
OPTIONS.clickPersistTime,
{
leading: false,
},
);
useEffect(() => {
if (!mapInstance || !vectorRendering) {
return;
......@@ -43,4 +58,27 @@ export const useOlMapVectorListeners = ({ mapInstance }: UseOlMapListenersInput)
// eslint-disable-next-line consistent-return
return () => unByKey(key);
}, [mapInstance, handleMapLeftClick, vectorRendering]);
useEffect(() => {
if (!mapInstance || !vectorRendering) {
return;
}
const rightClickEvent = (e: MouseEvent): Promise<void> | undefined => {
e.preventDefault();
coordinate.current = mapInstance.getEventCoordinate(e);
pixel.current = mapInstance.getEventPixel(e);
return handleRightClick(
{ coordinate: coordinate.current, pixel: pixel.current },
mapInstance,
);
};
mapInstance.getViewport().addEventListener('contextmenu', rightClickEvent);
// eslint-disable-next-line consistent-return
return () => mapInstance.getViewport().removeEventListener('contextmenu', rightClickEvent);
}, [mapInstance, handleRightClick, vectorRendering]);
};
......@@ -28,6 +28,7 @@ import CompartmentPathway from '@/components/Map/MapViewer/MapViewerVector/utils
import Reaction from '@/components/Map/MapViewer/MapViewerVector/utils/shapes/reaction/Reaction';
import { newReactionsDataSelector } from '@/redux/newReactions/newReactions.selectors';
import { getNewReactions } from '@/redux/newReactions/newReactions.thunks';
import { VECTOR_MAP_LAYER_TYPE } from '@/components/Map/MapViewer/MapViewerVector/MapViewerVector.constants';
export const useOlMapReactionsLayer = ({
mapInstance,
......@@ -182,11 +183,11 @@ export const useOlMapReactionsLayer = ({
});
}, [features]);
return useMemo(
() =>
new VectorLayer({
source: vectorSource,
}),
[vectorSource],
);
return useMemo(() => {
const vectorLayer = new VectorLayer({
source: vectorSource,
});
vectorLayer.set('type', VECTOR_MAP_LAYER_TYPE);
return vectorLayer;
}, [vectorSource]);
};
......@@ -126,7 +126,7 @@ export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput)
}, [mapInstance, handleMapSingleClick, vectorRendering]);
useEffect(() => {
if (!mapInstance) {
if (!mapInstance || vectorRendering) {
return;
}
......@@ -143,5 +143,5 @@ export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput)
// eslint-disable-next-line consistent-return
return () => mapInstance.getViewport().removeEventListener('contextmenu', rightClickEvent);
}, [mapInstance, handleRightClick]);
}, [mapInstance, handleRightClick, vectorRendering]);
};
import { ZOD_SEED } from '@/constants';
// eslint-disable-next-line import/no-extraneous-dependencies
import { createFixture } from 'zod-fixture';
import { modelElementSchema } from '@/models/modelElementSchema';
export const modelElementFixture = createFixture(modelElementSchema, {
seed: ZOD_SEED,
array: { min: 3, max: 3 },
});
......@@ -7,9 +7,11 @@ import { glyphSchema } from '@/models/glyphSchema';
export const modelElementSchema = z.object({
id: z.number(),
model: z.number().nullable(),
model: z.number(),
glyph: glyphSchema.nullable(),
submodel: submodelSchema.nullable(),
compartment: z.number().nullable(),
elementId: z.string(),
x: z.number(),
y: z.number(),
z: z.number(),
......
import { DEFAULT_ERROR } from '@/constants/errors';
import { ActionReducerMapBuilder, PayloadAction } from '@reduxjs/toolkit';
import { getBioEntityById } from '@/redux/bioEntity/thunks/getBioEntity';
import { BioEntityContent } from '@/types/models';
import { BIOENTITY_SUBMAP_CONNECTIONS_INITIAL_STATE } from './bioEntity.constants';
import { getBioEntity, getMultiBioEntity } from './bioEntity.thunks';
import { BioEntityContentsState } from './bioEntity.types';
......@@ -120,3 +121,18 @@ export const toggleIsContentTabOpenedReducer = (
): 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';
};
......@@ -5,6 +5,7 @@ import {
getBioEntityContentsReducer,
getMultiBioEntityContentsReducer,
getSubmapConnectionsBioEntityReducer,
setBioEntityContentsReducer,
toggleIsContentTabOpenedReducer,
} from './bioEntity.reducers';
......@@ -14,6 +15,7 @@ export const bioEntityContentsSlice = createSlice({
reducers: {
clearBioEntitiesData: clearBioEntitiesDataReducer,
toggleIsContentTabOpened: toggleIsContentTabOpenedReducer,
setBioEntityContents: setBioEntityContentsReducer,
},
extraReducers: builder => {
getBioEntityContentsReducer(builder);
......@@ -22,6 +24,7 @@ export const bioEntityContentsSlice = createSlice({
},
});
export const { clearBioEntitiesData, toggleIsContentTabOpened } = bioEntityContentsSlice.actions;
export const { clearBioEntitiesData, toggleIsContentTabOpened, setBioEntityContents } =
bioEntityContentsSlice.actions;
export default bioEntityContentsSlice.reducer;
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;
}
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