@3cr/viewer-browser 0.0.220 → 0.0.246

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/components.d.ts +6 -2
  2. package/dist/Viewer3CR.js +32 -32
  3. package/dist/Viewer3CR.mjs +17808 -14315
  4. package/dist/Viewer3CR.umd.js +32 -32
  5. package/index.html +1 -1
  6. package/package.json +4 -3
  7. package/playground/index.html +4 -12
  8. package/src/App.vue +29 -14
  9. package/src/__tests__/main.spec.ts +4 -4
  10. package/src/assets/styles.scss +6 -2
  11. package/src/components/demo/DemoPatientModal.vue +12 -22
  12. package/src/components/demo/licence/DemoLicenceInfoModal.vue +11 -29
  13. package/src/components/demo/options.ts +42 -39
  14. package/src/components/demo/patient/DemoPatientInfoModal.vue +11 -29
  15. package/src/components/modal/CloseViewerModal.vue +1 -1
  16. package/src/components/modal/MftpWebGL3DRModal.vue +133 -120
  17. package/src/components/modal/ViewerActionRail.vue +0 -6
  18. package/src/components/modal/ViewerNavigationDrawerContent.vue +25 -16
  19. package/src/components/modal/ViewerNavigationDrawerFooter.vue +32 -9
  20. package/src/components/modal/ViewerNavigationDrawerHeader.vue +6 -1
  21. package/src/components/modal/WebGL3DR.vue +7 -0
  22. package/src/components/modal/__tests__/ViewerNavigationDrawerHeader.spec.ts +3 -2
  23. package/src/components/modal/buttons/AutoAnnotateBtn.vue +181 -13
  24. package/src/components/modal/menus/FileMenu.vue +2 -9
  25. package/src/components/modal/menus/SettingsMenu.vue +2 -7
  26. package/src/components/navigation/mcad/McadGlobalActions.vue +20 -0
  27. package/src/components/navigation/mcad/McadGlobalOpacitySlider.vue +103 -0
  28. package/src/components/navigation/mcad/McadGlobalScanViewBtn.vue +28 -0
  29. package/src/components/navigation/mcad/McadGlobalVisibilityBtn.vue +38 -0
  30. package/src/components/shared/LoadingSpinner.vue +27 -36
  31. package/src/components/views/AnnotationTreeView.vue +3 -1
  32. package/src/components/views/MarkupTreeView.vue +3 -1
  33. package/src/components/views/McadObjectTreeView.vue +46 -36
  34. package/src/components/views/modals/DataOverlayGeneralModal.vue +71 -0
  35. package/src/components/views/modals/DataOverlayMarkupModal.vue +60 -0
  36. package/src/components/views/modals/DataOverlayModal.vue +54 -55
  37. package/src/components/views/shared/Opacity.vue +0 -1
  38. package/src/composables/useDebounce.ts +11 -0
  39. package/src/composables/useIntroJs.ts +23 -6
  40. package/src/composables/useViewerOptions.ts +1 -0
  41. package/src/functions/guards/isDataOverlayAngle.ts +6 -0
  42. package/src/functions/guards/isDataOverlayLength.ts +6 -0
  43. package/src/functions/guards/isDataOverlayPolygon.ts +6 -0
  44. package/src/functions/modelHelper.ts +2 -0
  45. package/src/functions/notification.ts +63 -29
  46. package/src/main.ts +22 -13
  47. package/src/models/loadViewerOptions.ts +39 -0
  48. package/src/models/loadViewerPayload.ts +0 -7
  49. package/src/services/viewer-3cr.service.ts +13 -1
  50. package/src/tools/data-overlay.tool.ts +71 -0
  51. package/src/types/data-overlay-event.ts +5 -0
  52. package/src/types/data-overlay-info.ts +4 -0
  53. package/src/types/demo-type.ts +4 -0
  54. package/src/components/modal/actions/HideViewAction.vue +0 -38
  55. package/src/components/views/modals/DataOverlayModalManager.vue +0 -104
  56. package/src/components/views/modals/__tests__/DataOverlayModal.spec.ts +0 -33
  57. package/src/components/views/modals/__tests__/DataOverlayModalManager.spec.ts +0 -93
package/src/main.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { registerVersion } from '@3cr/sdk-browser';
1
+ import { registerVersion, quit } from '@3cr/sdk-browser';
2
2
  import { ComponentPublicInstance, createApp } from 'vue';
