diff --git a/explore/CHANGELOG.md b/explore/CHANGELOG.md index 84c6afde..79df2a0f 100644 --- a/explore/CHANGELOG.md +++ b/explore/CHANGELOG.md @@ -14,6 +14,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - *Fixed (for any bug fixes)* - *Security (in case of vulnerabilities)* +## [production-release-july-2024] - 2024/07/11 +### Changed +* Parse instances new info (to delete deletedbyinference records) +* Detailed page: Remove subjects by vocabulary section and show all subjects under keywords + +### Fixed +* Updated vocabulary for Fields of Science level 4 +* Linking: Do not add unidentified code in queries - missing irish funders + +### Added +* Funders page: More information in cards (i.e. country, registered) +* Funders page: New sorting options by research products & projects +* Links between Research products and Data sources +* Design of compact search results + ## [production-release-june-2024] - 2024/06/04 ### Changed * Filter out unidentified projects from the search page and related tabs in detailed pages diff --git a/explore/package.json b/explore/package.json index 6b878b15..4c4c7078 100644 --- a/explore/package.json +++ b/explore/package.json @@ -39,6 +39,7 @@ "clipboard": "^1.5.16", "core-js": "^2.5.4", "express": "^4.15.2", + "flag-icons": "^7.2.1", "jquery": "^3.4.1", "ng-recaptcha": "^12.0.2", "prom-client": "^11.3.0", diff --git a/explore/src/app/contact/contact.component.ts b/explore/src/app/contact/contact.component.ts index d421ce75..116b35a9 100644 --- a/explore/src/app/contact/contact.component.ts +++ b/explore/src/app/contact/contact.component.ts @@ -58,7 +58,6 @@ export class ContactComponent implements OnInit { ngOnInit() { this._title.setTitle('OpenAIRE - Explore | Contact Us'); - this.properties = properties; this.email = {body: '', subject: '', recipients: []}; this.subscriptions.push( this._piwikService.trackView(this.properties, this.pageTitle).subscribe()); this.url = this.properties.domain + this._router.url; diff --git a/explore/src/app/funders/funders.component.html b/explore/src/app/funders/funders.component.html index d45e11c3..0ee945d6 100644 --- a/explore/src/app/funders/funders.component.html +++ b/explore/src/app/funders/funders.component.html @@ -126,17 +126,18 @@
- - + +
+
Registered
-
--> +
@@ -156,11 +157,11 @@ {{funder.name}}
- +
@@ -237,6 +238,7 @@
+
{{funder.name}} @@ -310,19 +312,19 @@
- +
diff --git a/explore/src/app/funders/funders.component.less b/explore/src/app/funders/funders.component.less index 7da80274..3c28bf03 100644 --- a/explore/src/app/funders/funders.component.less +++ b/explore/src/app/funders/funders.component.less @@ -1,5 +1,5 @@ @import (reference) "~src/assets/openaire-theme/less/color.less"; - +@import "flag-icons/css/flag-icons.min.css"; .custom-coins-dot:after { content: ""; @@ -21,22 +21,22 @@ margin-left: 10px; } -.custom-view-button { - padding: 4px; - background: @light-color; - border: 1px solid @disable-color; - border-radius: 4px; - icon { - color: @disable-color; - } - - &.active { - background: transparent linear-gradient(315deg, @primary-light-color 0%, @primary-dark-color 100%) 0% 0% no-repeat padding-box; - icon { - color: @light-color; - } - } -} +//.custom-view-button { +// padding: 4px; +// background: @light-color; +// border: 1px solid @disable-color; +// border-radius: 4px; +// icon { +// color: @disable-color; +// } +// +// &.active { +// background: transparent linear-gradient(315deg, @primary-light-color 0%, @primary-dark-color 100%) 0% 0% no-repeat padding-box; +// icon { +// color: @light-color; +// } +// } +//} // .uk-card { // &.funder-grid { diff --git a/explore/src/app/funders/funders.component.ts b/explore/src/app/funders/funders.component.ts index 29a587cd..2e0834a8 100644 --- a/explore/src/app/funders/funders.component.ts +++ b/explore/src/app/funders/funders.component.ts @@ -18,6 +18,7 @@ import {LayoutService} from '../openaireLibrary/dashboard/sharedComponents/sideb import {FormBuilder, FormControl} from '@angular/forms'; import {debounceTime, distinctUntilChanged} from 'rxjs/operators'; import {GroupedRequestsService} from "../openaireLibrary/services/groupedRequests.service"; +import {OpenaireEntities} from "../openaireLibrary/utils/properties/searchFields"; @Component({ selector: 'funders', @@ -31,6 +32,7 @@ export class FundersComponent implements OnInit { pageTitle: string = "OpenAIRE - Explore | Funders"; pageDescription: string = "Funders | Be an integral part of the open R&I ecosystem"; properties: EnvProperties = properties; + public openaireEntities = OpenaireEntities; breadcrumbs: Breadcrumb[] = [{name: 'home', route: '/'}, {name: 'funders'}]; showLoading: boolean = true; isMobile: boolean = false; @@ -59,22 +61,25 @@ export class FundersComponent implements OnInit { "projects": number, "monitorDashboard": string, "monitorDashboardStatus": string, - "logoUrl": string + "logoUrl": string, + "websiteUrl": string, + "country": string, + "registered": boolean }>(); - staticLogos: Set = new Set([ - "arc_________::ARC||Australian Research Council (ARC)||ARC", - "asap________::ASAP||Aligning Science Across Parkinson's||ASAP", - "cihr________::CIHR||Canadian Institutes of Health Research||CIHR", - "euenvagency_::EEA||European Environment Agency||EEA", - "inca________::INCA||Institut National du Cancer||INCa", - "nhmrc_______::NHMRC||National Health and Medical Research Council (NHMRC)||NHMRC", - "nih_________::NIH||National Institutes of Health||NIH", - "nserc_______::NSERC||Natural Sciences and Engineering Research Council of Canada||NSERC", - "nsf_________::NSF||National Science Foundation||NSF", - "sshrc_______::SSHRC||Social Sciences and Humanities Research Council||SSHRC", - "taraexp_____::tara||Tara Expeditions Foundation||TARA", - "ukri________::UKRI||UK Research and Innovation||UKRI", - "wt__________::WT||Wellcome Trust||WT" + staticLogos: Map = new Map([ + ["arc_________::ARC", "ARC"], + ["asap________::ASAP", "ASAP"], + ["cihr________::CIHR", "CIHR"], + ["euenvagency_::EEA", "EEA"], + ["inca________::INCA", "INCa"], + ["nhmrc_______::NHMRC", "NHMRC"], + ["nih_________::NIH", "NIH"], + ["nserc_______::NSERC", "NSERC"], + ["nsf_________::NSF", "NSF"], + ["sshrc_______::SSHRC", "SSHRC"], + ["taraexp_____::tara", "TARA"], + ["ukri________::UKRI", "UKRI"], + ["wt__________::WT", "WT"] ]); constructor(private router: Router, @@ -93,7 +98,6 @@ export class FundersComponent implements OnInit { ngOnInit() { this.layoutService.setRootClass('funders'); this.title.setTitle('OpenAIRE - Explore | Funders'); - this.properties = properties; this.subscriptions.push( this.piwikService.trackView(this.properties, this.pageTitle).subscribe()); this.url = this.properties.domain + this.router.url; this.seoService.createLinkForCanonicalURL(this.url); @@ -109,9 +113,12 @@ export class FundersComponent implements OnInit { {value: 'dashboard', label: 'Funders with dashboard'} ]; this.sortOptions = [ - {value: 'alphAsc', label: 'Alphabetically Asc. (A-Z)'}, - {value: 'alphDsc', label: 'Alphabetically Dsc. (Z-A)'}, - {value: 'oaDsc', label: '"Open Access %" Dsc.'} + {value: 'alphAsc', label: 'Alphabetically asc. (A-Z)'}, + {value: 'alphDsc', label: 'Alphabetically desc. (Z-A)'}, + {value: 'oaDsc', label: 'Open Access % desc.'}, + {value: 'countryAsc', label: 'Country desc. (A-Z)'}, + {value: 'researcProductsDsc', label: this.openaireEntities.RESULTS+' desc.'}, + {value: 'projectsDsc', label: this.openaireEntities.PROJECTS+' desc.'} ]; this.getFunders(); this.keywordControl = this.fb.control(''); @@ -160,7 +167,10 @@ export class FundersComponent implements OnInit { "projects": +queriedFunder.projects, "monitorDashboard": '', "monitorDashboardStatus": '', - "logoUrl": '' + "logoUrl": '', + "websiteUrl": '', + "country": queriedFunder.country, + "registered": queriedFunder.registered }; if((!funder.researchProducts || funder.researchProducts == 0) && (!funder.projects || funder.projects == 0)) { @@ -172,7 +182,10 @@ export class FundersComponent implements OnInit { funder.alias = stakeholder.alias; funder.monitorDashboard = stakeholder.alias; funder.monitorDashboardStatus = stakeholder.visibility; - funder.logoUrl = (stakeholder.isUpload ? properties.utilsService + "/download/" : "")+ (stakeholder.logoUrl); + if(stakeholder.logoUrl) { + funder.logoUrl = (stakeholder.isUpload ? properties.utilsService + "/download/" : "") + (stakeholder.logoUrl); + } + funder.websiteUrl = stakeholder.websiteUrl; } if(funder.openAccessResearchProducts && funder.researchProducts) { @@ -180,9 +193,7 @@ export class FundersComponent implements OnInit { } if(!funder.logoUrl && this.staticLogos.has(funder.id)) { - let split = funder.id.split("||"); - let shortname = (split && split.length==3) ? funder.id.split("||")[2] : funder.id; - funder.logoUrl = "assets/explore-assets/funders/logos/"+shortname+".png"; + funder.logoUrl = "assets/explore-assets/funders/logos/"+this.staticLogos.get(funder.id)+".png"; } this.fundersMap.set(queriedFunder.id, funder); @@ -335,6 +346,25 @@ export class FundersComponent implements OnInit { case 'oaDsc': this.funders = this.funders.sort((a, b) => b['openAccessPercentage'] - a['openAccessPercentage']); break; + case 'countryAsc': + this.funders = this.funders.sort((a, b) => { + if(a['country'] && b['country']) { + return a['country'].localeCompare(b['country']) + } else if(!a['country'] && !b['country']) { + return 0; + } else if(!a['country']) { + return 1; + } else { + return -1; + } + }); + break; + case "researcProductsDsc": + this.funders = this.funders.sort((a, b) => b['researchProducts'] - a['researchProducts']); + break; + case "projectsDsc": + this.funders = this.funders.sort((a, b) => b['projects'] - a['projects']); + break; } this.filtering(); } diff --git a/services/utils-service/beta-properties.file b/services/utils-service/beta-properties.file index e66a9f36..4fd7d30a 100644 --- a/services/utils-service/beta-properties.file +++ b/services/utils-service/beta-properties.file @@ -1,6 +1,7 @@ userInfoUrl = https://beta.services.openaire.eu/login-service/userInfo searchServiceAPIUrl = https://beta.services.openaire.eu/search/v2/api/ monitorAPIUrl = https://beta.services.openaire.eu/uoa-monitor-service/ +fundersServiceAPIUrl = https://beta.services.openaire.eu/openaire/funders/ ssl = true localPath = false # photo size in KB diff --git a/services/utils-service/production-properties.file b/services/utils-service/production-properties.file index 539e3cd1..f0110b3e 100644 --- a/services/utils-service/production-properties.file +++ b/services/utils-service/production-properties.file @@ -1,6 +1,7 @@ userInfoUrl = https://services.openaire.eu/login-service/userInfo searchServiceAPIUrl = https://services.openaire.eu/search/v2/api/ monitorAPIUrl = https://services.openaire.eu/uoa-monitor-service/ +fundersServiceAPIUrl = https://services.openaire.eu/openaire/funders/ ssl = true localPath = false # photo size in KB diff --git a/services/utils-service/properties.file b/services/utils-service/properties.file index 8ab7aa3b..031495a9 100644 --- a/services/utils-service/properties.file +++ b/services/utils-service/properties.file @@ -1,6 +1,7 @@ userInfoUrl = http://mpagasas.di.uoa.gr:19080/login-service/userInfo searchServiceAPIUrl = https://beta.services.openaire.eu/search/v2/api/ monitorAPIUrl = http://duffy.di.uoa.gr:19380/uoa-monitor-service/ +fundersServiceAPIUrl = https://beta.services.openaire.eu/openaire/funders/ ssl = false localPath = true # photo size in KB diff --git a/services/utils-service/uploadService.js b/services/utils-service/uploadService.js index 5d6202d5..01919451 100644 --- a/services/utils-service/uploadService.js +++ b/services/utils-service/uploadService.js @@ -15,6 +15,7 @@ if (properties.get('ssl')) { } var searchServiceAPIUrl = properties.get('searchServiceAPIUrl'); var monitorServiceAPIUrl = properties.get('monitorAPIUrl'); +var fundersServiceAPIUrl = properties.get('fundersServiceAPIUrl'); var auth = properties.get('userInfoUrl'); /** @deprecated*/ var authDeprecated = auth.includes("accessToken"); @@ -223,7 +224,7 @@ app.get('/explore/funders', async function (req, res) { searchServiceAPIUrl + 'resources2/?format=json&type=results&fq=relfunder=*&refine=true&fields=relfunder&sf=relfunder&page=0&size=0&fq=resultbestaccessright%20exact%20%22Open%20Access%22', searchServiceAPIUrl + 'resources2/?format=json&type=projects&fq=funder=*&fq=projectcode<>"unidentified"&refine=true&fields=funder&sf=funder&page=0&size=0', monitorServiceAPIUrl + 'stakeholder?type=funder', - + fundersServiceAPIUrl ] const dataPromises = requests.map((url) => axios.get( url)); const dataResponses = await Promise.all(dataPromises); @@ -233,37 +234,67 @@ app.get('/explore/funders', async function (req, res) { let resultsFunders = dataResponses[0].data.refineResults.relfunder; resultsFunders.forEach(queriedFunder => { - if (!fundersMap.has(queriedFunder.id)) { - fundersMap.set(queriedFunder.id,{name: queriedFunder.name.split("||")[0], id: queriedFunder.id, results:queriedFunder.count, openResults: null, projects:null, stakeholder:null}); + let id = queriedFunder.id.split("||")[0]; + if (!fundersMap.has(id)) { + fundersMap.set(id,{name: queriedFunder.name.split("||")[0], id: id, results:queriedFunder.count, openResults: null, projects:null, stakeholder:null}); } }); let openResultsFunders = dataResponses[1].data.refineResults.relfunder; openResultsFunders.forEach(queriedFunder => { - if (!fundersMap.has(queriedFunder.id)) { - fundersMap.set(queriedFunder.id,{name: queriedFunder.name.split("||")[0], id: queriedFunder.id, results:null, openResults: queriedFunder.count, projects:null, stakeholder:null}); + let id = queriedFunder.id.split("||")[0]; + if (!fundersMap.has(id)) { + fundersMap.set(id,{name: queriedFunder.name.split("||")[0], id: id, results:null, openResults: queriedFunder.count, projects:null, stakeholder:null}); }else{ - fundersMap.get(queriedFunder.id).openResults = queriedFunder.count; + fundersMap.get(id).openResults = queriedFunder.count; } }); let projectFunders = dataResponses[2].data.refineResults.funder; projectFunders.forEach(queriedFunder => { - if (!fundersMap.has(queriedFunder.id) ) { - fundersMap.set(queriedFunder.id,{name: queriedFunder.name.split("||")[0], id: queriedFunder.id, results:null, openResults: null, projects:queriedFunder.count, stakeholder:null}); + let id = queriedFunder.id.split("||")[0]; + if (!fundersMap.has(id) ) { + fundersMap.set(id,{name: queriedFunder.name.split("||")[0], id: id, results:null, openResults: null, projects:queriedFunder.count, stakeholder:null}); }else{ - fundersMap.get(queriedFunder.id).projects = queriedFunder.count; + fundersMap.get(id).projects = queriedFunder.count; } }); let stakeholders = dataResponses[3].data; stakeholders.forEach(stakeholder => { - let id = stakeholder.index_id + "||" + stakeholder.index_name + "||" + stakeholder.index_shortName; - // console.log(id); + let id = stakeholder.index_id;// + "||" + stakeholder.index_name + "||" + stakeholder.index_shortName; if (fundersMap.has(id)) { - let ministakeholder = {id:id, name:stakeholder.name, alias: stakeholder.alias, visibility: stakeholder.visibility, - logoUrl:stakeholder.logoUrl, isUpload: stakeholder.isUpload} - fundersMap.get(id).stakeholder = ministakeholder; + let ministakeholder = {id:id, name:stakeholder.name, alias: stakeholder.alias, visibility: stakeholder.visibility, + logoUrl:stakeholder.logoUrl, isUpload: stakeholder.isUpload, websiteUrl: null} + fundersMap.get(id).stakeholder = ministakeholder; } }); + let funders = dataResponses[4].data; + funders.forEach(funder => { + if (fundersMap.has(funder.id)) { + let storedFunder = fundersMap.get(funder.id); + if(funder.legalName) { + storedFunder.name = funder.legalName; + } + storedFunder.country = funder.country; + storedFunder.registered = funder.registered; + let storedStakeholder = storedFunder.stakeholder; + let ministakeholder = { + id:funder.id, name:storedStakeholder?.name, alias: storedStakeholder?.alias ? storedStakeholder.alias : funder.legalShortName, + websiteUrl: funder.websiteUrl, logoUrl: storedStakeholder?.logoUrl ? storedStakeholder.logoUrl : funder.logoUrl, + visibility: storedStakeholder?.visibility, isUpload: storedStakeholder?.isUpload + }; + storedFunder.stakeholder = ministakeholder; + // } else { + // console.log(funder.id); + } + }); + + // console.log("") + // for(let f of fundersMap.keys()) { + // if(!fundersMap.get(f).stakeholder || (!fundersMap.get(f).stakeholder.websiteUrl && !fundersMap.get(f).country && !fundersMap.get(f).registered)) { + // console.log(f); + // } + // } + // Combine the data // Send the aggregated data as the response