diff --git a/Dockerfile b/Dockerfile index 1b9302b48d60cce33ada1cd676b1040edfe10d4d..80d15098c500e692b918b354dc01f783d3d787a7 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://brainscapes.apps-dev.hbp.eu/v1_0} +ENV BS_REST_URL=${BS_REST_URL:-https://siibra-api-tmpfullvolmetadata.apps-dev.hbp.eu/v1_0} ARG STRICT_LOCAL ENV STRICT_LOCAL=${STRICT_LOCAL:-false} diff --git a/build_env.md b/build_env.md index 27ff68e52725910cb9144da5711f4df8d74e6f64..849c7e068d3c4ec433cbea158c3680f8b6ed0111 100644 --- a/build_env.md +++ b/build_env.md @@ -7,7 +7,7 @@ As interactive atlas viewer uses [webpack define plugin](https://webpack.js.org/ | `VERSION` | printed in console on viewer startup | `GIT_HASH` \|\| unspecificed hash | v2.2.2 | | `PRODUCTION` | if the build is for production, toggles optimisations such as minification | `undefined` | true | | `BACKEND_URL` | backend that the viewer calls to fetch available template spaces, parcellations, plugins, datasets | `null` | https://interactive-viewer.apps.hbp.eu/ | -| `BS_REST_URL` | [brainscape-api](https://jugit.fz-juelich.de/v.marcenko/brainscapes-api) used to fetch different resources | https://brainscapes.apps-dev.hbp.eu/v1_0 | +| `BS_REST_URL` | [brainscape-api](https://jugit.fz-juelich.de/v.marcenko/brainscapes-api) used to fetch different resources | https://siibra-api-tmpfullvolmetadata.apps-dev.hbp.eu/v1_0 | | `DATASET_PREVIEW_URL` | dataset preview url used by component <https://github.com/fzj-inm1-bda/kg-dataset-previewer>. Useful for diagnosing issues with dataset previews.| https://hbp-kg-dataset-previewer.apps.hbp.eu/datasetPreview | http://localhost:1234/datasetPreview | | `MATOMO_URL` | base url for matomo analytics | `null` | https://example.com/matomo/ | | `MATOMO_ID` | application id for matomo analytics | `null` | 6 | diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/constants.ts b/src/atlasComponents/regionalFeatures/bsFeatures/constants.ts index 312f9472a90d9574a3c126e1409be36f48828793..4bbc8df0f28b6f595f8e6e2c83c29fe2d2daa5b9 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/constants.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/constants.ts @@ -1,11 +1,10 @@ import { InjectionToken } from "@angular/core"; import { Observable } from "rxjs"; import { IHasId } from "src/util/interfaces"; +import { TBSDetail, TBSSummary } from "./receptor/type"; export const BS_ENDPOINT = new InjectionToken<string>('BS_ENDPOINT') -export type TFeature = 'ReceptorDistribution' - export type TRegion = { name: string status?: string @@ -16,4 +15,12 @@ export type TRegion = { } } -export const BS_DARKTHEME = new InjectionToken<Observable<boolean>>('BS_DARKTHEME') \ No newline at end of file +export const BS_DARKTHEME = new InjectionToken<Observable<boolean>>('BS_DARKTHEME') + +export interface IBSSummaryResponse { + 'ReceptorDistribution': TBSSummary +} + +export interface IBSDetailResponse { + 'ReceptorDistribution': TBSDetail +} diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/index.ts b/src/atlasComponents/regionalFeatures/bsFeatures/index.ts index 14b0368f720fb5bbdcf3c7876013c39f4e9e251f..c032b1e616b5779164711e13aa8c87f035459805 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/index.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/index.ts @@ -1,4 +1,4 @@ export { BSFeatureModule } from './module' -export { BS_ENDPOINT, TFeature, TRegion, BS_DARKTHEME } from './constants' +export { BS_ENDPOINT, TRegion, BS_DARKTHEME } from './constants' // nb do not export BsRegionInputBase from here // will result in cyclic imports \ No newline at end of file diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/ar/autoradiograph.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/ar/autoradiograph.component.ts index a687a61ca37efcc7f3b72fc2795b363b1449993a..867f18fb919b994d92a5c3516267571d60e7afb2 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/ar/autoradiograph.component.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/ar/autoradiograph.component.ts @@ -37,7 +37,7 @@ export class BsFeatureReceptorAR extends BsFeatureReceptorBase implements OnChan return } - const url = this.bsFeature.data._ReceptorDistribution__autoradiographs[this.bsLabel] + const url = this.bsFeature.__data.__autoradiographs[this.bsLabel] if (!url) { this.error = `ar cannot be found` return diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts index d8a35c92dd34be6b30e6b0ceb3fba07a25c53a27..f4e418aa320f7d2e201955b5ab9a56e22ec39e78 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/base.ts @@ -1,9 +1,9 @@ import { Input } from "@angular/core"; -import { TBSResp } from "./type"; +import { TBSDetail } from "./type"; export class BsFeatureReceptorBase { @Input() - bsFeature: TBSResp + bsFeature: TBSDetail public urls: { url: string diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.component.ts index eb37be2b0d369917e98453cede4ae3e184313fc2..f280d6e09f6675fcd74959f0383e30720f3830da 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.component.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.component.ts @@ -1,8 +1,9 @@ import { Component, OnDestroy } from "@angular/core"; -import { Subscription } from "rxjs"; +import { Observable, of, Subject, Subscription } from "rxjs"; import { filter, map, shareReplay, startWith, switchMap, tap } from "rxjs/operators"; import { BsRegionInputBase } from "../../bsRegionInputBase"; import { BsFeatureReceptorService } from '../service' +import { TBSDetail } from "../type"; @Component({ selector: 'bs-features-receptor-entry', @@ -16,13 +17,39 @@ export class BsFeatureReceptorEntry extends BsRegionInputBase implements OnDestr private sub: Subscription[] = [] + private selectedREntryId$ = new Subject<string>() + private _selectedREntryId: string + set selectedREntryId(id: string){ + this.selectedREntryId$.next(id) + this._selectedREntryId = id + } + get selectedREntryId(){ + return this._selectedREntryId + } + + public selectedReceptor$: Observable<TBSDetail> = this.selectedREntryId$.pipe( + switchMap(id => id + ? this.featureReceptorService.getReceptorRegionalFeatureDetail(this.region, id) + : of(null) + ), + shareReplay(1), + ) + ngOnDestroy(){ while (this.sub.length > 0) this.sub.pop().unsubscribe() } - public receptorResp$ = this.region$.pipe( + public receptorsSummary$ = this.region$.pipe( filter(v => !!v), - switchMap(val => this.featureReceptorService.getFeatureFromRegion(val)), + switchMap(val => this.featureReceptorService.getReceptorRegionalFeature(val)), + tap(arr => { + if (arr && arr.length > 0) { + this.selectedREntryId = arr[0]['@id'] + } else { + this.selectedREntryId = null + } + }), + startWith([]), shareReplay(1), ) @@ -31,11 +58,11 @@ export class BsFeatureReceptorEntry extends BsRegionInputBase implements OnDestr } public selectedReceptor = null - public allReceptors$ = this.receptorResp$.pipe( - map(val => val?.receptor_symbols), - filter(v => !!v), - map(obj => Object.keys(obj)), - startWith<string[]>([]) + public allReceptors$ = this.selectedReceptor$.pipe( + map(rec => { + if (!rec) return [] + return Object.keys(rec.__receptor_symbols || {}) + }) ) constructor( diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html index c6aef0ad9fac5c1f058a9bdfc42cdbc667b606d5..d9c42eee60f4f0d0017c92b57431a5ec142a6581 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/entry/entry.template.html @@ -1,31 +1,41 @@ -<bs-features-receptor-fingerprint - (onSelectReceptor)="onSelectReceptor($event)" - [bsFeature]="receptorResp$ | async"> -</bs-features-receptor-fingerprint> +<mat-select [(value)]="selectedREntryId"> + <mat-option *ngFor="let rec of receptorsSummary$ | async" + [value]="rec['@id']"> + {{ rec.name }} + </mat-option> +</mat-select> -<mat-divider></mat-divider> +<ng-container *ngIf="selectedReceptor$ | async as selectedRec"> -<mat-form-field class="mt-2 w-100"> - <mat-label> - Select a receptor - </mat-label> - <mat-select [(value)]="selectedReceptor"> - <mat-option - *ngFor="let receptorName of (allReceptors$ | async)" - [value]="receptorName"> - {{ receptorName }} - </mat-option> - </mat-select> -</mat-form-field> + <bs-features-receptor-fingerprint + (onSelectReceptor)="onSelectReceptor($event)" + [bsFeature]="selectedRec"> + </bs-features-receptor-fingerprint> -<bs-features-receptor-profile - *ngIf="selectedReceptor" - [bsFeature]="receptorResp$ | async" - [bsLabel]="selectedReceptor"> -</bs-features-receptor-profile> + <mat-divider></mat-divider> -<bs-features-receptor-autoradiograph - *ngIf="selectedReceptor" - [bsFeature]="receptorResp$ | async" - [bsLabel]="selectedReceptor"> -</bs-features-receptor-autoradiograph> \ No newline at end of file + <mat-form-field class="mt-2 w-100"> + <mat-label> + Select a receptor + </mat-label> + <mat-select [(value)]="selectedReceptor"> + <mat-option + *ngFor="let receptorName of (allReceptors$ | async)" + [value]="receptorName"> + {{ receptorName }} + </mat-option> + </mat-select> + </mat-form-field> + + <bs-features-receptor-profile + *ngIf="selectedReceptor" + [bsFeature]="selectedRec" + [bsLabel]="selectedReceptor"> + </bs-features-receptor-profile> + + <bs-features-receptor-autoradiograph + *ngIf="selectedReceptor" + [bsFeature]="selectedRec" + [bsLabel]="selectedReceptor"> + </bs-features-receptor-autoradiograph> +</ng-container> diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/fp/fp.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/fp/fp.component.ts index 5d04135e4932186f95c110dd517c632bb3556d41..a061221118bf8420bbf6883b14c15f18680c4fb8 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/fp/fp.component.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/fp/fp.component.ts @@ -67,14 +67,14 @@ export class BsFeatureReceptorFingerprint extends BsFeatureReceptorBase implemen } this.urls.push( - ...this.bsFeature.data.urls + ...this.bsFeature.__files .filter(u => /_fp_/.test(u)) .map(url => { return { url, } }), - ...this.bsFeature.data.urls + ...this.bsFeature.__files .filter(u => !/_pr_|_ar_/.test(u) && /receptors\.tsv$/.test(u)) .map(url => { return { @@ -84,7 +84,7 @@ export class BsFeatureReceptorFingerprint extends BsFeatureReceptorBase implemen ) const radarEl = (this.elRef.nativeElement as HTMLElement).querySelector<any>('kg-dataset-dumb-radar') - radarEl.radarBs = this.bsFeature.data._ReceptorDistribution__fingerprint - radarEl.metaBs = this.bsFeature.receptor_symbols + radarEl.radarBs = this.bsFeature.__data.__fingerprint + radarEl.metaBs = this.bsFeature.__receptor_symbols } } diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/hasReceptor.directive.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/hasReceptor.directive.ts index 375872e3c455a48352ee32b7bb98dfdab75e5c6a..80f074c6647815162407664f2e2a6d58e676f4e1 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/hasReceptor.directive.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/hasReceptor.directive.ts @@ -20,7 +20,7 @@ export class BsFeatureReceptorDirective extends BsRegionInputBase implements OnD public hasReceptor$ = this.region$.pipe( switchMap(val => merge( of(null), - this.featureReceptorService.getFeatureFromRegion(val).pipe( + this.featureReceptorService.getReceptorRegionalFeature(val).pipe( mapTo(true), catchError(() => of(false)) ) diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/profile/profile.component.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/profile/profile.component.ts index eb45a8e4ad1036f827df95acb6947c35e69b3a88..02f9ef7fe87b2d4c967acf00097f4e16cfc2d7c8 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/profile/profile.component.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/profile/profile.component.ts @@ -42,13 +42,13 @@ export class BsFeatureReceptorProfile extends BsFeatureReceptorBase implements O return } - this.urls = this.bsFeature.data.urls + this.urls = this.bsFeature.__files .filter(url => url.indexOf(`_pr_${this.bsLabel}`) >= 0) .map(url => { return { url } }) - const profileBs = this.bsFeature.data._ReceptorDistribution__profiles[this.bsLabel] + const profileBs = this.bsFeature.__data.__profiles[this.bsLabel] const lineEl = (this.elRef.nativeElement as HTMLElement).querySelector<any>('kg-dataset-dumb-line') lineEl.profileBs = profileBs } diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/service.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/service.ts index c37b29a8293c54840e961d5baa1afcf5a1cd2b9a..43384b1e00a23695d3be8fe358a82780b5f61e39 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/service.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/service.ts @@ -1,13 +1,15 @@ import { Injectable } from "@angular/core"; import { TRegion } from "../constants"; import { BsFeatureService } from "../service"; -import { TBSResp } from "./type"; @Injectable() export class BsFeatureReceptorService{ - public getFeatureFromRegion(region: TRegion) { - return this.bsFeatureService.getFeature<TBSResp>('ReceptorDistribution', region) + public getReceptorRegionalFeature(region: TRegion) { + return this.bsFeatureService.getFeatures('ReceptorDistribution', region) + } + public getReceptorRegionalFeatureDetail(region: TRegion, id: string) { + return this.bsFeatureService.getFeature('ReceptorDistribution', region, id) } constructor( private bsFeatureService: BsFeatureService diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts index 39146956a06122cf5bc3a030aa84f1ae5422922a..4776b5166a74b2d840b976e90483b23be14fc9d7 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/receptor/type.ts @@ -17,10 +17,6 @@ type TProfile = { [key: number]: number } -type THasName = { - name: string -} - type TBSFingerprint = { unit: string labels: TReceptor[] @@ -29,24 +25,23 @@ type TBSFingerprint = { n: 1 } -type TBSData = { - "region": string - "active": boolean - "name": string - "urls": string[] // array of urls - "info": string // md of desc of dataset - "modality": THasName[] - "_ReceptorDistribution__profiles": { - [key: string]: TProfile - } // key is receptor key - "_ReceptorDistribution__autoradiographs": { - [key: string]: string - } // value is tiff image URL - "_ReceptorDistribution__fingerprint": TBSFingerprint - "_ReceptorDistribution__profile_unit": string +export type TBSSummary = { + ['@id']: string + name: string + info: string } -export type TBSResp = { - data: TBSData - receptor_symbols: TReceptorSymbol +export type TBSDetail = TBSSummary & { + __files: string[] + __receptor_symbols: TReceptorSymbol + __data: { + __profiles: { + [key: string]: TProfile + } + __autoradiographs: { + [key: string]: string + } + __fingerprint: TBSFingerprint + __profile_unit: string + } } diff --git a/src/atlasComponents/regionalFeatures/bsFeatures/service.ts b/src/atlasComponents/regionalFeatures/bsFeatures/service.ts index 99f10433e25cb66c5c9ac23102a85cc8db73a71c..587e01d69308d87310eb7e2222a9faffc5ca8a1e 100644 --- a/src/atlasComponents/regionalFeatures/bsFeatures/service.ts +++ b/src/atlasComponents/regionalFeatures/bsFeatures/service.ts @@ -1,7 +1,7 @@ import { HttpClient } from "@angular/common/http"; import { Inject, Injectable } from "@angular/core"; import { shareReplay } from "rxjs/operators"; -import { BS_ENDPOINT, TFeature, TRegion } from "./constants"; +import { BS_ENDPOINT, IBSSummaryResponse, IBSDetailResponse, TRegion } from "./constants"; @Injectable() export class BsFeatureService{ @@ -14,13 +14,21 @@ export class BsFeatureService{ return `${region.name} ${region.status ? region.status : '' }` } - public getFeature<T>(featureName: TFeature, region: TRegion) { + public getFeatures<T extends keyof IBSSummaryResponse>(featureName: T, region: TRegion){ const { context } = region const { atlas, parcellation } = context - return this.http.get<T>( + return this.http.get<IBSSummaryResponse[T][]>( `${this.bsEndpoint}/atlases/${encodeURIComponent(atlas["@id"])}/parcellations/${encodeURIComponent(parcellation['@id'])}/regions/${encodeURIComponent(this.processRegion(region))}/features/${encodeURIComponent(featureName)}` ) } + + public getFeature<T extends keyof IBSDetailResponse>(featureName: T, region: TRegion, featureId: string) { + const { context } = region + const { atlas, parcellation } = context + return this.http.get<IBSDetailResponse[T]>( + `${this.bsEndpoint}/atlases/${encodeURIComponent(atlas["@id"])}/parcellations/${encodeURIComponent(parcellation['@id'])}/regions/${encodeURIComponent(this.processRegion(region))}/features/${encodeURIComponent(featureName)}/${encodeURIComponent(featureId)}` + ) + } constructor( private http: HttpClient, diff --git a/webpack/webpack.staticassets.js b/webpack/webpack.staticassets.js index 3f311ed752e55edec1dc99c2fc65d3d9722f1a66..d187f6b5a5a2fea0c9a79f5248835ed14ca3354b 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://brainscapes.apps-dev.hbp.eu/v1_0'), + BS_REST_URL: JSON.stringify(process.env.BS_REST_URL || 'https://siibra-api-tmpfullvolmetadata.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),