diff --git a/src/atlasViewer/atlasViewer.apiService.service.spec.ts b/src/atlasViewer/atlasViewer.apiService.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f4d4c0de6d513a0ebad97e81bb8a9f107a201a7 --- /dev/null +++ b/src/atlasViewer/atlasViewer.apiService.service.spec.ts @@ -0,0 +1,55 @@ +import {} from 'jasmine' +import {AtlasViewerAPIServices} from "src/atlasViewer/atlasViewer.apiService.service"; +import {async, TestBed} from "@angular/core/testing"; +import {provideMockActions} from "@ngrx/effects/testing"; +import {provideMockStore} from "@ngrx/store/testing"; +import {defaultRootState} from "src/services/stateStore.service"; +import {Observable, of} from "rxjs"; +import {Action} from "@ngrx/store"; +import {AngularMaterialModule} from "src/ui/sharedModules/angularMaterial.module"; +const actions$: Observable<Action> = of({type: 'TEST'}) + + + +describe('atlasViewer.apiService.service.ts', () => { + describe('getUserToSelectARegion', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + AngularMaterialModule, + ], + providers: [ + AtlasViewerAPIServices, + provideMockActions(() => actions$), + provideMockStore({initialState: defaultRootState}) + ] + }) + })) + + it('should return value on resolve', async () => { + const regionToSend = 'test-region' + let sentData: any + const apiService = TestBed.get(AtlasViewerAPIServices) + const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') + apiService.getUserToSelectARegionResolve(regionToSend) + await callApi.then(r => { + sentData = r + }) + expect(sentData).toEqual(regionToSend) + }) + + it('pluginRegionSelectionEnabled should false after resolve', async () => { + const { uiState } = defaultRootState + const regionToSend = 'test-region' + let sentData: any + const apiService = TestBed.get(AtlasViewerAPIServices) + const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') + apiService.getUserToSelectARegionResolve(regionToSend) + await callApi.then(r => { + sentData = r + }) + expect(uiState.pluginRegionSelectionEnabled).toBe(false) + }) + }) +}) \ No newline at end of file diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index c68c60bf953f2cd2951278dab547dbd3a17d5460..29adf10bd34b9e12f7ee082cb9e904bd4e6d0573 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -4,10 +4,17 @@ import { Observable } from "rxjs"; import { distinctUntilChanged, map, filter } from "rxjs/operators"; import { DialogService } from "src/services/dialogService.service"; import { LoggingService } from "src/services/logging.service"; -import { getLabelIndexMap, getMultiNgIdsRegionsLabelIndexMap, IavRootStoreInterface, safeFilter } from "src/services/stateStore.service"; +import { + DISABLE_PLUGIN_REGION_SELECTION, + getLabelIndexMap, + getMultiNgIdsRegionsLabelIndexMap, + IavRootStoreInterface, + safeFilter +} from "src/services/stateStore.service"; import { ModalHandler } from "../util/pluginHandlerClasses/modalHandler"; import { ToastHandler } from "../util/pluginHandlerClasses/toastHandler"; import { IPluginManifest } from "./atlasViewer.pluginService.service"; +import {ENABLE_PLUGIN_REGION_SELECTION} from "src/services/state/uiState.store"; declare let window @@ -23,6 +30,9 @@ export class AtlasViewerAPIServices { public loadedLibraries: Map<string, {counter: number, src: HTMLElement|null}> = new Map() + public getUserToSelectARegionResolve + public getUserToSelectARegionReject + constructor( private store: Store<IavRootStoreInterface>, private dialogService: DialogService, @@ -118,8 +128,27 @@ export class AtlasViewerAPIServices { return Promise.reject('Needs to be overwritted') }, - getUserInput: config => this.dialogService.getUserInput(config), + getUserInput: config => this.dialogService.getUserInput(config) , getUserConfirmation: config => this.dialogService.getUserConfirm(config), + + getUserToSelectARegion: (selectingMessage) => new Promise((resolve, reject) => { + this.store.dispatch({ + type: ENABLE_PLUGIN_REGION_SELECTION, + payload: selectingMessage + }) + + this.getUserToSelectARegionResolve = resolve + this.getUserToSelectARegionReject = reject + }), + + // ToDo Method should be able to cancel any pending promise. + cancelPromise: (pr) => { + if (pr === this.interactiveViewer.uiHandle.getUserToSelectARegion) { + if (this.getUserToSelectARegionReject) this.getUserToSelectARegionReject('Rej') + this.store.dispatch({type: DISABLE_PLUGIN_REGION_SELECTION}) + } + } + }, pluginControl : { loadExternalLibraries : () => Promise.reject('load External Library method not over written') @@ -205,6 +234,8 @@ export interface IInteractiveViewerInterface { launchNewWidget: (manifest: IPluginManifest) => Promise<any> getUserInput: (config: IGetUserInputConfig) => Promise<string> getUserConfirmation: (config: IGetUserConfirmation) => Promise<any> + getUserToSelectARegion: (selectingMessage: any) => Promise<any> + cancelPromise: (pr) => void } pluginControl: { diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index eb71bfd07cc1754ed2be6b759e6a63fa87b44be4..7b2659e3cfb08e3ecb498db89a99cb0e8502e6a0 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -1,5 +1,5 @@ import { - AfterViewInit, + AfterViewInit, ChangeDetectorRef, Component, HostBinding, OnDestroy, @@ -117,6 +117,11 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { public onhoverSegmentsForFixed$: Observable<string[]> + private pluginRegionSelectionEnabled$: Observable<boolean> + private pluginRegionSelectionEnabled: boolean = false + private persistentStateNotifierTemplate$: Observable<string> + // private pluginRegionSelectionEnabled: boolean = false + constructor( private store: Store<IavRootStoreInterface>, private widgetServices: WidgetServices, @@ -129,6 +134,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { private snackbar: MatSnackBar, private bottomSheet: MatBottomSheet, private log: LoggingService, + private changeDetectorRef: ChangeDetectorRef, ) { this.snackbarMessage$ = this.store.pipe( @@ -136,6 +142,17 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { select("snackbarMessage"), ) + this.pluginRegionSelectionEnabled$ = this.store.pipe( + select('uiState'), + select("pluginRegionSelectionEnabled"), + distinctUntilChanged(), + ) + this.persistentStateNotifierTemplate$ = this.store.pipe( + select('uiState'), + select("persistentStateNotifierTemplate"), + distinctUntilChanged(), + ) + this.bottomSheet$ = this.store.pipe( select('uiState'), select('bottomSheetTemplate'), @@ -279,6 +296,10 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { } }), ) + + this.onhoverSegments$.subscribe(hr => { + this.hoveringRegions = hr + }) } private selectedParcellation$: Observable<any> @@ -361,6 +382,13 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { this.rd.setAttribute(document.body, 'darktheme', flag.toString()) }), ) + + this.subscriptions.push( + this.pluginRegionSelectionEnabled$.subscribe(PRSE => { + this.pluginRegionSelectionEnabled = PRSE + this.changeDetectorRef.detectChanges() + }) + ) } public ngAfterViewInit() { @@ -409,21 +437,26 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { withLatestFrom(this.onhoverSegments$), map(([_flag, onhoverSegments]) => onhoverSegments || []), ) - } + private hoveringRegions = [] + public mouseDownNehuba(_event) { this.rClContextualMenu.hide() } - public mouseUpNehuba(event) { + public mouseClickNehuba(event) { // if (this.mouseUpLeftPosition === event.pageX && this.mouseUpTopPosition === event.pageY) {} if (!this.rClContextualMenu) { return } this.rClContextualMenu.mousePos = [ event.clientX, event.clientY, ] - this.rClContextualMenu.show() + if (!this.pluginRegionSelectionEnabled) { + this.rClContextualMenu.show() + } else { + if (this.hoveringRegions) this.apiService.getUserToSelectARegionResolve(this.hoveringRegions) + } } public toggleSideNavMenu(opened) { diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index e10c82d4cb40aba6e2d08355fe4b161421587f37..edf1cb961d858435682c621d47b0add5c213db91 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -47,7 +47,7 @@ [currentOnHover]="iavMouseHoverEl.currentOnHoverObs$ | async" iav-captureClickListenerDirective (iav-captureClickListenerDirective-onMousedown)="mouseDownNehuba($event)" - (iav-captureClickListenerDirective-onClick)="mouseUpNehuba($event)"> + (iav-captureClickListenerDirective-onClick)="mouseClickNehuba($event)"> </ui-nehuba-container> <div class="z-index-10 position-absolute pe-none w-100 h-100"> @@ -108,6 +108,11 @@ </ng-container> </div> + <div class="fixed-top pe-none d-flex justify-content-center m-4" *ngIf="pluginRegionSelectionEnabled"> + <ng-container *ngTemplateOutlet="persistentStateNotifierTemplate"> + </ng-container> + </div> + <div floatingMouseContextualContainerDirective> <div *ngIf="!ismobile" @@ -204,4 +209,9 @@ <!-- logo tmpl --> <ng-template #logoTmpl> <logo-container></logo-container> -</ng-template> \ No newline at end of file +</ng-template> + +<ng-template #persistentStateNotifierTemplate> + <mat-card>{{persistentStateNotifierTemplate$ | async}}</mat-card> +</ng-template> + diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts index 595df963cc01870bd831a4f9abed7137184e9f99..18c29e926e90b85da53013c154f6c0ff4373f38a 100644 --- a/src/services/state/uiState.store.ts +++ b/src/services/state/uiState.store.ts @@ -23,6 +23,9 @@ export const defaultState: StateInterface = { bottomSheetTemplate: null, + pluginRegionSelectionEnabled: false, + persistentStateNotifierTemplate: null, + /** * replace with server side logic (?) */ @@ -105,6 +108,22 @@ export const getStateStore = ({ state = defaultState } = {}) => (prevState: Stat ...prevState, sidePanelCurrentViewContent: 'Dataset', } + + case ENABLE_PLUGIN_REGION_SELECTION: { + return { + ...prevState, + pluginRegionSelectionEnabled: true, + persistentStateNotifierTemplate: action.payload + } + } + case DISABLE_PLUGIN_REGION_SELECTION: { + return { + ...prevState, + pluginRegionSelectionEnabled: false, + persistentStateNotifierTemplate: null + } + } + case AGREE_COOKIE: { /** * TODO replace with server side logic @@ -168,6 +187,9 @@ export interface StateInterface { snackbarMessage: symbol + pluginRegionSelectionEnabled: boolean + persistentStateNotifierTemplate: TemplateRef<any> + agreedCookies: boolean agreedKgTos: boolean @@ -243,6 +265,9 @@ export const HIDE_SIDE_PANEL_CONNECTIVITY = `HIDE_SIDE_PANEL_CONNECTIVITY` export const COLLAPSE_SIDE_PANEL_CURRENT_VIEW = `COLLAPSE_SIDE_PANEL_CURRENT_VIEW` export const EXPAND_SIDE_PANEL_CURRENT_VIEW = `EXPAND_SIDE_PANEL_CURRENT_VIEW` +export const ENABLE_PLUGIN_REGION_SELECTION = `ENABLE_PLUGIN_REGION_SELECTION` +export const DISABLE_PLUGIN_REGION_SELECTION = `DISABLE_PLUGIN_REGION_SELECTION` + export const AGREE_COOKIE = `AGREE_COOKIE` export const AGREE_KG_TOS = `AGREE_KG_TOS` export const SHOW_KG_TOS = `SHOW_KG_TOS` diff --git a/src/services/stateStore.service.ts b/src/services/stateStore.service.ts index dadde7dc67e49a1d0d041f611a953aa825f432cc..7b490020bf309499cd51f81669cc2f4bc11a957c 100644 --- a/src/services/stateStore.service.ts +++ b/src/services/stateStore.service.ts @@ -52,7 +52,7 @@ export { userConfigState, USER_CONFIG_ACTION_TYPES} export { ADD_NG_LAYER, FORCE_SHOW_SEGMENT, HIDE_NG_LAYER, REMOVE_NG_LAYER, SHOW_NG_LAYER } from './state/ngViewerState.store' export { CHANGE_NAVIGATION, DESELECT_LANDMARKS, FETCHED_TEMPLATE, NEWVIEWER, SELECT_LANDMARKS, SELECT_PARCELLATION, SELECT_REGIONS, USER_LANDMARKS } from './state/viewerState.store' export { IDataEntry, IParcellationRegion, FETCHED_DATAENTRIES, FETCHED_SPATIAL_DATA, ILandmark, IOtherLandmarkGeometry, IPlaneLandmarkGeometry, IPointLandmarkGeometry, IProperty, IPublication, IReferenceSpace, IFile, IFileSupplementData } from './state/dataStore.store' -export { CLOSE_SIDE_PANEL, MOUSE_OVER_LANDMARK, MOUSE_OVER_SEGMENT, OPEN_SIDE_PANEL, SHOW_SIDE_PANEL_CONNECTIVITY, HIDE_SIDE_PANEL_CONNECTIVITY, COLLAPSE_SIDE_PANEL_CURRENT_VIEW, EXPAND_SIDE_PANEL_CURRENT_VIEW } from './state/uiState.store' +export { CLOSE_SIDE_PANEL, MOUSE_OVER_LANDMARK, MOUSE_OVER_SEGMENT, OPEN_SIDE_PANEL, SHOW_SIDE_PANEL_CONNECTIVITY, HIDE_SIDE_PANEL_CONNECTIVITY, COLLAPSE_SIDE_PANEL_CURRENT_VIEW, EXPAND_SIDE_PANEL_CURRENT_VIEW, ENABLE_PLUGIN_REGION_SELECTION, DISABLE_PLUGIN_REGION_SELECTION } from './state/uiState.store' export { UserConfigStateUseEffect } from './state/userConfigState.store' export const GENERAL_ACTION_TYPES = {