From b785d802a1771651081985939a8664101ac5bd04 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Fri, 25 Jun 2021 19:50:02 +0200
Subject: [PATCH] chore: update endpoint, feat: loading indicator for ebrains
 features

---
 Dockerfile                                    |   2 +-
 deploy/datasets/index.js                      |   1 +
 .../parcellationRegion/module.ts              |   6 +
 .../regionAccordionTooltipText.pipe.ts        |   4 -
 .../regionMenu/regionMenu.component.ts        |  54 +++-
 .../regionMenu/regionMenu.template.html       | 236 +++++++++++-------
 .../kgRegDetail/kgRegDetail.component.ts      |  50 +++-
 .../kgRegDetail/kgRegDetail.template.html     |  50 ++++
 .../kgRegList/kgRegList.template.html         |   6 +-
 .../kgRegList/kgReglist.directive.ts          |  13 +-
 .../bsFeatures/kgRegionalFeature/module.ts    |   2 +
 .../bsFeatures/kgRegionalFeature/type.ts      |   5 +
 .../userAnnotations/tools/service.ts          |   1 +
 src/ui/ui.module.ts                           |   2 -
 src/viewerModule/constants.ts                 |   6 -
 src/viewerModule/module.ts                    |   4 -
 .../threeSurferGlue/threeSurfer.component.ts  |  10 +
 .../viewerCmp/viewerCmp.component.ts          |  43 +---
 .../viewerCmp/viewerCmp.template.html         | 166 ++----------
 webpack/webpack.staticassets.js               |   2 +-
 20 files changed, 356 insertions(+), 307 deletions(-)
 rename src/{viewerModule/util => atlasComponents/parcellationRegion}/regionAccordionTooltipText.pipe.ts (88%)

