Skip to content

Commit

Permalink
Make the active button navigation button in results be an additional …
Browse files Browse the repository at this point in the history
…item in the list if it's hidden
  • Loading branch information
ommann committed Apr 9, 2024
1 parent cdddd40 commit ad10892
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 351 deletions.
35 changes: 26 additions & 9 deletions src/app/portal/components/tab-button/tab-button.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
<a class='tab-button-layout2 link-button' [ngClass]='{"link-button__active": active}' [routerLink]='route' style='text-decoration: none'>
<ng-container *ngIf='routerLink && !disabled'>
<a class='tab-button-layout2 link-button' [ngClass]='{"link-button__active": active, "link-button__disabled": disabled}' style='text-decoration: none' [routerLink]='routerLink' [queryParams]='queryParams'>

<div style='display: flex'>
<fa-icon [icon]="_icon" style='margin-right: 12px'></fa-icon>
<div style='display: flex'>
<fa-icon [icon]="_icon" style='margin-right: 12px'></fa-icon>

<div>{{ label }}</div>
</div>
<div>{{ label }}</div>
</div>

<ng-container *ngIf='count !== -1'>
<div [countUp]="count" [options]="countOps"></div>
</ng-container>
<ng-container *ngIf='count !== -1'>
<div [countUp]="count" [options]="countOps"></div>
</ng-container>
</a>
</ng-container>

<ng-container *ngIf='!routerLink || disabled'>
<a class='tab-button-layout2 link-button' [ngClass]='{"link-button__active": active, "link-button__disabled": disabled}' style='text-decoration: none'>

<div style='display: flex'>
<fa-icon [icon]="_icon" style='margin-right: 12px'></fa-icon>

<div>{{ label }}</div>
</div>

<ng-container *ngIf='count !== -1'>
<div [countUp]="count" [options]="countOps"></div>
</ng-container>
</a>
</ng-container>

</a>
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
border: 2px solid #4546B9;
}

.link-button__disabled {
color: #B0B0B0;
cursor: not-allowed;
}

