From fc5add9d042bbbac24b42751cd39b410f516984b Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Tue, 20 Oct 2020 12:11:18 +0200 Subject: [PATCH] bugfix: temporarily disable multiregion selection --- docs/releases/v2.3.0.md | 8 ++++ .../atlasViewer.history.service.spec.ts | 4 +- .../atlasViewer.history.service.ts | 8 +++- src/atlasViewer/atlasViewer.urlUtil.spec.ts | 40 +++++++++++++++++++ src/atlasViewer/atlasViewer.urlUtil.ts | 14 +++++-- .../sharedModules/angularMaterial.module.ts | 7 +++- 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/docs/releases/v2.3.0.md b/docs/releases/v2.3.0.md index a0c965335..85b6cf282 100644 --- a/docs/releases/v2.3.0.md +++ b/docs/releases/v2.3.0.md @@ -22,3 +22,11 @@ ## Under the hood stuff - Updated how dataset retrieval work. It will now query on a region basis + +## Breaking changes + +- Temporarily disabled multiregion selection + +> as a result of the UI overhaul, multi-region selection as it existed before will break the UI in several ways. As a result, it will be disabled temporarily until higher hierarchy region selection can be implemented properly. +> +> Any existing URL which points to a multi-region selection state will be shown a message `Selecting multiple regions has been temporarily disabled in v2.3.0` diff --git a/src/atlasViewer/atlasViewer.history.service.spec.ts b/src/atlasViewer/atlasViewer.history.service.spec.ts index 3e4bfb146..aec52f695 100644 --- a/src/atlasViewer/atlasViewer.history.service.spec.ts +++ b/src/atlasViewer/atlasViewer.history.service.spec.ts @@ -7,6 +7,7 @@ import { Action, Store } from '@ngrx/store' import { defaultRootState } from '../services/stateStore.service' import { cold } from 'jasmine-marbles' import { HttpClientTestingModule } from '@angular/common/http/testing' +import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module' const bigbrainJson = require('!json-loader!src/res/ext/bigbrain.json') @@ -16,7 +17,8 @@ describe('atlasviewer.history.service.ts', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ - HttpClientTestingModule + HttpClientTestingModule, + AngularMaterialModule, ], providers: [ AtlasViewerHistoryUseEffect, diff --git a/src/atlasViewer/atlasViewer.history.service.ts b/src/atlasViewer/atlasViewer.history.service.ts index c58aa5a5f..59fe3cd5a 100644 --- a/src/atlasViewer/atlasViewer.history.service.ts +++ b/src/atlasViewer/atlasViewer.history.service.ts @@ -8,6 +8,7 @@ import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.consta import { cvtSearchParamToState, cvtStateToSearchParam } from "./atlasViewer.urlUtil"; import { viewerStateHelperStoreName } from '../services/state/viewerState.store.helper' import { PureContantService } from "src/util"; +import { MatSnackBar } from "@angular/material/snack-bar"; const getSearchParamStringFromState = state => { try { return cvtStateToSearchParam(state).toString() @@ -58,7 +59,9 @@ export class AtlasViewerHistoryUseEffect implements OnDestroy { } } else { // if non empty search param - const newState = cvtSearchParamToState(search, storeState) + const newState = cvtSearchParamToState(search, storeState, error => { + this.snackbar.open(`${error.message}`, 'Dismiss') + }) return { type: GENERAL_ACTION_TYPES.APPLY_STATE, state: newState, @@ -127,7 +130,8 @@ export class AtlasViewerHistoryUseEffect implements OnDestroy { private store$: Store<IavRootStoreInterface>, private actions$: Actions, private constantService: AtlasViewerConstantsServices, - private pureConstantSErvice: PureContantService + private pureConstantSErvice: PureContantService, + private snackbar: MatSnackBar ) { this.setNewSearchString$.subscribe(newSearchString => { diff --git a/src/atlasViewer/atlasViewer.urlUtil.spec.ts b/src/atlasViewer/atlasViewer.urlUtil.spec.ts index 01787b3b1..50746735a 100644 --- a/src/atlasViewer/atlasViewer.urlUtil.spec.ts +++ b/src/atlasViewer/atlasViewer.urlUtil.spec.ts @@ -31,6 +31,46 @@ const fetchedTemplateRootState = { describe('atlasViewer.urlService.service.ts', () => { describe('cvtSearchParamToState', () => { + /** + * for 2.3.0 onwards + * multi region selection has been temporarily disabled. + * search param parse needs to return emtpy array when encountered + */ + it('> filters out multi region selection an returns an empty array', () => { + const searchString = `?templateSelected=Waxholm+Space+rat+brain+MRI%2FDTI&parcellationSelected=Waxholm+Space+rat+brain+atlas+v2&cRegionsSelected=%7B%22v2%22%3A%2213.a.b.19.6.c.q.x.1.1L.Y.1K.r.s.y.z._.1G.-.Z.18.v.f.g.1J.1C.k.14.15.7.1E.1F.10.11.12.1D.1S.A.1V.1W.1X.1Y.1Z.1a.1i.1j.1k.1m.1n.1o.1p.U.V.W.3.1I.e.d.1T.1H.m.h.n.1U.o.t.2.17.p.w.4.5.1A.1B.u.l.j.16%22%7D&cNavigation=0.0.0.-W000..2-8Bnd.2_tvb9._yymE._tYzz..1Sjt..9Hnn%7E.Lqll%7E.Vcf..9fo` + const searchparam = new URLSearchParams(searchString) + const regionObj = JSON.parse(searchparam.get('cRegionsSelected')) + const totalRegions = [] + for (const key in regionObj) { + for (const el of regionObj[key].split('.')) { + totalRegions.push(el) + } + } + expect(totalRegions.length).toBeGreaterThan(1) + + const newState = cvtSearchParamToState(searchparam, fetchedTemplateRootState) + expect(newState?.viewerState?.regionsSelected).toEqual([]) + }) + + /** + * leaves single region selection intact + */ + it('> leaves single region selection intact', () => { + const searchString = '?templateSelected=Waxholm+Space+rat+brain+MRI%2FDTI&parcellationSelected=Waxholm+Space+rat+brain+atlas+v2&cRegionsSelected=%7B"v2"%3A"1S"%7D&cNavigation=0.0.0.-W000..2-8Bnd.2_tvb9._yymE._tYzz..1Sjt..9Hnn~.Lqll~.Vcf..9fo' + const searchparam = new URLSearchParams(searchString) + const regionObj = JSON.parse(searchparam.get('cRegionsSelected')) + const totalRegions = [] + for (const key in regionObj) { + for (const el of regionObj[key].split('.')) { + totalRegions.push(el) + } + } + expect(totalRegions.length).toEqual(1) + + const newState = cvtSearchParamToState(searchparam, fetchedTemplateRootState) + expect(newState?.viewerState?.regionsSelected?.length).toEqual(1) + }) + it('> convert empty search param to empty state', () => { const searchparam = new URLSearchParams() expect(() => cvtSearchParamToState(searchparam, defaultRootState)).toThrow() diff --git a/src/atlasViewer/atlasViewer.urlUtil.ts b/src/atlasViewer/atlasViewer.urlUtil.ts index 59640205e..85ef716d8 100644 --- a/src/atlasViewer/atlasViewer.urlUtil.ts +++ b/src/atlasViewer/atlasViewer.urlUtil.ts @@ -13,7 +13,9 @@ export const PARSING_SEARCHPARAM_ERROR = { const PARSING_SEARCHPARAM_WARNING = { UNKNOWN_PARCELLATION: 'UNKNOWN_PARCELLATION', DECODE_CIPHER_ERROR: 'DECODE_CIPHER_ERROR', - ID_ERROR: 'ID_ERROR' + ID_ERROR: 'ID_ERROR', + + DEPRECATION_ERROR: `DEPRECATION_ERROR` } export const CVT_STATE_TO_SEARCHPARAM_ERROR = { @@ -90,7 +92,7 @@ export const cvtStateToSearchParam = (state: any): URLSearchParams => { } const { TEMPLATE_NOT_FOUND, TEMPALTE_NOT_SET, PARCELLATION_NOT_UPDATED } = PARSING_SEARCHPARAM_ERROR -const { UNKNOWN_PARCELLATION, DECODE_CIPHER_ERROR, ID_ERROR } = PARSING_SEARCHPARAM_WARNING +const { UNKNOWN_PARCELLATION, DECODE_CIPHER_ERROR, ID_ERROR, DEPRECATION_ERROR } = PARSING_SEARCHPARAM_WARNING const parseSearchParamForTemplateParcellationRegion = (searchparams: URLSearchParams, state: IavRootStoreInterface, cb?: (arg: any) => void) => { @@ -193,7 +195,13 @@ const parseSearchParamForTemplateParcellationRegion = (searchparams: URLSearchPa return { templateSelected, parcellationSelected, - regionsSelected + regionsSelected: (() => { + if (regionsSelected.length > 1) { + cb({ type: DEPRECATION_ERROR, message: `Selecting multiple regions has been temporarily disabled in v2.3.0` }) + return [] + } + return regionsSelected + })() } } diff --git a/src/ui/sharedModules/angularMaterial.module.ts b/src/ui/sharedModules/angularMaterial.module.ts index d5384113b..9bed0ad4b 100644 --- a/src/ui/sharedModules/angularMaterial.module.ts +++ b/src/ui/sharedModules/angularMaterial.module.ts @@ -1,6 +1,6 @@ import {MAT_DIALOG_DEFAULT_OPTIONS, MatDialogConfig, MatDialogModule} from "@angular/material/dialog"; import {MatButtonModule} from "@angular/material/button"; -import {MatSnackBarModule} from "@angular/material/snack-bar"; +import {MatSnackBarModule, MAT_SNACK_BAR_DEFAULT_OPTIONS} from "@angular/material/snack-bar"; import {MatCardModule} from "@angular/material/card"; import {MatCheckboxModule} from "@angular/material/checkbox"; import {MatTabsModule} from "@angular/material/tabs"; @@ -96,6 +96,11 @@ const defaultDialogOption: MatDialogConfig = new MatDialogConfig() ...defaultDialogOption, panelClass: 'iav-dialog-class', }, + },{ + provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, + useValue: { + duration: 2500 + } }], }) export class AngularMaterialModule { } -- GitLab