diff --git a/libs/data-access/gn4/src/openapi/api/tools.api.service.ts b/libs/data-access/gn4/src/openapi/api/tools.api.service.ts index c03adcf654..ffb0c02e7a 100644 --- a/libs/data-access/gn4/src/openapi/api/tools.api.service.ts +++ b/libs/data-access/gn4/src/openapi/api/tools.api.service.ts @@ -14,18 +14,31 @@ import { Inject, Injectable, Optional } from '@angular/core' import { HttpClient, + HttpEvent, HttpHeaders, + HttpParameterCodec, HttpParams, HttpResponse, - HttpEvent, - HttpParameterCodec, } from '@angular/common/http' import { CustomHttpParameterCodec } from '../encoder' import { Observable } from 'rxjs' -import { BASE_PATH, COLLECTION_FORMATS } from '../variables' +import { BASE_PATH } from '../variables' import { Configuration } from '../configuration' +interface thesaurusResponse { + values: string[] + definitions: string[] + coordEast: string + coordWest: string + coordSouth: string + coordNorth: string + thesaurusKey: string + value: string + uri: string + definition: string +} + @Injectable({ providedIn: 'root', }) @@ -913,4 +926,88 @@ export class ToolsApiService { } ) } + + /** + * List database translations (used to overrides client application translations). + * @param esFieldName set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param iso3 set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTranslationsFromThesaurus( + thesaurusName: string, + langIso3: string, + observe?: 'body', + reportProgress?: boolean, + options?: { httpHeaderAccept?: 'application/json' } + ): Observable + public getTranslationsFromThesaurus( + thesaurusName: string, + langIso3: string, + observe?: 'response', + reportProgress?: boolean, + options?: { httpHeaderAccept?: 'application/json' } + ): Observable + public getTranslationsFromThesaurus( + thesaurusName: string, + langIso3: string, + observe?: 'events', + reportProgress?: boolean, + options?: { httpHeaderAccept?: 'application/json' } + ): Observable + public getTranslationsFromThesaurus( + thesaurusName: string, + langIso3: string, + observe: any = 'body', + reportProgress: boolean = false, + options?: { httpHeaderAccept?: 'application/json' } + ): Observable { + if ( + thesaurusName === null || + thesaurusName === undefined || + langIso3 === null || + langIso3 === undefined + ) { + throw new Error( + 'Required parameter pack was null or undefined when calling getTranslationsFromThesaurus.' + ) + } + + let headers = this.defaultHeaders + + let httpHeaderAcceptSelected: string | undefined = + options && options.httpHeaderAccept + if (httpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json'] + httpHeaderAcceptSelected = + this.configuration.selectHeaderAccept(httpHeaderAccepts) + } + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected) + } + + let responseType_: 'text' | 'json' = 'json' + if ( + httpHeaderAcceptSelected && + httpHeaderAcceptSelected.startsWith('text') + ) { + responseType_ = 'text' + } + + return this.httpClient.get( + `${ + this.configuration.basePath + }/registries/vocabularies/search?rows=1000&type=CONTAINS&sort=DESC&thesaurus=${encodeURIComponent( + String(thesaurusName) + )}&lang=${encodeURIComponent(langIso3)}`, + { + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ) + } } diff --git a/libs/feature/search/src/lib/utils/service/fields.service.ts b/libs/feature/search/src/lib/utils/service/fields.service.ts index 8c2bed40ae..2dd767e61f 100644 --- a/libs/feature/search/src/lib/utils/service/fields.service.ts +++ b/libs/feature/search/src/lib/utils/service/fields.service.ts @@ -1,14 +1,15 @@ import { Injectable, Injector } from '@angular/core' import { AbstractSearchField, - GnUiTranslationSearchField, FieldValue, FullTextSearchField, + GnUiTranslationSearchField, IsSpatialSearchField, LicenseSearchField, OrganizationSearchField, OwnerSearchField, SimpleSearchField, + ThesaurusTranslationSearchField, } from './fields' import { forkJoin, Observable, of } from 'rxjs' import { map } from 'rxjs/operators' @@ -52,8 +53,9 @@ export class FieldsService { this.injector ), topic: new GnUiTranslationSearchField('cl_topic.key', 'asc', this.injector), - inspireKeyword: new SimpleSearchField( - 'th_httpinspireeceuropaeutheme-theme_tree.default', + inspireKeyword: new ThesaurusTranslationSearchField( + 'th_httpinspireeceuropaeutheme-theme.link', + 'external.theme.httpinspireeceuropaeutheme-theme', 'asc', this.injector ), diff --git a/libs/feature/search/src/lib/utils/service/fields.ts b/libs/feature/search/src/lib/utils/service/fields.ts index 272fb73362..a3129015c7 100644 --- a/libs/feature/search/src/lib/utils/service/fields.ts +++ b/libs/feature/search/src/lib/utils/service/fields.ts @@ -14,6 +14,7 @@ import { } from '@geonetwork-ui/common/domain/search' import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/records-repository.interface' import { ElasticsearchService } from '@geonetwork-ui/api/repository/gn4' +import { LangService } from '@geonetwork-ui/util/i18n' export type FieldValue = string | number export interface FieldAvailableValue { @@ -127,6 +128,57 @@ export class GnUiTranslationSearchField extends SimpleSearchField { } } +export class ThesaurusTranslationSearchField extends SimpleSearchField { + private toolsApiService = this.injector.get(ToolsApiService) + private langService = this.injector.get(LangService) + allTranslations = this.toolsApiService + .getTranslationsFromThesaurus(this.thesaurusName, this.langService.iso3) + .pipe( + map((thesaurus) => { + const alltranslations = {} + thesaurus.map((val) => { + alltranslations[val.uri] = val.value + }) + return alltranslations + }), + catchError(() => { + console.warn('Error while loading thesaurus language package') + return of({}) + }), + shareReplay(1) + ) + + constructor( + esFieldName: string, + protected thesaurusName: string, + order: 'asc' | 'desc' = 'asc', + injector: Injector + ) { + super(esFieldName, order, injector) + } + + private async getTranslation(topicKey: string) { + return firstValueFrom( + this.allTranslations.pipe(map((translations) => translations[topicKey])) + ) + } + + protected async getBucketLabel(bucket: TermBucket) { + return (await this.getTranslation(bucket.term)) || bucket.term + } + + getAvailableValues(): Observable { + // sort values by alphabetical order + return super + .getAvailableValues() + .pipe( + map((values) => + values.sort((a, b) => new Intl.Collator().compare(a.label, b.label)) + ) + ) + } +} + export class FullTextSearchField implements AbstractSearchField { getAvailableValues(): Observable { return of([])