From cba88a8dc8ac048533a56f777783bfdca9c5741e Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Mon, 26 Aug 2024 11:52:45 +0200 Subject: [PATCH] feat: cheat code, remove complex experiiment flag set fix: deployment scripts fix: siibra-api 0.3.18 point assignment shape update --- .github/workflows/deploy-helm.yml | 2 + backend/app/config.py | 2 - backend/app/const.py | 1 - backend/app/index_html.py | 7 +- common/constants.js | 1 - docs/releases/v2.14.10.md | 12 +++ mkdocs.yml | 1 + package.json | 2 +- src/atlasComponents/sapi/sapi.service.ts | 9 +-- src/atlasComponents/sapi/translateV3.ts | 33 ++++++++- .../point-assignment.component.html | 6 +- .../point-assignment.component.ts | 11 ++- src/experimental/experimental.module.ts | 73 +++++++++++++++++++ src/main.module.ts | 12 +-- .../topMenu/topMenuCmp/topMenu.components.ts | 17 ++--- .../topMenu/topMenuCmp/topMenu.template.html | 2 +- .../nehuba/base.service/base.service.ts | 7 +- .../viewerCmp/viewerCmp.component.ts | 25 ++++++- .../viewerCmp/viewerCmp.template.html | 2 +- 19 files changed, 179 insertions(+), 46 deletions(-) create mode 100644 docs/releases/v2.14.10.md create mode 100644 src/experimental/experimental.module.ts diff --git a/.github/workflows/deploy-helm.yml b/.github/workflows/deploy-helm.yml index fe8c4c144..09b6a70f7 100644 --- a/.github/workflows/deploy-helm.yml +++ b/.github/workflows/deploy-helm.yml @@ -70,6 +70,7 @@ jobs: --set image.tag=${{ inputs.IMAGE_TAG }} \ --set podLabels.image-digest=${{ inputs.IMAGE_DIGEST }} \ --set envObj.HOST_PATHNAME=/viewer-staging \ + --set envObj.OVERWRITE_API_ENDPOINT="https://siibra-api-rc.apps.tc.humanbrainproject.eu/v3_0" \ ${{ inputs.DEPLOYMENT_NAME }} .helm/siibra-explorer/ rm $kubecfg_path @@ -91,6 +92,7 @@ jobs: --reuse-values \ --set image.tag=${{ inputs.IMAGE_TAG }} \ --set podLabels.image-digest=${{ inputs.IMAGE_DIGEST }} \ + --set envObj.OVERWRITE_API_ENDPOINT="https://siibra-api-rc.apps.tc.humanbrainproject.eu/v3_0" \ ${{ inputs.DEPLOYMENT_NAME }} .helm/siibra-explorer/ \ || helm --kubeconfig=$kubecfg_path \ install\ diff --git a/backend/app/config.py b/backend/app/config.py index 42ddbaace..54cac5d13 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -8,8 +8,6 @@ OVERWRITE_API_ENDPOINT = os.getenv("OVERWRITE_API_ENDPOINT") OVERWRITE_SPATIAL_ENDPOINT = os.getenv("OVERWRITE_SPATIAL_ENDPOINT") -EXPERIMENTAL_FLAG = os.getenv("EXPERIMENTAL_FLAG") - LOCAL_CDN = os.getenv("LOCAL_CDN") HBP_CLIENTID_V2 = os.getenv("HBP_CLIENTID_V2", "no hbp id") diff --git a/backend/app/const.py b/backend/app/const.py index 071545dee..75a3094ac 100644 --- a/backend/app/const.py +++ b/backend/app/const.py @@ -22,4 +22,3 @@ OVERWRITE_SAPI_ENDPOINT_ATTR = "x-sapi-base-url" OVERWRITE_SPATIAL_BACKEND_ATTR = "x-spatial-backend-url" -OVERWRITE_EXPERIMENTAL_FLAG_ATTR = "x-experimental-flag" diff --git a/backend/app/index_html.py b/backend/app/index_html.py index c054d76ca..339a69efa 100644 --- a/backend/app/index_html.py +++ b/backend/app/index_html.py @@ -2,8 +2,8 @@ from fastapi import APIRouter, Request from pathlib import Path from fastapi.responses import Response from typing import Dict -from .const import ERROR_KEY, DATA_ERROR_ATTR, OVERWRITE_SAPI_ENDPOINT_ATTR, COOKIE_KWARGS, OVERWRITE_SPATIAL_BACKEND_ATTR, OVERWRITE_EXPERIMENTAL_FLAG_ATTR -from .config import PATH_TO_PUBLIC, OVERWRITE_API_ENDPOINT, OVERWRITE_SPATIAL_ENDPOINT, EXPERIMENTAL_FLAG +from .const import ERROR_KEY, DATA_ERROR_ATTR, OVERWRITE_SAPI_ENDPOINT_ATTR, COOKIE_KWARGS, OVERWRITE_SPATIAL_BACKEND_ATTR +from .config import PATH_TO_PUBLIC, OVERWRITE_API_ENDPOINT, OVERWRITE_SPATIAL_ENDPOINT path_to_index = Path(PATH_TO_PUBLIC) / "index.html" index_html: str = None @@ -35,9 +35,6 @@ async def get_index_html(request: Request): if OVERWRITE_SPATIAL_ENDPOINT: attributes_to_append[OVERWRITE_SPATIAL_BACKEND_ATTR] = OVERWRITE_SPATIAL_ENDPOINT - if EXPERIMENTAL_FLAG: - attributes_to_append[OVERWRITE_EXPERIMENTAL_FLAG_ATTR] = EXPERIMENTAL_FLAG - attr_string = " ".join([f'{key}="{_monkey_sanitize(value)}"' for key, value in attributes_to_append.items()]) resp_string = index_html.replace("<atlas-viewer>", f"<atlas-viewer {attr_string}>") diff --git a/common/constants.js b/common/constants.js index 0e9f6b312..4ddf69753 100644 --- a/common/constants.js +++ b/common/constants.js @@ -151,7 +151,6 @@ If you do not accept the Terms & Conditions you are not permitted to access or u OVERWRITE_SAPI_ENDPOINT_ATTR: `x-sapi-base-url`, OVERWRITE_SPATIAL_BACKEND_ATTR: `x-spatial-backend-url`, - OVERWRITE_EXPERIMENTAL_FLAG_ATTR: `x-experimental-flag`, DATA_ERROR_ATTR: `data-error`, } diff --git a/docs/releases/v2.14.10.md b/docs/releases/v2.14.10.md new file mode 100644 index 000000000..4b9bccc5b --- /dev/null +++ b/docs/releases/v2.14.10.md @@ -0,0 +1,12 @@ +# v2.14.10 + +## Bugfix + +- Fix deployment scripts +- Fix region update to updated siibra-api endpoint + +## Behind the scenes + +- Re-enable siibra-api warning mismatch warning +- Adapt to siibra-api v0.3.18 point assignment rhetoric +- Enable cheat code, removing obsolete experimental flags diff --git a/mkdocs.yml b/mkdocs.yml index e23407216..e867e6f3e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ nav: - Differential gene expression analysis: "advanced/differential_gene_expression_analysis.md" - Release notes: + - v2.14.10: 'releases/v2.14.10.md' - v2.14.9: 'releases/v2.14.9.md' - v2.14.8: 'releases/v2.14.8.md' - v2.14.7: 'releases/v2.14.7.md' diff --git a/package.json b/package.json index 0d8728b4f..3a703dce6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "siibra-explorer", - "version": "2.14.9", + "version": "2.14.10", "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular", "scripts": { "lint": "eslint src --ext .ts", diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts index 0d35f90f5..f191d042f 100644 --- a/src/atlasComponents/sapi/sapi.service.ts +++ b/src/atlasComponents/sapi/sapi.service.ts @@ -20,7 +20,7 @@ export const useViewer = { } as const export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version' -export const EXPECTED_SIIBRA_API_VERSION = '0.3.16' +export const EXPECTED_SIIBRA_API_VERSION = '0.3.18' type PaginatedResponse<T> = { items: T[] @@ -286,11 +286,10 @@ export class SAPI{ tap(() => { const respVersion = SAPI.API_VERSION if (respVersion !== EXPECTED_SIIBRA_API_VERSION) { - // TODO temporarily disable snackbar. Enable once siibra-api version stabilises console.log(`Expecting ${EXPECTED_SIIBRA_API_VERSION}, got ${respVersion}. Some functionalities may not work as expected.`) - // this.snackbar.open(`Expecting ${EXPECTED_SIIBRA_API_VERSION}, got ${respVersion}. Some functionalities may not work as expected.`, 'Dismiss', { - // duration: 5000 - // }) + this.snackbar.open(`Expecting ${EXPECTED_SIIBRA_API_VERSION}, got ${respVersion}. Some functionalities may not work as expected.`, 'Dismiss', { + duration: 5000 + }) } }), shareReplay(1), diff --git a/src/atlasComponents/sapi/translateV3.ts b/src/atlasComponents/sapi/translateV3.ts index ff48d7125..9c6f8c5c8 100644 --- a/src/atlasComponents/sapi/translateV3.ts +++ b/src/atlasComponents/sapi/translateV3.ts @@ -272,7 +272,7 @@ class TranslateV3 { id: region["@id"], name: region.name, color: hexToRgb(region.hasAnnotation?.displayColor) as [number, number, number], - parentIds: region.hasParent.map( v => v["@id"] ), + parentIds: (region.hasParent || []).map( v => v["@id"] ), type: "SxplrRegion", centroid: bestViewPoint ? { @@ -771,3 +771,34 @@ class TranslateV3 { } export const translateV3Entities = new TranslateV3() + + +// TODO +// >= 0.3.18 siibra-api /maps endpoint populates *both* full region name as well as short names +// This is a side effect of mixing both versions of siibra-python. +// and expected to end at >= 0.4. By then, restore this warning for debugging purposes + +const REMOVE_FROM_NAMES = [ + "hemisphere", + " -", + "-brain", + "both", + "Both", +] +const REPLACE_IN_NAME = { + "ctx-lh-": "left ", + "ctx-rh-": "right ", +} + +export function translateRegionName(fullRegionName: string): string { + let returnName = fullRegionName + for (const rm of REMOVE_FROM_NAMES) { + returnName = returnName.replace(rm , "") + } + for (const key in REPLACE_IN_NAME){ + returnName = returnName.replace(key, REPLACE_IN_NAME[key]) + } + return returnName.trim() +} + +// end TODO diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html index b77d79655..31b58dd51 100644 --- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html +++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.html @@ -74,7 +74,7 @@ <!-- {{ element | json }} --> <button mat-button (click)="selectRegion(element['region'], $event)" class="ws-no-wrap"> - {{ element['region'].name }} + {{ element['region'] }} </button> </td> </ng-container> @@ -83,7 +83,7 @@ map value </th> <td mat-cell *matCellDef="let element"> - {{ element['map value'] | prettyPresent }} + {{ element['map_value'] | prettyPresent }} </td> </ng-container> @@ -108,7 +108,7 @@ <td mat-cell *matCellDef="let element"> <button mat-button (click)="selectRegion(element['region'], $event)" class="ws-no-wrap"> - {{ element['region'].name }} + {{ element['region'] }} </button> </td> </ng-container> diff --git a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts index e7eec1fe0..b901c539e 100644 --- a/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts +++ b/src/atlasComponents/sapiViews/volumes/point-assignment/point-assignment.component.ts @@ -3,8 +3,8 @@ import { Clipboard, MatDialog, MatDialogRef, MatSnackBar } from 'src/sharedModul import { BehaviorSubject, EMPTY, Observable, Subscription, combineLatest, concat, of } from 'rxjs'; import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators'; import { SAPI, EXPECTED_SIIBRA_API_VERSION } from 'src/atlasComponents/sapi/sapi.service'; -import { SxplrParcellation, SxplrRegion, SxplrTemplate } from 'src/atlasComponents/sapi/sxplrTypes'; -import { translateV3Entities } from 'src/atlasComponents/sapi/translateV3'; +import { SxplrParcellation, SxplrTemplate } from 'src/atlasComponents/sapi/sxplrTypes'; +import { translateRegionName } from 'src/atlasComponents/sapi/translateV3'; import { PathReturn } from 'src/atlasComponents/sapi/typeV3'; import { TFace, TSandsPoint } from 'src/util/types'; import { TZipFileConfig } from "src/zipFilesOutput/type" @@ -56,7 +56,7 @@ export class PointAssignmentComponent implements OnDestroy { } @Output() - clickOnRegion = new EventEmitter<{ target: SxplrRegion, event: MouseEvent }>() + clickOnRegionName = new EventEmitter<{ target: string, event: MouseEvent }>() df$: Observable<PathReturn<"/map/assign">> = combineLatest([ this.point$, @@ -131,9 +131,8 @@ export class PointAssignmentComponent implements OnDestroy { ngOnDestroy(): void { while (this.#sub.length > 0) this.#sub.pop().unsubscribe() } - async selectRegion(region: PathReturn<"/regions/{region_id}">, event: MouseEvent){ - const sxplrReg = await translateV3Entities.translateRegion(region) - this.clickOnRegion.emit({ target: sxplrReg, event }) + selectRegion(regionName: string, event: MouseEvent){ + this.clickOnRegionName.emit({ target: translateRegionName(regionName), event }) if (this.#dialogRef) { this.#dialogRef.close() } diff --git a/src/experimental/experimental.module.ts b/src/experimental/experimental.module.ts new file mode 100644 index 000000000..d7682ef0d --- /dev/null +++ b/src/experimental/experimental.module.ts @@ -0,0 +1,73 @@ +import { DOCUMENT } from "@angular/common"; +import { APP_INITIALIZER, InjectionToken, NgModule } from "@angular/core"; +import { BehaviorSubject, fromEvent, Observable } from "rxjs"; +import { filter, scan, take } from "rxjs/operators"; + +const CODE_DICT = { + ArrowUp: "ArrowUp", + ArrowDown: "ArrowDown", + ArrowLeft: "ArrowLeft", + ArrowRight: "ArrowRight", + b: "b", + a: "a", +} as const + +const CODE = [ + CODE_DICT.ArrowUp, + CODE_DICT.ArrowUp, + CODE_DICT.ArrowDown, + CODE_DICT.ArrowDown, + CODE_DICT.ArrowLeft, + CODE_DICT.ArrowRight, + CODE_DICT.ArrowLeft, + CODE_DICT.ArrowRight, + CODE_DICT.b, + CODE_DICT.a, +] + +function isKCode(input: string): input is (keyof typeof CODE_DICT) { + return input in CODE_DICT +} + +function isNextKCode(current: (keyof typeof CODE_DICT)[], input: keyof typeof CODE_DICT): boolean { + return CODE[current.length] === input +} + +export const SHOW_EXPERIMENTAL_TOKEN = new InjectionToken<Observable<boolean>>("SHOW_EXPERIMENTAL_TOKEN") + +const showXmptToggle = new BehaviorSubject<boolean>(false) + +@NgModule({ + providers: [ + { + provide: APP_INITIALIZER, + useFactory: (document: Document) => { + fromEvent(document, "keydown", { capture: true }).pipe( + scan((acc, curr: KeyboardEvent) => { + const key = curr.key + if (!isKCode(key)) { + return [] + } + if (!isNextKCode(acc, key)) { + return [] + } + return [...acc, key] + }, [] as (keyof typeof CODE_DICT)[]), + filter(code => code.length === CODE.length), + take(1) + ).subscribe(() => { + showXmptToggle.next(true) + }) + return () => Promise.resolve() + }, + multi: true, + deps: [DOCUMENT] + }, + { + provide: SHOW_EXPERIMENTAL_TOKEN, + useValue: showXmptToggle.asObservable() + } + ] +}) + +export class KCodeModule{} diff --git a/src/main.module.ts b/src/main.module.ts index aedbee438..2c59072d7 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -40,7 +40,6 @@ import { atlasSelection, RootStoreModule, getStoreEffects, - userPreference, } from "./state" import { DARKTHEME } from './util/injectionTokens'; import { map } from 'rxjs/operators'; @@ -54,6 +53,7 @@ import { ViewerCommonEffects } from './viewerModule'; import { environment } from './environments/environment'; import { SAPI } from './atlasComponents/sapi'; import { GET_ATTR_TOKEN, GetAttr } from './util/constants'; +import { KCodeModule } from "./experimental/experimental.module" @NgModule({ imports: [ @@ -85,6 +85,7 @@ import { GET_ATTR_TOKEN, GetAttr } from './util/constants'; ]), RootStoreModule, HttpClientModule, + KCodeModule, ], declarations: [ AtlasViewer, @@ -176,17 +177,12 @@ import { GET_ATTR_TOKEN, GetAttr } from './util/constants'; }, { provide: APP_INITIALIZER, - useFactory: (authSvc: AuthService, store: Store) => { - window['setExperimentalFlag'] = (flag: boolean) => { - store.dispatch(userPreference.actions.setShowExperimental({ - flag - })) - } + useFactory: (authSvc: AuthService) => { authSvc.authReloadState() return () => Promise.resolve() }, multi: true, - deps: [ AuthService, Store ] + deps: [ AuthService ] }, { provide: GET_ATTR_TOKEN, diff --git a/src/ui/topMenu/topMenuCmp/topMenu.components.ts b/src/ui/topMenu/topMenuCmp/topMenu.components.ts index 4adf087fe..1239ed800 100644 --- a/src/ui/topMenu/topMenuCmp/topMenu.components.ts +++ b/src/ui/topMenu/topMenuCmp/topMenu.components.ts @@ -3,9 +3,10 @@ import { Component, Inject, Input, + Optional, TemplateRef, } from "@angular/core"; -import { Observable } from "rxjs"; +import { Observable, of } from "rxjs"; import { map } from "rxjs/operators"; import { AuthService } from "src/auth"; import { MatBottomSheet, MatDialog, MatDialogConfig, MatDialogRef } from 'src/sharedModules/angularMaterial.exports' @@ -15,7 +16,7 @@ import { TypeMatBtnColor, TypeMatBtnStyle } from "src/components/dynamicMaterial import { select, Store } from "@ngrx/store"; import { userPreference } from "src/state"; import { environment } from "src/environments/environment" -import { GET_ATTR_TOKEN, GetAttr } from "src/util/constants"; +import { SHOW_EXPERIMENTAL_TOKEN } from "src/experimental/experimental.module"; @Component({ selector: 'top-menu-cmp', @@ -28,7 +29,10 @@ import { GET_ATTR_TOKEN, GetAttr } from "src/util/constants"; export class TopMenuCmp { - public showExperimentalToggle = environment.EXPERIMENTAL_FEATURE_FLAG + public showExptToggle$ = environment.EXPERIMENTAL_FEATURE_FLAG + ? of (true) + : (this.showXplrToggle$ || of(false)) + setExperimentalFlag(flag: boolean){ this.store.dispatch( userPreference.actions.setShowExperimental({ @@ -86,15 +90,10 @@ export class TopMenuCmp { private authService: AuthService, private dialog: MatDialog, public bottomSheet: MatBottomSheet, - @Inject(GET_ATTR_TOKEN) getAttr: GetAttr + @Optional() @Inject(SHOW_EXPERIMENTAL_TOKEN) private showXplrToggle$: Observable<boolean>, ) { this.user$ = this.authService.user$ - const experimentalFlag = getAttr(CONST.OVERWRITE_EXPERIMENTAL_FLAG_ATTR) - if (experimentalFlag) { - this.showExperimentalToggle = !!experimentalFlag - } - this.userBtnTooltip$ = this.user$.pipe( map(user => user ? `Logged in as ${(user && user.name) ? user.name : 'Unknown name'}` diff --git a/src/ui/topMenu/topMenuCmp/topMenu.template.html b/src/ui/topMenu/topMenuCmp/topMenu.template.html index 43d695b91..3334ea58e 100644 --- a/src/ui/topMenu/topMenuCmp/topMenu.template.html +++ b/src/ui/topMenu/topMenuCmp/topMenu.template.html @@ -159,7 +159,7 @@ </div> </ng-template> - <ng-template [ngIf]="showExperimentalToggle"> + <ng-template [ngIf]="showExptToggle$ | async"> <ng-template [ngTemplateOutlet]="toggleBtnTmpl" [ngTemplateOutletContext]="{$implicit: experimentalFlag$ | async}"> </ng-template> diff --git a/src/viewerModule/nehuba/base.service/base.service.ts b/src/viewerModule/nehuba/base.service/base.service.ts index a6bfe046a..5f825da7c 100644 --- a/src/viewerModule/nehuba/base.service/base.service.ts +++ b/src/viewerModule/nehuba/base.service/base.service.ts @@ -49,7 +49,12 @@ export class BaseService { for (const { name, label } of region) { const actualRegion = regionmap.get(name) || (() => { - console.log(`region with name ${name} cannot be found. Viewer may not behave properly`) + // TODO + // >= 0.3.18 siibra-api /maps endpoint populates *both* full region name as well as short names + // This is a side effect of mixing both versions of siibra-python. + // and expected to end at >= 0.4. By then, restore this warning for debugging purposes + + // console.log(`region with name ${name} cannot be found. Viewer may not behave properly`) return { name, id: '', parentIds: [], type: 'SxplrRegion' } })() const ngId = getParcNgId(atlas, template, parcellation, actualRegion) diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts index ac84f5c6e..35639ce12 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.component.ts +++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, TemplateRef, ViewChild, inject } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { BehaviorSubject, combineLatest, Observable, of } from "rxjs"; -import { debounceTime, distinctUntilChanged, map, shareReplay, switchMap, takeUntil } from "rxjs/operators"; +import { debounceTime, distinctUntilChanged, map, shareReplay, switchMap, take, takeUntil } from "rxjs/operators"; import { CONST, ARIA_LABELS, QUICKTOUR_DESC } from 'common/constants' import { animate, state, style, transition, trigger } from "@angular/animations"; import { IQuickTourData } from "src/ui/quickTour"; @@ -16,6 +16,7 @@ import { EntryComponent } from "src/features/entry/entry.component"; import { TFace, TSandsPoint, getCoord } from "src/util/types"; import { wait } from "src/util/fn"; import { DestroyDirective } from "src/util/directives/destroy.directive"; +import { generalActionError } from "src/state/actions"; interface HasName { name: string @@ -542,6 +543,28 @@ export class ViewerCmp { this.controlHalfNav(false) } + async handleClickOnRegionName(regionName: string, event: MouseEvent){ + const regions = await this.store$.pipe( + select(atlasSelection.selectors.selectedParcAllRegions), + take(1) + ).toPromise() + + const foundRegion = regions.find(r => r.name === regionName) + if (!foundRegion) { + this.store$.dispatch( + generalActionError({ + message: `Region with name ${regionName} not found.` + }) + ) + return + } + if (event.ctrlKey) { + this.toggleRoi(foundRegion) + } else { + this.selectRoi(foundRegion) + } + } + nameEql(a: HasName, b: HasName){ return a.name === b.name } diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index b837c843a..fcd679e41 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -861,7 +861,7 @@ [point]="view.selectedPoint" [template]="view.selectedTemplate" [parcellation]="view.selectedParcellation" - (clickOnRegion)="$event.event.ctrlKey ? toggleRoi($event.target) : selectRoi($event.target)"> + (clickOnRegionName)="handleClickOnRegionName($event.target, $event.event)"> </sxplr-point-assignment> </ng-template> -- GitLab