From 56a6e59ebd9d8b42789ab5be49cbea12a6923886 Mon Sep 17 00:00:00 2001
From: xgui3783 <xgui3783@gmail.com>
Date: Mon, 27 Jul 2020 16:35:07 +0200
Subject: [PATCH] chore/rf/bugfix (#616)

* chore: added origin dataset for cortical layers
bugfix: pinned datasets (#608)
bugfix: fixed counter of regional features
chore: moved region/DSPrev action btns to banner
chore: removed unused imports
ui: styling of collapse btn from accent to basic

* chore: fixed unit tests

* chore: added unit test for fav dtaset to prevent regression
---
 common/constants.js                           |  2 +
 src/glue.ts                                   |  2 -
 src/main.module.ts                            |  4 +-
 src/res/css/extra_styles.css                  | 10 ++
 src/res/ext/bigbrain.json                     |  6 ++
 src/services/state/dataState/actions.ts       | 21 ++++
 src/services/state/dataStore.store.ts         |  9 +-
 src/ui/databrowserModule/constants.ts         |  3 +
 .../databrowserModule/databrowser.module.ts   |  3 +
 .../databrowserModule/databrowser.service.ts  | 35 ++++---
 .../databrowser.useEffect.spec.ts             | 97 +++++++-----------
 .../databrowser.useEffect.ts                  | 43 ++++----
 .../databrowser/databrowser.base.ts           | 92 +++++++++++++++++
 .../databrowser/databrowser.component.ts      | 99 ++++---------------
 .../databrowser/databrowser.directive.ts      | 18 ++++
 .../databrowser/databrowser.template.html     |  2 +-
 src/ui/databrowserModule/index.ts             |  1 +
 .../previewCard/previewCard.component.ts      |  2 +-
 .../previewCard/previewCard.template.html     | 53 +++++++++-
 .../preview/previewDatasetFile.directive.ts   |  2 +-
 .../preview/shownPreviews.directive.ts        |  2 +-
 src/ui/databrowserModule/pure.ts              |  3 +-
 .../detailedView/singleDataset.component.ts   |  9 ++
 .../detailedView/singleDataset.template.html  |  5 +-
 .../singleDataset/singleDataset.base.ts       |  1 +
 src/ui/databrowserModule/store.module.ts      |  2 +-
 .../layerbrowser.component.ts                 |  1 -
 .../nehubaContainer.component.ts              |  1 -
 .../nehubaContainer.template.html             | 16 ++-
 src/ui/parcellationRegion/region.base.ts      |  4 +-
 .../regionMenu/regionMenu.component.spec.ts   | 68 +++++++++----
 .../regionMenu/regionMenu.component.ts        |  7 +-
 .../regionMenu/regionMenu.template.html       | 75 +++++++-------
 33 files changed, 429 insertions(+), 269 deletions(-)
 create mode 100644 src/services/state/dataState/actions.ts
 create mode 100644 src/ui/databrowserModule/databrowser/databrowser.base.ts
 create mode 100644 src/ui/databrowserModule/databrowser/databrowser.directive.ts

diff --git a/common/constants.js b/common/constants.js
index 393070145..284345dec 100644
--- a/common/constants.js
+++ b/common/constants.js
@@ -8,6 +8,7 @@
     COLLAPSE: 'Collapse',
 
     // dataset specific
+    EXPLORE_DATASET_IN_KG: `Explore dataset in Knowledge`,
     SHOW_DATASET_PREVIEW: 'Show dataset preview',
     TOGGLE_EXPLORE_PANEL: `Toggle explore panel`,
     MODALITY_FILTER: `Toggle dataset modality filter`,
@@ -36,6 +37,7 @@
     SHARE_CUSTOM_URL_DIALOG: 'Dialog for creating a custom URL',
 
     // parcellation region specific
+    GO_TO_REGION_CENTROID: 'Navigate to region centroid',
     SHOW_ORIGIN_DATASET: `Show probabilistic map`,
     SHOW_CONNECTIVITY_DATA: `Show connectivity data`,
     SHOW_IN_OTHER_REF_SPACE: `Show in other reference space`,
diff --git a/src/glue.ts b/src/glue.ts
index 1cb453421..1e2cc043c 100644
--- a/src/glue.ts
+++ b/src/glue.ts
@@ -23,8 +23,6 @@ const PREVIEW_FILE_TYPES_NO_UI = [
 
 const DATASET_PREVIEW_ANNOTATION = `DATASET_PREVIEW_ANNOTATION`
 
-export const GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME: InjectionToken<({ datasetId, filename }) => Observable<any>> = new InjectionToken('GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME')
-
 export const glueActionToggleDatasetPreview = createAction(
   '[glue] toggleDatasetPreview',
   props<{ datasetPreviewFile: IDatasetPreviewData }>()
diff --git a/src/main.module.ts b/src/main.module.ts
index 5c8684a3d..be401e892 100644
--- a/src/main.module.ts
+++ b/src/main.module.ts
@@ -26,7 +26,7 @@ import { LocalFileService } from "./services/localFile.service";
 import { NgViewerUseEffect } from "./services/state/ngViewerState.store";
 import { ViewerStateUseEffect } from "./services/state/viewerState.store";
 import { UIService } from "./services/uiService.service";
-import { DatabrowserModule, OVERRIDE_IAV_DATASET_PREVIEW_DATASET_FN, DataBrowserFeatureStore } from "src/ui/databrowserModule";
+import { DatabrowserModule, OVERRIDE_IAV_DATASET_PREVIEW_DATASET_FN, DataBrowserFeatureStore, GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "src/ui/databrowserModule";
 import { DatabrowserService } from "./ui/databrowserModule/databrowser.service";
 import { ViewerStateControllerUseEffect } from "./ui/viewerStateController/viewerState.useEffect";
 import { DockedContainerDirective } from "./util/directives/dockedContainer.directive";
@@ -54,7 +54,7 @@ import 'hammerjs'
 import 'src/res/css/extra_styles.css'
 import 'src/res/css/version.css'
 import 'src/theme.scss'
-import { DatasetPreviewGlue, datasetPreviewMetaReducer, IDatasetPreviewGlue, GlueEffects, GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from './glue';
+import { DatasetPreviewGlue, datasetPreviewMetaReducer, IDatasetPreviewGlue, GlueEffects } from './glue';
 import { viewerStateHelperReducer, viewerStateFleshOutDetail, viewerStateMetaReducers, ViewerStateHelperEffect } from './services/state/viewerState.store.helper';
 
 export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css
index 77eb5642a..d9e557e50 100644
--- a/src/res/css/extra_styles.css
+++ b/src/res/css/extra_styles.css
@@ -372,6 +372,11 @@ markdown-dom pre code
   pointer-events: none;
 }
 
+.h-2rem
+{
+  height: 2rem!important;
+}
+
 .h-5em
 {
   height: 5em!important;
@@ -751,3 +756,8 @@ mat-list.sm mat-list-item
   height:2rem!important;
   font-size: 0.8rem!important;
 }
+
+.color-inherit
+{
+  color: inherit!important;
+}
diff --git a/src/res/ext/bigbrain.json b/src/res/ext/bigbrain.json
index cd704abd5..4af8e7700 100644
--- a/src/res/ext/bigbrain.json
+++ b/src/res/ext/bigbrain.json
@@ -659,6 +659,12 @@
       "@id": "juelich/iav/atlas/v1.0.0/3",
       "name": "Cortical Layers Segmentation",
       "ngId": "cortical layers",
+      "originDatasets": [
+        {
+          "kgSchema": "minds/core/dataset/v1.0.0",
+          "kgId": "13e6ec48-4fec-4e9a-9bcf-45036d3c8ef9"
+        }
+      ],
       "properties": {
         "name": "Cortical Layers Segmentation",
         "description": "The cerebral isocortex has six cytoarchitectonic layers that vary depending on cortical area and local morphology. This datasets provides a 3D segmentation of all cortical and laminar surfaces in the BigBrain, a high-resolution, 3D histological model of the human brain. The segmentation has been computed automatically based on histological intensities along 3D cortical profiles which were sampled between the pial and white matter throughout the dataset. These cortical profiles were segmented into layers using a convolutional neural network. Training profiles were generated from examples of manually segmented layers on cortical regions from 2D histological sections of the BigBrain. From the segmented intensity profiles, surface meshes and voxel masks of all six cortical layers in the space of the Big Brain have been computed.",
diff --git a/src/services/state/dataState/actions.ts b/src/services/state/dataState/actions.ts
new file mode 100644
index 000000000..22560c293
--- /dev/null
+++ b/src/services/state/dataState/actions.ts
@@ -0,0 +1,21 @@
+import { createAction, props } from "@ngrx/store";
+
+export const datastateActionToggleFav = createAction(
+  `[datastate] toggleFav`,
+  props<{payload: { fullId: string }}>()
+)
+
+export const datastateActionUpdateFavDataset = createAction(
+  `[datastate] updateFav`,
+  props<{ favDataEntries: any[] }>()
+)
+
+export const datastateActionUnfavDataset = createAction(
+  `[datastate] unFav`,
+  props<{ payload: { fullId: string } }>()
+)
+
+export const datastateActionFavDataset = createAction(
+  `[datastate] fav`,
+  props<{ payload: { fullId: string } }>()
+)
diff --git a/src/services/state/dataStore.store.ts b/src/services/state/dataStore.store.ts
index 9acdec362..aae960f5f 100644
--- a/src/services/state/dataStore.store.ts
+++ b/src/services/state/dataStore.store.ts
@@ -5,6 +5,7 @@
 import { Action } from '@ngrx/store'
 import { GENERAL_ACTION_TYPES } from '../stateStore.service'
 import { LOCAL_STORAGE_CONST } from 'src/util/constants'
+import { datastateActionUpdateFavDataset } from './dataState/actions'
 
 /**
  * TODO merge with databrowser.usereffect.ts
@@ -48,13 +49,13 @@ export const getStateStore = ({ state: state = defaultState } = {}) => (prevStat
       fetchedDataEntries : action.fetchedDataEntries,
     }
   }
-  case FETCHED_SPATIAL_DATA : {
+  case FETCHED_SPATIAL_DATA: {
     return {
       ...prevState,
       fetchedSpatialData : action.fetchedDataEntries,
     }
   }
-  case ACTION_TYPES.UPDATE_FAV_DATASETS: {
+  case datastateActionUpdateFavDataset.type: {
     const { favDataEntries = [] } = action
     return {
       ...prevState,
@@ -211,10 +212,6 @@ export interface IFileSupplementData {
 }
 
 const ACTION_TYPES = {
-  FAV_DATASET: `FAV_DATASET`,
-  UPDATE_FAV_DATASETS: `UPDATE_FAV_DATASETS`,
-  UNFAV_DATASET: 'UNFAV_DATASET',
-  TOGGLE_FAV_DATASET: 'TOGGLE_FAV_DATASET',
   PREVIEW_DATASET: 'PREVIEW_DATASET',
   CLEAR_PREVIEW_DATASET: 'CLEAR_PREVIEW_DATASET',
   CLEAR_PREVIEW_DATASETS: 'CLEAR_PREVIEW_DATASETS'
diff --git a/src/ui/databrowserModule/constants.ts b/src/ui/databrowserModule/constants.ts
index 36163582e..617d39598 100644
--- a/src/ui/databrowserModule/constants.ts
+++ b/src/ui/databrowserModule/constants.ts
@@ -1,5 +1,6 @@
 import { InjectionToken } from "@angular/core";
 import { LOCAL_STORAGE_CONST } from "src/util/constants";
+import { Observable } from "rxjs";
 
 export const OVERRIDE_IAV_DATASET_PREVIEW_DATASET_FN = new InjectionToken<(file: any, dataset: any) => void>('OVERRIDE_IAV_DATASET_PREVIEW_DATASET_FN')
 export const DATASTORE_DEFAULT_STATE = {
@@ -93,3 +94,5 @@ export interface DatasetPreview {
   datasetId: string
   filename: string
 }
+
+export const GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME: InjectionToken<({ datasetId, filename }) => Observable<any>> = new InjectionToken('GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME')
diff --git a/src/ui/databrowserModule/databrowser.module.ts b/src/ui/databrowserModule/databrowser.module.ts
index 2e06dc080..059ea3107 100644
--- a/src/ui/databrowserModule/databrowser.module.ts
+++ b/src/ui/databrowserModule/databrowser.module.ts
@@ -42,6 +42,7 @@ import { ShownPreviewsDirective } from "./preview/shownPreviews.directive";
 import { FilterPreviewByType } from "./preview/filterPreview.pipe";
 import { PreviewCardComponent } from "./preview/previewCard/previewCard.component";
 import { LayerBrowserModule } from "../layerbrowser";
+import { DatabrowserDirective } from "./databrowser/databrowser.directive";
 
 
 const previewEmitFactory = ( overrideFn: (file: any, dataset: any) => void) => {
@@ -75,6 +76,7 @@ const previewEmitFactory = ( overrideFn: (file: any, dataset: any) => void) => {
     ShowDatasetDialogDirective,
     PreviewDatasetFile,
     ShownPreviewsDirective,
+    DatabrowserDirective,
 
     /**
      * pipes
@@ -114,6 +116,7 @@ const previewEmitFactory = ( overrideFn: (file: any, dataset: any) => void) => {
     ShownPreviewsDirective,
     FilterPreviewByType,
     PreviewCardComponent,
+    DatabrowserDirective,
   ],
   entryComponents: [
     DataBrowser,
diff --git a/src/ui/databrowserModule/databrowser.service.ts b/src/ui/databrowserModule/databrowser.service.ts
index 57ca8c1f2..3f9c3245c 100644
--- a/src/ui/databrowserModule/databrowser.service.ts
+++ b/src/ui/databrowserModule/databrowser.service.ts
@@ -10,13 +10,13 @@ import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.se
 import { WidgetUnit } from "src/widget";
 
 import { LoggingService } from "src/logging";
-import { DATASETS_ACTIONS_TYPES } from "src/services/state/dataStore.store";
 import { SHOW_KG_TOS } from "src/services/state/uiState.store";
 import { FETCHED_DATAENTRIES, FETCHED_SPATIAL_DATA, IavRootStoreInterface, IDataEntry, safeFilter } from "src/services/stateStore.service";
 import { regionFlattener } from "src/util/regionFlattener";
 import { DataBrowser } from "./databrowser/databrowser.component";
 import { NO_METHODS } from "./util/filterDataEntriesByMethods.pipe";
 import { FilterDataEntriesByRegion } from "./util/filterDataEntriesByRegion.pipe";
+import { datastateActionToggleFav, datastateActionUnfavDataset, datastateActionFavDataset } from "src/services/state/dataState/actions";
 
 const noMethodDisplayName = 'No methods described'
 
@@ -206,24 +206,33 @@ export class DatabrowserService implements OnDestroy {
   }
 
   public toggleFav(dataentry: Partial<IDataEntry>) {
-    this.store.dispatch({
-      type: DATASETS_ACTIONS_TYPES.TOGGLE_FAV_DATASET,
-      payload: dataentry,
-    })
+    this.store.dispatch(
+      datastateActionToggleFav({
+        payload: {
+          fullId: dataentry.fullId || null
+        }
+      })
+    )
   }
 
   public saveToFav(dataentry: Partial<IDataEntry>) {
-    this.store.dispatch({
-      type: DATASETS_ACTIONS_TYPES.FAV_DATASET,
-      payload: dataentry,
-    })
+    this.store.dispatch(
+      datastateActionFavDataset({
+        payload: {
+          fullId: dataentry?.fullId || null
+        }
+      })
+    )
   }
 
   public removeFromFav(dataentry: Partial<IDataEntry>) {
-    this.store.dispatch({
-      type: DATASETS_ACTIONS_TYPES.UNFAV_DATASET,
-      payload: dataentry,
-    })
+    this.store.dispatch(
+      datastateActionUnfavDataset({
+        payload: {
+          fullId: dataentry.fullId || null
+        }
+      })
+    )
   }
 
   // TODO deprecate
diff --git a/src/ui/databrowserModule/databrowser.useEffect.spec.ts b/src/ui/databrowserModule/databrowser.useEffect.spec.ts
index 3ff661da4..c6e3fda80 100644
--- a/src/ui/databrowserModule/databrowser.useEffect.spec.ts
+++ b/src/ui/databrowserModule/databrowser.useEffect.spec.ts
@@ -1,62 +1,39 @@
-// TODO reenable test
-// when injecting DataBrowserUseEffect, referenceError: defaultState is not defined error was thrown
+const defaultState = {
+  fetchedDataEntries: [],
+  favDataEntries: [],
+  fetchedSpatialData: [],
+}
 
-// import { DataBrowserUseEffect } from './databrowser.useEffect'
-// import { TestBed, async } from '@angular/core/testing'
-// import { AngularMaterialModule } from '../sharedModules/angularMaterial.module'
-// import { Observable } from 'rxjs'
-// import { provideMockActions } from '@ngrx/effects/testing'
-// import { provideMockStore } from '@ngrx/store/testing'
-// import { defaultRootState } from 'src/services/stateStore.service'
-// import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'
-// import { DatabrowserModule } from './databrowser.module'
-// import { hot } from 'jasmine-marbles'
-// import { KgSingleDatasetService } from './singleDataset/singleDataset.base'
+import { DataBrowserUseEffect } from './databrowser.useEffect'
+import { TestBed } from '@angular/core/testing'
+import { Observable } from 'rxjs'
+import { provideMockActions } from '@ngrx/effects/testing'
+import { provideMockStore } from '@ngrx/store/testing'
+import { hot } from 'jasmine-marbles'
 
-// describe('databrowser.useEffect.spec.ts', () => {
-
-//   it("fails", () => {
-//     expect(true).toEqual(true)
-//   })
-//   describe('DataBrowserUseEffect', () => {
-//     let actions$: Observable<any>
-//     beforeEach(async(() => {
-//       TestBed.configureTestingModule({
-//         providers: [
-//           DataBrowserUseEffect,
-//           provideMockActions(() => actions$),
-//           provideMockStore({ initialState: defaultRootState })
-//         ]
-//       }).compileComponents()
-//     }))
-
-//     afterEach(() => {
-//       const ctrl = TestBed.inject(HttpTestingController)
-//       ctrl.verify()
-//     })
-
-//     describe('storePreviewDatasetFile$', () => {
-//       it('on init, emit []', () => {
-//         // const effect = TestBed.inject(DataBrowserUseEffect)
-//         // expect(
-//         //   (effect as any).storePreviewDatasetFile$ as Observable<any>
-//         // ).toBeObservable(
-//         //   hot(
-//         //     'a',
-//         //     {
-//         //       a: []
-//         //     }
-//         //   )
-//         // )
-        
-//       })
-//       // it('on datasetPreviews change, kgSingleDatasetService.getInfoFromKg gets called', () => {
-//       //   const store = TestBed.get(Store)
-//       //   const copiedState = JSON.parse(JSON.stringify( defaultRootState ))
-//       // })
-//     })
-//     describe('previewRegisteredVolumes$', () => {
-
-//     })
-//   })
-// })
\ No newline at end of file
+let actions$: Observable<any>
+describe('> databrowser.useEffect.ts', () => {
+  describe('> DataBrowserUseEffect', () => {
+    beforeEach(() => {
+      TestBed.configureTestingModule({
+        providers: [
+          provideMockStore({
+            initialState: {
+              dataStore: defaultState
+            }
+          }),
+          provideMockActions(() => actions$),
+          DataBrowserUseEffect,
+        ]
+      })
+    })
+    it('> should instantiate properly', () => {
+      const useEffect = TestBed.inject(DataBrowserUseEffect)
+      expect(useEffect.favDataEntries$).toBeObservable(
+        hot('a', {
+          a: []
+        })
+      )
+    })
+  })
+})
\ No newline at end of file
diff --git a/src/ui/databrowserModule/databrowser.useEffect.ts b/src/ui/databrowserModule/databrowser.useEffect.ts
index b1ea697bd..88205d248 100644
--- a/src/ui/databrowserModule/databrowser.useEffect.ts
+++ b/src/ui/databrowserModule/databrowser.useEffect.ts
@@ -3,9 +3,9 @@ import { Actions, Effect, ofType } from "@ngrx/effects";
 import { select, Store } from "@ngrx/store";
 import { Observable, Subscription } from "rxjs";
 import { filter, map, withLatestFrom } from "rxjs/operators";
-import { DATASETS_ACTIONS_TYPES, IDataEntry } from "src/services/state/dataStore.store";
 import { LOCAL_STORAGE_CONST } from "src/util/constants";
 import { getKgSchemaIdFromFullId } from "./util/getKgSchemaIdFromFullId.pipe";
+import { datastateActionToggleFav, datastateActionUpdateFavDataset, datastateActionUnfavDataset, datastateActionFavDataset } from "src/services/state/dataState/actions";
 
 @Injectable({
   providedIn: 'root',
@@ -26,7 +26,7 @@ export class DataBrowserUseEffect {
     )
 
     this.toggleDataset$ = this.actions$.pipe(
-      ofType(DATASETS_ACTIONS_TYPES.TOGGLE_FAV_DATASET),
+      ofType(datastateActionToggleFav.type),
       withLatestFrom(this.favDataEntries$),
       map(([action, prevFavDataEntries]) => {
         const { payload = {} } = action as any
@@ -35,27 +35,25 @@ export class DataBrowserUseEffect {
         const re1 = getKgSchemaIdFromFullId(fullId)
 
         if (!re1) {
-          return {
-            type: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
-            favDataEntries: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
-          }
+          return datastateActionUpdateFavDataset({
+            favDataEntries: prevFavDataEntries
+          })
         }
         const favIdx = prevFavDataEntries.findIndex(ds => {
           const re2 = getKgSchemaIdFromFullId(ds.fullId)
           if (!re2) return false
           return re2[1] === re1[1]
         })
-        return {
-          type: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
+        return datastateActionUpdateFavDataset({
           favDataEntries: favIdx >= 0
             ? prevFavDataEntries.filter((_, idx) => idx !== favIdx)
             : prevFavDataEntries.concat(payload),
-        }
+        })
       }),
     )
 
     this.unfavDataset$ = this.actions$.pipe(
-      ofType(DATASETS_ACTIONS_TYPES.UNFAV_DATASET),
+      ofType(datastateActionUnfavDataset.type),
       withLatestFrom(this.favDataEntries$),
       map(([action, prevFavDataEntries]) => {
 
@@ -64,20 +62,19 @@ export class DataBrowserUseEffect {
 
         const re1 = getKgSchemaIdFromFullId(fullId)
 
-        return {
-          type: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
+        return datastateActionUpdateFavDataset({
           favDataEntries: prevFavDataEntries.filter(ds => {
             const re2 = getKgSchemaIdFromFullId(ds.fullId)
             if (!re2) return false
             if (!re1) return true
             return re2[1] !== re1[1]
-          }),
-        }
+          })
+        })
       }),
     )
 
     this.favDataset$ = this.actions$.pipe(
-      ofType(DATASETS_ACTIONS_TYPES.FAV_DATASET),
+      ofType(datastateActionFavDataset.type),
       withLatestFrom(this.favDataEntries$),
       map(([ action, prevFavDataEntries ]) => {
         const { payload } = action as any
@@ -88,10 +85,9 @@ export class DataBrowserUseEffect {
         const { fullId } = payload
         const re1 = getKgSchemaIdFromFullId(fullId)
         if (!re1) {
-          return {
-            type: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
-            favDataEntries: prevFavDataEntries,
-          }
+          return datastateActionUpdateFavDataset({
+            favDataEntries: prevFavDataEntries
+          })
         }
 
         const isDuplicate = prevFavDataEntries.some(favDe => {
@@ -103,10 +99,9 @@ export class DataBrowserUseEffect {
           ? prevFavDataEntries
           : prevFavDataEntries.concat(payload)
 
-        return {
-          type: DATASETS_ACTIONS_TYPES.UPDATE_FAV_DATASETS,
-          favDataEntries,
-        }
+        return datastateActionUpdateFavDataset({
+          favDataEntries
+        })
       }),
     )
 
@@ -136,7 +131,7 @@ export class DataBrowserUseEffect {
 
   private savedFav$: Observable<Array<{id: string, name: string}> | null>
 
-  private favDataEntries$: Observable<Partial<IDataEntry>[]>
+  public favDataEntries$: Observable<Partial<any>[]>
 
   @Effect()
   public favDataset$: Observable<any>
diff --git a/src/ui/databrowserModule/databrowser/databrowser.base.ts b/src/ui/databrowserModule/databrowser/databrowser.base.ts
new file mode 100644
index 000000000..ce800d094
--- /dev/null
+++ b/src/ui/databrowserModule/databrowser/databrowser.base.ts
@@ -0,0 +1,92 @@
+import { Input, Output, EventEmitter } from "@angular/core"
+import { LoggingService } from "src/logging"
+import { DatabrowserService } from "../singleDataset/singleDataset.base"
+import { Observable } from "rxjs"
+import { IDataEntry } from "src/services/stateStore.service"
+
+export class DatabrowserBase{
+
+  @Output()
+  public dataentriesUpdated: EventEmitter<IDataEntry[]> = new EventEmitter()
+
+  @Input()
+  regions: any[] = []
+
+  @Input()
+  public template: any
+
+  @Input()
+  public parcellation: any
+
+  public fetchError: boolean = false
+  public fetchingFlag = false
+
+  public favDataentries$: Observable<Partial<IDataEntry>[]>
+
+  public dataentries: IDataEntry[] = []
+
+  constructor(
+    private dbService: DatabrowserService,
+    private log: LoggingService,
+  ){
+
+    this.favDataentries$ = this.dbService.favedDataentries$
+  }
+
+  ngOnChanges(){
+
+
+    this.regions = this.regions.map(r => {
+      /**
+       * TODO to be replaced with properly region UUIDs from KG
+       */
+      return {
+        id: `${this.parcellation?.name || 'untitled_parcellation'}/${r.name}`,
+        ...r,
+      }
+    })
+    const { regions, parcellation, template } = this
+    this.fetchingFlag = true
+
+    // input may be undefined/null
+    if (!parcellation) { return }
+
+    /**
+     * reconstructing parcellation region is async (done on worker thread)
+     * if parcellation region is not yet defined, return.
+     * parccellation will eventually be updated with the correct region
+     */
+    if (!parcellation.regions) { return }
+
+    this.dbService.getDataByRegion({ regions, parcellation, template })
+      .then(de => {
+        this.dataentries = de
+        return de
+      })
+      .catch(e => {
+        this.log.error(e)
+        this.fetchError = true
+      })
+      .finally(() => {
+        this.fetchingFlag = false
+        this.dataentriesUpdated.emit(this.dataentries)
+      })
+  }
+
+  public retryFetchData(event: MouseEvent) {
+    event.preventDefault()
+    this.dbService.manualFetchDataset$.next(null)
+  }
+
+  public toggleFavourite(dataset: IDataEntry) {
+    this.dbService.toggleFav(dataset)
+  }
+
+  public saveToFavourite(dataset: IDataEntry) {
+    this.dbService.saveToFav(dataset)
+  }
+
+  public removeFromFavourite(dataset: IDataEntry) {
+    this.dbService.removeFromFav(dataset)
+  }
+}
diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts
index 7a257e749..4ed2d667c 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.component.ts
+++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts
@@ -5,6 +5,8 @@ import { IDataEntry } from "src/services/state/dataStore.store";
 import { CountedDataModality, DatabrowserService } from "../databrowser.service";
 import { ModalityPicker } from "../modalityPicker/modalityPicker.component";
 import { ARIA_LABELS } from 'common/constants.js'
+import { DatabrowserBase } from "./databrowser.base";
+import { debounceTime } from "rxjs/operators";
 
 const { MODALITY_FILTER, LIST_OF_DATASETS } = ARIA_LABELS
 
@@ -18,7 +20,7 @@ const { MODALITY_FILTER, LIST_OF_DATASETS } = ARIA_LABELS
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 
-export class DataBrowser implements OnChanges, OnDestroy, OnInit {
+export class DataBrowser extends DatabrowserBase implements OnChanges, OnDestroy, OnInit {
 
   @Input()
   disableVirtualScroll: boolean = false
@@ -28,22 +30,8 @@ export class DataBrowser implements OnChanges, OnDestroy, OnInit {
 
   public MODALITY_FILTER_ARIA_LABEL = MODALITY_FILTER
   public LIST_OF_DATASETS_ARIA_LABEL = LIST_OF_DATASETS
-  @Input()
-  public regions: any[] = []
-
-  @Input()
-  public template: any
-
-  @Input()
-  public parcellation: any
 
-  @Output()
-  public dataentriesUpdated: EventEmitter<IDataEntry[]> = new EventEmitter()
 
-  public dataentries: IDataEntry[] = []
-
-  public fetchingFlag: boolean = false
-  public fetchError: boolean = false
   /**
    * TODO filter types
    */
@@ -54,7 +42,6 @@ export class DataBrowser implements OnChanges, OnDestroy, OnInit {
   @ViewChild(ModalityPicker)
   public modalityPicker: ModalityPicker
 
-  public favDataentries$: Observable<Partial<IDataEntry>[]>
 
   /**
    * TODO
@@ -65,67 +52,36 @@ export class DataBrowser implements OnChanges, OnDestroy, OnInit {
   public gemoetryFilter: any
 
   constructor(
-    private dbService: DatabrowserService,
+    private dataService: DatabrowserService,
     private cdr: ChangeDetectorRef,
-    private log: LoggingService,
+    log: LoggingService,
   ) {
-    this.favDataentries$ = this.dbService.favedDataentries$
+    super(dataService, log)
   }
 
   public ngOnChanges() {
+    super.ngOnChanges()
+  }
 
-    this.regions = this.regions.map(r => {
-      /**
-       * TODO to be replaced with properly region UUIDs from KG
-       */
-      return {
-        id: `${this.parcellation?.name || 'untitled_parcellation'}/${r.name}`,
-        ...r,
-      }
-    })
-    const { regions, parcellation, template } = this
-    this.fetchingFlag = true
-
-    // input may be undefined/null
-    if (!parcellation) { return }
-
-    /**
-     * reconstructing parcellation region is async (done on worker thread)
-     * if parcellation region is not yet defined, return.
-     * parccellation will eventually be updated with the correct region
-     */
-    if (!parcellation.regions) { return }
+  public ngOnInit() {
 
-    this.dbService.getDataByRegion({ regions, parcellation, template })
-      .then(de => {
-        this.dataentries = de
-        return de
-      })
-      .then(this.dbService.getModalityFromDE)
-      .then(modalities => {
-        this.countedDataM = modalities
-      })
-      .catch(e => {
-        this.log.error(e)
-        this.fetchError = true
-      })
-      .finally(() => {
-        this.fetchingFlag = false
-        this.dataentriesUpdated.emit(this.dataentries)
+    this.subscriptions.push(
+      this.dataentriesUpdated.pipe(
+        debounceTime(60)
+      ).subscribe(() => {
+        this.countedDataM = this.dataService.getModalityFromDE(this.dataentries)
         this.cdr.markForCheck()
       })
-
-  }
-
-  public ngOnInit() {
+    )
+    
     /**
      * TODO gets init'ed everytime when appends to ngtemplateoutlet
      */
-    this.dbService.dbComponentInit(this)
+    this.dataService.dbComponentInit(this)
     this.subscriptions.push(
       merge(
-        // this.dbService.selectedRegions$,
-        this.dbService.fetchDataObservable$,
+        // this.dataService.selectedRegions$,
+        this.dataService.fetchDataObservable$,
       ).subscribe(() => {
         /**
          * Only reset modality picker
@@ -163,23 +119,6 @@ export class DataBrowser implements OnChanges, OnDestroy, OnInit {
     this.cdr.markForCheck()
   }
 
-  public retryFetchData(event: MouseEvent) {
-    event.preventDefault()
-    this.dbService.manualFetchDataset$.next(null)
-  }
-
-  public toggleFavourite(dataset: IDataEntry) {
-    this.dbService.toggleFav(dataset)
-  }
-
-  public saveToFavourite(dataset: IDataEntry) {
-    this.dbService.saveToFav(dataset)
-  }
-
-  public removeFromFavourite(dataset: IDataEntry) {
-    this.dbService.removeFromFav(dataset)
-  }
-
   public showParcellationList: boolean = false
 
   public filePreviewName: string
diff --git a/src/ui/databrowserModule/databrowser/databrowser.directive.ts b/src/ui/databrowserModule/databrowser/databrowser.directive.ts
new file mode 100644
index 000000000..5eeeacf5f
--- /dev/null
+++ b/src/ui/databrowserModule/databrowser/databrowser.directive.ts
@@ -0,0 +1,18 @@
+import { Directive } from "@angular/core";
+import { DatabrowserBase } from "./databrowser.base";
+import { DatabrowserService } from "../singleDataset/singleDataset.base";
+import { LoggingService } from "src/logging";
+
+@Directive({
+  selector: '[iav-databrowser-directive]',
+  exportAs: 'iavDatabrowserDirective'
+})
+
+export class DatabrowserDirective extends DatabrowserBase{
+  constructor(
+    dataService: DatabrowserService,
+    log: LoggingService,
+  ){
+    super(dataService, log)
+  }
+}
diff --git a/src/ui/databrowserModule/databrowser/databrowser.template.html b/src/ui/databrowserModule/databrowser/databrowser.template.html
index f6982a35a..27e4efbc0 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.template.html
+++ b/src/ui/databrowserModule/databrowser/databrowser.template.html
@@ -99,7 +99,7 @@
     <mat-card-content class="w-100">
       <!-- TODO export aria labels to common/constants -->
       <div *ngIf="showList">
-        <div *ngFor="let dataset of filteredDataEntry; trackBy: trackByFn; templateCacheSize: 20; let index = index"
+        <div *ngFor="let dataset of filteredDataEntry; trackBy: trackByFn; let index = index"
           class="scroll-element overflow-hidden">
 
           <mat-divider *ngIf="index !== 0"></mat-divider>
diff --git a/src/ui/databrowserModule/index.ts b/src/ui/databrowserModule/index.ts
index 72cea1ddf..a82fb3859 100644
--- a/src/ui/databrowserModule/index.ts
+++ b/src/ui/databrowserModule/index.ts
@@ -20,4 +20,5 @@ export {
   PreviewComponentWrapper,
   getKgSchemaIdFromFullId,
   PreviewDatasetFile,
+  GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME,
 } from './pure'
diff --git a/src/ui/databrowserModule/preview/previewCard/previewCard.component.ts b/src/ui/databrowserModule/preview/previewCard/previewCard.component.ts
index 91f44051c..ffba858ee 100644
--- a/src/ui/databrowserModule/preview/previewCard/previewCard.component.ts
+++ b/src/ui/databrowserModule/preview/previewCard/previewCard.component.ts
@@ -1,6 +1,6 @@
 import { Component, Optional, Inject } from "@angular/core";
 import { PreviewBase } from "../preview.base";
-import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "src/glue";
+import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "../../pure";
 
 @Component({
   selector: 'preview-card',
diff --git a/src/ui/databrowserModule/preview/previewCard/previewCard.template.html b/src/ui/databrowserModule/preview/previewCard/previewCard.template.html
index 82a521b2c..51c3b7a79 100644
--- a/src/ui/databrowserModule/preview/previewCard/previewCard.template.html
+++ b/src/ui/databrowserModule/preview/previewCard/previewCard.template.html
@@ -4,11 +4,41 @@
       {{ singleDsView?.name || file.name || filename }}
     </mat-card-title>
 
-    <mat-card-subtitle>
+    <mat-card-subtitle class="d-inline-flex align-items-center">
       <mat-icon fontSet="fas" fontIcon="fa-database"></mat-icon>
       <span>
         Dataset preview
       </span>
+      
+      <mat-divider [vertical]="true" class="ml-2 h-2rem"></mat-divider>
+
+      <!-- explore btn -->
+      <a *ngFor="let kgRef of singleDsView.kgReference"
+        [href]="kgRef | doiParserPipe"
+        class="color-inherit"
+        target="_blank">
+        <button mat-icon-button
+          [matTooltip]="singleDsView.EXPLORE_DATASET_IN_KG_ARIA_LABEL">
+          <i class="fas fa-external-link-alt"></i>
+        </button>
+      </a>
+
+      <!-- pin dataset btn -->
+      <ng-container *ngTemplateOutlet="favDatasetBtn; context: { singleDataset: singleDsView }">
+      </ng-container>
+
+      <!-- download zip btn -->
+      <a *ngIf="singleDsView.files && singleDsView.files.length > 0"
+        [href]="singleDsView.dlFromKgHref"
+        class="color-inherit"
+        target="_blank">
+        <button mat-icon-button
+          [matTooltip]="singleDsView.tooltipText"
+          [disabled]="singleDsView.downloadInProgress">
+          <i class="ml-1 fas" [ngClass]="!singleDsView.downloadInProgress? 'fa-download' :'fa-spinner fa-pulse'"></i>
+        </button>
+      </a>
+      
     </mat-card-subtitle>
   </div>
 </mat-card>
@@ -17,11 +47,32 @@
   <single-dataset-view [fullId]="datasetId"
     [hideTitle]="true"
     [hidePreview]="true"
+    [hideExplore]="true"
+    [hidePinBtn]="true"
+    [hideDownloadBtn]="true"
     #singleDsView="singleDatasetView">
 
   </single-dataset-view>
 </mat-card>
 
+<!-- TODO -->
+<!-- this is not exactly right -->
 <div class="mt-4">
   <layer-browser></layer-browser>
 </div>
+
+<!-- templates -->
+<ng-template #favDatasetBtn let-singleDataset="singleDataset">
+  <ng-container *ngTemplateOutlet="isFavCtxTmpl; context: { isFav: (singleDataset.favedDataentries$ | async | datasetIsFaved : singleDataset.dataset) }">
+  </ng-container>
+
+  <ng-template #isFavCtxTmpl let-isFav="isFav">
+    <button mat-icon-button
+      (click)="isFav ? singleDataset.undoableRemoveFav() : singleDataset.undoableAddFav()"
+      [attr.aria-label]="singleDataset.PIN_DATASET_ARIA_LABEL"
+      [matTooltip]="singleDataset.PIN_DATASET_ARIA_LABEL"
+      [color]="isFav ? 'primary' : 'basic'">
+      <i class="fas fa-thumbtack"></i>
+    </button>
+  </ng-template>
+</ng-template>
diff --git a/src/ui/databrowserModule/preview/previewDatasetFile.directive.ts b/src/ui/databrowserModule/preview/previewDatasetFile.directive.ts
index 7aecf85f5..f3f649ddf 100644
--- a/src/ui/databrowserModule/preview/previewDatasetFile.directive.ts
+++ b/src/ui/databrowserModule/preview/previewDatasetFile.directive.ts
@@ -4,7 +4,7 @@ import { ViewerPreviewFile, IDataEntry } from 'src/services/state/dataStore.stor
 import { Observable, Subscription } from "rxjs";
 import { distinctUntilChanged } from "rxjs/operators";
 import { PreviewBase } from "./preview.base";
-import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "src/glue";
+import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "../pure";
 
 export const IAV_DATASET_PREVIEW_DATASET_FN = 'IAV_DATASET_PREVIEW_DATASET_FN'
 
diff --git a/src/ui/databrowserModule/preview/shownPreviews.directive.ts b/src/ui/databrowserModule/preview/shownPreviews.directive.ts
index 8307bcd5e..bdebaf947 100644
--- a/src/ui/databrowserModule/preview/shownPreviews.directive.ts
+++ b/src/ui/databrowserModule/preview/shownPreviews.directive.ts
@@ -4,7 +4,7 @@ import { uiStatePreviewingDatasetFilesSelector } from "src/services/state/uiStat
 import { EnumPreviewFileTypes } from "../pure";
 import { switchMap, map, startWith } from "rxjs/operators";
 import { forkJoin, of, Subscription } from "rxjs";
-import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "src/glue";
+import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "../pure";
 
 @Directive({
   selector: '[iav-shown-previews]',
diff --git a/src/ui/databrowserModule/pure.ts b/src/ui/databrowserModule/pure.ts
index e9bfb417c..9fdf87408 100644
--- a/src/ui/databrowserModule/pure.ts
+++ b/src/ui/databrowserModule/pure.ts
@@ -10,7 +10,8 @@ export {
   IKgParcellationRegion,
   IKgPublication,
   IKgReferenceSpace,
-  DatasetPreview
+  DatasetPreview,
+  GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME,
 } from './constants'
 
 export { PreviewFileTypePipe } from './preview/previewFileType.pipe'
diff --git a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.component.ts b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.component.ts
index 338eca132..2d34d3971 100644
--- a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.component.ts
+++ b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.component.ts
@@ -33,4 +33,13 @@ export class SingleDatasetView extends SingleDatasetBase {
 
   @Input()
   hidePreview = false
+
+  @Input()
+  hideExplore = false
+
+  @Input()
+  hidePinBtn = false
+
+  @Input()
+  hideDownloadBtn = false
 }
diff --git a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
index 5113d07d4..cf98554f9 100644
--- a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
+++ b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
@@ -70,7 +70,7 @@
 <ng-template #actionBtns let-mediaBreakPoint>
 
   <!-- explore -->
-  <ng-container *ngIf="!strictLocal">
+  <ng-container *ngIf="!strictLocal && !hideExplore">
 
     <a *ngFor="let kgRef of kgReference"
       [href]="kgRef | doiParserPipe"
@@ -95,6 +95,7 @@
 
     <ng-template #favDatasetBtn let-isFav>
       <iav-dynamic-mat-button
+        *ngIf="!hidePinBtn"
         (click)="isFav ? undoableRemoveFav() : undoableAddFav()"
         iav-stop="click mousedown"
         [iav-dynamic-mat-button-aria-label]="PIN_DATASET_ARIA_LABEL"
@@ -110,7 +111,7 @@
   </ng-container>
 
   <!-- download -->
-  <ng-container *ngIf="!strictLocal">
+  <ng-container *ngIf="!strictLocal && !hideDownloadBtn">
 
     <a *ngIf="files && files.length > 0"
       [href]="dlFromKgHref"
diff --git a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
index 12d3bfd05..2847d1428 100644
--- a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
+++ b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
@@ -22,6 +22,7 @@ export class SingleDatasetBase implements OnChanges, OnDestroy {
 
   public SHOW_DATASET_PREVIEW_ARIA_LABEL = ARIA_LABELS.SHOW_DATASET_PREVIEW
   public PIN_DATASET_ARIA_LABEL = ARIA_LABELS.PIN_DATASET
+  public EXPLORE_DATASET_IN_KG_ARIA_LABEL = ARIA_LABELS.EXPLORE_DATASET_IN_KG
 
   @Input() public ripple: boolean = false
 
diff --git a/src/ui/databrowserModule/store.module.ts b/src/ui/databrowserModule/store.module.ts
index eab27f3e9..c8e0cf510 100644
--- a/src/ui/databrowserModule/store.module.ts
+++ b/src/ui/databrowserModule/store.module.ts
@@ -1,5 +1,5 @@
 import { NgModule } from "@angular/core";
-import { stateStore } from "src/services/state/uiState.store";
+import { stateStore } from "src/services/state/dataStore.store";
 import { DataBrowserUseEffect } from "./databrowser.useEffect";
 import { StoreModule } from "@ngrx/store";
 import { EffectsModule } from "@ngrx/effects";
diff --git a/src/ui/layerbrowser/layerBrowserComponent/layerbrowser.component.ts b/src/ui/layerbrowser/layerBrowserComponent/layerbrowser.component.ts
index 3225c8935..8c70e75bd 100644
--- a/src/ui/layerbrowser/layerBrowserComponent/layerbrowser.component.ts
+++ b/src/ui/layerbrowser/layerBrowserComponent/layerbrowser.component.ts
@@ -56,7 +56,6 @@ export class LayerBrowser implements OnInit, OnDestroy {
     private constantsService: PureContantService,
     private log: LoggingService,
   ) {
-    console.log('init')
     this.ngLayers$ = store.pipe(
       select('viewerState'),
       select('templateSelected'),
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index 54b01efda..64ab6f2c9 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -132,7 +132,6 @@ const {
 
 export class NehubaContainer implements OnInit, OnChanges, OnDestroy {
 
-  public _tmp: number = 0
   public ARIA_LABEL_ZOOM_IN = ZOOM_IN
   public ARIA_LABEL_ZOOM_OUT = ZOOM_OUT
   public ARIA_LABEL_TOGGLE_SIDE_PANEL = TOGGLE_SIDE_PANEL
diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html
index 6e46e1ee9..7f2195f4a 100644
--- a/src/ui/nehubaContainer/nehubaContainer.template.html
+++ b/src/ui/nehubaContainer/nehubaContainer.template.html
@@ -114,7 +114,6 @@
       (openedChange)="$event && sideNavSwitch.open()"
       [disableClose]="true"
       [@openClose]="sideNavMasterSwitch.switchState && sideNavSwitch.switchState ? 'open' : 'closed'"
-      (@openClose.start)="_tmp=1"
       (@openClose.done)="$event.toState === 'closed' && matDrawerMinor.close()">
 
       <div class="position-relative d-flex flex-column h-100">
@@ -134,7 +133,7 @@
         </div>
 
         <ng-container *ngIf="previews.iavAdditionalLayers$ | async | filterPreviewByType : [previews.FILETYPES.VOLUMES] as volumePreviews">
-          <ng-template [ngIf]="volumePreviews.length > 0" [ngIfElse]="sidenavTmpl">
+          <ng-template [ngIf]="volumePreviews.length > 0" [ngIfElse]="sidenavRegionTmpl">
             <ng-container *ngFor="let vPreview of volumePreviews">
               <ng-container *ngTemplateOutlet="sidenavDsPreviewTmpl; context: vPreview">
 
@@ -167,7 +166,7 @@
     <button mat-raised-button class="mat-elevation-z8"
       [attr.aria-label]="ARIA_LABEL_COLLAPSE"
       (click)="sideNavSwitch.close()"
-      color="accent">
+      color="basic">
       <i class="fas fa-chevron-up"></i>
       <span>
         collapse
@@ -177,7 +176,7 @@
 </ng-template>
 
 <!-- region sidenav tmpl -->
-<ng-template #sidenavTmpl>
+<ng-template #sidenavRegionTmpl>
 
   <div class="flex-shrink-1 flex-grow-1 d-flex flex-column"
     [ngClass]="{'region-populated': (selectedRegions$ | async).length > 0 }">
@@ -358,9 +357,16 @@
       </data-browser>
     </ng-template>
 
+    <div class="hidden" iav-databrowser-directive
+      [template]="templateSelected$ | async"
+      [parcellation]="selectedParcellation"
+      [regions]="[region]"
+      #iavDbDirective="iavDatabrowserDirective">
+    </div>
+
     <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
       title: 'Regional features',
-      desc: 123,
+      desc: iavDbDirective?.dataentries?.length,
       iconClass: 'fas fa-database',
       iavNgIf: true,
       content: regionalFeaturesTmpl
diff --git a/src/ui/parcellationRegion/region.base.ts b/src/ui/parcellationRegion/region.base.ts
index 6f4eac0d4..17b3833ca 100644
--- a/src/ui/parcellationRegion/region.base.ts
+++ b/src/ui/parcellationRegion/region.base.ts
@@ -12,9 +12,6 @@ export class RegionBase {
   public rgbString: string
   public rgbDarkmode: boolean
 
-  @Input()
-  showRegionInOtherTmpl: boolean = true
-
   private _region: any
 
   @Input()
@@ -121,6 +118,7 @@ export class RegionBase {
     })
   }
 
+  public GO_TO_REGION_CENTROID = ARIA_LABELS.GO_TO_REGION_CENTROID
   public SHOW_CONNECTIVITY_DATA = ARIA_LABELS.SHOW_CONNECTIVITY_DATA
   public SHOW_IN_OTHER_REF_SPACE = ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE
   public SHOW_ORIGIN_DATASET = ARIA_LABELS.SHOW_ORIGIN_DATASET
diff --git a/src/ui/parcellationRegion/regionMenu/regionMenu.component.spec.ts b/src/ui/parcellationRegion/regionMenu/regionMenu.component.spec.ts
index 9567a7337..3cf92bedd 100644
--- a/src/ui/parcellationRegion/regionMenu/regionMenu.component.spec.ts
+++ b/src/ui/parcellationRegion/regionMenu/regionMenu.component.spec.ts
@@ -3,11 +3,12 @@ import { RegionMenuComponent } from "./regionMenu.component"
 import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module"
 import { UtilModule } from "src/util/util.module"
 import { CommonModule } from "@angular/common"
-import { PreviewDatasetFile } from "src/ui/databrowserModule/pure"
 import { provideMockStore, MockStore } from "@ngrx/store/testing"
 import { regionInOtherTemplateSelector, RenderViewOriginDatasetLabelPipe } from '../region.base'
 import { ARIA_LABELS } from 'common/constants'
 import { By } from "@angular/platform-browser"
+import { Directive, Input } from "@angular/core"
+import { NoopAnimationsModule } from "@angular/platform-browser/animations"
 
 const mt0 = {
   name: 'mt0'
@@ -55,6 +56,31 @@ const hemisphereMrms = [ {
 
 const nohemisphereHrms = [mrm0, mrm1]
 
+@Directive({
+  selector: '[iav-dataset-preview-dataset-file]',
+  exportAs: 'iavDatasetPreviewDatasetFile'
+})
+class MockPrvDsFileDirective {
+  @Input('iav-dataset-preview-dataset-file') 
+  file
+
+  @Input('iav-dataset-preview-dataset-file-filename') 
+  filefilename
+
+  @Input('iav-dataset-preview-dataset-file-dataset') 
+  filedataset
+
+  @Input('iav-dataset-preview-dataset-file-kgid') 
+  filekgid
+
+  @Input('iav-dataset-preview-dataset-file-kgschema') 
+  filekgschema
+
+  @Input('iav-dataset-preview-dataset-file-fullid') 
+  filefullid
+
+}
+
 describe('> regionMenu.component.ts', () => {
   describe('> RegionMenuComponent', () => {
     beforeEach(async(() => {
@@ -64,6 +90,7 @@ describe('> regionMenu.component.ts', () => {
           UtilModule,
           AngularMaterialModule,
           CommonModule,
+          NoopAnimationsModule,
         ],
         declarations: [
           RegionMenuComponent,
@@ -71,7 +98,7 @@ describe('> regionMenu.component.ts', () => {
           /**
            * Used by regionMenu.template.html to show region preview
            */
-          PreviewDatasetFile,
+          MockPrvDsFileDirective,
         ],
         providers: [
           provideMockStore({ initialState: {} })
@@ -87,7 +114,7 @@ describe('> regionMenu.component.ts', () => {
     
     describe('> regionInOtherTemplatesTmpl', () => {
 
-      it('> toggleBtn does not exists if selector returns empty array', () => {
+      it('> if selector returns empty array, data-available-in-tmpl-count == 0', () => {
 
         const mockStore = TestBed.inject(MockStore)
         mockStore.overrideSelector(
@@ -99,11 +126,11 @@ describe('> regionMenu.component.ts', () => {
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
 
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
-        expect(toggleBtn).toBeFalsy()
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        expect(toggleBtn.attributes['data-available-in-tmpl-count']).toEqual('0')
       })
 
-      it('> toggleBtn exists if selector returns non empty array', () => {
+      it('> if selector returns non empty array, data-available-in-tmpl-count == array.length', () => {
 
         const mockStore = TestBed.inject(MockStore)
         mockStore.overrideSelector(
@@ -115,8 +142,8 @@ describe('> regionMenu.component.ts', () => {
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
 
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
-        expect(toggleBtn).toBeTruthy()
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        expect(toggleBtn.attributes['data-available-in-tmpl-count']).toEqual('2')
       })
 
       it('> if showRegionInOtherTmpl is set to false, toggle btn will not be shown', () => {
@@ -148,7 +175,7 @@ describe('> regionMenu.component.ts', () => {
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
 
-        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
         expect(listContainer).toBeFalsy()
       })
 
@@ -163,10 +190,10 @@ describe('> regionMenu.component.ts', () => {
         const fixture = TestBed.createComponent(RegionMenuComponent)
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
         toggleBtn.triggerEventHandler('click', null)
         fixture.detectChanges()
-        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
         expect(listContainer).toBeTruthy()
       })
 
@@ -181,11 +208,11 @@ describe('> regionMenu.component.ts', () => {
         const fixture = TestBed.createComponent(RegionMenuComponent)
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
         toggleBtn.triggerEventHandler('click', null)
         fixture.detectChanges()
-        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
-        expect(listContainer.nativeElement.children.length).toEqual(2)
+        const listContainer = fixture.debugElement.queryAll( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"] [role="button"]`) )
+        expect(listContainer.length).toEqual(2)
       })
 
       it('> the text (no hemisphere metadata) on the list is as expected', () => {
@@ -199,13 +226,14 @@ describe('> regionMenu.component.ts', () => {
         const fixture = TestBed.createComponent(RegionMenuComponent)
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
         toggleBtn.triggerEventHandler('click', null)
         fixture.detectChanges()
-        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        const listContainer = fixture.debugElement.queryAll( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"] [role="button"]`) )
 
         // trim white spaces before and after
-        const texts = Array.from(listContainer.nativeElement.children).map((c: HTMLElement) => c.textContent.replace(/^\s+/, '').replace(/\s+$/, ''))
+        
+        const texts = listContainer.map(c => c.nativeElement.textContent.replace(/^\s+/, '').replace(/\s+$/, ''))
         expect(texts).toContain(mt0.name)
         expect(texts).toContain(mt1.name)
       })
@@ -221,13 +249,13 @@ describe('> regionMenu.component.ts', () => {
         const fixture = TestBed.createComponent(RegionMenuComponent)
         fixture.componentInstance.region = mr1
         fixture.detectChanges()
-        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"]`) )
+        const toggleBtn = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
         toggleBtn.triggerEventHandler('click', null)
         fixture.detectChanges()
-        const listContainer = fixture.debugElement.query( By.css(`[aria-label="${ARIA_LABELS.AVAILABILITY_IN_OTHER_REF_SPACE}"]`) )
+        const listContainer = fixture.debugElement.queryAll( By.css(`[aria-label="${ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE}"] [role="button"]`) )
 
         // trim white spaces before and after, and middle white spaces into a single white space
-        const texts = Array.from(listContainer.nativeElement.children).map((c: HTMLElement) => c.textContent.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' '))
+        const texts = listContainer.map(c => c.nativeElement.textContent.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' '))
         expect(texts).toContain(`${mt0.name} (left hemisphere)`)
         expect(texts).toContain(`${mt1.name} (left hemisphere)`)
       })
diff --git a/src/ui/parcellationRegion/regionMenu/regionMenu.component.ts b/src/ui/parcellationRegion/regionMenu/regionMenu.component.ts
index 8d1210146..8d9f08545 100644
--- a/src/ui/parcellationRegion/regionMenu/regionMenu.component.ts
+++ b/src/ui/parcellationRegion/regionMenu/regionMenu.component.ts
@@ -1,7 +1,8 @@
-import { Component, OnDestroy } from "@angular/core";
+import { Component, OnDestroy, Input } from "@angular/core";
 import { Store } from "@ngrx/store";
 import { Subscription } from "rxjs";
 import { RegionBase } from '../region.base'
+import { ARIA_LABELS } from 'common/constants'
 
 @Component({
   selector: 'region-menu',
@@ -22,4 +23,8 @@ export class RegionMenuComponent extends RegionBase implements OnDestroy {
     this.subscriptions.forEach(s => s.unsubscribe())
   }
 
+  @Input()
+  showRegionInOtherTmpl: boolean = true
+
+  SHOW_IN_OTHER_REF_SPACE = ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE
 }
diff --git a/src/ui/parcellationRegion/regionMenu/regionMenu.template.html b/src/ui/parcellationRegion/regionMenu/regionMenu.template.html
index 7cbfc972b..75d64eafe 100644
--- a/src/ui/parcellationRegion/regionMenu/regionMenu.template.html
+++ b/src/ui/parcellationRegion/regionMenu/regionMenu.template.html
@@ -13,20 +13,16 @@
     </mat-card-title>
 
     <!-- subtitle on what it is -->
-    <mat-card-subtitle>
+    <mat-card-subtitle class="d-inline-flex align-items-center">
       <mat-icon fontSet="fas" fontIcon="fa-brain"></mat-icon>
       <span>
         Brain region
       </span>
-    </mat-card-subtitle>
-
-    <mat-divider></mat-divider>
 
-    <!-- other info about brain region -->
-    <mat-card-subtitle class="mt-4 mb-0 ml-5-n mr-5-n">
+      <mat-divider vertical="true" class="ml-2 h-2rem"></mat-divider>
 
       <!-- origin datas -->
-      <button mat-button 
+      <button mat-icon-button 
         [color]="previewDirective.active ? 'primary' : 'basic'"
         *ngFor="let originDataset of (region.originDatasets || []); let index = index"
         iav-dataset-preview-dataset-file
@@ -37,21 +33,35 @@
         [attr.primary]="previewDirective.active || null"
         role="switch"
         [attr.aria-checked]="previewDirective.active"
+        [matTooltip]="SHOW_ORIGIN_DATASET"
         [attr.aria-label]="SHOW_ORIGIN_DATASET">
         <mat-icon fontSet="fas" fontIcon="fa-eye"></mat-icon>
-        <span>
+        <!-- <span>
           View {{ regionOriginDatasetLabels$ | async | renderViewOriginDatasetlabel : index }}
-        </span>
+        </span> -->
       </button>
 
+
       <!-- position -->
       <button mat-icon-button *ngIf="region?.position"
         (click)="navigateToRegion()"
-        [matTooltip]="region.position | nmToMm | addUnitAndJoin : 'mm'">
+        [matTooltip]="GO_TO_REGION_CENTROID + ': ' + (region.position | nmToMm | addUnitAndJoin : 'mm')">
         <mat-icon fontSet="fas" fontIcon="fa-map-marked-alt">
         </mat-icon>
       </button>
+
+      <!-- region in other templates -->
+      <button mat-icon-button
+        *ngIf="showRegionInOtherTmpl"
+        [attr.data-available-in-tmpl-count]="(regionInOtherTemplates$ | async).length"
+        [attr.aria-label]="AVAILABILITY_IN_OTHER_REF_SPACE"
+        [matMenuTriggerFor]="regionInOtherTemplatesMenu"
+        [matMenuTriggerData]="{ regionInOtherTemplates: regionInOtherTemplates$ | async }">
+        <i class="fas fa-globe"></i>
+      </button>
+
     </mat-card-subtitle>
+
   </div>
 </mat-card>
 
@@ -68,43 +78,24 @@
 </mat-menu>
 
 <!-- template for switching template -->
-<ng-template #regionInOtherTemplatesTmpl let-regionInOtherTemplates="regionInOtherTemplates">
-
-  <div iav-switch #changeTmplSwitch="iavSwitch">
+<mat-menu #regionInOtherTemplatesMenu="matMenu"
+  [aria-label]="SHOW_IN_OTHER_REF_SPACE">
+  hello world
+  <ng-template matMenuContent let-regionInOtherTemplates="regionInOtherTemplates">
 
-    <mat-list-item *ngIf="regionInOtherTemplates.length"
+    <mat-list-item *ngFor="let sameRegion of regionInOtherTemplates; let i = index"
+      [attr.aria-label]="SHOW_IN_OTHER_REF_SPACE + ': ' + sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '') "
+      (click)="changeView(sameRegion)"
       mat-ripple
-      [attr.aria-label]="SHOW_IN_OTHER_REF_SPACE"
-      (click)="changeTmplSwitch && changeTmplSwitch.toggle()">
-      <mat-icon fontSet="fas" fontIcon="fa-brain" mat-list-icon></mat-icon>
+      [attr.role]="'button'">
+      <mat-icon fontSet="fas" fontIcon="fa-none" mat-list-icon></mat-icon>
       <div mat-line>
-        <span>
-          Explore in other templates
-        </span>
-        <span class="muted">
-          ({{ regionInOtherTemplates.length }})
-        </span>
+        <ng-container *ngTemplateOutlet="regionInOtherTemplate; context: sameRegion">
+        </ng-container>
       </div>
-      <mat-icon fontSet="fas" [fontIcon]="changeTmplSwitch.switchState ? 'fa-chevron-up' : 'fa-chevron-down'"></mat-icon>
     </mat-list-item>
-
-    <!-- change template items -->
-    <div *ngIf="changeTmplSwitch.switchState"
-      [attr.aria-label]="AVAILABILITY_IN_OTHER_REF_SPACE">
-      <mat-list-item *ngFor="let sameRegion of regionInOtherTemplates; let i = index"
-        [attr.aria-label]="SHOW_IN_OTHER_REF_SPACE + ': ' + sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '') "
-        (click)="changeView(sameRegion)"
-        mat-ripple
-        [attr.role]="'button'">
-        <mat-icon fontSet="fas" fontIcon="fa-none" mat-list-icon></mat-icon>
-        <div mat-line>
-          <ng-container *ngTemplateOutlet="regionInOtherTemplate; context: sameRegion">
-          </ng-container>
-        </div>
-      </mat-list-item>
-    </div>
-  </div>
-</ng-template>
+  </ng-template>
+</mat-menu>
 
 <!-- template for rendering template name and template hemisphere -->
 <ng-template #regionInOtherTemplate let-template="template" let-hemisphere="hemisphere">
-- 
GitLab