From bec56e6f298f398c779f5d2d982aa0f8026ab87a Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Tue, 28 Jan 2020 15:34:18 +0100
Subject: [PATCH] feat: use web component for preview of data

---
 common/util.js                                |  2 +-
 src/res/ext/MNI152.json                       |  1 +
 src/res/ext/bigbrain.json                     |  1 +
 src/res/ext/colin.json                        |  1 +
 src/services/state/dataStore.store.ts         |  4 ++
 .../databrowserModule/databrowser.module.ts   |  5 ++
 .../databrowser/databrowser.component.ts      |  2 +-
 .../kgSingleDatasetService.service.ts         |  1 +
 .../datasetPreviewList.component.ts           | 57 +++++++++++++++++++
 .../datasetPreviewList.template.html          | 53 +++++++++++++++++
 .../detailedView/singleDataset.template.html  | 38 ++-----------
 .../singleDatasetListView.template.html       | 38 ++-----------
 .../singleDataset/singleDataset.base.ts       | 24 +-------
 ...reviewFileDisabledByReferenceSpace.pipe.ts | 20 +++++++
 .../searchSideNav/searchSideNav.component.ts  |  4 +-
 15 files changed, 161 insertions(+), 90 deletions(-)
 create mode 100644 src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.component.ts
 create mode 100644 src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.template.html
 create mode 100644 src/ui/databrowserModule/util/previewFileDisabledByReferenceSpace.pipe.ts

