diff --git a/deploy/datasets/index.js b/deploy/datasets/index.js index 42e1ad1232692e943d1b884ad8d0d78fc6770b97..93124730f8cc6e871f87a8cc8d74a6e87715976e 100644 --- a/deploy/datasets/index.js +++ b/deploy/datasets/index.js @@ -3,6 +3,7 @@ const path = require('path') const fs = require('fs') const datasetsRouter = express.Router() const { init, getDatasets, getPreview, getDatasetFromId, getDatasetFileAsZip, getTos, hasPreview } = require('./query') +const { retry } = require('./util') const url = require('url') const qs = require('querystring') @@ -15,6 +16,7 @@ init() .then(() => console.log(`dataset init success`)) .catch(e => { console.warn(`dataset init failed`, e) + retry(() => init()) }) const cacheMaxAge24Hr = (_req, res, next) => { diff --git a/deploy/datasets/query.js b/deploy/datasets/query.js index 6907e075ca7ee0bb4c9c54d65b9f85588bfcb4ac..83986048bfd30ee2eca99c1bba2cd97cddf51b6d 100644 --- a/deploy/datasets/query.js +++ b/deploy/datasets/query.js @@ -199,6 +199,7 @@ const filter = (datasets = [], { templateName, parcellationName }) => datasets // TODO ask curaion team re name of jubrain atlas let overwriteParcellationName switch (parcellationName) { + case 'Cytoarchitectonic Maps': case 'JuBrain Cytoarchitectonic Atlas': useSet = juBrainSet overwriteParcellationName = 'Jülich Cytoarchitechtonic Brain Atlas (human)' diff --git a/deploy/datasets/util.js b/deploy/datasets/util.js index 8165cd5dbd1182341099133331804d208ccd0558..f8378038f74495fe3e0f4f01d69191a85932cbcf 100644 --- a/deploy/datasets/util.js +++ b/deploy/datasets/util.js @@ -34,7 +34,21 @@ const init = async () => { getPublicAccessToken = getPublic } +const retry = (fn) => { + let retryId + retryId = setInterval(() => { + fn() + .then(() => { + console.log(`retry succeeded, clearing retryId`) + clearTimeout(retryId) + }).catch(e => { + console.warn(`retry failed, retrying in 5sec`) + }) + }, 5000) +} + module.exports = { init, - getUserKGRequestParam + getUserKGRequestParam, + retry } \ No newline at end of file diff --git a/deploy/datasets/util.spec.js b/deploy/datasets/util.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..a4dbd0090c97fa77d8da167369133e9d6b5ea877 --- /dev/null +++ b/deploy/datasets/util.spec.js @@ -0,0 +1,10 @@ +const { retry } = require('./util') + +let val = 0 + +const prFn = () => { + val++ + return val >=3 ? Promise.resolve() : Promise.reject() +} + +retry(() => prFn()) \ No newline at end of file diff --git a/src/atlasViewer/atlasViewer.style.css b/src/atlasViewer/atlasViewer.style.css index d8dd38d79c50bdde5e9a19342486d0be3fc0449c..aca0ca06ef6f9579c7a615829f43f407a62e598d 100644 --- a/src/atlasViewer/atlasViewer.style.css +++ b/src/atlasViewer/atlasViewer.style.css @@ -1,4 +1,4 @@ -:host, :host > .atlas-container +:host { display:block; width:100%; @@ -19,20 +19,6 @@ ui-nehuba-container height:100%; } -/* zindex of banner wrapper needs to be lower than zindex of floating layer */ -div[bannerWrapper] -{ - z-index:12; - position:absolute; - - width:100%; - display:flex; - height:0px; - - justify-content: space-between; -} - - layout-floating-container { width:100%; @@ -40,11 +26,6 @@ layout-floating-container overflow:hidden; } -[iconWrapper] -{ - margin-left: 1em; -} - [signinWrapper] { margin: 0.8em 0.4em; @@ -60,39 +41,6 @@ layout-floating-container background-color : rgba(30,30,30,0.8); } - -[dockedContainer] -{ - margin-top:0.2em; -} - -[mobileMenu] -{ - min-height:50em; - margin-top: 1em; -} - -[mobileMenu] > * -{ - position: relative; -} - -[mobileMenu] > atlas-banner -{ - z-index: 9999; -} - -[mobileMenu] > template-parcellation-citation-container -{ - z-index: 9; -} - -[mobileTemplateCitation] -{ - padding: 1.5em; - display:block; -} - [fixedMouseContextualContainerDirective] { width: 15rem; @@ -103,12 +51,6 @@ layout-floating-container overflow: hidden; } -div[minReq] -{ - width: 100%; - height: 100%; -} - div[imageContainer] { flex-grow: 1; @@ -120,24 +62,6 @@ div.displayCard opacity: 0.8; } -.mobileNavigationPanel { - background-color: white; - width: 80%; -} - -.menuButtonMobile { - position: absolute; - top: 0px; - right: 0px; - z-index: 9; -} - -.logoContainerMobile { - width: 100%; - display:flex; - justify-content: center; -} - mat-sidenav { box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); } diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index cdd41d6c245ea567d49cd90eddedd8315e75d443..3dc71fc6024f009fb76916bbe70e0bb5753962cd 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -13,11 +13,7 @@ </mat-dialog-content> <mat-dialog-actions class="justify-content-end"> - <button - color="primary" - mat-raised-button - (click)="kgTosClickedOk()" - cdkFocusInitial> + <button color="primary" mat-raised-button (click)="kgTosClickedOk()" cdkFocusInitial> Ok </button> </mat-dialog-actions> @@ -32,11 +28,7 @@ </mat-dialog-content> <mat-dialog-actions class="justify-content-end"> - <button - color="primary" - mat-raised-button - (click)="cookieClickedOk()" - cdkFocusInitial> + <button color="primary" mat-raised-button (click)="cookieClickedOk()" cdkFocusInitial> Ok </button> </mat-dialog-actions> @@ -46,33 +38,22 @@ <ng-template #viewerBody> <div class="atlas-container" (drag-drop)="localFileService.handleFileDrop($event)"> - <ui-nehuba-container - iav-mouse-hover - #iavMouseHoverEl="iavMouseHover" + <ui-nehuba-container iav-mouse-hover #iavMouseHoverEl="iavMouseHover" [currentOnHoverObs$]="iavMouseHoverEl.currentOnHoverObs$" [currentOnHover]="iavMouseHoverEl.currentOnHoverObs$ | async" (contextmenu)="$event.stopPropagation(); $event.preventDefault();"> </ui-nehuba-container> - + <div class="z-index-10 position-absolute pe-none w-100 h-100"> <!-- dataset search side nav --> - <mat-drawer-container - *ngIf="newViewer$ | async" - [hasBackdrop]="false" + <mat-drawer-container *ngIf="newViewer$ | async" [hasBackdrop]="false" class="w-100 h-100 bg-none mat-drawer-content-overflow-visible"> - <mat-drawer - mode="push" + <mat-drawer mode="push" class="col-10 col-sm-10 col-md-4 col-lg-3 col-xl-2 p-2 bg-none box-shadow-none overflow-visible" - [disableClose]="true" - [autoFocus]="false" - [opened]="true" - #sideNavDrawer> - <search-side-nav - (dismiss)="sideNavDrawer.close()" - (open)="sideNavDrawer.open()" - class="h-100 d-block overflow-visible" - #searchSideNav> + [disableClose]="true" [autoFocus]="false" [opened]="true" #sideNavDrawer> + <search-side-nav (dismiss)="sideNavDrawer.close()" (open)="sideNavDrawer.open()" + class="h-100 d-block overflow-visible" #searchSideNav> </search-side-nav> </mat-drawer> @@ -80,21 +61,17 @@ <!-- tag for opening and closing side nav --> <div class="d-flex h-100 align-items-start bg-none pe-none"> - <button mat-flat-button - matBadgePosition="above after" - matBadgeColor="accent" + <button mat-flat-button matBadgePosition="above after" matBadgeColor="accent" [matBadge]="!sideNavDrawer.opened && (selectedRegions$ | async)?.length ? (selectedRegions$ | async)?.length : null" [matTooltip]="!sideNavDrawer.opened ? (selectedRegions$ | async)?.length ? ('Explore ' + (selectedRegions$ | async)?.length + ' selected regions.') : 'Explore current view' : null" [ngClass]="{'translate-x-6-n': !sideNavDrawer.opened, 'translate-x-7-n': sideNavDrawer.opened}" - class="pe-all mt-5" - (click)="sideNavDrawer.toggle()"> - <i [ngClass]="{'fa-chevron-left': sideNavDrawer.opened, 'fa-chevron-right': !sideNavDrawer.opened}" class="fas translate-x-3"></i> + class="pe-all mt-5" (click)="sideNavDrawer.toggle()"> + <i [ngClass]="{'fa-chevron-left': sideNavDrawer.opened, 'fa-chevron-right': !sideNavDrawer.opened}" + class="fas translate-x-3"></i> </button> - <mat-card *ngIf="!sideNavDrawer.opened" - (click)="sideNavDrawer.open()" - mat-ripple + <mat-card *ngIf="!sideNavDrawer.opened" (click)="sideNavDrawer.open()" mat-ripple class="pe-all mt-4 muted translate-x-4-n"> <mat-card-content> <viewer-state-mini> @@ -112,14 +89,17 @@ <signin-banner signinWrapper> </signin-banner> </div> - - <layout-floating-container - zIndex="13" - #floatingOverlayContainer> + + <layout-floating-container zIndex="13" #floatingOverlayContainer> <div floatingContainerDirective> - + + </div> + + <div class="fixed-bottom pe-none d-flex justify-content-end m-4"> + <ng-container *ngTemplateOutlet="logoTmpl"> + </ng-container> </div> - + <!-- TODO document fixedMouseContextualContainerDirective , then deprecate this --> <!-- TODO move to nehuba overlay container --> <panel-component class="shadow" fixedMouseContextualContainerDirective #rClContextMenu> @@ -130,24 +110,19 @@ </div> <div body> - <div - *ngIf="(onhoverSegmentsForFixed$ | async)?.length > 0 || (selectedRegions$ | async)?.length > 0" + <div *ngIf="(onhoverSegmentsForFixed$ | async)?.length > 0 || (selectedRegions$ | async)?.length > 0" class="p-2"> Search for data relating to: </div> - - <div - *ngFor="let onhoverSegmentFixed of (onhoverSegmentsForFixed$ | async)" + + <div *ngFor="let onhoverSegmentFixed of (onhoverSegmentsForFixed$ | async)" (click)="searchRegion([onhoverSegmentFixed])" - class="ws-no-wrap text-left pe-all btn btn-sm btn-secondary btn-block mt-0" - data-toggle="tooltip" - data-placement="top" - [title]="onhoverSegmentFixed.name"> + class="ws-no-wrap text-left pe-all btn btn-sm btn-secondary btn-block mt-0" data-toggle="tooltip" + data-placement="top" [title]="onhoverSegmentFixed.name"> <small class="text-semi-transparent">(hovering)</small> {{ onhoverSegmentFixed.name }} </div> - - <div - *ngIf="(selectedRegions$ | async)?.length > 0 && (selectedRegions$ | async); let selectedRegions" + + <div *ngIf="(selectedRegions$ | async)?.length > 0 && (selectedRegions$ | async); let selectedRegions" (click)="searchRegion(selectedRegions)" class="ws-no-wrap text-left pe-all mt-0 btn btn-sm btn-secondary btn-block"> <ng-container *ngIf="selectedRegions.length > 1"> @@ -158,45 +133,37 @@ </ng-container> </div> - <div - class="p-2 text-muted" + <div class="p-2 text-muted" *ngIf="(onhoverSegmentsForFixed$ | async)?.length === 0 && (selectedRegions$ | async)?.length === 0 && (onhoverLandmarksForFixed$ | async)?.length === 0"> Right click on a parcellation region or select parcellation regions to search KG for associated datasets. </div> - + <ng-template #noRegionSelected> - <div - (click)="searchRegion()" - class="ws-no-wrap text-left pe-all mt-0 btn btn-sm btn-secondary btn-block"> + <div (click)="searchRegion()" class="ws-no-wrap text-left pe-all mt-0 btn btn-sm btn-secondary btn-block"> No region selected. Search KG for all datasets in this template space. </div> </ng-template> - + </div> </panel-component> - + <div floatingMouseContextualContainerDirective> - <div class="d-inline-block" - iav-mouse-hover - #iavMouseHoverConetxtualBlock="iavMouseHover" - contextualBlock> + <div class="d-inline-block" iav-mouse-hover #iavMouseHoverConetxtualBlock="iavMouseHover" contextualBlock> - <ng-container *ngFor="let labelText of iavMouseHoverConetxtualBlock.currentOnHoverObs$ | async | mouseOverTextPipe : selectedParcellation"> + <ng-container + *ngFor="let labelText of iavMouseHoverConetxtualBlock.currentOnHoverObs$ | async | mouseOverTextPipe : selectedParcellation"> <mat-list dense> - <mat-list-item> + <mat-list-item class="h-auto"> <mat-icon [fontSet]="(labelText.label | mouseOverIconPipe).fontSet" - [fontIcon]="(labelText.label | mouseOverIconPipe).fontIcon" - mat-list-icon> + [fontIcon]="(labelText.label | mouseOverIconPipe).fontIcon" mat-list-icon> </mat-icon> - - <div matLine - *ngFor="let text of labelText.text" - [innerHTML]="text"> + + <div matLine *ngFor="let text of labelText.text" [innerHTML]="text"> </div> </mat-list-item> </mat-list> @@ -206,7 +173,8 @@ </div> </layout-floating-container> - + + <!-- required for manufacturing plugin templates --> <div pluginFactoryDirective> </div> </div> @@ -214,29 +182,31 @@ <!-- does not meet req template --> <ng-template #doesNotMeetReqTemplate> - <div class="d-flex flex-column" minReq *ngIf="!meetsRequirement"> + <div class="d-flex flex-column w-100 h-100" *ngIf="!meetsRequirement"> <div class="jumbotron bg-light text-center mb-0"> <div> <h1 class="mb-3"> <i class="fas fa-exclamation-triangle"></i> Unsupported browser detected </h1> <p> - We recommend using the latest version of <a target="_blank" href="https://www.google.com/chrome/">Google Chrome</a> - or <a target="_blank" href="https://www.mozilla.org/firefox/">Mozilla Firefox)</a> for viewing the interactive viewer. + We recommend using the latest version of <a target="_blank" href="https://www.google.com/chrome/">Google + Chrome</a> + or <a target="_blank" href="https://www.mozilla.org/firefox/">Mozilla Firefox)</a> for viewing the interactive + viewer. </p> <div class="col-6 d-inline-block text-left"> - <readmore-component - [collapsedHeight]="0"> + <readmore-component [collapsedHeight]="0"> <markdown-dom [markdown]="constantsService.minReqExplaner"> - + </markdown-dom> </readmore-component> </div> - + </div> </div> <ng-container *ngFor="let preview of unsupportedPreviews; let idx = index"> - <div [hidden]="idx !== unsupportedPreviewIdx" class="text-center mb-3" imageContainer [style.backgroundImage]="'url(' + preview.previewSrc + ')'" > + <div [hidden]="idx !== unsupportedPreviewIdx" class="text-center mb-3" imageContainer + [style.backgroundImage]="'url(' + preview.previewSrc + ')'"> <div class="mt-2 card d-inline-block displayCard"> <div class="card-body"> {{ preview.text }} @@ -246,3 +216,8 @@ </ng-container> </div> </ng-template> + +<!-- logo tmpl --> +<ng-template #logoTmpl> + <logo-container></logo-container> +</ng-template> \ No newline at end of file diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css index b7ac08924c4523515e4c680ef2b0e3540d5e26b3..2781c6cad4bac7c850d42f3e07cecb7d374d9f66 100644 --- a/src/res/css/extra_styles.css +++ b/src/res/css/extra_styles.css @@ -446,6 +446,11 @@ markdown-dom pre code overflow-y: auto!important; } +.h-auto +{ + height: auto!important; +} + .h-90vh { height: 90vh!important; @@ -663,3 +668,15 @@ body::after { flex-grow: 5!important; } + +.layerBrowserContainer +{ + margin:-1em!important; +} + +.layerBrowserContainer .mat-dialog-container +{ + padding: 0!important; + overflow: hidden; + margin-top: 0.25rem; +} \ No newline at end of file diff --git a/src/res/ext/bigbrain.json b/src/res/ext/bigbrain.json index dd7adbb2f1be11bb9c12ddd1348975206aeaef33..2440a1ee9b1c54631a4fa82215c7b58123c1b5f5 100644 --- a/src/res/ext/bigbrain.json +++ b/src/res/ext/bigbrain.json @@ -10,34 +10,6 @@ }], "nehubaConfigURL": "nehubaConfig/bigbrainNehubaConfig", "parcellations": [ - { - "name": "Grey/White matter", - "type": "parcellation", - "ngData": null, - "ngId": " tissue type: ", - "regions": [ - { - "name": "Grey matter", - "labelIndex": 100, - "rgb": [ - 200, - 200, - 200 - ], - "children": [] - }, - { - "name": "White matter", - "labelIndex": 200, - "rgb": [ - 255, - 255, - 255 - ], - "children": [] - } - ] - }, { "name": "Cytoarchitectonic Maps", "properties": { @@ -572,6 +544,34 @@ ] } ] + }, + { + "name": "Grey/White matter", + "type": "parcellation", + "ngData": null, + "ngId": " tissue type: ", + "regions": [ + { + "name": "Grey matter", + "labelIndex": 100, + "rgb": [ + 200, + 200, + 200 + ], + "children": [] + }, + { + "name": "White matter", + "labelIndex": 200, + "rgb": [ + 255, + 255, + 255 + ], + "children": [] + } + ] } ], "properties": { diff --git a/src/ui/config/config.template.html b/src/ui/config/config.template.html index d5a271152ebeabc0e7419d4346c38059344a0fad..adfe40f939b86f9a8ccf7884b49ec0f426a524aa 100644 --- a/src/ui/config/config.template.html +++ b/src/ui/config/config.template.html @@ -1,6 +1,6 @@ <mat-tab-group> <!-- viewer preference --> - <mat-tab label="Viewer Preference"> + <mat-tab *ngIf="false" label="Viewer Preference"> <div class="m-2"> <div class="mat-h2"> diff --git a/src/ui/databrowserModule/kgSingleDatasetService.service.ts b/src/ui/databrowserModule/kgSingleDatasetService.service.ts index cd305937f52d3cea8bb4bc0e88db04a4d2d2f5d8..95e57173e77ecad65dec2bf544250bd2aa2852e5 100644 --- a/src/ui/databrowserModule/kgSingleDatasetService.service.ts +++ b/src/ui/databrowserModule/kgSingleDatasetService.service.ts @@ -4,12 +4,12 @@ import { Store, select } from "@ngrx/store"; import { SHOW_BOTTOM_SHEET } from "src/services/state/uiState.store"; import { ViewerPreviewFile, DataEntry } from "src/services/state/dataStore.store"; import { determinePreviewFileType, PREVIEW_FILE_TYPES } from "./preview/previewFileIcon.pipe"; -import { MatDialog } from "@angular/material"; +import { MatDialog, MatSnackBar } from "@angular/material"; import { FileViewer } from "./fileviewer/fileviewer.component"; import { ADD_NG_LAYER, REMOVE_NG_LAYER, CHANGE_NAVIGATION } from "src/services/stateStore.service"; import { Subscription, Subject } from "rxjs"; import { HttpClient } from "@angular/common/http"; -import { DialogService } from "src/services/dialogService.service"; +import { UIService } from "src/services/uiService.service"; @Injectable({ providedIn: 'root' }) export class KgSingleDatasetService implements OnDestroy{ @@ -24,7 +24,7 @@ export class KgSingleDatasetService implements OnDestroy{ private store$: Store<any>, private dialog: MatDialog, private http: HttpClient, - private dialogService: DialogService + private snackBar: MatSnackBar ) { this.subscriptions.push( @@ -34,7 +34,6 @@ export class KgSingleDatasetService implements OnDestroy{ this.ngLayers = new Set(layersInterface.layers.map(l => l.source.replace(/^nifti\:\/\//, ''))) }) ) - } ngOnDestroy(){ @@ -100,20 +99,21 @@ export class KgSingleDatasetService implements OnDestroy{ const { position, name } = file if (position) { - this.dialogService.getUserConfirm({ - message: `The file - ${name} - has a position of interest defined. Navigate to it?`, - title: `Navigate to ROI`, + this.snackBar.open(`Postion of interest found.`, 'Go there', { + duration: 5000 }) - .then(() => { - this.store$.dispatch({ - type: CHANGE_NAVIGATION, - navigation: { - position, - animation: {} - } - }) + .afterDismissed() + .subscribe(({ dismissedByAction }) => { + if (dismissedByAction) { + this.store$.dispatch({ + type: CHANGE_NAVIGATION, + navigation: { + position, + animation: {} + } + }) + } }) - .catch() } const type = determinePreviewFileType(file) diff --git a/src/ui/databrowserModule/preview/previewList.template.html b/src/ui/databrowserModule/preview/previewList.template.html index e98b7e3017e9eb7deb7c0620ccd68469dd8dd028..de6a34f6e020dcd1bda060abab0af5afd41eac7a 100644 --- a/src/ui/databrowserModule/preview/previewList.template.html +++ b/src/ui/databrowserModule/preview/previewList.template.html @@ -11,6 +11,12 @@ <h4 mat-line>{{ file.name }}</h4> <p mat-line>mimetype: {{ file.mimetype }}</p> </mat-list-item> + + <small *ngIf="previewFiles.length === 0" + class="text-muted"> + There are no preview files in this parcellation/template space. + </small> + </mat-nav-list> <ng-template #loadingPlaceholder> diff --git a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.component.ts b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.component.ts index a107965354ff9af8f6598900784cee7fcd2a3a23..a7b2c7cc0376006437f2a5ed3b447f0774f5d6e9 100644 --- a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.component.ts +++ b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.component.ts @@ -4,7 +4,7 @@ import { Component,ChangeDetectionStrategy, ChangeDetectorRef } from "@angular/c KgSingleDatasetService, AtlasViewerConstantsServices } from "../singleDataset.base"; -import { MatDialog } from "@angular/material"; +import { MatDialog, MatSnackBar } from "@angular/material"; import { SingleDatasetView } from "../detailedView/singleDataset.component"; @Component({ @@ -19,13 +19,14 @@ import { SingleDatasetView } from "../detailedView/singleDataset.component"; export class SingleDatasetListView extends SingleDatasetBase { constructor( - dbService: DatabrowserService, + private _dbService: DatabrowserService, singleDatasetService: KgSingleDatasetService, cdr: ChangeDetectorRef, constantService: AtlasViewerConstantsServices, - private dialog:MatDialog + private dialog:MatDialog, + private snackBar: MatSnackBar ){ - super(dbService, singleDatasetService, cdr, constantService) + super(_dbService, singleDatasetService, cdr, constantService) } showDetailInfo(){ @@ -33,4 +34,30 @@ export class SingleDatasetListView extends SingleDatasetBase { data: this.dataset }) } + + undoableRemoveFav(){ + this.snackBar.open(`Unpinned dataset: ${this.dataset.name}`, 'Undo', { + duration: 5000 + }) + .afterDismissed() + .subscribe(({ dismissedByAction }) => { + if (dismissedByAction) { + this._dbService.saveToFav(this.dataset) + } + }) + this._dbService.removeFromFav(this.dataset) + } + + undoableAddFav(){ + this.snackBar.open(`Pin dataset: ${this.dataset.name}`, 'Undo', { + duration: 5000 + }) + .afterDismissed() + .subscribe(({ dismissedByAction }) => { + if (dismissedByAction) { + this._dbService.saveToFav(this.dataset) + } + }) + this._dbService.saveToFav(this.dataset) + } } \ No newline at end of file diff --git a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html index 929de1f2d7c5da1fd85bd6a7ad787b6132cd9a7a..c968f3a8cad3f0c1d150012b1de4e3be794c2403 100644 --- a/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html +++ b/src/ui/databrowserModule/singleDataset/listView/singleDatasetListView.template.html @@ -5,16 +5,31 @@ {{ name }} </small> - <!-- pin --> - <button mat-icon-button - *ngIf="downloadEnabled" - class="no-focus flex-grow-0 flex-shrink-0" - iav-stop="click" - (click)="toggleFav()" - [color]="(favedDataentries$ | async | datasetIsFaved : dataset) ? 'primary' : 'basic'"> - <mat-icon fontSet="fas" fontIcon="fa-thumbtack"></mat-icon> - </button> + <ng-container *ngIf="downloadEnabled"> + + <!-- unpin --> + <button mat-icon-button + *ngIf="favedDataentries$ | async | datasetIsFaved : dataset; else pinTmpl" + (click)="undoableRemoveFav()" + iav-stop="click" + class="no-focus flex-grow-0 flex-shrink-0" + color="primary"> + <mat-icon fontSet="fas" fontIcon="fa-thumbtack"></mat-icon> + </button> + + <!-- pin --> + <ng-template #pinTmpl> + <button mat-icon-button + (click)="undoableAddFav()" + iav-stop="click" + class="no-focus flex-grow-0 flex-shrink-0" + color="basic"> + <mat-icon fontSet="fas" fontIcon="fa-thumbtack"></mat-icon> + </button> + </ng-template> + + </ng-container> <!-- more menu --> <button mat-icon-button diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts index aa78bdeebfbe5fd8e709ef5d871beaf23c17c9da..1419f1ee0ea34b38790539583add518ab5af0371 100644 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ b/src/ui/nehubaContainer/nehubaContainer.component.ts @@ -13,8 +13,6 @@ import { NEHUBA_READY, H_ONE_THREE, V_ONE_THREE, FOUR_PANEL, SINGLE_PANEL, NG_VI import { MOUSE_OVER_SEGMENTS } from "src/services/state/uiState.store"; import { getHorizontalOneThree, getVerticalOneThree, getFourPanel, getSinglePanel } from "./util"; import { SELECT_REGIONS_WITH_ID, NEHUBA_LAYER_CHANGED, VIEWERSTATE_ACTION_TYPES } from "src/services/state/viewerState.store"; -import { MatBottomSheet } from "@angular/material"; -import { KgSingleDatasetService } from "../databrowserModule/kgSingleDatasetService.service"; const getProxyUrl = (ngUrl) => `nifti://${BACKEND_URL}preview/file?fileUrl=${encodeURIComponent(ngUrl.replace(/^nifti:\/\//,''))}` const getProxyOther = ({source}) => /AUTH_227176556f3c4bb38df9feea4b91200c/.test(source) @@ -152,7 +150,6 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{ private panelOrder: string public panelOrder$: Observable<string> private redrawLayout$: Observable<[string, string]> - public favDataEntries$: Observable<DataEntry[]> public hoveredPanelIndices$: Observable<number> @@ -163,17 +160,10 @@ export class NehubaContainer implements OnInit, OnChanges, OnDestroy{ private apiService :AtlasViewerAPIServices, private csf:ComponentFactoryResolver, private store : Store<ViewerStateInterface>, - private elementRef : ElementRef, - public bottomSheet: MatBottomSheet, - private kgSingleDataset: KgSingleDatasetService + private elementRef : ElementRef ){ this.useMobileUI$ = this.constantService.useMobileUI$ - - this.favDataEntries$ = this.store.pipe( - select('dataStore'), - select('favDataEntries') - ) this.viewerPerformanceConfig$ = this.store.pipe( select('viewerConfigState'), diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html index 9d7cc3ea2d06bb533e0fe7274e05e94f24a56a1f..3e827ac7dd6143fd7506c7decea0b2c7092d9292 100644 --- a/src/ui/nehubaContainer/nehubaContainer.template.html +++ b/src/ui/nehubaContainer/nehubaContainer.template.html @@ -23,21 +23,6 @@ </current-layout> <layout-floating-container *ngIf="viewerLoaded"> - - <!-- tmp fab --> - <div class="mb-5 mr-3 load-fav-dataentries-fab position-absolute pe-all"> - <button - (click)="bottomSheet.open(savedDatasets)" - [matBadge]="(favDataEntries$ | async)?.length > 0 ? (favDataEntries$ | async)?.length : null " - matBadgeColor="accent" - matBadgePosition="above before" - matTooltip="Pinned datasets" - matTooltipPosition="before" - mat-fab - color="primary"> - <i class="fas fa-thumbtack"></i> - </button> - </div> <!-- StatusCard container--> <ui-status-card @@ -183,35 +168,3 @@ </div> </layout-floating-container> </ng-template> - -<ng-template #savedDatasets> - <mat-list rol="list"> - <h3 mat-subheader>Pinned Datasets</h3> - - <!-- place holder when no fav data is available --> - <mat-card *ngIf="(!(favDataEntries$ | async)) || (favDataEntries$ | async).length === 0"> - <mat-card-content class="muted"> - No pinned datasets. - </mat-card-content> - </mat-card> - - <!-- render all fav dataset as mat list --> - <!-- TODO maybe use virtual scroll here? --> - - <mat-list-item - mat-ripple - class="align-items-center" - *ngFor="let ds of (favDataEntries$ | async)" - role="listitem"> - - <single-dataset-list-view - class="d-block pt-1 pb-1 w-100" - [kgSchema]="(ds.fullId | getKgSchemaIdFromFullIdPipe)[0]" - [kgId]="(ds.fullId | getKgSchemaIdFromFullIdPipe)[1]" - [dataset]="ds"> - - </single-dataset-list-view> - - </mat-list-item> - </mat-list> -</ng-template> diff --git a/src/ui/searchSideNav/searchSideNav.component.ts b/src/ui/searchSideNav/searchSideNav.component.ts index c7a42be3b0da862836117c0214b391c9ac90e821..4d12f4cc8665955fadc4e23026cd14048ffc8a62 100644 --- a/src/ui/searchSideNav/searchSideNav.component.ts +++ b/src/ui/searchSideNav/searchSideNav.component.ts @@ -77,8 +77,11 @@ export class SearchSideNav implements OnInit, OnDestroy { this.layerBrowserDialogRef = this.dialog.open(dialogToOpen, { hasBackdrop: false, autoFocus: false, + panelClass: [ + 'layerBrowserContainer' + ], position: { - top: '1em' + top: '0' }, disableClose: true }) @@ -90,10 +93,6 @@ export class SearchSideNav implements OnInit, OnDestroy { }) } - extraLayersCanBeDismissed(): boolean{ - return this.dialog.openDialogs.findIndex(dialog => dialog !== this.layerBrowserDialogRef) < 0 - } - removeRegion(region: any){ this.store$.dispatch({ type: VIEWERSTATE_CONTROLLER_ACTION_TYPES.SINGLE_CLICK_ON_REGIONHIERARCHY, @@ -102,10 +101,4 @@ export class SearchSideNav implements OnInit, OnDestroy { } trackByFn = trackRegionBy - - public keyListenerConfig = [{ - key: 'Escape', - type: 'keydown', - target: 'document' - }] } \ No newline at end of file diff --git a/src/ui/searchSideNav/searchSideNav.template.html b/src/ui/searchSideNav/searchSideNav.template.html index 45d7d8f7422c467488aa58326722218043c1c42e..150ee0c7d7c3afae98acf4dd5fc0aec0e1506525 100644 --- a/src/ui/searchSideNav/searchSideNav.template.html +++ b/src/ui/searchSideNav/searchSideNav.template.html @@ -55,8 +55,6 @@ <div [hidden]> <layer-browser - [iav-key-listener]="(layerBrowser.nonBaseNgLayers$ | async).length > 0 ? keyListenerConfig : null" - (iav-key-event)="extraLayersCanBeDismissed() ? layerBrowser.removeAllNonBasicLayer() : null" (nonBaseLayersChanged)="handleNonbaseLayerEvent($event)" #layerBrowser> </layer-browser> @@ -66,13 +64,6 @@ <mat-dialog-content> <layer-browser></layer-browser> </mat-dialog-content> - <mat-dialog-actions class="justify-content-end"> - <button matTooltip="Rmove layers with [Esc]" - mat-button - mat-dialog-close="user action"> - Hide - </button> - </mat-dialog-actions> </ng-template> <!-- selected regions container --> diff --git a/src/ui/signinBanner/signinBanner.components.ts b/src/ui/signinBanner/signinBanner.components.ts index ac85379b68bb48dc88b76331958f510c7997df04..45743948ec5e763251ccf8246c5b3d8823fe9d4e 100644 --- a/src/ui/signinBanner/signinBanner.components.ts +++ b/src/ui/signinBanner/signinBanner.components.ts @@ -1,8 +1,10 @@ import {Component, ChangeDetectionStrategy, Input, TemplateRef } from "@angular/core"; import { AuthService, User } from "src/services/auth.service"; -import { MatDialog, MatDialogRef } from "@angular/material"; +import { MatDialog, MatDialogRef, MatBottomSheet } from "@angular/material"; import { Observable } from "rxjs"; import { map } from "rxjs/operators"; +import { DataEntry } from "src/services/stateStore.service"; +import { Store, select } from "@ngrx/store"; @Component({ @@ -21,10 +23,13 @@ export class SigninBanner{ public user$: Observable<User> public userBtnTooltip$: Observable<string> + public favDataEntries$: Observable<DataEntry[]> constructor( + private store$: Store<any>, private authService: AuthService, - private dialog: MatDialog + private dialog: MatDialog, + public bottomSheet: MatBottomSheet ){ this.user$ = this.authService.user$ @@ -33,6 +38,11 @@ export class SigninBanner{ ? `Logged in as ${(user && user.name) ? user.name : 'Unknown name'}` : `Not logged in`) ) + + this.favDataEntries$ = this.store$.pipe( + select('dataStore'), + select('favDataEntries') + ) } private dialogRef: MatDialogRef<any> diff --git a/src/ui/signinBanner/signinBanner.template.html b/src/ui/signinBanner/signinBanner.template.html index 8280808f390b961a42c2dc059737f67dbd0d850a..cbf5a904bf0d49ab1dbc01be0cd796547f892e16 100644 --- a/src/ui/signinBanner/signinBanner.template.html +++ b/src/ui/signinBanner/signinBanner.template.html @@ -2,6 +2,21 @@ [iav-key-listener]="keyListenerConfig" (iav-key-event)="openTmplWithDialog(helpComponent)"> + <!-- pinned datasets --> + + <div class="btnWrapper"> + <button mat-icon-button + (click)="bottomSheet.open(savedDatasets)" + [matBadge]="(favDataEntries$ | async)?.length > 0 ? (favDataEntries$ | async)?.length : null " + matBadgeColor="accent" + matBadgePosition="above after" + matTooltip="Pinned datasets" + color="primary"> + + <i class="fas fa-thumbtack"></i> + </button> + </div> + <!-- signin --> <div class="btnWrapper"> <button @@ -21,7 +36,7 @@ </div> </div> -<!-- drop down menu --> +<!-- drop downmenu --> <mat-menu #dropdownMenu> <mat-card> <mat-card-content> @@ -40,7 +55,7 @@ <button mat-menu-item (click)="openTmplWithDialog(settingTemplate)"> <mat-icon fontSet="fas" fontIcon="fa-cog"></mat-icon> - Setting + Settings </button> <button mat-menu-item @@ -95,4 +110,38 @@ <config-component class="mb-4 d-block"> </config-component> </mat-dialog-content> -</ng-template> \ No newline at end of file +</ng-template> + +<!-- saved dataset tmpl --> + +<ng-template #savedDatasets> + <mat-list rol="list"> + <h3 mat-subheader>Pinned Datasets</h3> + + <!-- place holder when no fav data is available --> + <mat-card *ngIf="(!(favDataEntries$ | async)) || (favDataEntries$ | async).length === 0"> + <mat-card-content class="muted"> + No pinned datasets. + </mat-card-content> + </mat-card> + + <!-- render all fav dataset as mat list --> + <!-- TODO maybe use virtual scroll here? --> + + <mat-list-item + mat-ripple + class="align-items-center" + *ngFor="let ds of (favDataEntries$ | async)" + role="listitem"> + + <single-dataset-list-view + class="d-block pt-1 pb-1 w-100" + [kgSchema]="(ds.fullId | getKgSchemaIdFromFullIdPipe)[0]" + [kgId]="(ds.fullId | getKgSchemaIdFromFullIdPipe)[1]" + [dataset]="ds"> + + </single-dataset-list-view> + + </mat-list-item> + </mat-list> +</ng-template>