/*.animated-number {
font-variant-numeric: tabular-nums;
}*/
6 changes: 5 additions & 1 deletion src/app/portal/components/tab-button/tab-button.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ import { RouterLinkWithHref } from '@angular/router';
export class TabButtonComponent {
@Input() label: string;
@Input() count: number;
@Input() route: string;

@Input() routerLink: string;
@Input() queryParams: any;

@Input() active = false;
@Input() disabled = false;

countOps = {
duration: 0.5,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
<div class='navigation-layout'>
<ng-container *ngIf='responsiveOrder$ | async as responsiveOrder'>
<ng-container *ngFor='let button of responsiveOrder | slice: 0:(end$ | async); trackBy: trackByLabel'>

<app-tab-button [icon]='button.icon' [label]='button.label' [count]='button.count' [route]='button.route' [active]='button.active'></app-tab-button>
<ng-container *ngIf='slicedButtons$ | async as buttons'>
<ng-container *ngFor='let button of buttons; trackBy: trackByLabel'>

<app-tab-button [icon]='button.icon'
[label]='button.label'
[count]='button.count'
[active]='button.active'
[disabled]='button.disabled'
[routerLink]='button.route + "/" + ((input$ | async) ?? "")'
[queryParams]='queryParams$ | async'>
</app-tab-button>

</ng-container>
</ng-container>

<ng-container *ngIf='(isActiveVisible$ | async) === false'>
<ng-container *ngIf='activeButton$ | async as button'>

<app-tab-button [icon]='button.icon'
[label]='button.label'
[count]='button.count'
[active]='button.active'
[disabled]='button.disabled'
[routerLink]='button.route + "/" + ((input$ | async) ?? "")'
[queryParams]='queryParams$ | async'>
</app-tab-button>

</ng-container>
</ng-container>

</div>

<ng-container *ngIf='(isDesktop$ | async) === false'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { HttpClient } from '@angular/common/http';
import { AppConfigService } from '@shared/services/app-config-service.service';
import { BreakpointObserver } from '@angular/cdk/layout';
import { SearchService } from '@portal/services/search.service';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router, UrlSegment } from '@angular/router';

type IndexCounts = { [index: string]: number };
type ButtonData = { label: string, icon: string, route: string, count: number, active: boolean };
type ButtonData = { label: string, icon: string, route: string, count: number, active: boolean, disabled?: boolean};

@Component({
selector: 'app-tab-navigation',
Expand All @@ -24,13 +24,15 @@ export class TabNavigationComponent {
breakpointObserver = inject(BreakpointObserver);
appConfigService = inject(AppConfigService);

route = inject(ActivatedRoute);
router = inject(Router);

url = this.appConfigService.apiUrl + "publication,person,funding,dataset,funding-call,infrastructure,organization/_search?request_cache=true";

showAll$ = new BehaviorSubject(false);

// Legacy compatibility
searchService = inject(SearchService);
route = inject(ActivatedRoute);

fullCounts$: Observable<IndexCounts> = this.http.post(this.url, payloadWithoutKeywords()).pipe(
map((response: any) => response.aggregations),
Expand All @@ -41,6 +43,11 @@ export class TabNavigationComponent {
input$ = this.route.params.pipe(map(params => params["input"]))
tab$ = this.route.params.pipe(map(params => params["tab"]))

// Just the "size" (of the page) of the query parameters is needed
queryParams$ = this.route.queryParams.pipe(
map(queryParams => ({ size: queryParams.size }))
);

partialCounts$ = this.input$.pipe(
switchMap(input => this.http.post(this.url, payloadWithKeywords(input)).pipe(
map((response: any) => response.aggregations),
Expand All @@ -58,12 +65,18 @@ export class TabNavigationComponent {
defaultOrderButtons$: Observable<ButtonData[]> = combineLatest([this.counts$, this.tab$]).pipe(
map(([counts, tab]) => [
{ label: $localize`:@@navigation.publications:Julkaisut`, icon: `faFileLines`, route: "/results/publications", count: counts.publications, active: tab === `publications` },
{ label: $localize`:@@navigation.funding-calls:Rahoitushaut`, icon: 'faBullhorn', route: "/results/funding-calls", count: counts.fundingCalls, active: tab === 'funding-calls' },

// label: $localize`:@@navigation.fundings:Hankkeet`,
{ label: "Myönnetty rahoitus", icon: 'faBriefcase', route: "/results/fundings", count: counts.fundings, active: tab === 'fundings' },
// "Myönnetty rahoitus",

{ label: $localize`:@@navigation.persons:Tutkijat`, icon: 'faUsers', route: "/results/persons", count: counts.persons, active: tab === 'persons' },
{ label: $localize`:@@navigation.fundings:Hankkeet`, icon: 'faBriefcase', route: "/results/fundings", count: counts.fundings, active: tab === 'fundings' },
{ label: $localize`:@@navigation.datasets:Aineistot`, icon: 'faFileAlt', route: "/results/datasets", count: counts.datasets, active: tab === 'datasets' },
{ label: $localize`:@@navigation.funding-calls:Rahoitushaut`, icon: 'faBullhorn', route: "/results/funding-calls", count: counts.fundingCalls, active: tab === 'funding-calls' },
{ label: $localize`:@@navigation.infrastructures:Infrastruktuurit`, icon: 'faUniversity', route: "/results/infrastructures", count: counts.infrastructures, active: tab === 'infrastructures' },
{ label: $localize`:@@navigation.organizations:Organisaatiot`, icon: 'faCalculator', route: "/results/organizations", count: counts.organizations, active: tab === 'organizations' },

{ label: "Hankkeet (tulossa)", icon: `faFileLines`, route: "/results/publications", count: -1, active: false, disabled: true },
])
);

Expand All @@ -89,10 +102,26 @@ export class TabNavigationComponent {
})
);

end$ = combineLatest([this.showAll$, this.responsiveSize$, this.defaultOrderButtons$]).pipe(
sliceEnd$ = combineLatest([this.showAll$, this.responsiveSize$, this.defaultOrderButtons$]).pipe(
map<[boolean, number, ButtonData[]], number>(([showAll, end, buttons]) => showAll ? buttons.length : end)
);

slicedButtons$: Observable<ButtonData[]> = combineLatest([this.responsiveOrder$, this.sliceEnd$]).pipe(
map(([buttons, end]) => buttons.slice(0, end))
);

activeButton$: Observable<ButtonData> = combineLatest([this.defaultOrderButtons$]).pipe(
map(([buttons]) => buttons.find(button => button.active))
);

isActiveVisible$ = combineLatest([this.activeButton$, this.slicedButtons$]).pipe(
// See inclusion based on the label field
map(([active, buttons]) => buttons.map(b => b.label).includes(active.label))

// Compare button against buttons
// map(([active, buttons]) => buttons.includes(active))
);

isDesktop$ = this.breakpointObserver.observe(['(min-width: 1200px)']).pipe(
map(result => result.matches)
);
Expand All @@ -104,6 +133,28 @@ export class TabNavigationComponent {
trackByLabel(index: number, button: ButtonData) {
return button.label;
}

changeLastPartOfUrl(newLastSegment: string) {
// Extract the current URL segments.
this.route.url.subscribe((segments: UrlSegment[]) => {
const pathSegments = segments.map(s => s.path);

if (pathSegments.length > 0) {
// Modify the last part of the path.
pathSegments[pathSegments.length - 1] = newLastSegment;
}

// Retain the existing query parameters.
const queryParams = this.route.snapshot.queryParams;

// Navigate to the new URL.
this.router.navigate([pathSegments.join('/')], { queryParams: queryParams }).then(success => {
if (!success) {
console.error('Navigation failed!');
}
});
});
}
}

function payloadWithoutKeywords() {
Expand Down
113 changes: 56 additions & 57 deletions src/app/portal/models/person/person-activities-awards.model.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,56 @@
// This file is part of the research.fi API service
//
// Copyright 2019 Ministry of Education and Culture, Finland
//
// :author: CSC - IT Center for Science Ltd., Espoo Finland [email protected]
// :license: MIT

import { Adapter } from '../adapter.model';
import { Injectable } from '@angular/core';
import { ModelUtilsService } from '@shared/services/model-util.service';

export class PersonActivitiesAndRewards {
constructor(
public name: string,
public role: string,
public type: string,
public description: string,
public internationalCollaboration: string,
public year: string,
public organizationName: string,
public departmentName: string,
public url: string,
) {}
}

@Injectable({
providedIn: 'root',
})
export class PersonActivitiesAndRewardsAdapter
implements Adapter<PersonActivitiesAndRewards>
{
constructor(private utils: ModelUtilsService) {}

adapt(activity: any): PersonActivitiesAndRewards {
console.log('activity', activity);
const getYearRange = () => {
return [activity.startDate.year, activity.endDate.year]
.filter((item) => item > 0)
.join(' - ');
};

const translateBoolean = (value: boolean) =>
value ? $localize`:@@yes:Kyllä` : $localize`:@@no:Ei`;

return new PersonActivitiesAndRewards(
this.utils.checkTranslation('name', activity),
this.utils.checkTranslation('roleName', activity),
this.utils.checkTranslation('activityTypeName', activity),
this.utils.checkTranslation('description', activity),
translateBoolean(activity.internationalCollaboration),
getYearRange(),
this.utils.checkTranslation('organizationName', activity),
this.utils.checkTranslation('departmentName', activity),
activity.url
);
}
}
// This file is part of the research.fi API service
//
// Copyright 2019 Ministry of Education and Culture, Finland
//
// :author: CSC - IT Center for Science Ltd., Espoo Finland [email protected]
// :license: MIT

import { Adapter } from '../adapter.model';
import { Injectable } from '@angular/core';
import { ModelUtilsService } from '@shared/services/model-util.service';

export class PersonActivitiesAndRewards {
constructor(
public name: string,
public role: string,
public type: string,
public description: string,
public internationalCollaboration: string,
public year: string,
public organizationName: string,
public departmentName: string,
public url: string,
) {}
}

@Injectable({
providedIn: 'root',
})
export class PersonActivitiesAndRewardsAdapter
implements Adapter<PersonActivitiesAndRewards>
{
constructor(private utils: ModelUtilsService) {}

adapt(activity: any): PersonActivitiesAndRewards {
const getYearRange = () => {
return [activity.startDate.year, activity.endDate.year]
.filter((item) => item > 0)
.join(' - ');
};

const translateBoolean = (value: boolean) =>
value ? $localize`:@@yes:Kyllä` : $localize`:@@no:Ei`;

return new PersonActivitiesAndRewards(
this.utils.checkTranslation('name', activity),
this.utils.checkTranslation('roleName', activity),
this.utils.checkTranslation('activityTypeName', activity),
this.utils.checkTranslation('description', activity),
translateBoolean(activity.internationalCollaboration),
getYearRange(),
this.utils.checkTranslation('organizationName', activity),
this.utils.checkTranslation('departmentName', activity),
activity.url
);
}
}
Loading

0 comments on commit ad10892

Please sign in to comment.