diff --git a/common/util.js b/common/util.js
index 871481b91..330e538fe 100644
--- a/common/util.js
+++ b/common/util.js
@@ -2,7 +2,7 @@
   exports.getIdFromFullId = fullId => {
     if (!fullId) return null
     if (typeof fullId === 'string') {
-      const re = /\/([a-z]{1,}\/[a-z]{1,}\/[a-z]{1,}\/v[0-9.]{1,}\/[0-9a-z-]{1,}$)/.exec(fullId)
+      const re = /([a-z]{1,}\/[a-z]{1,}\/[a-z]{1,}\/v[0-9.]{1,}\/[0-9a-z-]{1,}$)/.exec(fullId)
       if (re) return re[1]
       return null
     } else {
diff --git a/src/res/ext/MNI152.json b/src/res/ext/MNI152.json
index cc88e19c2..679909551 100644
--- a/src/res/ext/MNI152.json
+++ b/src/res/ext/MNI152.json
@@ -1,5 +1,6 @@
 {
   "name": "MNI 152 ICBM 2009c Nonlinear Asymmetric",
+  "fullId": "minds/core/referencespace/v1.0.0/dafcffc5-4826-4bf1-8ff6-46b8a31ff8e2",
   "type": "template",
   "species": "Human",
   "useTheme": "dark",
diff --git a/src/res/ext/bigbrain.json b/src/res/ext/bigbrain.json
index abff253c1..7ac96b805 100644
--- a/src/res/ext/bigbrain.json
+++ b/src/res/ext/bigbrain.json
@@ -1,5 +1,6 @@
 {
   "name": "Big Brain (Histology)",
+  "fullId": "minds/core/referencespace/v1.0.0/a1655b99-82f1-420f-a3c2-fe80fd4c8588",
   "type": "template",
   "species": "Human",
   "useTheme": "light",
diff --git a/src/res/ext/colin.json b/src/res/ext/colin.json
index c9a3d1963..d80629a3b 100644
--- a/src/res/ext/colin.json
+++ b/src/res/ext/colin.json
@@ -1,5 +1,6 @@
 {
   "name": "MNI Colin 27",
+  "fullId": "minds/core/referencespace/v1.0.0/7f39f7be-445b-47c0-9791-e971c0b6d992",
   "type": "template",
   "species": "Human",
   "useTheme": "dark",
diff --git a/src/services/state/dataStore.store.ts b/src/services/state/dataStore.store.ts
index 2944d975e..0a328aec4 100644
--- a/src/services/state/dataStore.store.ts
+++ b/src/services/state/dataStore.store.ts
@@ -187,6 +187,10 @@ export interface ViewerPreviewFile {
   name: string
   filename: string
   mimetype: string
+  referenceSpaces: { 
+    name: string, 
+    fullId: string
+  }[]
   url?: string
   data?: any
   position?: any
diff --git a/src/ui/databrowserModule/databrowser.module.ts b/src/ui/databrowserModule/databrowser.module.ts
index e40a2a24c..0bd7944d6 100644
--- a/src/ui/databrowserModule/databrowser.module.ts
+++ b/src/ui/databrowserModule/databrowser.module.ts
@@ -26,6 +26,8 @@ import { SingleDatasetListView } from "./singleDataset/listView/singleDatasetLis
 import { AppendFilerModalityPipe } from "./util/appendFilterModality.pipe";
 import { GetKgSchemaIdFromFullIdPipe } from "./util/getKgSchemaIdFromFullId.pipe";
 import { ResetCounterModalityPipe } from "./util/resetCounterModality.pipe";
+import { PreviewFileVisibleInSelectedReferenceTemplatePipe } from "./util/previewFileDisabledByReferenceSpace.pipe";
+import { DatasetPreviewList, UnavailableTooltip } from "./singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.component";
 
 @NgModule({
   imports: [
@@ -43,6 +45,7 @@ import { ResetCounterModalityPipe } from "./util/resetCounterModality.pipe";
     ModalityPicker,
     SingleDatasetView,
     SingleDatasetListView,
+    DatasetPreviewList,
 
     /**
      * pipes
@@ -60,6 +63,8 @@ import { ResetCounterModalityPipe } from "./util/resetCounterModality.pipe";
     PreviewFileTypePipe,
     AppendFilerModalityPipe,
     ResetCounterModalityPipe,
+    PreviewFileVisibleInSelectedReferenceTemplatePipe,
+    UnavailableTooltip,
   ],
   exports: [
     DataBrowser,
diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts
index 3ae4430da..e8705a558 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.component.ts
+++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts
@@ -67,7 +67,7 @@ export class DataBrowser implements OnChanges, OnDestroy, OnInit {
     this.favDataentries$ = this.dbService.favedDataentries$
 
     const structuredData = window.document.querySelector('script[type="application/ld+json"]')
-    if (structuredData) console.log(JSON.parse(structuredData.textContent))
+    
   }
 
   public ngOnChanges() {
diff --git a/src/ui/databrowserModule/kgSingleDatasetService.service.ts b/src/ui/databrowserModule/kgSingleDatasetService.service.ts
index 931f3efeb..9544ef15f 100644
--- a/src/ui/databrowserModule/kgSingleDatasetService.service.ts
+++ b/src/ui/databrowserModule/kgSingleDatasetService.service.ts
@@ -39,6 +39,7 @@ export class KgSingleDatasetService implements OnDestroy {
     }
   }
 
+  // TODO deprecate, in favour of web component
   public datasetHasPreview({ name }: { name: string } = { name: null }) {
     if (!name) { throw new Error('kgSingleDatasetService#datasetHashPreview name must be defined') }
     const _url = new URL(`datasets/hasPreview`, this.constantService.backendUrl )
diff --git a/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.component.ts b/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.component.ts
new file mode 100644
index 000000000..a12aba9be
--- /dev/null
+++ b/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.component.ts
@@ -0,0 +1,57 @@
+import { Component, Input, ChangeDetectorRef, Output, EventEmitter, Pipe, PipeTransform } from "@angular/core";
+import { ViewerPreviewFile } from "src/services/state/dataStore.store";
+import { Store, select } from "@ngrx/store";
+import { IavRootStoreInterface } from "src/services/stateStore.service";
+import { Observable } from "rxjs";
+
+@Component({
+  selector: 'dataset-preview-list',
+  templateUrl: './datasetPreviewList.template.html'
+})
+
+export class DatasetPreviewList{
+
+  @Output() public previewingFile: EventEmitter<ViewerPreviewFile> = new EventEmitter()
+
+  public datasetPreviewList: any[] = []
+  public loadingDatasetPreviewList: boolean = false
+  public selectedTemplateSpace$: Observable<any>
+
+  constructor(
+    private cdr: ChangeDetectorRef,
+    store$: Store<IavRootStoreInterface>
+  ){
+    this.selectedTemplateSpace$ = store$.pipe(
+      select('viewerState'),
+      select('templateSelected')
+    )
+  }
+
+  @Input()
+  kgId: string
+
+  handleKgDsPrvUpdated(event: CustomEvent){
+    const { detail } = event
+    const { datasetFiles, loadingFlag } = detail
+
+    this.loadingDatasetPreviewList = loadingFlag
+    this.datasetPreviewList = datasetFiles
+
+    this.cdr.markForCheck()
+  }
+  public handlePreviewFile(file: ViewerPreviewFile) {
+    
+    this.previewingFile.emit(file)
+  }
+}
+
+@Pipe({
+  name: 'unavailableTooltip'
+})
+
+export class UnavailableTooltip implements PipeTransform{
+  public transform(file:ViewerPreviewFile):string{
+    if (file.referenceSpaces.length === 0) return `This preview is not available to be viewed in any reference space.`
+    else return `This preview is available in the following reference space: ${file.referenceSpaces.map(({ name }) => name).join(', ')}`
+  }
+}
\ No newline at end of file
diff --git a/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.template.html b/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.template.html
new file mode 100644
index 000000000..a92572cd7
--- /dev/null
+++ b/src/ui/databrowserModule/singleDataset/datasetPreviews/datasetPreviewsList/datasetPreviewList.template.html
@@ -0,0 +1,53 @@
+<kg-dataset-list
+  (kgDsPrvUpdated)="handleKgDsPrvUpdated($event)"
+  class="d-none"
+  [kgId]="kgId">
+
+</kg-dataset-list>
+
+<div *ngIf="loadingDatasetPreviewList; else datasetList" class="spinnerAnimationCircle"></div>
+
+<ng-template #datasetList>
+
+  <mat-nav-list>
+    <h3 mat-subheader>Available Preview Files</h3>
+
+    <ng-container *ngFor="let file of datasetPreviewList">
+
+      <!-- preview available -->
+      <ng-template [ngIf]="(selectedTemplateSpace$ | async | previewFileVisibleInSelectedReferenceTemplatePipe : file)" [ngIfElse]="notAvailalbePreview" >
+        <mat-list-item (click)=" handlePreviewFile(file)">
+          <mat-icon
+            [fontSet]="(file | previewFileIconPipe).fontSet"
+            [fontIcon]="(file | previewFileIconPipe).fontIcon"
+            matListIcon>
+          </mat-icon>
+          <h4 mat-line>{{ file.name }}</h4>
+          <p mat-line>mimetype: {{ file.mimetype }}</p>
+        </mat-list-item>
+      </ng-template>
+
+      <!-- preview not available in this reference space -->
+      <ng-template #notAvailalbePreview>
+        <mat-list-item
+          [matTooltip]="file | unavailableTooltip"
+          [matTooltipDisabled]="selectedTemplateSpace$ | async | previewFileVisibleInSelectedReferenceTemplatePipe : file"
+          [ngClass]="{'text-muted': !(selectedTemplateSpace$ | async | previewFileVisibleInSelectedReferenceTemplatePipe : file)}">
+          <mat-icon
+            [fontSet]="(file | previewFileIconPipe).fontSet"
+            [fontIcon]="(file | previewFileIconPipe).fontIcon"
+            matListIcon>
+          </mat-icon>
+          <h4 mat-line>{{ file.name }}</h4>
+          <p mat-line>mimetype: {{ file.mimetype }}</p>
+        </mat-list-item>
+      </ng-template>
+
+    </ng-container>
+    <small *ngIf="datasetPreviewList.length === 0"
+      class="text-muted">
+      There are no preview files in this parcellation/template space.
+    </small>
+    
+  </mat-nav-list>
+</ng-template>
diff --git a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
index 5a9d75185..5871fdd9f 100644
--- a/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
+++ b/src/ui/databrowserModule/singleDataset/detailedView/singleDataset.template.html
@@ -140,37 +140,9 @@
 <mat-card-footer></mat-card-footer>
 
 <ng-template #previewFilesListTemplate>
-  <kg-dataset-list
-    (kgDsPrvUpdated)="handleKgDsPrvUpdated($event)"
-    class="d-none"
-    [kgId]="kgId">
-  
-  </kg-dataset-list>
-  
-  <div *ngIf="loadingDatasetPreviewList; else datasetList" class="spinnerAnimationCircle"></div>
-
-  <ng-template #datasetList>
-
-    <mat-nav-list>
-      <h3 mat-subheader>Available Preview Files</h3>
-      <mat-list-item
-        *ngFor="let file of datasetPreviewList"
-        (click)="handlePreviewFile(file)">
-        <mat-icon
-          [fontSet]="(file | previewFileIconPipe).fontSet"
-          [fontIcon]="(file | previewFileIconPipe).fontIcon"
-          matListIcon>
-        </mat-icon>
-        <h4 mat-line>{{ file.name }}</h4>
-        <p mat-line>mimetype: {{ file.mimetype }}</p>
-      </mat-list-item>
-    
-      <small *ngIf="datasetPreviewList.length === 0"
-        class="text-muted">
-        There are no preview files in this parcellation/template space.
-      </small>
-      
-    </mat-nav-list>
-  </ng-template>
-  
+  <dataset-preview-list
+    [kgId]="kgId"
+    (previewingFile)="handlePreviewFile($event)">
+
+  </dataset-preview-list>
 </ng-template>
diff --git a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html
index cee6aeed4..ac442f660 100644
--- a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html
+++ b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html
@@ -102,39 +102,11 @@
 </mat-menu>
 
 <ng-template #previewFilesListTemplate>
-  <kg-dataset-list
-    (kgDsPrvUpdated)="handleKgDsPrvUpdated($event)"
-    class="d-none"
-    [kgId]="kgId">
-  
-  </kg-dataset-list>
-  
-  <div *ngIf="loadingDatasetPreviewList; else datasetList" class="spinnerAnimationCircle"></div>
-
-  <ng-template #datasetList>
-
-    <mat-nav-list>
-      <h3 mat-subheader>Available Preview Files</h3>
-      <mat-list-item
-        *ngFor="let file of datasetPreviewList"
-        (click)="handlePreviewFile(file)">
-        <mat-icon
-          [fontSet]="(file | previewFileIconPipe).fontSet"
-          [fontIcon]="(file | previewFileIconPipe).fontIcon"
-          matListIcon>
-        </mat-icon>
-        <h4 mat-line>{{ file.name }}</h4>
-        <p mat-line>mimetype: {{ file.mimetype }}</p>
-      </mat-list-item>
-    
-      <small *ngIf="datasetPreviewList.length === 0"
-        class="text-muted">
-        There are no preview files in this parcellation/template space.
-      </small>
-      
-    </mat-nav-list>
-  </ng-template>
-  
+  <dataset-preview-list
+    [kgId]="kgId"
+    (previewingFile)="handlePreviewFile($event)">
+
+  </dataset-preview-list>
 </ng-template>
 
 <ng-template #fullIcons>
diff --git a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
index 41ee25581..510232f24 100644
--- a/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
+++ b/src/ui/databrowserModule/singleDataset/singleDataset.base.ts
@@ -15,7 +15,6 @@ export {
 
 export class SingleDatasetBase implements OnInit {
 
-  @ViewChild('kg-dataset-list') kgDatasetList: any
   @Input() public ripple: boolean = false
 
   /**
@@ -32,8 +31,6 @@ export class SingleDatasetBase implements OnInit {
   @Input() public dataset: any = null
   @Input() public simpleMode: boolean = false
 
-  @Output() public previewingFile: EventEmitter<ViewerPreviewFile> = new EventEmitter()
-
   public preview: boolean = false
   private humanReadableFileSizePipe: HumanReadableFileSizePipe = new HumanReadableFileSizePipe()
 
@@ -43,10 +40,6 @@ export class SingleDatasetBase implements OnInit {
   public kgReference: string[] = []
   public files: IFile[] = []
   private methods: string[] = []
-  /**
-   * sic!
-   */
-  private parcellationRegion: Array<{ name: string }>
 
   private error: string = null
 
@@ -55,6 +48,8 @@ export class SingleDatasetBase implements OnInit {
 
   public dlFromKgHref: string = null
 
+  public selectedTemplateSpace$: Observable<any>
+
   public favedDataentries$: Observable<IDataEntry[]>
   constructor(
     private dbService: DatabrowserService,
@@ -64,6 +59,7 @@ export class SingleDatasetBase implements OnInit {
 
     dataset?: any,
   ) {
+
     this.favedDataentries$ = this.dbService.favedDataentries$
     if (dataset) {
       this.dataset = dataset
@@ -156,20 +152,6 @@ export class SingleDatasetBase implements OnInit {
   }
 
   public handlePreviewFile(file: ViewerPreviewFile) {
-    this.previewingFile.emit(file)
     this.singleDatasetService.previewFile(file, this.dataset)
   }
-  
-  public datasetPreviewList: any[] = []
-  public loadingDatasetPreviewList: boolean = false
-
-  handleKgDsPrvUpdated(event: CustomEvent){
-    const { detail } = event
-    const { datasetFiles, loadingFlag } = detail
-
-    this.loadingDatasetPreviewList = loadingFlag
-    this.datasetPreviewList = datasetFiles
-
-    this.cdr.markForCheck()
-  }
 }
diff --git a/src/ui/databrowserModule/util/previewFileDisabledByReferenceSpace.pipe.ts b/src/ui/databrowserModule/util/previewFileDisabledByReferenceSpace.pipe.ts
new file mode 100644
index 000000000..0c72d3998
--- /dev/null
+++ b/src/ui/databrowserModule/util/previewFileDisabledByReferenceSpace.pipe.ts
@@ -0,0 +1,20 @@
+import { Pipe, PipeTransform } from "@angular/core";
+import { ViewerPreviewFile } from "src/services/state/dataStore.store";
+import { getIdFromFullId } from "common/util"
+
+@Pipe({
+  name: 'previewFileVisibleInSelectedReferenceTemplatePipe'
+})
+
+export class PreviewFileVisibleInSelectedReferenceTemplatePipe implements PipeTransform{
+  public transform(selectedReferenceSpace: any, file: ViewerPreviewFile):boolean{
+    const { referenceSpaces = [] } = file
+    if (referenceSpaces.some(({ name, fullId }) => name === '*' && fullId === '*')) return true
+    const { fullId } = selectedReferenceSpace
+    if (!fullId) return false
+    return referenceSpaces.some(({ fullId: rsFullId }) => {
+      const compare = getIdFromFullId(rsFullId) === getIdFromFullId(fullId)
+      return compare
+    })
+  }
+}
\ No newline at end of file
diff --git a/src/ui/searchSideNav/searchSideNav.component.ts b/src/ui/searchSideNav/searchSideNav.component.ts
index 3e256b85e..46b4bfff9 100644
--- a/src/ui/searchSideNav/searchSideNav.component.ts
+++ b/src/ui/searchSideNav/searchSideNav.component.ts
@@ -13,6 +13,7 @@ import {
 import { IavRootStoreInterface, SELECT_REGIONS } from "src/services/stateStore.service";
 import { LayerBrowser } from "../layerbrowser/layerbrowser.component";
 import { trackRegionBy } from '../viewerStateController/regionHierachy/regionHierarchy.component'
+import { determinePreviewFileType, PREVIEW_FILE_TYPES } from "../databrowserModule/preview/previewFileIcon.pipe";
 
 @Component({
   selector: 'search-side-nav',
@@ -74,7 +75,8 @@ export class SearchSideNav implements OnDestroy {
         select('dataStore'),
         select('datasetPreviews'),
         filter(datasetPreviews => datasetPreviews.length > 0),
-        map((datasetPreviews) => datasetPreviews[datasetPreviews.length - 1])
+        map((datasetPreviews) => datasetPreviews[datasetPreviews.length - 1]),
+        filter(({ file }) => determinePreviewFileType(file) !== PREVIEW_FILE_TYPES.NIFTI)
       ).subscribe(({ dataset, file }) => {
         
         const { fullId } = dataset
-- 
GitLab