diff --git a/Dockerfile b/Dockerfile
index 80d15098c..56768d28e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,7 +7,7 @@ ARG DATASET_PREVIEW_URL
 ENV DATASET_PREVIEW_URL=${DATASET_PREVIEW_URL:-https://hbp-kg-dataset-previewer.apps.hbp.eu/v2}
 
 ARG BS_REST_URL
-ENV BS_REST_URL=${BS_REST_URL:-https://siibra-api-tmpfullvolmetadata.apps-dev.hbp.eu/v1_0}
+ENV BS_REST_URL=${BS_REST_URL:-https://siibra-api-tmpxgcustom.apps-dev.hbp.eu/v1_0}
 
 ARG STRICT_LOCAL
 ENV STRICT_LOCAL=${STRICT_LOCAL:-false}
diff --git a/deploy/datasets/index.js b/deploy/datasets/index.js
index 4f63e80b8..7f55dff26 100644
--- a/deploy/datasets/index.js
+++ b/deploy/datasets/index.js
@@ -192,6 +192,7 @@ datasetsRouter.get('/hasPreview', cacheMaxAge24Hr, async (req, res) => {
 })
 
 datasetsRouter.get('/kgInfo', checkKgQuery, cacheMaxAge24Hr, async (req, res) => {
+  return res.status(400).send('Deprecated')
   const { kgId } = req.query
   const { kgSchema } = req.query
   const { user } = req
diff --git a/src/atlasComponents/parcellationRegion/module.ts b/src/atlasComponents/parcellationRegion/module.ts
index 1e400b5e2..ea4826233 100644
--- a/src/atlasComponents/parcellationRegion/module.ts
+++ b/src/atlasComponents/parcellationRegion/module.ts
@@ -9,6 +9,9 @@ import { RegionDirective } from "./region.directive";
 import { RegionListSimpleViewComponent } from "./regionListSimpleView/regionListSimpleView.component";
 import { RegionMenuComponent } from "./regionMenu/regionMenu.component";
 import { SimpleRegionComponent } from "./regionSimple/regionSimple.component";
+import { BSFeatureModule } from "../regionalFeatures/bsFeatures";
+import { RegionAccordionTooltipTextPipe } from "./regionAccordionTooltipText.pipe";
+import { AtlasCmptConnModule } from "../connectivity";
 
 @NgModule({
   imports: [
@@ -17,6 +20,8 @@ import { SimpleRegionComponent } from "./regionSimple/regionSimple.component";
     DatabrowserModule,
     AngularMaterialModule,
     ComponentsModule,
+    BSFeatureModule,
+    AtlasCmptConnModule,
   ],
   declarations: [
     RegionMenuComponent,
@@ -25,6 +30,7 @@ import { SimpleRegionComponent } from "./regionSimple/regionSimple.component";
 
     RegionDirective,
     RenderViewOriginDatasetLabelPipe,
+    RegionAccordionTooltipTextPipe,
   ],
   exports: [
     RegionMenuComponent,
diff --git a/src/viewerModule/util/regionAccordionTooltipText.pipe.ts b/src/atlasComponents/parcellationRegion/regionAccordionTooltipText.pipe.ts
similarity index 88%
rename from src/viewerModule/util/regionAccordionTooltipText.pipe.ts
rename to src/atlasComponents/parcellationRegion/regionAccordionTooltipText.pipe.ts
index 65c5f2199..c2a92b83d 100644
--- a/src/viewerModule/util/regionAccordionTooltipText.pipe.ts
+++ b/src/atlasComponents/parcellationRegion/regionAccordionTooltipText.pipe.ts
@@ -1,9 +1,5 @@
 import { Pipe, PipeTransform } from "@angular/core"
 
-/**
- * TODO find this pipe a home
- * not too sure where this should stay
- */
 @Pipe({
   name: 'regionAccordionTooltipTextPipe',
   pure: true
diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts
index 8d9f08545..8747535e5 100644
--- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts
+++ b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts
@@ -1,30 +1,72 @@
-import { Component, OnDestroy, Input } from "@angular/core";
+import { Component, OnDestroy } from "@angular/core";
 import { Store } from "@ngrx/store";
-import { Subscription } from "rxjs";
+import { Observable, Subscription } from "rxjs";
 import { RegionBase } from '../region.base'
-import { ARIA_LABELS } from 'common/constants'
+import { CONST } from 'common/constants'
+import { ComponentStore } from "src/viewerModule/componentStore";
 
 @Component({
   selector: 'region-menu',
   templateUrl: './regionMenu.template.html',
   styleUrls: ['./regionMenu.style.css'],
+  providers: [ ComponentStore ]
 })
 export class RegionMenuComponent extends RegionBase implements OnDestroy {
 
+  public CONST = CONST
   private subscriptions: Subscription[] = []
 
+  public activePanelTitles$: Observable<string[]>
+  private activePanelTitles: string[] = []
   constructor(
     store$: Store<any>,
+    private viewerCmpLocalUiStore: ComponentStore<{ activePanelsTitle: string[] }>,
   ) {
     super(store$)
+    this.viewerCmpLocalUiStore.setState({
+      activePanelsTitle: []
+    })
+
+    this.activePanelTitles$ = this.viewerCmpLocalUiStore.select(
+      state => state.activePanelsTitle
+    ) as Observable<string[]>
+
+    this.subscriptions.push(
+      this.activePanelTitles$.subscribe(
+        (activePanelTitles: string[]) => this.activePanelTitles = activePanelTitles
+      )
+    )
   }
 
   ngOnDestroy(): void {
     this.subscriptions.forEach(s => s.unsubscribe())
   }
 
-  @Input()
-  showRegionInOtherTmpl: boolean = true
+  handleExpansionPanelClosedEv(title: string){
+    this.viewerCmpLocalUiStore.setState({
+      activePanelsTitle: this.activePanelTitles.filter(n => n !== title)
+    })
+  }
+  handleExpansionPanelAfterExpandEv(title: string){
+    if (this.activePanelTitles.includes(title)) return
+    this.viewerCmpLocalUiStore.setState({
+      activePanelsTitle: [
+        ...this.activePanelTitles,
+        title
+      ]
+    })
+  }
 
-  SHOW_IN_OTHER_REF_SPACE = ARIA_LABELS.SHOW_IN_OTHER_REF_SPACE
+  public busyFlag = false
+  private busyMap = new Map<string, boolean>()
+  handleBusySignal(namespace: string, flag: boolean) {
+    this.busyMap.set(namespace, flag)
+    for (const [_key, val] of this.busyMap.entries()) {
+      if (val) {
+        this.busyFlag = true
+        return
+      }
+    }
+    this.busyFlag = false
+  }
 }
diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html
index 8f7b7adcb..d972b2651 100644
--- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html
+++ b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html
@@ -1,4 +1,4 @@
-<mat-card>
+<mat-card class="mat-elevation-z4">
   <!-- rgbDarkmode must be checked for strict equality to true/false 
   as if rgb is undefined, rgbDarkmode will be null/undefined
   which is falsy -->
@@ -32,55 +32,6 @@
             {{ regionOriginDatasetLabels$ | async | renderViewOriginDatasetlabel : index }}
           </span>
         </ng-template>
-
-        <span
-          aria-hidden="true"
-          [kgSchema]="originDataset.kgSchema"
-          [kgId]="originDataset.kgId"
-          single-dataset-directive
-          #sdDirective="singleDatasetDirective">
-        </span>
-
-        <ng-template [ngIf]="sdDirective.fetchFlag" [ngIfElse]="contentTmpl">
-          <spinner-cmp></spinner-cmp>
-        </ng-template>
-
-        <ng-template #contentTmpl>
-
-          <!-- fall back if no kg ref is available -->
-          <a *ngIf="sdDirective.kgReference.length === 0"
-            [href]="sdDirective.directLinkToKg"
-            target="_blank">
-            <button mat-icon-button
-              color="primary">
-              <i class="fas fa-external-link-alt"></i>
-            </button>
-          </a>
-
-          <!-- kg ref, normally doi -->
-          <a *ngFor="let kgRef of sdDirective.kgReference"
-            [href]="kgRef | doiParserPipe"
-            target="_blank">
-            <button mat-icon-button
-              color="primary">
-              <i class="fas fa-external-link-alt"></i>
-            </button>
-          </a>
-
-          <!-- pin/unpin -->
-          <ng-container *ngTemplateOutlet="pinTmpl; context: { $implicit: sdDirective.isFav$ | async }">
-          </ng-container>
-
-          <ng-template #pinTmpl let-isFav>
-
-            <button mat-icon-button
-              (click)="isFav ? sdDirective.undoableRemoveFav() : sdDirective.undoableAddFav()"
-              [color]="isFav ? 'primary' : 'default'">
-              <i class="fas fa-thumbtack"></i>
-            </button>
-          </ng-template>
-
-        </ng-template>
       </div>
 
       <mat-divider vertical="true" class="ml-2 h-2rem"></mat-divider>
@@ -93,49 +44,156 @@
         </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>
 
-<!-- template for switching template -->
-<mat-menu #regionInOtherTemplatesMenu="matMenu"
-  [aria-label]="SHOW_IN_OTHER_REF_SPACE">
-  <ng-template matMenuContent let-regionInOtherTemplates="regionInOtherTemplates">
-
-    <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>
+<mat-accordion class="d-block mt-2">
+
+  <!-- receptor -->
+  <div bs-features-receptor-directive
+    [region]="region"
+    #bsFeatureReceptorDirective="bsFeatureReceptorDirective">
+  </div>
+  <ng-template #regionalReceptorTmpl>
+    <bs-features-receptor-entry [region]="region">
+    </bs-features-receptor-entry>
+  </ng-template>
+  <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
+      title: 'ReceptorDistribution',
+      iconClass: 'fas fa-info',
+      iavNgIf: bsFeatureReceptorDirective.hasReceptor$ | async,
+      content: regionalReceptorTmpl
+    }">
+  </ng-container>
+
+
+  <!-- Explore in other template -->
+  <ng-container *ngIf="regionInOtherTemplates$ | async as regionInOtherTemplates">
+
+    <ng-template #exploreInOtherTmpl>
+      <mat-card *ngFor="let sameRegion of regionInOtherTemplates"
+        class="p-0 border-0 box-shadow-none mt-1 tb-1 cursor-pointer"
+        (click)="changeView(sameRegion)"
+        [matTooltip]="sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '')"
+        mat-ripple>
+        <small>
+          {{ sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '') }}
+        </small>
+      </mat-card>
+    </ng-template>
+
+    <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
+      title: 'Explore in other templates',
+      desc: regionInOtherTemplates.length,
+      iconClass: 'fas fa-brain',
+      iconTooltip: regionInOtherTemplates.length | regionAccordionTooltipTextPipe : 'regionInOtherTmpl',
+      iavNgIf: regionInOtherTemplates.length,
+      content: exploreInOtherTmpl
+    }">
+
+
+    </ng-container>
+  </ng-container>
+
+  <!-- kg regional features list -->
+  <ng-template #kgRegionalFeatureList>
+    <kg-regional-features-list [region]="region">
+    </kg-regional-features-list>
+  </ng-template>
+
+  <div kg-regional-features-list-directive
+    [region]="region"
+    (kg-regional-features-list-directive-busy)="handleBusySignal('regionFeatureList', $event)"
+    #kgRegFeatlist="kgRegionalFeaturesListDirective">
+  </div>
+
+  <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
+    title: CONST.REGIONAL_FEATURES,
+    iconClass: 'fas fa-database',
+    content: kgRegionalFeatureList,
+    desc: kgRegFeatlist.kgRegionalFeatures.length,
+    iconTooltip: kgRegFeatlist.kgRegionalFeatures.length | regionAccordionTooltipTextPipe : 'regionalFeatures',
+    iavNgIf: (kgRegFeatlist.kgRegionalFeatures$ | async ).length
+  }">
+  </ng-container>
+
+  <!-- Connectivity -->
+  
+  <ng-template #connectivityContentTmpl let-expansionPanel="expansionPanel">
+    <mat-card-content class="flex-grow-1 flex-shrink-1 w-100">
+      <connectivity-browser class="pe-all flex-shrink-1"
+        [region]="region"
+        (setOpenState)="expansionPanel.expanded = $event"
+        [accordionExpanded]="expansionPanel.expanded"
+        (connectivityNumberReceived)="hasConnectivityDirective.connectivityNumber = $event">
+      </connectivity-browser>
+    </mat-card-content>
   </ng-template>
-</mat-menu>
-
-<!-- template for rendering template name and template hemisphere -->
-<ng-template #regionInOtherTemplate let-template="template" let-hemisphere="hemisphere">
-  <span class="overflow-x-hidden text-truncate"
-  [matTooltip]="template.name  + (hemisphere ? (' ' + hemisphere) : '')">
-    <span>
-      {{ template.name }}
-    </span>
-    <span *ngIf="hemisphere" class="text-muted">
-      ({{ hemisphere }})
-    </span>
-  </span>
+
+  <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
+    title: 'Connectivity',
+    desc: hasConnectivityDirective.connectivityNumber,
+    iconClass: 'fas fa-braille',
+    iconTooltip: hasConnectivityDirective.connectivityNumber | regionAccordionTooltipTextPipe : 'connectivity',
+    iavNgIf: hasConnectivityDirective.hasConnectivity,
+    content: connectivityContentTmpl
+  }">
+  </ng-container>
+
+  <div has-connectivity
+    [region]="[region]"
+    #hasConnectivityDirective="hasConnectivityDirective">
+  </div>
+</mat-accordion>
+
+<div *ngIf="busyFlag" class="mt-2 d-flex justify-content-center">
+  <spinner-cmp></spinner-cmp>
+</div>
+
+<!-- expansion tmpl -->
+<ng-template #ngMatAccordionTmpl
+  let-title="title"
+  let-desc="desc"
+  let-iconClass="iconClass"
+  let-iconTooltip="iconTooltip"
+  let-iavNgIf="iavNgIf"
+  let-content="content">
+  <mat-expansion-panel
+    [expanded]="activePanelTitles$ | async | arrayContains : title"
+    [attr.data-opened]="expansionPanel.expanded"
+    [attr.data-mat-expansion-title]="title"
+    (closed)="handleExpansionPanelClosedEv(title)"
+    (afterExpand)="handleExpansionPanelAfterExpandEv(title)"
+    hideToggle
+    *ngIf="iavNgIf"
+    #expansionPanel="matExpansionPanel">
+
+    <mat-expansion-panel-header>
+
+      <!-- title -->
+      <mat-panel-title>
+        {{ title }}
+      </mat-panel-title>
+
+      <!-- desc + icon -->
+      <mat-panel-description class="d-flex align-items-center justify-content-end"
+        [matTooltip]="iconTooltip">
+        <span class="mr-3">{{ desc }}</span>
+        <span class="accordion-icon d-inline-flex justify-content-center">
+          <i [class]="iconClass"></i>
+        </span>
+      </mat-panel-description>
+
+    </mat-expansion-panel-header>
+
+    <!-- content -->
+    <ng-template matExpansionPanelContent>
+      <ng-container *ngTemplateOutlet="content; context: {
+        expansionPanel: expansionPanel
+      }">
+      </ng-container>
+    </ng-template>
+  </mat-expansion-panel>
 </ng-template>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts
index 54fcf016d..4a7d79ddd 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.component.ts
@@ -1,6 +1,13 @@
-import { Component, Input } from "@angular/core";
+import { Component, Input, OnChanges } from "@angular/core";
 import { BsRegionInputBase } from "../../bsRegionInputBase";
-import { TBSDetail } from "../type";
+import { KG_REGIONAL_FEATURE_KEY, TBSDetail, UNDER_REVIEW } from "../type";
+import { ARIA_LABELS, CONST } from 'common/constants'
+import { TBSSummary } from "../../kgDataset";
+import { BsFeatureService } from "../../service";
+
+/**
+ * this component is specifically used to render side panel ebrains dataset view
+ */
 
 @Component({
   selector: 'kg-regional-feature-detail',
@@ -10,8 +17,45 @@ import { TBSDetail } from "../type";
   ]
 })
 
-export class KgRegDetailCmp extends BsRegionInputBase {
+export class KgRegDetailCmp extends BsRegionInputBase implements OnChanges {
+
+  public ARIA_LABELS = ARIA_LABELS
+  public CONST = CONST
+
+  @Input()
+  public summary: TBSSummary
 
   @Input()
   public detail: TBSDetail
+
+  public loadingFlag = false
+  public error = null
+
+  public nameFallback = `[This dataset cannot be fetched right now]`
+  public isGdprProtected = false
+
+  public descriptionFallback = `[This dataset cannot be fetched right now]`
+
+  constructor(svc: BsFeatureService){
+    super(svc)
+  }
+
+  ngOnChanges(){
+    if (!this.region) return
+    if (!this.summary) return
+    if (!!this.detail) return
+    this.loadingFlag = true
+    this.getFeatureInstance(KG_REGIONAL_FEATURE_KEY, this.summary['@id']).subscribe(
+      detail => {
+        this.detail = detail
+        this.isGdprProtected = detail.__detail.embargoStatus && detail.__detail.embargoStatus.some(status => status["@id"] === UNDER_REVIEW["@id"])
+      },
+      err => {
+        this.error = err.toString()
+      },
+      () => {
+        this.loadingFlag = false
+      }
+    )
+  }
 }
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html
index e69de29bb..7df120ded 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegDetail/kgRegDetail.template.html
@@ -0,0 +1,50 @@
+<!-- header -->
+
+<mat-card class="mat-elevation-z4">
+
+  <div class="sidenav-cover-header-container bg-50-grey-20">
+    <mat-card-title>
+      <ng-content select="[region-of-interest]"></ng-content>
+      <div *ngIf="!loadingFlag; else isLoadingTmpl">
+        {{ (detail && detail.src_name) || nameFallback }}
+      </div>
+    </mat-card-title>
+
+    <mat-card-subtitle class="d-inline-flex align-items-center">
+      <mat-icon fontSet="fas" fontIcon="fa-database"></mat-icon>
+      <span>
+        ebrains regional dataset
+      </span>
+
+      <button *ngIf="isGdprProtected"
+        [matTooltip]="CONST.GDPR_TEXT"
+        mat-icon-button color="warn">
+        <i class="fas fa-exclamation-triangle"></i>
+      </button>
+
+      <mat-divider [vertical]="true" class="ml-2 h-2rem"></mat-divider>
+
+      <!-- explore btn -->
+      <a *ngFor="let kgRef of (detail?.__detail?.kgReference || [])"
+        [href]="kgRef | doiParserPipe"
+        class="color-inherit"
+        mat-icon-button
+        [matTooltip]="ARIA_LABELS.EXPLORE_DATASET_IN_KG"
+        target="_blank">
+        <i class="fas fa-external-link-alt"></i>
+      </a>
+      
+    </mat-card-subtitle>
+  </div>
+
+</mat-card>
+
+<!-- description -->
+
+<markdown-dom class="text-muted d-block mat-body m-4" *ngIf="!loadingFlag"
+  [markdown]="detail?.__detail?.description || descriptionFallback">
+</markdown-dom>
+
+<ng-template #isLoadingTmpl>
+  <spinner-cmp></spinner-cmp>
+</ng-template>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
index 1cc27fde7..d8d99fe6e 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgRegList.template.html
@@ -59,15 +59,15 @@
       class="virtual-scroll-element overflow-hidden">
 
       <!-- divider, show if not first -->
-      <mat-divider *ngIf="index !== 0"></mat-divider>
+      <mat-divider class="mt-1" *ngIf="index !== 0"></mat-divider>
 
       <kg-regional-feature-summary
         mat-ripple
         iav-dataset-show-dataset-dialog
-        [iav-dataset-show-dataset-dialog-kgid]="dataset['@id'] | getTrailingHex"
+        [iav-dataset-show-dataset-dialog-fullid]="dataset['@id']"
         class="d-block pb-1 pt-1"
         [region]="region"
-        [loadFull]="true"
+        [loadFull]="false"
         [summary]="dataset"
         (loadedDetail)="handlePopulatedDetailEv($event)">
       </kg-regional-feature-summary>
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgReglist.directive.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgReglist.directive.ts
index 78e73c9e3..53d4ce42a 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgReglist.directive.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/kgRegList/kgReglist.directive.ts
@@ -1,4 +1,4 @@
-import { Directive, OnDestroy } from "@angular/core";
+import { Directive, EventEmitter, OnDestroy, Output } from "@angular/core";
 import { KG_REGIONAL_FEATURE_KEY, TBSSummary } from "../type";
 import { BsFeatureService } from "../../service";
 import { BsRegionInputBase } from "../../bsRegionInputBase";
@@ -15,9 +15,15 @@ export class KgRegionalFeaturesListDirective extends BsRegionInputBase implement
   public kgRegionalFeatures$ = this.region$.pipe(
     filter(v => !!v),
     // must not use switchmapto here
-    switchMap(() => this.getFeatureInstancesList(KG_REGIONAL_FEATURE_KEY)),
+    switchMap(() => {
+      this.busyEmitter.emit(true)
+      return this.getFeatureInstancesList(KG_REGIONAL_FEATURE_KEY).pipe(
+        tap(() => this.busyEmitter.emit(false))
+      )
+    }),
     startWith([])
   )
+  
   constructor(svc: BsFeatureService){
     super(svc)
     this.sub.push(
@@ -30,4 +36,7 @@ export class KgRegionalFeaturesListDirective extends BsRegionInputBase implement
   ngOnDestroy(){
     while (this.sub.length) this.sub.pop().unsubscribe()
   }
+
+  @Output('kg-regional-features-list-directive-busy')
+  busyEmitter = new EventEmitter<boolean>()
 }
\ No newline at end of file
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
index 79ecb08fd..73bbbf881 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/module.ts
@@ -8,6 +8,7 @@ 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";
 
 @NgModule({
   imports: [
@@ -15,6 +16,7 @@ import { UtilModule } from "src/util";
     AngularMaterialModule,
     KgDatasetModule,
     UtilModule,
+    ComponentsModule,
   ],
   declarations:[
     KgRegSummaryCmp,
diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
index 371a926c2..beb275754 100644
--- a/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
+++ b/src/atlasComponents/regionalFeatures/bsFeatures/kgRegionalFeature/type.ts
@@ -3,3 +3,8 @@ export {
 } from '../kgDataset'
 
 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/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts
index ab789a0d3..6652adb9c 100644
--- a/src/atlasComponents/userAnnotations/tools/service.ts
+++ b/src/atlasComponents/userAnnotations/tools/service.ts
@@ -548,6 +548,7 @@ export class ModularUserAnnotationToolService implements OnDestroy{
       arr.push(json)
     }
     const stringifiedJSON = JSON.stringify(arr)
+    if (!(window as any).export_nehuba) return
     const { pako } = (window as any).export_nehuba
     const compressed = pako.deflate(stringifiedJSON)
     let out = ''
diff --git a/src/ui/ui.module.ts b/src/ui/ui.module.ts
index 7145621bc..ff474d2af 100644
--- a/src/ui/ui.module.ts
+++ b/src/ui/ui.module.ts
@@ -48,7 +48,6 @@ import { Landmark2DModule } from "./nehubaContainer/2dLandmarks/module";
 import { HANDLE_SCREENSHOT_PROMISE, TypeHandleScrnShotPromise } from "./screenshot";
 import { ParcellationRegionModule } from "src/atlasComponents/parcellationRegion";
 import { AtlasCmpParcellationModule } from "src/atlasComponents/parcellation";
-import { AtlasCmptConnModule } from "src/atlasComponents/connectivity";
 
 @NgModule({
   imports : [
@@ -68,7 +67,6 @@ import { AtlasCmptConnModule } from "src/atlasComponents/connectivity";
     Landmark2DModule,
     ParcellationRegionModule,
     AtlasCmpParcellationModule,
-    AtlasCmptConnModule,
   ],
   declarations : [
     
diff --git a/src/viewerModule/constants.ts b/src/viewerModule/constants.ts
index aa974a56e..8fa2d2523 100644
--- a/src/viewerModule/constants.ts
+++ b/src/viewerModule/constants.ts
@@ -2,9 +2,3 @@ import { InjectionToken } from "@angular/core";
 import { Observable } from "rxjs";
 
 export const VIEWERMODULE_DARKTHEME = new InjectionToken<Observable<boolean>>('VIEWERMODULE_DARKTHEME')
-
-export interface IViewerCmpUiState {
-  sideNav: {
-    activePanelsTitle: string[]
-  }
-}
diff --git a/src/viewerModule/module.ts b/src/viewerModule/module.ts
index 3c74f7b74..91620bb87 100644
--- a/src/viewerModule/module.ts
+++ b/src/viewerModule/module.ts
@@ -1,7 +1,6 @@
 import { CommonModule } from "@angular/common";
 import { NgModule } from "@angular/core";
 import { Observable } from "rxjs";
-import { AtlasCmptConnModule } from "src/atlasComponents/connectivity";
 import { DatabrowserModule } from "src/atlasComponents/databrowserModule";
 import { AtlasCmpParcellationModule } from "src/atlasComponents/parcellation";
 import { ParcellationRegionModule } from "src/atlasComponents/parcellationRegion";
@@ -17,7 +16,6 @@ import { CONTEXT_MENU_ITEM_INJECTOR, TContextMenu, UtilModule } from "src/util";
 import { VIEWERMODULE_DARKTHEME } from "./constants";
 import { NehubaModule, NehubaViewerUnit } from "./nehuba";
 import { ThreeSurferModule } from "./threeSurfer";
-import { RegionAccordionTooltipTextPipe } from "./util/regionAccordionTooltipText.pipe";
 import { ViewerCmp } from "./viewerCmp/viewerCmp.component";
 import {UserAnnotationsModule} from "src/atlasComponents/userAnnotations";
 import {QuickTourModule} from "src/ui/quickTour/module";
@@ -40,7 +38,6 @@ import { TContextArg } from "./viewer.interface";
     ParcellationRegionModule,
     UtilModule,
     AtlasCmpParcellationModule,
-    AtlasCmptConnModule,
     ComponentsModule,
     BSFeatureModule,
     UserAnnotationsModule,
@@ -49,7 +46,6 @@ import { TContextArg } from "./viewer.interface";
   ],
   declarations: [
     ViewerCmp,
-    RegionAccordionTooltipTextPipe,
   ],
   providers: [
     {
diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
index db5e39b07..e4cc4fa88 100644
--- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
+++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.component.ts
@@ -69,6 +69,15 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
 
     this.selectedMode = mode.name
     const { meshes } = mode
+    await retry(async () => {
+      for (const singleMesh of meshes) {
+        const { hemisphere } = singleMesh
+      if (!this.regionMap.has(hemisphere)) throw new Error(`regionmap does not have hemisphere defined!`)
+      }
+    }, {
+      timeout: 32,
+      retries: 10
+    })
     for (const singleMesh of meshes) {
       const { mesh, colormap, hemisphere } = singleMesh
       this.allKeys.push({name: hemisphere, checked: true})
@@ -77,6 +86,7 @@ export class ThreeSurferGlueCmp implements IViewer<'threeSurfer'>, OnChanges, Af
         parseContext(mesh, [this.config['@context']])
       )
 
+      if (!this.regionMap.has(hemisphere)) continue
       const rMap = this.regionMap.get(hemisphere)
       const applyCM = new Map()
       for (const [ lblIdx, region ] of rMap.entries()) {
diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts
index c5b886f93..d7109e888 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.component.ts
+++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts
@@ -19,12 +19,8 @@ import { uiActionHideAllDatasets, uiActionHideDatasetWithId, uiActionShowDataset
 import { OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, REGION_OF_INTEREST } from "src/util/interfaces";
 import { animate, state, style, transition, trigger } from "@angular/animations";
 import { SwitchDirective } from "src/util/directives/switch.directive";
-import { IViewerCmpUiState } from "../constants";
 import { QuickTourThis, IQuickTourData } from "src/ui/quickTour";
 import { MatDrawer } from "@angular/material/sidenav";
-import { ComponentStore } from "../componentStore";
-import {BS_ENDPOINT} from "src/util/constants";
-import {HttpClient} from "@angular/common/http";
 import { PureContantService } from "src/util";
 import { EnumViewerEvt, TContextArg, TSupportedViewers, TViewerEvent } from "../viewer.interface";
 import { getGetRegionFromLabelIndexId } from "src/util/fn";
@@ -98,7 +94,6 @@ import { ContextMenuService, TContextMenuReg } from "src/contextMenuModule";
       },
       deps: [ Store ]
     },
-    ComponentStore
   ]
 })
 
@@ -224,24 +219,9 @@ export class ViewerCmp implements OnDestroy {
 
   constructor(
     private store$: Store<any>,
-    private viewerCmpLocalUiStore: ComponentStore<IViewerCmpUiState>,
     private viewerModuleSvc: ContextMenuService<TContextArg<'threeSurfer' | 'nehuba'>>,
     @Optional() @Inject(REGION_OF_INTEREST) public regionOfInterest$: Observable<any>
   ){
-    this.viewerCmpLocalUiStore.setState({
-      sideNav: {
-        activePanelsTitle: []
-      }
-    })
-
-    this.activePanelTitles$ = this.viewerCmpLocalUiStore.select(
-      state => state.sideNav.activePanelsTitle
-    ) as Observable<string[]>
-    this.subscriptions.push(
-      this.activePanelTitles$.subscribe(
-        (activePanelTitles: string[]) => this.activePanelTitles = activePanelTitles
-      )
-    )
 
     this.subscriptions.push(
       this.alwaysHideMinorPanel$.pipe(
@@ -334,27 +314,6 @@ export class ViewerCmp implements OnDestroy {
     while (this.onDestroyCb.length > 0) this.onDestroyCb.pop()()
   }
 
-  public activePanelTitles$: Observable<string[]>
-  private activePanelTitles: string[] = []
-  handleExpansionPanelClosedEv(title: string){
-    this.viewerCmpLocalUiStore.setState({
-      sideNav: {
-        activePanelsTitle: this.activePanelTitles.filter(n => n !== title)
-      }
-    })
-  }
-  handleExpansionPanelAfterExpandEv(title: string){
-    if (this.activePanelTitles.includes(title)) return
-    this.viewerCmpLocalUiStore.setState({
-      sideNav: {
-        activePanelsTitle: [
-          ...this.activePanelTitles,
-          title
-        ]
-      }
-    })
-  }
-
   public bindFns(fns){
     return () => {
       for (const [ fn, ...arg] of fns) {
@@ -411,7 +370,7 @@ export class ViewerCmp implements OnDestroy {
       }})
     )
   }
-  public clearPreviewingDataset(id: string){
+  public clearPreviewingDataset(id?: string){
     /**
      * clear all preview
      */
diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html
index 63a2320d7..4bcccb6e1 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.template.html
+++ b/src/viewerModule/viewerCmp/viewerCmp.template.html
@@ -113,7 +113,7 @@
 
       <iav-layout-fourcorners [iav-layout-fourcorners-cnr-cntr-ngclass]="{'w-100': true}">
 
-        <!-- pullable tab top right corner -->
+        <!-- pullable tab top left corner -->
         <div iavLayoutFourCornersTopLeft class="d-flex flex-nowrap w-100">
 
           <!-- top left -->
@@ -205,26 +205,26 @@
         <ng-container *ngIf="iavShownDataset.shownDatasetId$ | async as shownDatasetId">
           <ng-template [ngIf]="shownDatasetId.length > 0" [ngIfElse]="sideNavVolumePreview">
 
-            <!-- single dataset side nav panel -->
-            <single-dataset-sidenav-view *ngFor="let id of shownDatasetId"
-              (clear)="clearPreviewingDataset(id)"
-              [fullId]="id"
-              class="bs-border-box ml-15px-n mr-15px-n">
-              <mat-chip *ngIf="regionOfInterest$ && regionOfInterest$ | async as region"
-                region-of-interest
-                iav-region
-                [region]="region"
-                [ngClass]="{
-                  'darktheme':regionDirective.rgbDarkmode === true,
-                  'lighttheme': regionDirective.rgbDarkmode === false
-                }"
-                [style.backgroundColor]="regionDirective.rgbString"
-                #regionDirective="iavRegion">
-                <span class="iv-custom-comp text text-truncate d-inline">
-                  {{ region.name }}
+            <div class="position-relative ml-15px-n mr-15px-n">
+
+              <!-- back btn -->
+              <button mat-button
+                (click)="clearPreviewingDataset()"
+                [attr.aria-label]="ARIA_LABELS.CLOSE"
+                class="position-absolute z-index-10 m-2">
+                <i class="fas fa-chevron-left"></i>
+                <span class="ml-1">
+                  Back
                 </span>
-              </mat-chip>
-            </single-dataset-sidenav-view>
+              </button>
+
+              <!-- ebrains region -->
+              <kg-regional-feature-detail
+                *ngFor="let datasetId of shownDatasetId"
+                [summary]="{'@id': datasetId}"
+                [region]="selectedRegions$ | async | getNthElement : 0">
+              </kg-regional-feature-detail>
+            </div>
           </ng-template>
         </ng-container>
 
@@ -695,126 +695,10 @@
   <!-- region detail -->
   <ng-container *ngIf="region; else regionPlaceholderTmpl">
     <region-menu
-      [showRegionInOtherTmpl]="false"
       [region]="region"
-      class="bs-border-box ml-15px-n mr-15px-n mat-elevation-z4">
+      class="flex-grow-1 bs-border-box ml-15px-n mr-15px-n mat-elevation-z4">
     </region-menu>
   </ng-container>
-
-  <!-- other region detail accordion -->
-  <mat-accordion *ngIf="region"
-    class="bs-border-box ml-15px-n mr-15px-n mt-2"
-    iav-region
-    [region]="region"
-    #iavRegion="iavRegion">
-
-    <!-- desc -->
-    <!-- obsolete -->
-
-    <!-- Explore in other template -->
-    <ng-container *ngIf="iavRegion.regionInOtherTemplates$ | async as regionInOtherTemplates">
-
-      <ng-template #exploreInOtherTmpl>
-        <mat-card *ngFor="let sameRegion of regionInOtherTemplates"
-          class="p-0 border-0 box-shadow-none mt-1 tb-1 cursor-pointer"
-          (click)="iavRegion.changeView(sameRegion)"
-          [matTooltip]="sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '')"
-          mat-ripple>
-          <small>
-            {{ sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '') }}
-          </small>
-        </mat-card>
-      </ng-template>
-
-      <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
-        title: 'Explore in other templates',
-        desc: regionInOtherTemplates.length,
-        iconClass: 'fas fa-brain',
-        iconTooltip: regionInOtherTemplates.length | regionAccordionTooltipTextPipe : 'regionInOtherTmpl',
-        iavNgIf: regionInOtherTemplates.length,
-        content: exploreInOtherTmpl
-      }">
-
-
-      </ng-container>
-    </ng-container>
-
-    <!-- tmp experimtal -->
-    <ng-template #regionalReceptorTmpl>
-      <bs-features-receptor-entry
-        [region]="region">
-      </bs-features-receptor-entry>
-    </ng-template>
-
-    <div bs-features-receptor-directive
-      [region]="region"
-      #bsFeatureReceptorDirective="bsFeatureReceptorDirective">
-    </div>
-    <spinner-cmp *ngIf="bsFeatureReceptorDirective.fetching$ | async"></spinner-cmp>
-    <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
-      title: 'ReceptorDistribution',
-      iconClass: 'fas fa-info',
-      iavNgIf: bsFeatureReceptorDirective.hasReceptor$ | async,
-      content: regionalReceptorTmpl
-    }">
-
-    </ng-container>
-
-    <!-- kg regional features list -->
-    <ng-template #kgRegionalFeatureList>
-      <kg-regional-features-list [region]="region">
-      </kg-regional-features-list>
-    </ng-template>
-
-    <div kg-regional-features-list-directive
-      [region]="region"
-      #kgRegFeatlist="kgRegionalFeaturesListDirective">
-    </div>
-
-    <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
-      title: CONST.REGIONAL_FEATURES,
-      iconClass: 'fas fa-database',
-      content: kgRegionalFeatureList,
-      desc: kgRegFeatlist.kgRegionalFeatures.length,
-      iconTooltip: kgRegFeatlist.kgRegionalFeatures.length | regionAccordionTooltipTextPipe : 'regionalFeatures',
-      iavNgIf: (kgRegFeatlist.kgRegionalFeatures$ | async ).length
-    }">
-    </ng-container>
-
-    <!-- Connectivity -->
-    <ng-container  *ngIf="parcellationSelected$ | async as selectedParcellation">
-
-      <ng-template #connectivityContentTmpl let-expansionPanel="expansionPanel">
-        <mat-card-content class="flex-grow-1 flex-shrink-1 w-100">
-          <ng-container *ngFor="let region of selectedRegions$ | async">
-            <connectivity-browser class="pe-all flex-shrink-1"
-              [region]="region"
-              (setOpenState)="expansionPanel.expanded = $event"
-              [accordionExpanded]="expansionPanel.expanded"
-              (connectivityNumberReceived)="hasConnectivityDirective.connectivityNumber = $event">
-            </connectivity-browser>
-          </ng-container>
-        </mat-card-content>
-      </ng-template>
-
-      <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: {
-        title: 'Connectivity',
-        desc: hasConnectivityDirective.connectivityNumber,
-        iconClass: 'fas fa-braille',
-        iconTooltip: hasConnectivityDirective.connectivityNumber | regionAccordionTooltipTextPipe : 'connectivity',
-        iavNgIf: hasConnectivityDirective.hasConnectivity,
-        content: connectivityContentTmpl
-      }">
-      </ng-container>
-
-      <div has-connectivity
-           [region]="selectedRegions$ | async"
-           #hasConnectivityDirective="hasConnectivityDirective">
-      </div>
-
-    </ng-container>
-
-  </mat-accordion>
 </ng-template>
 
 
@@ -827,11 +711,8 @@
   let-iavNgIf="iavNgIf"
   let-content="content">
   <mat-expansion-panel
-    [expanded]="activePanelTitles$ | async | arrayContains : title"
     [attr.data-opened]="expansionPanel.expanded"
     [attr.data-mat-expansion-title]="title"
-    (closed)="handleExpansionPanelClosedEv(title)"
-    (afterExpand)="handleExpansionPanelAfterExpandEv(title)"
     hideToggle
     *ngIf="iavNgIf"
     #expansionPanel="matExpansionPanel">
@@ -883,10 +764,7 @@
 <ng-template #multiRegionTmpl let-regions="regions">
   <ng-template [ngIf]="regions.length > 0" [ngIfElse]="regionPlaceholderTmpl">
     <region-menu
-      [showRegionInOtherTmpl]="false"
-      [region]="{
-        name: CONST.MULTI_REGION_SELECTION
-      }"
+      [region]="{ name: CONST.MULTI_REGION_SELECTION }"
       class="bs-border-box ml-15px-n mr-15px-n mat-elevation-z4">
     </region-menu>
 
diff --git a/webpack/webpack.staticassets.js b/webpack/webpack.staticassets.js
index d187f6b5a..ac4863ef5 100644
--- a/webpack/webpack.staticassets.js
+++ b/webpack/webpack.staticassets.js
@@ -67,7 +67,7 @@ module.exports = {
       PRODUCTION: !!process.env.PRODUCTION,
       BACKEND_URL: (process.env.BACKEND_URL && JSON.stringify(process.env.BACKEND_URL)) || 'null',
       DATASET_PREVIEW_URL: JSON.stringify(process.env.DATASET_PREVIEW_URL || 'https://hbp-kg-dataset-previewer.apps.hbp.eu/v2'),
-      BS_REST_URL: JSON.stringify(process.env.BS_REST_URL || 'https://siibra-api-tmpfullvolmetadata.apps-dev.hbp.eu/v1_0'),
+      BS_REST_URL: JSON.stringify(process.env.BS_REST_URL || 'https://siibra-api-tmpxgcustom.apps-dev.hbp.eu/v1_0'),
       SPATIAL_TRANSFORM_BACKEND: JSON.stringify(process.env.SPATIAL_TRANSFORM_BACKEND || 'https://hbp-spatial-backend.apps.hbp.eu'),
       MATOMO_URL: JSON.stringify(process.env.MATOMO_URL || null),
       MATOMO_ID: JSON.stringify(process.env.MATOMO_ID || null),
-- 
GitLab