From 51c0cbf614f66ca747a30bb10c4d22ff5db99be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Or=C5=82=C3=B3w?= <adrian.orlow@fishbrain.com> Date: Fri, 8 Dec 2023 14:49:17 +0100 Subject: [PATCH] test: add tests for modal render overview image --- .../OverviewImagesModal.component.test.tsx | 104 +++++++++++ .../OverviewImagesModal.component.tsx | 10 +- .../utils/getFinalImageSize.test.ts | 33 ++++ .../utils/getFinalImageSize.ts | 27 +++ .../utils/useOverviewImage.test.ts | 116 +++++++++++++ .../utils/useOverviewImageSize.test.tsx | 104 +++++++++++ .../utils/useOverviewImageSize.ts | 24 +-- .../utils/useOverviewImageUrl.test.ts | 63 +++++++ src/constants/project.ts | 2 +- src/redux/project/project.mock.ts | 163 ++++++++++++++++++ 10 files changed, 622 insertions(+), 24 deletions(-) create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.test.ts create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.ts create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx create mode 100644 src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx new file mode 100644 index 00000000..b8c92be9 --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.test.tsx @@ -0,0 +1,104 @@ +import { BASE_MAP_IMAGES_URL } from '@/constants'; +import { projectFixture } from '@/models/fixtures/projectFixture'; +import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock'; +import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock'; +import { StoreType } from '@/redux/store'; +import { + InitialStoreState, + getReduxWrapperWithStore, +} from '@/utils/testing/getReduxWrapperWithStore'; +import { render, screen } from '@testing-library/react'; +import { OverviewImagesModal } from './OverviewImagesModal.component'; + +jest.mock('./utils/useOverviewImageSize', () => ({ + __esModule: true, + useOverviewImageSize: jest.fn().mockImplementation(() => ({ + width: 200, + height: 300, + })), +})); + +const renderComponent = (initialStoreState: InitialStoreState = {}): { store: StoreType } => { + const { Wrapper, store } = getReduxWrapperWithStore(initialStoreState); + + return ( + render( + <Wrapper> + <OverviewImagesModal /> + </Wrapper>, + ), + { + store, + } + ); +}; + +describe('OverviewImagesModal - component', () => { + describe('when currentImage is NOT valid', () => { + beforeEach(() => { + renderComponent({ + project: { + data: { + ...projectFixture, + overviewImageViews: [], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: 0, + }, + }, + }); + }); + + it('should not render component', () => { + const element = screen.queryByTestId('overview-images-modal'); + expect(element).toBeNull(); + }); + }); + + describe('when currentImage is valid', () => { + beforeEach(() => { + renderComponent({ + project: { + data: { + ...projectFixture, + overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + }); + + it('should render component', () => { + const element = screen.queryByTestId('overview-images-modal'); + expect(element).not.toBeNull(); + }); + + it('should render image with valid src', () => { + const imageElement = screen.getByAltText('overview'); + const result = `${BASE_MAP_IMAGES_URL}/map_images/${PROJECT_OVERVIEW_IMAGE_MOCK.filename}`; + expect(imageElement.getAttribute('src')).toBe(result); + }); + + it('should render image wrapper with valid size', () => { + const imageElement = screen.getByAltText('overview'); + const wrapperElement = imageElement.closest('div'); + const wrapperStyle = wrapperElement?.getAttribute('style'); + + expect(wrapperStyle).toBe('width: 200px; height: 300px;'); + }); + }); +}); diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.tsx b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.tsx index 927b3805..ef0e608a 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.tsx +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/OverviewImagesModal.component.tsx @@ -16,8 +16,16 @@ export const OverviewImagesModal: React.FC = () => { setContainerRect(node.getBoundingClientRect()); }, []); + if (!imageUrl) { + return null; + } + return ( - <div className="flex h-full w-full items-center justify-center bg-white" ref={handleRect}> + <div + data-testid="overview-images-modal" + className="flex h-full w-full items-center justify-center bg-white" + ref={handleRect} + > <div className="relative" style={{ width, height }}> <img alt="overview" className="block h-full w-full" src={imageUrl} /> {/* TODO: interactions - clickable elements (in next task) */} diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.test.ts new file mode 100644 index 00000000..e4d85760 --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.test.ts @@ -0,0 +1,33 @@ +import { getFinalImageSize } from './getFinalImageSize'; + +describe('getFinalImageSize - util', () => { + const cases = [ + [ + { width: 0, height: 0 }, + { width: 0, height: 0 }, + { width: 0, height: 0, sizeFactor: 0 }, + ], + [ + { width: 100, height: 100 }, + { width: 100, height: 100 }, + { width: 100, height: 100, sizeFactor: 1 }, + ], + [ + { width: 100, height: 100 }, + { width: 200, height: 250 }, + { width: 80, height: 100, sizeFactor: 0.4 }, + ], + [ + { width: 10, height: 40 }, + { width: 40, height: 60 }, + { width: 10, height: 15, sizeFactor: 0.25 }, + ], + ]; + + it.each(cases)( + 'should return valid size and size factor', + (containerSize, maxImageSize, finalSize) => { + expect(getFinalImageSize(containerSize, maxImageSize)).toStrictEqual(finalSize); + }, + ); +}); diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.ts new file mode 100644 index 00000000..877bc9fd --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/getFinalImageSize.ts @@ -0,0 +1,27 @@ +import { ZERO } from '@/constants/common'; +import { ImageContainerSize, OverviewImageSize } from '../OverviewImageModal.types'; + +interface GetFinalImageSizeResult extends OverviewImageSize { + sizeFactor: number; +} + +export const getFinalImageSize = ( + containerSize: ImageContainerSize, + maxImageSize: OverviewImageSize, +): GetFinalImageSizeResult => { + const maxHeight = Math.min(containerSize.height, maxImageSize.height); + const maxWidth = Math.min(containerSize.width, maxImageSize.width); + + const heightSizeFactor = maxHeight / maxImageSize.height; + const widthSizeFactor = maxWidth / maxImageSize.width; + const sizeFactor = Math.min(heightSizeFactor, widthSizeFactor); + + const width = maxImageSize.width * sizeFactor; + const height = maxImageSize.height * sizeFactor; + + return { + height: height || ZERO, + width: width || ZERO, + sizeFactor: sizeFactor || ZERO, + }; +}; diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts new file mode 100644 index 00000000..f4d964d3 --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImage.test.ts @@ -0,0 +1,116 @@ +import { BASE_MAP_IMAGES_URL } from '@/constants'; +import { DEFAULT_OVERVIEW_IMAGE_SIZE } from '@/constants/project'; +import { projectFixture } from '@/models/fixtures/projectFixture'; +import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock'; +import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import { useOverviewImage } from './useOverviewImage'; + +describe('useOverviewImage - hook', () => { + describe('when image data is invalid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: 0, + }, + }, + }); + + const { result } = renderHook(() => useOverviewImage({ containerRect: undefined }), { + wrapper: Wrapper, + }); + + it('should return default size of image and empty imageUrl', () => { + expect(result.current).toStrictEqual({ + imageUrl: '', + size: DEFAULT_OVERVIEW_IMAGE_SIZE, + }); + }); + }); + + describe('when containerReact is undefined', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + + const { result } = renderHook(() => useOverviewImage({ containerRect: undefined }), { + wrapper: Wrapper, + }); + + it('should return default size of image and valid imageUrl', () => { + const imageUrl = `${BASE_MAP_IMAGES_URL}/map_images/${PROJECT_OVERVIEW_IMAGE_MOCK.filename}`; + + expect(result.current).toStrictEqual({ + imageUrl, + size: DEFAULT_OVERVIEW_IMAGE_SIZE, + }); + }); + }); + + describe('when containerReact is valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [ + { + ...PROJECT_OVERVIEW_IMAGE_MOCK, + height: 500, + width: 500, + }, + ], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + + const { result } = renderHook( + () => useOverviewImage({ containerRect: { width: 100, height: 200 } as DOMRect }), + { + wrapper: Wrapper, + }, + ); + + it('should return size of image and valid imageUrl', () => { + const imageUrl = `${BASE_MAP_IMAGES_URL}/map_images/${PROJECT_OVERVIEW_IMAGE_MOCK.filename}`; + + expect(result.current).toStrictEqual({ + imageUrl, + size: { height: 100, width: 100, sizeFactor: 0.2 }, + }); + }); + }); +}); diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx new file mode 100644 index 00000000..b5c8b6b5 --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.test.tsx @@ -0,0 +1,104 @@ +/* eslint-disable no-magic-numbers */ +import { DEFAULT_OVERVIEW_IMAGE_SIZE } from '@/constants/project'; +import { projectFixture } from '@/models/fixtures/projectFixture'; +import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock'; +import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import { useOverviewImageSize } from './useOverviewImageSize'; + +describe('useOverviewImageSize - hook', () => { + describe('when currentImage is not valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: 0, + }, + }, + }); + + const { result } = renderHook( + () => useOverviewImageSize({ containerRect: { width: 800, height: 600 } as DOMRect }), + { + wrapper: Wrapper, + }, + ); + + it('should return default value', () => { + expect(result.current).toStrictEqual(DEFAULT_OVERVIEW_IMAGE_SIZE); + }); + }); + + describe('when containerRect is not valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + + const { result } = renderHook(() => useOverviewImageSize({ containerRect: undefined }), { + wrapper: Wrapper, + }); + + it('should return default value', () => { + expect(result.current).toStrictEqual(DEFAULT_OVERVIEW_IMAGE_SIZE); + }); + }); + + describe('when data is valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + + const { result } = renderHook( + () => useOverviewImageSize({ containerRect: { width: 1600, height: 1000 } as DOMRect }), + { + wrapper: Wrapper, + }, + ); + + const { height, width, sizeFactor } = result.current; + + it('should return calculated height, width, sizeFactor', () => { + expect(height).toBeCloseTo(1000); + expect(width).toBeCloseTo(1429.7); + expect(sizeFactor).toBeCloseTo(0.247); + }); + }); +}); diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.ts index 96015735..1623d526 100644 --- a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.ts +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageSize.ts @@ -1,7 +1,8 @@ import { DEFAULT_OVERVIEW_IMAGE_SIZE } from '@/constants/project'; import { currentOverviewImageSelector } from '@/redux/project/project.selectors'; import { useSelector } from 'react-redux'; -import { ImageContainerSize, OverviewImageSize } from '../OverviewImageModal.types'; +import { OverviewImageSize } from '../OverviewImageModal.types'; +import { getFinalImageSize } from './getFinalImageSize'; interface UseOverviewImageArgs { containerRect?: DOMRect; @@ -11,27 +12,6 @@ interface UseOverviewImageResult extends OverviewImageSize { sizeFactor: number; } -const getFinalImageSize = ( - containerSize: ImageContainerSize, - maxImageSize: OverviewImageSize, -): UseOverviewImageResult => { - const maxHeight = Math.min(containerSize.height, maxImageSize.height); - const maxWidth = Math.min(containerSize.width, maxImageSize.width); - - const heightSizeFactor = maxHeight / maxImageSize.height; - const widthSizeFactor = maxWidth / maxImageSize.width; - const sizeFactor = Math.min(heightSizeFactor, widthSizeFactor); - - const width = maxImageSize.width * sizeFactor; - const height = maxImageSize.height * sizeFactor; - - return { - height, - width, - sizeFactor, - }; -}; - export const useOverviewImageSize = ({ containerRect, }: UseOverviewImageArgs): UseOverviewImageResult => { diff --git a/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts new file mode 100644 index 00000000..b5e9beb8 --- /dev/null +++ b/src/components/FunctionalArea/Modal/OverviewImagesModal/utils/useOverviewImageUrl.test.ts @@ -0,0 +1,63 @@ +import { BASE_MAP_IMAGES_URL } from '@/constants'; +import { projectFixture } from '@/models/fixtures/projectFixture'; +import { MODAL_INITIAL_STATE_MOCK } from '@/redux/modal/modal.mock'; +import { PROJECT_OVERVIEW_IMAGE_MOCK } from '@/redux/project/project.mock'; +import { getReduxWrapperWithStore } from '@/utils/testing/getReduxWrapperWithStore'; +import { renderHook } from '@testing-library/react'; +import { useOverviewImageUrl } from './useOverviewImageUrl'; + +describe('useOverviewImageUrl - hook', () => { + describe('when currentImage data is valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: 0, + }, + }, + }); + + it('should return valid url', () => { + const { result } = renderHook(() => useOverviewImageUrl(), { wrapper: Wrapper }); + + expect(result.current).toBe(''); + }); + }); + + describe('when currentImage data is valid', () => { + const { Wrapper } = getReduxWrapperWithStore({ + project: { + data: { + ...projectFixture, + overviewImageViews: [PROJECT_OVERVIEW_IMAGE_MOCK], + topOverviewImage: PROJECT_OVERVIEW_IMAGE_MOCK, + }, + loading: 'succeeded', + error: { message: '', name: '' }, + }, + modal: { + ...MODAL_INITIAL_STATE_MOCK, + overviewImagesState: { + imageId: PROJECT_OVERVIEW_IMAGE_MOCK.idObject, + }, + }, + }); + + it('should return valid url', () => { + const { result } = renderHook(() => useOverviewImageUrl(), { wrapper: Wrapper }); + + expect(result.current).toBe( + `${BASE_MAP_IMAGES_URL}/map_images/${PROJECT_OVERVIEW_IMAGE_MOCK.filename}`, + ); + }); + }); +}); diff --git a/src/constants/project.ts b/src/constants/project.ts index 04fad94b..85fd9c68 100644 --- a/src/constants/project.ts +++ b/src/constants/project.ts @@ -5,5 +5,5 @@ export const DEFAULT_OVERVIEW_IMAGE_HEIGHT = 500; export const DEFAULT_OVERVIEW_IMAGE_SIZE = { width: DEFAULT_OVERVIEW_IMAGE_WIDTH, height: DEFAULT_OVERVIEW_IMAGE_HEIGHT, - sizeFactor: 0, + sizeFactor: 1, }; diff --git a/src/redux/project/project.mock.ts b/src/redux/project/project.mock.ts index 036d2634..dada67e4 100644 --- a/src/redux/project/project.mock.ts +++ b/src/redux/project/project.mock.ts @@ -1,4 +1,5 @@ import { DEFAULT_ERROR } from '@/constants/errors'; +import { OverviewImageView } from '@/types/models'; import { ProjectState } from './project.types'; export const PROJECT_STATE_INITIAL_MOCK: ProjectState = { @@ -6,3 +7,165 @@ export const PROJECT_STATE_INITIAL_MOCK: ProjectState = { loading: 'idle', error: DEFAULT_ERROR, }; + +export const PROJECT_OVERVIEW_IMAGE_MOCK: OverviewImageView = { + idObject: 440, + filename: '9d4911bdeeea752f076e57a91d9b1f45/biolayout_main_root.png', + width: 5776, + height: 4040, + links: [ + { + idObject: 2062, + polygon: [ + { + x: 515, + y: 2187, + }, + { + x: 1073, + y: 2187, + }, + { + x: 1073, + y: 2520, + }, + { + x: 515, + y: 2520, + }, + ], + zoomLevel: 4, + modelPoint: { + x: 3473, + y: 5871, + }, + modelLinkId: 5053, + type: 'OverviewModelLink', + }, + { + idObject: 2063, + polygon: [ + { + x: 2410, + y: 1360, + }, + { + x: 2692, + y: 1360, + }, + { + x: 2692, + y: 1570, + }, + { + x: 2410, + y: 1570, + }, + ], + imageLinkId: 435, + type: 'OverviewImageLink', + }, + { + idObject: 2064, + polygon: [ + { + x: 2830, + y: 497, + }, + { + x: 3256, + y: 497, + }, + { + x: 3256, + y: 832, + }, + { + x: 2830, + y: 832, + }, + ], + zoomLevel: 5, + modelPoint: { + x: 8081, + y: 1240, + }, + modelLinkId: 5053, + type: 'OverviewModelLink', + }, + { + idObject: 2065, + polygon: [ + { + x: 3232, + y: 2259, + }, + { + x: 3520, + y: 2259, + }, + { + x: 3520, + y: 2456, + }, + { + x: 3232, + y: 2456, + }, + ], + imageLinkId: 433, + type: 'OverviewImageLink', + }, + { + idObject: 2066, + polygon: [ + { + x: 4205, + y: 761, + }, + { + x: 4625, + y: 761, + }, + { + x: 4625, + y: 1102, + }, + { + x: 4205, + y: 1102, + }, + ], + zoomLevel: 5, + modelPoint: { + x: 7488, + y: 11986, + }, + modelLinkId: 5053, + type: 'OverviewModelLink', + }, + { + idObject: 2067, + polygon: [ + { + x: 4960, + y: 1971, + }, + { + x: 5241, + y: 1971, + }, + { + x: 5241, + y: 2163, + }, + { + x: 4960, + y: 2163, + }, + ], + imageLinkId: 434, + type: 'OverviewImageLink', + }, + ], +}; -- GitLab