[Harvester | master]: First version of the user interface - harvest page added, to get configuration template instances, then services, information and compatibility filter are displayed and harvest button triggers API call to start the harvest process.
This commit is contained in:
parent
90125442bd
commit
9f7aca0f10
|
@ -15,6 +15,7 @@ import {SharedModule} from "./openaireLibrary/shared/shared.module";
|
|||
import {ErrorInterceptorService} from "./openaireLibrary/error-interceptor.service";
|
||||
import {DEFAULT_TIMEOUT, TimeoutInterceptor} from "./openaireLibrary/timeout-interceptor.service";
|
||||
import { HomeModule } from './home/home.module';
|
||||
import {HarvesterModule} from "./harvester/harvester.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -26,10 +27,10 @@ import { HomeModule } from './home/home.module';
|
|||
ErrorModule,
|
||||
SharedModule,
|
||||
BrowserAnimationsModule, LoadingModule, SideBarModule,
|
||||
HomeModule
|
||||
HomeModule, HarvesterModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
AppComponent
|
||||
],
|
||||
providers: [
|
||||
TitleCasePipe,
|
||||
|
|
|
@ -3,24 +3,29 @@ import {RouterModule, Routes} from '@angular/router';
|
|||
import {LoginGuard} from "./openaireLibrary/login/loginGuard.guard";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./home/home.module').then(m => m.HomeModule)
|
||||
},
|
||||
{
|
||||
path: 'reload',
|
||||
loadChildren: () => import('./reload/libReload.module').then(m => m.LibReloadModule),
|
||||
data: {hasSidebar: false, hasHeader: false}
|
||||
},
|
||||
// { path: 'error',
|
||||
// pathMatch: 'full',
|
||||
// component: AdminErrorPageComponent,
|
||||
// data: {hasSidebar: false}
|
||||
// },
|
||||
// { path: '**',
|
||||
// pathMatch: 'full',
|
||||
// component: AdminErrorPageComponent
|
||||
// }
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./harvester/harvester.module').then(m => m.HarvesterModule)
|
||||
// loadChildren: () => import('./home/home.module').then(m => m.HomeModule)
|
||||
},
|
||||
{
|
||||
path: 'harvest',
|
||||
redirectTo: '', pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'reload',
|
||||
loadChildren: () => import('./reload/libReload.module').then(m => m.LibReloadModule),
|
||||
data: {hasSidebar: false, hasHeader: false}
|
||||
},
|
||||
// { path: 'error',
|
||||
// pathMatch: 'full',
|
||||
// component: AdminErrorPageComponent,
|
||||
// data: {hasSidebar: false}
|
||||
// },
|
||||
// { path: '**',
|
||||
// pathMatch: 'full',
|
||||
// component: AdminErrorPageComponent
|
||||
// }
|
||||
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
export class EOSCService {
|
||||
// id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
webpage: string;
|
||||
|
||||
// configuration template instance info
|
||||
baseurl: string;
|
||||
compatibility: string;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import{HarvesterComponent} from './harvester.component';
|
||||
import {PreviousRouteRecorder} from '../openaireLibrary/utils/piwik/previousRouteRecorder.guard';
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{ path: '', component: HarvesterComponent, canDeactivate: [PreviousRouteRecorder] }
|
||||
|
||||
])
|
||||
]
|
||||
})
|
||||
export class HarvesterRoutingModule { }
|
|
@ -0,0 +1,109 @@
|
|||
<div class="uk-section">
|
||||
<div class="uk-container uk-container-xlarge">
|
||||
<h1 class="uk-margin-large-bottom">EOSC Metadata Harvester</h1>
|
||||
|
||||
<div class="uk-grid">
|
||||
<div class="uk-width-1-4@m search-filters">
|
||||
<div [class.filterLoading]="false">
|
||||
<div class="uk-flex uk-flex-middle">
|
||||
<h4 class="uk-margin-right uk-margin-remove-bottom">Filters</h4>
|
||||
<!-- <a *ngIf="(selectedRangeFilters + selectedFilters + selectedTypesNum)>0"-->
|
||||
<!-- (click)="clearFilters()" class="uk-text-small"-->
|
||||
<!-- [class.uk-disabled]="disabled" [class.uk-link-muted]="disabled">-->
|
||||
<!-- Clear All-->
|
||||
<!-- </a>-->
|
||||
</div>
|
||||
<!-- <div *ngIf="searchUtils.refineStatus == errorCodes.LOADING && existingFiltersWithValues === 0"-->
|
||||
<!-- class="uk-margin-top" role="alert">-->
|
||||
<!-- <loading></loading>-->
|
||||
<!-- </div>-->
|
||||
<div>
|
||||
<div class="uk-flex uk-flex-middle uk-margin-bottom">
|
||||
<h6 title="compatibility" class="uk-margin-top uk-margin-remove-bottom">{{_formatTitle("Compatibility", compatibilityFilterValues.length)}}</h6>
|
||||
<!-- <a *ngIf="filter.countSelectedValues>0" class="uk-text-small uk-margin-left" (click)="clearFilter()" [class.uk-disabled]="isDisabled">Clear</a>-->
|
||||
</div>
|
||||
<div>
|
||||
<div *ngFor="let compatibilityFilter of compatibilityFilterValues"
|
||||
class="uk-animation-fade uk-text-small uk-margin-small-bottom">
|
||||
<div [title]="compatibilityFilter.compatibility">
|
||||
<span class="uk-flex uk-flex-middle">
|
||||
<!-- [class.uk-disabled]="isDisabled || (showResultCount && value.number === 0)">-->
|
||||
<label>
|
||||
<input type="checkbox" class="uk-checkbox"
|
||||
[(ngModel)]="compatibilityFilter.selected"
|
||||
(ngModelChange)="filterChange(compatibilityFilter.selected)"/>
|
||||
<span class="uk-margin-small-left">
|
||||
{{_formatName(compatibilityFilter.compatibility)}}
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-width-expand">
|
||||
<results-and-pages
|
||||
type="Services"
|
||||
[page]="page" [pageSize]="pageSize"
|
||||
[totalResults]="services.length">
|
||||
</results-and-pages>
|
||||
|
||||
<ul *ngIf="services && services.length > 0" class="uk-list uk-list-large uk-list-divider">
|
||||
<li *ngFor="let service of services.slice((page-1)*pageSize, page*pageSize)" class="uk-card uk-card-default">
|
||||
<div class="uk-card-body uk-text-small">
|
||||
<!-- {{service | json}}-->
|
||||
<h1 *ngIf="service.name" class="uk-h6">{{service.name}}</h1>
|
||||
<div *ngIf="service.webpage">
|
||||
<span class="uk-text-meta">Web page: </span>
|
||||
<a target="_blank" [href]="service.webpage" class="custom-external uk-link">{{service.webpage}}</a>
|
||||
</div>
|
||||
<div *ngIf="service.baseurl">
|
||||
<span class="uk-text-meta">Base URL: </span>
|
||||
<a target="_blank" [href]="service.baseurl" class="custom-external uk-link">{{service.baseurl}}</a>
|
||||
</div>
|
||||
<div *ngIf="service.compatibility">
|
||||
<span class="uk-text-meta">Compatibility: </span>
|
||||
{{service.compatibility}}
|
||||
</div>
|
||||
<div *ngIf="service.description" class="uk-margin-top uk-height-max-medium uk-overflow-auto">
|
||||
<p [innerHTML]="service.description"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-flex uk-flex-right">
|
||||
<button class="uk-button uk-button-text" (click)="openFeedbackModal(service.baseurl)">Harvest</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<paging-no-load *ngIf="services.length > 10"
|
||||
class="uk-margin-top"
|
||||
(pageChange)="updatePage($event)"
|
||||
[currentPage]="page" [size]="pageSize"
|
||||
[totalResults]="services.length">
|
||||
</paging-no-load>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<modal-alert #feedbackModal (alertOutput)="harvest()" [okDisabled]="(form.invalid || sending)">
|
||||
<div class="uk-flex uk-flex-column uk-flex-middle">
|
||||
<div>Want feedback on the harvest status?</div>
|
||||
<div>Please provide us with your email address and click the <i class="uk-text-bold">harvest</i> button.</div>
|
||||
<div class="uk-margin-small-top">Otherwise, simply click the <i class="uk-text-bold">harvest</i> button to continue.</div>
|
||||
|
||||
<div input class="uk-width-2-3 uk-margin-medium-top uk-margin-medium-bottom"
|
||||
[formInput]="form.get('email')" placeholder="E-mail">
|
||||
<span note>(Optional)</span>
|
||||
</div>
|
||||
<div>
|
||||
<re-captcha (resolved)="handleRecaptcha($event)" [siteKey]="properties.reCaptchaSiteKey"
|
||||
[ngClass]="sending ? 'uk-hidden':''"></re-captcha>
|
||||
<loading [ngClass]="sending ? '':'uk-hidden'"></loading>
|
||||
</div>
|
||||
</div>
|
||||
</modal-alert>
|
|
@ -0,0 +1,172 @@
|
|||
import {Component, ViewChild} from '@angular/core';
|
||||
import {HarvesterService} from "./harvester.service";
|
||||
import {EOSCService} from "../entities/eoscservice";
|
||||
import {OpenaireEntities} from "../openaireLibrary/utils/properties/searchFields";
|
||||
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
|
||||
import {browser} from "protractor";
|
||||
import {properties} from "../../environments/environment";
|
||||
import {FormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
|
||||
import {StringUtils} from "../openaireLibrary/utils/string-utils.class";
|
||||
import {NotificationHandler} from "../openaireLibrary/utils/notification-handler";
|
||||
|
||||
@Component({
|
||||
selector: 'app-harvester',
|
||||
templateUrl: './harvester.component.html',
|
||||
styleUrls: ['./harvester.component.css']
|
||||
})
|
||||
export class HarvesterComponent {
|
||||
public allServices: EOSCService[] = [];
|
||||
public services: EOSCService[] = [];
|
||||
public _maxCharacters: number = 28;
|
||||
public compatibilityFilterValues: Array<{"compatibility": string, "selected": boolean}> = [];
|
||||
public selectedFilters: number = 0;
|
||||
|
||||
public pageSize: number = 10;
|
||||
public page: number = 1;
|
||||
|
||||
public selectedBaseUrl: string = "";
|
||||
public sending: boolean = false;
|
||||
public form: UntypedFormGroup;
|
||||
@ViewChild('feedbackModal') feedbackModal;
|
||||
|
||||
constructor(private fb: FormBuilder, private harvesterService: HarvesterService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this.fb.group({
|
||||
email: this.fb.control('', Validators.email),
|
||||
recaptcha: this.fb.control('', Validators.required),
|
||||
});
|
||||
|
||||
let servicesMap: Map<string, EOSCService> = new Map<string, EOSCService>();
|
||||
|
||||
this.harvesterService.getAllTemplateInstances().subscribe(res => {
|
||||
// console.log(res);
|
||||
let instances = res['results'];
|
||||
|
||||
let compatibilitiesSet: Set<string> = new Set<string>();
|
||||
let serviceIds: Set<string> = new Set<string>();
|
||||
|
||||
let ids: string = "";
|
||||
instances.forEach(subProfile => {
|
||||
let serviceId = subProfile.resourceId;
|
||||
|
||||
if(!serviceIds.has(serviceId)) {
|
||||
ids += ids.length > 0 ? ("," + serviceId) : serviceId;
|
||||
|
||||
let service = new EOSCService();
|
||||
// service.id = serviceId;
|
||||
service.baseurl = subProfile.payload.baseURL;
|
||||
service.compatibility = subProfile.payload.compatibility;
|
||||
servicesMap.set(serviceId, service);
|
||||
|
||||
if (!compatibilitiesSet.has(service.compatibility)) {
|
||||
compatibilitiesSet.add(service.compatibility);
|
||||
this.compatibilityFilterValues.push({"compatibility": service.compatibility, "selected": false});
|
||||
}
|
||||
}
|
||||
|
||||
serviceIds.add(serviceId);
|
||||
});
|
||||
|
||||
compatibilitiesSet = null;
|
||||
// console.log("Subprofiles: ", this.subProfiles);
|
||||
|
||||
this.harvesterService.getListOfServicesByIds(ids).subscribe(res => {
|
||||
// this.services = res;
|
||||
// console.log(this.services);
|
||||
|
||||
for(let result of res) {
|
||||
let service = servicesMap.get(result.id);
|
||||
// console.log(service);
|
||||
service.name = result.name;
|
||||
service.description = result.description;
|
||||
service.webpage = result.webpage;
|
||||
}
|
||||
|
||||
this.allServices = this.getValues(servicesMap);
|
||||
this.services = [...this.allServices];
|
||||
}, error => {});
|
||||
|
||||
}, error => {});
|
||||
|
||||
|
||||
// this.harvesterService.getServiceById().subscribe(res => {
|
||||
// // console.log("Get service by id: ", res);
|
||||
// }, error => {});
|
||||
}
|
||||
|
||||
public getValues(map): any[] {
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
public _formatTitle(title, length) {
|
||||
return (((title + " (" + length + ")").length > this._maxCharacters) ? (title.substring(0, (this._maxCharacters - (" (" + length + ")").length - ('...').length)) + "...") : title) + " (" + (length > 95 ? "100" : length) + ")";
|
||||
}
|
||||
|
||||
public _formatName(value) {
|
||||
//let maxLineLength = 24;
|
||||
let maxLineLength = 35;
|
||||
|
||||
//1 space after checkbox
|
||||
//3 space before number + parenthesis
|
||||
if (value.length + 1 > maxLineLength) {
|
||||
return value.substr(0, maxLineLength - 3 - 1) + '...';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public filterChange(selected: boolean) {
|
||||
selected ? this.selectedFilters++ : this.selectedFilters--;
|
||||
if(this.selectedFilters == 0 || this.selectedFilters == this.compatibilityFilterValues.length) {
|
||||
this.services = [...this.allServices];
|
||||
} else {
|
||||
this.services = this.allServices.filter(service => {
|
||||
for (let filter of this.compatibilityFilterValues) {
|
||||
if (filter.selected && service.compatibility == filter.compatibility) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public updatePage($event) {
|
||||
this.page = $event.value;
|
||||
HelperFunctions.scroll();
|
||||
}
|
||||
|
||||
public openFeedbackModal(baseUrl: string = "") {
|
||||
this.selectedBaseUrl = baseUrl;
|
||||
this.sending = false;
|
||||
|
||||
this.feedbackModal.cancelButton = false;
|
||||
this.feedbackModal.okButton = true;
|
||||
this.feedbackModal.okButtonText = "Harvest";
|
||||
this.feedbackModal.alertTitle = "Provide your email to get feedback";
|
||||
this.feedbackModal.open();
|
||||
}
|
||||
|
||||
public harvest() {
|
||||
this.sending = true;
|
||||
let email: string = this.form.get("email").value;
|
||||
if(!StringUtils.validateEmails(email)) {
|
||||
email = null;
|
||||
}
|
||||
this.harvesterService.harvest(this.selectedBaseUrl, email).subscribe(res => {
|
||||
console.log("Harvest: ", res);
|
||||
this.sending = false;
|
||||
NotificationHandler.rise('Harvest has begun');
|
||||
}, error => {
|
||||
this.sending = false;
|
||||
NotificationHandler.rise('An error occured', "danger");
|
||||
});
|
||||
}
|
||||
|
||||
public handleRecaptcha(captchaResponse: string) {
|
||||
this.form.get('recaptcha').setValue(captchaResponse);
|
||||
}
|
||||
|
||||
protected readonly properties = properties;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import {NgModule} from "@angular/core";
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {RouterModule} from "@angular/router";
|
||||
import {PreviousRouteRecorder} from "../openaireLibrary/utils/piwik/previousRouteRecorder.guard";
|
||||
import {HarvesterRoutingModule} from "./harvester-routing.module";
|
||||
import {HarvesterComponent} from "./harvester.component";
|
||||
import {HarvesterService} from "./harvester.service";
|
||||
import {InputModule} from "../openaireLibrary/sharedComponents/input/input.module";
|
||||
import {PagingModule} from "../openaireLibrary/utils/paging.module";
|
||||
import {AlertModalModule} from "../openaireLibrary/utils/modal/alertModal.module";
|
||||
import {RecaptchaModule} from "ng-recaptcha";
|
||||
import {LoadingModule} from "../openaireLibrary/utils/loading/loading.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule, FormsModule, RouterModule,
|
||||
HarvesterRoutingModule, InputModule, PagingModule, AlertModalModule, RecaptchaModule, LoadingModule
|
||||
],
|
||||
declarations: [
|
||||
HarvesterComponent
|
||||
],
|
||||
providers:[
|
||||
PreviousRouteRecorder, HarvesterService
|
||||
],
|
||||
exports: [
|
||||
HarvesterComponent
|
||||
]
|
||||
})
|
||||
export class HarvesterModule {}
|
|
@ -0,0 +1,37 @@
|
|||
import {Injectable} from "@angular/core";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs";
|
||||
import {map} from "rxjs/operators";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class HarvesterService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getAllTemplateInstances(): Observable<any> {
|
||||
let url = "https://beta.providers.eosc-portal.eu/api/configurationTemplateInstance/all?from=0&quantity=100";
|
||||
return this.http.get(url, {responseType: 'json'}).pipe(map(res => res));
|
||||
}
|
||||
|
||||
// getAllSubprofiles(): Observable<any> {
|
||||
// let url = "https://beta.providers.eosc-portal.eu/api/datasource/all?catalogue_id=all&suspended=false&quantity=100";
|
||||
// // return this.http.get(url).pipe(map(res => res));
|
||||
// return this.http.get(url, {responseType: 'json'}).pipe(map(res => res));
|
||||
// }
|
||||
|
||||
getListOfServicesByIds(ids: string): Observable<any> {
|
||||
// let url = "https://beta.providers.eosc-portal.eu/api/service/byID/openaire.validator,eudat.b2find,lindatclariah-cz.lindatclariah-cz_repository";
|
||||
let url = "https://beta.providers.eosc-portal.eu/api/service/byID/"+ids;
|
||||
return this.http.get(url, {responseType: 'json'}).pipe(map(res => res));
|
||||
// return this.http.get(url, {responseType: 'text'}).pipe(map(res => res));
|
||||
}
|
||||
|
||||
harvest(baseUrl: string, email: string = null): Observable<any> {
|
||||
let url: string = "https://ip-90-147-152-76.na2.garrservices.it/oai-collector-service/api/collect?oaiBaseUrl="+baseUrl+(email ? ("¬ificationEmail="+email) : "");
|
||||
console.log(url);
|
||||
return this.http.get(url, {responseType: 'json'}).pipe(map(res => res));
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 0c21afdd7f957bd640c5d40707af826a8d07fd7d
|
||||
Subproject commit 8d6522270c26451c7474630fc71e7fa3e31c5c0e
|
|
@ -1,5 +1,6 @@
|
|||
import {EnvProperties} from '../app/openaireLibrary/utils/properties/env-properties';
|
||||
|
||||
export let properties: EnvProperties = {
|
||||
environment: "beta"
|
||||
environment: "beta",
|
||||
reCaptchaSiteKey: "6LezhVIUAAAAAOb4nHDd87sckLhMXFDcHuKyS76P"
|
||||
};
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
import {EnvProperties} from '../app/openaireLibrary/utils/properties/env-properties';
|
||||
|
||||
export let properties: EnvProperties = {
|
||||
environment: 'development'
|
||||
environment: 'development',
|
||||
reCaptchaSiteKey: "6LcVtFIUAAAAAB2ac6xYivHxYXKoUvYRPi-6_rLu"
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue