From e9a9c8b6ec5e33e35b8be02c60de35e17025dfb6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com>
Date: Wed, 3 Apr 2024 17:02:42 +0200
Subject: [PATCH] feat: add line marker w/ tests

---
 docs/plugins/data/bioentities.md              |  30 ++++--
 ...rseSurfaceMarkersToBioEntityRender.test.ts |   2 +-
 .../parseSurfaceMarkersToBioEntityRender.ts   |   2 +-
 .../pinsLayer/getMarkerSingleFeature.ts       |   4 +-
 .../config/pinsLayer/getMarkersFeatures.ts    |   4 +-
 .../utils/config/pinsLayer/getPinFeature.ts   |  11 +-
 .../reactionsLayer/useOlMapReactionsLayer.ts  |  19 +++-
 src/models/markerSchema.ts                    |  41 +++++++
 src/redux/markers/markers.reducers.ts         |   3 +-
 src/redux/markers/markers.selectors.ts        |  16 ++-
 src/redux/markers/markers.types.ts            |  27 +----
 src/redux/markers/markers.utils.ts            |   9 +-
 src/redux/models/marker.mock.ts               |   2 +-
 .../bioEntities/addSingleMarker.test.ts       | 102 ++++++++++++++++++
 .../bioEntities/addSingleMarker.ts            |  10 +-
 .../bioEntities/getAllMarkers.ts              |   2 +-
 .../bioEntities/getShownElements.types.ts     |   3 +-
 src/types/models.ts                           |  14 +++
 18 files changed, 245 insertions(+), 56 deletions(-)
 create mode 100644 src/models/markerSchema.ts
 create mode 100644 src/services/pluginsManager/bioEntities/addSingleMarker.test.ts

diff --git a/docs/plugins/data/bioentities.md b/docs/plugins/data/bioentities.md
index e17f46d1..e6d8fd8c 100644
--- a/docs/plugins/data/bioentities.md
+++ b/docs/plugins/data/bioentities.md
@@ -1,6 +1,6 @@
 ### Data / BioEntities
 
-The methods contained within 'Data / BioEntities' are used to access/modify data on content/drugs/chemicals entities, as well as pin and surface markers.
+The methods contained within 'Data / BioEntities' are used to access/modify data on content/drugs/chemicals entities, as well as pin, surface and line markers.
 
 Below is a description of the methods, as well as the types they return. A description of the object types can be found in folder `/docs/types/`.
 
@@ -49,27 +49,31 @@ Below is a description of the methods, as well as the types they return. A descr
   - **object:**
     ```
     {
-        type: 'pin' OR 'surface'
+        type: 'pin' OR 'surface' OR 'line'
         id: string [optional]
         color: string
         opacity: number
-        x: number
-        y: number
+        x: number [optional]
+        y: number [optional]
         width: number [optional]
         height: number [optional]
         number: number [optional]
         modelId: number [optional]
+        start: { x: number; y: number } [optional]
+        end: { x: number; y: number } [optional]
     }
     ```
   - **id** - optional, if not provided uuidv4 is generated
   - **color** - should be provided in hex format with hash (example: `#FF0000`)
   - **opacity** - should be a float between `0` and `1` (example: `0.54`)
-  - **x** - x coord on the map
-  - **y** - y coord on the map
+  - **x** - x coord on the map [surface/pin marker only]
+  - **y** - y coord on the map [surface/pin marker only]
   - **width** - width of surface [surface marker only]
   - **height** - width of height [surface marker only]
   - **number** - number presented on the pin [pin marker only]
   - **modelId** - if marker should be visible only on single map, modelId should be provided
+  - **start** - start point of the line [line marker only]
+  - **end** - end point of the line [line marker only]
 - adds one marker to markers list
 - returns created `Marker`
 - examples:
@@ -94,6 +98,20 @@ Below is a description of the methods, as well as the types they return. A descr
     y: 4322,
     number: 43,
   });
+  window.minerva.data.bioEntities.addSingleMarker({
+    type: 'line',
+    color: '#106AD7',
+    opacity: 1,
+    modelId: 52,
+    start: {
+      x: 8723,
+      y: 4322,
+    },
+    end: {
+      x: 4438,
+      y: 1124,
+    },
+  });
   ```
 
 ##### `removeSingleMarker`
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.test.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.test.ts
index 0510f572..1176b3ed 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.test.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.test.ts
@@ -1,5 +1,5 @@
-import { MarkerSurface } from '@/redux/markers/markers.types';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
+import { MarkerSurface } from '@/types/models';
 import { parseSurfaceMarkersToBioEntityRender } from './parseSurfaceMarkersToBioEntityRender';
 
 const MARKERS: MarkerSurface[] = [
diff --git a/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.ts b/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.ts
index bd6461e9..2f20250e 100644
--- a/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.ts
+++ b/src/components/Map/MapViewer/utils/config/overlaysLayer/parseSurfaceMarkersToBioEntityRender.ts
@@ -1,6 +1,6 @@
 import { ZERO } from '@/constants/common';
-import { MarkerSurface } from '@/redux/markers/markers.types';
 import { OverlayBioEntityRender } from '@/types/OLrendering';
+import { MarkerSurface } from '@/types/models';
 import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString';
 
 export const parseSurfaceMarkersToBioEntityRender = (
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts
index 705debb6..f024c157 100644
--- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkerSingleFeature.ts
@@ -1,4 +1,4 @@
-import { Marker } from '@/redux/markers/markers.types';
+import { MarkerWithPosition } from '@/types/models';
 import { addAlphaToHexString } from '@/utils/convert/addAlphaToHexString';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
@@ -6,7 +6,7 @@ import { getPinFeature } from './getPinFeature';
 import { getPinStyle } from './getPinStyle';
 
 export const getMarkerSingleFeature = (
-  marker: Marker,
+  marker: MarkerWithPosition,
   {
     pointToProjection,
   }: {
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkersFeatures.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkersFeatures.ts
index fa12fb5e..84855d47 100644
--- a/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkersFeatures.ts
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getMarkersFeatures.ts
@@ -1,10 +1,10 @@
-import { Marker } from '@/redux/markers/markers.types';
+import { MarkerWithPosition } from '@/types/models';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
 import { getMarkerSingleFeature } from './getMarkerSingleFeature';
 
 export const getMarkersFeatures = (
-  markers: Marker[],
+  markers: MarkerWithPosition[],
   {
     pointToProjection,
   }: {
diff --git a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts
index 51d4f8d3..8b5bf85b 100644
--- a/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts
+++ b/src/components/Map/MapViewer/utils/config/pinsLayer/getPinFeature.ts
@@ -1,15 +1,20 @@
 import { ZERO } from '@/constants/common';
 import { HALF } from '@/constants/dividers';
 import { FEATURE_TYPE } from '@/constants/features';
-import { Marker } from '@/redux/markers/markers.types';
-import { BioEntity } from '@/types/models';
+import { BioEntity, MarkerWithPosition } from '@/types/models';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import isUUID from 'is-uuid';
 import { Feature } from 'ol';
 import { Point } from 'ol/geom';
 
 export const getPinFeature = (
-  { x, y, width, height, id }: Pick<BioEntity, 'id' | 'width' | 'height' | 'x' | 'y'> | Marker,
+  {
+    x,
+    y,
+    width,
+    height,
+    id,
+  }: Pick<BioEntity, 'id' | 'width' | 'height' | 'x' | 'y'> | MarkerWithPosition,
   pointToProjection: UsePointToProjectionResult,
 ): Feature => {
   const isMarker = isUUID.anyNonNil(`${id}`);
diff --git a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
index 37bb871b..10e1d4e4 100644
--- a/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
+++ b/src/components/Map/MapViewer/utils/config/reactionsLayer/useOlMapReactionsLayer.ts
@@ -1,7 +1,8 @@
 /* eslint-disable no-magic-numbers */
 import { LINE_COLOR, LINE_WIDTH } from '@/constants/canvas';
+import { markersLinesCurrentMapDataSelector } from '@/redux/markers/markers.selectors';
 import { allReactionsSelectorOfCurrentMap } from '@/redux/reactions/reactions.selector';
-import { Reaction } from '@/types/models';
+import { MarkerLine, Reaction } from '@/types/models';
 import { LinePoint } from '@/types/reactions';
 import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import { Feature } from 'ol';
@@ -15,17 +16,27 @@ import { useMemo } from 'react';
 import { useSelector } from 'react-redux';
 import { getLineFeature } from './getLineFeature';
 
+const getLinePoints = ({ start, end }: Pick<MarkerLine, 'start' | 'end'>): LinePoint => [
+  start,
+  end,
+];
+
 const getReactionsLines = (reactions: Reaction[]): LinePoint[] =>
-  reactions.map(({ lines }) => lines.map(({ start, end }): LinePoint => [start, end])).flat();
+  reactions.map(({ lines }) => lines.map(getLinePoints)).flat();
 
 export const useOlMapReactionsLayer = (): VectorLayer<VectorSource<Feature<Geometry>>> => {
   const pointToProjection = usePointToProjection();
   const reactions = useSelector(allReactionsSelectorOfCurrentMap);
+  const markers = useSelector(markersLinesCurrentMapDataSelector);
   const reactionsLines = getReactionsLines(reactions);
+  const markerLines = markers.map(getLinePoints);
 
   const reactionsLinesFeatures = useMemo(
-    () => reactionsLines.map(linePoint => getLineFeature(linePoint, pointToProjection)),
-    [reactionsLines, pointToProjection],
+    () =>
+      [...reactionsLines, ...markerLines].map(linePoint =>
+        getLineFeature(linePoint, pointToProjection),
+      ),
+    [reactionsLines, markerLines, pointToProjection],
   );
 
   const vectorSource = useMemo(() => {
diff --git a/src/models/markerSchema.ts b/src/models/markerSchema.ts
new file mode 100644
index 00000000..9ea29511
--- /dev/null
+++ b/src/models/markerSchema.ts
@@ -0,0 +1,41 @@
+import { z } from 'zod';
+import { positionSchema } from './positionSchema';
+
+export const markerTypeSchema = z.union([
+  z.literal('pin'),
+  z.literal('surface'),
+  z.literal('line'),
+]);
+
+const markerBaseSchema = z.object({
+  type: markerTypeSchema,
+  id: z.string(),
+  color: z.string(),
+  opacity: z.number(),
+  number: z.number().optional(),
+  modelId: z.number().optional(),
+});
+
+const markerWithPositionBaseSchema = markerBaseSchema.extend({
+  x: z.number(),
+  y: z.number(),
+});
+
+export const markerPinSchema = markerWithPositionBaseSchema.extend({
+  width: z.number().optional(),
+  height: z.number().optional(),
+});
+
+export const markerSurfaceSchema = markerWithPositionBaseSchema.extend({
+  width: z.number(),
+  height: z.number(),
+});
+
+export const markerLineSchema = markerBaseSchema.extend({
+  start: positionSchema,
+  end: positionSchema,
+});
+
+export const markerWithPositionSchema = z.union([markerPinSchema, markerSurfaceSchema]);
+
+export const markerSchema = z.union([markerPinSchema, markerSurfaceSchema, markerLineSchema]);
diff --git a/src/redux/markers/markers.reducers.ts b/src/redux/markers/markers.reducers.ts
index d0cad10d..89e912b2 100644
--- a/src/redux/markers/markers.reducers.ts
+++ b/src/redux/markers/markers.reducers.ts
@@ -1,5 +1,6 @@
+import { Marker } from '@/types/models';
 import { PayloadAction } from '@reduxjs/toolkit';
-import { Marker, MarkersState } from './markers.types';
+import { MarkersState } from './markers.types';
 
 export const setMarkersDataReducer = (
   state: MarkersState,
diff --git a/src/redux/markers/markers.selectors.ts b/src/redux/markers/markers.selectors.ts
index da6987b3..18a3a82c 100644
--- a/src/redux/markers/markers.selectors.ts
+++ b/src/redux/markers/markers.selectors.ts
@@ -1,8 +1,8 @@
+import { Marker, MarkerLine, MarkerSurface, MarkerWithPosition } from '@/types/models';
 import { createSelector } from '@reduxjs/toolkit';
 import { currentModelIdSelector } from '../models/models.selectors';
 import { rootSelector } from '../root/root.selectors';
-import { MarkerSurface } from './markers.types';
-import { isMarkerSurface } from './markers.utils';
+import { isMarkerLine, isMarkerSurface } from './markers.utils';
 
 export const markersSelector = createSelector(rootSelector, state => state.markers);
 
@@ -20,7 +20,12 @@ export const markersPinsDataSelector = createSelector(markersDataSelector, marke
 
 export const markersPinsOfCurrentMapDataSelector = createSelector(
   markersDataOfCurrentMapSelector,
-  markersData => markersData.filter(m => m.type === 'pin'),
+  (markersData): MarkerWithPosition[] =>
+    markersData
+      .filter(m => m.type === 'pin')
+      .filter((marker: Marker): marker is MarkerWithPosition =>
+        Boolean('x' in marker && 'y' in marker),
+      ),
 );
 
 export const markersSufraceSelector = createSelector(markersDataSelector, markersData =>
@@ -31,3 +36,8 @@ export const markersSufraceOfCurrentMapDataSelector = createSelector(
   markersDataOfCurrentMapSelector,
   (markers): MarkerSurface[] => markers.filter(isMarkerSurface),
 );
+
+export const markersLinesCurrentMapDataSelector = createSelector(
+  markersDataOfCurrentMapSelector,
+  (markers): MarkerLine[] => markers.filter(isMarkerLine),
+);
diff --git a/src/redux/markers/markers.types.ts b/src/redux/markers/markers.types.ts
index 4ea83078..62f9b9f1 100644
--- a/src/redux/markers/markers.types.ts
+++ b/src/redux/markers/markers.types.ts
@@ -1,30 +1,9 @@
-export type MarkerType = 'pin' | 'surface';
+import { Marker } from '@/types/models';
 
-interface MarkerBase {
-  type: MarkerType;
-  id: string;
-  color: string;
-  opacity: number;
-  x: number;
-  y: number;
-  number?: number;
-  modelId?: number;
+export interface MarkerWithOptionalId extends Omit<Marker, 'id'> {
+  id?: string;
 }
 
-export interface MarkerPin extends MarkerBase {
-  width?: number;
-  height?: number;
-}
-
-export interface MarkerSurface extends MarkerBase {
-  width: number;
-  height: number;
-}
-
-export type Marker = MarkerPin | MarkerSurface;
-
-export type MarkerWithoutId = Omit<Marker, 'id'>;
-
 export interface MarkersState {
   data: Marker[];
 }
diff --git a/src/redux/markers/markers.utils.ts b/src/redux/markers/markers.utils.ts
index 08b862e3..c0cd24ec 100644
--- a/src/redux/markers/markers.utils.ts
+++ b/src/redux/markers/markers.utils.ts
@@ -1,4 +1,9 @@
-import { Marker, MarkerSurface } from './markers.types';
+import { Marker, MarkerLine, MarkerSurface } from '@/types/models';
 
 export const isMarkerSurface = (marker: Marker): marker is MarkerSurface =>
-  Boolean(marker?.width && marker?.height && marker.type === 'surface');
+  Boolean('width' in marker && marker?.width && marker?.height && marker.type === 'surface');
+
+export const isMarkerLine = (marker: Marker): marker is MarkerLine =>
+  Boolean(
+    'start' in marker && 'end' in marker && marker?.start && marker?.end && marker.type === 'line',
+  );
diff --git a/src/redux/models/marker.mock.ts b/src/redux/models/marker.mock.ts
index 951b5d62..657f2893 100644
--- a/src/redux/models/marker.mock.ts
+++ b/src/redux/models/marker.mock.ts
@@ -1,4 +1,4 @@
-import { MarkerPin, MarkerSurface } from '../markers/markers.types';
+import { MarkerPin, MarkerSurface } from '@/types/models';
 
 export const SURFACE_MARKER: MarkerSurface = {
   type: 'surface',
diff --git a/src/services/pluginsManager/bioEntities/addSingleMarker.test.ts b/src/services/pluginsManager/bioEntities/addSingleMarker.test.ts
new file mode 100644
index 00000000..63c3269a
--- /dev/null
+++ b/src/services/pluginsManager/bioEntities/addSingleMarker.test.ts
@@ -0,0 +1,102 @@
+import { addMarkerToMarkersData } from '@/redux/markers/markers.slice';
+import { MarkerWithOptionalId } from '@/redux/markers/markers.types';
+import { Marker, MarkerLine, MarkerPin, MarkerSurface } from '@/types/models';
+import { ZodError } from 'zod';
+import { store } from '../../../redux/store';
+import { addSingleMarker } from './addSingleMarker';
+
+jest.mock('../../../redux/store');
+
+const VALID_MARKERS: MarkerWithOptionalId[] = [
+  {
+    id: 'id-123',
+    type: 'pin',
+    color: '#F48C41',
+    opacity: 0.68,
+    x: 1000,
+    y: 200,
+    number: 75,
+    modelId: 52,
+  } as MarkerPin,
+  {
+    type: 'surface',
+    color: '#106AD7',
+    opacity: 0.24,
+    x: 442,
+    y: 442,
+    width: 600,
+    height: 500,
+    number: 37,
+  } as MarkerSurface,
+  {
+    type: 'line',
+    color: '#106AD7',
+    opacity: 0.7312,
+    modelId: 52,
+    start: {
+      x: 1200,
+      y: 432,
+    },
+    end: {
+      x: 332,
+      y: 112,
+    },
+  } as MarkerLine,
+];
+
+export const INVALID_MARKERS: unknown[] = [
+  {
+    id: 'id-123',
+    type: 'pin',
+    x: 1000,
+    y: 200,
+    number: 75,
+    modelId: 52,
+  },
+  {
+    type: 'surface',
+    color: '#106AD7',
+    opacity: 0.24,
+    x: 442,
+    number: 37,
+  },
+  {
+    type: 'line',
+    color: '#106AD7',
+    opacity: 0.7312,
+    modelId: 52,
+    start: {
+      x: 1200,
+      y: 432,
+    },
+  },
+  {
+    id: 123345,
+    color: '#106AD7',
+    opacity: 0.7312,
+    modelId: 52,
+    start: {
+      x: 1200,
+      y: 432,
+    },
+  },
+];
+
+describe('addSingleMarker - plugin method', () => {
+  const dispatchSpy = jest.spyOn(store, 'dispatch');
+
+  it.each(VALID_MARKERS)(
+    'should dispatch addMarkerToMarkersData and return valid marker with id',
+    marker => {
+      const markerResults = addSingleMarker(marker);
+
+      expect(dispatchSpy).toHaveBeenCalledWith(
+        addMarkerToMarkersData({ ...marker, id: markerResults.id } as Marker),
+      );
+    },
+  );
+
+  it.each(INVALID_MARKERS)('should throw error', marker => {
+    expect(() => addSingleMarker(marker as MarkerWithOptionalId)).toThrow(ZodError);
+  });
+});
diff --git a/src/services/pluginsManager/bioEntities/addSingleMarker.ts b/src/services/pluginsManager/bioEntities/addSingleMarker.ts
index 0b496795..2475a78b 100644
--- a/src/services/pluginsManager/bioEntities/addSingleMarker.ts
+++ b/src/services/pluginsManager/bioEntities/addSingleMarker.ts
@@ -1,11 +1,15 @@
+import { markerSchema } from '@/models/markerSchema';
 import { addMarkerToMarkersData } from '@/redux/markers/markers.slice';
-import { Marker, MarkerWithoutId } from '@/redux/markers/markers.types';
+import { MarkerWithOptionalId } from '@/redux/markers/markers.types';
 import { store } from '@/redux/store';
+import { Marker } from '@/types/models';
 import { v4 as uuidv4 } from 'uuid';
 
-export const addSingleMarker = (markerWithoutId: MarkerWithoutId): Marker => {
+export const addSingleMarker = (markerWithoutId: MarkerWithOptionalId): Marker => {
   const { dispatch } = store;
-  const marker = { id: uuidv4(), ...markerWithoutId };
+  const marker = { id: uuidv4(), ...markerWithoutId } as Marker;
+  markerSchema.parse(marker);
+
   dispatch(addMarkerToMarkersData(marker));
 
   return marker;
diff --git a/src/services/pluginsManager/bioEntities/getAllMarkers.ts b/src/services/pluginsManager/bioEntities/getAllMarkers.ts
index 1ed70af6..2fa459d3 100644
--- a/src/services/pluginsManager/bioEntities/getAllMarkers.ts
+++ b/src/services/pluginsManager/bioEntities/getAllMarkers.ts
@@ -1,6 +1,6 @@
 import { markersDataSelector } from '@/redux/markers/markers.selectors';
-import { Marker } from '@/redux/markers/markers.types';
 import { store } from '@/redux/store';
+import { Marker } from '@/types/models';
 
 export const getAllMarkers = (): Marker[] => {
   const { getState } = store;
diff --git a/src/services/pluginsManager/bioEntities/getShownElements.types.ts b/src/services/pluginsManager/bioEntities/getShownElements.types.ts
index dcbacd29..210a0e01 100644
--- a/src/services/pluginsManager/bioEntities/getShownElements.types.ts
+++ b/src/services/pluginsManager/bioEntities/getShownElements.types.ts
@@ -1,5 +1,4 @@
-import { Marker } from '@/redux/markers/markers.types';
-import { BioEntity } from '@/types/models';
+import { BioEntity, Marker } from '@/types/models';
 
 export interface GetShownElementsPluginMethodResult {
   content: BioEntity[];
diff --git a/src/types/models.ts b/src/types/models.ts
index 39fada22..aa0b1d3f 100644
--- a/src/types/models.ts
+++ b/src/types/models.ts
@@ -23,6 +23,14 @@ import {
   mapOverlay,
   uploadedOverlayFileContentSchema,
 } from '@/models/mapOverlay';
+import {
+  markerLineSchema,
+  markerPinSchema,
+  markerSchema,
+  markerSurfaceSchema,
+  markerTypeSchema,
+  markerWithPositionSchema,
+} from '@/models/markerSchema';
 import { mapModelSchema } from '@/models/modelSchema';
 import { organism } from '@/models/organism';
 import {
@@ -102,3 +110,9 @@ 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>;
+export type MarkerType = z.infer<typeof markerTypeSchema>;
+export type MarkerPin = z.infer<typeof markerPinSchema>;
+export type MarkerSurface = z.infer<typeof markerSurfaceSchema>;
+export type MarkerLine = z.infer<typeof markerLineSchema>;
+export type MarkerWithPosition = z.infer<typeof markerWithPositionSchema>;
+export type Marker = z.infer<typeof markerSchema>;
-- 
GitLab