From 0342260c0317502d601a6acd9347ea834186e1e4 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Wed, 18 Oct 2023 08:54:41 +0200 Subject: [PATCH] feat: add info icon, even if they are hidden --- docs/releases/v2.14.0.md | 1 + src/atlasComponents/sapi/schemaV3.ts | 2 + src/atlasComponents/sapi/translateV3.ts | 9 +- .../sapiViews/core/parcellation/index.ts | 2 +- .../sapiViews/core/parcellation/module.ts | 6 +- .../core/parcellation/parcTmplDoi.pipe.ts | 13 ++ .../core/parcellation/parcellationDoi.pipe.ts | 13 -- .../region/rich/region.rich.template.html | 2 +- .../sapiViews/core/rich/ATPSelector/module.ts | 2 + .../pureDumb/pureATPSelector.components.ts | 68 +++++---- .../pureDumb/pureATPSelector.template.html | 144 ++++++++++-------- 11 files changed, 155 insertions(+), 107 deletions(-) create mode 100644 src/atlasComponents/sapiViews/core/parcellation/parcTmplDoi.pipe.ts delete mode 100644 src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts diff --git a/docs/releases/v2.14.0.md b/docs/releases/v2.14.0.md index 0339fb1b0..4c561f6b4 100644 --- a/docs/releases/v2.14.0.md +++ b/docs/releases/v2.14.0.md @@ -4,6 +4,7 @@ - added `[p]` and `[n]` as keyboard shortcut to navigate previous/next slice - experimental support for other versions of regions +- show template and parcellation info even if the chip are hidden ## Behind the scenes diff --git a/src/atlasComponents/sapi/schemaV3.ts b/src/atlasComponents/sapi/schemaV3.ts index 53b4c245c..2e26c5065 100644 --- a/src/atlasComponents/sapi/schemaV3.ts +++ b/src/atlasComponents/sapi/schemaV3.ts @@ -550,6 +550,8 @@ export interface components { * @description Term or code used to identify the version of something. */ versionIdentifier: string + /** Datasets */ + datasets?: (components["schemas"]["EbrainsDatasetModel"])[] } /** * CoordinatePointModel diff --git a/src/atlasComponents/sapi/translateV3.ts b/src/atlasComponents/sapi/translateV3.ts index 6d08f2199..3f9de1ba5 100644 --- a/src/atlasComponents/sapi/translateV3.ts +++ b/src/atlasComponents/sapi/translateV3.ts @@ -166,14 +166,19 @@ class TranslateV3 { return this.#templateMap.get(template.id) } async translateTemplate(template:PathReturn<"/spaces/{space_id}">): Promise<SxplrTemplate> { + + const ds = await Promise.all((template.datasets || []).map(ds => this.translateDs(ds))) + const { ...rest } = ds[0] || {} this.#templateMap.set(template["@id"], template) - const tmpl = { + const tmpl: SxplrTemplate = { id: template["@id"], name: template.fullName, shortName: template.shortName, - type: "SxplrTemplate" as const + type: "SxplrTemplate" as const, + ...rest } + this.#sxplrTmplMap.set(tmpl.id, tmpl) return tmpl } diff --git a/src/atlasComponents/sapiViews/core/parcellation/index.ts b/src/atlasComponents/sapiViews/core/parcellation/index.ts index 78616fb9b..74925f1e2 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/index.ts +++ b/src/atlasComponents/sapiViews/core/parcellation/index.ts @@ -2,5 +2,5 @@ export { SapiViewsCoreParcellationModule } from "./module" export { FilterGroupedParcellationPipe } from "./filterGroupedParcellations.pipe" export { FilterUnsupportedParcPipe } from "./filterUnsupportedParc.pipe" export { GroupedParcellation } from "./groupedParcellation" -export { ParcellationDoiPipe } from "./parcellationDoi.pipe" +export { ParcTmplDoiPipe } from "./parcTmplDoi.pipe" export { ParcellationGroupSelectedPipe } from "./parcellationGroupSelected.pipe" diff --git a/src/atlasComponents/sapiViews/core/parcellation/module.ts b/src/atlasComponents/sapiViews/core/parcellation/module.ts index 9fb7e0066..5ed46747d 100644 --- a/src/atlasComponents/sapiViews/core/parcellation/module.ts +++ b/src/atlasComponents/sapiViews/core/parcellation/module.ts @@ -8,7 +8,7 @@ import { UtilModule } from "src/util"; import { SapiViewsUtilModule } from "../../util"; import { FilterGroupedParcellationPipe } from "./filterGroupedParcellations.pipe"; import { FilterUnsupportedParcPipe } from "./filterUnsupportedParc.pipe"; -import { ParcellationDoiPipe } from "./parcellationDoi.pipe"; +import { ParcTmplDoiPipe } from "./parcTmplDoi.pipe"; import { ParcellationVisibilityService } from "./parcellationVis.service"; import { ParcellationGroupSelectedPipe } from "./parcellationGroupSelected.pipe"; import { IsGroupedParcellation } from "./isGroupedParcellation.pipe"; @@ -31,7 +31,7 @@ import { ParcellationVisEffect } from "./parcellationVis.effect"; declarations: [ FilterGroupedParcellationPipe, FilterUnsupportedParcPipe, - ParcellationDoiPipe, + ParcTmplDoiPipe, ParcellationGroupSelectedPipe, IsGroupedParcellation, ], @@ -39,7 +39,7 @@ import { ParcellationVisEffect } from "./parcellationVis.effect"; FilterGroupedParcellationPipe, FilterUnsupportedParcPipe, ParcellationGroupSelectedPipe, - ParcellationDoiPipe, + ParcTmplDoiPipe, IsGroupedParcellation, ], providers: [ diff --git a/src/atlasComponents/sapiViews/core/parcellation/parcTmplDoi.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/parcTmplDoi.pipe.ts new file mode 100644 index 000000000..a2306403f --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/parcTmplDoi.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SxplrParcellation, SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes"; + +@Pipe({ + name: 'parcTmplDoiPipe', + pure: true +}) + +export class ParcTmplDoiPipe implements PipeTransform { + public transform(_parc: SxplrParcellation|SxplrTemplate): string[] { + return (_parc.link || []).map(v => v.href) + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts deleted file mode 100644 index dad016dc1..000000000 --- a/src/atlasComponents/sapiViews/core/parcellation/parcellationDoi.pipe.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { SxplrParcellation } from "src/atlasComponents/sapi/sxplrTypes"; - -@Pipe({ - name: 'parcellationDoiPipe', - pure: true -}) - -export class ParcellationDoiPipe implements PipeTransform { - public transform(_parc: SxplrParcellation): string[] { - return (_parc.link || []).map(v => v.href) - } -} diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html index b48e7804e..0f5e72501 100644 --- a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html @@ -43,7 +43,7 @@ [sxplr-dialog-data]="{ title: parcellation.name, descMd: parcellation.desc, - actions: parcellation | parcellationDoiPipe + actions: parcellation | parcTmplDoiPipe }"> <mat-icon mat-list-icon fontSet="fas" fontIcon="fa-brain"></mat-icon> <div mat-line class="overview-content">{{ parcellation.name }}</div> diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/module.ts b/src/atlasComponents/sapiViews/core/rich/ATPSelector/module.ts index acd1fbb94..c0269e9f1 100644 --- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/module.ts +++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/module.ts @@ -13,6 +13,7 @@ import { WrapperATPSelector } from "./wrapper/wrapper.component"; import { SAPIModule } from "src/atlasComponents/sapi/module"; import { MatTooltipModule } from "@angular/material/tooltip"; import { QuickTourModule } from "src/ui/quickTour"; +import { ExperimentalModule } from "src/experimental/experimental.module"; @NgModule({ imports: [ @@ -28,6 +29,7 @@ import { QuickTourModule } from "src/ui/quickTour"; SAPIModule, SapiViewsCoreParcellationModule, QuickTourModule, + ExperimentalModule, ], declarations: [ PureATPSelector, diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts index a11e3301d..2a169d93a 100644 --- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts +++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, Output, QueryList, SimpleChanges, ViewChildren } from "@angular/core"; +import { AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, OnDestroy, Output, QueryList, ViewChildren } from "@angular/core"; import { BehaviorSubject, Subscription, combineLatest, concat, merge, of } from "rxjs"; import { map, switchMap } from "rxjs/operators"; import { SxplrAtlas, SxplrParcellation, SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes"; @@ -43,28 +43,35 @@ const pipe = new FilterGroupedParcellationPipe() changeDetection: ChangeDetectionStrategy.OnPush, }) -export class PureATPSelector implements OnChanges, AfterViewInit, OnDestroy{ +export class PureATPSelector implements AfterViewInit, OnDestroy{ #subscriptions: Subscription[] = [] @Input('sxplr-pure-atp-selector-color-palette') colorPalette: string[] = darkThemePalette + #selectedATP$ = new BehaviorSubject<ATP>(null) @Input(`sxplr-pure-atp-selector-selected-atp`) - public selectedATP: ATP + set selectedATP(val: ATP){ + this.#selectedATP$.next(val) + } public selectedIds: string[] = [] @Input(`sxplr-pure-atp-selector-atlases`) public allAtlases: SxplrAtlas[] = [] + #availableTemplates$ = new BehaviorSubject<SxplrTemplate[]>([]) @Input(`sxplr-pure-atp-selector-templates`) - public availableTemplates: SxplrTemplate[] = [] + set availableTemplates(val: SxplrTemplate[]){ + this.#availableTemplates$.next(val) + } + #parcellations$ = new BehaviorSubject<SxplrParcellation[]>([]) @Input(`sxplr-pure-atp-selector-parcellations`) - public parcellations: SxplrParcellation[] = [] - - public parcAndGroup: (GroupedParcellation|SxplrParcellation)[] = [] + set parcellations(val: SxplrParcellation[]){ + this.#parcellations$.next(val) + } @Input('sxplr-pure-atp-selector-is-busy') public isBusy: boolean = false @@ -93,27 +100,34 @@ export class PureATPSelector implements OnChanges, AfterViewInit, OnDestroy{ this.selectLeafEmitter.emit(atp) } - ngOnChanges(changes: SimpleChanges): void { - if (changes.selectedATP) { - if (!changes.selectedATP.currentValue) { - this.selectedIds = [] - } else { - const { atlas, parcellation, template } = changes.selectedATP.currentValue as ATP - this.selectedIds = [atlas?.id, parcellation?.id, template?.id].filter(v => !!v) + view$ = combineLatest([ + this.#selectedATP$, + this.#parcellations$, + this.#availableTemplates$, + ]).pipe( + map(([{ atlas, parcellation, template }, parcellations, availableTemplates]) => { + const parcAndGroup = [ + ...pipe.transform(parcellations || [], true), + ...pipe.transform(parcellations || [], false), + ] + const selectedIds = [atlas?.id, parcellation?.id, template?.id].filter(v => !!v) + + const hideParcChip = parcAndGroup.length <= 1 + const hideTmplChip = availableTemplates?.length <= 1 + + return { + atlas, + parcellation, + template, + parcAndGroup, + parcellations, + selectedIds, + hideParcChip, + hideTmplChip, + availableTemplates: availableTemplates || [], } - } - - if (changes.parcellations) { - if (!changes.parcellations.currentValue) { - this.parcAndGroup = [] - } else { - this.parcAndGroup = [ - ...pipe.transform(changes.parcellations.currentValue, true), - ...pipe.transform(changes.parcellations.currentValue, false), - ] - } - } - } + }) + ) ngAfterViewInit(): void { this.#subscriptions.push( diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html index 9aaf8f964..d1a85f1b6 100644 --- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html +++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html @@ -1,8 +1,36 @@ -<ng-template [ngIf]="selectedATP" let-ATP> +<ng-template [ngIf]="view$ | async" let-view> + + <!-- fallback for parcellation info icon --> + <ng-template [ngIf]="view.hideParcChip"> + <button mat-icon-button + sxplr-dialog + [sxplr-dialog-size]="null" + [sxplr-dialog-data]="{ + title: view.parcellation.name, + descMd: view.parcellation.desc, + actions: view.parcellation | parcTmplDoiPipe + }"> + <i class="fas fa-info"></i> + </button> + </ng-template> + + <!-- fallback for space info icon --> + <ng-template [ngIf]="view.hideTmplChip"> + <button mat-icon-button + sxplr-dialog + [sxplr-dialog-size]="null" + [sxplr-dialog-data]="{ + title: view.template.name, + descMd: view.template.desc, + actions: view.template | parcTmplDoiPipe + }"> + <i class="fas fa-info"></i> + </button> + </ng-template> <!-- parcellation smart chip --> - <sxplr-smart-chip *ngIf="ATP.parcellation && parcAndGroup && parcAndGroup.length > 1" - [items]="parcAndGroup || []" + <sxplr-smart-chip *ngIf="!view.hideParcChip" + [items]="view.parcAndGroup || []" [color]="colorPalette[2]" [getChildren]="getChildren" (itemClicked)="selectLeaf({ parcellation: $event })" @@ -15,7 +43,7 @@ </span> <span class="sxplr-ml-1 text-muted"> - ({{ parcellations.length }}) + ({{ view.parcellations.length }}) </span> </ng-template> @@ -27,9 +55,9 @@ sxplr-dialog [sxplr-dialog-size]="null" [sxplr-dialog-data]="{ - title: ATP.parcellation.name, - descMd: ATP.parcellation.desc, - actions: ATP.parcellation | parcellationDoiPipe + title: view.parcellation.name, + descMd: view.parcellation.desc, + actions: view.parcellation | parcTmplDoiPipe }"> <i class="fas fa-info"></i> </button> @@ -42,7 +70,7 @@ <ng-template sxplrSmartChipContent> <span class="chip-text"> - {{ ATP.parcellation.shortName }} + {{ view.parcellation.shortName }} </span> </ng-template> @@ -51,7 +79,7 @@ <ng-container *ngTemplateOutlet="optionTmpl; context: { $implicit: parc, suffixText: (parc | isGroupedParcellation) && '(' + parc.parcellations.length + ')' , - overridePrefixIconTmpl: (parc | parcellationGroupSelected : ATP.parcellation) + overridePrefixIconTmpl: (parc | parcellationGroupSelected : view.parcellation) ? halfSelectedTmpl : null }"> @@ -60,8 +88,8 @@ </sxplr-smart-chip> <!-- space smart chip --> - <sxplr-smart-chip *ngIf="ATP.template && availableTemplates && availableTemplates.length > 1" - [items]="availableTemplates || []" + <sxplr-smart-chip *ngIf="!view.hideTmplChip" + [items]="view.availableTemplates || []" [color]="colorPalette[1]" (itemClicked)="selectLeaf({ template: $event })" [elevation]="4" @@ -73,14 +101,14 @@ </span> <span class="sxplr-ml-1 text-muted"> - ({{ availableTemplates.length }}) + ({{ view.availableTemplates.length }}) </span> </ng-template> <ng-template sxplrSmartChipContent> <span class="chip-text"> - {{ ATP.template.shortName }} + {{ view.template.shortName }} </span> </ng-template> <ng-template sxplrSmartChipMenu let-space> @@ -89,7 +117,7 @@ </sxplr-smart-chip> <!-- atlas smart chip --> - <sxplr-smart-chip *ngIf="ATP.atlas" + <sxplr-smart-chip *ngIf="view.atlas" [items]="allAtlases" [color]="colorPalette[0]" (itemClicked)="selectLeaf({ atlas: $event})" @@ -112,13 +140,54 @@ <ng-template sxplrSmartChipContent> <span class="chip-text"> - {{ ATP.atlas.name }} + {{ view.atlas.name }} </span> </ng-template> <ng-template sxplrSmartChipMenu let-atlas> <ng-container *ngTemplateOutlet="optionTmpl; context: { $implicit: atlas }"></ng-container> </ng-template> </sxplr-smart-chip> + + <!-- option template --> + <ng-template + #optionTmpl + let-item + let-overridePrefixIconTmpl="overridePrefixIconTmpl" + let-overrideSuffixIcon="overrideSuffixIcon" + let-suffixText="suffixText"> + + <!-- prefix --> + <ng-template [ngIf]="overridePrefixIconTmpl" [ngIfElse]="defaultPrefix"> + <ng-template [ngTemplateOutlet]="overridePrefixIconTmpl"></ng-template> + </ng-template> + <ng-template #defaultPrefix> + <ng-template [ngIf]="view.selectedIds" let-selectedIds> + <mat-icon + fontSet="fas" + [fontIcon]="selectedIds.includes(item.id) ? 'fa-circle' : 'fa-none'" + > + </mat-icon> + </ng-template> + </ng-template> + + <!-- button body --> + <span *ngIf="item" class="full-sized-button" + [matTooltip]="item.version?.name || item.name || item.fullName" + [matTooltipPosition]="'above'"> + {{ item.version?.name || item.shortName || item.name || item.fullName }} + <ng-template [ngIf]="suffixText"> + <span class="text-muted"> + {{ suffixText }} + </span> + </ng-template> + </span> + + <!-- suffix --> + <ng-template [ngIf]="overrideSuffixIcon"> + <i [class]="overrideSuffixIcon"></i> + </ng-template> + </ng-template> + </ng-template> <!-- half selected --> @@ -126,48 +195,3 @@ <ng-template #halfSelectedTmpl> <mat-icon fontSet="far" fontIcon="fa-circle"></mat-icon> </ng-template> - -<!-- option template --> -<ng-template - #optionTmpl - let-item - let-overridePrefixIconTmpl="overridePrefixIconTmpl" - let-overrideSuffixIcon="overrideSuffixIcon" - let-suffixText="suffixText"> - - <!-- prefix --> - <ng-template [ngIf]="overridePrefixIconTmpl" [ngIfElse]="defaultPrefix"> - <ng-template [ngTemplateOutlet]="overridePrefixIconTmpl"></ng-template> - </ng-template> - <ng-template #defaultPrefix> - <ng-template [ngIf]="selectedIds" let-selectedIds> - <mat-icon - fontSet="fas" - [fontIcon]="selectedIds.includes(item.id) ? 'fa-circle' : 'fa-none'" - > - </mat-icon> - </ng-template> - </ng-template> - - <!-- button body --> - <span *ngIf="item" class="full-sized-button" - [matTooltip]="item.version?.name || item.name || item.fullName" - [matTooltipPosition]="'above'"> - {{ item.version?.name || item.shortName || item.name || item.fullName }} - <ng-template [ngIf]="suffixText"> - <span class="text-muted"> - {{ suffixText }} - </span> - </ng-template> - </span> - - <!-- suffix --> - <ng-template [ngIf]="overrideSuffixIcon"> - <i [class]="overrideSuffixIcon"></i> - </ng-template> -</ng-template> - - -<ng-template #isBusyTmpl> - -</ng-template> \ No newline at end of file -- GitLab