3
3
  import { usePlugins } from '@/plugins/usePlugins';
4
4
  import { defaultLoadViewerOptions, LoadViewerOptions } from '@/models/loadViewerOptions';
@@ -6,22 +6,25 @@ import { LoadViewerPayload } from '@/models/loadViewerPayload';
6
6
  import { injectedStyleId } from './config';
7
7
  import { useVersion3cr } from '@/composables/useVersion3cr';
8
8
  import App from '@/App.vue';
9
+ import { getAvailableLanguages, setLanguage } from '@3cr/translations-ts';
9
10
 
10
11
  let mountedApp: ComponentPublicInstance | undefined = undefined;
11
12
 
12
- let modalId = `__modal_set__`;
13
+ export async function registerViewer(host: Element | string, version: string, language?: string): Promise<void> {
14
+ await registerVersion(version);
13
15
 
14
- export async function registerViewer(version: string) {
15
- const newElement = document.createElement('div');
16
- newElement.style.width = '0';
17
- newElement.style.height = '0';
18
- newElement.id = modalId;
19
- document.body.appendChild(newElement);
16
+ const languages = await getAvailableLanguages();
17
+ if (language && languages.includes(language)) {
18
+ await setLanguage(language);
19
+ } else {
20
+ const documentLanguage = document.querySelector('html')?.getAttribute('lang');
21
+ const defaultLanguage = documentLanguage ?? languages[0];
22
+ await setLanguage(defaultLanguage);
23
+ }
20
24
 
21
25
  const app = createApp(App);
22
26
  usePlugins(app);
23
- mountedApp = app.mount(newElement);
24
- await registerVersion(version);
27
+ mountedApp = app.mount(host);
25
28
 
26
29
  const version3cr = useVersion3cr();
27
30
  version3cr.value = version;
@@ -44,9 +47,15 @@ export async function loadSession(url: string): Promise<void> {
44
47
  await (mountedApp as any).loadSession(url);
45
48
  }
46
49
 
47
- export async function ejectViewer() {
48
- const modal = document.getElementById(modalId);
50
+ export async function ejectViewer(): Promise<void> {
49
51
  const styleSheet = document.getElementById(injectedStyleId);
50
- modal?.remove();
51
52
  styleSheet?.remove();
53
+ await quit();
54
+ }
55
+
56
+ export async function closeViewer(): Promise<void> {
57
+ if (!mountedApp) {
58
+ throw new Error('Please call `registerViewer(version: string)` first');
59
+ }
60
+ await (mountedApp as any).close();
52
61
  }
@@ -1,7 +1,33 @@
1
1
  import { ViewerCallback } from '@/models/callbacks';
2
2
  import { CurrentDataOverlayState, CurrentMcadState, CurrentScanState } from '@3cr/types-ts';
3
+ import { Viewer3crService } from '@/services/viewer-3cr.service';
3
4
 
4
5
  export interface LoadViewerOptions {
6
+ ViewerTitle?: string;
7
+ DisplaySettings?: {
8
+ Show?: boolean;
9
+ Title?: string;
10
+ Tooltip?: string;
11
+ Icon?: string;
12
+ };
13
+ Annotations?: {
14
+ Show?: boolean;
15
+ Title?: string;
16
+ Tooltip?: string;
17
+ Icon?: string;
18
+ };
19
+ Markups?: {
20
+ Show?: boolean;
21
+ Title?: string;
22
+ Tooltip?: string;
23
+ Icon?: string;
24
+ };
25
+ Mcad?: {
26
+ Show?: boolean;
27
+ Title?: string;
28
+ Tooltip?: string;
29
+ Icon?: string;
30
+ };
5
31
  OnAutoAnnotate?: ViewerCallback;
6
32
  OnClosePopup?: ViewerCallback;
7
33
  OnDownloadDicomSeries?: ViewerCallback;
@@ -18,6 +44,19 @@ export interface LoadViewerOptions {
18
44
  OnSendTo3rdParty?: ViewerCallback;
19
45
  OnShare?: ViewerCallback;
20
46
  OnShareToMobile?: ViewerCallback;
47
+ OnInteractionReady?: ViewerCallback;
48
+ OnViewerLoaded?: ViewerCallback<void, [Viewer3crService]>;
49
+ ShowFileMenu?: boolean;
50
+ ShowSettingsMenu?: boolean;
51
+ ShowAiMenu?: boolean;
52
+ Show2x2Layout?: boolean;
53
+ Show1x3Layout?: boolean;
54
+ ShowTutorial?: boolean;
55
+ ShowResetScan?: boolean;
56
+ ShowEnableCloudStorage?: boolean;
57
+ ShowSendTo3rdParty?: boolean;
58
+ ShowShareToMobile?: boolean;
59
+ ShowScreenshot?: boolean;
21
60
  }
22
61
 
23
62
  export const defaultLoadViewerOptions: LoadViewerOptions = {
@@ -8,13 +8,6 @@ export interface MftpDecryptionKey {
8
8
  Iv: string;
9
9
  }
10
10
 
11
- export const defaultLoadViewerPayload_old: LoadViewerPayload = {
12
- Url: 'https://webgl-3dr.singular.health/demo/scans/chest.3vxl',
13
- DecryptionKey: {
14
- Iv: 'XEloSh+OcO7TG77au6HjPw==',
15
- Key: 'KUc722X1y4w42M+jCf9a3+6EGz66z7UMWK3m2aMqGxM='
16
- }
17
- };
18
11
  export const defaultLoadViewerPayload: LoadViewerPayload = {
19
12
  Url: 'https://webgl-3dr.singular.health/demo/scans/chest_v6.3vxl',
20
13
  DecryptionKey: {
@@ -22,7 +22,8 @@ import {
22
22
  ObjectColour,
23
23
  ObjectInvert,
24
24
  ObjectVisibility,
25
- ViewToggleData
25
+ ViewToggleData,
26
+ GraphicType
26
27
  } from '@3cr/types-ts';
27
28
  import { LoadViewerPayload } from '@/models/loadViewerPayload';
28
29
  import { currentColourPreset, previousLayout, transactionStarted } from '@/models/scanState';
@@ -338,6 +339,17 @@ export class Viewer3crService {
338
339
  });
339
340
  }
340
341
 
342
+ /**
343
+ * NC-08: Set Navigation Cube Face Graphics.
344
+ * @param type Face type of cube.
345
+ */
346
+ async setNavCubeGraphics(type: GraphicType): Promise<void> {
347
+ await this.sendPayload(FrontEndInterfaces.navigation_cube, NavigationCubeActions.nc08, {
348
+ Version: '0.0.1',
349
+ Value: type
350
+ });
351
+ }
352
+
341
353
  /**
342
354
  * SM-13: Pan the selected view to the left.
343
355
  * @param view The view.
@@ -0,0 +1,71 @@
1
+ import { McadObjectInteraction } from '@/types/mcad-object-interaction';
2
+ import { Interactiontype } from '@3cr/types-ts';
3
+ import { DataOverlay } from '@/types/data-overlay';
4
+ import { ref, watch, WatchStopHandle } from 'vue';
5
+ import { useAnnotations } from '@/composables/useAnnotations';
6
+ import { useMarkups } from '@/composables/useMarkups';
7
+ import { useMcadObjects } from '@/composables/useMcadObjects';
8
+ import { DataOverlayInteraction } from '@/types/data-overlay-interaction';
9
+
10
+ export function useDataOverlayTool() {
11
+ let _flag = false;
12
+ let _focused: DataOverlay | null = null;
13
+ let _handles: WatchStopHandle[] = [];
14
+
15
+ const { annotationEvent } = useAnnotations();
16
+ const { markupEvent } = useMarkups();
17
+ const { mcadObjectEvent } = useMcadObjects();
18
+ const selected = ref<DataOverlay | null>(null);
19
+
20
+ function activate(): void {
21
+ document.addEventListener('mousedown', onMouseDown);
22
+ document.addEventListener('mousemove', onMouseMove);
23
+ document.addEventListener('mouseup', onMouseUp);
24
+ _handles.push(
25
+ watch(annotationEvent, onInteraction),
26
+ watch(markupEvent, onInteraction),
27
+ watch(mcadObjectEvent, onMcadInteraction)
28
+ );
29
+ }
30
+
31
+ function deactivate(): void {
32
+ document.removeEventListener('mousedown', onMouseDown);
33
+ document.removeEventListener('mousemove', onMouseMove);
34
+ document.removeEventListener('mouseup', onMouseUp);
35
+ _handles.forEach((handle) => handle());
36
+ _handles = [];
37
+ selected.value = null;
38
+ }
39
+
40
+ function onMouseDown(): void {
41
+ _flag = true;
42
+ }
43
+
44
+ function onMouseMove(): void {
45
+ _flag = false;
46
+ }
47
+
48
+ function onMouseUp(): void {
49
+ if (_flag) {
50
+ selected.value = _focused;
51
+ }
52
+ }
53
+
54
+ function onInteraction(event: DataOverlayInteraction<DataOverlay> | null): void {
55
+ if (event?.Interaction === Interactiontype.HOVER_START) {
56
+ _focused = event.DataOverlay;
57
+ } else if (event?.Interaction === Interactiontype.HOVER_END) {
58
+ _focused = null;
59
+ }
60
+ }
61
+
62
+ function onMcadInteraction(event: McadObjectInteraction | null): void {
63
+ if (event?.Interaction === Interactiontype.HOVER_START) {
64
+ _focused = event.Mcad;
65
+ } else if (event?.Interaction === Interactiontype.HOVER_END) {
66
+ _focused = null;
67
+ }
68
+ }
69
+
70
+ return { selected, activate, deactivate };
71
+ }
@@ -0,0 +1,5 @@
1
+ import { DataOverlay } from '@/types/data-overlay';
2
+ import { DataOverlayData } from '@/types/data-overlay-data';
3
+ import { DataOverlayInteraction } from '@/types/data-overlay-interaction';
4
+
5
+ export type DataOverlayEvent<T extends DataOverlay> = DataOverlayData<DataOverlayInteraction<T>>;
@@ -6,6 +6,10 @@ export interface DataOverlayInfo {
6
6
  icon: string;
7
7
  title: string;
8
8
  subtitle?: string;
9
+ data?: {
10
+ key: string;
11
+ value: string;
12
+ }[];
9
13
  actions?: {
10
14
  url: string;
11
15
  description: string;
@@ -0,0 +1,4 @@
1
+ export enum DemoType {
2
+ Patient,
3
+ Licence
4
+ }
@@ -1,38 +0,0 @@
1
- <template>
2
- <Action :text="text" :icon="icon" :variant="variant" @click="hide" />
3
- </template>
4
-
5
- <script setup lang="ts">
6
- import { ScanView } from '@3cr/types-ts';
7
- import { useViewer3cr } from '@/composables/useViewer3cr';
8
- import { computed, ref } from 'vue';
9
- import { getViewName } from '@/models/scanState';
10
-
11
- interface Props {
12
- view: ScanView;
13
- variant?: 'button' | 'menu-item';
14
- }
15
- const isHidden = ref<boolean>(false);
16
-
17
- const props = withDefaults(defineProps<Props>(), {
18
- variant: 'button'
19
- });
20
-
21
- const icon = computed(() => {
22
- return isHidden.value ? 'visibility' : 'visibility_off';
23
- });
24
-
25
- const text = computed(() => {
26
- return isHidden.value ? `Show the ${getViewName(props.view)} view.` : `Hide the ${getViewName(props.view)} view.`;
27
- });
28
-
29
- const viewer3cr = useViewer3cr();
30
-
31
- async function hide(): Promise<void> {
32
- await viewer3cr.viewSelectionToggleView({
33
- View: props.view,
34
- Visibility: isHidden.value
35
- });
36
- isHidden.value = !isHidden.value;
37
- }
38
- </script>
@@ -1,104 +0,0 @@
1
- <template>
2
- <template v-for="[item, modal] of modals" :key="item">
3
- <data-overlay-modal :modal="modal" :item="item" />
4
- </template>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import { ref, watch } from 'vue';
9
- import { Interactiontype } from '@3cr/types-ts';
10
- import { DataOverlayInfo } from '@/types/data-overlay-info';
11
- import { DataOverlay } from '@/types/data-overlay';
12
- import { useMouse } from '@/composables/useMouse';
13
- import { useAnnotations } from '@/composables/useAnnotations';
14
- import { useMarkups } from '@/composables/useMarkups';
15
- import { useMcadObjects } from '@/composables/useMcadObjects';
16
- import { useEventListener } from '@/composables/useEventListener';
17
- import { GptService } from '@/services/gpt.service';
18
- import { GptResponsePayload } from '@/types/gpt-response-payload';
19
-
20
- useEventListener(document, 'mousedown', onMouseDown);
21
- const { x, y } = useMouse(document);
22
- const { annotationEvent } = useAnnotations();
23
- const { markupEvent } = useMarkups();
24
- const { mcadObjectEvent } = useMcadObjects();
25
-
26
- const modals = ref<Map<DataOverlayInfo, boolean>>(new Map<DataOverlayInfo, boolean>());
27
- const smartDescriptions = ref<Record<string, GptResponsePayload>>({});
28
-
29
- watch(
30
- annotationEvent,
31
- async (event) => {
32
- if (event?.Interaction === Interactiontype.POINTER_UP) {
33
- await generateSmartDescriptions(event.DataOverlay);
34
- const item = mapToDataOverlayModal(event.DataOverlay);
35
- modals.value.set(item, true);
36
- }
37
- },
38
- { immediate: true }
39
- );
40
-
41
- watch(
42
- markupEvent,
43
- async (event) => {
44
- if (event?.Interaction === Interactiontype.POINTER_UP) {
45
- await generateSmartDescriptions(event.DataOverlay);
46
- const item = mapToDataOverlayModal(event.DataOverlay);
47
- modals.value.set(item, true);
48
- }
49
- },
50
- { immediate: true }
51
- );
52
-
53
- watch(
54
- mcadObjectEvent,
55
- async (event) => {
56
- if (event?.Interaction === Interactiontype.POINTER_UP) {
57
- await generateSmartDescriptions(event.Mcad as any);
58
- const item = mapToDataOverlayModal(event.Mcad as any);
59
- modals.value.set(item, true);
60
- }
61
- },
62
- { immediate: true }
63
- );
64
-
65
- function onMouseDown(): void {
66
- for (const [key, value] of modals.value.entries()) {
67
- if (value) {
68
- modals.value.set(key, false);
69
- setTimeout(() => modals.value.delete(key), 500); // wait for animation
70
- }
71
- }
72
- }
73
-
74
- async function generateSmartDescriptions(overlay: DataOverlay): Promise<void> {
75
- const key = overlay.Title;
76
- if (!(key in smartDescriptions.value)) {
77
- const response = await GptService.Instantiate().GenerateAnnotations(key);
78
- smartDescriptions.value[key] = response.data;
79
- }
80
- }
81
-
82
- function mapToDataOverlayModal(overlay: DataOverlay): DataOverlayInfo {
83
- return {
84
- id: overlay.Id,
85
- title: overlay.Title,
86
- target: [x.value, y.value],
87
- data: [
88
- {
89
- icon: overlay.Description ? 'description' : 'psychology',
90
- title: overlay.Description ? 'Description' : 'Smart Description',
91
- subtitle: overlay.Description || smartDescriptions.value[overlay.Title].GptResponse
92
- },
93
- {
94
- icon: 'help',
95
- title: 'Resources',
96
- actions: overlay.CallToAction?.Actions.map((action) => ({
97
- url: action.ActionData.Url,
98
- description: action.ActionData.Description
99
- }))
100
- }
101
- ]
102
- };
103
- }
104
- </script>
@@ -1,33 +0,0 @@
1
- import DataOverlayModal from '@/components/views/modals/DataOverlayModal.vue';
2
- import { DataOverlayInfoFaker } from '@test/fakers/data-overlay-info.faker';
3
- import { mount } from '@vue/test-utils';
4
- import { VCard, VMenu } from 'vuetify/components';
5
-
6
- describe('DataOverlayInfo tests', () => {
7
- it('should mount', () => {
8
- const item = DataOverlayInfoFaker.random();
9
- const props = { item, modal: true };
10
- const wrapper = mount(DataOverlayModal, { props });
11
- expect(wrapper).toBeTruthy();
12
- });
13
-
14
- it('should open and close menu', async () => {
15
- const item = DataOverlayInfoFaker.random();
16
- const props = { item, modal: true };
17
- const wrapper = mount(DataOverlayModal, { props });
18
- const menu = wrapper.findComponent(VMenu);
19
- await menu.setValue(false);
20
- await wrapper.setProps({ modal: false });
21
- expect(wrapper.findComponent(VCard).isVisible()).toBeFalsy();
22
- });
23
-
24
- it('should open link', async () => {
25
- const item = DataOverlayInfoFaker.random(1);
26
- const props = { item, modal: true };
27
- const wrapper = mount(DataOverlayModal, { props });
28
- const card = wrapper.findComponent(VCard);
29
- const anchor = card.find('a');
30
- await anchor.trigger('click');
31
- expect(anchor.attributes('href')).toBe(item.data[0].actions![0].url);
32
- });
33
- });
@@ -1,93 +0,0 @@
1
- import { GptService } from '@/services/gpt.service';
2
- import { DOMWrapper, flushPromises, mount } from '@vue/test-utils';
3
- import { useAnnotations } from '@/composables/useAnnotations';
4
- import { DataOverlayInteractionFaker } from '@test/fakers/data-overlay-interaction.faker';
5
- import { Interactiontype } from '@3cr/types-ts';
6
- import { useMarkups } from '@/composables/useMarkups';
7
- import { McadObjectInteractionFaker } from '@test/fakers/mcad-object-interaction.faker';
8
- import { useMcadObjects } from '@/composables/useMcadObjects';
9
- import { VCard } from 'vuetify/components';
10
- import { GptResponsePayload } from '@/types/gpt-response-payload';
11
- import DataOverlayModalManager from '@/components/views/modals/DataOverlayModalManager.vue';
12
- import DataOverlayModal from '@/components/views/modals/DataOverlayModal.vue';
13
-
14
- const gpt: GptResponsePayload = {
15
- GptResponse: 'Example',
16
- FollowupQuestions: []
17
- };
18
-
19
- describe('DataOverlayModalManager tests', () => {
20
- beforeEach(() => {
21
- vi.spyOn(GptService.prototype, 'GenerateAnnotations').mockResolvedValue({ data: gpt } as any);
22
- });
23
-
24
- it('should mount', () => {
25
- const wrapper = mount(DataOverlayModalManager);
26
- expect(wrapper).toBeTruthy();
27
- });
28
-
29
- it('should display annotation on pointer up', async () => {
30
- const event = DataOverlayInteractionFaker.annotation(Interactiontype.POINTER_UP);
31
- const { annotationEvent } = useAnnotations();
32
- vi.spyOn(annotationEvent, 'value', 'get').mockReturnValue(event);
33
-
34
- const wrapper = mount(DataOverlayModalManager);
35
- await flushPromises();
36
- expect(wrapper.findComponent(DataOverlayModal).exists()).toBeTruthy();
37
- });
38
-
39
- it('should display markup on pointer up', async () => {
40
- const event = DataOverlayInteractionFaker.polygon(Interactiontype.POINTER_UP);
41
- const { markupEvent } = useMarkups();
42
- vi.spyOn(markupEvent, 'value', 'get').mockReturnValue(event);
43
-
44
- const wrapper = mount(DataOverlayModalManager);
45
- await flushPromises();
46
- expect(wrapper.findComponent(DataOverlayModal).exists()).toBeTruthy();
47
- });
48
-
49
- it('should display mcad on pointer up', async () => {
50
- const event = McadObjectInteractionFaker.random(Interactiontype.POINTER_UP);
51
- const { mcadObjectEvent } = useMcadObjects();
52
- vi.spyOn(mcadObjectEvent, 'value', 'get').mockReturnValue(event);
53
-
54
- const wrapper = mount(DataOverlayModalManager);
55
- await flushPromises();
56
- expect(wrapper.findComponent(DataOverlayModal).exists()).toBeTruthy();
57
- });
58
-
59
- it('should generate smart description if none provided', async () => {
60
- const event = DataOverlayInteractionFaker.annotation(Interactiontype.POINTER_UP);
61
- event.DataOverlay.Description = '';
62
- const { annotationEvent } = useAnnotations();
63
- vi.spyOn(annotationEvent, 'value', 'get').mockReturnValue(event);
64
-
65
- const wrapper = mount(DataOverlayModalManager);
66
- await flushPromises();
67
- expect(wrapper.findComponent(VCard).text()).toContain('Smart Description');
68
- });
69
-
70
- describe('timed tests', () => {
71
- beforeEach(() => {
72
- vi.useFakeTimers();
73
- });
74
-
75
- afterEach(() => {
76
- vi.useRealTimers();
77
- });
78
-
79
- it('should dismiss modal on mousedown', async () => {
80
- const event = DataOverlayInteractionFaker.annotation(Interactiontype.POINTER_UP);
81
- const { annotationEvent } = useAnnotations();
82
- vi.spyOn(annotationEvent, 'value', 'get').mockReturnValue(event);
83
-
84
- const wrapper = mount(DataOverlayModalManager);
85
- await flushPromises();
86
-
87
- await new DOMWrapper(document).trigger('mousedown');
88
- vi.advanceTimersByTime(500);
89
- await flushPromises();
90
- expect(wrapper.findComponent(DataOverlayModal).exists()).toBeFalsy();
91
- });
92
- });
93
- });