diff --git a/claims/claim-utils/displayClaims/displayClaims.component.html b/claims/claim-utils/displayClaims/displayClaims.component.html index bdcc74b3..94034a2e 100644 --- a/claims/claim-utils/displayClaims/displayClaims.component.html +++ b/claims/claim-utils/displayClaims/displayClaims.component.html @@ -56,57 +56,76 @@
No links found
- +
+ +
+ diff --git a/claims/claim-utils/displayClaims/displayClaims.component.less b/claims/claim-utils/displayClaims/displayClaims.component.less index 0eadec18..e322586c 100644 --- a/claims/claim-utils/displayClaims/displayClaims.component.less +++ b/claims/claim-utils/displayClaims/displayClaims.component.less @@ -4,14 +4,4 @@ position: relative; padding: 0 20px; height: 100%; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 50%; - right: 0; - bottom: 0; - border-left: @global-border-width solid @global-border; - } } diff --git a/claims/claim-utils/displayClaims/displayClaims.component.ts b/claims/claim-utils/displayClaims/displayClaims.component.ts index d4204ceb..8fd1f4ee 100644 --- a/claims/claim-utils/displayClaims/displayClaims.component.ts +++ b/claims/claim-utils/displayClaims/displayClaims.component.ts @@ -52,6 +52,7 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy { lastIndexDate = null; public filterForm: FormGroup; public entities: string[] = []; + selected = []; allOptions: Option[] = [ {label: OpenaireEntities.PUBLICATIONS, value: "publication"}, @@ -310,23 +311,34 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy { } isSelected(value: string) { - return this.filterForm && this.filterForm.get('entities').value.find(entity => entity === value) + return this.filterForm && this.filterForm.get('entities').value.find(entity => entity === value); } - deleteOpen(index: number) { + deleteOpen(index: number = null) { this.index = index; this.deleteModal.alertTitle = 'Delete Confirmation'; - this.deleteModal.message = 'Are you sure you want to delete this link?'; + this.deleteModal.message = 'Are you sure you want to delete ' + (this.index != null ? '1' : this.selected.length) + ' link(s)?'; this.deleteModal.okButtonText = 'Yes'; this.deleteModal.open(); } delete() { - this.subscriptions.push(this._claimService.deleteBulk([this.claims[this.index].id], this.properties.claimsAPIURL).subscribe( + let claimsToBeDeleted = ((this.index != null) ? [this.claims[this.index].id] : this.selected.map(claim => claim.id)); + console.log(claimsToBeDeleted); + this.subscriptions.push(this._claimService.deleteBulk(claimsToBeDeleted, this.properties.claimsAPIURL).subscribe( res => { - this.claims.splice(this.index, 1); - this.resultsNum = this.resultsNum - 1; - NotificationHandler.rise('Link has been deleted successfully'); + if (this.index != null) { + this.claims.splice(this.index, 1); + this.resultsNum = this.resultsNum - 1; + NotificationHandler.rise('Link has been deleted successfully'); + } else { + claimsToBeDeleted.forEach(claimId => { + this.claims.splice(this.claims.findIndex((id) => id == claimId), 1); + }); + this.resultsNum = this.resultsNum - claimsToBeDeleted.length; + NotificationHandler.rise(claimsToBeDeleted.length + ' links have been deleted successfully'); + } + this.selected = []; let goToPage = this.page; if (this.totalPages(this.resultsNum) < this.page && this.page > 0) { goToPage = this.page - 1; @@ -334,7 +346,8 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy { this.goTo(goToPage); }, err => { this.handleErrors(err, "Error deleting claim with id: " + this.claims[this.index].id); - })); + } + )); } pageChange($event) { @@ -362,7 +375,44 @@ export class DisplayClaimsComponent implements OnInit, OnDestroy { } return totalPages; } - + + selectClaim(item: any, event) { + let value = event.currentTarget.checked; + if (value) { + this.selected.push(item); + } else { + for (var _i = 0; _i < this.selected.length; _i++) { + let claim = this.selected[_i]; + if (claim['id'] == item.id) { + this.selected.splice(_i, 1); + } + } + } + } + + selectAll(event) { + let value = event.currentTarget.checked; + if (value) { + this.selected = []; + for (let _i = 0; _i < this.claims.length; _i++) { + let claim = this.claims[_i]; + this.selected.push(claim); + } + } else { + this.selected = []; + } + } + + isSelectedClaim(id: string) { + for (let _i = 0; _i < this.selected.length; _i++) { + let claim = this.selected[_i]; + if (claim['id'] == id) { + return true; + } + } + return false; + } + private updateDescription(description: string) { this._meta.updateTag({content: description}, "name='description'"); this._meta.updateTag({content: description}, "property='og:description'"); diff --git a/claims/claim-utils/entityFormatter/claimEntityFormatter.component.ts b/claims/claim-utils/entityFormatter/claimEntityFormatter.component.ts index 6102d684..547e4c16 100644 --- a/claims/claim-utils/entityFormatter/claimEntityFormatter.component.ts +++ b/claims/claim-utils/entityFormatter/claimEntityFormatter.component.ts @@ -15,21 +15,22 @@ import {StringUtils} from "../../../utils/string-utils.class";
{{getEntityName(type)}}
-
- Link to: +
+ Link to:
-
- Link to: +
+ Link to:
-
- Link to: - {{entity.title}} +
+ Link to: +
+ {{entity.title}} +
` }) diff --git a/claims/claim-utils/entityFormatter/projectTitleFormatter.component.ts b/claims/claim-utils/entityFormatter/projectTitleFormatter.component.ts index 92557d9a..14ee0e60 100644 --- a/claims/claim-utils/entityFormatter/projectTitleFormatter.component.ts +++ b/claims/claim-utils/entityFormatter/projectTitleFormatter.component.ts @@ -20,7 +20,7 @@ import {properties} from "../../../../../environments/environment"; - Funder: {{project['funderName']}} + Funder: {{project['funderName']}} ` }) diff --git a/dashboard/menu/menu.component.ts b/dashboard/menu/menu.component.ts index d756a77f..9f89224b 100644 --- a/dashboard/menu/menu.component.ts +++ b/dashboard/menu/menu.component.ts @@ -372,10 +372,8 @@ export class MenuComponent implements OnInit { } public valueChange() { - this.elements.disable(); this.cdr.detectChanges(); this.elements.init(); - this.elements.enable(); } public get displayMenuItems() { diff --git a/dashboard/sharedComponents/sidebar/layout.service.ts b/dashboard/sharedComponents/sidebar/layout.service.ts index 17657431..dc515f81 100644 --- a/dashboard/sharedComponents/sidebar/layout.service.ts +++ b/dashboard/sharedComponents/sidebar/layout.service.ts @@ -88,6 +88,10 @@ export class LayoutService { * Handle it manually in the component, it doesn't use data * */ private rootClassSubject: BehaviorSubject = new BehaviorSubject(null); + /** + * Display help pop-up on non-admin pages. (default true for the rest of the pages) + * */ + private hasHelpPopUpSubject: BehaviorSubject = new BehaviorSubject(true); private subscriptions: any[] = []; ngOnDestroy() { @@ -343,4 +347,12 @@ export class LayoutService { this.rootClassSubject.next(value); } } + + get hasHelpPopUp(): Observable { + return this.hasHelpPopUpSubject.asObservable(); + } + + setHasHelpPopUp(value: boolean) { + this.hasHelpPopUpSubject.next(value); + } } diff --git a/dashboard/users/role-users/role-users.component.html b/dashboard/users/role-users/role-users.component.html index 6fb1d94f..88befe57 100644 --- a/dashboard/users/role-users/role-users.component.html +++ b/dashboard/users/role-users/role-users.component.html @@ -8,26 +8,26 @@
+ [searchControl]="filterForm.get('active')" [expandable]="true" [placeholder]="'Search ' + stakeholderUtils.roles[role] + 's'" searchInputClass="outer">
- -
-
-
-
- -
-
- - + [large]="true" classTitle="uk-background-primary uk-light" + (alertOutput)="saveIndicator()" + [okDisabled]="numberIndicatorFb && (numberIndicatorFb.invalid || numberIndicatorFb.pristine)"> +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ JSON Path +
+
+
+ This JSON path is not valid or the result has not been calculated yet. + Please press calculate on box below to see the result. +
+
+
+
+
+ + + + + + +
+
+ +
+
+
+ +
+
+
+
+
-
- -
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{urlParameterizedMessage}}
+ [okDisabled]="chartIndicatorFb && (chartIndicatorFb.invalid || chartIndicatorFb.pristine)"> +
+ +
+
+
+
+
-
- +
-
-
-
- There are schema enhancements that can be applied in this query. Apply - now +
-
- -
-
- -
-
- + +
+
+ +
+ You are about to delete + "{{ indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title ? indicator.indicatorPaths[0].parameters.title : '') }} + " indicator permanently. +
+ Indicators of all profiles based on this default indicator, will be deleted as well. +
+ Are you sure you want to proceed? +
- You are about to delete - "{{indicator.name ? indicator.name : (indicator.indicatorPaths[0]?.parameters?.title?indicator.indicatorPaths[0].parameters.title:'')}}" indicator permanently. -
- Indicators of all profiles based on this default indicator, will be deleted as well. -
- - - - Are you sure you want to proceed? -
-
- - -
-
- + +
+
+ +
+ You are about to delete this section and its indicators permanently. +
+ Sections of all profiles based on this default section and their contents, will be deleted as well. +
+ Are you sure you want to proceed?
- You are about to delete this section and its indicators permanently. -
- Sections of all profiles based on this default section and their contents, will be deleted as well. -
- - - - Are you sure you want to proceed? -
- -
-
- +
+
+ +
-
diff --git a/monitor-admin/topic/indicators.component.ts b/monitor-admin/topic/indicators.component.ts index 30343944..e4e4eb9d 100644 --- a/monitor-admin/topic/indicators.component.ts +++ b/monitor-admin/topic/indicators.component.ts @@ -20,7 +20,7 @@ import { Visibility } from "../../monitor/entities/stakeholder"; import { - AbstractControl, + AbstractControl, FormArray, FormGroup, UntypedFormArray, UntypedFormBuilder, UntypedFormControl, @@ -31,8 +31,8 @@ import {AlertModal} from "../../utils/modal/alert"; import {StatisticsService} from "../utils/services/statistics.service"; import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {DomSanitizer, SafeResourceUrl} from "@angular/platform-browser"; -import {Reorder, StakeholderService} from "../../monitor/services/stakeholder.service"; -import {Observable, Subscriber} from "rxjs"; +import {MoveIndicator, SectionInfo, StakeholderService} from "../../monitor/services/stakeholder.service"; +import {BehaviorSubject, Observable, Subscriber} from "rxjs"; import {LayoutService} from "../../dashboard/sharedComponents/sidebar/layout.service"; import {Router} from "@angular/router"; import {Role, Session, User} from "../../login/utils/helper.class"; @@ -45,6 +45,7 @@ import {NotificationHandler} from "../../utils/notification-handler"; import {IndicatorStakeholderBaseComponent} from "../utils/stakeholder-base.component"; import {properties} from "../../../../environments/environment"; import {StatsProfilesService} from "../utils/services/stats-profiles.service"; +import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component"; declare var UIkit; declare var copy; @@ -82,12 +83,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple public index: number = -1; public editing: boolean = false; public dragging: boolean = false; + /* Reorder indicators */ + public to: BehaviorSubject = new BehaviorSubject(null); /** Caches */ public safeUrls: Map = new Map([]); public numberResponses: Map = new Map(); public numberResults: Map = new Map(); - /** Import / Export Indicators */ - importLoading: boolean = false; + public loading: boolean = false; @ViewChild('editChartModal', {static: true}) editChartModal: AlertModal; @ViewChild('editNumberModal', {static: true}) editNumberModal: AlertModal; @ViewChild('deleteModal', {static: true}) deleteModal: AlertModal; @@ -95,12 +97,12 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple public sectionTypeToDelete: string; public sectionChildrenActionOnDelete: string; public indicatorChildrenActionOnDelete: string; - urlParameterizedMessage = null; - showCheckForSchemaEnhancements: boolean = false; private notification: Notification; @ViewChild('editNumberNotify', {static: true}) editNumberNotify: NotifyFormComponent; @ViewChild('editChartNotify', {static: true}) editChartNotify: NotifyFormComponent; @ViewChild('deleteNotify', {static: true}) deleteNotify: NotifyFormComponent; + /* Transition Groups */ + @ViewChild('transitionGroup') transitionGroup: TransitionGroupComponent; public isFullscreen: boolean = false; @@ -125,7 +127,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple private notificationService: NotificationService, private fb: UntypedFormBuilder, protected _router: Router, - private cdr: ChangeDetectorRef, private sanitizer: DomSanitizer) { super() this.filesToUpload = []; @@ -187,7 +188,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } }); if (document !== undefined) { - let callback = (list, type: IndicatorType, action: 'moved' | 'added' | 'removed'): void => { + let callback = (list): string[] => { let items: HTMLCollection = list.current.children; let reordered = []; for (let i = 0; i < items.length; i++) { @@ -195,12 +196,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple reordered.push(items.item(i).id); } } - let reorder: Reorder = { - action: action, - target: list.detail[1].id, - ids: reordered - } - this.reorderIndicators(list.current.id.toString().split('-')[1], type, reorder); + return reordered; }; this.numbers.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'start', '#number-' + section._id, (): void => { @@ -210,24 +206,32 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.dragging = false; })); this.subscriptions.push(UIkit.util.on(document, 'moved', '#number-' + section._id, (list): void => { - callback(list, "number", 'moved'); + this.reorderIndicators(section._id, 'number', callback(list)); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#number-' + section._id, (list): void => { - callback(list, "number", 'added'); + this.to.next({id: section._id, indicators: callback(list)}); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#number-' + section._id, (list): void => { - callback(list, "number", 'removed'); + let sub = this.to.asObservable().subscribe(to => { + if (to) { + let from: SectionInfo = {id: section._id, indicators: callback(list)}; + this.moveIndicator({target: list.detail[1].id, from: from, to: to}); + setTimeout(() => { + sub.unsubscribe(); + }) + } + }) })); }); this.charts.forEach((section) => { this.subscriptions.push(UIkit.util.on(document, 'moved', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'moved'); + this.reorderIndicators(section._id, 'chart', callback(list)); })); this.subscriptions.push(UIkit.util.on(document, 'added', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'added'); + //callback(list, "chart", 'added'); })); this.subscriptions.push(UIkit.util.on(document, 'removed', '#chart-' + section._id, (list): void => { - callback(list, "chart", 'removed'); + // callback(list, "chart", 'removed'); })); }); } @@ -264,7 +268,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple setNumbers() { this.numberSections = this.fb.array([]); this.numberResults.clear(); - let urls: Map = new Map(); + let urls: Map = new Map(); this.numbers.forEach((section, i) => { this.numberSections.push(this.fb.group({ _id: this.fb.control(section._id), @@ -276,11 +280,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple indicators: this.fb.control(section.indicators) })); section.indicators.forEach((number, j) => { - 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]); - urls.set(pair, indexes); + number.indicatorPaths.forEach((indicatorPath, k) => { + let url = this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath); + const pair = JSON.stringify([indicatorPath.source, url]); + const indexes = urls.get(pair) ? urls.get(pair) : []; + indexes.push([i, j, k]); + urls.set(pair, indexes); + }); }); }); this.numberSubscription.forEach(value => { @@ -302,10 +308,10 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple }); } - private calculateResults(response: any, indexes: [number, number][]) { - indexes.forEach(([i, j]) => { + private calculateResults(response: any, indexes: [number, number, number][]) { + indexes.forEach(([i, j, k]) => { let result = JSON.parse(JSON.stringify(response)); - this.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { + this.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } @@ -318,14 +324,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } else { result = 0; } - this.numberResults.set(i + '-' + j, result); + this.numberResults.set(i + '-' + j + '-' + k, result); }); } get charts(): Section[] { if (this.stakeholder.topics[this.topicIndex] && - this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && - this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].charts; } else { return []; @@ -334,8 +340,8 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple get numbers(): Section[] { if (this.stakeholder.topics[this.topicIndex] && - this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && - this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]) { return this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex].numbers; } else { return []; @@ -352,9 +358,9 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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]; + this.stakeholder.topics[this.topicIndex] && + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex] && + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] && !this.loading; } public get numberIndicatorPaths(): UntypedFormArray { @@ -365,6 +371,14 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple return this.chartIndicatorFb.get('indicatorPaths') as UntypedFormArray; } + public getActiveIndicatorPath(indicator: Indicator) { + if (indicator.activePath) { + return indicator.indicatorPaths[indicator.activePath]; + } else { + return indicator.indicatorPaths[0]; + } + } + public getNumberClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-medium@m uk-width-1-1'; @@ -461,7 +475,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } public getParameters(index: number, type: IndicatorType = 'chart'): UntypedFormArray { - if(type === 'chart') { + if (type === 'chart') { return this.chartIndicatorPaths.at(index).get('parameters') as UntypedFormArray; } else { return this.numberIndicatorPaths.at(index).get('parameters') as UntypedFormArray; @@ -474,7 +488,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple private getSecureUrlByStakeHolder(indicatorPath: IndicatorPath) { return this.sanitizer.bypassSecurityTrustResourceUrl( - this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath))); + this.indicatorUtils.getChartUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath))); } private getUrlByStakeHolder(indicatorPath: IndicatorPath) { @@ -486,71 +500,57 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple jsonPath.push(this.fb.control('', Validators.required)); } this.numberIndicatorPaths.push(this.fb.group({ - url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]), - jsonPath: jsonPath, - result: this.fb.control(0, Validators.required), - source: this.fb.control(source, Validators.required), - parameters: parameters, - format: this.fb.control(format, Validators.required) - } + url: this.fb.control(url, [Validators.required, StringUtils.urlValidator()]), + jsonPath: jsonPath, + result: this.fb.control(0, Validators.required), + source: this.fb.control(source, Validators.required), + parameters: parameters, + format: this.fb.control(format, Validators.required) + } )); let index = this.numberIndicatorPaths.length - 1; if (this.numberIndicatorPaths.at(index).get('url').valid) { this.validateJsonPath(index); - this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); } if (this.indicator.defaultId === null) { 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.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) { - this.urlParameterizedMessage = "This indicator couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly." + this.numberIndicatorPaths.at(index).get('result').setValue(null); + if (this.numberIndicatorPaths.at(index).get('url').valid) { + 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.indicator.indicatorPaths[index]) { + this.indicator.indicatorPaths[index] = indicatorPath; } else { - this.urlParameterizedMessage = "This indicator couldn't be generated properly. Please make sure chart data is for the current stakeholder." + this.indicator.indicatorPaths.push(indicatorPath); } - } else { - this.urlParameterizedMessage = null; - } - this.checkForSchemaEnhancements(this.numberIndicatorPaths.at(index).get('url').value); - if (this.indicator.indicatorPaths[index]) { - this.indicator.indicatorPaths[index] = indicatorPath; - } else { - this.indicator.indicatorPaths.push(indicatorPath); - } - if (indicatorPath.source) { - this.numberIndicatorPaths.at(index).get('source').setValue(indicatorPath.source); - } - (this.numberIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); - if (indicatorPath.jsonPath.length > 1 && this.getJsonPath(index).length == 1) { - let paths = indicatorPath.jsonPath; - for (let i = 0; i < paths.length; i++) { - if (i == this.getJsonPath(index).length) { - this.getJsonPath(index).push(this.fb.control('', Validators.required)); + if (indicatorPath.source) { + this.numberIndicatorPaths.at(index).get('source').setValue(indicatorPath.source); + } + (this.numberIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); + if (indicatorPath.jsonPath.length > 1 && this.getJsonPath(index).length == 1) { + let paths = indicatorPath.jsonPath; + for (let i = 0; i < paths.length; i++) { + if (i == this.getJsonPath(index).length) { + this.getJsonPath(index).push(this.fb.control('', Validators.required)); + } } + this.getJsonPath(index).setValue(paths) } - this.getJsonPath(index).setValue(paths) } - } else { - this.urlParameterizedMessage = null; - } - }) + }) ); this.subscriptions.push(this.numberIndicatorPaths.at(index).get('jsonPath').valueChanges.subscribe(value => { - if (this.indicator.indicatorPaths[index]) { - this.indicator.indicatorPaths[index].jsonPath = value; - } - this.numberIndicatorPaths.at(index).get('result').setValue(null); - }) + if (this.indicator.indicatorPaths[index]) { + this.indicator.indicatorPaths[index].jsonPath = value; + } + this.numberIndicatorPaths.at(index).get('result').setValue(null); + }) ); this.subscriptions.push(this.numberIndicatorPaths.at(index).get('source').valueChanges.subscribe(value => { - if (this.indicator.indicatorPaths[index]) { - this.indicator.indicatorPaths[index].source = value; - } - }) + if (this.indicator.indicatorPaths[index]) { + this.indicator.indicatorPaths[index].source = value; + } + }) ); } else { this.numberIndicatorPaths.at(index).get('url').disable(); @@ -561,30 +561,18 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple 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()]), - parameters: parameters, - type: this.fb.control(type) - } + url: this.fb.control(value, [Validators.required, StringUtils.urlValidator()]), + parameters: parameters, + type: this.fb.control(type) + } )); let index = this.chartIndicatorPaths.length - 1; if (disableUrl) { this.chartIndicatorPaths.at(index).get('url').disable(); } else { - 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.indicatorUtils.getChartSource(value), value, this.chartIndicatorPaths.at(index).get('type').value, this.stakeholder); - if (!this.isStakeholderParametersValid(indicatorPath)) { - // default profile - if (this.stakeholder.defaultId == null) { - this.urlParameterizedMessage = "This chart couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly." - } else { - this.urlParameterizedMessage = "This chart couldn't be generated properly. Please make sure chart data is for the current stakeholder." - } - } else { - this.urlParameterizedMessage = null; - } - this.checkForSchemaEnhancements(this.chartIndicatorPaths.at(index).get('url').value); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).get('type').setValue(indicatorPath.type); (this.chartIndicatorPaths.at(index) as UntypedFormGroup).setControl('parameters', this.getParametersAsFormArray(indicatorPath)); if (!this.indicator.indicatorPaths[index]) { @@ -594,17 +582,68 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple indicatorPath.safeResourceUrl = this.indicator.indicatorPaths[index].safeResourceUrl; this.indicator.indicatorPaths[index] = indicatorPath; } - } else { - this.urlParameterizedMessage = null; } })); } } - 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)); + public removeNumberIndicatorPath(index: number) { + this.numberIndicatorPaths.removeAt(index); + this.indicator.indicatorPaths.splice(index, 1); + this.transitionGroup.init(); + if (this.indicator.activePath === index) { + this.activeNumberIndicatorPath(Math.max(0, index - 1)); + } else if (this.indicator.activePath > index) { + this.activeNumberIndicatorPath(this.indicator.activePath - 1); + } + this.numberIndicatorFb.markAsDirty(); + } + public removeChartIndicatorPath(index: number) { + this.chartIndicatorPaths.removeAt(index); + this.indicator.indicatorPaths.splice(index, 1); + this.transitionGroup.init(); + if (this.indicator.activePath === index) { + this.activeChartIndicatorPath(Math.max(0, index - 1)); + } else if (this.indicator.activePath > index) { + this.activeChartIndicatorPath(this.indicator.activePath - 1); + } + this.chartIndicatorFb.markAsDirty(); + } + + public moveIndicatorPath(form: FormGroup, + indicatorPaths: FormArray, index: number, + newIndex: number = index - 1) { + this.transitionGroup.init(); + let a = indicatorPaths.at(index); + let b = indicatorPaths.at(newIndex); + indicatorPaths.setControl(index, b); + indicatorPaths.setControl(newIndex, a); + HelperFunctions.swap(this.indicator.indicatorPaths, index, newIndex); + if (this.indicator.activePath === index) { + this.indicator.activePath = newIndex; + } else if (this.indicator.activePath === newIndex) { + this.indicator.activePath = index; + } + form.markAsDirty(); + } + + public activeNumberIndicatorPath(index: number) { + let paths = this.numberIndicatorPaths; + if (index == paths.length) { + this.addNumberIndicatorPath(); + this.transitionGroup.init(); + } + this.indicator.activePath = index; + } + + public activeChartIndicatorPath(index: number) { + let paths = this.chartIndicatorPaths; + if (index == paths.length) { + this.addChartIndicatorPath(); + this.transitionGroup.init(); + } + this.indicator.activePath = index; } private getJsonPathAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray { @@ -620,6 +659,9 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple private getParametersAsFormArray(indicatorPath: IndicatorPath): UntypedFormArray { let parameters = this.fb.array([]); if (indicatorPath.parameters) { + if(!indicatorPath.parameters.statsProfile) { + indicatorPath.parameters.statsProfile = null; + } Object.keys(indicatorPath.parameters).forEach(key => { if (this.indicatorUtils.ignoredParameters.indexOf(key) === -1) { if (this.indicatorUtils.parametersValidators.has(key)) { @@ -640,7 +682,21 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } public editNumberIndicatorOpen(section: Section, id = null) { - this.urlParameterizedMessage = null; + this.editNumberModal.cancelButtonText = 'Cancel'; + this.editNumberModal.okButtonLeft = false; + this.editNumberModal.alertMessage = false; + if (this.index === -1) { + this.editNumberModal.alertTitle = 'Create a new number indicator'; + this.editNumberModal.okButtonText = 'Save'; + this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); + this.editNumberNotify.reset(this.notification.message); + } else { + this.editNumberModal.alertTitle = 'Edit number indicator\'s information'; + this.editNumberModal.okButtonText = 'Save Changes'; + this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); + this.editNumberNotify.reset(this.notification.message); + } + this.editNumberModal.stayOpen = true; this.section = section; this.index = (id) ? section.indicators.findIndex(value => value._id === id) : -1; if (this.index !== -1) { @@ -682,26 +738,26 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.numberIndicatorFb.get('description').disable(); }, 0); } - this.editNumberModal.cancelButtonText = 'Cancel'; - this.editNumberModal.okButtonLeft = false; - this.editNumberModal.alertMessage = false; - if (this.index === -1) { - this.editNumberModal.alertTitle = 'Create a new number indicator'; - this.editNumberModal.okButtonText = 'Save'; - this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); - this.editNumberNotify.reset(this.notification.message); - } else { - this.editNumberModal.alertTitle = 'Edit number indicator\'s information'; - this.editNumberModal.okButtonText = 'Save Changes'; - this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); - this.editNumberNotify.reset(this.notification.message); - } - this.editNumberModal.stayOpen = true; this.editNumberModal.open(); } public editChartIndicatorOpen(section: Section, id = null) { - this.urlParameterizedMessage = null; + this.editChartModal.cancelButtonText = 'Cancel'; + this.editChartModal.okButtonLeft = false; + this.editChartModal.alertMessage = false; + if (this.index === -1) { + this.editChartModal.alertTitle = 'Create a new chart indicator'; + this.editChartModal.okButtonText = 'Save'; + this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); + this.editChartNotify.reset(this.notification.message); + } else { + this.editChartModal.alertTitle = 'Edit chart indicator\'s information'; + this.editChartModal.okButtonText = 'Save Changes'; + this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); + ; + this.editChartNotify.reset(this.notification.message); + } + this.editChartModal.stayOpen = true; this.urlSubscriptions.forEach(value => { if (value instanceof Subscriber) { value.unsubscribe(); @@ -725,7 +781,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple }); this.indicator.indicatorPaths.forEach(indicatorPath => { this.addChartIndicatorPath(this.getUrlByStakeHolder(indicatorPath), - this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type); + this.getParametersAsFormArray(indicatorPath), this.indicator.defaultId !== null, indicatorPath.type); indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); }); } else { @@ -748,22 +804,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.chartIndicatorFb.get('description').disable(); }, 0); } - this.editChartModal.cancelButtonText = 'Cancel'; - this.editChartModal.okButtonLeft = false; - this.editChartModal.alertMessage = false; - if (this.index === -1) { - this.editChartModal.alertTitle = 'Create a new chart indicator'; - this.editChartModal.okButtonText = 'Save'; - this.notification = NotificationUtils.createIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); - this.editChartNotify.reset(this.notification.message); - } else { - this.editChartModal.alertTitle = 'Edit chart indicator\'s information'; - this.editChartModal.okButtonText = 'Save Changes'; - this.notification = NotificationUtils.editIndicator(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name); - ; - this.editChartNotify.reset(this.notification.message); - } - this.editChartModal.stayOpen = true; this.editChartModal.open(); } @@ -863,7 +903,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.setCharts(); this.setNumbers(); this.initReorder(); - if(properties.notificationsAPIURL) { + if (properties.notificationsAPIURL) { this.notification = NotificationUtils.importIndicators(this.user.fullname, this.stakeholder.alias); this.notification.entity = this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index]._id; this.notification.name = this.user.firstname; @@ -900,20 +940,39 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple }); } } - this.editing = false; - this.importLoading = false; + this.finish(); NotificationHandler.rise('Indicators have been imported successfully!'); }, error => { this.chartIndicatorFb = null; NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); - this.editing = false; - this.importLoading = false; + this.finish(); })); } - reorderIndicators(sectionId: string, type: IndicatorType, reorder: Reorder) { + finish() { + this.editing = false; + this.loading = false; + } + + moveIndicator(moveIndicator: MoveIndicator) { + this.editing = true; + let path = [ + this.stakeholder._id, + this.stakeholder.topics[this.topicIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex]._id, + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id + ]; + this.subscriptions.push(this.stakeholderService.moveIndicator(this.properties.monitorServiceAPIURL, path, moveIndicator).subscribe(subCategory => { + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex] = subCategory; + this.setCharts(); + this.setNumbers(); + this.editing = false; + })); + } + + reorderIndicators(sectionId: string, type: IndicatorType, indicators: string[]) { this.editing = true; let path = [ this.stakeholder._id, @@ -922,7 +981,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.subcategoryIndex]._id, sectionId ]; - this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, reorder, type).subscribe(indicators => { + this.subscriptions.push(this.stakeholderService.reorderIndicators(this.properties.monitorServiceAPIURL, path, indicators).subscribe(indicators => { if (type === 'chart') { this.charts.find(section => section._id === sectionId).indicators = indicators; this.setCharts(); @@ -936,7 +995,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple hasDifference(index: number, type: IndicatorType = 'chart'): boolean { let hasDifference = false; - if(type === 'chart') { + if (type === 'chart') { this.chartIndicatorPaths.at(index).value.parameters.forEach(parameter => { if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) { hasDifference = true; @@ -945,7 +1004,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple }); return hasDifference || this.indicator.indicatorPaths[index].safeResourceUrl.toString() !== this.getSecureUrlByStakeHolder(this.indicator.indicatorPaths[index]).toString(); - } else if(type === 'number') { + } else if (type === 'number') { let indicatorPath = this.numberIndicatorPaths.at(index).value; indicatorPath.parameters.forEach(parameter => { if (parameter.value !== this.indicator.indicatorPaths[index].parameters[parameter.key]) { @@ -966,12 +1025,12 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple } refreshIndicator(type: IndicatorType = 'chart') { - if(type === 'chart') { + if (type === 'chart') { this.indicator = this.indicatorUtils.generateIndicatorByForm(this.chartIndicatorFb.value, this.indicator.indicatorPaths, 'chart'); this.indicator.indicatorPaths.forEach(indicatorPath => { indicatorPath.safeResourceUrl = this.getSecureUrlByStakeHolder(indicatorPath); }); - } else if(type === 'number') { + } else if (type === 'number') { this.indicator = this.indicatorUtils.generateIndicatorByForm(this.numberIndicatorFb.value, this.indicator.indicatorPaths, 'number'); this.indicator.indicatorPaths.forEach((indicatorPath, index) => { this.validateJsonPath(index); @@ -1159,24 +1218,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple })); } - // deleteNumberSectionOpen(section: Section, index: number) { - // this.section = section; - // this.index = index; - // this.deleteNumberSectionModal.alertTitle = 'Delete Section'; - // this.deleteNumberSectionModal.cancelButtonText = 'No'; - // this.deleteNumberSectionModal.okButtonText = 'Yes'; - // this.deleteNumberSectionModal.open(); - // } - // - // deleteChartSectionOpen(section: Section, index: number) { - // this.section = section; - // this.index = index; - // this.deleteChartSectionModal.alertTitle = 'Delete Section'; - // this.deleteChartSectionModal.cancelButtonText = 'No'; - // 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; @@ -1233,10 +1274,6 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple })); } - private checkForSchemaEnhancements(url: string) { - this.showCheckForSchemaEnhancements = this.isAdministrator && url && !this.properties.useOldStatisticsSchema && this.indicatorUtils.checkForSchemaEnhancements(url) && this.properties.dashboard != 'irish'; - } - migrateFromOldImportJsonFile(charts) { // first section contains numbers // second contains charts @@ -1252,35 +1289,50 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple if (chart['sectionIndex'] == null) { chart['sectionIndex'] = chart['type'] == 'chart' ? chartsSection : 0; } + if (chart.url && chart.jsonPath) { + chart.indicatorPaths = [{url: chart.url, jsonPath: chart.jsonPath}]; + } else if(chart.url) { + chart.indicatorPaths = [{url: chart.url}]; + } } return charts; } - importIndicatorsAndSave(charts: any[]) { + importIndicatorsAndSave(stakeholder: Stakeholder, charts: any[]) { let sectionsToSave: Section[] = []; let countIndicators = 0; + if (stakeholder.type !== this.stakeholder.type) { + UIkit.notification("The type of this profile is not the same with the file's one!", { + status: 'warning', + timeout: 6000, + pos: 'bottom-right' + }); + this.finish(); + return; + } // name description additionalDescription, height, width, visibility - let noValidParams = 0; let duplicates = 0; charts = this.migrateFromOldImportJsonFile(charts); for (let chart of charts) { - chart.visibility = this.showVisibility?chart.visibility:this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities); + chart.visibility = this.showVisibility ? chart.visibility : this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities); if (!sectionsToSave[chart['sectionIndex']]) { let sectionToSave = new Section(chart['sectionType'] ? chart['sectionType'] : chart['type'], chart['sectionTitle']); sectionToSave.indicators = []; sectionsToSave[chart['sectionIndex']] = sectionToSave; } let exists = false; - let indicatorPath; + let indicatorPaths: IndicatorPath[] = []; // validate indicators' schema from file let invalid_file_message; if (!chart.type) { invalid_file_message = "No indicator type is specified. Type should be chart or number."; } else if (chart.type != "chart" && chart.type != "number") { invalid_file_message = "Invalid indicator type. Type should be chart or number."; - } else if (chart.type == "number" && !chart.jsonPath) { + } else if (chart.indicatorPaths.length === 0) { + invalid_file_message = "No indicator paths are specified." + } else if (chart.type == "number" && chart.indicatorPaths.filter(path => !path.jsonPath).length > 0) { invalid_file_message = "No jsonPath is specified for number indicator." - } else if (!chart.url) { + } else if (chart.indicatorPaths.filter(path => !path.url).length > 0) { invalid_file_message = "No indicator url is specified."; } @@ -1290,46 +1342,47 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); break; } if (chart.type == "chart") { - 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)) { - duplicates++; - exists = true; - } - } - - } + indicatorPaths = chart.indicatorPaths.map(path => this.indicatorUtils.generateIndicatorByChartUrl(this.indicatorUtils.getChartSource(path.url), path.url, chart.type, stakeholder)); + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].charts.forEach((section: Section) => { + section.indicators.forEach(indicator => { + indicator.indicatorPaths.forEach(path => { + let size = indicatorPaths.length; + indicatorPaths = indicatorPaths.filter(indicatorPath => JSON.stringify(path.chartObject) !== JSON.stringify(indicatorPath.chartObject)) + if (indicatorPaths.length < size) { + duplicates = duplicates + (size - indicatorPaths.length); + exists = true; + } + }); + }); + }); } else if (chart.type == "number") { - 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)) { - duplicates++; - exists = true; - } - } - - } + indicatorPaths = chart.indicatorPaths.map(path => + this.indicatorUtils.generateIndicatorByNumberUrl(this.indicatorUtils.getNumberSource(path.url), path.url, + stakeholder, path.jsonPath, this.indicatorUtils.numberSources.get(this.indicatorUtils.getNumberSource(path.url)))); + this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[this.index].numbers.forEach((section: Section) => { + section.indicators.forEach(indicator => { + indicator.indicatorPaths.forEach(path => { + let size = indicatorPaths.length; + indicatorPaths = indicatorPaths.filter(indicatorPath => JSON.stringify(path.chartObject) !== JSON.stringify(indicatorPath.chartObject)) + if (indicatorPaths.length < size) { + duplicates = duplicates + (size - indicatorPaths.length); + exists = true; + } + }); + }); + }); } - if (!this.isStakeholderParametersValid(indicatorPath)) { - noValidParams++; - } - if (!exists) { - let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, this.showVisibility?"RESTRICTED":this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities), [indicatorPath]); + if (indicatorPaths.length > 0) { + let i: Indicator = new Indicator(chart.name, chart.description, chart.additionalDescription, chart.type, chart.width, chart.height, this.showVisibility ? "RESTRICTED" : this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities), indicatorPaths); sectionsToSave[chart['sectionIndex']].indicators.push(i); countIndicators++; } - } - if (duplicates > 0) { UIkit.notification(duplicates + " urls already exist and will not be imported!", { status: 'warning', @@ -1337,19 +1390,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple pos: 'bottom-right' }); } - if (noValidParams > 0 && !(this.stakeholder.type == 'country')) { - let noValidMessage = "Some indicators couldn't be generated properly. Please make sure chart data is for the current stakeholder."; - if (this.stakeholder.defaultId == null) { - noValidMessage = "Some indicators couldn't be generated properly. Stakeholders based on this profile may not inherit the data correctly."; - } - UIkit.notification(noValidMessage, { - status: 'danger', - timeout: 6000, - pos: 'bottom-right' - }); - this.editing = false; - this.importLoading = false; - } else if (sectionsToSave.length > 0 && countIndicators > 0) { + if (sectionsToSave.length > 0 && countIndicators > 0) { this.saveIndicators(sectionsToSave.filter(section => !!section)); } if (sectionsToSave.length == 0 || countIndicators == 0) { @@ -1358,8 +1399,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); } } @@ -1370,36 +1410,41 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple let indexIndicator: number = 0; this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].numbers.forEach(section => { section.indicators.forEach(indicator => { - indicator.indicatorPaths.forEach(indicatorPath => { - indicators[indexIndicator] = { - "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.indicatorUtils.getNumberUrl(indicatorPath.source, this.indicatorUtils.getFullUrl(this.stakeholder, indicatorPath)), - "sectionTitle": section.title, - "sectionType": section.type, - "sectionIndex": index - }; - indexIndicator++; - }); + indicators[indexIndicator] = { + "indicatorPaths": indicator.indicatorPaths.map(path => { + return { + jsonPath: path.jsonPath, + url: this.indicatorUtils.getNumberUrl(path.source, this.indicatorUtils.getFullUrl(this.stakeholder, path)) + } + }), + "type": indicator.type, "name": indicator.name, + "description": indicator.description, "additionalDescription": indicator.additionalDescription, + "visibility": indicator.visibility, "width": indicator.width, "height": indicator.height, + "sectionTitle": section.title, + "sectionType": section.type, + "sectionIndex": index + }; + indexIndicator++; }); index++; }); this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories[subcategoryIndex].charts.forEach(section => { section.indicators.forEach(indicator => { - indicator.indicatorPaths.forEach(indicatorPath => { - indicators[indexIndicator] = { - "type": indicator.type, "name": indicator.name, - "description": indicator.description, "additionalDescription": indicator.additionalDescription, - "visibility": indicator.visibility, "width": indicator.width, "height": indicator.height, - "url": this.getUrlByStakeHolder(indicatorPath), - "sectionTitle": section.title, - "sectionType": section.type, - "sectionIndex": index - }; - indexIndicator++; - }); + indicators[indexIndicator] = { + "indicatorPaths": indicator.indicatorPaths.map(path => { + return { + url: this.getUrlByStakeHolder(path) + } + }), + "type": indicator.type, "name": indicator.name, + "description": indicator.description, "additionalDescription": indicator.additionalDescription, + "visibility": indicator.visibility, "width": indicator.width, "height": indicator.height, + "sectionTitle": section.title, + "sectionType": section.type, + "sectionIndex": index + }; + indexIndicator++; }); index++; @@ -1408,8 +1453,12 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple let topic = this.stakeholder ? this.stakeholder.topics[this.topicIndex] : null; let category = topic ? topic.categories[this.categoryIndex] : null; let subCategory = category ? category.subCategories[subcategoryIndex] : null; - - var jsonFileUrl = window.URL.createObjectURL(new Blob([JSON.stringify(indicators)], {type: 'application/json'})); + let json = { + stakeholder: HelperFunctions.copy(this.stakeholder), + indicators: indicators + } + delete json.stakeholder.topics; + var jsonFileUrl = window.URL.createObjectURL(new Blob([JSON.stringify(json)], {type: 'application/json'})); var a = window.document.createElement('a'); window.document.body.appendChild(a); a.setAttribute('style', 'display: none'); @@ -1418,14 +1467,13 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple a.click(); window.URL.revokeObjectURL(jsonFileUrl); a.remove(); // remove the element - - this.editing = false; + this.finish(); } fileChangeEvent(fileInput: any, index) { this.index = index; this.editing = true; - this.importLoading = true; + this.loading = true; this.filesToUpload = >fileInput.target.files; this.upload(); } @@ -1438,8 +1486,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); return; } else { if (this.filesToUpload[0].name.indexOf(".json") == -1 || (this.filesToUpload[0].type != "application/json")) { @@ -1449,27 +1496,30 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); return; } } this.makeFileRequest(this.properties.utilsService + '/upload?type=json', [], this.filesToUpload).then(async (result: string) => { - - let json_result = JSON.parse(result); - + let json = JSON.parse(result); // validate file - if (!json_result || json_result.length == 0) { + if (json && Array.isArray(json)) { + UIkit.notification("This file is not supported any more. Please export indicators and try again!", { + status: 'danger', + timeout: 6000, + pos: 'bottom-right' + }); + this.finish(); + } else if (!json || json?.indicators.length == 0) { UIkit.notification("Importing file is empty", { status: 'danger', timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); } else { - this.importIndicatorsAndSave(json_result); + this.importIndicatorsAndSave(json.stakeholder, json.indicators); } }, (error) => { console.error("Error importing files", error); @@ -1478,8 +1528,7 @@ export class IndicatorsComponent extends IndicatorStakeholderBaseComponent imple timeout: 6000, pos: 'bottom-right' }); - this.editing = false; - this.importLoading = false; + this.finish(); }); } diff --git a/monitor-admin/topic/topic.component.ts b/monitor-admin/topic/topic.component.ts index b178eb46..40d128d8 100644 --- a/monitor-admin/topic/topic.component.ts +++ b/monitor-admin/topic/topic.component.ts @@ -242,30 +242,18 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } topicChanged(callback: Function, save: boolean = false) { - if(this.topics && save) { - this.topics.disable(); - } - if(this.categories) { - this.categories.disable(); - } - if(this.subCategories) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.topics && save) { this.topics.init(); - this.topics.enable(); } if(this.categories) { this.categories.init(); - this.categories.enable(); } if(this.subCategories) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -359,6 +347,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics.splice(this.index, 1); if(this.topicIndex === this.index) { this.chooseTopic(Math.max(0, this.index - 1)); + } else if(this.topicIndex > this.index) { + this.chooseTopic(this.topicIndex - 1); } }, true); }; @@ -388,23 +378,15 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } categoryChanged(callback: Function, save: boolean = false) { - if(this.categories && save) { - this.categories.disable(); - } - if(this.subCategories) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.categories && save) { this.categories.init(); - this.categories.enable(); } if(this.subCategories) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -500,6 +482,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics[this.topicIndex].categories.splice(this.index, 1); if(this.categoryIndex === this.index) { this.chooseCategory(Math.max(0, this.index - 1)); + } else if(this.categoryIndex > this.index) { + this.chooseCategory(this.categoryIndex - 1); } }, true); }; @@ -528,16 +512,12 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, } subCategoryChanged(callback: Function, save: boolean = false) { - if(this.subCategories && save) { - this.subCategories.disable(); - } if(callback) { callback(); } this.cdr.detectChanges(); if(this.subCategories && save) { this.subCategories.init(); - this.subCategories.enable(); } } @@ -640,6 +620,8 @@ export class TopicComponent extends StakeholderBaseComponent implements OnInit, this.stakeholder.topics[this.topicIndex].categories[this.categoryIndex].subCategories.splice(this.index, 1); if(this.subCategoryIndex === this.index) { this.chooseSubcategory(Math.max(0, this.index - 1)); + } else if(this.subCategoryIndex > this.index) { + this.chooseSubcategory(this.subCategoryIndex - 1); } }, true); }; diff --git a/monitor-admin/topic/topic.module.ts b/monitor-admin/topic/topic.module.ts index 71e9b9d9..4c887228 100644 --- a/monitor-admin/topic/topic.module.ts +++ b/monitor-admin/topic/topic.module.ts @@ -20,11 +20,12 @@ import {TransitionGroupModule} from "../../utils/transition-group/transition-gro import {NumberRoundModule} from "../../utils/pipes/number-round.module"; import {SideBarModule} from "../../dashboard/sharedComponents/sidebar/sideBar.module"; import {SidebarMobileToggleModule} from "../../dashboard/sharedComponents/sidebar/sidebar-mobile-toggle/sidebar-mobile-toggle.module"; +import {SliderTabsModule} from "../../sharedComponents/tabs/slider-tabs.module"; @NgModule({ imports: [ CommonModule, TopicRoutingModule, ClickModule, RouterModule, FormsModule, AlertModalModule, - ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule + ReactiveFormsModule, InputModule, IconsModule, PageContentModule, LoadingModule, NotifyFormModule, LogoUrlPipeModule, TransitionGroupModule, NumberRoundModule, SideBarModule, SidebarMobileToggleModule, SliderTabsModule ], declarations: [ TopicComponent, IndicatorsComponent diff --git a/monitor-admin/utils/indicator-utils.ts b/monitor-admin/utils/indicator-utils.ts index 9360c228..3e8cf554 100644 --- a/monitor-admin/utils/indicator-utils.ts +++ b/monitor-admin/utils/indicator-utils.ts @@ -17,6 +17,11 @@ import {Session} from "../../login/utils/helper.class"; import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {properties} from "src/environments/environment"; +class Roles { + manager = 'manager'; + member = 'member'; +} + class Entities { stakeholder = 'Dashboard'; funder = 'Funder'; @@ -37,6 +42,7 @@ class Entities { } export class StakeholderConfiguration { + public static ROLES: Roles = new Roles(); public static ENTITIES: Entities = new Entities(); public static TYPES: Option[] = [ {value: 'funder', label: StakeholderConfiguration.ENTITIES.funder}, @@ -55,9 +61,15 @@ export class StakeholderConfiguration { {icon: 'incognito', value: "PRIVATE", label: 'Private'}, ]; public static CACHE_INDICATORS: boolean = true; + public static NUMBER_MULTI_INDICATOR_PATHS = false; + public static CHART_MULTI_INDICATOR_PATHS = true; } export class StakeholderUtils { + get roles() { + return StakeholderConfiguration.ROLES; + } + get entities() { return StakeholderConfiguration.ENTITIES; } @@ -82,6 +94,14 @@ export class StakeholderUtils { return StakeholderConfiguration.CACHE_INDICATORS; } + get hasMultiNumberIndicatorPaths() { + return StakeholderConfiguration.NUMBER_MULTI_INDICATOR_PATHS; + } + + get hasMultiChartIndicatorPaths() { + return StakeholderConfiguration.CHART_MULTI_INDICATOR_PATHS; + } + visibilityIcon: Map = new Map(this.visibilities.map(option => [option.value, option.icon])); defaultValue(options: Option[]) { diff --git a/monitor/entities/stakeholder.ts b/monitor/entities/stakeholder.ts index 49c8e755..a33506ac 100644 --- a/monitor/entities/stakeholder.ts +++ b/monitor/entities/stakeholder.ts @@ -183,6 +183,7 @@ export class Indicator { visibility: Visibility; defaultId: string; indicatorPaths: IndicatorPath[]; + activePath: number = 0; overlay: Overlay = false; constructor(name: string, description: string, additionalDescription:string, type: IndicatorType, width: IndicatorSize,height: IndicatorSize, visibility: Visibility, indicatorPaths: IndicatorPath[], defaultId: string = null) { diff --git a/monitor/monitor-indicator-stakeholder-base.component.ts b/monitor/monitor-indicator-stakeholder-base.component.ts index 4573dee4..c6d388e3 100644 --- a/monitor/monitor-indicator-stakeholder-base.component.ts +++ b/monitor/monitor-indicator-stakeholder-base.component.ts @@ -53,7 +53,6 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator minYear = Dates.currentYear - 20; maxYear = Dates.currentYear; public numberResults: Map = new Map(); - public chartsActiveType: Map = new Map(); public clipboard; /** Services */ @@ -214,15 +213,17 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : ""); //clear numbers when filters change this.numberResults.clear(); - let urls: Map = new Map(); + let urls: Map = new Map(); this.activeSubCategory.numbers.forEach((section, i) => { section.indicators.forEach((number, j) => { if (this.hasPermission(number.visibility)) { - let url = this.getFullUrl(number.indicatorPaths[0]); - const pair = JSON.stringify([number.indicatorPaths[0].source, url]); - const indexes = urls.get(pair) ? urls.get(pair) : []; - indexes.push([i, j]); - urls.set(pair, indexes); + number.indicatorPaths.forEach((indicatorPath, k) => { + let url = this.getFullUrl(indicatorPath); + const pair = JSON.stringify([indicatorPath.source, url]); + const indexes = urls.get(pair) ? urls.get(pair) : []; + indexes.push([i, j, k]); + urls.set(pair, indexes); + }) } }); }); @@ -231,10 +232,10 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator let activeSubcategory = this.activeSubCategory._id; this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => { if(activeSubcategory === this.activeSubCategory._id) { - indexes.forEach(([i, j]) => { + indexes.forEach(([i, j, k]) => { if( this.activeSubCategory?.numbers[i]?.indicators[j]) { let result = JSON.parse(JSON.stringify(response)); - this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[0].jsonPath.forEach(jsonPath => { + this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } @@ -247,7 +248,7 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator } else { result = 0; } - this.numberResults.set(i + '-' + j, result); + this.numberResults.set(i + '-' + j + '-' + k, result); } }); } @@ -255,10 +256,9 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator }); this.activeSubCategory.charts.forEach((section, i) => { section.indicators.forEach((indicator, j) => { - if (indicator.indicatorPaths.length > 0) { - indicator.indicatorPaths[0].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[0]); - this.chartsActiveType.set(i + '-' + j, indicator.indicatorPaths[0]); - } + indicator.indicatorPaths.forEach((indicatorPath, k) => { + indicator.indicatorPaths[k].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[k]); + }); }); }); if (this.cdr && !(this.cdr as ViewRef).destroyed) { @@ -271,10 +271,12 @@ export abstract class MonitorIndicatorStakeholderBaseComponent extends Indicator this.indicatorUtils.getChartUrl(indicatorPath.source, this.getFullUrl(indicatorPath))); } - public setActiveChart(i: number, j: number, type: string) { - let activeChart = this.activeSubCategory.charts[i].indicators[j].indicatorPaths.filter(indicatorPath => indicatorPath.type === type)[0]; - activeChart.safeResourceUrl = this.getUrlByStakeHolder(activeChart); - this.chartsActiveType.set(i + '-' + j, activeChart); + public getActiveIndicatorPath(indicator: Indicator) { + if(indicator.activePath) { + return indicator.indicatorPaths[indicator.activePath]; + } else { + return indicator.indicatorPaths[0]; + } } public filter() { diff --git a/monitor/services/stakeholder.service.ts b/monitor/services/stakeholder.service.ts index 3f0f3a11..d8b8bf30 100644 --- a/monitor/services/stakeholder.service.ts +++ b/monitor/services/stakeholder.service.ts @@ -1,16 +1,21 @@ import {Injectable} from "@angular/core"; import {HttpClient} from "@angular/common/http"; import {BehaviorSubject, from, Observable, Subscriber} from "rxjs"; -import {Indicator, Section, Stakeholder, StakeholderInfo, Visibility} from "../entities/stakeholder"; +import {Indicator, Section, Stakeholder, StakeholderInfo, SubCategory, Visibility} from "../entities/stakeholder"; import {HelperFunctions} from "../../utils/HelperFunctions.class"; import {map} from "rxjs/operators"; import {properties} from "../../../../environments/environment"; import {CustomOptions} from "../../services/servicesUtils/customOptions.class"; -export interface Reorder { - action: 'moved' | 'added' | 'removed', - target: string, - ids: string[]; +export interface SectionInfo { + id: string; + indicators: string[]; +} + +export interface MoveIndicator { + target: string; + from: SectionInfo; + to: SectionInfo; } @Injectable({ @@ -128,7 +133,6 @@ export class StakeholderService { if (element.alias && element.alias.startsWith('/')) { element.alias = element.alias.slice(1); } - path = HelperFunctions.encodeArray(path); return this.http.post(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save', element, CustomOptions.registryOptions()).pipe(map(element => { if (path.length === 0) { @@ -140,7 +144,6 @@ export class StakeholderService { } saveBulkElements(url: string, indicators, path: string[] = []): Observable { - path = HelperFunctions.encodeArray(path); return this.http.post(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save-bulk', indicators, CustomOptions.registryOptions()).pipe(map(element => { if (path.length === 0) { @@ -152,7 +155,6 @@ export class StakeholderService { } saveSection(url: string, element: any, path: string[] = [], index: number = -1): Observable
{ - path = HelperFunctions.encodeArray(path); return this.http.post
(url + ((path.length > 0) ? '/' : '') + path.join('/') + '/save/' + index, element, CustomOptions.registryOptions()).pipe(map(element => { return HelperFunctions.copy(element); @@ -160,7 +162,6 @@ export class StakeholderService { } deleteElement(url: string, path: string[], childrenAction: string = null): Observable { - path = HelperFunctions.encodeArray(path); let params: string = ""; if (childrenAction) { params = "?children=" + childrenAction; @@ -169,17 +170,21 @@ export class StakeholderService { } reorderElements(url: string, path: string[], ids: string[]): Observable { - path = HelperFunctions.encodeArray(path); return this.http.post(url + '/' + path.join('/') + '/reorder', ids, CustomOptions.registryOptions()); } - reorderIndicators(url: string, path: string[], reorder: Reorder, type: string = 'chart'): Observable { - path = HelperFunctions.encodeArray(path); - return this.http.post(url + '/' + path.join('/') + '/' + type + '/reorder', reorder, CustomOptions.registryOptions()).pipe(map(indicators => { + reorderIndicators(url: string, path: string[], indicators: string[]): Observable { + return this.http.post(url + '/' + path.join('/') + '/reorder', indicators, CustomOptions.registryOptions()).pipe(map(indicators => { return HelperFunctions.copy(indicators); })); } + moveIndicator(url: string, path: string[], moveIndicator: MoveIndicator): Observable { + return this.http.post(url + '/' + path.join('/') + '/moveIndicator', moveIndicator, CustomOptions.registryOptions()).pipe(map(subCategory => { + return HelperFunctions.copy(subCategory); + })); + } + getStakeholderAsObservable(): Observable { return this.stakeholderSubject.asObservable(); } diff --git a/orcid/my-orcid-links/searchMyOrcidResults.module.ts b/orcid/my-orcid-links/searchMyOrcidResults.module.ts index 87ce11d0..66cf5358 100644 --- a/orcid/my-orcid-links/searchMyOrcidResults.module.ts +++ b/orcid/my-orcid-links/searchMyOrcidResults.module.ts @@ -6,15 +6,15 @@ import {RouterModule} from '@angular/router'; import {ResultPreviewModule} from "../../utils/result-preview/result-preview.module"; import {ErrorMessagesModule} from "../../utils/errorMessages.module"; import {searcMyOrcidResultsComponent} from "./searchMyOrcidResults.component"; -import {OrcidModule} from "../orcid.module"; import {NoLoadPaging} from "../../searchPages/searchUtils/no-load-paging.module"; import {PagingModule} from "../../utils/paging.module"; +import {OrcidCoreModule} from "../orcid-core.module"; @NgModule({ imports: [ CommonModule, FormsModule, RouterModule, ErrorMessagesModule, - ResultPreviewModule, OrcidModule, NoLoadPaging, PagingModule + ResultPreviewModule, OrcidCoreModule, NoLoadPaging, PagingModule ], declarations: [ searcMyOrcidResultsComponent diff --git a/orcid/orcid-core.module.ts b/orcid/orcid-core.module.ts new file mode 100644 index 00000000..eda20ab1 --- /dev/null +++ b/orcid/orcid-core.module.ts @@ -0,0 +1,43 @@ +import {NgModule} from '@angular/core'; +import {CommonModule} from '@angular/common'; + +import {RouterModule} from '@angular/router'; + +import {OrcidComponent} from './orcid.component'; +import {OrcidService} from './orcid.service'; +import {OrcidWorkComponent} from './orcid-work.component'; +import {AlertModalModule} from '../utils/modal/alertModal.module'; +import {ResultLandingService} from '../landingPages/result/resultLanding.service'; +import {LoadingModule} from '../utils/loading/loading.module'; +import {ResultLandingUtilsModule} from '../landingPages/landing-utils/resultLandingUtils.module'; +import {IconsModule} from '../utils/icons/icons.module'; +import {IconsService} from "../utils/icons/icons.service"; +import {orcid_add, orcid_bin} from "../utils/icons/icons"; +import {FullScreenModalModule} from "../utils/modal/full-screen-modal/full-screen-modal.module"; +import {LogServiceModule} from "../utils/log/LogService.module"; +import {OrcidRoutingModule} from "./orcid-routing.module"; + +@NgModule({ + imports: [ + CommonModule, RouterModule, AlertModalModule, LoadingModule, ResultLandingUtilsModule, + IconsModule, FullScreenModalModule, LogServiceModule + ], + declarations: [ + OrcidComponent, + OrcidWorkComponent + ], + providers:[ + OrcidService, ResultLandingService + ], + exports: [ + OrcidComponent, + OrcidWorkComponent + ] +}) + + +export class OrcidCoreModule{ + constructor(private iconsService: IconsService) { + this.iconsService.registerIcons([orcid_add, orcid_bin]) + } +} diff --git a/orcid/orcid.module.ts b/orcid/orcid.module.ts index 54bae78b..5743c46a 100644 --- a/orcid/orcid.module.ts +++ b/orcid/orcid.module.ts @@ -1,43 +1,15 @@ import {NgModule} from '@angular/core'; -import {CommonModule} from '@angular/common'; - -import {RouterModule} from '@angular/router'; - -import {OrcidComponent} from './orcid.component'; -import {OrcidService} from './orcid.service'; -import {OrcidWorkComponent} from './orcid-work.component'; -import {AlertModalModule} from '../utils/modal/alertModal.module'; -import {ResultLandingService} from '../landingPages/result/resultLanding.service'; -import {LoadingModule} from '../utils/loading/loading.module'; -import {ResultLandingUtilsModule} from '../landingPages/landing-utils/resultLandingUtils.module'; -import {IconsModule} from '../utils/icons/icons.module'; import {IconsService} from "../utils/icons/icons.service"; import {orcid_add, orcid_bin} from "../utils/icons/icons"; -import {FullScreenModalModule} from "../utils/modal/full-screen-modal/full-screen-modal.module"; -import {LogServiceModule} from "../utils/log/LogService.module"; import {OrcidRoutingModule} from "./orcid-routing.module"; +import {OrcidCoreModule} from "./orcid-core.module"; +import {OrcidComponent} from "./orcid.component"; @NgModule({ - imports: [ - CommonModule, RouterModule, OrcidRoutingModule, AlertModalModule, LoadingModule, ResultLandingUtilsModule, - IconsModule, FullScreenModalModule, LogServiceModule - ], - declarations: [ - OrcidComponent, - OrcidWorkComponent - ], - providers:[ - OrcidService, ResultLandingService - ], - exports: [ - OrcidComponent, - OrcidWorkComponent - ] + imports: [OrcidCoreModule, OrcidRoutingModule], + exports: [OrcidComponent] }) export class OrcidModule{ - constructor(private iconsService: IconsService) { - this.iconsService.registerIcons([orcid_add, orcid_bin]) - } } diff --git a/role-verification/role-verification.component.ts b/role-verification/role-verification.component.ts index 1b54fe75..2c260add 100644 --- a/role-verification/role-verification.component.ts +++ b/role-verification/role-verification.component.ts @@ -12,6 +12,8 @@ import {EmailService} from "../utils/email/email.service"; import {Composer} from "../utils/email/composer"; import {ClearCacheService} from "../services/clear-cache.service"; import {BaseComponent} from "../sharedComponents/base/base.component"; +import {StakeholderUtils} from "../monitor-admin/utils/indicator-utils"; +import {StringUtils} from "../utils/string-utils.class"; @Component({ selector: 'role-verification', @@ -19,12 +21,9 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
- You have been invited to join {{name}} {{(service === 'monitor' ? 'Monitor' : 'Research Community')}} Dashboard - as a manager. + You have been invited to join {{name}} {{(dashboard)}} Dashboard as a {{stakeholderUtils.roles.manager}}. Fill in the verification code, sent to - your - email, to accept the invitation request. + your email, to accept the invitation request.
@@ -36,14 +35,12 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
-
+ (alertOutput)="verifyMember()" [okDisabled]="(code.invalid || loading)"> +
- You have been invited to join {{name}} Monitor Dashboard as a member. + You have been invited to join {{name}} {{(dashboard)}} Dashboard as a {{stakeholderUtils.roles.member}}. Fill in the verification code, sent - to - your - email, to accept the invitation request. + to your email, to accept the invitation request.
@@ -54,13 +51,6 @@ import {BaseComponent} from "../sharedComponents/base/base.component";
-
-
- Welcome! You are now a member of the OpenAIRE Monitor Dashboard for the {{name}}! - From now on, you will have access to our restricted content. -
-
@@ -95,6 +85,8 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, public userInfoLink = null; @Input() public relativeTo: ActivatedRoute = this._route; + @Input() + public dashboard: string = 'Research Community'; public user: User; public verification: any; public code: UntypedFormControl; @@ -105,8 +97,8 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, @ViewChild('errorModal') errorModal: AlertModal; public error: string = null; public loading: boolean = false; - public isMember: boolean = false; - + public stakeholderUtils: StakeholderUtils = new StakeholderUtils(); + constructor(protected _route: ActivatedRoute, protected _router: Router, private fb: UntypedFormBuilder, @@ -117,18 +109,23 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, private cdr: ChangeDetectorRef) { super(); } - + ngOnInit() { this.reset(); } - + ngAfterViewInit() { + this.init(); + } + + init() { + this.ngOnDestroy(); this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => { this.user = user; this.paramsSubscription = this._route.queryParams.subscribe(params => { if (params) { this.cdr.detectChanges(); - if(params['verify'] && !this.isMember) { + if(params['verify']) { if (this.user) { this.subscriptions.push(this.userRegistryService.getInvitation(params['verify']).subscribe(verification => { this.verification = verification; @@ -155,51 +152,43 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, relativeTo: this.relativeTo }); } - } else if(this.isMember) { - this.openMemberModal(); } } else { - this.isMember = false; this.cdr.detectChanges(); } }); })); } - + ngOnDestroy() { super.ngOnDestroy(); if (this.paramsSubscription instanceof Subscription) { this.paramsSubscription.unsubscribe(); } } - + public openManagerModal() { this.error = null; this.managerModal.okButtonLeft = false; this.managerModal.okButtonText = 'Accept'; this.managerModal.stayOpen = true; this.managerModal.cancelButtonText = 'Cancel'; - this.managerModal.alertTitle = 'Manager Invitation'; + this.managerModal.alertTitle = StringUtils.capitalize(this.stakeholderUtils.roles.manager) + ' Invitation'; this.managerModal.open(); } - + public openMemberModal() { this.error = null; - if(this.isMember) { - this.memberModal.cancelButton = false; - this.memberModal.okButtonText = 'Close'; - } else { - this.memberModal.cancelButton = true; - this.memberModal.okButtonText = 'Accept'; - } + this.memberModal.cancelButton = true; + this.memberModal.okButtonText = 'Accept'; this.memberModal.okButtonLeft = false; this.memberModal.stayOpen = true; this.memberModal.cancelButtonText = 'Cancel'; - this.memberModal.alertTitle = 'Member Invitation'; + this.memberModal.alertTitle = StringUtils.capitalize(this.stakeholderUtils.roles.member) + ' Invitation'; this.cdr.detectChanges(); this.memberModal.open(); } - + public openErrorModal() { this.error = null; this.errorModal.cancelButton = false; @@ -207,27 +196,20 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, this.errorModal.alertTitle = 'Invalid URL'; this.errorModal.open(); } - + public verifyManager() { this.loading = true; this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value).subscribe(() => { this.clearCacheService.clearCache('Managers updated'); this.managerModal.cancel(); this.error = null; - this.userManagementService.updateUserInfo(() => { - if (this.paramsSubscription instanceof Subscription) { - this.paramsSubscription.unsubscribe(); - } - if(this.service === "irish") { - this.loading = false; - this.userManagementService.login(properties.domain + '/admin/' + this.verification.entity); - } else if (this.service === "monitor" ) { - this.loading = false; - this._router.navigate(['/admin/' + this.verification.entity]); - } else { - this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager', + if(this.service === "irish" || this.service === "monitor") { + this.loading = false; + this.userManagementService.login(properties.domain + '/admin/' + this.verification.entity); + } else { + this.subscriptions.push(this.emailService.notifyManagers(this.id, 'manager', Composer.composeEmailToInformOldManagersForTheNewOnes(this.name, this.id)).subscribe(() => { - this.subscriptions.push(this.emailService.notifyNewManager(Composer.composeEmailForNewManager(this.id, this.name)).subscribe( + this.subscriptions.push(this.emailService.notifyNewManager(Composer.composeEmailForNewManager(this.id, this.name)).subscribe( () => { this.loading = false; window.location.href = properties.adminPortalURL + '/' + this.verification.entity; @@ -237,49 +219,38 @@ export class RoleVerificationComponent extends BaseComponent implements OnInit, this.loading = false; window.location.href = properties.adminPortalURL + '/' + this.verification.entity; } - )); - }, error => { - console.error(error); - this.loading = false; - window.location.href = properties.adminPortalURL + '/' + this.verification.entity; - })); - } - }); + )); + }, error => { + console.error(error); + this.loading = false; + window.location.href = properties.adminPortalURL + '/' + this.verification.entity; + })); + } }, error => { this.loading = false; this.error = 'The verification code is invalid'; })); } - + public verifyMember() { this.loading = true; - if (!this.isMember) { this.subscriptions.push(this.userRegistryService.verify(this.verification.id, this.code.value, "member").subscribe(() => { this.clearCacheService.clearCache('Members updated'); + this.memberModal.cancel(); this.loading = false; this.error = null; - this.isMember = true; - this.userManagementService.updateUserInfo(() => { - if (this.paramsSubscription instanceof Subscription) { - this.paramsSubscription.unsubscribe(); - } - this.cancel(); - }); + window.location.href = window.location.href.split('?')[0]; }, error => { this.loading = false; this.error = 'The verification code is invalid'; })); - } else { - this.memberModal.cancel(); - } } - + public reset() { this.code = this.fb.control('', [Validators.required, Validators.pattern('^[+0-9]{6}$')]); } - + cancel() { - this.isMember = false; this._router.navigate([]); } } diff --git a/searchPages/searchUtils/newSearchPage.component.html b/searchPages/searchUtils/newSearchPage.component.html index f9143437..d59cb0b1 100644 --- a/searchPages/searchUtils/newSearchPage.component.html +++ b/searchPages/searchUtils/newSearchPage.component.html @@ -1,11 +1,11 @@

-
+
  • - + {{customFilter.valueName}}
  • @@ -15,7 +15,7 @@
  • - + {{type.name}}
-
0) || (staticFilters && staticFilters.length > 0) + || (rangeFilters && rangeFilters.length > 0) || (filters && filters.length > 0))) + && (results.length > 0 || (searchUtils.refineStatus == errorCodes.LOADING && searchUtils.status != errorCodes.LOADING) || (!hideFilters && (existingFiltersWithValues > 0 || (selectedRangeFilters + selectedFilters + selectedTypesNum) > 0))) " class="uk-width-1-4@m search-filters"> @@ -308,31 +310,47 @@ [href]="openaireLink+this.routerHelper.createQueryParamsString(this.parameterNames, this.parameterValues)" target="_blank"> OpenAIRE - Explore.
- + +
+ +
+ + {{searchUtils.totalResults|number}} + {{type}} + + for + {{searchTerm}} + + + ({{advancedSearchTerms}} rule{{advancedSearchTerms == 1 ? '' : 's'}} applied) + + + + {{oldTotalResults|number}} + {{type}}, page + {{searchUtils.page | number}} + of {{(totalPages(oldTotalResults)|number)}} + +
-
+
+ *ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'" + [isDisabled]="disabled" + [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults"> - Data dump + Zenodo dumpData dump
- -
- -
- -
-
+ +
+ class="uk-grid uk-flex-middle uk-child-width-1-1 uk-child-width-1-2@m" uk-grid>
+ class="uk-margin-small-left uk-flex uk-flex-middle" [class.uk-flex-center]="mobile" [class.uk-margin-medium-top]="mobile"> + *ngIf="( entityType !='community' && entityType != 'stakeholder') && usedBy == 'search'" + [isDisabled]="disabled" + [type]="csvPath" [csvParams]="csvParams" [totalResults]="searchUtils.totalResults"> - Data dump + Zenodo dumpData dump
+ +
+ +
+ +
+

For more results please try a new, more specific query

diff --git a/searchPages/searchUtils/newSearchPage.component.ts b/searchPages/searchUtils/newSearchPage.component.ts index cf9f105a..e8447acb 100644 --- a/searchPages/searchUtils/newSearchPage.component.ts +++ b/searchPages/searchUtils/newSearchPage.component.ts @@ -1085,7 +1085,7 @@ export class NewSearchPageComponent implements OnInit, OnDestroy, OnChanges { let params = ""; let doisParams = ""; var DOIs: Identifier[] = Identifier.getIdentifiersFromString(value); - if ((entityType == 'publication' || entityType == 'dataset' || entityType == 'software' || entityType == 'other' || entityType == "result" || entityType == "dataprovider" || entityType == "service")) { + if ((entityType == 'publication' || entityType == 'dataset' || entityType == 'software' || entityType == 'other' || entityType == "result" || entityType == "dataprovider" || entityType == "service" || entityType == "organization")) { for (let identifier of DOIs) { // console.log(identifier) // pidclassid exact \"doi\" and pid exact \"10.1016/j.nima.2015.11.134\" diff --git a/searchPages/searchUtils/searchResult.component.ts b/searchPages/searchUtils/searchResult.component.ts index 4303238b..33ba74c0 100644 --- a/searchPages/searchUtils/searchResult.component.ts +++ b/searchPages/searchUtils/searchResult.component.ts @@ -57,7 +57,7 @@ export class SearchResultComponent implements OnInit, OnChanges { this.previewResults.push(this.getResultPreview(result)); } - if ((properties.adminToolsPortalType == "explore" || properties.adminToolsPortalType == "community" || properties.adminToolsPortalType == "aggregator") + if ((properties.adminToolsPortalType == "explore" || properties.adminToolsPortalType == "community" || properties.adminToolsPortalType == "aggregator" || properties.dashboard == "irish") && Session.isLoggedIn() && this.results && this.results.length > 0 && (this.type == "result" || this.type == "publication" || this.type == "dataset" || this.type == "software" || this.type == "other") ) { diff --git a/services/searchResearchResults.service.ts b/services/searchResearchResults.service.ts index 3e49a7cc..aadcd730 100644 --- a/services/searchResearchResults.service.ts +++ b/services/searchResearchResults.service.ts @@ -133,7 +133,14 @@ export class SearchResearchResultsService { return this.http.get((properties.useLongCache && size == 0 && !params && (!refineQuery || !refineQuery.includes("fq="))) ? (properties.cacheUrl + encodeURIComponent(url)) : url) .pipe(map(res => [res['meta'].total, this.parseResults(resultType, res['results'], properties), RefineResultsUtils.parse(res['refineResults'], refineFields, "publication")])); } + countResults(field:string,value:string): any { + let url = properties.utilsService + "/portals/countResults"; + if (field && value) { + url += "?field=" + encodeURIComponent(field) + "&value="+encodeURIComponent(value); + } + return this.http.get((properties.useLongCache ) ? (properties.cacheUrl + encodeURIComponent(url)) : url); + } searchResultForEntity(resultType: string, params: string, page: number, size: number, properties: EnvProperties): any { let link = properties.searchAPIURLLAst; //let url = link+params+"/"+this.getEntityQueryName(resultType,true)+ "?format=json"; diff --git a/sharedComponents/menu.ts b/sharedComponents/menu.ts index e3b38e60..b4328834 100644 --- a/sharedComponents/menu.ts +++ b/sharedComponents/menu.ts @@ -23,10 +23,11 @@ export class MenuItem { isFeatured: boolean; isActive: boolean; target: string = "_blank"; + badge?: string = ""; // used only for RDGraph portal (FAIRCORE4EOSC) constructor(id: string, title: string, url: string, route: string, needsAuthorization: boolean, entitiesRequired: string[], routeRequired: string[], params, icon: Icon = null, fragment = null, customClass = null, routeActive = null, - target: string = "_blank", type: string = "internal", isFeatured: boolean = false, items: MenuItem[] = []) { + target: string = "_blank", type: string = "internal", isFeatured: boolean = false, items: MenuItem[] = [], badge: string = "") { this._id = id; this.title = title; this.url = url; @@ -43,6 +44,7 @@ export class MenuItem { this.target = target; this.type = type; this.isFeatured = isFeatured; + this.badge = badge; } public static isTheActiveMenu(menu: MenuItem, currentRoute: any, activeMenuItem: string = ""): boolean { diff --git a/sharedComponents/navigationBar.component.html b/sharedComponents/navigationBar.component.html index 7f502eab..a0147369 100644 --- a/sharedComponents/navigationBar.component.html +++ b/sharedComponents/navigationBar.component.html @@ -41,7 +41,9 @@ {{menu.title}} + [fragment]="menu.fragment"> + {{menu.badge}} + {{menu.title}} {{menu.title}} - {{menu.title}} + + {{menu.badge}} + {{menu.title}}
diff --git a/sharedComponents/tabs/slider-tabs.component.ts b/sharedComponents/tabs/slider-tabs.component.ts index d4246f23..666f90a2 100644 --- a/sharedComponents/tabs/slider-tabs.component.ts +++ b/sharedComponents/tabs/slider-tabs.component.ts @@ -6,11 +6,14 @@ import { ElementRef, EventEmitter, Input, OnDestroy, Output, QueryList, - ViewChild + ViewChild, + Inject, + PLATFORM_ID } from "@angular/core"; import {SliderTabComponent} from "./slider-tab.component"; import {ActivatedRoute, Router} from "@angular/router"; import {Subscription} from "rxjs"; +import {isPlatformServer} from "@angular/common"; import Timeout = NodeJS.Timeout; declare var UIkit; @@ -20,7 +23,7 @@ declare var UIkit; template: `
-
+
- - + + + +
`, }) @@ -112,6 +117,11 @@ export class SliderTabsComponent implements AfterViewInit, OnDestroy { * */ @Input() public flexPosition: 'center' | 'left' | 'right' = 'left'; + /** + * Set a class for the container + * */ + @Input() + public containerClass: string; /** * Set a class above tabs * */ @@ -138,10 +148,13 @@ export class SliderTabsComponent implements AfterViewInit, OnDestroy { private subscriptions: any[] = []; private observer: IntersectionObserver; private timeout: Timeout; + isServer: boolean; constructor(private route: ActivatedRoute, private router: Router, - private cdr: ChangeDetectorRef) { + private cdr: ChangeDetectorRef, + @Inject(PLATFORM_ID) private platform: any) { + this.isServer = isPlatformServer(this.platform); } ngAfterViewInit() { @@ -164,7 +177,7 @@ export class SliderTabsComponent implements AfterViewInit, OnDestroy { } }); if (this.type === 'static') { - let tabs = UIkit.tab(this.tabsElement.nativeElement, {connect: this.connect}); + let tabs = UIkit.switcher(this.tabsElement.nativeElement, {connect: this.connect}); tabs.show(this.activeIndex); if (this.connect.includes('#')) { this.scrollToStart(); diff --git a/utils/email/composer.ts b/utils/email/composer.ts index 676dc4c2..ab3c69f0 100644 --- a/utils/email/composer.ts +++ b/utils/email/composer.ts @@ -2,6 +2,7 @@ import {Email} from "./email"; import {Body} from "./body"; import {properties} from "../../../../environments/environment"; import {User} from "../../login/utils/helper.class"; +import {StakeholderConfiguration} from "../../monitor-admin/utils/indicator-utils"; export class Composer { private static noteBodySize = "14px"; @@ -335,13 +336,13 @@ export class Composer { email.subject = 'National Open Access Monitor Ireland | ' + name; email.recipient = recipient; email.body = '

Dear user,

' + - '

You have been invited to be a ' + role +' of the for the National Open Access Monitor, Ireland dashboard for the ' + name + '.

' + + '

You have been invited to be a ' + StakeholderConfiguration.ROLES[role] +' of the for the National Open Access Monitor, Ireland dashboard for the ' + name + '.

' + '

Click this URL and use the verification code below to accept the invitation.

' + '

The verification code is ((__code__)).

' + '

At your first sign in you will be asked to accept and consent to the "OpenAIRE Personal Data Protection Policy and Consent Form" to be able to use the service.

' + (role === "manager"? - '

As a manager of the National Open Access Monitor, Ireland, you will have access to the administration part of the dashboard, where you will be able to also invite other users to become managers.

': - '

As a member of the OpenAIRE Monitor Dashboard, you will have access to the restricted access areas of the profile for the ' + name + '.') + + '

As a ' + StakeholderConfiguration.ROLES[role] + ' of the National Open Access Monitor, Ireland, you will have access to the administration part of the dashboard, where you will be able to also invite other users to become ' + StakeholderConfiguration.ROLES['member'] + 's.

': + '

As a ' + StakeholderConfiguration.ROLES[role] + ' of the National Open Access Monitor, Ireland, you will have access to the sandbox of the profile for the ' + name + '.') + '

Please contact us at ' + properties.helpdeskEmail + ' if you have any questions or concerns.

' + '

Kind Regards
The OpenAIRE Team

' + diff --git a/utils/properties/environments/environment.ts b/utils/properties/environments/environment.ts index fb86e5d4..283a1295 100644 --- a/utils/properties/environments/environment.ts +++ b/utils/properties/environments/environment.ts @@ -23,7 +23,7 @@ export let common: EnvProperties = { rorURL: "https://ror.org/", isniURL: "https://isni.org/isni/", wikiDataURL: "https://www.wikidata.org/wiki/", - fundRefURL: "https://api.crossref.org/funders/", + fundRefURL: "https://data.crossref.org/fundingdata/funder/", fairSharingURL: "https://fairsharing.org/", eoscMarketplaceURL: "https://marketplace.eosc-portal.eu/services/", sherpaURL: "http://sherpa.ac.uk/romeo/issn/", diff --git a/utils/properties/searchFields.base.ts b/utils/properties/searchFields.base.ts index 79ece5b3..a029a42e 100644 --- a/utils/properties/searchFields.base.ts +++ b/utils/properties/searchFields.base.ts @@ -333,6 +333,14 @@ export class SearchFieldsBase { operator: "pf", equalityOperator: " = ", filterType: "triplet" + }, + ["haslicense"]: { + name: "License", + type: "triplet", + param: "haslicense", + operator: "hl", + equalityOperator: " = ", + filterType: "triplet" } }; @@ -369,6 +377,11 @@ export class SearchFieldsBase { { name: "All", id: "", count: "0" }, { name: "Yes", id: "true", count: "0" }, { name: "No", id: "false", count: "0" } + ], + ["haslicense"]: [ + { name: "All", id: "", count: "0" }, + { name: "Yes", id: "true", count: "0" }, + { name: "No", id: "false", count: "0" } ] }; @@ -784,8 +797,8 @@ export class SearchFieldsBase { //ORGANIZATION - public ORGANIZATION_REFINE_FIELDS: string[] = ["country"] - public ORGANIZATION_ADVANCED_FIELDS: string[] = ["q", "organizationlegalname", "organizationlegalshortname", "country"]; + public ORGANIZATION_REFINE_FIELDS: string[] = ["countrynojurisdiction"] + public ORGANIZATION_ADVANCED_FIELDS: string[] = ["q", "organizationlegalname", "organizationlegalshortname", "countrynojurisdiction", "pid"]; public ORGANIZATION_FIELDS: { [key: string]: FieldDetails } = { ["q"]: {name: "Any field", type: "keyword", param: "q", operator: "op", equalityOperator: "=", filterType: null}, @@ -805,7 +818,7 @@ export class SearchFieldsBase { equalityOperator: "=", filterType: null }, - ["country"]: { + ["countrynojurisdiction"]: { name: "Country", type: "vocabulary", param: "country", @@ -813,6 +826,7 @@ export class SearchFieldsBase { equalityOperator: " exact ", filterType: "checkbox" }, + ["pid"]: {name: "PID", type: "keyword", param: "pid", operator: "pd", equalityOperator: " exact ", filterType: null} }; // public ORGANIZATION_INDEX:string[] = ["organizationcountryname"]//,"organizationeclegalbody"]; // public ADVANCED_SEARCH_ORGANIZATION_PARAM:string[] = ["q","contenttype","compatibility","country","type"]; @@ -948,7 +962,7 @@ export class SearchFieldsBase { return "and"; } else if (fieldId == "instancetypename" || fieldId == "eoscdatasourcetype" || fieldId == "resultlanguagename" || fieldId == "datasourceodlanguages" - || fieldId == "datasourcecompatibilityname" || fieldId == "country" || fieldId == "datasourceodcontenttypes" + || fieldId == "datasourcecompatibilityname" || fieldId == "country" || fieldId == "countrynojurisdiction" || fieldId == "datasourceodcontenttypes" || fieldId == "resulthostingdatasource" || fieldId == "collectedfrom") { return "or"; } diff --git a/utils/result-preview/result-preview.module.ts b/utils/result-preview/result-preview.module.ts index 5ad90baf..12726cc6 100644 --- a/utils/result-preview/result-preview.module.ts +++ b/utils/result-preview/result-preview.module.ts @@ -4,15 +4,15 @@ import {ResultPreviewComponent} from "./result-preview.component"; import {RouterModule} from "@angular/router"; import {ShowAuthorsModule} from "../authors/showAuthors.module"; import {ResultLandingUtilsModule} from "../../landingPages/landing-utils/resultLandingUtils.module"; -import {OrcidModule} from "../../orcid/orcid.module"; import {IconsModule} from "../icons/icons.module"; import {IconsService} from "../icons/icons.service"; import {cite, fire, landmark, link, link_to, quotes, rocket} from "../icons/icons"; import {EntityActionsModule} from "../entity-actions/entity-actions.module"; import {EntityMetadataModule} from "../../landingPages/landing-utils/entity-metadata.module"; +import {OrcidCoreModule} from "../../orcid/orcid-core.module"; @NgModule({ - imports: [CommonModule, RouterModule, ShowAuthorsModule, ResultLandingUtilsModule, OrcidModule, IconsModule, EntityActionsModule, EntityMetadataModule], + imports: [CommonModule, RouterModule, ShowAuthorsModule, ResultLandingUtilsModule, OrcidCoreModule, IconsModule, EntityActionsModule, EntityMetadataModule], declarations: [ResultPreviewComponent], exports: [ResultPreviewComponent] }) diff --git a/utils/string-utils.class.ts b/utils/string-utils.class.ts index cbce9848..3ccf6e6b 100644 --- a/utils/string-utils.class.ts +++ b/utils/string-utils.class.ts @@ -150,7 +150,7 @@ export class DOI { } export class Identifier { - class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" | "swhid" = null; + class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" | "swhid" | "ror" | "wikidata" | "fundref" | "isni" = null; id: string; public static getDOIsFromString(str: string): string[] { @@ -205,14 +205,22 @@ export class Identifier { return {"class": "re3data", "id": pid}; } else if (Identifier.isValidSwhId(pid)) { return {"class": "swhid", "id": pid}; + } else if (Identifier.isValidRor(pid)) { + return {"class": "ror", "id": pid}; + } else if (Identifier.isValidFundRef(pid)) { + return {"class": "fundref", "id": pid}; + } else if (Identifier.isValidWikidata(pid)) { + return {"class": "wikidata", "id": pid}; + } else if (Identifier.isValidIsni(pid)) { + return {"class": "isni", "id": pid}; } //set it as a doi, to catch the case that doi has not valid format return (strict?null:{"class": "doi", "id": pid}); } public static getPIDFromIdentifiers(identifiers: Map): Identifier { - let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data", "swhid"]; - if(identifiers) { + let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data", "swhid", "ror", "wikidata", "fundref", "isni"]; + if(identifiers && identifiers.size > 0) { for (let cl of classes) { if (identifiers.get(cl)) { for (let pid of identifiers.get(cl)) { @@ -258,6 +266,7 @@ export class Identifier { } public static isValidHANDLE(str: string): boolean { + // let exp = /\b[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g; // resolve with url - need to add method for raw value let exp = /^[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g; return str.match(exp) != null; } @@ -272,6 +281,28 @@ export class Identifier { let exp = /swh:1:snp:[0-9a-f]{40}/g; return str.match(exp) != null; } + + public static isValidRor(str: string): boolean { + let exp = /0[a-z|0-9]{6}[0-9]{2}\b/g; + return str.match(exp) != null; + } + + public static isValidIsni(str: string): boolean { + let exp = /^[0]{7}[0-9]{8}[0-9X]$/g; + return str.match(exp) != null; + } + + public static isValidWikidata(str: string): boolean { + let exp = /^Q\d+$/g; + return str.match(exp) != null; + } + + public static isValidFundRef(str: string): boolean { + // let exp = /aaa/g; + let exp = /^[1-9]\d+$/g; + return str.match(exp) != null; + } + } export class StringUtils { diff --git a/utils/transition-group/transition-group.component.ts b/utils/transition-group/transition-group.component.ts index 53530868..8cea910d 100644 --- a/utils/transition-group/transition-group.component.ts +++ b/utils/transition-group/transition-group.component.ts @@ -1,6 +1,6 @@ import {TransitionGroupItemDirective} from "./transition-group-item.directive"; import { - AfterViewInit, + AfterViewInit, ChangeDetectorRef, Component, ContentChildren, ElementRef, Input, @@ -29,15 +29,14 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { @ContentChildren(TransitionGroupItemDirective) items: QueryList; @Input() public id: string; - private disabled: boolean = false; + public size: number; private subscription: Subscription; constructor(public element: ElementRef) {} ngAfterViewInit() { - this.init(); this.subscription = this.items.changes.subscribe(items => { - if(!this.disabled) { + if(items.length === this.size) { items.forEach(item => item.prevPos = item.newPos || item.prevPos); items.forEach(this.runCallback); this.refreshPosition('newPos'); @@ -80,6 +79,7 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { init() { this.refreshPosition('prevPos'); this.refreshPosition('newPos'); + this.size = this.items.length; } runCallback(item: TransitionGroupItemDirective) { @@ -126,17 +126,17 @@ export class TransitionGroupComponent implements AfterViewInit, OnDestroy { /** * Enable transition - * + * @deprecated * */ enable() { - this.disabled = false; + console.debug('Deprecated') } /** * Disable transition - * + * @deprecated * */ disable() { - this.disabled = true; + console.debug('Deprecated') } }