diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78d9a7e7b59248e5b280835a47c7860b579061e2..98ff32775c62db929d9bcd1087e89d60eaee393c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,38 +26,37 @@ jobs: if: always() runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] - env: NODE_ENV: test steps: - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js 16.x uses: actions/setup-node@v1 with: - node-version: ${{ matrix.node-version }} + node-version: 16.x - run: npm i - - run: npm run test-ci + - run: | + if [[ "$GITHUB_REF" = *hotfix* ]] + then + export BS_REST_URL=https://siibra-api-rc.apps.hbp.eu/v2_0 + echo 'export const environment = { "BS_REST_URL": "https://siibra-api-rc.apps.hbp.eu/v2_0" }' > src/environments/environment.common.ts + fi + npm run test-ci backend: if: always() runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] env: NODE_ENV: test steps: - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js 16.x uses: actions/setup-node@v1 with: - node-version: ${{ matrix.node-version }} + node-version: 16.x - run: | cd deploy npm i diff --git a/docs/releases/v2.7.2.md b/docs/releases/v2.7.2.md new file mode 100644 index 0000000000000000000000000000000000000000..2a5ada611284053bd629c4f6dc0ed4c765889b58 --- /dev/null +++ b/docs/releases/v2.7.2.md @@ -0,0 +1,12 @@ +# v2.7.2 + +## Feature + +- (re)introduced the parcellation info button + +## Bugfix + +- fix the position of quick tour panel of slice view panels +- fix the atlas selection logic. This should reduce 4xx/5xx calls significantly +- minor update to parcellation chip appearance +- clicking on feature badge now properly selects the feature diff --git a/e2e/checklist.md b/e2e/checklist.md index b1a0c2ce262eb278c84724a0c680404b6c512fc6..eef89d804006fd65b2cfadb59cc3d687cb78f714 100644 --- a/e2e/checklist.md +++ b/e2e/checklist.md @@ -14,6 +14,11 @@ - [ ] Human multilevel atlas - [ ] on click from home page, MNI152, Julich v2.9 loads without issue - [ ] on hover, show correct region name(s) + - [ ] Parcellation smart chip + - [ ] show/hide parcellation toggle exists and works + - [ ] `q` is a shortcut to show/hide parcellation toggle + - [ ] info button exists and works + - [ ] info button shows desc, and link to KG - [ ] regional is fine :: select hOC1 right - [ ] probabilistic map loads fine - [ ] segmentation layer hides diff --git a/mkdocs.yml b/mkdocs.yml index 1ef131b83660c22bfd32bf74ff2f28882ed1193c..4d705ac0aabaec7503bcfab2794f46ea6a27d83b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: Interactive Atlas Viewer User Documentation +site_name: Siibra Explorer User Documentation theme: name: 'material' @@ -33,6 +33,7 @@ nav: - Fetching datasets: 'advanced/datasets.md' - Display non-atlas volumes: 'advanced/otherVolumes.md' - Release notes: + - v2.7.2: 'releases/v2.7.2.md' - v2.7.1: 'releases/v2.7.1.md' - v2.7.0: 'releases/v2.7.0.md' - v2.6.10: 'releases/v2.6.10.md' diff --git a/package.json b/package.json index 13acbd1cc0359acf28e8ab8ce42c6c44eb1bc1b9..82db76567fac6c5f0b472486c523ce38fa0b3a82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "interactive-viewer", - "version": "2.7.1", + "version": "2.7.2", "description": "siibra-explorer - explore brain atlases. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular", "scripts": { "lint": "eslint src --ext .ts", diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts index 62ba0e2528a8633db52bc44acdcadd3e9e851e04..0600ef2978744509aacbd555e1ae9c5472df89ec 100644 --- a/src/atlasComponents/sapi/sapi.service.ts +++ b/src/atlasComponents/sapi/sapi.service.ts @@ -24,7 +24,7 @@ import { SAPIFeature } from "./features"; import { environment } from "src/environments/environment" export const SIIBRA_API_VERSION_HEADER_KEY='x-siibra-api-version' -export const SIIBRA_API_VERSION = '0.2.0' +export const SIIBRA_API_VERSION = '0.2.1' type RegistryType = SAPIAtlas | SAPISpace | SAPIParcellation diff --git a/src/atlasComponents/sapiViews/core/parcellation/module.ts b/src/atlasComponents/sapiViews/core/parcellation/module.ts index cb7581d2d88ab9f43518261e87a515b8ceb99456..91133d0c156a173c9b9ccf063c2e69094bfee3fc 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/module.ts +++ b/src/atlasComponents/sapiViews/core/parcellation/module.ts @@ -4,11 +4,13 @@ import { Store } from "@ngrx/store"; import { ComponentsModule } from "src/components"; import { AngularMaterialModule } from "src/sharedModules"; import { atlasAppearance } from "src/state"; +import { DialogModule } from "src/ui/dialogInfo/module"; import { UtilModule } from "src/util"; import { SapiViewsUtilModule } from "../../util"; import { SapiViewsCoreParcellationParcellationChip } from "./chip/parcellation.chip.component"; import { FilterGroupedParcellationPipe } from "./filterGroupedParcellations.pipe"; import { FilterUnsupportedParcPipe } from "./filterUnsupportedParc.pipe"; +import { ParcellationDoiPipe } from "./parcellationDoi.pipe"; import { ParcellationIsBaseLayer } from "./parcellationIsBaseLayer.pipe"; import { ParcellationVisibilityService } from "./parcellationVis.service"; import { PreviewParcellationUrlPipe } from "./previewParcellationUrl.pipe"; @@ -22,6 +24,7 @@ import { SapiViewsCoreParcellationParcellationTile } from "./tile/parcellation.t AngularMaterialModule, UtilModule, SapiViewsUtilModule, + DialogModule, ], declarations: [ SapiViewsCoreParcellationParcellationTile, @@ -31,6 +34,7 @@ import { SapiViewsCoreParcellationParcellationTile } from "./tile/parcellation.t FilterGroupedParcellationPipe, FilterUnsupportedParcPipe, ParcellationIsBaseLayer, + ParcellationDoiPipe, ], exports: [ SapiViewsCoreParcellationParcellationTile, diff --git a/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..8652365e1bb40d6565ccfd9d88e30eb94492c6d4 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiParcellationModel } from "src/atlasComponents/sapi/type"; + +@Pipe({ + name: 'parcellationDoiPipe', + pure: true +}) + +export class ParcellationDoiPipe implements PipeTransform { + public transform(parc: SapiParcellationModel): string[] { + const urls = (parc?.brainAtlasVersions || []).filter( + v => v.digitalIdentifier && v.digitalIdentifier['@type'] === 'https://openminds.ebrains.eu/core/DOI' + ).map( + v => v.digitalIdentifier['@id'] as string + ) + return Array.from(new Set(urls)) + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/parcellationVersion.pipe.spec.ts b/src/atlasComponents/sapiViews/core/parcellation/parcellationVersion.pipe.spec.ts index 5a7eb1fc32405cd1a4f9128cfda54c018eb45766..77df043bb37ed7ffb87cad72d422dda777db33d0 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/parcellationVersion.pipe.spec.ts +++ b/src/atlasComponents/sapiViews/core/parcellation/parcellationVersion.pipe.spec.ts @@ -3,7 +3,7 @@ import { SAPI } from "src/atlasComponents/sapi/sapi.service" import { SapiParcellationModel } from "src/atlasComponents/sapi/type" import { getTraverseFunctions } from "./parcellationVersion.pipe" -describe("parcellationVersion.pipe.ts", () => { +describe(`parcellationVersion.pipe.ts (endpoint at ${SAPI.bsEndpoint})`, () => { describe("getTraverseFunctions", () => { let julichBrainParcellations: SapiParcellationModel[] = [] beforeAll(async () => { diff --git a/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.style.css b/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.style.css index e8d0ca357ccbfe577e65a2f9d78c1589227cbf33..f83fb1f49984f554b1a3fbcea0852d7f8005949b 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.style.css +++ b/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.style.css @@ -21,3 +21,14 @@ { margin: 0.5rem; } + +.icons-container +{ + transform: scale(0.7); + margin-right: -1.5rem; +} + +.icons-container > * +{ + margin: auto 0.2rem; +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.template.html b/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.template.html index e56b6b69b9fc9405c4efb29900f9a448921839cf..c15b1d11c2b503b4023ec2b46df3d163bb5f7dab 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.template.html +++ b/src/atlasComponents/sapiViews/core/parcellation/smartChip/parcellation.smartChip.template.html @@ -18,6 +18,22 @@ [sxplr-sapiviews-core-parcellation-chip-color]="(parcellation | equality : parc : trackByFn) ? 'primary' : 'default'" (sxplr-sapiviews-core-parcellation-chip-onclick)="selectParcellation(parc)"> + <div class="sxplr-scale-70" + suffix + iav-stop="mousedown click"> + + <ng-template #otherParcDesc> + <ng-template [ngTemplateOutlet]="parcDescTmpl" + [ngTemplateOutletContext]="{ parcellation: parc }"> + </ng-template> + </ng-template> + + <button mat-mini-fab color="default" + [sxplr-dialog]="otherParcDesc" + [sxplr-dialog-size]="null"> + <i class="fas fa-info"></i> + </button> + </div> </sxplr-sapiviews-core-parcellation-chip> <div class="spinner-container" *ngIf="(loadingParc$ | async) === parc"> @@ -42,9 +58,25 @@ #menuTrigger="matMenuTrigger" > - <div prefix class="sxplr-scale-70"> - <button mat-mini-fab - [color]="(parcellationVisibility$ | async) ? 'primary' : 'default'" + <div class="icons-container" + suffix + iav-stop="mousedown click"> + + <ng-template #mainParcDesc> + <ng-template [ngTemplateOutlet]="parcDescTmpl" + [ngTemplateOutletContext]="{ parcellation: parcellation }"> + </ng-template> + </ng-template> + + <button mat-icon-button + color="default" + [sxplr-dialog]="mainParcDesc" + [sxplr-dialog-size]="null"> + <i class="fas fa-info"></i> + </button> + + <button mat-icon-button + color="default" [matTooltip]="ARIA_LABELS.TOGGLE_DELINEATION" iav-stop="mousedown click" [iav-key-listener]="[{'type': 'keydown', 'key': 'q', 'capture': true, 'target': 'document' }]" @@ -58,14 +90,10 @@ {{ ARIA_LABELS.TOGGLE_DELINEATION }} </span> </button> - </div> - <div *ngIf="!(parcellation | parcellationIsBaseLayer)" - class="sxplr-scale-70" - suffix> <button mat-mini-fab - color="primary" - iav-stop="mousedown click" + *ngIf="!(parcellation | parcellationIsBaseLayer)" + color="default" (click)="dismiss()"> <spinner-cmp class="sxplr-w-100 sxplr-h-100" *ngIf="onDismissClicked$ | async; else defaultDismissIcon"></spinner-cmp> @@ -76,3 +104,32 @@ </button> </div> </sxplr-sapiviews-core-parcellation-chip> + +<!-- parcellation description template --> + +<ng-template #parcDescTmpl let-parc="parcellation"> + <h1 mat-dialog-title> + {{ parc.name }} + </h1> + <div mat-dialog-content> + <markdown-dom + *ngIf="parc.brainAtlasVersions.length > 0 && parc.brainAtlasVersions[0].versionInnovation" + [markdown]="parc.brainAtlasVersions[0].versionInnovation"> + </markdown-dom> + </div> + + <mat-dialog-actions align="start"> + <a *ngFor="let url of parc | parcellationDoiPipe" + [href]="url" + target="_blank" + mat-raised-button + color="primary"> + <div class="fas fa-external-link-alt"></div> + <span> + Explore + </span> + </a> + + <button mat-button mat-dialog-close>Close</button> + </mat-dialog-actions> +</ng-template> diff --git a/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html index 76f584328b3e46b5a240defb44e98e7cc2abe4a2..fc1ac7920b3599f52aafb071417eb6bb41c0d6e1 100644 --- a/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html +++ b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html @@ -3,7 +3,7 @@ <mat-chip-list *ngIf="feature | featureBadgeFlag" - class="sxplr-scale-80 transform-origin-left-center"> + class="sxplr-scale-80 transform-origin-left-center sxplr-pe-none"> <mat-chip [color]="feature | featureBadgeColour" selected> diff --git a/src/atlasComponents/sapiViews/util/parcellationSupportedInSpace.pipe.ts b/src/atlasComponents/sapiViews/util/parcellationSupportedInSpace.pipe.ts index f16e6a0a82d991ca8955e84f9ed4a15fe14e2ab4..42eec193e93fcd29dcf576c45135bf0b0f892eef 100644 --- a/src/atlasComponents/sapiViews/util/parcellationSupportedInSpace.pipe.ts +++ b/src/atlasComponents/sapiViews/util/parcellationSupportedInSpace.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from "@angular/core"; -import { Observable, of } from "rxjs"; +import { NEVER, Observable, of } from "rxjs"; import { map } from "rxjs/operators"; import { SAPIParcellation } from "src/atlasComponents/sapi/core"; import { SAPI } from "src/atlasComponents/sapi/sapi.service"; @@ -29,6 +29,7 @@ export class ParcellationSupportedInSpacePipe implements PipeTransform{ constructor(private sapi: SAPI){} public transform(parc: SapiParcellationModel|string, tmpl: SapiSpaceModel|string): Observable<boolean> { + if (!parc) return NEVER const parcId = typeof parc === "string" ? parc : parc["@id"] diff --git a/src/extra_styles.css b/src/extra_styles.css index 35a70999b7b44433ec39f25835dac0ceb5bff1a7..643ab1e507c31fc6e833ca777748a16714e83982 100644 --- a/src/extra_styles.css +++ b/src/extra_styles.css @@ -390,11 +390,6 @@ markdown-dom p height: 0px; } -.pe-none -{ - pointer-events: none!important; -} - .h-2rem { height: 2rem!important; diff --git a/src/overwrite.scss b/src/overwrite.scss index 790e436d35acc4e970127548ec060fa796b6a650..86f98096cead1a68e768e98ebd77aa084859fdf2 100644 --- a/src/overwrite.scss +++ b/src/overwrite.scss @@ -279,3 +279,13 @@ $flex-directions: row,column; opacity: 0.5; } } + +a[mat-raised-button] +{ + text-decoration: none; +} + +.#{$nsp}-pe-none +{ + pointer-events: none!important; +} diff --git a/src/state/atlasSelection/store.ts b/src/state/atlasSelection/store.ts index 08848c1efa9b81e649bfc8d7c29d3cc6581f77ed..ebea8a78dd3015d9b0b050c3902e40fb8ab2a0c8 100644 --- a/src/state/atlasSelection/store.ts +++ b/src/state/atlasSelection/store.ts @@ -117,9 +117,14 @@ const reducer = createReducer( on( actions.selectAtlas, (state, { atlas }) => { + if (atlas?.["@id"] === state?.selectedAtlas?.["@id"]) { + return state + } return { ...state, - selectedAtlas: atlas + selectedAtlas: atlas, + selectedTemplate: null, + selectedParcellation: null, } } ), diff --git a/src/ui/dialogInfo/dialog.directive.ts b/src/ui/dialogInfo/dialog.directive.ts index 1b30c4e59ede96787318fe0f8582a2ee85317072..63d886a6ef5fa172ea1a8cf17abb5587005a5751 100644 --- a/src/ui/dialogInfo/dialog.directive.ts +++ b/src/ui/dialogInfo/dialog.directive.ts @@ -52,7 +52,7 @@ export class DialogDirective{ } this.matDialog.open(this.templateRef, { data: this.data, - ...sizeDict[this.size] + ...(sizeDict[this.size] || {}) }) } } \ No newline at end of file diff --git a/src/ui/quickTour/quickTour.service.ts b/src/ui/quickTour/quickTour.service.ts index 3853a19497de7f3494d77c587b1a1e044cf00f5c..3aed96edf8d1cde0ff32642954be57f735a634a5 100644 --- a/src/ui/quickTour/quickTour.service.ts +++ b/src/ui/quickTour/quickTour.service.ts @@ -90,7 +90,7 @@ export class QuickTourService { height: '0px', width: '0px', hasBackdrop: true, - backdropClass: ['pe-none', 'cdk-overlay-dark-backdrop'], + backdropClass: ['sxplr-pe-none', 'cdk-overlay-dark-backdrop'], positionStrategy: this.overlay.position().global(), }) } diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts index 93af83e0d5f39e69334043acd31657aa18231e11..2fcf3b824328773660a44e725872f1aafd36dfd5 100644 --- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts +++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, ChangeDetectorRef, Component, Inject, OnDestroy } from "@angular/core"; +import { ChangeDetectorRef, Component, Inject, OnDestroy } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { combineLatest, fromEvent, interval, merge, Observable, of, Subject, Subscription } from "rxjs"; import { userInterface } from "src/state"; @@ -16,7 +16,7 @@ import { debounce, debounceTime, distinctUntilChanged, filter, map, mapTo, switc ] }) -export class NehubaLayoutOverlay implements OnDestroy, AfterViewInit{ +export class NehubaLayoutOverlay implements OnDestroy{ public ARIA_LABELS = ARIA_LABELS public IDS = IDS @@ -44,10 +44,6 @@ export class NehubaLayoutOverlay implements OnDestroy, AfterViewInit{ while(this.nehubaUnitSubs.length > 0) this.nehubaUnitSubs.pop().unsubscribe() } - ngAfterViewInit(): void { - this.setQuickTourPos() - } - handleCycleViewEvent(): void { if (this.currentPanelMode !== "SINGLE_PANEL") return this.store$.dispatch( @@ -124,6 +120,7 @@ export class NehubaLayoutOverlay implements OnDestroy, AfterViewInit{ nehuba$.subscribe(nehuba => { this.nehubaUnit = nehuba this.onNewNehubaUnit(nehuba) + this.setQuickTourPos() }) ) } diff --git a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html index e716c29fac236a4c7394b76a68a5027ffaf94646..245fb9f07ed2da09550b1bc63a6f1d9497a924cb 100644 --- a/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html +++ b/src/viewerModule/nehuba/layoutOverlay/nehuba.layoutOverlay/nehuba.layoutOverlay.template.html @@ -68,7 +68,7 @@ [attr.data-viewer-controller-visible]="visible" [attr.data-viewer-controller-index]="panelIndex"> - <div class="position-absolute w-100 h-100 pe-none" + <div class="position-absolute w-100 h-100 sxplr-pe-none" *ngIf="panelIndex === 1" quick-tour [quick-tour-description]="quickTourIconsSlide.description" diff --git a/src/viewerModule/viewerCmp/viewerCmp.style.css b/src/viewerModule/viewerCmp/viewerCmp.style.css index e7f00472f295d233a6d12cbd1b6dcc751d59d000..66c272acfcbc1f6fca1419582bde6d98efa53d88 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.style.css +++ b/src/viewerModule/viewerCmp/viewerCmp.style.css @@ -123,3 +123,9 @@ mat-list[dense].contextual-block { overflow: hidden auto; } + +.region-chip-suffix +{ + transform: scale(0.7); + margin-right: -0.25rem; +} diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index 90d6d4a3810ecb35d68f616af533a3579493d78a..f1a6b4faf088a2d733b6c91ff1f9d6c6d53964d5 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -5,7 +5,7 @@ <div class="floating-ui"> <div *ngIf="(media.mediaBreakPoint$ | async) < 2" - class="fixed-bottom pe-none mb-2 d-flex justify-content-center"> + class="fixed-bottom sxplr-pe-none mb-2 d-flex justify-content-center"> <logo-container></logo-container> </div> @@ -99,7 +99,7 @@ </mat-drawer> <!-- master content --> - <mat-drawer-content class="visible pe-none position-relative"> + <mat-drawer-content class="visible sxplr-pe-none position-relative"> <iav-layout-fourcorners> <!-- top left --> @@ -148,7 +148,7 @@ <!-- bottom left --> - <div iavLayoutFourCornersBottomLeft class="ws-no-wrap d-inline-flex w-100vw pe-none align-items-center mb-4"> + <div iavLayoutFourCornersBottomLeft class="ws-no-wrap d-inline-flex w-100vw sxplr-pe-none align-items-center mb-4"> <!-- special bottom left --> <ng-template [ngIf]="viewerMode$ | async" let-mode [ngIfElse]="localBottomLeftTmpl"></ng-template> @@ -436,7 +436,7 @@ <div prefix> </div> - <div suffix class="sxplr-scale-70"> + <div suffix class="region-chip-suffix"> <button mat-mini-fab color="primary" iav-stop="mousedown click" @@ -545,7 +545,7 @@ <i class="fas fa-sitemap"></i> </button> - <div class="w-100 h-100 position-absolute pe-none" *ngIf="showTour"> + <div class="w-100 h-100 position-absolute sxplr-pe-none" *ngIf="showTour"> </div> </div>