From c9b2cdf285c95bb81f04f86c0fa6e7637bbe3bb5 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Mon, 26 Jul 2021 14:52:17 +0200
Subject: [PATCH] feat: reorganised regional features

---
 .../genericInfoCmp/genericInfo.component.ts}  |  58 ++++++-
 .../genericInfoCmp/genericInfo.style.css}     |   0
 .../genericInfoCmp/genericInfo.template.html} |  16 +-
 .../bsFeatures/genericInfo/index.ts           |   2 +
 .../bsFeatures/genericInfo/module.ts          |  65 +++++++
 .../bsFeatures/ieeg/ieegCmp/ieeg.style.css    |   5 -
 .../ieeg/ieegCmp/ieeg.template.html           |  18 --
 .../regionalFeatures/bsFeatures/ieeg/index.ts |   8 +
 .../bsFeatures/ieeg/module.ts                 |   3 +-
 .../regionalFeatures/bsFeatures/ieeg/type.ts  |   1 +
 .../showDataset/showDataset.directive.ts      |   2 +-
 .../bsFeatures/kgRegionalFeature/index.ts     |   8 +
 .../kgRegList/kgRegList.style.css             |   4 -
 .../kgRegList/kgRegList.template.html         |   2 +-
 .../bsFeatures/kgRegionalFeature/module.ts    |  61 ++-----
 .../bsFeatures/kgRegionalFeature/type.ts      |   2 +-
 .../regionalFeatures/bsFeatures/module.ts     |  14 +-
 .../pipes/getBadgeFromFeature.pipe.ts         |  36 ++++
 .../renderRegionalFeatureSummary.pipe.ts      |  31 ++++
 .../bsFeatures/receptor/entry/entry.style.css |   4 +-
 .../receptor/entry/entry.template.html        |  22 +--
 .../bsFeatures/receptor/index.ts              |   3 +-
 .../bsFeatures/receptor/module.ts             |   3 +-
 .../bsFeatures/receptor/type.ts               |   2 +
 .../regionalFeatureWrapper.component.ts       | 160 +++++++++++++-----
 .../regionalFeatureWrapper.style.css          |  13 ++
 .../regionalFeatureWrapper.template.html      |  94 ++++++----
 .../regionalFeatures/bsFeatures/type.ts       |   9 +
 src/res/css/extra_styles.css                  |   8 +
 src/util/interfaces.ts                        |   2 +-
 .../viewerCmp/viewerCmp.component.ts          |  73 ++++----
 .../viewerCmp/viewerCmp.template.html         |   7 +-
 32 files changed, 501 insertions(+), 235 deletions(-)
 rename src/atlasComponents/regionalFeatures/bsFeatures/{kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts => genericInfo/genericInfoCmp/genericInfo.component.ts} (56%)
 rename src/atlasComponents/regionalFeatures/bsFeatures/{kgRegionalFeature/kgRegDetail/kgRegDetail.style.css => genericInfo/genericInfoCmp/genericInfo.style.css} (100%)
 rename src/atlasComponents/regionalFeatures/bsFeatures/{kgRegionalFeature/kgRegDetail/kgRegDetail.template.html => genericInfo/genericInfoCmp/genericInfo.template.html} (90%)
 create mode 100644 src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/index.ts
 create mode 100644 src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/module.ts
 create mode 100644 src/atlasComponents/regionalFeatures/bsFeatures/ieeg/index.ts
 create mode 100644 src/atlasComponents/regionalFeatures/bsFeatures/pipes/getBadgeFromFeature.pipe.ts
 create mode 100644 src/atlasComponents/regionalFeatures/bsFeatures/pipes/renderRegionalFeatureSummary.pipe.ts

diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.component.ts
similarity index 56%
rename from src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts
rename to src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.component.ts
index ff3f6f1a6..d36cc47d4 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.component.ts
@@ -1,25 +1,34 @@
-import { Component, Inject, Input, OnChanges, Optional } from "@angular/core";
+import { AfterViewInit, Component, Inject, Input, OnChanges, OnDestroy, Optional, TemplateRef, ViewChild, ViewContainerRef, ViewRef } from "@angular/core";
 import { BsRegionInputBase } from "../../bsRegionInputBase";
-import { KG_REGIONAL_FEATURE_KEY, TBSDetail, UNDER_REVIEW } from "../type";
+import { KG_REGIONAL_FEATURE_KEY, TBSDetail, UNDER_REVIEW } from "../../kgRegionalFeature/type";
 import { ARIA_LABELS, CONST } from 'common/constants'
 import { TBSSummary } from "../../kgDataset";
 import { BsFeatureService } from "../../service";
 import { MAT_DIALOG_DATA } from "@angular/material/dialog";
 import { TDatainfos } from "src/util/siibraApiConstants/types";
+import { TRegion } from "../../type";
 
 /**
  * this component is specifically used to render side panel ebrains dataset view
  */
 
+export type TInjectableData = TDatainfos & {
+  dataType?: string
+  view?: ViewRef | TemplateRef<any>
+  region?: TRegion
+  summary?: TBSSummary
+  isGdprProtected?: boolean
+}
+
 @Component({
-  selector: 'kg-regional-feature-detail',
-  templateUrl: './kgRegDetail.template.html',
+  selector: 'generic-info-cmp',
+  templateUrl: './genericInfo.template.html',
   styleUrls: [
-    './kgRegDetail.style.css'
+    './genericInfo.style.css'
   ]
 })
 
