Compare commits

..

13 Commits

Author SHA1 Message Date
Konstantina Galouni fe32746cef [recommendations-and-nl-search-client-only | DONE | CHANGED]: Removed ssr - Deleted files server.ts, src/app/app.server.module.ts, src/main.server.ts, src/tsconfig.server.json and removed server references from files angular.json, package.json. 2024-09-09 14:24:20 +03:00
Konstantina Galouni 5c8c31ae45 Updating openaireLibrary & common-assets 2024-09-09 13:21:47 +03:00
Konstantina Galouni b48796dc47 Revert "Updating openaireLibrary & common-assets"
This reverts commit 0b75c0b3dd.
2024-09-09 13:20:36 +03:00
Konstantina Galouni 0b75c0b3dd Updating openaireLibrary & common-assets 2024-09-09 13:18:50 +03:00
Konstantina Galouni f32dfc0ac6 [recommendations-and-nl-search | DONE | FIXED]: Fixed when and how error messages are displayed on NL Search page.
1. natural-language-search.component.html: Added check if results.data also exist.
2. natural-language-search.component.ts: In method "search()" initialize also results to null and added check if response has at least 1 row of results.
3. libOrp.module.ts: Changed order of imports to be loaded and initialized correctly - first OrpRoutingModule which is more specific and then ResultLandingModule.
2024-09-09 13:15:10 +03:00
Alex Martzios 1d3ab8f645 [recommendations-and-nl-search | DONE | CHANGED] category-to-item rec: add user id on the API call - /recommend and /update, stack sidebar on mobile view, remove communities search bar when there are less than 5 communities 2024-07-02 15:18:14 +03:00
Alex Martzios deaa8a33a0 [recommendations-and-nl-search | DONE | FIXED] nl-search: html/css adjustments 2024-06-26 12:42:12 +03:00
Alex Martzios 3ddf7ac4fd [recommendations-and-nl-search | DONE | ADDED] category-to-item recommendations: add error handling 2024-06-26 11:19:13 +03:00
Alex Martzios 8ea9cd5dbc [recommendations-and-nl-search | DONE | CHANGED] move DareLAB APIs to environment properties 2024-06-20 14:14:42 +03:00
Alex Martzios fe3a439ff0 [recommendations-and-nl-search | DONE | ADDED] home.component > author-to-item recommendations: add slider for results 2024-06-20 12:32:11 +03:00
Alex Martzios 667c9b1c5f [recommendations-and-nl-search | DONE | CHANGED] home.component: remove old and unused code 2024-06-20 11:00:08 +03:00
Alex Martzios d4a092ed7c [recommendations-and-nl-search | WIP] re-enable login funcionality, finish NL search, progress on category-to-item, author-to-item recs 2024-06-14 14:12:24 +03:00
Alex Martzios 582285c8b2 [recommendations-and-nl-search | WIP] create new page for category-to-item recs, create section in home page for author-to-item, add assets, add new dummy menu item 2024-05-16 10:18:27 +03:00
34 changed files with 807 additions and 429 deletions

View File

@ -212,77 +212,6 @@
"src/assets"
]
}
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/eosc/server",
"main": "server.ts",
"tsConfig": "src/tsconfig.server.json",
"sourceMap": true,
"optimization": false,
"buildOptimizer": false
},
"configurations": {
"development": {
"outputHashing": "media",
"sourceMap": false,
"optimization": true,
"vendorChunk": true,
"buildOptimizer": true
},
"beta": {
"outputHashing": "media",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.beta.ts"
}
],
"sourceMap": false,
"optimization": true,
"buildOptimizer": true
},
"production": {
"outputHashing": "media",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"sourceMap": false,
"optimization": true,
"buildOptimizer": true
}
},
"defaultConfiguration": ""
},
"serve-ssr": {
"builder": "@nguniversal/builders:ssr-dev-server",
"options": {
"browserTarget": "eosc:build",
"serverTarget": "eosc:server"
},
"configurations": {
"production": {
"browserTarget": "eosc:build:production",
"serverTarget": "eosc:server:production"
}
}
},
"prerender": {
"builder": "@nguniversal/builders:prerender",
"options": {
"browserTarget": "eosc:build:production",
"serverTarget": "eosc:server:production",
"routes": [
"/"
]
},
"configurations": {
"production": {}
}
}
}
},

View File

