[Monitor Dashboard|Trunk]

Indicators page - Filters:
	filters in burger menu on the right
	add range filter component
	
Indicator utils:
	AddFilter(): add filter for parameterized queries
	parameterizeDefaultQuery(): 
		for parameterized queries stakeholder position is not fixed in first place. parameters contain start/end year in first 2 places.
		make it work for double queries like "name":"monitor.funder.greenvsgold.name.type","parameters":["2020","2020","European Commission","dataset","2020","2020","European Commission","dataset"]
		


git-svn-id: https://svn.driver.research-infrastructures.eu/driver/dnet40/modules/uoa-monitor-portal/trunk/monitor_dashboard@59061 d315682c-612b-4755-9ff5-7f18f6832af3
This commit is contained in:
Argiro Kokogiannaki 2020-07-10 08:37:51 +00:00
parent 887884c260
commit 204cb9a597
8 changed files with 205 additions and 117 deletions

View File

@ -51,7 +51,6 @@
"jquery": "^3.4.1",
"ng-recaptcha": "^3.0.5",
"ng2-ckeditor": "1.1.9",
"ng2-nouislider": "^1.8.2",
"ngx-json-ld": "0.1.6",
"nouislider": "^14.6.0",
"prom-client": "^11.3.0",

View File

@ -28,21 +28,13 @@
</li>
</ng-template>
</ul>
<!-- <div>
Filters
<input class="uk-input uk-form-width-medium" placeholder="Funding Stream" type="text" name="fund_level_0"
[(ngModel)]="fundingL0">
<input class="uk-input uk-form-width-medium" placeholder="Start year" type="text" name="start_year"
[(ngModel)]="startYear">
<input class="uk-input uk-form-width-medium" placeholder="End year" type="text" name="end_year"
[(ngModel)]="endYear">
<nouislider [connect]="true" [min]="0" [max]="15" [step]="1" [(ngModel)]="someRange"
(ngModelChange)="filter()"></nouislider>
&lt;!&ndash; <double-slider></double-slider>&ndash;&gt;
<button class="uk-button uk-button-primary" (click)="filter()">Apply</button>
</div>-->
<div *ngIf="filterApplied">
<span>Filters: </span>
<span *ngIf="periodFilter.selectedFromAndToValues.length > 0" class="filter">
<a (click)="clearPeriodFilter()"> <i
class=" material-icons"></i>
</a> {{periodFilter.selectedFromAndToValues}}</span>
</div>
<div *ngIf="privateStakeholder">
<div class="uk-text-center uk-height-medium">
<div class="uk-h3 "><i>
@ -97,6 +89,7 @@
[class.uk-width-1-2]="indicator.width === 'large'" class=" uk-margin-bottom">
<div class="md-card" [attr.uk-tooltip]="indicator.description">
<div class="md-card-content">
<!-- <div>Filtered: {{indicator.indicatorPaths[0].filteredApplied}}</div>-->
<h2 *ngIf="numberResults.get(i + '-' + j)" class="">
<span>{{numberResults.get(i + '-' + j) | number}}</span>
</h2>
@ -107,8 +100,7 @@
</ng-template>
</ng-template>
</div>
<div *ngIf="activeSubCategory"
>
<div *ngIf="activeSubCategory">
<div *ngFor="let chart of activeSubCategory.charts; let i = index;"
class="uk-grid uk-grid-medium uk-margin-bottom uk-flex uk-flex-bottom "
uk-height-match="target: div > div > .chartTitle">
@ -134,7 +126,7 @@
{{indicatorPath.type}}
</button>
</div>
<div>Filtered: {{chartsActiveType.get(i + '-' + j).filteredApplied}}</div>
<!-- <div>Filtered: {{chartsActiveType.get(i + '-' + j).filteredApplied}}</div>-->
<iframe *ngIf="chartsActiveType.get(i + '-' + j).source !== 'image'"
[src]="chartsActiveType.get(i + '-' + j).safeResourceUrl"
class="uk-width-1-1 uk-height-medium"></iframe>
@ -158,17 +150,9 @@
</div>
</div>
</div>
<!--<div *ngIf="stakeholder" id="style_switcher" title="This functionality is comming soon. Stay tuned!">
<div id="style_switcher_toggle">
<a *ngIf="isAdmin() " [routerLink]="['/admin', this.stakeholder.alias]" >
<i class="material-icons">settings</i>
</a>
<i *ngIf="!isAdmin() " class="material-icons uk-text-muted">settings</i>
</div>
</div>-->
<div *ngIf="stakeholder && !privateStakeholder" id="style_switcher" class="filters_switcher"
title="It is comming soon. Stay tuned!">
<div id="style_switcher_toggle">
[class.switcher_active]="filterToggle">
<div id="style_switcher_toggle" (click)="filterToggle= !filterToggle">
<i class=" uk-text-muted">
<svg style="margin-top: 6px;" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
@ -182,6 +166,27 @@
</svg>
</i>
</div>
<div class="">
<div class="uk-float-right" ><a (click)="filterToggle=!filterToggle"> <i
class=" material-icons md-icon"></i>
</a></div>
<div class="uk-padding">
<div class="uk-h4 ">Filters</div>
<div *ngIf="periodFilter.selectedFromAndToValues.length > 0">
<span class="filter" title="Remove {{periodFilter.selectedFromAndToValues}}">
<a (click)="clearPeriodFilter()"> <i
class=" material-icons"></i>
</a> {{periodFilter.selectedFromAndToValues}}</span>
</div>
<ul class="uk-list uk-list-divider uk-margin-medium">
<li>
<range-filter [filter]="periodFilter" yearMin="2000" yearMax="2020" [mandatoryRange]="true"
(onFilterChange)="filter()"></range-filter>
</li>
</ul>
</div>
</div>
</div>