-export class KgRegDetailCmp extends BsRegionInputBase implements OnChanges {
+export class GenericInfoCmp extends BsRegionInputBase implements OnChanges, AfterViewInit, OnDestroy {
 
   public ARIA_LABELS = ARIA_LABELS
   public CONST = CONST
@@ -38,6 +47,7 @@ export class KgRegDetailCmp extends BsRegionInputBase implements OnChanges {
 
   public descriptionFallback = `[This dataset cannot be fetched right now]`
   public useClassicUi = false
+  public dataType = 'ebrains regional dataset'
 
   public description: string
   public name: string
@@ -46,17 +56,49 @@ export class KgRegDetailCmp extends BsRegionInputBase implements OnChanges {
     doi: string
   }[]
 
+  template: TemplateRef<any>
+  viewref: ViewRef
+
+  @ViewChild('insertViewTarget', { read: ViewContainerRef })
+  insertedViewVCR: ViewContainerRef
+
   constructor(
     svc: BsFeatureService,
-    @Optional() @Inject(MAT_DIALOG_DATA) data: TDatainfos
+    @Optional() @Inject(MAT_DIALOG_DATA) data: TInjectableData
   ){
     super(svc)
     if (data) {
-      const { description, name, urls, useClassicUi } = data
+      const { dataType, description, name, urls, useClassicUi, view, region, summary, isGdprProtected } = data
       this.description = description
       this.name = name
       this.urls = urls
       this.useClassicUi = useClassicUi
+      if (dataType) this.dataType = dataType
+      if (typeof isGdprProtected !== 'undefined') this.isGdprProtected = isGdprProtected
+
+      if (!!view) {
+        if (view instanceof TemplateRef){
+          this.template = view
+        } else {
+          this.viewref = view
+        }
+      }
+
+      if (region && summary) {
+        this.region = region
+        this.summary = summary
+        this.ngOnChanges()
+      }
+    }
+  }
+
+  ngOnDestroy(){
+    this.insertedViewVCR.clear()
+  }
+
+  ngAfterViewInit(){
+    if (this.insertedViewVCR && this.viewref) {
+      this.insertedViewVCR.insert(this.viewref)
     }
   }
 
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.style.css b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.style.css
similarity index 100%
rename from src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.style.css
rename to src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.style.css
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.template.html
similarity index 90%
rename from src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html
rename to src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.template.html
index e743a14cd..ab89e43ad 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/genericInfoCmp/genericInfo.template.html
@@ -12,6 +12,8 @@
     <ng-container *ngTemplateOutlet="descTmpl"></ng-container>
   </small>
 
+  <ng-container *ngTemplateOutlet="insertedView">
+  </ng-container>
 
   <!-- footer -->
   <mat-card-actions iav-media-query #iavMediaQuery="iavMediaQuery">
@@ -60,7 +62,7 @@
       <mat-card-subtitle class="d-inline-flex align-items-center">
         <mat-icon fontSet="fas" fontIcon="fa-database"></mat-icon>
         <span>
-          ebrains regional dataset
+          {{ dataType }}
         </span>
 
         <button *ngIf="isGdprProtected"
@@ -92,6 +94,11 @@
     <ng-container *ngTemplateOutlet="descTmpl">
     </ng-container>
   </div>
+
+  <div>
+    <ng-container *ngTemplateOutlet="insertedView">
+    </ng-container>
+  </div>
 </ng-template>
 
 <ng-template #nameTmpl>
@@ -107,6 +114,13 @@
   </markdown-dom>
 </ng-template>
 
+<!-- inserted view -->
+<ng-template #insertedView>
+  <ng-template #insertViewTarget>
+
+  </ng-template>
+</ng-template>
+
 <!-- is loading tmpl -->
 <ng-template #isLoadingTmpl>
   <spinner-cmp></spinner-cmp>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/index.ts b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/index.ts
new file mode 100644
index 000000000..d38b84407
--- /dev/null
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/index.ts
@@ -0,0 +1,2 @@
+export { GenericInfoModule } from './module'
+export { GenericInfoCmp, TInjectableData } from './genericInfoCmp/genericInfo.component'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/module.ts
new file mode 100644
index 000000000..22c713041
--- /dev/null
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/genericInfo/module.ts
@@ -0,0 +1,65 @@
+import { CommonModule } from "@angular/common";
+import { Component, Inject, NgModule, Optional } from "@angular/core";
+import { MAT_DIALOG_DATA } from "@angular/material/dialog";
+import { ComponentsModule } from "src/components";
+import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module";
+import { UtilModule } from "src/util";
+import { IAV_DATASET_SHOW_DATASET_DIALOG_CMP } from "../kgDataset/showDataset/showDataset.directive";
+import { GenericInfoCmp } from "./genericInfoCmp/genericInfo.component";
+
+@Component({
+  selector: 'show-ds-dialog-cmp',
+  template: `
+<ng-template [ngIf]="useClassicUi" [ngIfElse]="modernUiTmpl">
+  <generic-info-cmp></generic-info-cmp>
+</ng-template>
+
+<ng-template #modernUiTmpl>
+
+  <mat-dialog-content class="m-0 p-0">
+    <generic-info-cmp></generic-info-cmp>
+  </mat-dialog-content>
+
+  <mat-dialog-actions align="center">
+    <button mat-button mat-dialog-close>
+      Close
+    </button>
+  </mat-dialog-actions>
+
+</ng-template>
+`
+})
+
+export class ShowDsDialogCmp{
+  public useClassicUi = false
+  constructor(
+    @Optional() @Inject(MAT_DIALOG_DATA) data: any
+  ){
+    this.useClassicUi = data.useClassicUi
+  }
+}
+
+@NgModule({
+  imports: [
+    CommonModule,
+    AngularMaterialModule,
+    UtilModule,
+    ComponentsModule,
+  ],
+  declarations: [
+    GenericInfoCmp,
+    ShowDsDialogCmp,
+  ],
+  exports: [
+    GenericInfoCmp,
+  ],
+
+  providers: [
+    {
+      provide: IAV_DATASET_SHOW_DATASET_DIALOG_CMP,
+      useValue: ShowDsDialogCmp
+    }
+  ]
+})
+
+export class GenericInfoModule{}
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.style.css b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.style.css
index d049e6fac..e69de29bb 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.style.css
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.style.css
@@ -1,5 +0,0 @@
-mat-expansion-panel
-{
-  margin-left: -24px;
-  margin-right: -24px;
-}
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.template.html
index 575b6632f..faa88471f 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/ieegCmp/ieeg.template.html
@@ -31,24 +31,6 @@
       </section>
     </section> -->
 
-    <h4 class="mat-h4">
-      {{ datum['name'] }}
-    </h4>
-
-    <button
-      [matTooltip]="CONST.GDPR_TEXT"
-      mat-icon-button color="warn">
-      <i class="fas fa-exclamation-triangle"></i>
-    </button>
-
-    <a [href]="'https://search.kg.ebrains.eu/instances/' + datum.__kg_id"
-      mat-icon-button
-      color="primary"
-      target="_blank"
-      [matTooltip]="ARIA_LABELS.EXPLORE_DATASET_IN_KG"
-      [attr.aria-labels]="ARIA_LABELS.EXPLORE_DATASET_IN_KG">
-      <i class="fas fa-external-link-alt"></i>
-    </a>
     <mat-divider></mat-divider>
 
     <label for="contact-points-list" class="d-block mat-h4 mt-4 text-muted">
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/index.ts b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/index.ts
new file mode 100644
index 000000000..e4e8322a0
--- /dev/null
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/index.ts
@@ -0,0 +1,8 @@
+export {
+  BsFeatureIEEGModule
+} from './module'
+
+export {
+  IEEG_FEATURE_NAME,
+  SIIBRA_FEATURE_KEY,
+} from './type'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/module.ts
index 7da095414..086074560 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/module.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/module.ts
@@ -6,6 +6,7 @@ import { UtilModule } from "src/util";
 import { BsFeatureService } from "../service";
 import { BsFeatureIEEGCmp } from "./ieegCmp/ieeg.component";
 import { BsFeatureIEEGDirective } from "./ieegCtrl.directive";
+import { IEEG_FEATURE_NAME } from "./type";
 
 @NgModule({
   imports: [
@@ -23,7 +24,7 @@ import { BsFeatureIEEGDirective } from "./ieegCtrl.directive";
 export class BsFeatureIEEGModule{
   constructor(svc: BsFeatureService){
     svc.registerFeature({
-      name: 'iEEG recordings',
+      name: IEEG_FEATURE_NAME,
       icon: 'fas fa-info',
       View: BsFeatureIEEGCmp,
       Ctrl: BsFeatureIEEGDirective
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/type.ts
index 37454f35b..fb910a33c 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/type.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/ieeg/type.ts
@@ -17,3 +17,4 @@ export type TBSDEtail = {
 }
 
 export const SIIBRA_FEATURE_KEY = 'IEEG_Electrode'
+export const IEEG_FEATURE_NAME = 'iEEG recordings'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgDataset/showDataset/showDataset.directive.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgDataset/showDataset/showDataset.directive.ts
index 4e48f9951..2cc1dae60 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgDataset/showDataset/showDataset.directive.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgDataset/showDataset/showDataset.directive.ts
@@ -68,7 +68,7 @@ export class ShowDatasetDialogDirective{
     }
 
     if (this.overwriteFn) {
-      return this.overwriteFn(data, this)
+      return this.overwriteFn(data)
     }
 
     if (!this.dialogCmp) throw new Error(`IAV_DATASET_SHOW_DATASET_DIALOG_CMP not provided!`)
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/index.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/index.ts
index 251565d34..3efa1d80e 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/index.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/index.ts
@@ -1,3 +1,11 @@
 export {
   KgRegionalFeatureModule
 } from './module'
+
+export {
+  EbrainsRegionalFeatureName,
+  KG_REGIONAL_FEATURE_KEY,
+  UNDER_REVIEW,
+  TBSDetail,
+  TBSSummary
+} from './type'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.style.css b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.style.css
index f3a3b5acb..a0d49c324 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.style.css
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.style.css
@@ -7,7 +7,3 @@ modality-picker
 {
   font-size: 90%;
 }
-.virtual-scroll-element
-{
-  height:50px;
-}
\ No newline at end of file
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
index 4426e64ff..010f4c859 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
@@ -8,7 +8,7 @@
     maxBufferPx="400"
     itemSize="50">
     <div *cdkVirtualFor="let dataset of visibleRegionalFeatures; trackBy: trackByFn; templateCacheSize: 20; let index = index"
-      class="virtual-scroll-element overflow-hidden">
+      class="h-50px overflow-hidden">
 
       <!-- divider, show if not first -->
       <mat-divider class="mt-1" *ngIf="index !== 0"></mat-divider>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
index 8af82e8e0..dcf021cc7 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
@@ -1,48 +1,15 @@
 import { CommonModule } from "@angular/common";
-import { Component, Inject, NgModule, Optional } from "@angular/core";
+import { Inject, NgModule, Optional } from "@angular/core";
 import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module";
 import { KgRegSummaryCmp } from "./kgRegSummary/kgRegSummary.component";
 import { KgRegionalFeaturesList } from "./kgRegList/kgRegList.component";
 import { KgRegionalFeaturesListDirective } from "./kgRegList/kgReglist.directive";
-import { KgRegDetailCmp } from "./kgRegDetail/kgRegDetail.component";
 import { KgDatasetModule } from "../kgDataset";
-import { IAV_DATASET_SHOW_DATASET_DIALOG_CMP } from "../kgDataset/showDataset/showDataset.directive";
 import { UtilModule } from "src/util";
 import { ComponentsModule } from "src/components";
 import { BsFeatureService } from "../service";
-import { MAT_DIALOG_DATA } from "@angular/material/dialog";
-
-@Component({
-  selector: 'show-ds-dialog-cmp',
-  template: `
-<ng-template [ngIf]="useClassicUi" [ngIfElse]="modernUiTmpl">
-  <kg-regional-feature-detail></kg-regional-feature-detail>
-</ng-template>
-
-<ng-template #modernUiTmpl>
-
-  <mat-dialog-content class="m-0 p-0">
-    <kg-regional-feature-detail></kg-regional-feature-detail>
-  </mat-dialog-content>
-
-  <mat-dialog-actions align="center">
-    <button mat-button mat-dialog-close>
-      Close
-    </button>
-  </mat-dialog-actions>
-
-</ng-template>
-`
-})
-
-export class ShowDsDialogCmp{
-  public useClassicUi = false
-  constructor(
-    @Optional() @Inject(MAT_DIALOG_DATA) data: any
-  ){
-    this.useClassicUi = data.useClassicUi
-  }
-}
+import { EbrainsRegionalFeatureName } from "./type";
+import { GENERIC_INFO_INJ_TOKEN } from "../type";
 
 @NgModule({
   imports: [
@@ -56,29 +23,27 @@ export class ShowDsDialogCmp{
     KgRegSummaryCmp,
     KgRegionalFeaturesList,
     KgRegionalFeaturesListDirective,
-    KgRegDetailCmp,
-    ShowDsDialogCmp,
   ],
   exports:[
     KgRegSummaryCmp,
     KgRegionalFeaturesList,
     KgRegionalFeaturesListDirective,
-    KgRegDetailCmp,
   ],
-  providers: [
-    {
-      provide: IAV_DATASET_SHOW_DATASET_DIALOG_CMP,
-      useValue: ShowDsDialogCmp
-    }
-  ]
 })
 
 export class KgRegionalFeatureModule{
-  constructor(svc: BsFeatureService){
+  constructor(
+    svc: BsFeatureService,
+    @Optional() @Inject(GENERIC_INFO_INJ_TOKEN) Cmp: any
+  ){
+    if (!Cmp) {
+      console.warn(`GENERIC_INFO_INJ_TOKEN not injected!`)
+      return
+    }
     svc.registerFeature({
-      name: 'EBRAINS datasets',
+      name: EbrainsRegionalFeatureName,
       icon: 'fas fa-ellipsis-h',
-      View: KgRegionalFeaturesList,
+      View: null,
       Ctrl: KgRegionalFeaturesListDirective,
     })
   }
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
index beb275754..f7ebe6036 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
@@ -2,9 +2,9 @@ export {
   TBSDetail, TBSSummary
 } from '../kgDataset'
 
+export const EbrainsRegionalFeatureName = 'EBRAINS datasets'
 export const KG_REGIONAL_FEATURE_KEY = 'EbrainsRegionalDataset'
 
 export const UNDER_REVIEW = {
   ['@id']: "https://nexus.humanbrainproject.org/v0/data/minds/core/embargostatus/v1.0.0/1d726b76-b176-47ed-96f0-b4f2e17d5f19"
 }
-
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/module.ts
index b9ac4e077..5851de10c 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/module.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/module.ts
@@ -2,11 +2,15 @@ import { CommonModule } from "@angular/common";
 import { NgModule } from "@angular/core";
 import { ComponentsModule } from "src/components";
 import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module";
+import { GenericInfoCmp, GenericInfoModule } from "./genericInfo";
 import { BsFeatureIEEGModule } from "./ieeg/module";
 import { KgRegionalFeatureModule } from "./kgRegionalFeature";
+import { GetBadgeFromFeaturePipe } from "./pipes/getBadgeFromFeature.pipe";
+import { RenderRegionalFeatureSummaryPipe } from "./pipes/renderRegionalFeatureSummary.pipe";
 import { BSFeatureReceptorModule } from "./receptor";
 import { RegionalFeatureWrapperCmp } from "./regionalFeatureWrapper/regionalFeatureWrapper.component";
 import { BsFeatureService } from "./service";
+import { GENERIC_INFO_INJ_TOKEN } from "./type";
 
 @NgModule({
   imports: [
@@ -16,15 +20,23 @@ import { BsFeatureService } from "./service";
     BSFeatureReceptorModule,
     BsFeatureIEEGModule,
     ComponentsModule,
+    GenericInfoModule,
   ],
   declarations: [
     RegionalFeatureWrapperCmp,
+    RenderRegionalFeatureSummaryPipe,
+    GetBadgeFromFeaturePipe,
   ],
   providers: [
-    BsFeatureService
+    BsFeatureService,
+    {
+      provide: GENERIC_INFO_INJ_TOKEN,
+      useValue: GenericInfoCmp
+    }
   ],
   exports: [
     RegionalFeatureWrapperCmp,
+    GenericInfoModule,
   ]
 })
 
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/pipes/getBadgeFromFeature.pipe.ts b/src/atlasComponents/regionalFeatures/bsFeatures/pipes/getBadgeFromFeature.pipe.ts
new file mode 100644
index 000000000..8fe67e163
--- /dev/null
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/pipes/getBadgeFromFeature.pipe.ts
@@ -0,0 +1,36 @@
+import { Pipe, PipeTransform } from "@angular/core";
+import { IBSSummaryResponse, TContextedFeature } from "../type";
+import {
+  IEEG_FEATURE_NAME
+} from '../ieeg'
+import {
+  RECEPTOR_FEATURE_NAME
+} from '../receptor'
+
+export type TBadge = {
+  text: string
+  color: 'primary' | 'warn' | 'accent'
+}
+
+@Pipe({
+  name: 'getBadgeFromFeaturePipe',
+  pure: true
+})
+
+export class GetBadgeFromFeaturePipe implements PipeTransform{
+  public transform(input: TContextedFeature<keyof IBSSummaryResponse>): TBadge[]{
+    if (input.featureName === IEEG_FEATURE_NAME) {
+      return [{
+        text: IEEG_FEATURE_NAME,
+        color: 'primary',
+      }]
+    }
+    if (input.featureName === RECEPTOR_FEATURE_NAME) {
+      return [{
+        text: RECEPTOR_FEATURE_NAME,
+        color: 'accent',
+      }]
+    }
+    return []
+  }
+}
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/pipes/renderRegionalFeatureSummary.pipe.ts b/src/atlasComponents/regionalFeatures/bsFeatures/pipes/renderRegionalFeatureSummary.pipe.ts
new file mode 100644
index 000000000..829ed0198
--- /dev/null
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/pipes/renderRegionalFeatureSummary.pipe.ts
@@ -0,0 +1,31 @@
+import { Pipe, PipeTransform } from "@angular/core";
+import { IBSSummaryResponse, TContextedFeature } from "../type";
+import {
+  IEEG_FEATURE_NAME
+} from '../ieeg'
+import {
+  RECEPTOR_FEATURE_NAME
+} from '../receptor'
+import {
+  EbrainsRegionalFeatureName
+} from '../kgRegionalFeature'
+
+@Pipe({
+  name: 'renderRegionalFeatureSummaryPipe',
+  pure: true,
+})
+
+export class RenderRegionalFeatureSummaryPipe implements PipeTransform{
+  public transform(input: TContextedFeature<keyof IBSSummaryResponse>): string{
+    if (input.featureName === IEEG_FEATURE_NAME) {
+      return input.result['name']
+    }
+    if (input.featureName === RECEPTOR_FEATURE_NAME) {
+      return input.result['name']
+    }
+    if (input.featureName === EbrainsRegionalFeatureName) {
+      return input.result['src_name']
+    }
+    return `[Unknown feature type]`
+  }
+}
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.style.css b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.style.css
index 92e5c8af4..71beb4683 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.style.css
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.style.css
@@ -3,4 +3,6 @@
   display: block;
   width: 100%;
   height: 100%;
-}
\ No newline at end of file
+  padding-left:24px;
+  padding-right:24px;
+}
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html
index 3343e8006..5a6294e1f 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html
@@ -1,3 +1,5 @@
+<mat-divider class="mt-2 mb-2"></mat-divider>
+
 <!-- potential selector for receptor data -->
 <mat-select class="invisible" [(value)]="selectedREntryId">
   <mat-option *ngFor="let rec of receptorsSummary$ | async"
@@ -8,26 +10,6 @@
 
 <ng-container *ngIf="selectedReceptor$ | async as selectedRec">
 
-  <h3 class="mat-h3">
-    <span>
-      {{ selectedRec.name }}
-    </span>
-  </h3>
-
-  <ng-container *ngFor="let info of (selectedRec.origin_datainfos || [])">
-    <a *ngFor="let url of (info.urls || [])"
-      mat-icon-button
-      color="primary"
-      [href]="url.doi | doiParserPipe"
-      target="_blank"
-      [matTooltip]="ARIA_LABELS.EXPLORE_DATASET_IN_KG"
-      [attr.aria-label]="ARIA_LABELS.EXPLORE_DATASET_IN_KG">
-      <i class="fas fa-external-link-alt"></i>
-    </a>
-  </ng-container>
-
-  <mat-divider class="m-2"></mat-divider>
-
   <bs-features-receptor-fingerprint
     (onSelectReceptor)="onSelectReceptor($event)"
     [bsFeature]="selectedRec">
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/index.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/index.ts
index afe4bd7cc..79f8e55d9 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/index.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/index.ts
@@ -1 +1,2 @@
-export { BSFeatureReceptorModule } from './module'
\ No newline at end of file
+export { BSFeatureReceptorModule } from './module'
+export { RECEPTOR_FEATURE_NAME } from './type'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/module.ts
index c8880c6e8..5527da1e8 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/module.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/module.ts
@@ -9,6 +9,7 @@ import { BsFeatureReceptorEntry } from "./entry/entry.component";
 import { BsFeatureReceptorFingerprint } from "./fp/fp.component";
 import { BsFeatureReceptorDirective } from "./hasReceptor.directive";
 import { BsFeatureReceptorProfile } from "./profile/profile.component";
+import { RECEPTOR_FEATURE_NAME } from "./type";
 
 @NgModule({
   imports: [
@@ -36,7 +37,7 @@ import { BsFeatureReceptorProfile } from "./profile/profile.component";
 export class BSFeatureReceptorModule{
   constructor(svc: BsFeatureService){
     svc.registerFeature({
-      name: 'receptor density',
+      name: RECEPTOR_FEATURE_NAME,
       icon: 'fas fa-info',
       View: BsFeatureReceptorEntry,
       Ctrl: BsFeatureReceptorDirective,
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts
index db91d6912..fd08389b3 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts
@@ -53,3 +53,5 @@ export type TBSDetail = TBSSummary & {
     __profile_unit: string
   }
 }
+
+export const RECEPTOR_FEATURE_NAME = 'receptor density'
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.component.ts
index 610eb96e6..10d488f98 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.component.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.component.ts
@@ -1,9 +1,20 @@
-import { Component, ComponentFactory, ComponentFactoryResolver, Injector, Input, OnChanges, ViewChild, ViewContainerRef } from "@angular/core";
-import { TRegion } from "../type";
+import { Component, ComponentFactory, ComponentFactoryResolver, Inject, Injector, Input, OnChanges, Optional, ViewChild, ViewContainerRef } from "@angular/core";
+import { IBSSummaryResponse, TContextedFeature, TRegion } from "../type";
 import { BsFeatureService, TFeatureCmpInput } from "../service";
-import { BehaviorSubject, combineLatest, Observable } from "rxjs";
-import { map, scan } from "rxjs/operators";
+import { combineLatest, Observable, Subject } from "rxjs";
+import { debounceTime, map, shareReplay, startWith } from "rxjs/operators";
 import { REGISTERED_FEATURE_INJECT_DATA } from "../constants";
+import { ARIA_LABELS } from 'common/constants'
+import {
+  IEEG_FEATURE_NAME
+} from '../ieeg'
+import {
+  RECEPTOR_FEATURE_NAME
+} from '../receptor'
+import {
+  EbrainsRegionalFeatureName
+} from '../kgRegionalFeature'
+import { OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, TOverwriteShowDatasetDialog } from "src/util/interfaces";
 
 @Component({
   selector: 'regional-feature-wrapper',
@@ -15,6 +26,10 @@ import { REGISTERED_FEATURE_INJECT_DATA } from "../constants";
 
 export class RegionalFeatureWrapperCmp implements OnChanges{
 
+  public useVirtualScroll = false
+
+  public ARIA_LABELS = ARIA_LABELS
+
   @Input()
   region: TRegion
 
@@ -23,34 +38,36 @@ export class RegionalFeatureWrapperCmp implements OnChanges{
 
   private weakmap = new WeakMap<(new () => any),  ComponentFactory<any>>()
 
-  public registeredFeatures$: Observable<{
-    name: string
-    icon: string
-    
-  }[]>
+  public registeredFeatures$: Observable<TContextedFeature<keyof IBSSummaryResponse>[]>
   constructor(
     private svc: BsFeatureService,
     private cfr: ComponentFactoryResolver,
-    private injector: Injector,
+    @Optional() @Inject(OVERWRITE_SHOW_DATASET_DIALOG_TOKEN) private overwriteFn: TOverwriteShowDatasetDialog
   ){
     this.registeredFeatures$ = this.registeredFeatureMasterStream$.pipe(
-      scan((acc, curr) => {
-        return {
-          ...acc,
-          ...curr
-        }
-      }),
       map(obj => {
         const returnArr = []
         for (const name in obj) {
           if (obj[name].busy || obj[name].results.length === 0) {
             continue
           }
-          returnArr.push({
-            name,
-            icon: obj[name].icon
-          })
+          for (const result of obj[name].results) {
+            const objToBeInserted = {
+              featureName: name,
+              icon: obj[name].icon,
+              result
+            }
+            /**
+             * place ebrains regional features at the end
+             */
+            if (name === EbrainsRegionalFeatureName) {
+              returnArr.push(objToBeInserted)
+            } else {
+              returnArr.unshift(objToBeInserted)
+            }
+          }
         }
+
         return returnArr
       })
     )
@@ -65,12 +82,13 @@ export class RegionalFeatureWrapperCmp implements OnChanges{
       const ctrl = new feat.Ctrl(this.svc, { region })
       const sub = combineLatest([
         ctrl.busy$,
-        ctrl.results$
+        ctrl.results$.pipe(
+          startWith([])
+        )
       ]).subscribe(
         ([busy, results]) => {
-          this.registeredFeatureMasterStream$.next({
-            [name]: { busy, results, icon }
-          })
+          this.registeredFeatureRawRegister[name] = { busy, results, icon }
+          this.registeredFeatureFireStream$.next(true)
         }
       )
       this.regionOnDestroyCb.push(() => sub.unsubscribe())
@@ -78,16 +96,30 @@ export class RegionalFeatureWrapperCmp implements OnChanges{
   }
   private cleanUpRegionalFeature(){
     while (this.regionOnDestroyCb.length) this.regionOnDestroyCb.pop()()
-    this.registeredFeatureMasterStream$.next({})
+    /**
+     * emit null to signify flush out of existing scan map
+     */
+    this.registeredFeatureRawRegister = {}
+    this.registeredFeatureFireStream$.next(true)
   }
 
-  private registeredFeatureMasterStream$ = new BehaviorSubject<{
+  private registeredFeatureRawRegister: {
     [key: string]: {
       icon: string
       busy: boolean
       results: any[]
     }
-  }>({})
+  } = {}
+  private registeredFeatureFireStream$ = new Subject()
+  private registeredFeatureMasterStream$ = this.registeredFeatureFireStream$.pipe(
+    debounceTime(16),
+    /**
+     * must not use mapTo operator
+     * otherwise the emitted value will not change
+     */
+    map(() => this.registeredFeatureRawRegister),
+    shareReplay(1),
+  )
   public busy$: Observable<boolean> = this.registeredFeatureMasterStream$.pipe(
     map(obj => {
       for (const key in obj) {
@@ -102,23 +134,51 @@ export class RegionalFeatureWrapperCmp implements OnChanges{
     this.setupRegionalFeatureCtrl()
   }
 
-  public activatedFeatureName: string = null
-  activateFeature(featNameObj: {
-    name: string
-  }){
-    const feat = this.svc.registeredFeatures.find(f => f.name === featNameObj.name)
-    if (!feat) {
-      console.log(`cannot find feature with name ${featNameObj.name}`)
+  public handleFeatureClick(contextedFeature: TContextedFeature<any>){
+    if (!this.overwriteFn) {
+      console.warn(`show dialog function not overwritten!`)
       return
     }
-    this.activatedFeatureName = featNameObj.name
-    if (!this.regionalFeatureContainerRef) {
-      console.warn(`regionalFeatureContainerRef not defined.`)
+    
+    const arg = {}
+    if (contextedFeature.featureName === RECEPTOR_FEATURE_NAME) {
+      arg['name'] = contextedFeature.result['name']
+      arg['description'] = contextedFeature.result['info']
+      arg['urls'] = []
+      for (const info of contextedFeature.result['origin_datainfos']) {
+        arg['urls'].push(...info.urls)
+      }
+    }
+
+    if (contextedFeature.featureName === IEEG_FEATURE_NAME) {
+      arg['name'] = contextedFeature.result['name']
+      arg['description'] = ' '
+      arg['isGdprProtected'] = true
+      /**
+       * todo use actual fetched data
+       */
+      const re = /\(dataset:([a-f0-9-]+)\)/.exec(arg['name'])
+      if (re) {
+        arg['urls'] = [{
+          doi: `https://search.kg.ebrains.eu/instances/${re[1]}`
+        }]
+      }
+    }
+
+    if (contextedFeature.featureName === EbrainsRegionalFeatureName) {
+      arg['summary'] = contextedFeature.result
+    }
+
+    const { region } = this
+    
+    const feat = this.svc.registeredFeatures.find(f => f.name === contextedFeature.featureName)
+    if (!feat) {
+      console.log(`cannot find feature with name ${contextedFeature.featureName}`)
       return
     }
-    this.regionalFeatureContainerRef.clear()
     
     const cf = (() => {
+      if (!feat.View) return null
       const mapped = this.weakmap.get(feat.View)
       if (mapped) return mapped
       const _cf = this.cfr.resolveComponentFactory(feat.View)
@@ -126,15 +186,21 @@ export class RegionalFeatureWrapperCmp implements OnChanges{
       return _cf
     })()
 
-    const { region } = this
-
-    const injector = Injector.create({
-      providers: [{
-        provide: REGISTERED_FEATURE_INJECT_DATA,
-        useValue: { region } as TFeatureCmpInput
-      }],
-      parent: this.injector
+    this.overwriteFn({
+      region,
+      dataType: contextedFeature.featureName,
+      view: (() => {
+        if (!cf) return null
+        const injector = Injector.create({
+          providers: [{
+            provide: REGISTERED_FEATURE_INJECT_DATA,
+            useValue: { region } as TFeatureCmpInput
+          }],
+        })
+        const cmp = cf.create(injector)
+        return cmp.hostView
+      })(),
+      ...arg,
     })
-    this.regionalFeatureContainerRef.createComponent(cf, null, injector)
   }
 }
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.style.css b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.style.css
index 325d83c9e..816e7ba25 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.style.css
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.style.css
@@ -4,3 +4,16 @@
   line-height: 1.5rem;
   text-align: center;
 }
+
+.feature-container,
+cdk-virtual-scroll-viewport
+{
+  min-height: 24rem;
+}
+
+
+.feature-container
+{
+  height: 24rem;
+  overflow-y: scroll;
+}
\ No newline at end of file
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.template.html
index 6d501b94f..00212b977 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/regionalFeatureWrapper/regionalFeatureWrapper.template.html
@@ -1,44 +1,68 @@
-<!-- icons container -->
-<div class="d-flex flex-row align-items-stretch">
-
-  <!-- icon container -->
-  <div *ngFor="let feature of registeredFeatures$ | async; let last = last"
-    class="d-flex flex-row">
-
-    <!-- hoverable/clickable -->
-    <div class="p-2 flex-grow-1 flex-shrink-1 w-5em d-inline-flex flex-column align-items-center iv-custom-comp hoverable"
-      (click)="activateFeature(feature)"
-      [ngClass]="{
-        'text primary': activatedFeatureName === feature.name
-      }"
-      mat-ripple>
-
-      <!-- icon container -->
-      <div class="h-4rem d-flex align-items-center justify-content-center">
-        <i class="d-inline-block" [ngClass]="feature.icon"></i>
-      </div>
+<spinner-cmp *ngIf="busy$ | async; else resultTmpl"></spinner-cmp>
+
+<ng-template #resultTmpl>
+  
+  <!-- virtual scroll. do not activate until autosize is supported -->
+  <cdk-virtual-scroll-viewport
+    *ngIf="useVirtualScroll; else regularScrollTmpl"
+    [attr.aria-label]="ARIA_LABELS.LIST_OF_DATASETS_ARIA_LABEL"
+    class="h-100"
+    minBufferPx="200"
+    maxBufferPx="400"
+    itemSize="50">
+    <div *cdkVirtualFor="let feature of registeredFeatures$ | async; templateCacheSize: 20; let index = index"
+      class="h-50px overflow-hidden">
+
+      <!-- divider, show if not first -->
+      <mat-divider *ngIf="index !== 0"></mat-divider>
+      <ng-container *ngTemplateOutlet="itemContainer; context: { $implicit: feature }">
+      </ng-container>
 
-      <!-- text -->
-      <span class="d-inline-block button-text">
-        {{ feature.name }}
-      </span>
     </div>
+  </cdk-virtual-scroll-viewport>
 
-    <!-- divider -->
-    <mat-divider *ngIf="!last" vertical="true"
-      class="flex-grow-0 flex-shrink-0">
-    </mat-divider>
-    
-  </div>
-</div>
+  <!-- fallback, regular scroll -->
+  <!-- less efficient on large list, but for now should do -->
+  <ng-template #regularScrollTmpl>
+    <div class="feature-container"
+      [attr.aria-label]="ARIA_LABELS.LIST_OF_DATASETS_ARIA_LABEL">
 
-<spinner-cmp *ngIf="busy$ | async"></spinner-cmp>
+      <div *ngFor="let feature of registeredFeatures$ | async; let index = index"
+        class="overflow-hidden">
 
+        <!-- divider, show if not first -->
+        <mat-divider *ngIf="index !== 0"></mat-divider>
+        <ng-container *ngTemplateOutlet="itemContainer; context: { $implicit: feature }">
+        </ng-container>
 
-<span *ngIf="!activatedFeatureName"
-  class="text-muted pt-4">
-  select type of regional feature
-</span>
+      </div>
+    </div>
+  </ng-template>
+  
+</ng-template>
+
+<!-- feature template -->
+<ng-template #itemContainer let-feature>
+  <div class="d-inline-block pt-4 cursor-default"
+    (click)="handleFeatureClick(feature)"
+    mat-ripple>
+
+    <!-- mat-chip container -->
+    <!-- do not use mat-chip-list to avoid adding incorrect a11y info -->
+    <div class="transform-origin-left-center scale-80">
+      <mat-chip *ngFor="let badge of feature | getBadgeFromFeaturePipe"
+        [color]="badge.color"
+        selected>
+        {{ badge.text }}
+      </mat-chip>
+    </div>
+
+    <small>
+      {{ feature | renderRegionalFeatureSummaryPipe }}
+    </small>
+  </div>
+</ng-template>
 
+<!-- dummy container -->
 <ng-template #regionalFeatureContainerTmpl>
 </ng-template>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/type.ts
index ffc9751c7..b16d5dcad 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/type.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/type.ts
@@ -3,6 +3,7 @@ import { TBSDetail as TReceptorDetail, TBSSummary as TReceptorSummary } from "./
 import { KG_REGIONAL_FEATURE_KEY, TBSDetail as TKGDetail, TBSSummary as TKGSummary } from './kgRegionalFeature/type'
 import { SIIBRA_FEATURE_KEY, TBSSummary as TIEEGSummary, TBSDEtail as TIEEGDetail } from './ieeg/type'
 import { Observable } from "rxjs";
+import { InjectionToken } from "@angular/core";
 
 /**
  * change KgRegionalFeature -> EbrainsRegionalDataset in prod
@@ -41,3 +42,11 @@ export interface IRegionalFeatureReadyDirective {
   busy$: Observable<boolean>
   results$: Observable<IBSSummaryResponse[keyof IBSSummaryResponse][]>
 }
+
+export type TContextedFeature<T extends keyof IBSSummaryResponse> = {
+  featureName: string
+  icon: string
+  result: IBSSummaryResponse[T]
+}
+
+export const GENERIC_INFO_INJ_TOKEN = new InjectionToken('GENERIC_INFO_INJ_TOKEN')
diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css
index fffbc752f..4db5bf300 100644
--- a/src/res/css/extra_styles.css
+++ b/src/res/css/extra_styles.css
@@ -862,3 +862,11 @@ mat-list.sm mat-list-item
   padding-right:0 !important;
   padding-left:0 !important;
 }
+.h-50px
+{
+  height:50px;
+}
+.scale-80
+{
+  transform: scale(0.8);
+}
diff --git a/src/util/interfaces.ts b/src/util/interfaces.ts
index d389168ba..27b92d2ab 100644
--- a/src/util/interfaces.ts
+++ b/src/util/interfaces.ts
@@ -14,7 +14,7 @@ export interface IHasFullId{
 }
 
 
-export type TOverwriteShowDatasetDialog = (dataset: { fullId: string } | { name: string, description: string }, arg?: any) => void
+export type TOverwriteShowDatasetDialog = (arg: any) => void
 
 export const OVERWRITE_SHOW_DATASET_DIALOG_TOKEN = new InjectionToken<TOverwriteShowDatasetDialog>('OVERWRITE_SHOW_DATASET_DIALOG_TOKEN')
 
diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts
index 6b0ca9cbc..7bb913885 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.component.ts
+++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts
@@ -1,4 +1,4 @@
-import { Component, ElementRef, Inject, Input, OnDestroy, Optional, TemplateRef, ViewChild } from "@angular/core";
+import { Component, ComponentFactory, ComponentFactoryResolver, ElementRef, Inject, Injector, Input, OnDestroy, Optional, TemplateRef, ViewChild, ViewContainerRef } from "@angular/core";
 import { select, Store } from "@ngrx/store";
 import {combineLatest, merge, Observable, of, Subject, Subscription} from "rxjs";
 import {catchError, distinctUntilChanged, filter, map, shareReplay, startWith, switchMap } from "rxjs/operators";
@@ -18,27 +18,14 @@ import { QuickTourThis, IQuickTourData } from "src/ui/quickTour";
 import { MatDrawer } from "@angular/material/sidenav";
 import { PureContantService } from "src/util";
 import { EnumViewerEvt, TContextArg, TSupportedViewers, TViewerEvent } from "../viewer.interface";
-import { getGetRegionFromLabelIndexId } from "src/util/fn";
+import { getGetRegionFromLabelIndexId, switchMapWaitFor } from "src/util/fn";
 import { ContextMenuService, TContextMenuReg } from "src/contextMenuModule";
 import { ComponentStore } from "../componentStore";
-
-interface IOverlayTypes {
-  ebrainsRegionalDataset: {
-    datasetId: string
-    atlasId: string
-    parcId: string
-    region: any
-    spaceId?: string
-  }
-}
-
-type TOverlaySideNav<T extends keyof IOverlayTypes> = {
-  '@type': T
-  context: IOverlayTypes[T]
-}
+import { MAT_DIALOG_DATA } from "@angular/material/dialog";
+import { GenericInfoCmp } from "src/atlasComponents/regionalFeatures/bsFeatures/genericInfo";
 
 type TCStoreViewerCmp = {
-  overlaySideNav: TOverlaySideNav<keyof IOverlayTypes>
+  overlaySideNav: any
 }
 
 @Component({
@@ -110,24 +97,10 @@ type TCStoreViewerCmp = {
     {
       provide: OVERWRITE_SHOW_DATASET_DIALOG_TOKEN,
       useFactory: (cStore: ComponentStore<TCStoreViewerCmp>) => {
-        return function overwriteShowDatasetDialog( arg: { fullId?: string, name: string, description: string }, data: any ){
+        return function overwriteShowDatasetDialog( arg: any ){
           
-          const { region } = data
-          const datasetId = arg.fullId
-          const atlasId = data?.region?.context?.atlas?.['@id']
-          const parcId = data?.region?.context?.parcellation?.['@id']
-          const spaceId = data?.region?.context?.template?.['@id']
           cStore.setState({
-            overlaySideNav: {
-              '@type': 'ebrainsRegionalDataset',
-              context: {
-                datasetId,
-                atlasId,
-                parcId,
-                region,
-                spaceId,
-              }
-            }
+            overlaySideNav: arg
           })
         }
       },
@@ -148,6 +121,8 @@ export class ViewerCmp implements OnDestroy {
   @ViewChild('sideNavFullLeftSwitch', { static: true })
   private sidenavLeftSwitch: SwitchDirective
 
+  @ViewChild('genericInfoVCR', { read: ViewContainerRef })
+  genericInfoVCR: ViewContainerRef
 
   public quickTourRegionSearch: IQuickTourData = {
     order: 7,
@@ -187,7 +162,9 @@ export class ViewerCmp implements OnDestroy {
     select(viewerStateViewerModeSelector),
   )
 
-  public overlaySidenav$ = this.cStore.select(s => s.overlaySideNav)
+  public overlaySidenav$ = this.cStore.select(s => s.overlaySideNav).pipe(
+    shareReplay(1),
+  )
 
   public useViewer$: Observable<TSupportedViewers | 'notsupported'> = combineLatest([
     this.templateSelected$,
@@ -233,13 +210,17 @@ export class ViewerCmp implements OnDestroy {
   private templateSelected: any
   private getRegionFromlabelIndexId: Function
 
+  private genericInfoCF: ComponentFactory<GenericInfoCmp>
   constructor(
     private store$: Store<any>,
     private viewerModuleSvc: ContextMenuService<TContextArg<'threeSurfer' | 'nehuba'>>,
     private cStore: ComponentStore<TCStoreViewerCmp>,
+    cfr: ComponentFactoryResolver,
     @Optional() @Inject(REGION_OF_INTEREST) public regionOfInterest$: Observable<any>
   ){
 
+    this.genericInfoCF = cfr.resolveComponentFactory(GenericInfoCmp)
+
     this.subscriptions.push(
       this.selectedRegions$.subscribe(() => {
         this.clearPreviewingDataset()
@@ -327,6 +308,28 @@ export class ViewerCmp implements OnDestroy {
     this.onDestroyCb.push(
       () => this.viewerModuleSvc.deregister(cb)
     )
+    this.subscriptions.push(
+      this.overlaySidenav$.pipe(
+        switchMap(switchMapWaitFor({
+          condition: () => !!this.genericInfoVCR
+        }))
+      ).subscribe(data => {
+        if (!this.genericInfoVCR) {
+          console.warn(`genericInfoVCR not defined!`)
+          return
+        }
+        const injector = Injector.create({
+          providers: [{
+            provide: MAT_DIALOG_DATA,
+            useValue: data
+          }]
+        })
+
+        this.genericInfoVCR.clear()
+        this.genericInfoVCR.createComponent(this.genericInfoCF, null, injector)
+
+      })
+    )
   }
 
   ngOnDestroy() {
diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html
index 38a567c91..aa2004d86 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.template.html
+++ b/src/viewerModule/viewerCmp/viewerCmp.template.html
@@ -204,11 +204,8 @@
             </span>
           </button>
 
-          <!-- ebrains region -->
-          <kg-regional-feature-detail
-            [summary]="{'@id': overlaySideNav['context']['datasetId']}"
-            [region]="overlaySideNav['context']['region']">
-          </kg-regional-feature-detail>
+          <ng-template #genericInfoVCR>
+          </ng-template>
         </div>
       </div>
 
-- 
GitLab