@ -11,12 +11,6 @@
"webpack-bundle-analyzer": "ng build --stats-json && webpack-bundle-analyzer dist/eosc/browser/stats-es2015.json --host 0.0.0.0",
"test": "ng test",
"e2e": "ng e2e",
"dev:ssr": "ng run eosc:serve-ssr",
"serve:ssr": "node dist/eosc/server/main.js",
"build:ssr-dev": "npm run build-dev && ng run eosc:server:development",
"build:ssr-beta": "npm run build-beta && ng run eosc:server:beta",
"build:ssr-prod": "npm run build-prod && ng run eosc:server:production",
"prerender": "ng run eosc:prerender",
"after-build-clean": "rm -rf dist/eosc/browser/assets/common-assets/.git/ src/app/openaireLibrary/.git node_modules .angular .git*"
},
"private": true,
@ -31,12 +25,9 @@
"@angular/material": "^16.1.7",
"@angular/platform-browser": "^16.1.8",
"@angular/platform-browser-dynamic": "^16.1.8",
"@angular/platform-server": "^16.1.8",
"@angular/router": "^16.1.8",
"@nguniversal/express-engine": "^16.1.1",
"clipboard": "^1.5.16",
"core-js": "^2.5.4",
"express": "^4.15.2",
"jquery": "^3.4.1",
"ng-recaptcha": "^12.0.2",
"prom-client": "^11.3.0",
@ -44,6 +35,7 @@
"ts-md5": "^1.2.0",
"tslib": "^2.0.0",
"uikit": "3.16.24",
"uuid": "^10.0.0",
"zone.js": "~0.13.1"
},
"devDependencies": {
@ -51,10 +43,7 @@
"@angular/cli": "^16.1.7",
"@angular/compiler-cli": "^16.1.8",
"@angular/language-service": "^16.1.8",
"@nguniversal/builders": "^16.1.1",
"@types/express": "^4.17.0",
"@types/compression": "^1.7.0",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^6.0.0",

110
server.ts
View File

@ -1,110 +0,0 @@
import 'zone.js/node';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import * as compression from 'compression';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';
import {Prometheus} from "./prometheus";
import {Counter} from "prom-client";
import {REQUEST, RESPONSE} from "./src/app/openaireLibrary/utils/tokens";
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
server.use(compression());
const distFolder = join(process.cwd(), 'dist/eosc/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
const prometheus: Prometheus = new Prometheus();
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
inlineCriticalCss: false
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
server.get('/metrics', (req, res) => {
res.set('Content-Type', prometheus.register.contentType);
res.end(prometheus.register.metrics());
});
// All regular routes use the Universal engine
server.get('*', (req, res) => {
let start = new Date();
let counter: Counter = prometheus.counters.get(req.path);
if(counter !== undefined) {
counter.inc(1, new Date());
res.render(indexHtml, {
req, providers: [
{
provide: APP_BASE_HREF,
useValue: req.baseUrl
},
{
provide: REQUEST, useValue: (req)
},
{
provide: RESPONSE, useValue: (res)
}
]
});
// event triggers when express is done sending response
res.on('finish', function() {
console.log(new Date().getTime() - start.getTime());
});
} else {
res.render(indexHtml, {
req, providers: [
{
provide: APP_BASE_HREF,
useValue: req.baseUrl
},
{
provide: REQUEST, useValue: (req)
},
{
provide: RESPONSE, useValue: (res)
}
]
});
}
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';

View File

@ -6,66 +6,44 @@ import {PageURLResolverComponent} from "./openaireLibrary/utils/pageURLResolver.
const routes: Routes = [
{path: '', loadChildren: () => import('./home/home.module').then(m => m.HomeModule)},
// Landing Pages
{path: 'search/result', loadChildren: () => import('./openaireLibrary/landingPages/result/resultLanding.module').then(m => m.ResultLandingModule), data: {hasQuickContact: false, hasMenuSearchBar: true, type: 'result', showHeader: true}},
{path: 'search/publication', loadChildren: () => import('./openaireLibrary/landingPages/result/resultLanding.module').then(m => m.ResultLandingModule), data: {hasQuickContact: false, hasMenuSearchBar: true, type: 'publication', showHeader: true}},
{path: 'search/dataset', loadChildren: () => import('./openaireLibrary/landingPages/result/resultLanding.module').then(m => m.ResultLandingModule), data: {hasQuickContact: false, hasMenuSearchBar: true, type: 'dataset', showHeader: true}},
{path: 'search/software', loadChildren: () => import('./openaireLibrary/landingPages/result/resultLanding.module').then(m => m.ResultLandingModule), data: {hasQuickContact: false, hasMenuSearchBar: true, type: 'software', showHeader: true}},
{path: 'search/other', loadChildren: () => import('./openaireLibrary/landingPages/result/resultLanding.module').then(m => m.ResultLandingModule), data: {hasQuickContact: false, hasMenuSearchBar: true, type: 'orp', showHeader: true}},
{path: 'search/project', loadChildren: () => import('./openaireLibrary/landingPages/project/project.module').then(m => m.ProjectModule), data: {hasQuickContact: false, hasMenuSearchBar: true, showHeader: true}},
{
path: 'search/result',
loadChildren: () => import('./landingPages/result/libResult.module').then(m => m.LibResultModule),
data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/publication',
loadChildren: () => import('./landingPages/publication/libPublication.module').then(m => m.LibPublicationModule),
data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/dataset',
loadChildren: () => import('./landingPages/dataset/libDataset.module').then(m => m.LibDatasetModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/software',
loadChildren: () => import('./landingPages/software/libSoftware.module').then(m => m.LibSoftwareModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/other',
loadChildren: () => import('./landingPages/orp/libOrp.module').then(m => m.LibOrpModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/project',
loadChildren: () => import('./landingPages/project/libProject.module').then(m => m.LibProjectModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/dataprovider',
loadChildren: () => import('./openaireLibrary/landingPages/dataProvider/dataProvider.module').then(m => m.DataProviderModule),
data: {hasQuickContact: false, hasMenuSearchBar: true, showHeader: true}
loadChildren: () => import('./landingPages/dataProvider/libDataProvider.module').then(m => m.LibDataProviderModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/service',
loadChildren: () => import('./openaireLibrary/landingPages/dataProvider/dataProvider.module').then(m => m.DataProviderModule),
data: {hasQuickContact: false, hasMenuSearchBar: true, showHeader: true, type: "service"}
loadChildren: () => import('./landingPages/service/libService.module').then(m => m.LibServiceModule), data: { showHeader: true, hasMenuSearchBar: true}
},
{
path: 'search/organization',
loadChildren: () => import('./openaireLibrary/landingPages/organization/organization.module').then(m => m.OrganizationModule),
data: {hasQuickContact: false, hasMenuSearchBar: true, showHeader: true}
loadChildren: () => import('./landingPages/organization/libOrganization.module').then(m => m.LibOrganizationModule), data: { showHeader: true, hasMenuSearchBar: true}
},
// {
// path: 'search/result',
// loadChildren: () => import('./landingPages/result/libResult.module').then(m => m.LibResultModule),
// data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/publication',
// loadChildren: () => import('./landingPages/publication/libPublication.module').then(m => m.LibPublicationModule),
// data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/dataset',
// loadChildren: () => import('./landingPages/dataset/libDataset.module').then(m => m.LibDatasetModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/software',
// loadChildren: () => import('./landingPages/software/libSoftware.module').then(m => m.LibSoftwareModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/other',
// loadChildren: () => import('./landingPages/orp/libOrp.module').then(m => m.LibOrpModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/project',
// loadChildren: () => import('./landingPages/project/libProject.module').then(m => m.LibProjectModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/dataprovider',
// loadChildren: () => import('./landingPages/dataProvider/libDataProvider.module').then(m => m.LibDataProviderModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/service',
// loadChildren: () => import('./landingPages/service/libService.module').then(m => m.LibServiceModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// {
// path: 'search/organization',
// loadChildren: () => import('./landingPages/organization/libOrganization.module').then(m => m.LibOrganizationModule), data: { showHeader: true, hasMenuSearchBar: true}
// },
// Search Pages
{
@ -133,6 +111,14 @@ const routes: Routes = [
// redirectTo: ''
loadChildren: () => import('./searchPages/advanced/advancedSearchProjects.module').then(m => m.LibAdvancedSearchProjectsModule)
},
{
path: 'recommendations',
loadChildren: () => import('./recommendations/recommendations.module').then(m => m.RecommendationsModule)
},
{
path: 'natural-language-search',
loadChildren: () => import('./natural-language-search/natural-language-search.module').then(m => m.NaturalLanguageSearchModule)
},
{
path: 'reload',
loadChildren: () => import('./reload/libReload.module').then(m => m.LibReloadModule),

View File

@ -77,7 +77,7 @@ export class AppComponent {
logoUrl: this.agg.logoUrl,
logoSmallUrl: this.agg.logoUrl,
position: 'left',
menuPosition: 'right',
menuPosition: 'center',
badge: false,
darkBg: false
};
@ -122,7 +122,9 @@ export class AppComponent {
null, null, "alpha-badge", null, "_blank", "internal", false,
[
new MenuItem("recommendations", "Community Recommendations", "https://test.darelab.athenarc.gr/crps/", "", false, [], null, {}),
new MenuItem("nl-search", "NL Search", "https://darelab.athenarc.gr/nl_search/fc4eosc", "", false, [], null, {})
new MenuItem("nl-search", "NL Search", "https://darelab.athenarc.gr/nl_search/fc4eosc", "", false, [], null, {}),
new MenuItem("category-to-item", "Dev - Category to Item", "", "/recommendations/category-to-item", false, [], null, {}),
new MenuItem("natural-language-search", "Dev - NL Search", "", "/natural-language-search", false, [], null, {})
],
"Alpha"
)

View File

@ -16,6 +16,8 @@ import {HttpInterceptorService} from "./openaireLibrary/http-interceptor.service
import {ErrorInterceptorService} from "./openaireLibrary/error-interceptor.service";
import {DEFAULT_TIMEOUT, TimeoutInterceptor} from "./openaireLibrary/timeout-interceptor.service";
import {ConfigurationService} from "./openaireLibrary/utils/configuration/configuration.service";
import {RouteReuseStrategy} from '@angular/router';
import {CustomRouteReuseStrategy} from './openaireLibrary/shared/custom-route-reuse-strategy';
@NgModule({
imports: [
@ -34,6 +36,7 @@ import {ConfigurationService} from "./openaireLibrary/utils/configuration/config
exports: [AppComponent],
providers: [
ConfigurationService,
{provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy},
{provide: APP_ID, useValue: 'eosc'},
{
provide: HTTP_INTERCEPTORS,

View File

@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import {ServerModule} from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}

View File

@ -12,44 +12,13 @@
</a>
</div>
<div search-input [(value)]="keyword"
[placeholder]="'Search in FAIRCORE4EOSC'" (searchEmitter)="goTo()"
[searchInputClass]="'inner background'"></div>
[placeholder]="'Search in FAIRCORE4EOSC'" (searchEmitter)="goTo()"
[searchInputClass]="'inner background'"></div>
</div>
</div>
</div>
</div>
</div>
<!-- <div class="image-front-topbar">-->
<!-- <div class="uk-section uk-section-small home-background">-->
<!-- <div id="searchForm" class="uk-container uk-container-large uk-section uk-section-xsmall uk-padding-remove-bottom">-->
<!-- <div class="uk-grid uk-flex uk-flex-center uk-margin-small-top">-->
<!-- <div class="uk-width-1-1 uk-width-auto@m uk-first-column"><div id="searchImage"></div></div>-->
<!-- <div class="uk-width-expand uk-padding-remove-vertical search_box_bg" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-slide-bottom-medium; delay: 200">-->
<!-- <div class="uk-flex uk-flex-center uk-flex-wrap">-->
<!-- <div class="uk-width-xlarge@l uk-width-large">-->
<!-- <div class="uk-flex uk-flex-center uk-child-width-1-1">-->
<!-- <div [class.uk-invisible]="disableSelect" uk-scrollspy-class>-->
<!-- <advanced-search-input (searchEmitter)="goTo(true)">-->
<!-- <entities-selection #entities [simpleView]="true" currentEntity="all" [selectedEntity]="selectedEntity"-->
<!-- (selectionChange)="entityChanged($event)" (disableSelectEmitter)="disableSelectChange($event)"-->
<!-- [onChangeNavigate]="false" class="uk-width-2-5"></entities-selection>-->
<!-- <div class="uk-width-expand" input placeholder="Scholary works" [hint]="'Search in OpenAIRE'"-->
<!-- [(value)]="keyword" tooltip="true"></div>-->
<!-- </advanced-search-input>-->
<!-- <div *ngIf="selectedEntity === 'result' && !entities.input.focused" class="uk-dropdown uk-display-block uk-margin-top uk-width-auto">-->
<!-- <div class="uk-padding-small">-->
<!-- <quick-selections [resultTypes]="resultTypes" [quickFilter]="resultsQuickFilter"></quick-selections>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div class="uk-section uk-container uk-container-large">
<div class="contentbox uk-grid uk-child-width-1-1 uk-child-width-1-2@l">
<div>
@ -74,3 +43,84 @@
</div>
<img src="/assets/home/cloud.svg" class="cloudSvg">
</div>
<div class="author-recommendations">
<div class="uk-section uk-container uk-container-large">
<hr class="uk-margin-large-bottom">
<ng-container *ngIf="!user">
<div class="uk-flex uk-flex-column uk-flex-middle uk-flex-center uk-padding uk-padding-remove-bottom uk-margin-small-bottom">
<span class="uk-h4 uk-text-center uk-width-1-2@m">
Login and receive recommendations based on your ORCID.
</span>
<a class="uk-button uk-button-primary uk-text-uppercase uk-margin-top"
(click)="logIn()">
Login
</a>
</div>
<div class="uk-text-right">
<img class="uk-margin-large-right" src="assets/recommendations/asset-3.svg" style="width: 225px;">
</div>
</ng-container>
<ng-container *ngIf="user">
<ng-container *ngIf="user.orcid">
<div *ngIf="recommendations">
<div class="uk-section uk-section-small">
<div *ngFor="let item of recommendations | keyvalue;" class="uk-margin-large-bottom">
<div class="uk-flex uk-flex-middle">
<icon [name]="'recommendations'" [flex]="true" [ratio]="1.5"></icon>
<span class="uk-margin-left">Recommended for you in relation to <span class="uk-text-bold uk-text-uppercase">{{item.key}}</span></span>
</div>
<!-- <div class="uk-grid uk-child-width-1-3@m uk-margin-top" uk-height-match=".uk-card" uk-grid>
<div *ngFor="let result of item.value | keyvalue;">
<recommendation-card [result]="result.value"></recommendation-card>
</div>
</div> -->
<div class="uk-slider uk-margin-top" uk-slider>
<ul class="uk-slider-items" uk-height-match=".uk-card">
<li *ngFor="let slide of resultsSlider(item.value); let i = index" class="uk-width-1-1">
<div class="uk-padding">
<div class="uk-grid uk-child-width-1-3@m" uk-grid>
<ng-container *ngIf="i === 0">
<div *ngFor="let result of slide | keyvalue;" uk-scrollspy-class>
<recommendation-card [result]="result.value"></recommendation-card>
</div>
</ng-container>
<ng-container *ngIf="i !== 0">
<div *ngFor="let result of slide | keyvalue;">
<recommendation-card [result]="result.value"></recommendation-card>
</div>
</ng-container>
</div>
</div>
</li>
</ul>
<ul class="uk-slider-nav uk-dotnav uk-flex-center uk-margin-medium-top"></ul>
</div>
</div>
</div>
</div>
<div *ngIf="!recommendations" class="uk-flex uk-flex-middle uk-flex-center uk-margin-bottom">
<div class="uk-h6 uk-text-center">
No recommendations found based on your ORCID.
</div>
</div>
</ng-container>
<ng-container *ngIf="!user.orcid">
<div class="uk-flex uk-flex-column uk-flex-middle uk-flex-center uk-padding uk-padding-remove-bottom uk-margin-small-bottom">
<span class="uk-h4 uk-text-center uk-width-1-2@m">
Please logout and login with your ORCID account.
</span>
<a class="uk-button uk-button-primary uk-text-uppercase uk-margin-top"
(click)="logOut()">
Logout
</a>
</div>
<div class="uk-text-right">
<img class="uk-margin-large-right" src="assets/recommendations/asset-3.svg" style="width: 225px;">
</div>
</ng-container>
</ng-container>
</div>
</div>

View File

@ -1,61 +1,24 @@
// import {Component, Inject} from "@angular/core";
// import {DOCUMENT} from "@angular/common";
// import {Meta, Title} from "@angular/platform-browser";
// import {properties} from "../../environments/environment";
//
// @Component({
// selector: 'home',
// templateUrl: 'home.component.html',
// })
// export class HomeComponent {
//
// constructor(@Inject(DOCUMENT) readonly document: Document, private _meta: Meta, private _title: Title) {
// let title = "EOSC Explore";
//
// this._title.setTitle(title);
// this._meta.updateTag({content:title},"property='og:title'");
// }
//
// /** The Window object from Document defaultView */
// get window(): Window {
// return this.document.defaultView;
// }
//
// ngOnInit() {
// // this.window.location.href = '...';
// if (typeof document !== 'undefined') {
// this.window.open('https://'+(properties.environment == "beta" ? "beta." : "")+'search.marketplace.eosc-portal.eu/search/all?q=*', "_self");
// }
// }
// }
import {ChangeDetectorRef, Component, Inject, ViewChild} from '@angular/core';
import {Subscription, zip} from 'rxjs';
import {ActivatedRoute, Router} from '@angular/router';
import {DOCUMENT, Location} from '@angular/common';
import {ChangeDetectorRef, Component} from '@angular/core';
import {Subscription} from 'rxjs';
import {Router} from '@angular/router';
import {Meta, Title} from '@angular/platform-browser';
import {ConfigurationService} from '../openaireLibrary/utils/configuration/configuration.service';
import {SearchDataprovidersService} from '../openaireLibrary/services/searchDataproviders.service';
import {SearchProjectsService} from '../openaireLibrary/services/searchProjects.service';
import {SearchOrganizationsService} from '../openaireLibrary/services/searchOrganizations.service';
import {RefineFieldResultsService} from '../openaireLibrary/services/refineFieldResults.service';
import {OpenaireEntities, SearchFields} from '../openaireLibrary/utils/properties/searchFields';
import {RouterHelper} from '../openaireLibrary/utils/routerHelper.class';
import {EnvProperties} from '../openaireLibrary/utils/properties/env-properties';
import {ErrorCodes} from '../openaireLibrary/utils/properties/errorCodes';
import {PiwikService} from '../openaireLibrary/utils/piwik/piwik.service';
import {SEOService} from '../openaireLibrary/sharedComponents/SEO/SEO.service';
import {SearchResearchResultsService} from "../openaireLibrary/services/searchResearchResults.service";
import {HelperService} from "../openaireLibrary/utils/helper/helper.service";
import {Filter} from "../openaireLibrary/searchPages/searchUtils/searchHelperClasses.class";
import {AggregatorInfo, PortalAggregators} from "../utils/aggregators";
import {SearchCustomFilter} from "../openaireLibrary/searchPages/searchUtils/searchUtils.class";
import {properties} from "../../environments/environment";
import {portalProperties} from "../../environments/environment-aggregator";
import {UserManagementService} from '../openaireLibrary/services/user-management.service';
import {User} from '../openaireLibrary/login/utils/helper.class';
import {Identifier} from '../openaireLibrary/utils/string-utils.class';
import {RecommendationsService} from '../openaireLibrary/recommendations/recommendations.service';
@Component({
selector: 'home',
@ -63,7 +26,6 @@ import {portalProperties} from "../../environments/environment-aggregator";
})
export class HomeComponent {
public keyword:string = "";
public searchFields:SearchFields = new SearchFields();
public errorCodes:ErrorCodes = new ErrorCodes();
public routerHelper:RouterHelper = new RouterHelper();
@ -76,12 +38,8 @@ export class HomeComponent {
showDataProviders: boolean = portalProperties.entities.datasource.isEnabled;
properties: EnvProperties = properties;
public readMore: boolean = false;
private noOfFunders = 3;
public funders = [];
subs: Subscription[] = [];
resultsQuickFilter: { filter: Filter, selected: boolean, filterId: string, value: string } = {
filter: null,
selected: true,
@ -96,36 +54,27 @@ export class HomeComponent {
public pageContents = null;
customFilter:SearchCustomFilter= null;
aggregator:AggregatorInfo;
user: User;
recommendations;
resultsSize: number = 6;
errorMessage: string;
constructor (
private route: ActivatedRoute,
private _router: Router,
private _searchResearchResultsService: SearchResearchResultsService,
private _searchDataprovidersService: SearchDataprovidersService,
private _searchProjectsService: SearchProjectsService,
private _searchOrganizationsService: SearchOrganizationsService,
private _refineFieldResultsService:RefineFieldResultsService,
private location: Location, private _piwikService:PiwikService,
private _piwikService:PiwikService,
private config: ConfigurationService, private _meta: Meta, private _title: Title, private seoService: SEOService,
private helper: HelperService, private cdr: ChangeDetectorRef
private helper: HelperService, private cdr: ChangeDetectorRef,
private userManagementService: UserManagementService,
private recommendationsService: RecommendationsService
) {
this.aggregator = PortalAggregators.eoscInfo;
this.customFilter = PortalAggregators.getSearchCustomFilterByAggregator();
let description = "RDGraph Portal: Over 100M of research deduplicated, 170K research software, 11M research data. One of the largest open scholarly records collection worldwide.";
let title = "RDGraph Portal";
this._title.setTitle(title);
this._meta.updateTag({content:description},"name='description'");
this._meta.updateTag({content:description},"property='og:description'");
this._meta.updateTag({content:title},"property='og:title'");
}
private getPageContents() {
this.subs.push(this.helper.getPageHelpContents(this.properties, 'faircore4eosc', this._router.url).subscribe(contents => {
this.pageContents = contents;
}));
}
public ceil(num: number) {
@ -134,7 +83,12 @@ export class HomeComponent {
public ngOnInit() {
this.seoService.createLinkForCanonicalURL(this.properties.domain + this.properties.baseLink+this._router.url, false);
//this.getPageContents();
this.subs.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user;
if (this.user?.orcid) {
this.getOrcidRecommendations();
}
}));
if(this.properties!=null){
var url = this.properties.domain + this.properties.baseLink+this._router.url;
this._meta.updateTag({content:url},"property='og:url'");
@ -142,7 +96,6 @@ export class HomeComponent {
this.subs.push(this._piwikService.trackView(this.properties, "RDGraph Portal").subscribe());
}
//this.config.getCommunityInformation(this.properties, this.properties.adminToolsCommunity ).subscribe(data => {
this.subs.push(this.config.portalAsObservable.subscribe(data => {
if(data) {
var showEntity = {};
@ -176,8 +129,8 @@ export class HomeComponent {
}
));
}
}
public ngOnDestroy() {
for (let sub of this.subs) {
sub.unsubscribe();
@ -187,37 +140,20 @@ export class HomeComponent {
private handleError(message: string, error) {
console.error("Home Page: "+message, error);
}
entityChanged($event){
this.selectedEntity = $event.entity;
this.selectedEntitySimpleUrl = $event.simpleUrl;
this.selectedEntityAdvancedUrl = $event.advancedUrl;
}
goTo() {
let parameterNames = [];
let parameterValues = [];
// if (this.selectedEntity == "result") {
// if (this.resultTypes) {
// let values = [];
// for (let value of this.resultTypes.values) {
// if (value.selected) {
// values.push(value.id);
// }
// }
// if (values.length > 0 && values.length != 4) {
// parameterNames.push("type");
// parameterValues.push(values.join(","));
// }
// if (this.resultsQuickFilter && this.resultsQuickFilter.selected) {
// parameterNames.push(this.resultsQuickFilter.filterId);
// parameterValues.push('"' + encodeURIComponent(this.resultsQuickFilter.value) + '"');
// }
// }
// } else if (this.selectedEntity == "all") {
if (this.resultsQuickFilter && this.resultsQuickFilter.selected) {
parameterNames.push(this.resultsQuickFilter.filterId);
parameterValues.push('"' + encodeURIComponent(this.resultsQuickFilter.value) + '"');
}
// }
if (this.keyword.length > 0) {
parameterNames.push("fv0");
parameterValues.push(this.keyword);
@ -239,7 +175,7 @@ export class HomeComponent {
params["f0"] = "q";
}
if(this.customFilter){
params = this.customFilter.getParameters(params);
params = this.customFilter.getParameters(params);
}
return params;
}
@ -259,4 +195,29 @@ export class HomeComponent {
this.disableSelect = event;
this.cdr.detectChanges();
}
logIn() {
this.userManagementService.login();
}
logOut() {
this.userManagementService.logout();
}
getOrcidRecommendations() {
let orcid = Identifier.getRawORCID(this.user.orcid);
this.subs.push(this.recommendationsService.getRecommendationsForOrcid(this.properties.recommendationsForOrcidAPI, orcid).subscribe(data => {
this.recommendations = data['recommendations'];
}, error => {
console.log(error);
}));
}
resultsSlider(results) {
let slider = [];
for (let i = 0; i < (results.length / this.resultsSize); i++) {
slider.push(results.slice(i * this.resultsSize, ((i + 1) * this.resultsSize)));
}
return slider;
}
}

View File

@ -24,11 +24,13 @@ import {EntitiesSelectionModule} from "../openaireLibrary/searchPages/searchUtil
import {QuickSelectionsModule} from "../openaireLibrary/searchPages/searchUtils/quick-selections.module";
import {IconsModule} from "../openaireLibrary/utils/icons/icons.module";
import {IconsService} from "../openaireLibrary/utils/icons/icons.service";
import {book, cog, database, earth} from "../openaireLibrary/utils/icons/icons";
import {book, cog, database, earth, recommendations} from "../openaireLibrary/utils/icons/icons";
import {NumbersModule} from "../openaireLibrary/sharedComponents/numbers/numbers.module";
import {AdvancedSearchInputModule} from "../openaireLibrary/sharedComponents/advanced-search-input/advanced-search-input.module";
import {InputModule} from "../openaireLibrary/sharedComponents/input/input.module";
import {SearchInputModule} from "../openaireLibrary/sharedComponents/search-input/search-input.module";
import {RecommendationsService} from '../openaireLibrary/recommendations/recommendations.service';
import {RecommendationCardModule} from '../openaireLibrary/recommendations/recommendation-card.module';
@NgModule({
imports: [
@ -41,13 +43,14 @@ import {SearchInputModule} from "../openaireLibrary/sharedComponents/search-inpu
HomeRoutingModule,
HelperModule,
ErrorMessagesModule,
SEOServiceModule, EntitiesSelectionModule, QuickSelectionsModule, IconsModule, NumbersModule, AdvancedSearchInputModule, InputModule, SearchInputModule
SEOServiceModule, EntitiesSelectionModule, QuickSelectionsModule, IconsModule, NumbersModule, AdvancedSearchInputModule, InputModule, SearchInputModule,
RecommendationCardModule
],
declarations: [
HomeComponent
],
providers:[
PreviousRouteRecorder
PreviousRouteRecorder, RecommendationsService
],
exports: [
HomeComponent
@ -55,6 +58,6 @@ import {SearchInputModule} from "../openaireLibrary/sharedComponents/search-inpu
})
export class HomeModule {
constructor(private iconsService: IconsService) {
this.iconsService.registerIcons([book, earth, cog, database]);
this.iconsService.registerIcons([book, earth, cog, database, recommendations]);
}
}

View File

@ -6,7 +6,7 @@ import {PreviousRouteRecorder} from '../../openaireLibrary/utils/piwik/previousR
import {OrpRoutingModule} from './orp-routing.module';
@NgModule({
imports: [ResultLandingModule, OrpRoutingModule],
imports: [OrpRoutingModule, ResultLandingModule],
declarations:[OpenaireOrpComponent],
providers:[FreeGuard, PreviousRouteRecorder],
exports:[OpenaireOrpComponent]

View File

@ -0,0 +1,14 @@
import {NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
import {NaturalLanguageSearchComponent} from './natural-language-search.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: '', component: NaturalLanguageSearchComponent,
},
])
]
})
export class NaturalLanguageSearchModuleRoutingModule { }

View File

@ -0,0 +1,92 @@
<div class="uk-section uk-container uk-container-large" uk-scrollspy="target: [uk-scrollspy-class]; cls: uk-animation-slide-bottom-medium; delay: 200">
<div class="uk-flex uk-flex-column uk-flex-middle">
<div class="uk-text-center">
<h1 class="uk-h3 uk-margin-remove" uk-scrollspy-class>
Natural search, real results.
</h1>
<p class="uk-h6 uk-margin-top uk-margin-medium-bottom" uk-scrollspy-class>
Search as you speak. Intuitive, natural, effortless.
</p>
</div>
<div class="uk-width-1-2@m uk-width-1-1" uk-scrollspy-class>
<div search-input [(value)]="phrase" (searchEmitter)="search()"
[placeholder]="'Search in natural language'"
[searchInputClass]="'flat background'">
</div>
<div *ngIf="queryPhrase" class="uk-text-center uk-text-small uk-margin-top">
<span class="uk-text-warning">
Note: Each new question deletes the previous session
</span>
</div>
</div>
</div>
<ng-container *ngIf="queryPhrase">
<div *ngIf="showLoading">
<div class="uk-section">
<loading></loading>
</div>
</div>
<div *ngIf="!showLoading">
<div class="uk-section">
<ng-container *ngIf="errorMessage">
<div class="uk-flex uk-flex-middle uk-margin-bottom">
<img src="assets/common-assets/common/Logo_Small.png" alt="OpenAIRE" loading="lazy"
class="bot-img">
<span class="uk-text-small uk-text-bolder uk-margin-small-left">
Bot
</span>
</div>
<div>
{{errorMessage}}
</div>
</ng-container>
<ng-container *ngIf="results && results.length == 0">
<div class="uk-flex uk-flex-middle uk-margin-bottom">
<img src="assets/common-assets/common/Logo_Small.png" alt="OpenAIRE" loading="lazy"
class="bot-img">
<span class="uk-text-small uk-text-bolder uk-margin-small-left">
Bot
</span>
</div>
<div>
No results found for your query
</div>
</ng-container>
<ng-container *ngIf="results && results.data">
<div class="uk-margin-medium-bottom">
<div class="uk-flex uk-flex-middle uk-margin-small-bottom">
<img src="assets/common-assets/common/Logo_Small.png" alt="OpenAIRE" loading="lazy"
class="bot-img">
<span class="uk-text-small uk-text-bolder uk-margin-small-left">
Bot
</span>
</div>
<div>
<table class="uk-table uk-table-striped uk-table-small uk-table-responsive">
<thead>
<tr>
<ng-container *ngFor="let header of results.columns; let i = index;">
<th *ngIf="i != indexColumnId">
{{header}}
</th>
</ng-container>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of results.data">
<ng-container *ngFor="let item of row; let i = index;">
<td *ngIf="i != indexColumnId">
{{item}}
</td>
</ng-container>
</tr>
</tbody>
</table>
</div>
</div>
</ng-container>
</div>
</div>
</ng-container>
</div>

View File

@ -0,0 +1,3 @@
.bot-img {
width: 30px;
}

View File

@ -0,0 +1,65 @@
import {Component} from "@angular/core";
import {Subscriber} from "rxjs";
import {NaturalLanguageSearchService} from "./natural-language-search.service";
import {EnvProperties} from "../openaireLibrary/utils/properties/env-properties";
import {properties} from "../../environments/environment";
@Component({
selector: 'natural-language-search',
templateUrl: './natural-language-search.component.html',
styleUrls: ['natural-language-search.component.less']
})
export class NaturalLanguageSearchComponent {
private subscriptions = [];
properties: EnvProperties = properties;
showLoading: boolean = false;
errorMessage: string;
phrase: string;
queryPhrase: string;
results;
indexColumnId: number;
constructor(private naturalLanguageSearchService: NaturalLanguageSearchService) {
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
}
search() {
this.results = null;
this.queryPhrase = this.phrase;
this.errorMessage = null;
this.showLoading = true;
this.subscriptions.push(this.naturalLanguageSearchService.getResults(this.properties.naturalLanguageSearchAPI, this.queryPhrase).subscribe(data => {
if(data && data['data'] && data['data'].length > 0) {
if(data && data['columns']) {
for(let i = 0; i < data['columns'].length - 1; i++) {
if(data['columns'][i] == 'id') {
this.indexColumnId = i;
break;
}
}
}
this.results = data;
} else {
this.results = [];
}
this.showLoading = false;
}, error => {
if(error.status == 500) {
this.errorMessage = error.error.message;
} else {
this.errorMessage = 'Sorry, something went wrong. Please try again later.';
}
this.showLoading = false;
}));
}
}

View File

@ -0,0 +1,30 @@
import {NgModule} from "@angular/core";
import {CommonModule} from "@angular/common";
import {RouterModule} from "@angular/router";
import {SearchInputModule} from "../openaireLibrary/sharedComponents/search-input/search-input.module";
import {IconsModule} from "../openaireLibrary/utils/icons/icons.module";
import {LoadingModule} from "../openaireLibrary/utils/loading/loading.module";
import {NaturalLanguageSearchModuleRoutingModule} from "./natural-language-search-routing.module";
import {NaturalLanguageSearchComponent} from "./natural-language-search.component";
import {NaturalLanguageSearchService} from "./natural-language-search.service";
@NgModule({
imports: [
NaturalLanguageSearchModuleRoutingModule, CommonModule, RouterModule, IconsModule,
SearchInputModule, LoadingModule
],
declarations: [
NaturalLanguageSearchComponent
],
providers: [
NaturalLanguageSearchService
],
exports: [
NaturalLanguageSearchComponent
]
})
export class NaturalLanguageSearchModule {
constructor() {
}
}

View File

@ -0,0 +1,21 @@
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {Injectable} from "@angular/core";
@Injectable()
export class NaturalLanguageSearchService {
constructor(private http: HttpClient) {
}
getResults(url: string, queryPhrase: string) {
const body = {
"nl_query": queryPhrase,
};
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post(url, body, options);
}
}

@ -1 +1 @@
Subproject commit 503ab40616c53a071cd74fb2802cd3de130923f6
Subproject commit 25b3c6121b00b18f482b08ad9d7bf1199cb63a9a

View File

@ -0,0 +1,84 @@
<ng-container *ngIf="showLoading">
<div class="uk-container uk-container-large uk-section">
<loading></loading>
</div>
</ng-container>
<ng-container *ngIf="!showLoading && communities?.length">
<div class="uk-flex uk-background-default" [class.uk-flex-column]="isMobile">
<aside [attr.offset]="offset" class="sidebar uk-background-default uk-visible@m" uk-sticky>
<div class="uk-padding">
<div class="uk-text-center">
<h5>In which community are you interested?</h5>
<p>Select a community to see recommendations.</p>
<div *ngIf="filteredCommunities?.length >= size" search-input [searchControl]="keywordControl"
[placeholder]="'Search for communities'"
[searchInputClass]="'flat background'">
</div>
</div>
<div class="uk-margin-medium-top">
<div *ngIf="filteredCommunities?.length">
<span class="uk-text-bold uk-text-meta uk-text-uppercase">Communities</span>
<ul class="uk-list uk-list-divider">
<li *ngFor="let community of filteredCommunities;" class="uk-padding-xsmall" [class.uk-active-custom]="activeCommunity == community.communityId">
<a class="uk-link-heading uk-text-bold" (click)="selectCommunity(community.communityId); setActiveCommunity(community.communityId);">
{{community.title}}
</a>
</li>
</ul>
</div>
<div *ngIf="filteredCommunities?.length == 0" class="uk-text-center uk-text-bold uk-text-meta">
No communities found based on your keyword
</div>
</div>
</div>
</aside>
<div class="uk-hidden@m">
<div class="uk-padding-small">
<div class="uk-text-center">
<h5>In which community are you interested?</h5>
<p>Select a community to see recommendations.</p>
<div *ngIf="filteredCommunities?.length >= size" search-input [searchControl]="keywordControl"
[placeholder]="'Search for communities'"
[searchInputClass]="'flat background'">
</div>
</div>
<div class="uk-margin-top">
<div *ngIf="filteredCommunities?.length">
<span class="uk-text-bold uk-text-meta uk-text-uppercase">Communities</span>
<ul class="uk-list uk-list-divider">
<li *ngFor="let community of filteredCommunities;" class="uk-padding-xsmall" [class.uk-active-custom]="activeCommunity == community.communityId">
<a class="uk-link-heading uk-text-bold" (click)="selectCommunity(community.communityId); setActiveCommunity(community.communityId); scrollToId('content');">
{{community.title}}
</a>
</li>
</ul>
</div>
<div *ngIf="filteredCommunities?.length == 0" class="uk-text-center uk-text-bold uk-text-meta">
No communities found based on your keyword
</div>
</div>
</div>
</div>
<div id="content" class="content uk-width-expand uk-container">
<div *ngIf="errorMessage" class="uk-padding uk-text-center" [class.uk-position-center]="!isMobile">
<h4 class="uk-text-warning uk-width-1-1 uk-width-2-3@m uk-margin-auto">{{errorMessage}}</h4>
</div>
<div *ngIf="!recommendations && !errorMessage" class="uk-padding uk-text-center" [class.uk-position-center]="!isMobile">
<h3 class="uk-width-1-1 uk-width-2-3@m uk-margin-auto">Select a community from the list on the left and receive recommendations.</h3>
</div>
<div *ngIf="recommendations" class="uk-section">
<div *ngFor="let item of recommendations" class="uk-margin-large-bottom">
<div class="uk-flex uk-flex-middle uk-margin-medium-bottom">
<icon [name]="'recommendations'" [ratio]="1.5" [flex]="true"></icon>
<span class="uk-margin-left">Recommended by topic <span class="uk-text-bold">{{item.field}}</span></span>
</div>
<div class="uk-grid uk-child-width-1-2@m uk-child-width-1-3@l" uk-height-match=".uk-card" uk-grid>
<div *ngFor="let result of item.recommendations">
<recommendation-card [result]="result" [category]="item" [community]="activeCommunity" [user]="user"></recommendation-card>
</div>
</div>
</div>
</div>
</div>
</div>
</ng-container>

View File

@ -0,0 +1,30 @@
@import (less) "~src/assets/openaire-theme/less/color.less";
@header-height: var(--header-height);
@sidebar-width: 450px;
.sidebar, .content {
position: relative;
}
.sidebar {
height: calc(100vh - @header-height);
width: @sidebar-width;
overflow-y: auto;
}
.content {
background-color: @default-color;
}
.uk-active-custom {
background-color: @ciel-color;
position: relative;
&::after {
position: absolute;
right: 0;
font-size: 1.8em;
font-family: "Material Icons";
content: "\e5cc"; /* chevron right */
}
}

View File

@ -0,0 +1,130 @@
import {ChangeDetectorRef, Component} from "@angular/core";
import {CommunitiesService} from "../../openaireLibrary/connect/communities/communities.service";
import {EnvProperties} from "../../openaireLibrary/utils/properties/env-properties";
import {properties} from "../../../environments/environment";
import {CommunityInfo} from "../../openaireLibrary/connect/community/communityInfo";
import {Subscriber, zip} from "rxjs";
import {FormBuilder, FormControl} from "@angular/forms";
import {debounceTime, distinctUntilChanged} from "rxjs/operators";
import {RecommendationsService} from "../../openaireLibrary/recommendations/recommendations.service";
import {ActivatedRoute, Router} from "@angular/router";
import {UserManagementService} from "../../openaireLibrary/services/user-management.service";
import {User} from "../../openaireLibrary/login/utils/helper.class";
import {LayoutService} from "../../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
import {HelperFunctions} from "../../openaireLibrary/utils/HelperFunctions.class";
@Component({
selector: 'category-to-item',
templateUrl: './category-to-item.component.html',
styleUrls: ['category-to-item.component.less']
})
export class CategoryToItemComponent {
private subscriptions = [];
properties: EnvProperties = properties;
showLoading: boolean = true;
errorMessage: string;
offset: number;
activeCommunity: string;
size: number = 5; // show search-bar only when communities are more than this number - defaults to 5
communities: CommunityInfo[];
filteredCommunities: CommunityInfo[];
recommendations: any;
user: User;
keywordControl: FormControl;
keyword: string;
isMobile: boolean;
constructor(private communitiesService: CommunitiesService,
private recommendationsService: RecommendationsService,
private router: Router,
private route: ActivatedRoute,
private fb: FormBuilder,
private cdr: ChangeDetectorRef,
private userManagementService: UserManagementService,
private layoutService: LayoutService) {
}
ngOnInit() {
this.properties = properties;
if (typeof document !== "undefined") {
this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'));
}
this.layoutService.isMobile.subscribe(isMobile => {
this.isMobile = isMobile;
this.cdr.detectChanges();
});
this.getCommunities();
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user;
}));
this.subscriptions.push(this.route.params.subscribe(params => {
if(params && params['community']) {
this.subscriptions.push(this.recommendationsService.getRecommendationsForCommunity(this.properties.recommendationsForCommunityAPI, params['community'], this.user ? this.user.id : null).subscribe(data => {
this.recommendations = data;
this.setActiveCommunity(params['community']);
}, error => {
if(error.status == 422) {
this.errorMessage = 'We could not find any recommendations for this community.'
} else {
this.errorMessage = 'Sorry, something went wrong.';
}
}));
}
}));
this.keywordControl = this.fb.control('');
this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(300), distinctUntilChanged()).subscribe(value => {
this.keyword = value;
this.filtering();
}));
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscriber) {
subscription.unsubscribe();
}
});
}
private getCommunities() {
this.subscriptions.push(zip(this.recommendationsService.getAvailableCommunities(this.properties.availableCommunitiesAPI), this.communitiesService.getCommunities(this.properties, this.properties.communitiesAPI)).subscribe(data => {
let availableCommunities: any = data[0];
this.communities = availableCommunities.map(id => {
const obj = data[1].find(o => o.communityId === id);
return { id, ...obj };
});
this.communities.sort((a, b) => a['title'].localeCompare(b['title']));
this.filteredCommunities = this.communities;
this.showLoading = false;
}));
}
filtering() {
let filteredCommunities = this.communities;
if(!this.keyword){
this.keyword = '';
}
if(this.communities.length) {
filteredCommunities = filteredCommunities.filter(item => (item['title'] && item['title'].toLowerCase().includes(this.keyword.toLowerCase())) || (item['shortTitle'] && item['shortTitle'].toLowerCase().includes(this.keyword.toLowerCase())));
}
this.filteredCommunities = filteredCommunities;
}
selectCommunity(id: string) {
this.errorMessage = null;
this.router.navigate(['/recommendations/category-to-item/' + id]);
}
setActiveCommunity(id) {
this.activeCommunity = id;
}
scrollToId(value: string) {
HelperFunctions.scrollToId(value);
}
}

View File

@ -0,0 +1,17 @@
import {NgModule} from '@angular/core';
import {RouterModule} from '@angular/router';
import {CategoryToItemComponent} from './category-to-item/category-to-item.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: 'category-to-item', component: CategoryToItemComponent,
},
{
path: 'category-to-item/:community', component: CategoryToItemComponent
}
])
]
})
export class RecommendationsRoutingModule { }

View File

@ -0,0 +1,33 @@
import {NgModule} from "@angular/core";
import {CommonModule} from "@angular/common";
import {RouterModule} from "@angular/router";
import {CategoryToItemComponent} from "./category-to-item/category-to-item.component";
import {RecommendationsRoutingModule} from "./recommendations-routing.module";
import {SearchInputModule} from "../openaireLibrary/sharedComponents/search-input/search-input.module";
import {CommunitiesService} from "../openaireLibrary/connect/communities/communities.service";
import {IconsModule} from "../openaireLibrary/utils/icons/icons.module";
import {LoadingModule} from "../openaireLibrary/utils/loading/loading.module";
import {RecommendationsService} from "../openaireLibrary/recommendations/recommendations.service";
import {RecommendationCardModule} from "../openaireLibrary/recommendations/recommendation-card.module";
@NgModule({
imports: [
RecommendationsRoutingModule, CommonModule, RouterModule, IconsModule,
SearchInputModule, LoadingModule, RecommendationCardModule
],
declarations: [
CategoryToItemComponent
],
providers: [
CommunitiesService, RecommendationsService
],
exports: [
CategoryToItemComponent
]
})
export class RecommendationsModule {
constructor() {
}
}

View File

@ -35,7 +35,7 @@ export class AggregatorInfo {
export class PortalAggregators {
static eoscInfo: AggregatorInfo =
new AggregatorInfo("faircore4eosc", "Faircore4eosc Explore", "assets/logo.svg",
null, null, null, null,null,null ,false,true,
null, null, null, null,null,null ,true,true,
`

View File

@ -168,6 +168,10 @@
z-index: -1;
}
.author-recommendations hr {
border-top: 1px solid @grey-color;
}
//.image-front-topbar, .search-form, #main-menu .uk-navbar-container, #main-menu-small .uk-navbar-container {
.eosc-explore-back-search-bar {
//background: @global-primary-background;

@ -1 +1 @@
Subproject commit c6d21a6c027df56ae3bbf5c489b2ee9893924aef
Subproject commit b4d09b7cd942893c238d4152eeac1bbc822a0b13

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 165.67 142.95">
<defs>
<style>
.cls-1 {
stroke-width: 0px;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<g>
<path class="cls-1" d="m78.87,47.8c-7.25-.92-16.45,2.46-18.53,15-.18,1.09.55,2.12,1.64,2.3.11.02.22.03.33.03.96,0,1.81-.69,1.97-1.67,2.03-12.25,11.29-12.04,14.08-11.69.09.01.25.03.33.03,1.1,0,2-.9,2-2s-.8-1.91-1.82-2Zm0,0c-7.25-.92-16.45,2.46-18.53,15-.18,1.09.55,2.12,1.64,2.3.11.02.22.03.33.03.96,0,1.81-.69,1.97-1.67,2.03-12.25,11.29-12.04,14.08-11.69.09.01.25.03.33.03,1.1,0,2-.9,2-2s-.8-1.91-1.82-2Zm80.15,15.39c-41.4-21.33-39.11-30.98-48.51-46.48-6.71-11.06-11.35-14.09-13.45-14.92-.73-.29-1.42-.64-2.12-1-3.51-1.78-14.48-.06-17.77.52-.62.1-1.23.25-1.83.45-5.94,1.92-40.26,13.5-58.54,29.94C-3.27,49.73-.43,75.91,1.05,84.78c2.26,13.58,19.56,47.24,72.13,55.87,52.57,8.64,70.85-7.62,85.84-39.11,14.98-31.49,0-38.35,0-38.35Zm-116.89-15.36c-.06.13-9.43,5.27-9.43,5.27l3.91-10.92-7.43-7.68,11.04,1.14-.22-.03c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.64,1.21s-9.24,6.07-9.24,6.19c.19,0,2.31,11.84,2.31,11.84,0,0-8.63-7.88-8.82-7.88Zm37.27,68.26s-12.1-.57-12.38-.86c-.29-.29-4.67-2.19-5.34-6.95-.66-4.76,0-7.81,0-7.81l24.48,2.57s-.67,12.1-6.76,13.05Zm7.68-18.07c-1.51,2.02-24.37-2.22-24.37-2.22-.38-1.01-.64-5.39-2.42-9.2-1.78-3.81-15.11-17.4-3.68-35.05,11.42-17.65,31.81-9.91,31.81-9.91,0,0,18.03,7.24,16.88,22.99-1.14,15.74-7.42,19.67-9.2,21.33-.59.55-7.2,9.65-9.02,12.06Zm31.56,25.75s-8.62-7.87-8.83-7.87c-.06.12-9.43,5.27-9.43,5.27l3.91-10.92-7.43-7.69,11.05,1.15-.23-.03c.2-.26,4.86-10.16,4.86-10.16l2.38,11.01,10.64,1.21s-9.24,6.07-9.24,6.19c.19,0,2.32,11.84,2.32,11.84Zm13.58-33.14s-8.63-7.88-8.82-7.88c-.06.13-9.43,5.27-9.43,5.27l3.91-10.92-7.43-7.68,11.04,1.14-.22-.03c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.64,1.21s-9.24,6.07-9.24,6.19c.19,0,2.31,11.84,2.31,11.84Zm-53.35-42.83c-7.25-.92-16.45,2.46-18.53,15-.18,1.09.55,2.12,1.64,2.3.11.02.22.03.33.03.96,0,1.81-.69,1.97-1.67,2.03-12.25,11.29-12.04,14.08-11.69.09.01.25.03.33.03,1.1,0,2-.9,2-2s-.8-1.91-1.82-2Zm0,0c-7.25-.92-16.45,2.46-18.53,15-.18,1.09.55,2.12,1.64,2.3.11.02.22.03.33.03.96,0,1.81-.69,1.97-1.67,2.03-12.25,11.29-12.04,14.08-11.69.09.01.25.03.33.03,1.1,0,2-.9,2-2s-.8-1.91-1.82-2Zm0,0c-7.25-.92-16.45,2.46-18.53,15-.18,1.09.55,2.12,1.64,2.3.11.02.22.03.33.03.96,0,1.81-.69,1.97-1.67,2.03-12.25,11.29-12.04,14.08-11.69.09.01.25.03.33.03,1.1,0,2-.9,2-2s-.8-1.91-1.82-2Z"/>
<path class="cls-1" d="m80.69,49.8c0,1.1-.9,2-2,2-.08,0-.24-.02-.33-.03-2.79-.35-12.05-.56-14.08,11.69-.16.98-1.01,1.67-1.97,1.67-.11,0-.22-.01-.33-.03-1.09-.18-1.82-1.21-1.64-2.3,2.08-12.54,11.28-15.92,18.53-15,1.02.09,1.82.95,1.82,2Z"/>
<path class="cls-1" d="m80.69,49.8c0,1.1-.9,2-2,2-.08,0-.24-.02-.33-.03-2.79-.35-12.05-.56-14.08,11.69-.16.98-1.01,1.67-1.97,1.67-.11,0-.22-.01-.33-.03-1.09-.18-1.82-1.21-1.64-2.3,2.08-12.54,11.28-15.92,18.53-15,1.02.09,1.82.95,1.82,2Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 109.97 98.32">
<defs>
<style>
.cls-1 {
stroke-width: 0px;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<g>
<path class="cls-1" d="m10.83,10.16c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92L0,9.05l11.05,1.14-.22-.03Z"/>
<path class="cls-1" d="m92.1,45.08c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92-7.43-7.68,11.05,1.14-.22-.03Z"/>
<path class="cls-1" d="m78.51,78.22c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92-7.43-7.68,11.05,1.14-.22-.03Z"/>
<path class="cls-1" d="m32.51,75.02l24.48,2.57s-.67,12.1-6.76,13.05c0,0-12.1-.57-12.38-.86s-4.67-2.19-5.33-6.95,0-7.81,0-7.81Z"/>
<path class="cls-1" d="m59.24,16.19s-20.38-7.74-31.81,9.91c-11.43,17.65,1.91,31.23,3.69,35.04,1.77,3.81,2.03,8.19,2.42,9.21,0,0,22.85,4.24,24.37,2.22,1.81-2.41,8.43-11.51,9.01-12.06,1.78-1.66,8.07-5.59,9.21-21.33,1.14-15.75-16.89-22.99-16.89-22.99Zm-9.72,10.15c-.09,0-.25-.01-.33-.02-2.79-.35-12.05-.56-14.08,11.69-.16.97-1.01,1.67-1.97,1.67-.11,0-.22-.01-.33-.03-1.09-.18-1.83-1.21-1.65-2.3,2.09-12.54,11.29-15.92,18.53-15,1.03.09,1.83.95,1.83,1.99,0,1.11-.9,2-2,2Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 165.67 142.94">
<defs>
<style>
.cls-1 {
fill: #ffd215;
}
.cls-1, .cls-2, .cls-3 {
stroke-width: 0px;
}
.cls-2 {
fill: #e86438;
}
.cls-3 {
fill: #f9f9f9;
}
</style>
</defs>
<g id="Layer_1-2" data-name="Layer 1">
<g>
<path class="cls-2" d="m94.93.79c.7.35,1.39.71,2.12.99,2.1.83,6.74,3.86,13.45,14.93,9.4,15.49,7.11,25.14,48.51,46.48,0,0,14.98,6.86,0,38.35s-33.27,47.75-85.84,39.11C20.6,132.01,3.31,98.35,1.04,84.77c-1.48-8.86-4.32-35.05,15.75-53.08C35.08,15.26,69.4,3.67,75.33,1.75c.6-.19,1.21-.34,1.83-.45,3.29-.57,14.26-2.29,17.77-.51Z"/>
<path class="cls-1" d="m40,35.6c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92-7.43-7.68,11.05,1.14"/>
<path class="cls-1" d="m121.27,70.52c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92-7.43-7.68,11.05,1.14"/>
<path class="cls-1" d="m107.68,103.67c.19-.25,4.86-10.16,4.86-10.16l2.38,11.02,10.63,1.21s-9.43,6.19-9.24,6.19,2.32,11.84,2.32,11.84c0,0-8.76-8-8.83-7.87s-9.43,5.27-9.43,5.27l3.9-10.92-7.43-7.68,11.05,1.14"/>
<path class="cls-3" d="m61.68,100.46l24.48,2.57s-.67,12.1-6.76,13.05c0,0-12.1-.57-12.38-.86s-4.67-2.19-5.33-6.95,0-7.81,0-7.81Z"/>
<path class="cls-3" d="m62.7,95.79c-.38-1.02-.64-5.4-2.42-9.21s-15.11-17.4-3.68-35.05,31.81-9.9,31.81-9.9c0,0,18.03,7.24,16.89,22.98s-7.43,19.67-9.21,21.33c-.59.55-7.2,9.65-9.02,12.06-1.52,2.02-24.37-2.22-24.37-2.22Z"/>
<path class="cls-2" d="m62.3,65.12c-.11,0-.22,0-.33-.03-1.09-.18-1.83-1.21-1.65-2.3,2.08-12.55,11.28-15.92,18.53-15h0c1.02.09,1.82.95,1.82,1.99,0,1.1-.9,2-2,2-.08,0-.24-.01-.33-.02-2.79-.35-12.05-.56-14.08,11.69-.16.98-1.01,1.67-1.97,1.67Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -27,10 +27,14 @@ let props: EnvProperties = {
reCaptchaSiteKey: null,
footerGrantText : "",
searchAPIURLLAst: "https://services.openaire.eu/search/v2/api/",
searchResourcesAPIURL: "https://services.openaire.eu/search/v2/api/resources",
csvAPIURL: "https://services.openaire.eu/search/v2/api/reports"
naturalLanguageSearchAPI: "https://darelab.athenarc.gr/nl_search/api/fc4e_get_results/",
availableCommunitiesAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/available-communities',
recommendationsForCommunityAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/recommend',
recommendationsForOrcidAPI: 'https://darelab.athenarc.gr/api/faircore/user-to-item-recommender/recommend',
recommendationsForPublicationAPI: 'https://darelab.athenarc.gr/api/faircore/item-to-item-recommender/recommend/',
feedbackForRecommendationAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/update/'
};
export let properties: EnvProperties = {
...common, ...commonBeta, ...props}
...props, ...common, ...commonBeta
}

View File

@ -25,7 +25,14 @@ let props: EnvProperties = {
searchLinkToServices: "/search/find/services",
searchLinkToAdvancedServices: "/search/advanced/services",
reCaptchaSiteKey: null,
footerGrantText : ""
footerGrantText : "",
naturalLanguageSearchAPI: "https://darelab.athenarc.gr/nl_search/api/fc4e_get_results/",
availableCommunitiesAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/available-communities',
recommendationsForCommunityAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/recommend',
recommendationsForOrcidAPI: 'https://darelab.athenarc.gr/api/faircore/user-to-item-recommender/recommend',
recommendationsForPublicationAPI: 'https://darelab.athenarc.gr/api/faircore/item-to-item-recommender/recommend/',
feedbackForRecommendationAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/update/'
};
export let properties: EnvProperties = {

View File

@ -25,7 +25,14 @@ let props: EnvProperties = {
searchLinkToServices: "/search/find/services",
searchLinkToAdvancedServices: "/search/advanced/services",
reCaptchaSiteKey: null,
footerGrantText : "This OpenAIRE gateway is part of a project that has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreements No. 777541 and 101017452"
footerGrantText : "This OpenAIRE gateway is part of a project that has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreements No. 777541 and 101017452",
naturalLanguageSearchAPI: "https://darelab.athenarc.gr/nl_search/api/fc4e_get_results/",
availableCommunitiesAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/available-communities',
recommendationsForCommunityAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/recommend',
recommendationsForOrcidAPI: 'https://darelab.athenarc.gr/api/faircore/user-to-item-recommender/recommend',
recommendationsForPublicationAPI: 'https://darelab.athenarc.gr/api/faircore/item-to-item-recommender/recommend/',
feedbackForRecommendationAPI: 'https://darelab.athenarc.gr/api/faircore/category-based-recommender/update/'
};
export let properties: EnvProperties = {

View File

@ -1,15 +0,0 @@
/***************************************************************************************************
* Load `$localize` onto the global scope - used if i18n tags appear in Angular templates.
*/
import '@angular/localize/init';
import { enableProdMode } from '@angular/core';
import {properties} from './environments/environment';
if (properties.environment !== "development") {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';

View File

@ -1,16 +0,0 @@
{
"extends": "./tsconfig.app.json",
"compilerOptions": {
"outDir": "../out-tsc/app-server",
"types": [
"node"
]
},
"files": [
"main.server.ts",
"../server.ts"
],
"angularCompilerOptions": {
"entryModule": "./app/app.server.module#AppServerModule"
}
}