diff --git a/src/atlasComponents/sapi/schemaV3.ts b/src/atlasComponents/sapi/schemaV3.ts index 78aa3e006d082b8ba95dd50716a438dd98026c0c..16bccab868831ecaf188e2f3b5c7f1c0a55c4c5f 100644 --- a/src/atlasComponents/sapi/schemaV3.ts +++ b/src/atlasComponents/sapi/schemaV3.ts @@ -544,10 +544,16 @@ export interface components { FeatureMetaModel: { /** Name */ name: string + /** Display Name */ + display_name: string /** Path */ path?: string /** Query Params */ query_params?: (string)[] + /** Required Query Params */ + required_query_params?: (string)[] + /** Optional Query Params */ + optional_query_params?: (string)[] /** Path Params */ path_params?: (string)[] /** Category */ @@ -716,6 +722,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[FeatureMetaModel] */ Page_FeatureMetaModel_: { @@ -727,6 +735,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[ParcellationEntityVersionModel] */ Page_ParcellationEntityVersionModel_: { @@ -738,6 +748,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraAtlasModel] */ Page_SiibraAtlasModel_: { @@ -749,6 +761,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraCorticalProfileModel] */ Page_SiibraCorticalProfileModel_: { @@ -760,6 +774,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraEbrainsDataFeatureModel] */ Page_SiibraEbrainsDataFeatureModel_: { @@ -771,6 +787,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraParcellationModel] */ Page_SiibraParcellationModel_: { @@ -782,6 +800,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraRegionalConnectivityModel] */ Page_SiibraRegionalConnectivityModel_: { @@ -793,6 +813,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraTabularModel] */ Page_SiibraTabularModel_: { @@ -804,6 +826,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[SiibraVoiModel] */ Page_SiibraVoiModel_: { @@ -815,6 +839,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** Page[Union[SiibraCorticalProfileModel, SiibraReceptorDensityFp, SiibraTabularModel]] */ Page_Union_SiibraCorticalProfileModel__SiibraReceptorDensityFp__SiibraTabularModel__: { @@ -826,6 +852,8 @@ export interface components { page: number /** Size */ size: number + /** Pages */ + pages?: number } /** ParcellationEntityVersionModel */ ParcellationEntityVersionModel: { @@ -1809,7 +1837,6 @@ export interface operations { parameters: { query: { space_id: string - bbox?: string type?: components["schemas"]["ImageTypes"] } path: { diff --git a/src/atlasComponents/sapiViews/util/module.ts b/src/atlasComponents/sapiViews/util/module.ts index 8d092a8c809ad7b3a42888a92b9becbf54ef6578..e863302c8626f285de94af0b4347b302a8ac715d 100644 --- a/src/atlasComponents/sapiViews/util/module.ts +++ b/src/atlasComponents/sapiViews/util/module.ts @@ -1,7 +1,6 @@ import { NgModule } from "@angular/core"; import { AddUnitAndJoin } from "./addUnitAndJoin.pipe"; import { EqualityPipe } from "./equality.pipe"; -import { IncludesPipe } from "./includes.pipe"; import { NumbersPipe } from "./numbers.pipe"; import { ParseDoiPipe } from "./parseDoi.pipe"; @@ -11,14 +10,12 @@ import { ParseDoiPipe } from "./parseDoi.pipe"; ParseDoiPipe, NumbersPipe, AddUnitAndJoin, - IncludesPipe, ], exports: [ EqualityPipe, ParseDoiPipe, NumbersPipe, AddUnitAndJoin, - IncludesPipe, ] }) diff --git a/src/features/category-acc.directive.ts b/src/features/category-acc.directive.ts index 353b405dca239768fa013f3aecd7aa921202d5ec..1ddb52d0c90c956c89f3ab62a0b6ee1f5518d586 100644 --- a/src/features/category-acc.directive.ts +++ b/src/features/category-acc.directive.ts @@ -4,6 +4,13 @@ import { map } from 'rxjs/operators'; import { Feature } from "src/atlasComponents/sapi/sxplrTypes" import { ListDirective } from './list/list.directive'; +export type GroupedFeature = { + features: Feature[] + meta: { + displayName: string + } +} + @Directive({ selector: '[sxplrCategoryAcc]', exportAs: 'categoryAcc' @@ -12,7 +19,10 @@ export class CategoryAccDirective implements AfterContentInit, OnDestroy { public isBusy$ = new BehaviorSubject<boolean>(false) public total$ = new BehaviorSubject<number>(0) - public features$ = new BehaviorSubject<Feature[]>([]) + public groupedFeatures$ = new BehaviorSubject<GroupedFeature[]>([]) + public features$ = this.groupedFeatures$.pipe( + map(arr => arr.flatMap(val => val.features)) + ) @ContentChildren(ListDirective, { read: ListDirective, descendants: true }) listCmps: QueryList<ListDirective> @@ -37,10 +47,14 @@ export class CategoryAccDirective implements AfterContentInit, OnDestroy { const listCmp = Array.from(this.listCmps) - this.#subscriptions.push( + this.#subscriptions.push( combineLatest( - listCmp.map(listC => listC.features$) - ).subscribe(features => this.features$.next(features.flatMap(f => f))), + listCmp.map( + listC => listC.features$.pipe( + map(features => ({ features, meta: { displayName: listC.displayName } })) + ) + ) + ).subscribe(val => this.groupedFeatures$.next(val)), combineLatest( listCmp.map(listC => listC.features$) diff --git a/src/features/entry/entry.flattened.component.html b/src/features/entry/entry.flattened.component.html index 03bf62d889518945041f00c0965024353e0372e1..db548da3942dcf8a081ed5841bc6fcb31cc4f7ee 100644 --- a/src/features/entry/entry.flattened.component.html +++ b/src/features/entry/entry.flattened.component.html @@ -69,6 +69,62 @@ </mat-panel-description> </mat-expansion-panel-header> + + <!-- <button mat-button>Show all</button> --> + <div class="mat-chip-container" + feature-filter-directive + [initValue]="true" + [items]="categoryAcc.groupedFeatures$ | async " + #filterFeatureCls="featureFilterDirective"> + + <div class="mat-chip-inner-container"> + + <button mat-icon-button matTooltip="Reset filter" + (click)="filterFeatureCls.setAll(true)"> + <i class="fas fa-filter"></i> + </button> + + <ng-template ngFor [ngForOf]="filterFeatureCls.items" let-grpFeat> + <ng-template [ngIf]="grpFeat.features.length > 0"> + + <ng-template [ngIf]="filterFeatureCls.checked$ | async | grpFeatToName | includes : grpFeat.meta.displayName" + [ngIfThen]="selectedTmpl" + [ngIfElse]="notSelectedTmpl"> + </ng-template> + + <ng-template #textTmpl> + <span> + {{ grpFeat.meta.displayName }} + </span> + <span class="text-muted1"> + ({{ grpFeat.features.length }}) + </span> + </ng-template> + <ng-template #selectedTmpl> + <button mat-flat-button + (click)="filterFeatureCls.toggle(grpFeat)" + color="primary"> + <i class="fas fa-eye"></i> + <ng-template [ngTemplateOutlet]="textTmpl"> + </ng-template> + </button> + </ng-template> + + <ng-template #notSelectedTmpl> + <button mat-flat-button + (click)="filterFeatureCls.toggle(grpFeat)" + color="default"> + <i class="fas fa-eye-slash"></i> + <ng-template [ngTemplateOutlet]="textTmpl"> + </ng-template> + </button> + </ng-template> + + </ng-template> + </ng-template> + </div> + </div> + <ng-template ngFor [ngForOf]="keyvalue.value" let-feature> <div sxplr-feature-list-directive @@ -78,13 +134,20 @@ [bbox]="bbox" [queryParams]="queryParams | mergeObj : { type: (feature.name | featureNamePipe) }" [featureRoute]="feature.path" + [name]="feature.name" + [displayName]="feature.display_name" #featureListDirective="featureListDirective"> </div> </ng-template> <cdk-virtual-scroll-viewport itemSize="36" + filter-grp-feat + [featureDisplayName]="filterFeatureCls.checked$ | async | mapToProperty : 'meta' | mapToProperty : 'displayName'" + [groupFeature]="categoryAcc.groupedFeatures$ | async" + #filterGrpFeat="filterGrpFeat" class="virtual-scroll-viewport"> - <button *cdkVirtualFor="let feature of categoryAcc.features$ | async" + + <button *cdkVirtualFor="let feature of filterGrpFeat.filteredFeatures$" mat-button class="virtual-scroll-item sxplr-w-100" [matTooltip]="feature.name" diff --git a/src/features/entry/entry.flattened.component.scss b/src/features/entry/entry.flattened.component.scss index 6aae997963d51b01cee208293d958dd5fd1591ac..34b69d51fd334765c690052c5676419602215c19 100644 --- a/src/features/entry/entry.flattened.component.scss +++ b/src/features/entry/entry.flattened.component.scss @@ -8,4 +8,23 @@ cdk-virtual-scroll-viewport button text-align: left; height: 36px; display: block; -} \ No newline at end of file +} + +.mat-chip-container +{ + width: 100%; + overflow-x: scroll; + overflow-y: hidden; + padding: 0.5rem; +} + +.mat-chip-inner-container +{ + display: inline-flex; +} + +.mat-chip-inner-container button +{ + white-space: nowrap; + margin: 0.2rem 0.4rem; +} diff --git a/src/features/feature-view/feature-view.component.html b/src/features/feature-view/feature-view.component.html index f4fdfe35f8a3b9f8240413bda9666e322ab06655..3c6339d0eb07bfb052fe578ce2ae2d1d6a5e6492 100644 --- a/src/features/feature-view/feature-view.component.html +++ b/src/features/feature-view/feature-view.component.html @@ -33,9 +33,39 @@ <spinner-cmp></spinner-cmp> </ng-template> - <a mat-icon-button sxplr-hide-when-local *ngFor="let url of feature.link" [href]="url.href" target="_blank"> - <i class="fas fa-external-link-alt"></i> - </a> + <!-- template for external link --> + <ng-template #externalLinkTmpl let-url> + <a mat-icon-button sxplr-hide-when-local [href]="url" target="_blank"> + <i class="fas fa-external-link-alt"></i> + </a> + </ng-template> + + <!-- if link is prepopulated --> + <ng-template + ngFor + [ngForOf]="feature.link" + let-url> + <ng-template + [ngTemplateOutlet]="externalLinkTmpl" + [ngTemplateOutletContext]="{ + $implicit: url.href + }"> + </ng-template> + </ng-template> + + <!-- if link is lazy fetched --> + <ng-template + ngFor + [ngForOf]="additionalLinks$ | async" + let-url> + <ng-template + [ngTemplateOutlet]="externalLinkTmpl" + [ngTemplateOutletContext]="{ + $implicit: url + }"> + </ng-template> + </ng-template> + </mat-card-subtitle> </mat-card> diff --git a/src/features/feature-view/feature-view.component.ts b/src/features/feature-view/feature-view.component.ts index 61371830b8d5e81761b9de75b311523e8016d0b9..b73f0e29cf4edc43b3a75e4385f9e264e2a3a683 100644 --- a/src/features/feature-view/feature-view.component.ts +++ b/src/features/feature-view/feature-view.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Inject, Input, OnChanges } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map } from 'rxjs/operators'; import { SAPI } from 'src/atlasComponents/sapi/sapi.service'; import { Feature, TabularFeature, VoiFeature } from 'src/atlasComponents/sapi/sxplrTypes'; import { DARKTHEME } from 'src/util/injectionTokens'; @@ -28,6 +28,15 @@ export class FeatureViewComponent implements OnChanges { @Input() feature: Feature + #detailLinks = new Subject<string[]>() + additionalLinks$ = this.#detailLinks.pipe( + distinctUntilChanged((o, n) => o.length == n.length), + map(links => { + const set = new Set((this.feature.link || []).map(v => v.href)) + return links.filter(l => !set.has(l)) + }) + ) + busy$ = new BehaviorSubject<boolean>(false) tabular$ = new BehaviorSubject<TabularFeature<number|string|number[]>>(null) @@ -90,6 +99,9 @@ export class FeatureViewComponent implements OnChanges { if (isVoiData(val)) { this.voi$.next(val) } + + this.#detailLinks.next((val.link || []).map(l => l.href)) + }, () => this.busy$.next(false) ) diff --git a/src/features/feature.filter.directive.ts b/src/features/feature.filter.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..14421065f2a2ed090a8c31dfef2c41877ddf3152 --- /dev/null +++ b/src/features/feature.filter.directive.ts @@ -0,0 +1,95 @@ +import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core"; +import { BehaviorSubject, combineLatest, concat, merge, of, Subject } from "rxjs"; +import { map, scan, shareReplay, switchMap } from "rxjs/operators"; + +@Directive({ + selector: '[feature-filter-directive]', + exportAs: 'featureFilterDirective' +}) +export class FeatureFilterDirective<T> implements OnChanges{ + @Input() + items: T[] = [] + + @Input() + initValue = false + + #items$ = new BehaviorSubject<T[]>(this.items) + #initValue$ = new BehaviorSubject<boolean>(this.initValue) + #toggle$ = new Subject<{ target: T }>() + #setValue$ = new Subject<{ target: T, flag: boolean}>() + #setAll$ = new Subject<{ flag: boolean }>() + + ngOnChanges(changes: SimpleChanges): void { + if (changes.items) { + this.#items$.next(changes.items.currentValue) + } + if (changes.initValue) { + this.#initValue$.next(changes.initValue.currentValue) + } + } + #checkbox$ = combineLatest([ + this.#items$, + this.#initValue$ + ]).pipe( + switchMap(([items, initFlag]) => { + const initialCondition = items.map(item => ({ item, flag: initFlag })) + return merge<{ target: T, flag?: boolean, op: string }>( + this.#toggle$.pipe( + map(v => ({ ...v, op: 'toggle' })) + ), + this.#setValue$.pipe( + map(v => ({ ...v, op: 'set' })) + ), + this.#setAll$.pipe( + map(v => ({ ...v, op: 'setAll' })) + ), + of({ op: 'noop' }) + ).pipe( + scan((acc, { target, op, flag }) => { + + if (op === 'noop') return acc + if (op === 'setAll') { + return acc.map(({ item }) => ({ item, flag })) + } + + const found = acc.find(({ item }) => item === target) + const other = acc.filter(({ item }) => item !== target) + const itemToAppend = found + ? [{ + item: found.item, + flag: op === 'set' + ? flag + : !found.flag + }] + : [] + return [ ...other, ...itemToAppend ] + }, initialCondition) + ) + }), + shareReplay(1), + ) + + checked$ = concat( + of([] as T[]), + this.#checkbox$.pipe( + map(arr => arr.filter(v => v.flag).map(v => v.item)), + ) + ) + + unchecked$ = concat( + of([] as T[]), + this.#checkbox$.pipe( + map(arr => arr.filter(v => !v.flag).map(v => v.item)), + ) + ) + + toggle(target: T){ + this.#toggle$.next({ target }) + } + setValue(target: T, flag: boolean) { + this.#setValue$.next({ target, flag }) + } + setAll(flag: boolean){ + this.#setAll$.next({ flag }) + } +} diff --git a/src/features/filterGrpFeat.directive.ts b/src/features/filterGrpFeat.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..3caa9416d934aa64a43716dbad8108ee697e698f --- /dev/null +++ b/src/features/filterGrpFeat.directive.ts @@ -0,0 +1,31 @@ +import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core"; +import { GroupedFeature } from "./category-acc.directive"; +import { combineLatest, Subject } from "rxjs"; +import { map } from "rxjs/operators"; + +@Directive({ + selector: '[filter-grp-feat]', + exportAs: 'filterGrpFeat' +}) +export class FilterGroupList implements OnChanges{ + + @Input() + featureDisplayName: string[] = [] + #featureDisplayName = new Subject<string[]>() + + @Input() + groupFeature: GroupedFeature[] = [] + #groupFeature = new Subject<GroupedFeature[]>() + + filteredFeatures$ = combineLatest([ + this.#featureDisplayName, + this.#groupFeature + ]).pipe( + map(([ displaynames, grpfeats ]) => grpfeats.filter(feat => displaynames.includes(feat.meta.displayName)).flatMap(f => f.features)) + ) + + ngOnChanges(): void { + this.#featureDisplayName.next(this.featureDisplayName) + this.#groupFeature.next(this.groupFeature) + } +} diff --git a/src/features/grpFeatToName.pipe.ts b/src/features/grpFeatToName.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..f124a683609247864bb79b1a55d9055c7b16627d --- /dev/null +++ b/src/features/grpFeatToName.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { GroupedFeature } from "./category-acc.directive"; + +@Pipe({ + name: 'grpFeatToName', + pure: true +}) + +export class GroupFeaturesToName implements PipeTransform{ + public transform(groupFeats: GroupedFeature[]): string[] { + return groupFeats.map(f => f.meta.displayName) + } +} diff --git a/src/features/list/list.directive.ts b/src/features/list/list.directive.ts index c5c4734d9fdc209219ccd49710f27e15005ffd6f..a2a7353ec31049d15c09b42b7634b94b35110c48 100644 --- a/src/features/list/list.directive.ts +++ b/src/features/list/list.directive.ts @@ -12,6 +12,12 @@ import { AllFeatures, FeatureBase } from "../base"; }) export class ListDirective extends FeatureBase{ + @Input() + name: string + + @Input() + displayName: string + @Input() featureRoute: string private guardedRoute$ = new BehaviorSubject<FeatureType>(null) diff --git a/src/features/module.ts b/src/features/module.ts index 48bf3848f516a69cfbb927506318cba85c6b9820..ba78304b9941fd6cafb9c1a85a53f2aa92be54d3 100644 --- a/src/features/module.ts +++ b/src/features/module.ts @@ -24,6 +24,10 @@ import { NgLayerCtlModule } from "src/viewerModule/nehuba/ngLayerCtlModule/modul import { VoiBboxDirective } from "./voi-bbox.directive"; import { FilterCategoriesPipe } from "./filterCategories.pipe"; import { ListDirective } from "./list/list.directive"; +import { MatChipsModule } from "@angular/material/chips"; +import { FeatureFilterDirective } from "./feature.filter.directive"; +import { FilterGroupList } from "./filterGrpFeat.directive" +import { GroupFeaturesToName } from "./grpFeatToName.pipe"; @NgModule({ imports: [ @@ -43,6 +47,7 @@ import { ListDirective } from "./list/list.directive"; MarkdownModule, MatTableModule, NgLayerCtlModule, + MatChipsModule, ], declarations: [ EntryComponent, @@ -50,12 +55,15 @@ import { ListDirective } from "./list/list.directive"; FeatureViewComponent, FilterCategoriesPipe, ListDirective, + FeatureFilterDirective, + FilterGroupList, CategoryAccDirective, VoiBboxDirective, FeatureNamePipe, TransformPdToDsPipe, + GroupFeaturesToName, ], exports: [ EntryComponent, diff --git a/src/routerModule/routeStateTransform.service.ts b/src/routerModule/routeStateTransform.service.ts index deab0f8b9733a703c9279a57c49a299c966a8bce..bbc9c3ab99f3cb27af71e07c49ceb4aa3ca225b4 100644 --- a/src/routerModule/routeStateTransform.service.ts +++ b/src/routerModule/routeStateTransform.service.ts @@ -8,7 +8,7 @@ import { atlasSelection, defaultState, MainState, plugins, userInteraction } fro import { getParcNgId } from "src/viewerModule/nehuba/config.service"; import { decodeToNumber, encodeNumber, encodeURIFull, separator } from "./cipher"; import { TUrlAtlas, TUrlPathObj, TUrlStandaloneVolume } from "./type"; -import { decodePath, encodeId, decodeId, endcodePath } from "./util"; +import { decodePath, encodeId, decodeId, encodePath } from "./util"; @Injectable() export class RouteStateTransformSvc { @@ -210,6 +210,8 @@ export class RouteStateTransformSvc { try { if (returnObj.f && returnObj.f.length === 1) { const decodedFeatId = decodeId(returnObj.f[0]) + .replace(/~ptc~/g, '://') + .replace(/~/g, ':') const feature = await this.sapi.getV3FeatureDetailWithId(decodedFeatId).toPromise() returnState["[state.userInteraction]"].selectedFeature = feature } @@ -290,7 +292,15 @@ export class RouteStateTransformSvc { // nav ['@']: cNavString, // showing dataset - f: selectedFeature && encodeId(selectedFeature.id) + f: (() => { + return selectedFeature && encodeId( + encodeURIFull( + selectedFeature.id + .replace(/:\/\//, '~ptc~') + .replace(/:/g, '~') + ) + ) + })() } /** @@ -307,7 +317,7 @@ export class RouteStateTransformSvc { const routesArr: string[] = [] for (const key in routes) { if (!!routes[key]) { - const segStr = endcodePath(key, routes[key]) + const segStr = encodePath(key, routes[key]) routesArr.push(segStr) } } diff --git a/src/routerModule/util.ts b/src/routerModule/util.ts index cd0709ea8fc1a30e4d11eab738db77af0ebd4ad2..0552eb3c882a1bc8e58b151155e5423cba7106e0 100644 --- a/src/routerModule/util.ts +++ b/src/routerModule/util.ts @@ -4,7 +4,7 @@ import { Component } from "@angular/core" export const encodeId = (id: string) => id && id.replace(/\//g, ':') export const decodeId = (codedId: string) => codedId && codedId.replace(/:/g, '/') -export const endcodePath = (key: string, val: string|string[]) => +export const encodePath = (key: string, val: string|string[]) => key[0] === '?' ? `?${key}=${val}` : `${key}:${Array.isArray(val) @@ -56,7 +56,7 @@ export const encodeCustomState = (key: string, value: string|string[]) => { throw new Error(`custom state must start with x-`) } if (!value) return null - return endcodePath(key, value).replace(/\//g, '%2F') + return encodePath(key, value).replace(/\//g, '%2F') } @Component({ diff --git a/src/atlasComponents/sapiViews/util/includes.pipe.ts b/src/util/includes.pipe.ts similarity index 100% rename from src/atlasComponents/sapiViews/util/includes.pipe.ts rename to src/util/includes.pipe.ts diff --git a/src/util/pipes/filterArray.pipe.ts b/src/util/pipes/filterArray.pipe.ts index 5e7c9653d73430b7631b78cd7a739a2a2ca13c75..3a4f76192591964ce667a568bce41c24635df7fd 100644 --- a/src/util/pipes/filterArray.pipe.ts +++ b/src/util/pipes/filterArray.pipe.ts @@ -6,7 +6,7 @@ import { Pipe, PipeTransform } from "@angular/core"; }) export class FilterArrayPipe implements PipeTransform{ - public transform<T>(arr: T[], filterFn: (item: T, index: number, array: T[]) => boolean){ + public transform<T>(arr: T[], filterFn: (item: T, index?: number, array?: T[]) => boolean){ return (arr || []).filter(filterFn) } } diff --git a/src/util/util.module.ts b/src/util/util.module.ts index b1007281e3c037b4766b301c0189e15dca21a878..de0d23cb14d309d82c2126ebe8b4f2b0421ea9d1 100644 --- a/src/util/util.module.ts +++ b/src/util/util.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; import { KeyListner } from "./directives/keyDownListener.directive"; - import { StopPropagationDirective } from "./directives/stopPropagation.directive"; import { SafeResourcePipe } from "./pipes/safeResource.pipe"; import { CaptureClickListenerDirective } from "./directives/captureClickListener.directive"; @@ -19,6 +18,7 @@ import { DoiParserPipe } from "./pipes/doiPipe.pipe"; import { GetFilenamePipe } from "./pipes/getFilename.pipe"; import { CombineFnPipe } from "./pipes/combineFn.pipe"; import { MergeObjPipe } from "./mergeObj.pipe"; +import { IncludesPipe } from "./includes.pipe"; @NgModule({ imports:[ @@ -43,6 +43,7 @@ import { MergeObjPipe } from "./mergeObj.pipe"; GetFilenamePipe, CombineFnPipe, MergeObjPipe, + IncludesPipe, ], exports: [ StopPropagationDirective, @@ -63,6 +64,7 @@ import { MergeObjPipe } from "./mergeObj.pipe"; GetFilenamePipe, CombineFnPipe, MergeObjPipe, + IncludesPipe, ] }) diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index 395ccba4f4f6c16ba74c0b3e215959d1ad7efd0f..1d15fc8f4f9ea9724719939cdd54d7ba4d56135c 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -1010,7 +1010,7 @@ </ng-template> </button> <div - *ngIf="voiSwitch.switchState$| async" + *ngIf="voiSwitch.switchState$ | async" voiBbox [features]="voiFeatureEntryCmp.features$ | async">