View File

@ -18,6 +18,7 @@ import {FormBuilder, FormControl} from "@angular/forms";
import {Subscription} from "rxjs";
import {Session, User} from "../openaireLibrary/login/utils/helper.class";
import {UserManagementService} from "../openaireLibrary/services/user-management.service";
import {RangeFilter} from "../openaireLibrary/utils/rangeFilter/rangeFilterHelperClasses.class";
@Component({
selector: 'monitor',
@ -45,8 +46,10 @@ export class MonitorComponent implements OnInit, OnDestroy {
private errorMessages: ErrorMessagesComponent;
properties: EnvProperties;
fundingL0;
startYear;
endYear;
filterToggle = false;
filterApplied = false;
periodFilter:RangeFilter = { title: "Period", filterId: "year", originalFilterIdFrom: null, originalFilterIdTo: null, selectedFromValue: null, selectedToValue: null, selectedFromAndToValues: ""};
privateStakeholder = false;
public keyword: FormControl;
public someRange: number[] = [3, 7];
@ -68,7 +71,7 @@ export class MonitorComponent implements OnInit, OnDestroy {
this.errorMessages = new ErrorMessagesComponent();
this.status = this.errorCodes.LOADING;
}
public ngOnInit() {
this.keyword = this._fb.control('');
this.keyword.valueChanges.subscribe(value => {
@ -94,31 +97,12 @@ export class MonitorComponent implements OnInit, OnDestroy {
var url = data.envSpecific.baseLink + this._router.url;
this.route.queryParams.subscribe(params => {
this.isViewPublic = (params['view'] == 'public');
this.startYear = (params['year'] && params['year'].indexOf("range")==0)?params['year'].split("range")[1].split(":")[0]:null;
this.endYear = (params['year'] && params['year'].indexOf("range")==0)?params['year'].split("range")[1].split(":")[1]:null;
let invalidYears = false;
if(this.startYear && (!this.endYear || !Dates.isValidYear(this.endYear, Dates.currentYear - 20, Dates.currentYear))){
this.endYear = Dates.currentYear;
invalidYears = true;
this.periodFilter.selectedFromValue = (params['year'] && params['year'].indexOf("range")==0)?params['year'].split("range")[1].split(":")[0]:"";
this.periodFilter.selectedToValue = (params['year'] && params['year'].indexOf("range")==0)?params['year'].split("range")[1].split(":")[1]:"";
this.validateYearRange(false);
if (this.stakeholder) {
this.setIndicators();
}
if((!this.startYear || !Dates.isValidYear(this.startYear, Dates.currentYear - 20, Dates.currentYear)) && this.endYear){
this.startYear = Dates.currentYear - 20;
invalidYears = true;
}
if(parseInt(this.startYear, 10) > parseInt(this.endYear, 10)){
this.startYear = this.endYear;
invalidYears = true;
}
if(invalidYears){
this.router.navigate(
[],
{
relativeTo: this.route,
queryParams: { year: 'range'+this.startYear+":"+this.endYear },
queryParamsHandling: 'merge'
});
}
});
if (!this.stakeholder || this.stakeholder.alias !== params['stakeholder']) {
this.status = this.errorCodes.LOADING;
@ -161,23 +145,47 @@ export class MonitorComponent implements OnInit, OnDestroy {
}));
});
}
private validateYearRange(navigateTo:boolean=false){
let validYears = true;
if(this.periodFilter.selectedToValue && (this.periodFilter.selectedToValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedToValue, Dates.currentYear - 20, Dates.currentYear))){
this.periodFilter.selectedToValue = Dates.currentYear+"";
validYears = false;
}
if( this.periodFilter.selectedFromValue && (this.periodFilter.selectedFromValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedFromValue, Dates.currentYear - 20, Dates.currentYear))){
this.periodFilter.selectedFromValue = Dates.currentYear - 20+"";
validYears = false;
}
if(this.periodFilter.selectedFromValue && this.periodFilter.selectedFromValue.length && this.periodFilter.selectedToValue && this.periodFilter.selectedToValue.length > 0 && parseInt(this.periodFilter.selectedFromValue, 10) > parseInt(this.periodFilter.selectedToValue, 10)){
this.periodFilter.selectedFromValue = this.periodFilter.selectedToValue;
validYears = false;
}
if(!validYears || navigateTo){
this.router.navigate(
[],
{
relativeTo: this.route,
queryParams: { year: 'range'+(this.periodFilter.selectedFromValue?this.periodFilter.selectedFromValue:'')+":"+(this.periodFilter.selectedToValue?this.periodFilter.selectedToValue:"") },
queryParamsHandling: 'merge'
});
}
}
public get open() {
return this.layoutService.open;
}
private getPageContents() {
this.helper.getPageHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
this.pageContents = contents;
})
}
private getDivContents() {
this.helper.getDivHelpContents(this.properties, 'monitor', this._router.url).subscribe(contents => {
this.divContents = contents;
})
}
private setView(params: Params) {
if (params['topic']) {
this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && this.isPublicOrIsMember(topic.isPublic) && topic.isActive);
@ -240,23 +248,27 @@ export class MonitorComponent implements OnInit, OnDestroy {
}
filter(){
// this.router.navigate([this.searchUtils.baseUrl], {queryParams: this.routerHelper.createQueryParams(this.parameterNames, this.parameterValues)});
this.router.navigate(
[],
{
relativeTo: this.route,
queryParams: { year: 'range'+this.startYear+":"+this.endYear },
queryParamsHandling: 'merge'
});
this.setIndicators();
this.validateYearRange(true);
}
clearPeriodFilter(){
if(this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue){
this.periodFilter.selectedFromValue = "";
this.periodFilter.selectedToValue = "";
this.filter();
}
}
private setIndicators() {
this.periodFilter.selectedFromAndToValues = (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue?((this.periodFilter.selectedFromValue && !this.periodFilter.selectedToValue?"From ":"")+(!this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue?"Until ":"")+ (this.periodFilter.selectedFromValue?this.periodFilter.selectedFromValue:"") +
(this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue?" - ":"")+ (this.periodFilter.selectedToValue?this.periodFilter.selectedToValue:"")):"");
this.filterApplied = !!(this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue);
//clear numbers when filters change
this.numberResults.clear();
let urls: Map<string, [number, number][]> = new Map<string, [number, number][]>();
this.activeSubCategory.numbers.forEach((section, i) => {
section.indicators.forEach((number, j) => {
if (number.isActive && this.isPublicOrIsMember(number.isPublic)) {
let url =this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0],this.fundingL0, this.startYear, this.endYear);
let url =this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0],this.fundingL0, this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue);
const pair = JSON.stringify([number.indicatorPaths[0].source, url]);
const indexes = urls.get(pair) ? urls.get(pair) : [];
indexes.push([i, j]);
@ -290,32 +302,32 @@ export class MonitorComponent implements OnInit, OnDestroy {
this.cdr.detectChanges();
}
}
public getUrlByStakeHolder(indicatorPath: IndicatorPath) {
return this.sanitizer.bypassSecurityTrustResourceUrl(
this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath, this.fundingL0, this.startYear, this.endYear)));
this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath, this.fundingL0, this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue)));
}
public setActiveChart(i: number, j: number, type: string) {
let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0];
activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart);
this.chartsActiveType.set(i + '-' + j, activeChart);
}
private navigateToError() {
this._router.navigate(['/error'], {queryParams: {'page': this._router.url}});
}
public navigateTo(stakeholder: string, topic: string, category: string = null, subcategory: string = null) {
let url = stakeholder + '/' + topic + ((category) ? ('/'
+ category) : '') + ((subcategory) ? ('/' + subcategory) : '');
return this._router.navigate([url]);
}
public quote(param: string): string {
return StringUtils.quote(param);
}
public ngOnDestroy() {
if (this.piwiksub) {
this.piwiksub.unsubscribe();
@ -325,7 +337,7 @@ export class MonitorComponent implements OnInit, OnDestroy {
isAdmin(){
return this.user && (Session.isPortalAdministrator(this.user) || Session.isCommunityCurator(this.user) || Session.isMonitorCurator(this.user));
}
public isPublicOrIsMember(isPublic: boolean): boolean {
if (isPublic) {
return true;

View File

@ -19,18 +19,16 @@ import {InputModule} from "../openaireLibrary/dashboard/sharedComponents/input/i
import {UserMiniModule} from "../openaireLibrary/login/userMiniModule.module";
import {ClickModule} from "../openaireLibrary/utils/click/click.module";
import {BottomModule} from "../openaireLibrary/sharedComponents/bottom.module";
import { NouisliderModule } from 'ng2-nouislider';
import { DoubleSliderComponent } from './double-slider/double-slider.component';
import {RangeFilterModule} from "../openaireLibrary/utils/rangeFilter/rangeFilter.module";
@NgModule({
imports: [
CommonModule, FormsModule, RouterModule, ErrorMessagesModule,
HelperModule, Schema2jsonldModule, SEOServiceModule, MonitorRoutingModule, SideBarModule, InputModule,
UserMiniModule, ClickModule, BottomModule, NouisliderModule
UserMiniModule, ClickModule, BottomModule, RangeFilterModule
],
declarations: [
MonitorComponent,
DoubleSliderComponent
MonitorComponent
],
providers: [
FreeGuard, PreviousRouteRecorder,

View File

@ -607,7 +607,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
});
} else {
this.indicator = new Indicator('', '', 'chart', 'small', true, true, []);
this.indicator = new Indicator('', '', 'chart', 'medium', true, true, []);
this.chartIndicatorFb = this.fb.group({
_id: this.fb.control(this.indicator._id),
name: this.fb.control(this.indicator.name),

View File

@ -16,7 +16,7 @@ export class AdminDashboardGuard implements CanActivate, CanLoad {
}
check(path: string): Observable<boolean> | boolean {
/* //Argiro testing
/* //Argiro testing
if(properties.environment == "development"){
return true;
}*/

View File

@ -297,6 +297,7 @@ export class IndicatorUtils {
return indicatorPath.url + encodeURIComponent(replacedUrl);
}
public getFullUrlWithFilters(stakeholder:Stakeholder, indicatorPath: IndicatorPath, fundingL0: string = null, startYear: string = null, endYear: string = null, isNumber:boolean=false): string {
indicatorPath.filteredApplied = false;
let replacedUrl = indicatorPath.chartObject?indicatorPath.chartObject:indicatorPath.url;
if (indicatorPath.parameters) {
Object.keys(indicatorPath.parameters).forEach(key => {
@ -362,36 +363,61 @@ export class IndicatorUtils {
for (let queries of this.getQueryObjectName(newJsonObject)?newJsonObject[this.getDescriptionObjectName(newJsonObject)][this.getQueryObjectName(newJsonObject)]:newJsonObject[this.getDescriptionObjectName(newJsonObject)]) {
if(queries["query"]["name"] && !queries["query"]["select"]){
/*
//Uncomment when the named queries filters are defined
//monitor.stakeholderType.name.id.type.fl0
if(queries["query"]["name"].indexOf("monitor.")==-1){
if(queries["query"]["name"].indexOf("monitor.")==-1 ){
continue;
}
filterApplied = true;
let filterPosition = queries["query"]["name"].split(".").indexOf(filterType=="fundingL0"?'fl0':filterType);
if(filterType == "fundingL0"){
filterApplied = true;
if(filterPosition != -1){
queries["query"]["parameters"][filterPosition-3]=filterValue;
}else{
queries["query"]["name"]=queries["query"]["name"]+".fl0";
queries["query"]["parameters"].push(filterValue);
if(filterType == 'fundingL0') {
let filterPosition = queries["query"]["name"].split(".").indexOf(filterType == "fundingL0" ? 'fl0' : filterType);
if (filterType == "fundingL0") {
filterApplied = true;
if (filterPosition != -1) {
queries["query"]["parameters"][filterPosition - 3] = filterValue;
} else {
queries["query"]["name"] = queries["query"]["name"] + ".fl0";
queries["query"]["parameters"].push(filterValue);
}
} else {
filterApplied = true;
//start_year end_year
if (filterPosition != -1) {
queries["query"]["parameters"][filterPosition - 3] = filterValue;
} else {
queries["query"]["name"] = queries["query"]["name"] + ".start_year.end_year";
filterPosition = queries["query"]["name"].split(".").indexOf(filterType);
queries["query"]["parameters"].push("0");
queries["query"]["parameters"].push("9999");
queries["query"]["parameters"][filterPosition - 3] = filterValue
}
}
}else {
filterApplied = true;
//start_year end_year
if(filterPosition != -1){
queries["query"]["parameters"][filterPosition-3]=filterValue;
}else{
queries["query"]["name"]=queries["query"]["name"]+".start_year.end_year";
filterPosition = queries["query"]["name"].split(".").indexOf(filterType);
queries["query"]["parameters"].push("0");
queries["query"]["parameters"].push("9999");
queries["query"]["parameters"][filterPosition-3]=filterValue
}else{
let paramFields = queries["query"]["name"].split(".").slice(3);
// console.debug("Field Params length:" + paramFields.length)
// console.debug(paramFields)
// console.debug("Parameters length:" + queries["query"]["parameters"].length)
console.debug("Parameters length:" + queries["query"]["parameters"].length)
if((paramFields.length + 2) == queries["query"]["parameters"].length || (paramFields.length*2 + 4) == queries["query"]["parameters"].length){
console.debug("update param position 0,1" )
if(filterType == "start_year"){
queries["query"]["parameters"][0]=filterValue;
}else if(filterType == "end_year"){
queries["query"]["parameters"][1]=filterValue;
}
}
if((paramFields.length*2 + 4) == queries["query"]["parameters"].length){
console.debug("update param position "+(paramFields.length + 2) + "," +(paramFields.length + 3) )
if(filterType == "start_year"){
queries["query"]["parameters"][paramFields.length + 2]=filterValue;
}else if(filterType == "end_year"){
queries["query"]["parameters"][paramFields.length + 3]=filterValue;
}
}
}
console.debug(queries["query"])*/
// console.debug(queries["query"])
// it is a name query
continue;
}
@ -666,16 +692,20 @@ export class IndicatorUtils {
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName.toLowerCase();
}else if(name.split('.')[0] == "monitor" && parameters.length > 0 && name.split('.')[1] == stakeholder.type) {
// new parameterized queries
//monitor.{{type}}.{{queryname}}.{{param1 - id }}.{{param2 result-type}}.{{fl0}}
if( name.split('.').length > 3 && name.split('.')[3] == "id") {
parameters[0] = ChartHelper.prefix + "index_id" + ChartHelper.suffix;
indicatorPath.parameters["index_id"] = stakeholder.index_id;
}else if( name.split('.').length > 3 && name.split('.')[3] == "shortname") {
parameters[0] = ChartHelper.prefix + "index_shortName" + ChartHelper.suffix;
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName.toLowerCase();
}else if( name.split('.').length > 3 && name.split('.')[3] == "name") {
parameters[0] = ChartHelper.prefix + "index_name" + ChartHelper.suffix;
indicatorPath.parameters["index_name"] = stakeholder.index_name;
//monitor.{{type}}.{{queryname}}.{{param1 - id }}.{{param2 result-type}}.{{fl0}} --> params [start year, end year, id, result type, fl0]
let index = (name.split('.').slice(3).length +2 == parameters.length)?[2]:((name.split('.').slice(3).length * 2 + 4 == parameters.length)?[2,name.split('.').slice(3).length+4]:[0]);
for(let i of index) {
if (name.split('.').length > 3 && name.split('.')[3] == "id") {
parameters[i] = ChartHelper.prefix + "index_id" + ChartHelper.suffix;
indicatorPath.parameters["index_id"] = stakeholder.index_id;
} else if (name.split('.').length > 3 && name.split('.')[3] == "shortname") {
parameters[i] = ChartHelper.prefix + "index_shortName" + ChartHelper.suffix;
indicatorPath.parameters["index_shortName"] = stakeholder.index_shortName.toLowerCase();
} else if (name.split('.').length > 3 && name.split('.')[3] == "name") {
parameters[i] = ChartHelper.prefix + "index_name" + ChartHelper.suffix;
indicatorPath.parameters["index_name"] = stakeholder.index_name;
}
}
}
}

View File

@ -136,3 +136,47 @@ bottom a:not(.license), bottom a > :not(svg) {
text-decoration: underline;
}
#style_switcher{
width:30% !important;
}
#style_switcher:not(.switcher_active){
margin-right: -30% !important;
}
.filter{
background: var(--portal-main-color);
color: white;
padding: 8px;
border-radius: 25px;
}
.filter, .filter .material-icons{
color: white;
}
.ng5-slider .ng5-slider-pointer, .ng5-slider .ng5-slider-selection {
background-color: var(--portal-main-color) !important;
}
.ng5-slider .ng5-slider-pointer.ng5-slider-active::after {
background-color:#55637d !important;
}
#style_switcher_toggle{
top:200px !important;
}
#style_switcher{
top: 0 !important;
bottom: 0 !important;
/*padding: 50px !important;*/
z-index: 1105 !important;
}
.uk-subnav.recentyears > :first-child {
padding-left: 0 !important;
}
.uk-subnav.uk-subnav-divider.recentyears {
padding-left: 0 !important;
}