Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
8d6205bb32
|
@ -5,13 +5,13 @@
|
|||
"ng": "ng",
|
||||
"start": "ng serve --port 4600 --disable-host-check --host 0.0.0.0",
|
||||
"build": "ng build",
|
||||
"build-dev": "ng build --configuration=development --source-map --base-href /dashboard/",
|
||||
"build-dev": "ng build --configuration=development --source-map",
|
||||
"build-beta": "ng build --configuration=beta --base-href /dashboard/ --source-map",
|
||||
"build-prod": "ng build --configuration production --base-href /dashboard/ --source-map",
|
||||
"webpack-bundle-analyzer": "ng build --stats-json && webpack-bundle-analyzer dist/monitor-dashboard/browser/stats.json --host 0.0.0.0",
|
||||
"test": "ng test",
|
||||
"e2e": "ng e2e",
|
||||
"dev:ssr": "ng run monitor-dashboard:serve-ssr",
|
||||
"dev:ssr": "ng run monitor-dashboard:serve-ssr --port 4600",
|
||||
"serve:ssr": "node dist/monitor-dashboard/server/main.js",
|
||||
"build:ssr-dev": "npm run build-dev && ng run monitor-dashboard:server:development",
|
||||
"build:ssr-beta": "npm run build-beta && ng run monitor-dashboard:server:beta",
|
||||
|
@ -34,6 +34,7 @@
|
|||
"@angular/platform-server": "^14.2.3",
|
||||
"@angular/router": "^14.2.3",
|
||||
"@nguniversal/express-engine": "^14.2.0",
|
||||
"axios": "^1.4.0",
|
||||
"clipboard": "^1.5.16",
|
||||
"core-js": "^2.5.4",
|
||||
"express": "^4.15.2",
|
||||
|
@ -52,12 +53,12 @@
|
|||
"@angular/compiler-cli": "^14.2.3",
|
||||
"@angular/language-service": "^14.2.3",
|
||||
"@nguniversal/builders": "^14.2.0",
|
||||
"@types/ckeditor": "^4.9.10",
|
||||
"@types/compression": "^1.7.0",
|
||||
"@types/express": "^4.17.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"@types/ckeditor": "^4.9.10",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
|
|
97
server.ts
97
server.ts
|
@ -1,14 +1,22 @@
|
|||
import 'zone.js/node';
|
||||
|
||||
import { ngExpressEngine } from '@nguniversal/express-engine';
|
||||
import {ngExpressEngine} from '@nguniversal/express-engine';
|
||||
import * as express from 'express';
|
||||
import * as compression from 'compression';
|
||||
import { join } from 'path';
|
||||
import {join} from 'path';
|
||||
|
||||
import { AppServerModule } from './src/main.server';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { existsSync } from 'fs';
|
||||
import {AppServerModule} from './src/main.server';
|
||||
import {APP_BASE_HREF} from '@angular/common';
|
||||
import {existsSync} from 'fs';
|
||||
import {REQUEST, RESPONSE} from "./src/app/openaireLibrary/utils/tokens";
|
||||
import {properties} from "./src/environments/environment";
|
||||
import axios, {AxiosHeaders} from "axios";
|
||||
import {Stakeholder} from "./src/app/openaireLibrary/monitor/entities/stakeholder";
|
||||
import {CacheIndicators} from "./src/cache-indicators";
|
||||
import {Session, User} from "./src/app/openaireLibrary/login/utils/helper.class";
|
||||
|
||||
var bodyParser = require('body-parser');
|
||||
var jsonParser = bodyParser.json();
|
||||
|
||||
// The Express app is exported so that it can be used by serverless Functions.
|
||||
export function app() {
|
||||
|
@ -16,23 +24,90 @@ export function app() {
|
|||
server.use(compression());
|
||||
const distFolder = join(process.cwd(), 'dist/monitor-dashboard/browser');
|
||||
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
|
||||
|
||||
let cacheIndicators: CacheIndicators = new CacheIndicators();
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
server.use('/cache', function (req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', req.headers.origin);
|
||||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
|
||||
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS, POST, DELETE');
|
||||
res.header('Access-Control-Max-Age', "1800");
|
||||
next();
|
||||
});
|
||||
|
||||
server.post('/cache/:alias', jsonParser, async (req, res) => {
|
||||
await checkPermissions(req, res, (stakeholder, user) => {
|
||||
if (cacheIndicators.completed(stakeholder._id)) {
|
||||
res.send({
|
||||
id: stakeholder._id,
|
||||
report: cacheIndicators.createReport(stakeholder._id, cacheIndicators.stakeholderToCacheItems(stakeholder), stakeholder.name, user.email)
|
||||
});
|
||||
} else {
|
||||
res.status(409).send('There is another active caching process for this stakeholder');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.get('/cache/:alias', async (req, res) => {
|
||||
await checkPermissions(req, res, stakeholder => {
|
||||
if (cacheIndicators.exists(stakeholder._id)) {
|
||||
res.send({
|
||||
id: stakeholder._id,
|
||||
report: cacheIndicators.getReport(stakeholder._id)
|
||||
});
|
||||
} else {
|
||||
res.status(404).send('There is not an active caching process for this stakeholder');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async function checkPermissions(req, res, access: (stakeholder, user) => void) {
|
||||
let headers: AxiosHeaders = new AxiosHeaders();
|
||||
headers.set('Cookie', req.headers.cookie);
|
||||
let userinfoRes = (await axios.get<any>(properties.userInfoUrl, {
|
||||
withCredentials: true,
|
||||
headers: headers
|
||||
}).catch(error => {
|
||||
return error.response;
|
||||
}));
|
||||
if (userinfoRes.status === 200) {
|
||||
let user = new User(userinfoRes.data);
|
||||
let stakeholderRes = (await axios.get<Stakeholder>(properties.monitorServiceAPIURL + '/stakeholder/' + encodeURIComponent(req.params.alias), {
|
||||
withCredentials: true,
|
||||
headers: headers
|
||||
}).catch(error => {
|
||||
return error.response;
|
||||
}));
|
||||
if (stakeholderRes.status === 200) {
|
||||
let stakeholder = stakeholderRes.data;
|
||||
if (Session.isPortalAdministrator(user) || Session.isCurator(stakeholder.type, user)) {
|
||||
access(stakeholder, user);
|
||||
} else {
|
||||
res.status(403).send('You are forbidden to access this resource');
|
||||
}
|
||||
} else {
|
||||
res.status(stakeholderRes.status).send(stakeholderRes.statusText);
|
||||
}
|
||||
} else {
|
||||
res.status(userinfoRes.status).send(userinfoRes.data.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Example Express Rest API endpoints
|
||||
// server.get('/api/**', (req, res) => { });
|
||||
// Serve static files from /browser
|
||||
server.get('*.*', express.static(distFolder, {
|
||||
maxAge: '1y'
|
||||
}));
|
||||
|
||||
|
||||
// All regular routes use the Universal engine
|
||||
server.get('*', (req, res) => {
|
||||
res.render(indexHtml, {
|
||||
|
@ -51,13 +126,13 @@ export function app() {
|
|||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
function run() {
|
||||
const port = process.env.PORT || 4000;
|
||||
|
||||
|
||||
// Start up the Node server
|
||||
const server = app();
|
||||
server.listen(port, () => {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
</main>
|
||||
<bottom id="bottom" *ngIf="isFrontPage" [centered]="true" [properties]="properties" [showMenuItems]="true"></bottom>
|
||||
<notification-sidebar *ngIf="!isMobile && user && notificationGroupsInitialized" [configuration]="notificationConfiguration" [user]="user"></notification-sidebar>
|
||||
<cache-indicators *ngIf="stakeholder && !isFrontPage && isCurator()" [alias]="stakeholder.alias"></cache-indicators>
|
||||
</div>
|
||||
<div *ngIf="view" class="preview uk-text-small uk-flex uk-flex-middle">
|
||||
<span>You are currently in a <span class="uk-text-bold">"Preview"</span> mode. <span class="uk-visible@m"><a (click)="removeView()">The current view</a> of this dashboard may differ.</span></span>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Data, NavigationEnd, Params, Router} from '@angular/router';
|
||||
import {EnvProperties} from './openaireLibrary/utils/properties/env-properties';
|
||||
import {Role, Session, User} from './openaireLibrary/login/utils/helper.class';
|
||||
|
@ -18,7 +18,6 @@ import {LinksResolver} from "./search/links-resolver";
|
|||
import {Header} from "./openaireLibrary/sharedComponents/navigationBar.component";
|
||||
import {properties} from "../environments/environment";
|
||||
import {ConfigurationService} from "./openaireLibrary/utils/configuration/configuration.service";
|
||||
import {Option} from "./openaireLibrary/sharedComponents/input/input.component";
|
||||
import {StakeholderUtils} from "./utils/indicator-utils";
|
||||
import {SmoothScroll} from "./openaireLibrary/utils/smooth-scroll";
|
||||
import {ConnectHelper} from "./openaireLibrary/connect/connectHelper";
|
||||
|
@ -343,7 +342,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
false, [], null, {resultbestaccessright: '"' + encodeURIComponent("Open Access") + '"'},
|
||||
null, null, null, null)
|
||||
);
|
||||
this.resourcesService.setResources(this.menuItems, "/" + this.stakeholder.alias);
|
||||
this.resourcesService.setResources(this.menuItems, '', this.monitorLink, '_blank');
|
||||
this.menuItems.push(new MenuItem("support", "Support", this.monitorLink + '/support/', "", false, [], null, {}));
|
||||
if (this.stakeholder.type === "funder") {
|
||||
this.menuItems.push(
|
||||
new MenuItem("develop", "Develop",
|
||||
|
@ -402,12 +402,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.monitorLink + '/browse', "", false, [], null, {}, null, null, null, null, "_self")
|
||||
);
|
||||
this.resourcesService.setResources(this.menuItems, '', this.monitorLink);
|
||||
let about = new MenuItem("about", "About", "", "", false, [], null, {});
|
||||
about.items = [
|
||||
new MenuItem("how-it-works", "How it works", this.monitorLink + '/about/how-it-works', "", false, [], null, {}, null, null, null, null, "_self"),
|
||||
new MenuItem("faqs", "FAQs", this.monitorLink + '/about/faqs',"", false, [], null, {}, null, null, null, null, "_self")
|
||||
]
|
||||
this.menuItems.push(about);
|
||||
this.menuItems.push(new MenuItem("support", "Support", this.monitorLink + '/support/', "", false, [], null, {}, null, null, null, null, "_self"));
|
||||
this.menuItems.push(new MenuItem("about", "About", this.monitorLink + '/about/', "", false, [], null, {}, null, null, null, null, "_self"));
|
||||
if (this.hasAdminMenu) {
|
||||
this.adminMenuItems = [];
|
||||
this.backItem = null;
|
||||
|
|
|
@ -29,9 +29,10 @@ import {LoginGuard} from "./openaireLibrary/login/loginGuard.guard";
|
|||
import {IconsModule} from "./openaireLibrary/utils/icons/icons.module";
|
||||
import {IconsService} from "./openaireLibrary/utils/icons/icons.service";
|
||||
import {incognito} from "./openaireLibrary/utils/icons/icons";
|
||||
import {CacheIndicatorsModule} from "./cache-indicators/cache-indicators.module";
|
||||
|
||||
@NgModule({
|
||||
|
||||
|
||||
imports: [
|
||||
SharedModule,
|
||||
BrowserAnimationsModule,
|
||||
|
@ -44,7 +45,7 @@ import {incognito} from "./openaireLibrary/utils/icons/icons";
|
|||
CookieLawModule,
|
||||
BrowserModule.withServerTransition({appId: 'serverApp'}),
|
||||
AppRoutingModule,
|
||||
SideBarModule, Schema2jsonldModule, RoleVerificationModule, LoadingModule, NotificationsSidebarModule, IconsModule
|
||||
SideBarModule, Schema2jsonldModule, RoleVerificationModule, LoadingModule, NotificationsSidebarModule, IconsModule, CacheIndicatorsModule
|
||||
],
|
||||
declarations: [AppComponent, OpenaireErrorPageComponent],
|
||||
exports: [AppComponent],
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
@import (reference) "~src/assets/openaire-theme/less/_import-variables.less";
|
||||
|
||||
.cache-progress {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: @global-z-index;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, PLATFORM_ID, SimpleChanges} from "@angular/core";
|
||||
import {Report} from "../../cache-indicators";
|
||||
import {CacheIndicatorsService} from "../utils/services/cache-indicators.service";
|
||||
import {interval, Subject, Subscription} from "rxjs";
|
||||
import {map, switchMap, takeUntil} from "rxjs/operators";
|
||||
|
||||
@Component({
|
||||
selector: 'cache-indicators',
|
||||
template: `
|
||||
<div *ngIf="report" class="cache-progress">
|
||||
<div class="uk-position-relative" [attr.uk-tooltip]="'Caching indicators process for ' + alias">
|
||||
<div class="uk-progress-circle" [attr.percentage]="report.percentage?report.percentage:0" [style]="'--percentage: ' + (report.percentage?report.percentage:0)"></div>
|
||||
<button *ngIf="report.percentage === 100" (click)="clear()" class="uk-icon-button uk-icon-button-xsmall uk-button-default uk-position-top-right"><icon name="close" [flex]="true" ratio="0.8"></icon></button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['cache-indicators.component.less']
|
||||
})
|
||||
export class CacheIndicatorsComponent implements OnInit, OnChanges, OnDestroy {
|
||||
report: Report;
|
||||
subscriptions: Subscription[] = [];
|
||||
interval: number = 10000;
|
||||
readonly destroy$ = new Subject();
|
||||
@Input() alias: string;
|
||||
|
||||
constructor(private cacheIndicatorsService: CacheIndicatorsService,
|
||||
@Inject(PLATFORM_ID) private platformId) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.getReport();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if(changes.alias) {
|
||||
this.getReport();
|
||||
}
|
||||
}
|
||||
|
||||
getReport() {
|
||||
this.clear();
|
||||
this.subscriptions.push(this.cacheIndicatorsService.getReport(this.alias).subscribe(report => {
|
||||
this.getReportInterval(report);
|
||||
}));
|
||||
}
|
||||
|
||||
getReportInterval(report: Report) {
|
||||
if(this.isBrowser && (this.report || !report?.completed)) {
|
||||
this.report = report;
|
||||
this.subscriptions.push(interval(this.interval).pipe(
|
||||
map(() => this.cacheIndicatorsService.getReport(this.alias)),
|
||||
switchMap(report => report),
|
||||
takeUntil(this.destroy$)).subscribe(report => {
|
||||
console.log(this.alias);
|
||||
this.report = report;
|
||||
if(this.report.completed) {
|
||||
this.destroy$.next();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.subscriptions.forEach(subscription => {
|
||||
subscription.unsubscribe();
|
||||
})
|
||||
this.report = null;
|
||||
}
|
||||
|
||||
|
||||
get isBrowser() {
|
||||
return this.platformId === 'browser';
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import {NgModule} from "@angular/core";
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {CacheIndicatorsComponent} from "./cache-indicators.component";
|
||||
import {IconsModule} from "../openaireLibrary/utils/icons/icons.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, IconsModule],
|
||||
declarations: [CacheIndicatorsComponent],
|
||||
exports: [CacheIndicatorsComponent]
|
||||
})
|
||||
export class CacheIndicatorsModule {}
|
|
@ -15,93 +15,106 @@ import {NotifyFormComponent} from "../../openaireLibrary/notifications/notify-fo
|
|||
import {NotificationUtils} from "../../openaireLibrary/notifications/notification-utils";
|
||||
import {Notification} from "../../openaireLibrary/notifications/notifications";
|
||||
import {NotificationHandler} from "../../openaireLibrary/utils/notification-handler";
|
||||
import {StatsProfilesService} from "../../utils/services/stats-profiles.service";
|
||||
|
||||
@Component({
|
||||
selector: 'edit-stakeholder',
|
||||
template: `
|
||||
<form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
|
||||
<div class="uk-grid uk-grid-large" uk-grid>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input id="name" [formInput]="stakeholderFb.get('name')"
|
||||
placeholder="Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input [formInput]="stakeholderFb.get('alias')"
|
||||
placeholder="URL Alias"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_id')"
|
||||
placeholder="Index ID"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_name')"
|
||||
placeholder="Index Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_shortName')"
|
||||
placeholder="Index Short Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<div input [type]="'textarea'" placeholder="Description"
|
||||
[rows]="4" [formInput]="stakeholderFb.get('description')"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
|
||||
<div *ngIf="!stakeholderFb.get('isUpload').value" class="uk-grid uk-grid-column-large" uk-grid>
|
||||
<div class="uk-margin-top uk-width-auto@l uk-width-1-1">
|
||||
<div class="uk-grid uk-grid-column-large uk-flex-middle" uk-grid>
|
||||
<div class="uk-width-auto@l uk-width-1-1 uk-flex uk-flex-center">
|
||||
<button class="uk-button uk-button-primary uk-flex uk-flex-middle uk-flex-wrap"
|
||||
(click)="file.click()">
|
||||
<icon name="cloud_upload" [flex]="true"></icon>
|
||||
<span class="uk-margin-small-left">Upload a file</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="uk-text-center uk-text-bold uk-width-expand">
|
||||
OR
|
||||
</div>
|
||||
<form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
|
||||
<div class="uk-grid uk-grid-large" uk-grid>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input id="name" [formInput]="stakeholderFb.get('name')"
|
||||
placeholder="Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input [formInput]="stakeholderFb.get('alias')"
|
||||
placeholder="URL Alias"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_id')"
|
||||
placeholder="Index ID"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_name')"
|
||||
placeholder="Index Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-3@m">
|
||||
<div input [formInput]="stakeholderFb.get('index_shortName')"
|
||||
placeholder="Index Short Name"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div *ngIf="statsProfiles" input [formInput]="stakeholderFb.get('statsProfile')" [type]="'select'"
|
||||
[options]="statsProfiles"
|
||||
placeholder="Stats Profile"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input [formInput]="stakeholderFb.get('locale')" [type]="'select'"
|
||||
[options]="stakeholderUtils.locales"
|
||||
placeholder="Locale"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<div input [type]="'textarea'" placeholder="Description"
|
||||
[rows]="4" [formInput]="stakeholderFb.get('description')"></div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
|
||||
<div *ngIf="!stakeholderFb.get('isUpload').value" class="uk-grid uk-grid-column-large" uk-grid>
|
||||
<div class="uk-margin-top uk-width-auto@l uk-width-1-1">
|
||||
<div class="uk-grid uk-grid-column-large uk-flex-middle" uk-grid>
|
||||
<div class="uk-width-auto@l uk-width-1-1 uk-flex uk-flex-center">
|
||||
<button class="uk-button uk-button-primary uk-flex uk-flex-middle uk-flex-wrap"
|
||||
(click)="file.click()">
|
||||
<icon name="cloud_upload" [flex]="true"></icon>
|
||||
<span class="uk-margin-small-left">Upload a file</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="uk-text-center uk-text-bold uk-width-expand">
|
||||
OR
|
||||
</div>
|
||||
</div>
|
||||
<div input class="uk-width-expand" type="logoURL" [placeholder]="'Link to the logo'" [formInput]="stakeholderFb.get('logoUrl')"></div>
|
||||
</div>
|
||||
<div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle">
|
||||
<div class="uk-card uk-card-default uk-text-center uk-border-circle">
|
||||
<img class="uk-position-center uk-blend-multiply" [src]="photo">
|
||||
</div>
|
||||
<div class="uk-margin-left">
|
||||
<button (click)="remove()" class="uk-button-danger uk-icon-button uk-icon-button-small">
|
||||
<icon [flex]="true" ratio="0.8" name="delete"></icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="uk-margin-small-left">
|
||||
<button class="uk-button-secondary uk-icon-button uk-icon-button-small" (click)="file.click()">
|
||||
<icon [flex]="true" ratio="0.8" name="edit"></icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Full width error message -->
|
||||
<div *ngIf="uploadError" class="uk-text-danger uk-margin-small-top uk-width-1-1">{{uploadError}}</div>
|
||||
</div>
|
||||
<div [class]="canChooseType ? 'uk-width-1-3@m' : 'uk-width-1-2@m'">
|
||||
<div input [formInput]="stakeholderFb.get('visibility')"
|
||||
[placeholder]="'Select a status'"
|
||||
[options]="stakeholderUtils.statuses" type="select"></div>
|
||||
</div>
|
||||
<div [class]="canChooseType ? 'uk-width-1-3@m' : 'uk-width-1-2@m'">
|
||||
<div input [formInput]="stakeholderFb.get('type')"
|
||||
[placeholder]="'Select a type'"
|
||||
[options]="types" type="select"></div>
|
||||
</div>
|
||||
<ng-container *ngIf="canChooseType">
|
||||
<div class="uk-width-1-3@m">
|
||||
<div [placeholder]="'Select a template'"
|
||||
input [formInput]="stakeholderFb.get('defaultId')"
|
||||
[options]="defaultStakeholdersOptions" type="select"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div input class="uk-width-expand" type="logoURL" [placeholder]="'Link to the logo'"
|
||||
[formInput]="stakeholderFb.get('logoUrl')"></div>
|
||||
</div>
|
||||
<div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle">
|
||||
<div class="uk-card uk-card-default uk-text-center uk-border-circle">
|
||||
<img class="uk-position-center uk-blend-multiply" [src]="photo">
|
||||
</div>
|
||||
<div class="uk-margin-left">
|
||||
<button (click)="remove()" class="uk-button-danger uk-icon-button uk-icon-button-small">
|
||||
<icon [flex]="true" ratio="0.8" name="delete"></icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="uk-margin-small-left">
|
||||
<button class="uk-button-secondary uk-icon-button uk-icon-button-small" (click)="file.click()">
|
||||
<icon [flex]="true" ratio="0.8" name="edit"></icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Full width error message -->
|
||||
<div *ngIf="uploadError" class="uk-text-danger uk-margin-small-top uk-width-1-1">{{uploadError}}</div>
|
||||
</div>
|
||||
</form>
|
||||
<div #notify [class.uk-hidden]="!stakeholderFb" notify-form class="uk-width-1-1 uk-margin-large-top uk-margin-medium-bottom"></div>
|
||||
<div [class]="canChooseTemplate ? 'uk-width-1-3@m' : 'uk-width-1-2@m'">
|
||||
<div input [formInput]="stakeholderFb.get('visibility')"
|
||||
[placeholder]="'Select a status'"
|
||||
[options]="stakeholderUtils.statuses" type="select"></div>
|
||||
</div>
|
||||
<div [class]="canChooseTemplate ? 'uk-width-1-3@m' : 'uk-width-1-2@m'">
|
||||
<div input [formInput]="stakeholderFb.get('type')"
|
||||
[placeholder]="'Select a type'"
|
||||
[options]="types" type="select"></div>
|
||||
</div>
|
||||
<ng-container *ngIf="canChooseTemplate">
|
||||
<div class="uk-width-1-3@m">
|
||||
<div [placeholder]="'Select a template'"
|
||||
input [formInput]="stakeholderFb.get('defaultId')"
|
||||
[options]="defaultStakeholdersOptions" type="select"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</form>
|
||||
<div #notify [class.uk-hidden]="!stakeholderFb" notify-form
|
||||
class="uk-width-1-1 uk-margin-large-top uk-margin-medium-bottom"></div>
|
||||
`,
|
||||
styleUrls: ['edit-stakeholder.component.less']
|
||||
})
|
||||
|
@ -117,8 +130,9 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
public stakeholder: Stakeholder;
|
||||
public isDefault: boolean;
|
||||
public isNew: boolean;
|
||||
public loading: boolean = false;
|
||||
public loading: boolean = false;
|
||||
public types: Option[];
|
||||
public statsProfiles: string[];
|
||||
public properties: EnvProperties = properties;
|
||||
private subscriptions: any[] = [];
|
||||
/**
|
||||
|
@ -130,11 +144,12 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
public deleteCurrentPhoto: boolean = false;
|
||||
private maxsize: number = 200 * 1024;
|
||||
user: User;
|
||||
@ViewChild('notify', { static: true }) notify: NotifyFormComponent;
|
||||
@ViewChild('notify', {static: true}) notify: NotifyFormComponent;
|
||||
private notification: Notification;
|
||||
|
||||
constructor(private fb: UntypedFormBuilder,
|
||||
private stakeholderService: StakeholderService,
|
||||
private statsProfileService: StatsProfilesService,
|
||||
private utilsService: UtilitiesService, private userManagementService: UserManagementService,) {
|
||||
}
|
||||
|
||||
|
@ -151,92 +166,110 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
this.isDefault = isDefault;
|
||||
this.isNew = isNew;
|
||||
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
|
||||
this.user = user;
|
||||
this.types = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias);
|
||||
this.stakeholderFb = this.fb.group({
|
||||
_id: this.fb.control(this.stakeholder._id),
|
||||
defaultId: this.fb.control(this.stakeholder.defaultId),
|
||||
name: this.fb.control(this.stakeholder.name, Validators.required),
|
||||
description: this.fb.control(this.stakeholder.description),
|
||||
index_name: this.fb.control(this.stakeholder.index_name, Validators.required),
|
||||
index_id: this.fb.control(this.stakeholder.index_id, Validators.required),
|
||||
index_shortName: this.fb.control(this.stakeholder.index_shortName, Validators.required),
|
||||
creationDate: this.fb.control(this.stakeholder.creationDate),
|
||||
alias: this.fb.control(this.stakeholder.alias,
|
||||
[
|
||||
Validators.required,
|
||||
this.stakeholderUtils.aliasValidatorString(
|
||||
this.alias.filter(alias => alias !== this.stakeholder.alias)
|
||||
)]
|
||||
),
|
||||
isDefault: this.fb.control((this.isDefault)),
|
||||
visibility: this.fb.control(this.stakeholder.visibility, Validators.required),
|
||||
type: this.fb.control(this.stakeholder.type, Validators.required),
|
||||
topics: this.fb.control(this.stakeholder.topics),
|
||||
isUpload: this.fb.control(this.stakeholder.isUpload),
|
||||
logoUrl: this.fb.control(this.stakeholder.logoUrl),
|
||||
});
|
||||
if (this.stakeholder.isUpload) {
|
||||
this.user = user;
|
||||
if (this.isCurator) {
|
||||
this.subscriptions.push(this.statsProfileService.getStatsProfiles().subscribe(statsProfiles => {
|
||||
this.statsProfiles = statsProfiles;
|
||||
}, error => {
|
||||
this.statsProfiles = [];
|
||||
}));
|
||||
} else {
|
||||
this.statsProfiles = [];
|
||||
}
|
||||
this.types = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias);
|
||||
this.stakeholderFb = this.fb.group({
|
||||
_id: this.fb.control(this.stakeholder._id),
|
||||
defaultId: this.fb.control(this.stakeholder.defaultId),
|
||||
name: this.fb.control(this.stakeholder.name, Validators.required),
|
||||
description: this.fb.control(this.stakeholder.description),
|
||||
index_name: this.fb.control(this.stakeholder.index_name, Validators.required),
|
||||
index_id: this.fb.control(this.stakeholder.index_id, Validators.required),
|
||||
index_shortName: this.fb.control(this.stakeholder.index_shortName, Validators.required),
|
||||
statsProfile: this.fb.control(this.stakeholder.statsProfile, Validators.required),
|
||||
locale: this.fb.control(this.stakeholder.locale, Validators.required),
|
||||
creationDate: this.fb.control(this.stakeholder.creationDate),
|
||||
alias: this.fb.control(this.stakeholder.alias,
|
||||
[
|
||||
Validators.required,
|
||||
this.stakeholderUtils.aliasValidatorString(
|
||||
this.alias.filter(alias => alias !== this.stakeholder.alias)
|
||||
)]
|
||||
),
|
||||
isDefault: this.fb.control((this.isDefault)),
|
||||
visibility: this.fb.control(this.stakeholder.visibility, Validators.required),
|
||||
type: this.fb.control(this.stakeholder.type, Validators.required),
|
||||
topics: this.fb.control(this.stakeholder.topics),
|
||||
isUpload: this.fb.control(this.stakeholder.isUpload),
|
||||
logoUrl: this.fb.control(this.stakeholder.logoUrl),
|
||||
});
|
||||
if (this.stakeholder.isUpload) {
|
||||
this.stakeholderFb.get('logoUrl').clearValidators();
|
||||
this.stakeholderFb.get('logoUrl').updateValueAndValidity();
|
||||
} else {
|
||||
this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
|
||||
this.stakeholderFb.get('logoUrl').updateValueAndValidity();
|
||||
}
|
||||
this.subscriptions.push(this.stakeholderFb.get('isUpload').valueChanges.subscribe(value => {
|
||||
if (value == true) {
|
||||
this.stakeholderFb.get('logoUrl').clearValidators();
|
||||
this.stakeholderFb.get('logoUrl').updateValueAndValidity();
|
||||
this.stakeholderFb.updateValueAndValidity();
|
||||
} else {
|
||||
this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
|
||||
this.stakeholderFb.get('logoUrl').updateValueAndValidity();
|
||||
this.stakeholderFb.updateValueAndValidity();
|
||||
}
|
||||
this.subscriptions.push(this.stakeholderFb.get('isUpload').valueChanges.subscribe(value => {
|
||||
if (value == true) {
|
||||
this.stakeholderFb.get('logoUrl').clearValidators();
|
||||
this.stakeholderFb.updateValueAndValidity();
|
||||
} else {
|
||||
this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
|
||||
this.stakeholderFb.updateValueAndValidity();
|
||||
}
|
||||
}));
|
||||
this.secure = (!this.stakeholderFb.get('logoUrl').value || this.stakeholderFb.get('logoUrl').value.includes('https://'));
|
||||
this.subscriptions.push(this.stakeholderFb.get('logoUrl').valueChanges.subscribe(value => {
|
||||
this.secure = (!value || value.includes('https://'));
|
||||
}));
|
||||
this.initPhoto();
|
||||
if (!isDefault) {
|
||||
this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => {
|
||||
this.onTypeChange(value, defaultStakeholders);
|
||||
}));
|
||||
this.stakeholderFb.setControl('defaultId', this.fb.control(stakeholder.defaultId, Validators.required));
|
||||
}
|
||||
if (!isNew) {
|
||||
this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
|
||||
this.notify.reset(this.notification.message);
|
||||
if (this.isAdmin) {
|
||||
if (this.disableAlias) {
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('alias').disable();
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
}));
|
||||
this.secure = (!this.stakeholderFb.get('logoUrl').value || this.stakeholderFb.get('logoUrl').value.includes('https://'));
|
||||
this.subscriptions.push(this.stakeholderFb.get('logoUrl').valueChanges.subscribe(value => {
|
||||
this.secure = (!value || value.includes('https://'));
|
||||
}));
|
||||
this.initPhoto();
|
||||
this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => {
|
||||
this.onTypeChange(value, defaultStakeholders);
|
||||
}));
|
||||
this.stakeholderFb.setControl('defaultId', this.fb.control(stakeholder.defaultId, (this.isDefault && !this.isNew)?[]:Validators.required));
|
||||
if (!this.isNew) {
|
||||
this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
|
||||
this.notify.reset(this.notification.message);
|
||||
if (this.isAdmin) {
|
||||
if (this.disableAlias) {
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('alias').disable();
|
||||
this.stakeholderFb.get('index_id').disable();
|
||||
this.stakeholderFb.get('index_name').disable();
|
||||
this.stakeholderFb.get('index_shortName').disable();
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
if (!this.isCurator) {
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('statsProfile').disable();
|
||||
}, 0);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('type').disable();
|
||||
}, 0);
|
||||
} else {
|
||||
this.notification = NotificationUtils.createStakeholder(this.user.firstname + ' ' + this.user.lastname);
|
||||
this.notify.reset(this.notification.message);
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('type').enable();
|
||||
this.stakeholderFb.get('alias').disable();
|
||||
this.stakeholderFb.get('index_id').disable();
|
||||
this.stakeholderFb.get('index_name').disable();
|
||||
this.stakeholderFb.get('index_shortName').disable();
|
||||
}, 0);
|
||||
}
|
||||
}));
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('type').disable();
|
||||
}, 0);
|
||||
} else {
|
||||
this.notification = NotificationUtils.createStakeholder(this.user.firstname + ' ' + this.user.lastname);
|
||||
this.notify.reset(this.notification.message);
|
||||
setTimeout(() => {
|
||||
this.stakeholderFb.get('type').enable();
|
||||
}, 0);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public get isAdmin() {
|
||||
return Session.isPortalAdministrator(this.user);
|
||||
}
|
||||
|
||||
public get isCurator() {
|
||||
return this.stakeholder && (this.isAdmin || Session.isCurator(this.stakeholder.type, this.user));
|
||||
}
|
||||
|
||||
public get disabled(): boolean {
|
||||
return (this.stakeholderFb && this.stakeholderFb.invalid) ||
|
||||
(this.stakeholderFb && this.stakeholderFb.pristine && !this.isNew && !this.file) ||
|
||||
|
@ -247,8 +280,8 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
return this.stakeholderFb && this.stakeholderFb.dirty;
|
||||
}
|
||||
|
||||
public get canChooseType(): boolean {
|
||||
return !this.stakeholderFb.get('isDefault').value && this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions;
|
||||
public get canChooseTemplate(): boolean {
|
||||
return this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions;
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
@ -262,7 +295,7 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
onTypeChange(value, defaultStakeholders: Stakeholder[]) {
|
||||
this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, Validators.required));
|
||||
this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, (this.isDefault && !this.isNew)?[]:Validators.required));
|
||||
this.defaultStakeholdersOptions = [{
|
||||
label: 'New blank profile',
|
||||
value: '-1'
|
||||
|
@ -276,7 +309,7 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
public save(callback: Function, errorCallback: Function = null) {
|
||||
this.loading = true;
|
||||
this.loading = true;
|
||||
if (this.file) {
|
||||
this.subscriptions.push(this.utilsService.uploadPhoto(this.properties.utilsService + "/upload/" + encodeURIComponent(this.stakeholderFb.getRawValue().type) + "/" + encodeURIComponent(this.stakeholderFb.getRawValue().alias), this.file).subscribe(res => {
|
||||
this.deletePhoto();
|
||||
|
@ -297,12 +330,13 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
|
||||
public saveStakeholder(callback: Function, errorCallback: Function = null) {
|
||||
if (this.isNew) {
|
||||
if (!this.stakeholderFb.getRawValue().isDefault) {
|
||||
let stakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId);
|
||||
this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(),
|
||||
(stakeholder ? stakeholder.topics : [])));
|
||||
}
|
||||
let defaultStakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId);
|
||||
this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(),
|
||||
(defaultStakeholder ? defaultStakeholder.topics : []), this.stakeholderFb.getRawValue().isDefault));
|
||||
this.removePhoto();
|
||||
if(this.stakeholderFb.getRawValue().isDefault) {
|
||||
this.stakeholderFb.get('defaultId').setValue(null);
|
||||
}
|
||||
this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL,
|
||||
this.stakeholderFb.getRawValue()).subscribe(stakeholder => {
|
||||
this.notification.entity = stakeholder._id;
|
||||
|
@ -312,13 +346,13 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
this.notify.sendNotification(this.notification);
|
||||
NotificationHandler.rise(stakeholder.name + ' has been <b>successfully created</b>');
|
||||
callback(stakeholder);
|
||||
this.loading = false;
|
||||
this.loading = false;
|
||||
}, error => {
|
||||
NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
|
||||
if (errorCallback) {
|
||||
errorCallback(error)
|
||||
}
|
||||
this.loading = false;
|
||||
this.loading = false;
|
||||
}));
|
||||
} else {
|
||||
this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.stakeholderFb.getRawValue()).subscribe(stakeholder => {
|
||||
|
@ -328,14 +362,14 @@ export class EditStakeholderComponent implements OnDestroy {
|
|||
this.notification.groups = [Role.curator(stakeholder.type), Role.manager(stakeholder.type, stakeholder.alias)];
|
||||
this.notify.sendNotification(this.notification);
|
||||
NotificationHandler.rise(stakeholder.name + ' has been <b>successfully saved</b>');
|
||||
callback(stakeholder);
|
||||
this.loading = false;
|
||||
callback(stakeholder);
|
||||
this.loading = false;
|
||||
}, error => {
|
||||
NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
|
||||
if (errorCallback) {
|
||||
errorCallback(error)
|
||||
}
|
||||
this.loading = false;
|
||||
this.loading = false;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
<li>
|
||||
<a (click)="editStakeholder(stakeholder, !stakeholder.defaultId); hide(element)">Edit</a>
|
||||
</li>
|
||||
<li *ngIf="isCurator">
|
||||
<a (click)="createReport(stakeholder);hide(element)">Cache Indicators</a>
|
||||
</li>
|
||||
<li class="uk-nav-divider"></li>
|
||||
<ng-template ngFor [ngForOf]="stakeholderUtils.visibility" let-v>
|
||||
<li [class.uk-active]="stakeholder.visibility === v.value">
|
||||
|
|
|
@ -13,6 +13,8 @@ import {Session} from "../openaireLibrary/login/utils/helper.class";
|
|||
import {EditStakeholderComponent} from "../general/edit-stakeholder/edit-stakeholder.component";
|
||||
import {properties} from "../../environments/environment";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {CacheIndicatorsService} from "../utils/services/cache-indicators.service";
|
||||
import {NotificationHandler} from "../openaireLibrary/utils/notification-handler";
|
||||
|
||||
type Tab = 'all' | 'templates'| 'profiles';
|
||||
|
||||
|
@ -62,6 +64,7 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
|
|||
@ViewChild('editStakeholderComponent', { static: true }) editStakeholderComponent: EditStakeholderComponent;
|
||||
|
||||
constructor(private stakeholderService: StakeholderService,
|
||||
private cacheIndicatorsService: CacheIndicatorsService,
|
||||
private userManagementService: UserManagementService,
|
||||
private route: ActivatedRoute,
|
||||
private title: Title,
|
||||
|
@ -202,6 +205,15 @@ export class ManageStakeholdersComponent implements OnInit, OnDestroy {
|
|||
this.editStakeholderModal.open();
|
||||
}
|
||||
|
||||
public createReport(stakeholder: Stakeholder) {
|
||||
this.cacheIndicatorsService.createReport(stakeholder.alias).subscribe(report => {
|
||||
NotificationHandler.rise('A caching process for ' + stakeholder.name + ' has been started.' )
|
||||
}, error => {
|
||||
console.log(error);
|
||||
NotificationHandler.rise(error.message(), 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
public deleteStakeholderOpen(stakeholder: Stakeholder) {
|
||||
this.stakeholder = stakeholder;
|
||||
this.deleteStakeholderModal.alertTitle = 'Delete ' + this.stakeholder.index_name;
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
class="uk-text-small uk-text-truncate uk-margin-xsmall-bottom uk-margin-right">{{indicator.name}}</div>
|
||||
<div class="number uk-text-small uk-text-bold">
|
||||
<span *ngIf="numberResults.get(i + '-' + j)"
|
||||
[innerHTML]="numberResults.get(i + '-' + j) | numberRound: 2:1"></span>
|
||||
[innerHTML]="(indicator.indicatorPaths[0].format == 'NUMBER'?(numberResults.get(i + '-' + j) | numberRound: 2:1:stakeholder.locale):(numberResults.get(i + '-' + j) | numberPercentage: stakeholder.locale))"></span>
|
||||
<span *ngIf="!numberResults.get(i + '-' + j)">--</span>
|
||||
</div>
|
||||
<div *ngIf="indicator.description || indicator.additionalDescription"
|
||||
|
@ -159,7 +159,7 @@
|
|||
class="uk-text-xsmall uk-text-truncate uk-margin-xsmall-bottom uk-margin-right">{{indicator.name}}</div>
|
||||
<div class="number uk-text-small uk-text-bold">
|
||||
<span *ngIf="numberResults.get(i + '-' + j)"
|
||||
[innerHTML]="numberResults.get(i + '-' + j) | numberRound: 2:1"></span>
|
||||
[innerHTML]="(indicator.indicatorPaths[0].format == 'NUMBER'?(numberResults.get(i + '-' + j) | numberRound: 2:1:stakeholder.locale):(numberResults.get(i + '-' + j) | numberPercentage: stakeholder.locale))"></span>
|
||||
<span *ngIf="!numberResults.get(i + '-' + j)">--</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -485,7 +485,7 @@ export class MonitorComponent implements OnInit, OnDestroy {
|
|||
urls.forEach((indexes, pair) => {
|
||||
pair = JSON.parse(pair);
|
||||
let activeSubcategory = this.activeSubCategory._id;
|
||||
this.subscriptions.push(this.statisticsService.getNumbers(this.statisticsService.getSourceType(pair[0]), pair[1]).subscribe(response => {
|
||||
this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => {
|
||||
if(activeSubcategory === this.activeSubCategory._id) {
|
||||
indexes.forEach(([i, j]) => {
|
||||
if( this.activeSubCategory?.numbers[i]?.indicators[j]) {
|
||||
|
@ -524,7 +524,7 @@ export class MonitorComponent implements OnInit, OnDestroy {
|
|||
|
||||
public getUrlByStakeHolder(indicatorPath: IndicatorPath) {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(
|
||||
this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath, this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded())));
|
||||
this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath, this.getfl0(), this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, this.getCoFunded())));
|
||||
}
|
||||
|
||||
public setActiveChart(i: number, j: number, type: string) {
|
||||
|
|
|
@ -15,14 +15,14 @@ import {RouterModule} from "@angular/router";
|
|||
{ path: 'advanced/dataproviders', loadChildren: () => import('./searchPages/advanced/searchDataProviders.module').then(m => m.MonitorAdvancedSearchDataProvidersModule)},
|
||||
{ path: 'advanced/organizations', loadChildren: () => import('./searchPages/advanced/searchOrganizations.module').then(m => m.MonitorAdvancedSearchOrganizationsModule)},
|
||||
// Landing Pages
|
||||
{ path: 'result', loadChildren: () => import('./landingPages/result/libResult.module').then(m => m.LibResultModule)},
|
||||
{ path: 'publication', loadChildren: () => import('./landingPages/publication/libPublication.module').then(m => m.LibPublicationModule)},
|
||||
{ path: 'dataset', loadChildren: () => import('./landingPages/dataset/libDataset.module').then(m => m.LibDatasetModule)},
|
||||
{ path: 'software', loadChildren: () => import('./landingPages/software/libSoftware.module').then(m => m.LibSoftwareModule)},
|
||||
{ path: 'other', loadChildren: () => import('./landingPages/orp/libOrp.module').then(m => m.LibOrpModule)},
|
||||
{ path: 'project', loadChildren: () => import('./landingPages/project/libProject.module').then(m => m.LibProjectModule)},
|
||||
{ path: 'dataprovider', loadChildren: () => import('./landingPages/dataProvider/libDataProvider.module').then(m => m.LibDataProviderModule)},
|
||||
{ path: 'organization', loadChildren: () => import('./landingPages/organization/libOrganization.module').then(m => m.LibOrganizationModule)},
|
||||
{ path: 'result', loadChildren: () => import('./landingPages/result/libResult.module').then(m => m.LibResultModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'publication', loadChildren: () => import('./landingPages/publication/libPublication.module').then(m => m.LibPublicationModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'dataset', loadChildren: () => import('./landingPages/dataset/libDataset.module').then(m => m.LibDatasetModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'software', loadChildren: () => import('./landingPages/software/libSoftware.module').then(m => m.LibSoftwareModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'other', loadChildren: () => import('./landingPages/orp/libOrp.module').then(m => m.LibOrpModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'project', loadChildren: () => import('./landingPages/project/libProject.module').then(m => m.LibProjectModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'dataprovider', loadChildren: () => import('./landingPages/dataProvider/libDataProvider.module').then(m => m.LibDataProviderModule), data: {hasMenuSearchBar: true}},
|
||||
{ path: 'organization', loadChildren: () => import('./landingPages/organization/libOrganization.module').then(m => m.LibOrganizationModule), data: {hasMenuSearchBar: true}},
|
||||
])]
|
||||
})
|
||||
export class SearchModule {}
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
</div>
|
||||
<div class="uk-text-small uk-text-truncate uk-margin-xsmall-bottom uk-margin-right">{{indicator.name}}</div>
|
||||
<div class="number uk-text-small uk-text-bold">
|
||||
<span *ngIf="numberResults.get(i + '-' + j)" [innerHTML]="numberResults.get(i + '-' + j) | numberRound: 2:1"></span>
|
||||
<span *ngIf="numberResults.get(i + '-' + j)" [innerHTML]="(indicator.indicatorPaths[0].format == 'NUMBER'?(numberResults.get(i + '-' + j) | numberRound: 2:1:stakeholder.locale):(numberResults.get(i + '-' + j) | numberPercentage: stakeholder.locale))"></span>
|
||||
<span *ngIf="!numberResults.get(i + '-' + j)">--</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -257,11 +257,16 @@
|
|||
now</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-1">
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input [formInput]="indicatorPath.get('source')" placeholder="Source"
|
||||
[options]="isAdministrator?indicatorUtils.allSourceTypes:indicatorUtils.sourceTypes" type="select">
|
||||
</div>
|
||||
</div>
|
||||
<div class="uk-width-1-2@m">
|
||||
<div input [formInput]="indicatorPath.get('format')" placeholder="Format"
|
||||
[options]="indicatorUtils.formats" type="select">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div formArrayName="jsonPath" class="uk-width-1-1">
|
||||
|
@ -297,8 +302,8 @@
|
|||
<div class="uk-width-1-1 uk-flex uk-flex-center">
|
||||
<div class="uk-flex uk-position-relative">
|
||||
<span class="uk-padding number number-preview uk-flex uk-flex-column uk-flex-center uk-text-center">
|
||||
<span *ngIf="numberIndicatorPaths.at(i).get('result').valid && numberIndicatorPaths.at(i).get('result').value !== 0">
|
||||
{{numberIndicatorPaths.at(i).get('result').value | number}}
|
||||
<span *ngIf="numberIndicatorPaths.at(i).get('result').valid && numberIndicatorPaths.at(i).get('result').value !== 0"
|
||||
[innerHTML]="(numberIndicatorPaths.at(i).get('format').value == 'NUMBER'?(numberIndicatorPaths.at(i).get('result').value | numberRound: 2:1:stakeholder.locale):(numberIndicatorPaths.at(i).get('result').value | numberPercentage: stakeholder.locale))">
|
||||
</span>
|
||||
<span *ngIf="numberIndicatorPaths.at(i).get('result').valid && numberIndicatorPaths.at(i).get('result').value === 0">
|
||||
--
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
ViewChild
|
||||
} from "@angular/core";
|
||||
import {
|
||||
Format,
|
||||
Indicator,
|
||||
IndicatorPath,
|
||||
IndicatorSize,
|
||||
|
@ -20,7 +21,14 @@ import {
|
|||
Visibility
|
||||
} from "../openaireLibrary/monitor/entities/stakeholder";
|
||||
import {IndicatorUtils, StakeholderUtils} from "../utils/indicator-utils";
|
||||
import {AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators} from "@angular/forms";
|
||||
import {
|
||||
AbstractControl,
|
||||
UntypedFormArray,
|
||||
UntypedFormBuilder,
|
||||
UntypedFormControl,
|
||||
UntypedFormGroup,
|
||||
Validators
|
||||
} from "@angular/forms";
|
||||
import {AlertModal} from "../openaireLibrary/utils/modal/alert";
|
||||
import {StatisticsService} from "../utils/services/statistics.service";
|
||||
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
|
||||
|
@ -96,9 +104,9 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
@ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent;
|
||||
@ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent;
|
||||
@ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent;
|
||||
|
||||
|
||||
public isFullscreen: boolean = false;
|
||||
|
||||
|
||||
@HostListener('fullscreenchange', ['$event'])
|
||||
@HostListener('webkitfullscreenchange', ['$event'])
|
||||
@HostListener('mozfullscreenchange', ['$event'])
|
||||
|
@ -106,14 +114,14 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
screenChange(event) {
|
||||
this.isFullscreen = !this.isFullscreen;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subscriptions
|
||||
**/
|
||||
private subscriptions: any[] = [];
|
||||
private urlSubscriptions: any[] = [];
|
||||
private numberSubscription: any[] = [];
|
||||
|
||||
|
||||
constructor(private layoutService: LayoutService,
|
||||
private stakeholderService: StakeholderService,
|
||||
private statisticsService: StatisticsService,
|
||||
|
@ -124,7 +132,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
private sanitizer: DomSanitizer) {
|
||||
this.filesToUpload = [];
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.stakeholder) {
|
||||
this.setCharts();
|
||||
|
@ -136,7 +144,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.initReorder();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscriptions.forEach(value => {
|
||||
if (value instanceof Subscriber) {
|
||||
|
@ -156,11 +164,11 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.initReorder();
|
||||
}
|
||||
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (this.canEdit) {
|
||||
if (changes.topicIndex || changes.categoryIndex || changes.subcategoryIndex) {
|
||||
|
@ -170,7 +178,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
initReorder() {
|
||||
this.subscriptions.forEach(value => {
|
||||
if (value instanceof Function) {
|
||||
|
@ -223,11 +231,11 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hide(element: any) {
|
||||
UIkit.dropdown(element).hide();
|
||||
}
|
||||
|
||||
|
||||
setCharts() {
|
||||
this.chartSections = this.fb.array([]);
|
||||
this.charts.forEach(section => {
|
||||
|
@ -251,7 +259,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
setNumbers() {
|
||||
this.numberSections = this.fb.array([]);
|
||||
this.numberResults.clear();
|
||||
|
@ -267,7 +275,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
indicators: this.fb.control(section.indicators)
|
||||
}));
|
||||
section.indicators.forEach((number, j) => {
|
||||
let url = this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, number.indicatorPaths[0]);
|
||||
let url = this.indicatorUtils.getFullUrl(this.stakeholder, number.indicatorPaths[0]);
|
||||
const pair = JSON.stringify([number.indicatorPaths[0].source, url]);
|
||||
const indexes = urls.get(pair) ? urls.get(pair) : [];
|
||||
indexes.push([i, j]);
|
||||
|
@ -285,14 +293,14 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
if (response) {
|
||||
this.calculateResults(response, indexes);
|
||||
} else {
|
||||
this.numberSubscription.push(this.statisticsService.getNumbers(this.statisticsService.getSourceType(parsed[0]), parsed[1]).subscribe(response => {
|
||||
this.numberSubscription.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(parsed[0]), parsed[1]).subscribe(response => {
|
||||
this.calculateResults(response, indexes);
|
||||
this.numberResponses.set(pair, response);
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private calculateResults(response: any, indexes: [number, number][]) {
|
||||
indexes.forEach(([i, j]) => {
|
||||
let result = JSON.parse(JSON.stringify(response));
|
||||
|
@ -312,7 +320,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.numberResults.set(i + '-' + j, result);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
get charts(): Section[] {
|
||||
if (this.stakeholder.topics[this.topicIndex] &&
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
|
||||
|
@ -322,7 +330,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
get numbers(): Section[] {
|
||||
if (this.stakeholder.topics[this.topicIndex] &&
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
|
||||
|
@ -332,30 +340,30 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set numbers(sections: Section[]) {
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers = sections;
|
||||
}
|
||||
|
||||
|
||||
get open(): boolean {
|
||||
return this.layoutService.open;
|
||||
}
|
||||
|
||||
|
||||
get canEdit() {
|
||||
return this.stakeholder &&
|
||||
this.stakeholder.topics[this.topicIndex] &&
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] &&
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex];
|
||||
}
|
||||
|
||||
|
||||
public get numberIndicatorPaths(): UntypedFormArray {
|
||||
return this.numberIndicatorFb.get('indicatorPaths') as UntypedFormArray;
|
||||
}
|
||||
|
||||
|
||||
public get chartIndicatorPaths(): UntypedFormArray {
|
||||
return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray;
|
||||
}
|
||||
|
||||
|
||||
public getNumberClassBySize(size: IndicatorSize) {
|
||||
if (size === 'small') {
|
||||
return 'uk-width-medium@m uk-width-1-1';
|
||||
|
@ -365,7 +373,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return 'uk-width-1-2@l uk-width-1-1@m uk-width-1-1';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public getChartClassBySize(size: IndicatorSize) {
|
||||
if (size === 'small') {
|
||||
return 'uk-width-1-3@xl uk-width-1-2@m uk-width-1-1';
|
||||
|
@ -375,7 +383,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return 'uk-width-1-1';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public addJsonPath(index: number) {
|
||||
if (index == 0 && this.getJsonPath(index).getRawValue()[index].indexOf(",") != -1) {
|
||||
//if in the first path there are more than one paths comma separated, split them and autogenerate the forms
|
||||
|
@ -390,13 +398,13 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.getJsonPath(index).push(this.fb.control('', Validators.required));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public removeJsonPath(i: number, j: number) {
|
||||
if (this.getJsonPath(i).enabled) {
|
||||
this.getJsonPath(i).removeAt(j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public validateJsonPath(index: number, dirty: boolean = false) {
|
||||
let indicatorPath: UntypedFormGroup = <UntypedFormGroup>this.numberIndicatorPaths.at(index);
|
||||
if (this.indicator.defaultId === null) {
|
||||
|
@ -442,33 +450,33 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}, 500);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
public getJsonPath(index: number): UntypedFormArray {
|
||||
return this.numberIndicatorPaths.at(index).get('jsonPath') as UntypedFormArray;
|
||||
}
|
||||
|
||||
|
||||
public getCurrentJsonPath(index: number): string[] {
|
||||
return this.section.indicators[this.index].indicatorPaths[index].jsonPath;
|
||||
}
|
||||
|
||||
|
||||
public getParameters(index: number): UntypedFormArray {
|
||||
return this.chartIndicatorPaths.at(index).get('parameters') as UntypedFormArray;
|
||||
}
|
||||
|
||||
|
||||
public getParameter(index: number, key: string): UntypedFormControl {
|
||||
return this.getParameters(index).controls.filter(control => control.value.key === key)[0] as UntypedFormControl;
|
||||
}
|
||||
|
||||
|
||||
private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(
|
||||
this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)));
|
||||
this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)));
|
||||
}
|
||||
|
||||
|
||||
private getUrlByStakeHolder(indicatorPath: IndicatorPath) {
|
||||
return this.statisticsService.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath));
|
||||
return this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath));
|
||||
}
|
||||
|
||||
public addNumberIndicatorPath(url: string = '', parameters: UntypedFormArray = new UntypedFormArray([]), source: string = 'stats-tool', jsonPath: UntypedFormArray = new UntypedFormArray([])) {
|
||||
|
||||
public addNumberIndicatorPath(url: string = '', parameters: UntypedFormArray = new UntypedFormArray([]), source: string = 'stats-tool', jsonPath: UntypedFormArray = new UntypedFormArray([]), format: Format = "NUMBER") {
|
||||
if (jsonPath.length === 0) {
|
||||
jsonPath.push(this.fb.control('', Validators.required));
|
||||
}
|
||||
|
@ -476,8 +484,8 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]),
|
||||
jsonPath: jsonPath,
|
||||
result: this.fb.control(0, Validators.required),
|
||||
// parameters: parameters,
|
||||
source: this.fb.control(source, Validators.required)
|
||||
source: this.fb.control(source, Validators.required),
|
||||
format: this.fb.control(format, Validators.required)
|
||||
}
|
||||
));
|
||||
let index = this.numberIndicatorPaths.length - 1;
|
||||
|
@ -489,7 +497,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.subscriptions.push(this.numberIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
|
||||
this.numberIndicatorPaths.at(index).get('result').setValue(null);
|
||||
if (this.numberIndicatorPaths.at(index).get('url').valid) {
|
||||
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.statisticsService.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.statisticsService.numberSources.get(this.statisticsService.getNumberSource(value)));
|
||||
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(value), value, this.stakeholder, this.numberIndicatorPaths.at(index).get('jsonPath').value, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(value)));
|
||||
if (!this.isStakeholderParametersValid(indicatorPath)) {
|
||||
// default profile
|
||||
if (this.stakeholder.defaultId == null) {
|
||||
|
@ -523,7 +531,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
this.subscriptions.push(this.numberIndicatorPaths.at(index).get('jsonPath').valueChanges.subscribe(value => {
|
||||
if (this.indicator.indicatorPaths[index]) {
|
||||
this.indicator.indicatorPaths[index].jsonPath = value;
|
||||
|
@ -543,7 +551,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.numberIndicatorPaths.at(index).get('source').disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public addChartIndicatorPath(value: string = '', parameters: UntypedFormArray = new UntypedFormArray([]), disableUrl: boolean = false, type: string = null) {
|
||||
this.chartIndicatorPaths.push(this.fb.group({
|
||||
url: this.fb.control(value, [Validators.required, StringUtils.urlValidator()]),
|
||||
|
@ -558,7 +566,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value);
|
||||
this.urlSubscriptions.push(this.chartIndicatorPaths.at(index).get('url').valueChanges.subscribe(value => {
|
||||
if (this.chartIndicatorPaths.at(index).get('url').valid) {
|
||||
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder);
|
||||
let indicatorPath: IndicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder);
|
||||
if (!this.isStakeholderParametersValid(indicatorPath)) {
|
||||
// default profile
|
||||
if (this.stakeholder.defaultId == null) {
|
||||
|
@ -586,13 +594,13 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private isStakeholderParametersValid(indicatorPath: IndicatorPath) {
|
||||
return !((indicatorPath.chartObject && Object.keys(indicatorPath.parameters).indexOf("index_id") == -1 && Object.keys(indicatorPath.parameters).indexOf("index_name") == -1 && Object.keys(indicatorPath.parameters).indexOf("index_shortName") == -1)
|
||||
|| (!indicatorPath.chartObject && indicatorPath.url.indexOf("index_id") == -1 && indicatorPath.url.indexOf("index_name") == -1 && (indicatorPath.url).indexOf("index_shortName") == -1));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray {
|
||||
let jsonPath = this.fb.array([]);
|
||||
if (indicatorPath.jsonPath) {
|
||||
|
@ -602,7 +610,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
return jsonPath;
|
||||
}
|
||||
|
||||
|
||||
private getParametersAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray {
|
||||
let parameters = this.fb.array([]);
|
||||
if (indicatorPath.parameters) {
|
||||
|
@ -624,7 +632,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
public editNumberIndicatorOpen(section: Section, id = null) {
|
||||
this.urlParameterizedMessage = null;
|
||||
this.section = section;
|
||||
|
@ -645,7 +653,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
defaultId: this.fb.control(this.indicator.defaultId)
|
||||
});
|
||||
this.indicator.indicatorPaths.forEach(indicatorPath => {
|
||||
this.addNumberIndicatorPath(this.statisticsService.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)), indicatorPath.parameters, indicatorPath.source, this.getJsonPathAsFormArray(indicatorPath));
|
||||
this.addNumberIndicatorPath(this.indicatorUtils.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)), indicatorPath.parameters, indicatorPath.source, this.getJsonPathAsFormArray(indicatorPath), indicatorPath.format);
|
||||
});
|
||||
} else {
|
||||
this.indicator = new Indicator('', '', '', 'number', 'small', 'small', "PUBLIC", []);
|
||||
|
@ -685,7 +693,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editNumberModal.stayOpen = true;
|
||||
this.editNumberModal.open();
|
||||
}
|
||||
|
||||
|
||||
public editChartIndicatorOpen(section: Section, id = null) {
|
||||
this.urlParameterizedMessage = null;
|
||||
this.urlSubscriptions.forEach(value => {
|
||||
|
@ -752,7 +760,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editChartModal.stayOpen = true;
|
||||
this.editChartModal.open();
|
||||
}
|
||||
|
||||
|
||||
saveIndicator() {
|
||||
this.editing = true;
|
||||
if (this.indicator.type === 'chart') {
|
||||
|
@ -834,7 +842,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
saveIndicators(sections) {
|
||||
this.editing = true;
|
||||
let path = [
|
||||
|
@ -892,10 +900,10 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editing = false;
|
||||
this.importLoading = false;
|
||||
}));
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
reorderIndicators(sectionId: string, type: IndicatorType, reorder: Reorder) {
|
||||
this.editing = true;
|
||||
let path = [
|
||||
|
@ -916,7 +924,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editing = false;
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
hasDifference(index: number): boolean {
|
||||
let hasDifference = false;
|
||||
this.chartIndicatorPaths.at(index).value.parameters.forEach((parameter) => {
|
||||
|
@ -928,22 +936,22 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !==
|
||||
this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString();
|
||||
}
|
||||
|
||||
|
||||
public get isAdministrator(): boolean {
|
||||
return Session.isPortalAdministrator(this.user);
|
||||
}
|
||||
|
||||
|
||||
public get isCurator(): boolean {
|
||||
return this.isAdministrator || Session.isCurator(this.stakeholder.type, this.user);
|
||||
}
|
||||
|
||||
|
||||
refreshIndicator() {
|
||||
this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, 'chart', true);
|
||||
this.indicator.indicatorPaths.forEach(indicatorPath => {
|
||||
indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
deleteIndicatorOpen(section: Section, indicatorId: string, type: string, childrenAction: string = null) {
|
||||
this.indicatorChildrenActionOnDelete = null;
|
||||
if (childrenAction == "delete") {
|
||||
|
@ -951,7 +959,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
} else if (childrenAction == "disconnect") {
|
||||
this.indicatorChildrenActionOnDelete = childrenAction;
|
||||
}
|
||||
|
||||
|
||||
this.section = section;
|
||||
if (type === 'chart') {
|
||||
this.index = this.charts.find(value => value._id == section._id).indicators.findIndex(value => value._id == indicatorId);
|
||||
|
@ -967,7 +975,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.deleteModal.stayOpen = true;
|
||||
this.deleteModal.open();
|
||||
}
|
||||
|
||||
|
||||
deleteIndicator() {
|
||||
this.editing = true;
|
||||
let path = [
|
||||
|
@ -1018,7 +1026,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.deleteModal.cancel();
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
changeIndicatorStatus(sectionId: string, indicator: Indicator, visibility: Visibility) {
|
||||
this.editing = true;
|
||||
let path = [
|
||||
|
@ -1046,7 +1054,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editing = false;
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
saveSection(focused: boolean, sectionControl: AbstractControl, index: number, type: IndicatorType = "chart") {
|
||||
if (!focused && sectionControl.dirty) {
|
||||
this.editing = true;
|
||||
|
@ -1081,7 +1089,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
createSection(index = -1, type: IndicatorType = 'chart') {
|
||||
this.editing = true;
|
||||
this.section = new Section(type, null, null, this.stakeholder.alias);
|
||||
|
@ -1123,7 +1131,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editing = false;
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
// deleteNumberSectionOpen(section: Section, index: number) {
|
||||
// this.section = section;
|
||||
// this.index = index;
|
||||
|
@ -1141,7 +1149,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
// this.deleteChartSectionModal.okButtonText = 'Yes';
|
||||
// this.deleteChartSectionModal.open();
|
||||
// }
|
||||
|
||||
|
||||
deleteSectionOpen(section: Section, index: number, type: IndicatorType, childrenAction: string = null) {
|
||||
if (!this.editing && !section.defaultId) {
|
||||
this.sectionTypeToDelete = type;
|
||||
|
@ -1151,7 +1159,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
} else if (childrenAction == "disconnect") {
|
||||
this.sectionChildrenActionOnDelete = childrenAction;
|
||||
}
|
||||
|
||||
|
||||
this.section = section;
|
||||
this.index = index;
|
||||
this.deleteSectionModal.alertTitle = 'Delete Section';
|
||||
|
@ -1161,7 +1169,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.deleteSectionModal.open();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
deleteSection() {
|
||||
this.editing = true;
|
||||
let path = [
|
||||
|
@ -1197,21 +1205,22 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.deleteSectionModal.cancel();
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
private checkForSchemaEnhancements(url: string) {
|
||||
this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url);
|
||||
}
|
||||
migrateFromOldImportJsonFile(charts){
|
||||
|
||||
migrateFromOldImportJsonFile(charts) {
|
||||
// first section contains numbers
|
||||
// second contains charts
|
||||
let hasNumbers = false;
|
||||
for (let chart of charts) {
|
||||
for (let chart of charts) {
|
||||
if (chart['type'] == 'number') {
|
||||
hasNumbers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let chartsSection = (hasNumbers?1:0); // no numbers: first sections contains charts
|
||||
let chartsSection = (hasNumbers ? 1 : 0); // no numbers: first sections contains charts
|
||||
for (let chart of charts) {
|
||||
if (chart['sectionIndex'] == null) {
|
||||
chart['sectionIndex'] = chart['type'] == 'chart' ? chartsSection : 0;
|
||||
|
@ -1219,7 +1228,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
}
|
||||
return charts;
|
||||
}
|
||||
|
||||
|
||||
importIndicatorsAndSave(charts: any[]) {
|
||||
let sectionsToSave: Section[] = [];
|
||||
let countIndicators = 0;
|
||||
|
@ -1246,7 +1255,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
} else if (!chart.url) {
|
||||
invalid_file_message = "No indicator url is specified.";
|
||||
}
|
||||
|
||||
|
||||
if (invalid_file_message) {
|
||||
UIkit.notification(invalid_file_message, {
|
||||
status: 'danger',
|
||||
|
@ -1257,9 +1266,9 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.importLoading = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (chart.type == "chart") {
|
||||
indicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.statisticsService.getChartSource(chart.url), chart.url, chart.type, this.stakeholder);
|
||||
indicatorPath = this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(chart.url), chart.url, chart.type, this.stakeholder);
|
||||
for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts) {
|
||||
for (let chart of section.indicators) {
|
||||
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) {
|
||||
|
@ -1267,11 +1276,11 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else if (chart.type == "number") {
|
||||
indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.statisticsService.getNumberSource(chart.url), chart.url, this.stakeholder,
|
||||
chart.jsonPath, this.statisticsService.numberSources.get(this.statisticsService.getNumberSource(chart.url)));
|
||||
indicatorPath = this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(chart.url), chart.url, this.stakeholder,
|
||||
chart.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(chart.url)));
|
||||
for (let section of this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers) {
|
||||
for (let chart of section.indicators) {
|
||||
if (JSON.stringify(chart.indicatorPaths[0].chartObject) == JSON.stringify(indicatorPath.chartObject)) {
|
||||
|
@ -1279,7 +1288,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (!this.isStakeholderParametersValid(indicatorPath)) {
|
||||
|
@ -1290,9 +1299,9 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
sectionsToSave[chart['sectionIndex']].indicators.push(i);
|
||||
countIndicators++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (duplicates > 0) {
|
||||
UIkit.notification(duplicates + " urls already exist and will not be imported!", {
|
||||
status: 'warning',
|
||||
|
@ -1313,7 +1322,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.editing = false;
|
||||
this.importLoading = false;
|
||||
} else if (sectionsToSave.length > 0 && countIndicators > 0) {
|
||||
this.saveIndicators(sectionsToSave)
|
||||
this.saveIndicators(sectionsToSave.filter(section => !!section));
|
||||
}
|
||||
if (sectionsToSave.length == 0 || countIndicators == 0) {
|
||||
UIkit.notification(" No urls imported!", {
|
||||
|
@ -1325,7 +1334,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.importLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public exportIndicators(subcategoryIndex) {
|
||||
this.editing = true;
|
||||
let indicators = [];
|
||||
|
@ -1338,7 +1347,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
"type": indicator.type, "name": indicator.name, "jsonPath": indicatorPath.jsonPath,
|
||||
"description": indicator.description, "additionalDescription": indicator.additionalDescription,
|
||||
"visibility": indicator.visibility, "width": indicator.width, "height": indicator.height,
|
||||
"url": this.statisticsService.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)),
|
||||
"url": this.indicatorUtils.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)),
|
||||
"sectionTitle": section.title,
|
||||
"sectionType": section.type,
|
||||
"sectionIndex": index
|
||||
|
@ -1348,7 +1357,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
});
|
||||
index++;
|
||||
});
|
||||
|
||||
|
||||
this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].charts.forEach(section => {
|
||||
section.indicators.forEach(indicator => {
|
||||
indicator.indicatorPaths.forEach(indicatorPath => {
|
||||
|
@ -1365,13 +1374,13 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
});
|
||||
});
|
||||
index++;
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
let topic = this.stakeholder ? this.stakeholder.topics[this.topicIndex] : null;
|
||||
let category = topic ? topic.categories[this.categoryIndex] : null;
|
||||
let subCategory = category ? category.subCategories[this.subcategoryIndex] : null;
|
||||
|
||||
|
||||
var jsonFileUrl = window.URL.createObjectURL(new Blob([JSON.stringify(indicators)], {type: 'application/json'}));
|
||||
var a = window.document.createElement('a');
|
||||
window.document.body.appendChild(a);
|
||||
|
@ -1381,10 +1390,10 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
a.click();
|
||||
window.URL.revokeObjectURL(jsonFileUrl);
|
||||
a.remove(); // remove the element
|
||||
|
||||
|
||||
this.editing = false;
|
||||
}
|
||||
|
||||
|
||||
fileChangeEvent(fileInput: any, index) {
|
||||
this.index = index;
|
||||
this.editing = true;
|
||||
|
@ -1392,7 +1401,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.filesToUpload = <Array<File>>fileInput.target.files;
|
||||
this.upload();
|
||||
}
|
||||
|
||||
|
||||
upload() {
|
||||
if (this.filesToUpload.length == 0) {
|
||||
console.error("There is no selected file to upload.");
|
||||
|
@ -1417,11 +1426,11 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.makeFileRequest(this.properties.utilsService + '/upload?type=json', [], this.filesToUpload).then(async (result: string) => {
|
||||
|
||||
|
||||
let json_result = JSON.parse(result);
|
||||
|
||||
|
||||
// validate file
|
||||
if (!json_result || json_result.length == 0) {
|
||||
UIkit.notification("Importing file is empty", {
|
||||
|
@ -1445,7 +1454,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
this.importLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData: any = new FormData();
|
||||
|
@ -1466,7 +1475,7 @@ export class IndicatorsComponent implements OnInit, OnDestroy, OnChanges, AfterV
|
|||
xhr.send(formData);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
copyToClipboard(value) {
|
||||
const tempBox = document.createElement('textarea');
|
||||
tempBox.style.position = 'fixed';
|
||||
|
|
|
@ -27,7 +27,7 @@ export class AdminDashboardGuard implements CanActivate, CanActivateChild {
|
|||
check(path: string, alias: string): Observable<boolean> | boolean {
|
||||
let errorCode = LoginErrorCodes.NOT_LOGIN;
|
||||
return zip(
|
||||
this.userManagementService.getUserInfo() ,this.stakeholderService.getStakeholder(alias)
|
||||
this.userManagementService.getUserInfo(), this.stakeholderService.getStakeholder(alias)
|
||||
).pipe(take(1),map(res => {
|
||||
if(res[0]) {
|
||||
errorCode = LoginErrorCodes.NOT_ADMIN;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {properties} from "../../../environments/environment";
|
||||
import {BehaviorSubject, Observable} from "rxjs";
|
||||
import {CustomOptions} from "../../openaireLibrary/services/servicesUtils/customOptions.class";
|
||||
import {map, tap} from "rxjs/operators";
|
||||
import {Report} from "../../../cache-indicators";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CacheIndicatorsService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
createReport(alias: string) {
|
||||
return this.http.post<any>(properties.domain + properties.baseLink + '/cache/' + alias, {}, CustomOptions.registryOptions())
|
||||
.pipe(map(res => res.report));
|
||||
}
|
||||
|
||||
getReport(alias: string) {
|
||||
return this.http.get<any>(properties.domain + properties.baseLink + '/cache/' + alias, CustomOptions.registryOptions())
|
||||
.pipe(map(res => res.report));
|
||||
}
|
||||
}
|
|
@ -3,69 +3,23 @@ import {HttpClient} from "@angular/common/http";
|
|||
import {Observable} from "rxjs";
|
||||
import {SourceType} from "../../openaireLibrary/monitor/entities/stakeholder";
|
||||
import {properties} from "../../../environments/environment";
|
||||
import {IndicatorUtils} from "../indicator-utils";
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StatisticsService {
|
||||
|
||||
numberSources: Map<SourceType, string[]> = new Map<SourceType, string[]>();
|
||||
chartSources: Map<SourceType, string[]> = new Map<SourceType, string[]>();
|
||||
|
||||
constructor(private http:HttpClient) {
|
||||
this.numberSources.set('statistics', [properties.statisticsAPIURL]);
|
||||
this.numberSources.set('search', [properties.searchAPIURLLAst]);
|
||||
this.numberSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/","https://beta.services.openaire.eu/stats-tool/","https://services.openaire.eu/stats-tool/","https://services.openaire.eu/monitor-stats-tool/"]);
|
||||
this.chartSources.set('stats-tool', [properties.monitorStatsFrameUrl, "http://marilyn.athenarc.gr:8080/stats-api/", "http://88.197.53.71:8080/stats-api/", "https://stats.madgik.di.uoa.gr/stats-api/","https://beta.services.openaire.eu/stats-tool/","https://services.openaire.eu/stats-tool/","https://services.openaire.eu/monitor-stats-tool/"]);
|
||||
this.chartSources.set('old', [properties.statisticsFrameAPIURL]);
|
||||
this.chartSources.set('image', [""]);
|
||||
|
||||
indicatorsUtils = new IndicatorUtils();
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
getNumbers(source: SourceType, url: string): Observable<any> {
|
||||
if (source !== null) {
|
||||
return this.http.get<any>(this.indicatorsUtils.getNumberUrl(source, url));
|
||||
} else {
|
||||
return this.http.get<any>(url);
|
||||
}
|
||||
}
|
||||
getSourceType(source:string):SourceType{
|
||||
let sourceType: SourceType = 'search';
|
||||
this.numberSources.forEach((values, key) => {
|
||||
if(key == source) {
|
||||
sourceType = key;
|
||||
|
||||
}
|
||||
});
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
getNumbers(source: SourceType, url: string): Observable<any> {
|
||||
if(source !== null) {
|
||||
return this.http.get<any>(this.numberSources.get(source)[0] + url);
|
||||
} else {
|
||||
return this.http.get<any>(url);
|
||||
}
|
||||
}
|
||||
|
||||
getChartUrl(source: SourceType, url: string): string {
|
||||
return this.chartSources.get(source)[0] + url;
|
||||
}
|
||||
getNumberUrl(source: string, url: string): string {
|
||||
return this.numberSources.get(this.getSourceType(source))[0] + url;
|
||||
}
|
||||
getNumberSource(url: string): SourceType {
|
||||
let source: SourceType = 'search';
|
||||
this.numberSources.forEach((values, key) => {
|
||||
values.forEach((value) => {
|
||||
if(value !== '' && url.indexOf(value) !== -1) {
|
||||
source = key;
|
||||
}
|
||||
});
|
||||
});
|
||||
return source;
|
||||
}
|
||||
getChartSource(url: string): SourceType {
|
||||
let source: SourceType = 'image';
|
||||
this.chartSources.forEach((values, key) => {
|
||||
values.forEach((value) => {
|
||||
if(value !== '' && url.indexOf(value) !== -1) {
|
||||
source = key;
|
||||
}
|
||||
});
|
||||
});
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {properties} from "../../../environments/environment";
|
||||
import {Observable} from "rxjs";
|
||||
import {CustomOptions} from "../../openaireLibrary/services/servicesUtils/customOptions.class";
|
||||
import {map} from "rxjs/operators";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StatsProfilesService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getStatsProfiles(): Observable<string[]> {
|
||||
return this.http.get<any[]>(properties.monitorStatsFrameUrl + 'schema/profiles')
|
||||
.pipe(map(profiles => profiles.map(profile => profile.name)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
import {IndicatorType, Stakeholder} from "./app/openaireLibrary/monitor/entities/stakeholder";
|
||||
import axios from "axios";
|
||||
import {IndicatorUtils} from "./app/utils/indicator-utils";
|
||||
import {Composer} from "./app/openaireLibrary/utils/email/composer";
|
||||
import {properties} from "./environments/environment";
|
||||
import {error} from "protractor";
|
||||
|
||||
|
||||
export interface CacheItem {
|
||||
reportId: string,
|
||||
type: IndicatorType,
|
||||
url: string
|
||||
}
|
||||
|
||||
export class Report {
|
||||
creator: string;
|
||||
name: string;
|
||||
success: number;
|
||||
errors: {
|
||||
url: string,
|
||||
status: number
|
||||
}[];
|
||||
total: number;
|
||||
completed: boolean;
|
||||
percentage: number
|
||||
|
||||
constructor(total: number, name: string, creator: string) {
|
||||
this.creator = creator;
|
||||
this.name = name;
|
||||
this.success = 0;
|
||||
this.errors = [];
|
||||
this.total = total;
|
||||
this.completed = false;
|
||||
}
|
||||
|
||||
setPercentage() {
|
||||
this.percentage = Math.floor((this.success + this.errors.length) / this.total * 100);
|
||||
}
|
||||
}
|
||||
|
||||
export class CacheIndicators {
|
||||
|
||||
private static BATCH_SIZE = 10;
|
||||
|
||||
private reports: Map<string, Report> = new Map<string, Report>();
|
||||
private queue: CacheItem[] = [];
|
||||
private process: Promise<void>;
|
||||
private isFinished: boolean = true;
|
||||
|
||||
stakeholderToCacheItems(stakeholder: Stakeholder) {
|
||||
let cacheItems: CacheItem[] = [];
|
||||
let indicatorUtils = new IndicatorUtils();
|
||||
stakeholder.topics.forEach(topic => {
|
||||
topic.categories.forEach(category => {
|
||||
category.subCategories.forEach(subCategory => {
|
||||
subCategory.numbers.forEach(section => {
|
||||
section.indicators.forEach(indicator => {
|
||||
indicator.indicatorPaths.forEach(indicatorPath => {
|
||||
let url = indicatorUtils.getNumberUrl(indicatorPath.source, indicatorUtils.getFullUrl(stakeholder, indicatorPath));
|
||||
cacheItems.push({
|
||||
reportId: stakeholder._id,
|
||||
type: 'number',
|
||||
url: url
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
subCategory.charts.forEach(section => {
|
||||
section.indicators.forEach(indicator => {
|
||||
indicator.indicatorPaths.forEach(indicatorPath => {
|
||||
let url = indicatorUtils.getChartUrl(indicatorPath.source, indicatorUtils.getFullUrl(stakeholder, indicatorPath));
|
||||
cacheItems.push({
|
||||
reportId: stakeholder._id,
|
||||
type: 'chart',
|
||||
url: url
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return cacheItems;
|
||||
}
|
||||
|
||||
public exists(id: string) {
|
||||
return this.reports.has(id);
|
||||
}
|
||||
|
||||
public completed(id: string) {
|
||||
return !this.exists(id) || this.reports.get(id).completed;
|
||||
}
|
||||
|
||||
public createReport(id: string, cacheItems: CacheItem[], name: string, creator: string) {
|
||||
let report = new Report(cacheItems.length, name, creator);
|
||||
this.reports.set(id, report);
|
||||
this.addItemsToQueue(cacheItems);
|
||||
return report;
|
||||
}
|
||||
|
||||
public getReport(id: string) {
|
||||
return this.reports.get(id);
|
||||
}
|
||||
|
||||
private async processQueue() {
|
||||
this.isFinished = false;
|
||||
while (this.queue.length > 0) {
|
||||
let batch = this.queue.splice(0, CacheIndicators.BATCH_SIZE);
|
||||
await this.processBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
private async processBatch(batch: CacheItem[]) {
|
||||
let promises: Promise<any>[] = [];
|
||||
let ids = new Set<string>();
|
||||
batch.forEach(item => {
|
||||
let promise;
|
||||
ids.add(item.reportId);
|
||||
if (item.type === 'chart') {
|
||||
let [url, json] = item.url.split('?json=');
|
||||
json = decodeURIComponent(json);
|
||||
json = statsToolParser(JSON.parse(json));
|
||||
promise = axios.post(url, json);
|
||||
} else {
|
||||
promise = axios.get(item.url);
|
||||
}
|
||||
promises.push(promise.then(response => {
|
||||
let report = this.reports.get(item.reportId);
|
||||
if (report) {
|
||||
report.success++;
|
||||
report.setPercentage();
|
||||
}
|
||||
return response;
|
||||
}).catch(error => {
|
||||
let report = this.reports.get(item.reportId);
|
||||
if (report) {
|
||||
report.errors.push({url: item.url, status: error.response.status});
|
||||
report.setPercentage();
|
||||
}
|
||||
return error.response;
|
||||
}));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
ids.forEach(id => {
|
||||
let report = this.reports.get(id);
|
||||
if (report?.percentage === 100) {
|
||||
report.completed = true;
|
||||
this.sendEmail(report);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private addItemsToQueue(cacheItems: CacheItem[]) {
|
||||
cacheItems.forEach(item => {
|
||||
this.queue.push(item);
|
||||
});
|
||||
if (this.isFinished) {
|
||||
this.processQueue().then(() => {
|
||||
this.isFinished = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendEmail(report: Report) {
|
||||
let email = Composer.composeEmailToReportCachingProcess(report);
|
||||
axios.post(properties.adminToolsAPIURL + "sendMail/", email).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function statsToolParser(dataJSONobj: any): any {
|
||||
let RequestInfoObj = Object.assign({});
|
||||
switch (dataJSONobj.library) {
|
||||
case "GoogleCharts":
|
||||
//Pass the Chart library to ChartDataFormatter
|
||||
RequestInfoObj.library = dataJSONobj.library;
|
||||
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||||
|
||||
//Create ChartInfo Object Array
|
||||
RequestInfoObj.chartsInfo = [];
|
||||
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||||
//along with the requested Chart type
|
||||
RequestInfoObj.chartsInfo = dataJSONobj.chartDescription.queriesInfo;
|
||||
break;
|
||||
case "eCharts":
|
||||
//Pass the Chart library to ChartDataFormatter
|
||||
RequestInfoObj.library = dataJSONobj.library;
|
||||
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||||
|
||||
//Create ChartInfo Object Array
|
||||
RequestInfoObj.chartsInfo = [];
|
||||
|
||||
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||||
//along with the requested Chart type
|
||||
for (let index = 0; index < dataJSONobj.chartDescription.queries.length; index++) {
|
||||
let element = dataJSONobj.chartDescription.queries[index];
|
||||
var ChartInfoObj = Object.assign({});
|
||||
|
||||
if (element.type === undefined)
|
||||
ChartInfoObj.type = dataJSONobj.chartDescription.series[index].type;
|
||||
else
|
||||
ChartInfoObj.type = element.type;
|
||||
|
||||
if (element.name === undefined)
|
||||
ChartInfoObj.name = null;
|
||||
else
|
||||
ChartInfoObj.name = element.name;
|
||||
|
||||
ChartInfoObj.query = element.query;
|
||||
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||||
}
|
||||
break;
|
||||
case "HighCharts":
|
||||
RequestInfoObj.library = dataJSONobj.library;
|
||||
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||||
//Pass the Chart type to ChartDataFormatter
|
||||
var defaultType = dataJSONobj.chartDescription.chart.type;
|
||||
//Create ChartInfo Object Array
|
||||
RequestInfoObj.chartsInfo = [];
|
||||
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||||
//along with the requested Chart type
|
||||
dataJSONobj.chartDescription.queries.forEach(element => {
|
||||
var ChartInfoObj = Object.assign({});
|
||||
|
||||
if (element.type === undefined)
|
||||
ChartInfoObj.type = defaultType;
|
||||
else
|
||||
ChartInfoObj.type = element.type;
|
||||
|
||||
if (element.name === undefined)
|
||||
ChartInfoObj.name = null;
|
||||
else
|
||||
ChartInfoObj.name = element.name;
|
||||
|
||||
ChartInfoObj.query = element.query;
|
||||
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||||
});
|
||||
break;
|
||||
case "HighMaps":
|
||||
RequestInfoObj.library = dataJSONobj.library;
|
||||
//Create ChartInfo Object Array
|
||||
RequestInfoObj.chartsInfo = [];
|
||||
|
||||
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||||
dataJSONobj.mapDescription.queries.forEach(element => {
|
||||
var ChartInfoObj = Object.assign({});
|
||||
|
||||
if (element.name === undefined)
|
||||
ChartInfoObj.name = null;
|
||||
else
|
||||
ChartInfoObj.name = element.name;
|
||||
|
||||
ChartInfoObj.query = element.query;
|
||||
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("Unsupported Library: " + dataJSONobj.library);
|
||||
}
|
||||
return RequestInfoObj;
|
||||
}
|
|
@ -62,7 +62,6 @@ export let properties: EnvProperties = {
|
|||
cookieDomain: ".di.uoa.gr",
|
||||
feedbackmail: "openaire.test@gmail.com",
|
||||
cacheUrl: "http://scoobydoo.di.uoa.gr:3000/get?url=",
|
||||
// monitorServiceAPIURL: "https://services.openaire.eu/uoa-monitor-service",
|
||||
monitorServiceAPIURL: "http://duffy.di.uoa.gr:19380/uoa-monitor-service",
|
||||
adminToolsAPIURL: "http://duffy.di.uoa.gr:19380/uoa-monitor-service/",
|
||||
notificationsAPIURL: "http://duffy.di.uoa.gr:19380/uoa-monitor-service/notification/",
|
||||
|
@ -75,7 +74,7 @@ export let properties: EnvProperties = {
|
|||
csvLimit: 2000,
|
||||
pagingLimit: 20,
|
||||
resultsPerPage: 10,
|
||||
baseLink: "/dashboard",
|
||||
baseLink: "/",
|
||||
domain: "http://mpagasas.di.uoa.gr:4600",
|
||||
searchLinkToResult: "/search/result?id=",
|
||||
searchLinkToPublication: "/search/publication?articleId=",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<base href="/dashboard"/>
|
||||
<base href="/"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
|
||||
<meta name="description" content="OpenAIRE Monitor, funder, funding, research, "/>
|
||||
<meta property="og:description" content="OpenAIRE Monitor, funder, funding"/>
|
||||
|
|
Loading…
Reference in New Issue