Skip to content
Snippets Groups Projects
Commit 050c62fe authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: new toast behaviour

parent f7e0d945
No related branches found
No related tags found
No related merge requests found
Showing
with 759 additions and 76 deletions
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, HostListener, ViewChild, ElementRef } from "@angular/core";
import { dropdownAnimation } from "./dropdown.animation";
import { HasExtraButtons, ExraBtnClickEvent } from '../radiolist/radiolist.component'
import { HasExtraButtons, ExraBtnClickEvent, ExtraButton } from '../radiolist/radiolist.component'
@Component({
selector : 'dropdown-component',
......@@ -16,6 +16,9 @@ import { HasExtraButtons, ExraBtnClickEvent } from '../radiolist/radiolist.compo
export class DropdownComponent{
@Input() activeDisplayBtns: ExtraButton[] = []
@Output() activeDisplayBtnClicked: EventEmitter<{extraBtn: ExtraButton, event: MouseEvent}> = new EventEmitter()
@Input() inputArray : HasExtraButtons[] = []
@Input() selectedItem : any | null = null
@Input() checkSelected: (selectedItem:any, item:any) => boolean = (si,i) => si === i
......@@ -38,4 +41,11 @@ export class DropdownComponent{
else
this.openState = false;
}
handleActiveDisplayBtnClick(btn: ExtraButton, event: MouseEvent){
this.activeDisplayBtnClicked.emit({
extraBtn: btn,
event
})
}
}
\ No newline at end of file
<!-- TODO remove dependency on ismobile -->
<span
class="btn btn-default dropdownTitle"
[innerHTML]="activeDisplay(selectedItem)"
[hoverable]="{translateY:-2}"
#dropdownToggle
dropdownToggle
[ngClass]="openState ? 'dropdownTitleOpen' : 'dropdownTitle'">
</span>
<div class="d-flex flex-column">
<div class="d-flex">
<span
class="btn btn-default dropdownTitle flex-grow-1 m-auto"
[innerHTML]="activeDisplay(selectedItem)"
[hoverable]="{translateY:-2}"
#dropdownToggle
dropdownToggle
[ngClass]="openState ? 'dropdownTitleOpen' : 'dropdownTitle'">
</span>
<span
*ngFor="let btn of activeDisplayBtns"
class="btn btn-default"
(click)="handleActiveDisplayBtnClick(btn, $event)"
[hoverable]="{translateY:-1}"
dropdownToggle>
<div class="d-flex align-items-center">
<small [ngClass]="btn.faIcon"></small>
</div>
</span>
</div>
</div>
<!-- needed to ensure dropdown width matches -->
<ul class="m-0 h-0 overflow-hidden">
......
......@@ -42,7 +42,7 @@ export class RadioList{
}
}
interface ExtraButton{
export interface ExtraButton{
name: string,
faIcon: string
class?: string
......
......@@ -8,13 +8,13 @@
class="d-flex justify-content-between"
[ngClass]="checkSelected(selectedItem, input) ? 'selected' : 'notselected'"
role="menuitem"
(click)="itemSelected.emit({previous: selectedItem, current: input})">
(click)="itemSelected.emit({previous: selectedItem, current: input})"
[matTooltip]="input.tooltipText">
<span class="dropdown-item-1 textSpan"
#DropDownText
[innerHTML]="listDisplay(input)"
[ngClass]="checkSelected(selectedItem, input) ? 'font-weight-bold' : ''"
[matTooltip]="overflowText(DropDownText)? DropDownText.innerText: ''">
[ngClass]="checkSelected(selectedItem, input) ? 'font-weight-bold' : ''">
</span>
<ng-container *ngIf="input.extraButtons as extraButtons">
......
......@@ -342,7 +342,8 @@ markdown-dom pre code
opacity: 0.5;
}
[darktheme="true"] .card
.card
{
background:none;
border:none;
}
\ No newline at end of file
This diff is collapsed.
......@@ -24,6 +24,7 @@ import { AggregateArrayIntoRootPipe } from "./util/aggregateArrayIntoRoot.pipe";
import { KgSingleDatasetService } from "./kgSingleDatasetService.service"
import { SingleDatasetView } from './singleDataset/singleDataset.component'
import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module'
import { DoiParserPipe } from "src/util/pipes/doiPipe.pipe";
@NgModule({
imports:[
......@@ -54,7 +55,8 @@ import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.modu
CopyPropertyPipe,
FilterDataEntriesbyMethods,
FilterDataEntriesByRegion,
AggregateArrayIntoRootPipe
AggregateArrayIntoRootPipe,
DoiParserPipe
],
exports:[
DataBrowser,
......
......@@ -93,6 +93,12 @@ export class SingleDatasetView implements OnInit {
: null
}
get showFooter(){
return (this.appendedKgReferences && this.appendedKgReferences.length > 0)
|| (this.publications && this.publications.length > 0)
|| (this.files && this.files.length > 0)
}
downloadZipFromKg() {
this.downloadInProgress = true
const { kgId, kgSchema } = this
......
......@@ -11,14 +11,17 @@
{{ description }}
</p>
<hr>
<hr *ngIf="showFooter">
<!-- publications -->
<a
*ngFor="let publication of publications"
[href]="'https://doi.org/' + publication.doi"
target="_blank">
{{ publication.cite }}
</a>
<div class="d-flex flex-column">
<a
*ngFor="let publication of publications"
[href]="publication.doi | doiParserPipe"
target="_blank">
{{ publication.cite }}
</a>
</div>
<!-- footer -->
<div class="d-flex justify-content-end">
......@@ -39,6 +42,8 @@
<!-- download -->
<a
(click)="downloadZipFromKg()"
[disabled]="downloadInProgress"
class="m-2"
*ngIf="files.length > 0"
mat-raised-button
......@@ -46,7 +51,7 @@
<span>
Download Zip
</span>
<span *ngIf="false">({{ numOfFiles }} files ~ {{ totalFileByteSize / 1e6 | number: '.1-2' }} MB)</span>
<span>({{ numOfFiles }} files ~ {{ totalFileByteSize / 1e6 | number: '.1-2' }} MB)</span>
<i class="fas" [ngClass]="!downloadInProgress? 'fa-download' :'fa-spinner fa-pulse'"></i>
</a>
</div>
......
......@@ -3,14 +3,16 @@ import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.consta
import { AuthService, User } from "src/services/auth.service";
import { Store, select } from "@ngrx/store";
import { ViewerConfiguration } from "src/services/state/viewerConfig.store";
import { Subscription, Observable, merge, Subject, interval } from "rxjs";
import { Subscription, Observable, merge, Subject, combineLatest } from "rxjs";
import { safeFilter, isDefined, NEWVIEWER, SELECT_REGIONS, SELECT_PARCELLATION, CHANGE_NAVIGATION } from "src/services/stateStore.service";
import { map, filter, distinctUntilChanged, bufferTime, delay, share, tap } from "rxjs/operators";
import { map, filter, distinctUntilChanged, bufferTime, delay, share, tap, withLatestFrom } from "rxjs/operators";
import { regionFlattener } from "src/util/regionFlattener";
import { ToastService } from "src/services/toastService.service";
import { getSchemaIdFromName } from "src/util/pipes/templateParcellationDecoration.pipe";
const compareParcellation = (o, n) => o.name === n.name
const compareParcellation = (o, n) => !o || !n
? false
: o.name === n.name
@Component({
selector: 'signin-banner',
......@@ -27,12 +29,14 @@ export class SigninBanner implements OnInit, OnDestroy{
public compareParcellation = compareParcellation
private subscriptions: Subscription[] = []
public loadedTemplates$: Observable<any[]>
public selectedTemplate$: Observable<any>
public selectedParcellation$: Observable<any>
public selectedRegions$: Observable<any[]>
private selectedRegions: any[] = []
selectedTemplate: any
@Input() darktheme: boolean
@ViewChild('publicationTemplate', {read:TemplateRef}) publicationTemplate: TemplateRef<any>
......@@ -74,28 +78,19 @@ export class SigninBanner implements OnInit, OnDestroy{
distinctUntilChanged((arr1, arr2) => arr1.length === arr2.length && (arr1 as any[]).every((item, index) => item.name === arr2[index].name))
)
this.focusedDatasets$ = merge(
this.selectedTemplate$.pipe(
map(v => [v])
),
this.selectedParcellation$.pipe(
distinctUntilChanged((o, n) => o.name === n.name),
map(p => {
if (!p.originDatasets || !p.originDatasets.map) return [p]
return p.originDatasets.map(od => {
return {
...p,
...od
}
})
})
this.focusedDatasets$ = this.userFocusedDataset$.pipe(
filter(v => !!v),
withLatestFrom(
combineLatest(this.selectedTemplate$, this.selectedParcellation$)
),
this.userFocusedDataset$.pipe(
filter(v => !!v)
)
).pipe(
map(([userFocusedDataset, [selectedTemplate, selectedParcellation]]) => {
const { type, ...rest } = userFocusedDataset
if (type === 'template') return { ...selectedTemplate, ...rest}
if (type === 'parcellation') return { ...selectedParcellation, ...rest }
return { ...rest }
}),
bufferTime(100),
map(arrOfArr => arrOfArr.reduce((acc, curr) => acc.concat(curr), [])),
filter(arr => arr.length > 0),
/**
* merge properties field with the root level
......@@ -119,9 +114,6 @@ export class SigninBanner implements OnInit, OnDestroy{
this.selectedRegions = regions
})
)
this.subscriptions.push(
this.selectedTemplate$.subscribe(template => this.selectedTemplate = template)
)
this.subscriptions.push(
this.focusedDatasets$.subscribe(() => {
......@@ -239,6 +231,22 @@ export class SigninBanner implements OnInit, OnDestroy{
})
}
handleActiveDisplayBtnClicked(event, type: 'parcellation' | 'template'){
const {
extraBtn,
event: extraBtnClickEvent
} = event
const { name } = extraBtn
const { kgSchema, kgId } = getSchemaIdFromName(name)
this.userFocusedDataset$.next({
kgSchema,
kgId,
type
})
}
handleExtraBtnClicked(event, toastType: 'parcellation' | 'template'){
const {
extraBtn,
......@@ -249,11 +257,11 @@ export class SigninBanner implements OnInit, OnDestroy{
const { name } = extraBtn
const { kgSchema, kgId } = getSchemaIdFromName(name)
this.userFocusedDataset$.next([{
this.userFocusedDataset$.next({
...inputItem,
kgSchema,
kgId
}])
})
extraBtnClickEvent.stopPropagation()
}
......
......@@ -4,11 +4,14 @@
<dropdown-component
(itemSelected)="changeTemplate($event)"
[checkSelected]="compareParcellation"
[activeDisplay]="displayActiveTemplate"
[selectedItem]="selectedTemplate$ | async"
[inputArray]="loadedTemplates$ | async | filterNull | templateParcellationsDecorationPipe"
[inputArray]="loadedTemplates$ | async | filterNull | appendTooltipTextPipe"
[ngClass]="isMobile ? flexItemIsMobileClass : flexItemIsDesktopClass"
(extraBtnClicked)="handleExtraBtnClicked($event, 'template')"
[activeDisplayBtns]="(selectedTemplate$ | async | templateParcellationsDecorationPipe)?.extraButtons"
(activeDisplayBtnClicked)="handleActiveDisplayBtnClicked($event, 'template')"
(listItemButtonClicked)="showInfoToast($event, 'template')">
</dropdown-component>
......@@ -19,9 +22,11 @@
[checkSelected]="compareParcellation"
[activeDisplay]="displayActiveParcellation"
[selectedItem]="selectedParcellation"
[inputArray]="selectedTemplate.parcellations | templateParcellationsDecorationPipe"
[inputArray]="selectedTemplate.parcellations | appendTooltipTextPipe"
[ngClass]="isMobile ? flexItemIsMobileClass : flexItemIsDesktopClass"
(extraBtnClicked)="handleExtraBtnClicked($event, 'parcellation')"
[activeDisplayBtns]="(selectedParcellation | templateParcellationsDecorationPipe)?.extraButtons"
(activeDisplayBtnClicked)="handleActiveDisplayBtnClicked($event, 'parcellation')"
(listItemButtonClicked)="showInfoToast($event, 'parcellation')">
</dropdown-component>
......
......@@ -47,6 +47,7 @@ import { CookieAgreement } from "./cookieAgreement/cookieAgreement.component";
import { KGToS } from "./kgtos/kgtos.component";
import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module'
import { TemplateParcellationsDecorationPipe } from "src/util/pipes/templateParcellationDecoration.pipe";
import { AppendtooltipTextPipe } from "src/util/pipes/appendTooltipText.pipe";
@NgModule({
......@@ -97,6 +98,7 @@ import { TemplateParcellationsDecorationPipe } from "src/util/pipes/templateParc
FilterNgLayer,
FilterNameBySearch,
TemplateParcellationsDecorationPipe,
AppendtooltipTextPipe,
/* directive */
DownloadDirective,
......
import { Pipe, PipeTransform } from "@angular/core";
/**
* TODO
* merge this pipe into cpProp pipe
*/
@Pipe({
name: 'appendTooltipTextPipe'
})
export class AppendtooltipTextPipe implements PipeTransform{
public transform(array: any[]){
return array.map(item => {
const { properties = {} } = item
const { description: tooltipText } = properties
return {
...item,
tooltipText
}
})
}
}
\ No newline at end of file
import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
name: 'doiParserPipe'
})
export class DoiParserPipe implements PipeTransform{
public transform(s: string, prefix: string = 'https://doi.org/'){
const prependFlag = /^https?:\.\./.test(s)
return `${prependFlag ? prefix : ''}${s}`
}
}
\ No newline at end of file
......@@ -15,29 +15,36 @@ const notEmptyArray = (arr) => !!arr && arr instanceof Array && arr.length > 0
})
export class TemplateParcellationsDecorationPipe implements PipeTransform{
public transform(parcellations:any[]){
return parcellations.map(p => {
const { description, properties = {}, publications } = p
const { description:pDescriptions, publications: pPublications } = properties
const defaultOriginaldataset = notNullNotEmptyString(description)
|| notNullNotEmptyString(pDescriptions)
|| notEmptyArray(publications)
|| notEmptyArray(pPublications)
? [{}]
: []
private decorateSingle(p:any){
const { originDatasets = defaultOriginaldataset } = p
return {
...p,
extraButtons: originDatasets
.map(({ kgSchema, kgId }) => {
return {
name: getNameFromSchemaId({ kgSchema, kgId }),
faIcon: 'fas fa-info-circle'
}
})
}
})
const { description, properties = {}, publications } = p
const { description:pDescriptions, publications: pPublications } = properties
const defaultOriginaldataset = notNullNotEmptyString(description)
|| notNullNotEmptyString(pDescriptions)
|| notEmptyArray(publications)
|| notEmptyArray(pPublications)
? [{}]
: []
const { originDatasets = defaultOriginaldataset } = p
return {
...p,
extraButtons: originDatasets
.map(({ kgSchema, kgId }) => {
return {
name: getNameFromSchemaId({ kgSchema, kgId }),
faIcon: 'fas fa-info'
}
})
}
}
private decorateArray (array:any[]) {
return array.map(this.decorateSingle)
}
public transform(item:any){
if (!item) return item
if(item instanceof Array) return this.decorateArray(item)
else return this.decorateSingle(item)
}
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment