diff --git a/src/app/models/index.ts b/src/app/models/index.ts index f123f397b39976ea19f77a9f398cb8ae1af89ff3..d85d6f26d081db626ce9fe3a60978872214eb031 100644 --- a/src/app/models/index.ts +++ b/src/app/models/index.ts @@ -86,6 +86,7 @@ import {FacetResult as FacetResultPartial} from "../generated-api/model/facet-re import {FileFormat as FileFormatPartial} from "../generated-api/model/file-format.partial.model"; import {FileList as FileListPartial} from "../generated-api/model/file-list.partial.model"; import {FundingAgency as FundingAgencyPartial} from "../generated-api/model/funding-agency.partial.model"; +import {I18nLink as I18nLinkPartial} from "../generated-api/model/i18n-link.partial.model"; import {Institution as InstitutionPartial} from "../generated-api/model/institution.partial.model"; import {JobExecutionReportLine as JobExecutionReportLinePartial} from "../generated-api/model/job-execution-report-line.partial.model"; import {JobExecutionReport as JobExecutionReportPartial} from "../generated-api/model/job-execution-report.partial.model"; @@ -95,12 +96,12 @@ import {Language as LanguagePartial} from "../generated-api/model/language.parti import {License as LicensePartial} from "../generated-api/model/license.partial.model"; import {Link as LinkPartial} from "../generated-api/model/link.partial.model"; import {LoginInfo as LoginInfoPartial} from "../generated-api/model/login-info.partial.model"; - import {MetadataType as MetadataTypePartial} from "../generated-api/model/metadata-type.partial.model"; import {NotificationType as NotificationTypePartial} from "../generated-api/model/notification-type.partial.model"; import {Notification as NotificationPartial} from "../generated-api/model/notification.partial.model"; import {OAIMetadataPrefix as OaiMetadataPrefixPartial} from "../generated-api/model/oai-metadata-prefix.partial.model"; import {OAISet as OaiSetPartial} from "../generated-api/model/oai-set.partial.model"; +import {OrcidWebsiteDTO as OrcidWebsiteDTOPartial} from "../generated-api/model/orcid-website-dto.partial.model"; import {OrderArchive as OrderArchivePartial} from "../generated-api/model/order-archive.partial.model"; import {OrderSubsetItem as OrderSubsetItemPartial} from "../generated-api/model/order-subset-item.partial.model"; import {Order as OrderPartial} from "../generated-api/model/order.partial.model"; @@ -403,6 +404,8 @@ export type FundingAgency = OverrideType<FundingAgencyPartial, { logo?: SolidifyFile; }> & BaseResourceLogo & BaseResourceExtended; +export type I18nLink = OverrideType<I18nLinkPartial>; + export type Institution = OverrideType<InstitutionPartial, { organizationalUnits?: OrganizationalUnit[]; identifiers?: MappingObject<IdentifiersEnum, string>; @@ -481,6 +484,8 @@ export type Order = OverrideType<OrderPartial, { orderStatus?: Enums.Order.StatusEnum; }> & BaseResourceExtended; +export type OrcidWebsiteDTO = OverrideType<OrcidWebsiteDTOPartial>; + export type OrderArchive = OverrideType<OrderArchivePartial, { archive?: Aip; metadata?: ArchiveMetadata; @@ -517,6 +522,7 @@ export type Person = OverrideType<PersonPartial, { notificationTypes?: NotificationType[]; avatar?: PersonAvatar; searchCriterias?: SearchCriteria[]; + orcidLinks?: I18nLink[]; }> & BaseResourceAvatar & BaseResourceExtended; export type PreservationJob = OverrideType<PreservationJobPartial, { diff --git a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.html b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.html index 50be37421e43d34fe5737e65a827d95cf69d03c1..bef457fdc7da712fc9ac7175212f3863814ed60f 100644 --- a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.html +++ b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.html @@ -17,7 +17,8 @@ <div class="informations"> <div class="fullname" solidifyTooltipOnEllipsis - >{{data.firstName}} {{data.lastName}}</div> + >{{data.firstName}} {{data.lastName}} + </div> <div *ngIf="data.orcid | isNotNullNorUndefinedNorWhiteString" class="orcid-wrapper" (click)="orcidPresentational.navigateToOrcid()" @@ -48,5 +49,23 @@ ></solidify-icon> </li> </ul> + + <div *ngIf="data.orcidLinks | isNonEmptyArray" + class="orcid-websites-zone" + > + <div class="title">{{labelTranslateEnum.orcidExternalWebsites | translate}}:</div> + + <ul class="websites"> + <li *ngFor="let orcidLink of data.orcidLinks" + class="website" + > + <a [href]="orcidLink.url" + target="_blank" + class="website-name" + solidifyTooltipOnEllipsis + >{{orcidLink.text}}</a> + </li> + </ul> + </div> </div> </div> diff --git a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.scss b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.scss index b1c91d306b1210c93b40833ab0b24685a64ec4c7..b5436f2459e2274ee69438f9609edf4bda592202 100644 --- a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.scss +++ b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.scss @@ -55,5 +55,29 @@ } } } + + .orcid-websites-zone { + .title { + font-size: 14px; + } + + .websites { + margin-left: 5px; + display: grid; + grid-gap: 2px; + + .website { + display: grid; + grid-template-columns: 1fr; + grid-gap: 5px; + align-items: center; + + .website-name { + font-size: 12px; + @include truncate-with-ellipsis; + } + } + } + } } } diff --git a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.ts b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.ts index 39724cfe6efa7238710c21fec266da5edaf2c248..b9fd5c710c90848fdb4ea9b37c652a95e1ed6213 100644 --- a/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.ts +++ b/src/app/shared/components/presentationals/shared-person-overlay/shared-person-overlay.presentational.ts @@ -31,6 +31,7 @@ import { import {Enums} from "@enums"; import {environment} from "@environments/environment"; import { + I18nLink, Institution, Person, User, @@ -51,6 +52,7 @@ import { isNotNullNorUndefined, isNullOrUndefined, isNullOrUndefinedOrWhiteString, + isNotNullNorUndefinedNorWhiteString, isTrue, MappingObjectUtil, ObjectUtil, @@ -58,6 +60,7 @@ import { ResourceFileNameSpace, SsrUtil, StoreUtil, + MemoizedUtil, } from "solidify-frontend"; @Component({ @@ -131,6 +134,27 @@ export class SharedPersonOverlayPresentational extends AbstractOverlayPresentati }, )); } + + if (isNotNullNorUndefinedNorWhiteString(this.data.orcid)) { + this.subscribe(StoreUtil.dispatchActionAndWaitForSubActionCompletion(this._store, this._actions$, + new SharedPersonAction.GetExternalOrcidWebsites(this.data.orcid), + SharedPersonAction.GetExternalOrcidWebsitesSuccess, + result => { + this.data = ObjectUtil.clone(this.data); + const currentLanguage = MemoizedUtil.selectSnapshot(this._store, environment.appState, state => state.appLanguage); + const orcidLinks: I18nLink[] = []; + result.orcidWebsites.forEach(website => { + website.links.forEach(link => { + if (link.languageCode === currentLanguage) { + orcidLinks.push(link); + } + }); + }); + this.data.orcidLinks = orcidLinks; + this._changeDetector.detectChanges(); + }, + )); + } } } diff --git a/src/app/shared/enums/api-resource-name.enum.ts b/src/app/shared/enums/api-resource-name.enum.ts index 6842080a62d7638ed60ab3cf9b3327383b9daa7e..36569e4fa5b60472be7dde819d2e1c27f14e6519 100644 --- a/src/app/shared/enums/api-resource-name.enum.ts +++ b/src/app/shared/enums/api-resource-name.enum.ts @@ -79,6 +79,7 @@ enum ApiResourceNameExtendEnum { SCHEDULED_TASK = "scheduled-tasks", GLOBAL_BANNERS = "global-banners", ORCID_SYNCHRONIZATION = "orcid-synchronizations", + ORCID_EXTERNAL_WEBSITES = "external-websites", // Miscellaneous SCHEMA = "schema", diff --git a/src/app/shared/enums/label-translate.enum.ts b/src/app/shared/enums/label-translate.enum.ts index adab2083f17fc06d379cbd3ec01a6895b9023ddf..0400e039f8149239312f0d84fbf83bf77779b55a 100644 --- a/src/app/shared/enums/label-translate.enum.ts +++ b/src/app/shared/enums/label-translate.enum.ts @@ -385,6 +385,7 @@ export class LabelTranslateEnum { static desiredRole: string = MARK_AS_TRANSLATABLE("general.label.desiredRole"); static orcidAuthenticated: string = MARK_AS_TRANSLATABLE("general.label.orcidAuthenticated"); static orcidNotAuthenticated: string = MARK_AS_TRANSLATABLE("general.label.orcidNotAuthenticated"); + static orcidExternalWebsites: string = MARK_AS_TRANSLATABLE("general.label.orcidExternalWebsites"); static data: string = MARK_AS_TRANSLATABLE("general.label.data"); static reason: string = MARK_AS_TRANSLATABLE("general.label.reason"); static reasonForRejection: string = MARK_AS_TRANSLATABLE("general.label.reasonForRejection"); diff --git a/src/app/shared/stores/person/shared-person.action.ts b/src/app/shared/stores/person/shared-person.action.ts index 9336b575437cfd075e2cdc9506413db04aa755cf..c2a16cce7577146d81df495532d3d66bb534635b 100644 --- a/src/app/shared/stores/person/shared-person.action.ts +++ b/src/app/shared/stores/person/shared-person.action.ts @@ -23,6 +23,7 @@ import { Institution, + OrcidWebsiteDTO, Person, } from "@models"; import {StateEnum} from "@shared/enums/state.enum"; @@ -298,6 +299,26 @@ export namespace SharedPersonAction { export class SearchPersonInstitutionFail extends BaseSubActionFail<SearchPersonInstitution> { static readonly type: string = `[${state}] Search Person Institution Fail`; } + + export class GetExternalOrcidWebsites extends BaseAction { + static readonly type: string = `[${state}] Get External Orcid Websites`; + + constructor(public orcid: string) { + super(); + } + } + + export class GetExternalOrcidWebsitesSuccess extends BaseSubActionSuccess<GetExternalOrcidWebsites> { + static readonly type: string = `[${state}] Get External Orcid Websites Success`; + + constructor(public parentAction: GetExternalOrcidWebsites, public orcidWebsites: OrcidWebsiteDTO[]) { + super(parentAction); + } + } + + export class GetExternalOrcidWebsitesFail extends BaseSubActionFail<GetExternalOrcidWebsites> { + static readonly type: string = `[${state}] Get External Orcid Websites Fail`; + } } export const sharedPersonActionNameSpace: ResourceFileNameSpace = SharedPersonAction; diff --git a/src/app/shared/stores/person/shared-person.state.ts b/src/app/shared/stores/person/shared-person.state.ts index 76b1708dc6c406b922c1cc505d250fe8819e5aef..85852980305d625f27fe7900a6889d1679fb4a02 100644 --- a/src/app/shared/stores/person/shared-person.state.ts +++ b/src/app/shared/stores/person/shared-person.state.ts @@ -30,6 +30,7 @@ import { import {environment} from "@environments/environment"; import { Institution, + OrcidWebsiteDTO, Person, } from "@models"; import { @@ -79,6 +80,7 @@ import {ApiActionNameEnum} from "../../enums/api-action-name.enum"; export interface SharedPersonStateModel extends ResourceFileStateModel<Person> { listPersonMatching: Person[]; + orcidWebsites: OrcidWebsiteDTO[]; } @Injectable() @@ -87,6 +89,7 @@ export interface SharedPersonStateModel extends ResourceFileStateModel<Person> { defaults: { ...defaultResourceFileStateInitValue(), listPersonMatching: [], + orcidWebsites: [], queryParameters: new QueryParameters(environment.defaultEnumValuePageSizeOption), }, children: [ @@ -111,6 +114,10 @@ export class SharedPersonState extends ResourceFileState<SharedPersonStateModel, return ApiEnum.adminPeople; } + protected get _urlOrcid(): string { + return ApiEnum.adminOrcid; + } + protected get _urlFileResource(): string { return this._urlResource; } @@ -304,4 +311,35 @@ export class SharedPersonState extends ResourceFileState<SharedPersonStateModel, }), ); } + + @Action(SharedPersonAction.GetExternalOrcidWebsites) + getExternalOrcidWebsites(ctx: SolidifyStateContext<SharedPersonStateModel>, action: SharedPersonAction.GetExternalOrcidWebsites): Observable<any> { + ctx.patchState({ + isLoadingCounter: ctx.getState().isLoadingCounter + 1, + }); + return this._apiService.getList<OrcidWebsiteDTO>(`${this._urlOrcid}/${action.orcid}/${ApiResourceNameEnum.ORCID_EXTERNAL_WEBSITES}`, null) + .pipe( + tap(result => { + ctx.dispatch(new SharedPersonAction.GetExternalOrcidWebsitesSuccess(action, result)); + }), + catchError((error: SolidifyHttpErrorResponseModel) => { + ctx.dispatch(new SharedPersonAction.GetExternalOrcidWebsitesFail(action)); + throw new SolidifyStateError(this, error); + }), + ); + } + + @Action(SharedPersonAction.GetExternalOrcidWebsitesSuccess) + getExternalOrcidWebsitesSuccess(ctx: SolidifyStateContext<SharedPersonStateModel>, action: SharedPersonAction.GetExternalOrcidWebsitesSuccess): void { + ctx.patchState({ + orcidWebsites: action.orcidWebsites, + }); + } + + @Action(SharedPersonAction.GetExternalOrcidWebsitesFail) + getExternalOrcidWebsitesFail(ctx: SolidifyStateContext<SharedPersonStateModel>, action: SharedPersonAction.GetExternalOrcidWebsitesFail): void { + ctx.patchState({ + orcidWebsites: undefined, + }); + } } diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 1903967a294f2ed4a5793ebda7bd38cb02c5aae3..6510b546452e0dee58c4e072a1e72f40ab3b7abc 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -1552,6 +1552,7 @@ "optional": "Optional", "orcid": "ORCID", "orcidAuthenticated": "ORCID-authentifiziert", + "orcidExternalWebsites": "general.label.orcidExternalWebsites", "orcidNotAuthenticated": "ORCID nicht authentifiziert", "orderInError": "Fehlerhafte Reihenfolge", "orderInProgress": "Datenanfrage in Bearbeitung", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index a0eb4367303fa1799413e99adf8876095bdbfa68..a21aa9d52242f69ff2841fa496772f8382770b4e 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -1552,6 +1552,7 @@ "optional": "Optional", "orcid": "ORCID", "orcidAuthenticated": "ORCID Authenticated", + "orcidExternalWebsites": "Affiliated websites supporting ORCID", "orcidNotAuthenticated": "ORCID not authenticated", "orderInError": "Order in error", "orderInProgress": "Order in progress", diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 224bbcc0e5a903252d41fa26bc8b81357053adf9..ac050455c954510f5821663d30f3ba5c0410931b 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -1552,6 +1552,7 @@ "optional": "Facultatif", "orcid": "ORCID", "orcidAuthenticated": "Authentifié par l'ORCID", + "orcidExternalWebsites": "Site affiliés supportant ORCID", "orcidNotAuthenticated": "ORCID non authentifié", "orderInError": "La demande est en erreur", "orderInProgress": "La demande est en cours",