import {ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {AdvancedField, Filter} from './searchUtils/searchHelperClasses.class'; import {SearchResearchResultsService} from '../services/searchResearchResults.service'; import {ErrorCodes} from '../utils/properties/errorCodes'; import {ErrorMessagesComponent} from '../utils/errorMessages.component'; import {OpenaireEntities, SearchFields} from '../utils/properties/searchFields'; import {SearchCustomFilter, SearchUtilsClass} from './searchUtils/searchUtils.class'; import {EnvProperties} from '../utils/properties/env-properties'; import {NewSearchPageComponent, SearchForm} from "./searchUtils/newSearchPage.component"; import {RangeFilter} from "../utils/rangeFilter/rangeFilterHelperClasses.class"; import {properties} from "../../../environments/environment"; import {ContextsService} from "../claims/claim-utils/service/contexts.service"; import {StringUtils} from "../utils/string-utils.class"; import {RefineResultsUtils} from "../services/servicesUtils/refineResults.class"; import {RefineFieldResultsService} from "../services/refineFieldResults.service"; @Component({ selector: 'search-research-results', template: ` ` }) export class SearchResearchResultsComponent { @Input() resultType: string = "result"; @Input() simpleSearchLink: string = ""; advancedSearchLink: string = ""; private errorCodes: ErrorCodes; private errorMessages: ErrorMessagesComponent; @Input() hasPrefix: boolean = true; @Input() searchForm: SearchForm = {class: 'search-form', dark: true}; public results = []; public filters = []; public rangeFilters: RangeFilter[] = []; public searchUtils: SearchUtilsClass = new SearchUtilsClass(); public searchFields: SearchFields = new SearchFields(); public fieldIds: string[] = this.searchFields.getResultAdvancedFields(); public fieldIdsMap = this.searchFields.RESULT_FIELDS; public rangeFields: string[][] = this.searchFields.RESULT_RANGE_FIELDS; public selectedFields: AdvancedField[] = []; public staticFields: string[] = this.searchFields.RESULT_STATIC_FIELDS; public staticFieldValues = this.searchFields.RESULT_STATIC_FIELD_VALUES; public staticFilters = RefineResultsUtils.parse(this.staticFieldValues, this.staticFields, this.resultType, "search", true); public orderedFilters; public resourcesQuery = "((oaftype exact result) and (resulttypeid exact " + this.resultType + "))"; public csvParams: string; public disableForms: boolean = false; public disableRefineForms: boolean = false; public loadPaging: boolean = true; public oldTotalResults: number = 0; @Input() openaireLink: string = null; @Input() customFilters: SearchCustomFilter[] = null; @Input() set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) { if(!Array.isArray(customFilter)) { this.customFilters = [customFilter]; }else{ this.customFilters = customFilter; } } public pagingLimit: number = 0; properties: EnvProperties = properties; public openaireEntities = OpenaireEntities; public refineFields: string[] = this.searchFields.RESULT_REFINE_FIELDS; public orderedFields = this.searchFields.RESULT_FIELDS_ORDERED; @ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent; @Input() simpleView: boolean = true; quickFilter: { filter: Filter, selected: boolean, filterId: string, value: string } = { filter: null, selected: true, filterId: "resultbestaccessright", value: "Open Access" }; @Input() includeOnlyResultsAndFilter: boolean = false; @Input() showBreadcrumb: boolean = false; @Output() searchPageUpdates = new EventEmitter(); @Input() showSwitchSearchLink: boolean = true; subs: any[] = []; searchResultsSub: any; searchFiltersSub: any; @Input() stickyForm:boolean = false; private timeoutId; private promise: Promise = null; private publicCommunities = null; @Input() usedBy: string = "search"; @Input() orcidQuery: string = ""; @Input() identifiers: string[] = []; @Input() pageTitlePrefix: string = ""; private refineQuery: string = ""; constructor(private route: ActivatedRoute, private _router: Router, private _searchResearchResultsService: SearchResearchResultsService, private _refineFieldsResultsService: RefineFieldResultsService, private _contextService: ContextsService, private cdr: ChangeDetectorRef) { this.results = []; this.errorCodes = new ErrorCodes(); this.errorMessages = new ErrorMessagesComponent(); this.searchUtils.status = this.errorCodes.LOADING; this.searchUtils.refineStatus = this.errorCodes.LOADING; this.getPublicCommunities(); this.searchFields.sortFieldsByName(this.fieldIds, this.fieldIdsMap); } getRoute(){ return this._router.url.split("?")[0]; } ngOnInit() { //TODO add checks about which result types are enabled! this.pagingLimit = this.properties.pagingLimit; if (!this.simpleSearchLink) { this.simpleSearchLink = this.properties.searchLinkToResults; } this.advancedSearchLink = this.properties.searchLinkToAdvancedResults; this.searchUtils.baseUrl = this.getRoute();//(this.simpleView) ? this.simpleSearchLink : this.advancedSearchLink; this.searchUtils.status = this.errorCodes.LOADING; var firstLoad = true; this.subs.push(this.route.queryParams.subscribe(params => { if(this.usedBy == "orcid"){ this.searchPage.usedBy = "orcid"; } //this.subs.push(this.route.queryParams.switchMap(params => { this.loadPaging = true; if (params['page'] && this.searchUtils.page != params['page']) { this.loadPaging = false; this.oldTotalResults = this.searchUtils.totalResults; } var refine = true; if(this.searchPage.searchUtils.refineStatus == this.errorCodes.DONE) { if (params['page'] != undefined && this.filters && !firstLoad && this.searchUtils.page != +params['page']) { refine = false; } if (params['sortBy'] != undefined && this.filters && !firstLoad && this.searchUtils.sortBy != params['sortBy']) { refine = false; } if (params['size'] != undefined && this.filters && !firstLoad && this.searchUtils.size != params['size']) { refine = false; } } let page = (params['page'] === undefined) ? 1 : +params['page']; this.searchUtils.page = (page <= 0) ? 1 : page; this.searchUtils.validateSize(params['size']); this.searchUtils.sortBy = (params['sortBy']) ? params['sortBy'] : ''; if (this.searchUtils.sortBy && this.searchUtils.sortBy != "resultdateofacceptance,descending" && this.searchUtils.sortBy != "resultdateofacceptance,ascending" && this.searchUtils.sortBy != "citation_count,descending" && this.searchUtils.sortBy != "popularity,descending" && this.searchUtils.sortBy != "influence,descending" && this.searchUtils.sortBy != "impulse,descending") { this.searchUtils.sortBy = ""; } this.selectedFields = []; this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, this.rangeFields, this.staticFields, this.fieldIdsMap,this.customFilters,params, this.resultType, this.quickFilter); if(refine) { this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, 0, "", true, this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); } else { this.searchUtils.refineStatus = this.errorCodes.DONE; } this._getResults(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), this.searchUtils.page, this.searchUtils.size, this.searchUtils.sortBy, refine, this.searchPage.getSearchAPIQueryForRangeFields(params) + this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad)); firstLoad = false; this.refineQuery = this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad); })); } ngOnDestroy() { if(this.searchResultsSub) { this.searchResultsSub.unsubscribe(); } if(this.searchFiltersSub) { this.searchFiltersSub.unsubscribe(); } for (let sub of this.subs) { sub.unsubscribe(); } } public getPublicCommunities() { this.promise = new Promise(resolve => { this._contextService.getPublicCommunitiesByState().subscribe( data => { if(this.publicCommunities == null) { this.publicCommunities = data.map(value => value.id); } resolve(); }, error => { this.handleError("Error getting communities status", error); resolve(); }); }); } racePromiseWithTimeout() { const timeoutPromise = new Promise((_, reject) => { this.timeoutId = setTimeout(() => { this.publicCommunities = []; reject(new Error('Request timed out')); }, 300); }); return Promise.race([this.promise, timeoutPromise]); } public _getFilters(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) { if(this.usedBy == "orcid" && this.orcidQuery) { parameters += (parameters ? ' and ' : '') + "(" + this.orcidQuery + ")"; } if (page <= this.pagingLimit || this.searchUtils.refineStatus == this.errorCodes.LOADING) { this.searchUtils.refineStatus = this.errorCodes.LOADING; this.disableRefineForms = true; this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}); this.searchFiltersSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery, true) // this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery) //.switchMap( .subscribe( data => { let totalResults = data[0]; let filters = data[2]; // if (refine) { // this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults); // this.rangeFilters = this.searchPage.prepareRangeFiltersToShow(); // } // // this.searchUtils.refineStatus = this.errorCodes.DONE; // // this.disableRefineForms = false; this.filtersReturned(refine, filters, totalResults, page); this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}) }, err => { this.filters = this.searchPage.prepareFiltersToShow([], 0); this.rangeFilters = this.searchPage.prepareRangeFiltersToShow(); this.staticFilters = this.searchPage.prepareStaticFiltersToShow(); this.handleError("Error getting refine filters for " + this.getEntityName(this.resultType, true, true), err); this.searchUtils.refineStatus = this.errorMessages.getErrorCode(err.status); this.disableRefineForms = false; this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}) } );//); } } public async filtersReturned(refine: boolean, filters: Filter[], totalResults, page: number) { if(!this.timeoutId) { try { await this.racePromiseWithTimeout(); } catch (error) { this.handleError("Getting communities status was over 300ms - timeout", error); } finally { clearTimeout(this.timeoutId); } } let communitiesFilter = filters.find(filters => filters.filterId == "community"); if(communitiesFilter && this.publicCommunities && this.publicCommunities.length > 0) { communitiesFilter.values = communitiesFilter.values.filter(value => { let valueId = ""; if(value.id) { let idArray = value.id.split("||"); if(idArray) { valueId = idArray[0]; } } //for(let publicCom of this.publicCommunities) { //if(valueId && publicCom['id'] == valueId) { if(valueId && this.publicCommunities.includes(valueId)) { return true; //} } }); } if (refine) { this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults); this.rangeFilters = this.searchPage.prepareRangeFiltersToShow(); this.staticFilters = this.searchPage.prepareStaticFiltersToShow(); if(this.orderedFields) { this.orderedFilters = []; for(let group of this.orderedFields) { if (group.type == "refine") { let groupedFilters = {title: group.title, values: []}; for (let field of group.values) { let index = this.filters.findIndex(filter => filter.filterId == field); if (index > -1) { groupedFilters.values.push(this.filters[index]); } } if (groupedFilters.values.length > 0) { this.orderedFilters.push(groupedFilters); } } else if (group.type == "range") { let groupedFilters = {title: group.title, values: []}; let from = group.values[0]; let to = group.values[1]; let index = this.rangeFilters.findIndex(filter => filter.originalFilterIdFrom == from && filter.originalFilterIdTo == to); if (index > -1) { groupedFilters.values.push(this.rangeFilters[index]); this.orderedFilters.push(groupedFilters); } } else if (group.type == "static") { let groupedFilters = {title: group.title, values: []}; for (let field of group.values) { let index = this.staticFilters.findIndex(filter => filter.filterId == field); if (index > -1) { groupedFilters.values.push(this.staticFilters[index]); } } if (groupedFilters.values.length > 0) { this.orderedFilters.push(groupedFilters); } } } } } this.searchUtils.refineStatus = this.errorCodes.DONE; if(totalResults == 0) { this.searchUtils.refineStatus = this.errorCodes.NONE; } if (this.searchUtils.refineStatus == this.errorCodes.DONE) { // Page out of limit!!! let totalPages: any = totalResults / (this.searchUtils.size); if (!(Number.isInteger(totalPages))) { totalPages = (parseInt(totalPages, 10) + 1); } if (totalPages < page) { this.searchUtils.refineStatus = this.errorCodes.OUT_OF_BOUND; } } if(this.searchUtils.refineStatus != this.errorCodes.DONE && this.searchUtils.status != this.searchUtils.refineStatus) { if (this.searchResultsSub) { this.searchResultsSub.unsubscribe(); } this.resultsReturned(refine, [], totalResults, page); } this.disableRefineForms = false; } public _getResults(parameters: string, page: number, size: number, sortBy: string, refine: boolean, refineFieldsFilterQuery = null) { if(this.usedBy == "orcid" && this.orcidQuery) { parameters += (parameters ? ' and ' : '') + "(" + this.orcidQuery + ")"; } if (page > this.pagingLimit) { size = 0; } if (page <= this.pagingLimit || this.searchUtils.status == this.errorCodes.LOADING) { // if (parameters != null && parameters != '') { // this.csvParams = "&fq=(" + this.resourcesQuery + " and (" + parameters + "))"; // } else { // this.csvParams = "&fq=" + this.resourcesQuery; // } this.csvParams = (parameters ? ("&fq=(" + parameters) : "") + (parameters ? ")" : ""); this.csvParams += (refineFieldsFilterQuery ? refineFieldsFilterQuery : ""); this.searchUtils.status = this.errorCodes.LOADING; this.disableForms = true; this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}); this.results = []; this.searchUtils.totalResults = 0; //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, (refine) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineFieldsFilterQuery) this.searchResultsSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery) //this.subs.push(this._searchResearchResultsService.advancedSearchResults(this.resultType, parameters, page, size, sortBy, this.properties, null, this.searchPage.getFields(), refineFieldsFilterQuery) .subscribe( data => { let totalResults = data[0]; let results = data[1]; // this.searchUtils.totalResults = totalResults; // this.results = results; // // if (refine) { // // this.filters = this.searchPage.prepareFiltersToShow(data[2],this.searchUtils.totalResults); // // this.rangeFilters = this.searchPage.prepareRangeFiltersToShow(); // // } else { // if(!refine) { // this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, false); // } // // this.searchPage.hideFilters = false; // // this.searchUtils.status = this.errorCodes.DONE; // if (this.searchUtils.totalResults == 0) { // this.searchUtils.status = this.errorCodes.NONE; // } // this.disableForms = false; this.resultsReturned(refine, results, totalResults, page); }, err => { this.handleError("Error getting " + this.getEntityName(this.resultType, true, true), err); this.searchUtils.status = this.errorMessages.getErrorCode(err.status); //TODO check erros (service not available, bad request) // if( ){ // this.searchUtils.status = ErrorCodes.ERROR; // } //var errorCodes:ErrorCodes = new ErrorCodes(); //this.searchUtils.status = errorCodes.NOT_AVAILABLE; /*if(err.status == '404') { this.searchUtils.status = this.errorCodes.NOT_FOUND; } else if(err.status == '500') { this.searchUtils.status = this.errorCodes.ERROR; } else { this.searchUtils.status = this.errorCodes.NOT_AVAILABLE; }*/ //this.searchPage.closeLoading(); this.disableForms = false; this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}) this.searchPage.hideFilters = false; } ); } } public resultsReturned(refine: boolean, results: any, totalResults, page: number) { this.searchUtils.totalResults = totalResults; this.results = results; if(!refine) { this.searchPage.buildPageURLParameters(this.filters, this.rangeFilters, this.staticFilters, false); } this.searchPage.hideFilters = false; this.searchUtils.status = this.errorCodes.DONE; if (this.searchUtils.totalResults == 0) { this.searchUtils.status = this.errorCodes.NONE; } if (this.searchUtils.status == this.errorCodes.DONE) { // Page out of limit!!! let totalPages: any = this.searchUtils.totalResults / (this.searchUtils.size); if (!(Number.isInteger(totalPages))) { totalPages = (parseInt(totalPages, 10) + 1); } if (totalPages < page) { this.searchUtils.totalResults = 0; this.searchUtils.status = this.errorCodes.OUT_OF_BOUND; } } if(this.searchUtils.status != this.errorCodes.DONE && this.searchUtils.refineStatus != this.searchUtils.status) { if(this.searchFiltersSub) { this.searchFiltersSub.unsubscribe(); } this.filtersReturned(refine, [], totalResults, page); } this.disableForms = false; this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils}); } private handleError(message: string, error) { console.error(this.getEntityName(this.resultType, true, true) + " advanced Search Page: " + message, error); } public getEntityName(entityType: string, plural: boolean, full: boolean): string { return StringUtils.getEntityName(entityType, plural); } public getEntityFileName(entityType: string) { return StringUtils.getEntityFileName(entityType); } public filterRequestedAll(oldFilter: Filter) { let fieldsStr: string = "&fields=" + oldFilter.filterId+"&refine=true"; this.searchFiltersSub = this._searchResearchResultsService.advancedSearchResults(this.resultType, this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), 1, 0, null, properties, fieldsStr, [oldFilter.filterId], this.refineQuery).subscribe( // this.searchFiltersSub = this._refineFieldsResultsService.getAllRefineFieldResultsByFieldName(oldFilter.filterId, this.resultType, this.properties, this.refineQuery).subscribe( res => { // let filter: Filter = res[1][0]; let filter: Filter = res[2][0]; if(filter.values.length == 0) { filter = oldFilter; filter.countAllValues = 0; } else { filter.countAllValues = filter.values.length; for (let value of filter.values) { for (let oldValue of oldFilter.values) { if (oldValue.id == value.id && oldValue.selected) { value.selected = true; break; } } } } let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); filter.isOpen = true; filter.countSelectedValues = oldFilter.countSelectedValues; filter.radioValue = oldFilter.radioValue; this.filters[index] = filter; this.updateOrderedFilter(filter); this.cdr.detectChanges(); }, error => { let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == oldFilter.filterId); oldFilter.countAllValues = 0; this.filters[index] = oldFilter; this.updateOrderedFilter(oldFilter); this.cdr.detectChanges(); } ) } public updateOrderedFilter(filter: Filter) { if(this.orderedFilters) { let groupIndex = 0; let index; for(let group of this.orderedFilters) { index = group.values.findIndex((fltr: Filter) => fltr.filterId == filter.filterId); if(index != -1) { break; } groupIndex++; } this.orderedFilters[groupIndex].values[index] = filter; } } }