diff --git a/apps/datahub/src/app/home/news-page/key-figures/key-figures.component.html b/apps/datahub/src/app/home/news-page/key-figures/key-figures.component.html index 943dab7b50..d04e7eee5f 100644 --- a/apps/datahub/src/app/home/news-page/key-figures/key-figures.component.html +++ b/apps/datahub/src/app/home/news-page/key-figures/key-figures.component.html @@ -4,7 +4,7 @@ class="py-[37px] pl-[47px] rounded-lg border bg-white mb-5 card-shadow cursor-pointer" [figure]="recordsCount$ | async" [icon]="'folder_open'" - [title]="'catalog.figures.datasets'" + [title]="'catalog.figures.datasets' | translate" [color]="'secondary'" > @@ -13,7 +13,7 @@ class="py-[37px] pl-[47px] rounded-lg bg-white border card-shadow cursor-pointer" [figure]="orgsCount$ | async" [icon]="'corporate_fare'" - [title]="'catalog.figures.organisations'" + [title]="'catalog.figures.organisations' | translate" [color]="'secondary'" > diff --git a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts index 504412fb37..bea2a42653 100644 --- a/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +++ b/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts @@ -28,6 +28,7 @@ import { combineLatest, Observable, of, switchMap, takeLast } from 'rxjs' import { filter, map, shareReplay, startWith, tap } from 'rxjs/operators' import { LangService } from '@geonetwork-ui/util/i18n' import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' +import { coerce, satisfies, valid } from 'semver' const IMAGE_URL = '/geonetwork/images/harvesting/' @@ -144,6 +145,7 @@ export class OrganizationsFromMetadataService } private getAggregationSearchRequest(gnVersion: string) { + const semVersion = valid(coerce(gnVersion)) return this.esService.getSearchRequestBody({ contact: { nested: { @@ -152,9 +154,10 @@ export class OrganizationsFromMetadataService aggs: { org: { terms: { - field: gnVersion.startsWith('4.2.2') - ? 'contactForResource.organisation' - : 'contactForResource.organisationObject.default.keyword', + field: + semVersion === '4.2.2' + ? 'contactForResource.organisation' + : 'contactForResource.organisationObject.default.keyword', exclude: '', size: 5000, order: { _key: 'asc' }, @@ -164,12 +167,9 @@ export class OrganizationsFromMetadataService terms: { size: 50, exclude: '', - field: - gnVersion.startsWith('4.2.2') || - gnVersion.startsWith('4.2.3') || - gnVersion.startsWith('4.2.4') - ? 'contactForResource.email.keyword' - : 'contactForResource.email', + field: satisfies(semVersion, '4.2.2 - 4.2.4') + ? 'contactForResource.email.keyword' + : 'contactForResource.email', }, }, logoUrl: { @@ -187,9 +187,10 @@ export class OrganizationsFromMetadataService terms: { size: 5000, exclude: '', - field: gnVersion.startsWith('4.2.2') - ? 'OrgForResource' - : 'OrgForResourceObject.default', + field: + semVersion === '4.2.2' + ? 'OrgForResource' + : 'OrgForResourceObject.default', order: { _key: 'asc', }, diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts index bb34126673..67da958a92 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts @@ -37,6 +37,6 @@ export class Gn4PlatformMapper { credentialsNonExpired, ...user } = apiUser - return { ...apiUser, id: id + '' } as UserModel + return { ...apiUser, id: id.toString() } as UserModel } } diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts index 4d42efc935..7580f52018 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts @@ -5,7 +5,7 @@ import { } from '@geonetwork-ui/data-access/gn4' import { TestBed } from '@angular/core/testing' import { Gn4PlatformService } from './gn4-platform.service' -import { firstValueFrom, lastValueFrom, of, Subject } from 'rxjs' +import { firstValueFrom, of, Subject } from 'rxjs' import { AvatarServiceInterface } from '../auth/avatar.service.interface' import { Gn4PlatformMapper } from './gn4-platform.mapper' @@ -31,6 +31,7 @@ class MeApiMock { getMe() { return this._me$ } + _me$ = new Subject() } @@ -46,6 +47,7 @@ class SiteApiServiceMock { }) ) } + class UsersApiServiceMock { getUsers() { return of([ @@ -98,11 +100,32 @@ describe('Gn4PlatformService', () => { expect(service).toBeTruthy() }) - it('fetches version from settings', async () => { - geonetworkVersion = '4.2.0' - const version = await firstValueFrom(service.getApiVersion()) - expect(version).toEqual('4.2.0') + describe('version', () => { + describe('when version is lower than 4.2.2', () => { + beforeEach(() => { + geonetworkVersion = '4.2.0' + }) + it('throws an error', async () => { + let error + await firstValueFrom(service.getApiVersion()).catch((e) => (error = e)) + expect(error).toEqual( + new Error( + 'Gn4 API version is not compatible.\nMinimum: 4.2.2\nYour version: 4.2.0' + ) + ) + }) + }) + describe('when version is euqal or greater than 4.2.2', () => { + beforeEach(() => { + geonetworkVersion = '4.2.2' + }) + it('fetches version from settings', async () => { + const version = await firstValueFrom(service.getApiVersion()) + expect(version).toEqual('4.2.2') + }) + }) }) + it('fetches users from api', async () => { const users = await firstValueFrom(service.getUsers()) expect(users).toEqual([ diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts index 5e4807ade3..0b4cfa1d3e 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts @@ -10,14 +10,15 @@ import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform. import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' import { Organization } from '@geonetwork-ui/common/domain/model/record' import { Gn4PlatformMapper } from './gn4-platform.mapper' +import { ltr } from 'semver' -const minApiVersion = '4.2.0' +const minApiVersion = '4.2.2' @Injectable() export class Gn4PlatformService implements PlatformServiceInterface { private readonly type = 'GeoNetwork' private me$: Observable private users$: Observable - isAnonymous$: Observable + private isAnonymous$: Observable private settings$ = of(true).pipe( switchMap(() => this.siteApiService.getSiteOrPortalDescription()), @@ -26,18 +27,16 @@ export class Gn4PlatformService implements PlatformServiceInterface { private readonly apiVersion$ = this.settings$.pipe( map((info) => info['system/platform/version'] as string), + tap((version) => { + if (ltr(version, minApiVersion)) { + throw new Error( + `Gn4 API version is not compatible.\nMinimum: ${minApiVersion}\nYour version: ${version}` + ) + } + }), shareReplay(1) ) - private readonly isApiCompatible$ = this.apiVersion$.pipe( - tap( - (version) => - version < minApiVersion && - console.warn(`The GeoNetwork Api version is too low ${version}`) - ), - map((version) => version >= minApiVersion) - ) - constructor( private siteApiService: SiteApiService, private meApi: MeApiService, @@ -62,9 +61,6 @@ export class Gn4PlatformService implements PlatformServiceInterface { getApiVersion(): Observable { return this.apiVersion$ } - isApiCompatible(): Observable { - return this.isApiCompatible$ - } getMe(): Observable { return this.me$ diff --git a/libs/common/domain/src/lib/platform.service.interface.ts b/libs/common/domain/src/lib/platform.service.interface.ts index 7872c2d052..4711d1d047 100644 --- a/libs/common/domain/src/lib/platform.service.interface.ts +++ b/libs/common/domain/src/lib/platform.service.interface.ts @@ -5,7 +5,6 @@ import { Organization } from './model/record/organization.model' export abstract class PlatformServiceInterface { abstract getType(): string abstract getApiVersion(): Observable - abstract isApiCompatible(): Observable abstract getMe(): Observable abstract isAnonymous(): Observable diff --git a/libs/data-access/gn4/src/custom-api/thesaurus.api.service.ts b/libs/data-access/gn4/src/custom-api/thesaurus.api.service.ts new file mode 100644 index 0000000000..138d7bfc14 --- /dev/null +++ b/libs/data-access/gn4/src/custom-api/thesaurus.api.service.ts @@ -0,0 +1,135 @@ +import { Inject, Injectable, Optional } from '@angular/core' +import { + HttpClient, + HttpHeaders, + HttpParameterCodec, +} from '@angular/common/http' +import { Observable } from 'rxjs' +import { CustomHttpParameterCodec } from '../openapi/encoder' +import { Configuration } from '../openapi/configuration' + +import { BASE_PATH } from '../openapi/variables' + +export interface thesaurusResponse { + values: { [key: string]: string } + definitions: { [key: string]: string } + coordEast?: string + coordWest?: string + coordSouth?: string + coordNorth?: string + thesaurusKey: string + value: string + uri: string + definition?: string +} + +@Injectable({ + providedIn: 'root', +}) +export class ThesaurusApiService { + protected basePath = 'https://apps.titellus.net/geonetwork/srv/api' + public defaultHeaders = new HttpHeaders() + public configuration = new Configuration() + public encoder: HttpParameterCodec + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (configuration) { + this.configuration = configuration + } + if (typeof this.configuration.basePath !== 'string') { + if (typeof basePath !== 'string') { + basePath = this.basePath + } + this.configuration.basePath = basePath + } + this.encoder = this.configuration.encoder || new CustomHttpParameterCodec() + } + + /** + * 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/data-access/gn4/src/openapi/README.md b/libs/data-access/gn4/src/openapi/README.md index dcc0fbf9db..f16604dcff 100644 --- a/libs/data-access/gn4/src/openapi/README.md +++ b/libs/data-access/gn4/src/openapi/README.md @@ -3,7 +3,6 @@ ### Building To install the required dependencies and to build the typescript sources run: - ``` npm install npm run build @@ -11,7 +10,7 @@ npm run build ### publishing -First build the package then run `npm publish dist` (don't forget to specify the `dist` folder!) +First build the package then run ```npm publish dist``` (don't forget to specify the `dist` folder!) ### consuming @@ -34,25 +33,25 @@ _It's important to take the tgz file, otherwise you'll get trouble with links on _using `npm link`:_ In PATH_TO_GENERATED_PACKAGE/dist: - ``` npm link ``` In your project: - ``` -npm link +npm link ``` -**Note for Windows users:** The Angular CLI has troubles to use linked npm packages. +__Note for Windows users:__ The Angular CLI has troubles to use linked npm packages. Please refer to this issue https://github.com/angular/angular-cli/issues/8284 for a solution / workaround. Published packages are not effected by this issue. + #### General usage In your Angular project: + ``` // without configuring providers import { ApiModule } from ''; @@ -129,11 +128,9 @@ Note: The ApiModule is restricted to being instantiated once app wide. This is to ensure that all services are treated as singletons. #### Using multiple OpenAPI files / APIs / ApiModules - In order to use multiple `ApiModules` generated from different OpenAPI files, you can create an alias name when importing the modules in order to avoid naming conflicts: - ``` import { ApiModule } from 'my-api-path'; import { ApiModule as OtherApiModule } from 'my-other-api-path'; @@ -153,9 +150,9 @@ export class AppModule { } ``` -### Set service base path -If different than the generated base path, during app bootstrap, you can provide the base path to your service. +### Set service base path +If different than the generated base path, during app bootstrap, you can provide the base path to your service. ``` import { BASE_PATH } from ''; @@ -164,7 +161,6 @@ bootstrap(AppComponent, [ { provide: BASE_PATH, useValue: 'https://your-web-service.com' }, ]); ``` - or ``` @@ -179,8 +175,8 @@ import { BASE_PATH } from ''; export class AppModule {} ``` -#### Using @angular/cli +#### Using @angular/cli First extend your `src/environments/*.ts` files by adding the corresponding base path: ``` @@ -191,7 +187,6 @@ export const environment = { ``` In the src/app/app.module.ts: - ``` import { BASE_PATH } from ''; import { environment } from '../environments/environment'; @@ -205,4 +200,4 @@ import { environment } from '../environments/environment'; bootstrap: [ AppComponent ] }) export class AppModule { } -``` +``` 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..0faa979284 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,16 +14,16 @@ 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' @Injectable({ diff --git a/libs/data-access/gn4/src/openapi/index.ts b/libs/data-access/gn4/src/openapi/index.ts index 8e6723a9e5..92f0d7b85f 100644 --- a/libs/data-access/gn4/src/openapi/index.ts +++ b/libs/data-access/gn4/src/openapi/index.ts @@ -3,3 +3,4 @@ export * from './model/models' export * from './variables' export * from './configuration' export * from './api.module' +export * from '../custom-api/thesaurus.api.service' diff --git a/libs/feature/search/src/lib/utils/service/fields.service.spec.ts b/libs/feature/search/src/lib/utils/service/fields.service.spec.ts index 138965ffba..1427c0b66d 100644 --- a/libs/feature/search/src/lib/utils/service/fields.service.spec.ts +++ b/libs/feature/search/src/lib/utils/service/fields.service.spec.ts @@ -1,7 +1,10 @@ import { TestBed } from '@angular/core/testing' import { FieldsService } from './fields.service' import { EMPTY, lastValueFrom, of } from 'rxjs' -import { ToolsApiService } from '@geonetwork-ui/data-access/gn4' +import { + ThesaurusApiService, + ToolsApiService, +} from '@geonetwork-ui/data-access/gn4' import { TranslateModule } from '@ngx-translate/core' import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface' import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' @@ -17,6 +20,11 @@ class ElasticsearchServiceMock { class ToolsApiServiceMock { getTranslationsPackage1 = jest.fn(() => EMPTY) } + +class ThesaurusApiServiceMock { + getTranslationsFromThesaurus = jest.fn(() => of([])) +} + class OrganisationsServiceMock { organisations$ = of([{ name: 'orgA', recordCount: 10 }]) getOrgsFromFilters = jest.fn(() => of([{ name: 'orgB' }])) @@ -50,6 +58,10 @@ describe('FieldsService', () => { provide: OrganizationsServiceInterface, useClass: OrganisationsServiceMock, }, + { + provide: ThesaurusApiService, + useClass: ThesaurusApiServiceMock, + }, ], }) }) @@ -78,6 +90,7 @@ describe('FieldsService', () => { 'q', 'license', 'owner', + 'contact', ]) }) }) @@ -146,6 +159,7 @@ describe('FieldsService', () => { }) it('calls the search api', () => { expect(values).toEqual({ + contact: [], documentStandard: [], format: ['ascii', 'png'], inspireKeyword: [], 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 8ef7ae172e..a329078272 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,16 @@ import { Injectable, Injector } from '@angular/core' import { AbstractSearchField, - GnUiTranslationSearchField, + ContactField, FieldValue, FullTextSearchField, + GnUiTranslationSearchField, IsSpatialSearchField, LicenseSearchField, OrganizationSearchField, OwnerSearchField, SimpleSearchField, + ThesaurusTranslationSearchField, } from './fields' import { forkJoin, Observable, of } from 'rxjs' import { map } from 'rxjs/operators' @@ -28,6 +30,7 @@ marker('search.filters.representationType') marker('search.filters.resourceType') marker('search.filters.standard') marker('search.filters.topic') +marker('search.filters.contact') @Injectable({ providedIn: 'root', @@ -52,8 +55,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 ), @@ -66,6 +70,7 @@ export class FieldsService { q: new FullTextSearchField(), license: new LicenseSearchField(this.injector), owner: new OwnerSearchField(this.injector), + contact: new ContactField('asc', this.injector), // new TranslationField('OrgForResource') } as Record get supportedFields() { diff --git a/libs/feature/search/src/lib/utils/service/fields.spec.ts b/libs/feature/search/src/lib/utils/service/fields.spec.ts index 01b5259af5..fade2a56dd 100644 --- a/libs/feature/search/src/lib/utils/service/fields.spec.ts +++ b/libs/feature/search/src/lib/utils/service/fields.spec.ts @@ -1,4 +1,8 @@ -import { ToolsApiService } from '@geonetwork-ui/data-access/gn4' +import { + ThesaurusApiService, + ToolsApiService, + thesaurusResponse, +} from '@geonetwork-ui/data-access/gn4' import { lastValueFrom, of } from 'rxjs' import { AbstractSearchField, @@ -8,6 +12,7 @@ import { LicenseSearchField, OrganizationSearchField, SimpleSearchField, + ThesaurusTranslationSearchField, } from './fields' import { TestBed } from '@angular/core/testing' import { Injector } from '@angular/core' @@ -145,6 +150,30 @@ const sampleOrgs: Organization[] = [ }, ] +const samplInspireThesaurus: thesaurusResponse[] = [ + { + values: { + ger: 'Adressen', + }, + definitions: { + ger: 'Lokalisierung von Grundstücken anhand von Adressdaten, in der Regel Straßenname, Hausnummer und Postleitzahl.', + }, + coordEast: '', + coordWest: '', + coordSouth: '', + coordNorth: '', + thesaurusKey: 'external.theme.httpinspireeceuropaeutheme-theme', + definition: + 'Lokalisierung von Grundstücken anhand von Adressdaten, in der Regel Straßenname, Hausnummer und Postleitzahl.', + value: 'Adressen', + uri: 'http://inspire.ec.europa.eu/theme/ad', + }, +] + +class ThesaurusApiServiceMock { + getTranslationsFromThesaurus = jest.fn(() => of(samplInspireThesaurus)) +} + class OrganisationsServiceMock { organisations$ = of(sampleOrgs) getOrgsFromFilters = jest.fn(() => of(sampleOrgs.slice(0, 2))) @@ -165,6 +194,7 @@ describe('search fields implementations', () => { let esService: ElasticsearchService let repository: RecordsRepositoryInterface let toolsService: ToolsApiService + let thesaurusService: ThesaurusApiService let injector: Injector beforeEach(() => { @@ -183,6 +213,10 @@ describe('search fields implementations', () => { provide: ToolsApiService, useClass: ToolsApiServiceMock, }, + { + provide: ThesaurusApiService, + useClass: ThesaurusApiServiceMock, + }, { provide: TranslateService, useClass: TranslateServiceMock, @@ -196,6 +230,7 @@ describe('search fields implementations', () => { esService = TestBed.inject(ElasticsearchService) repository = TestBed.inject(RecordsRepositoryInterface) toolsService = TestBed.inject(ToolsApiService) + thesaurusService = TestBed.inject(ThesaurusApiService) injector = TestBed.inject(Injector) }) @@ -545,4 +580,58 @@ describe('search fields implementations', () => { }) }) }) + describe('ThesaurusTranslationSearchField', () => { + beforeEach(() => { + searchField = new ThesaurusTranslationSearchField( + 'th_httpinspireeceuropaeutheme-theme.link', + 'external.theme.httpinspireeceuropaeutheme-theme', + 'asc', + injector + ) + }) + describe('#getFiltersForValues', () => { + let filters + beforeEach(async () => { + filters = await lastValueFrom( + searchField.getFiltersForValues([ + 'Adressen', + 'Abwasser', + 'Atmosphärische Bedingungen', + ]) + ) + }) + it('returns the filters provided by the thesaurus service', () => { + expect(filters).toEqual({ + 'th_httpinspireeceuropaeutheme-theme.link': { + Adressen: true, + Abwasser: true, + 'Atmosphärische Bedingungen': true, + }, + }) + }) + }) + describe('#getAvailableValues', () => { + let values + beforeEach(async () => { + values = await lastValueFrom(searchField.getAvailableValues()) + }) + it('returns a list of values sorted by translated labels', () => { + expect(values).toEqual([ + { label: 'First value (5)', value: 'First value' }, + { + label: 'Fourth value (1)', + value: 'Fourth value', + }, + { label: 'Second value (3)', value: 'Second value' }, + { label: 'Third value (12)', value: 'Third value' }, + ]) + }) + + it('only calls the thesaurus service once', () => { + expect( + thesaurusService.getTranslationsFromThesaurus + ).toHaveBeenCalledTimes(1) + }) + }) + }) }) diff --git a/libs/feature/search/src/lib/utils/service/fields.ts b/libs/feature/search/src/lib/utils/service/fields.ts index 41949fe408..2f3c272367 100644 --- a/libs/feature/search/src/lib/utils/service/fields.ts +++ b/libs/feature/search/src/lib/utils/service/fields.ts @@ -1,5 +1,9 @@ import { firstValueFrom, Observable, of, switchMap } from 'rxjs' -import { ToolsApiService } from '@geonetwork-ui/data-access/gn4' +import { + SearchApiService, + ThesaurusApiService, + ToolsApiService, +} from '@geonetwork-ui/data-access/gn4' import { catchError, map, shareReplay } from 'rxjs/operators' import { Injector } from '@angular/core' import { TranslateService } from '@ngx-translate/core' @@ -14,6 +18,8 @@ import { } from '@geonetwork-ui/common/domain/model/search' import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' import { ElasticsearchService } from '@geonetwork-ui/api/repository/gn4' +import { LangService } from '@geonetwork-ui/util/i18n' +import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' export type FieldValue = string | number export interface FieldAvailableValue { @@ -69,15 +75,22 @@ export class SimpleSearchField implements AbstractSearchField { }) ) } - getFiltersForValues(values: FieldValue[]): Observable { + getFiltersForValues( + values: FieldValue[], + esFieldName: string = this.esFieldName + ): Observable { return of({ - [this.esFieldName]: values.reduce((acc, val) => { + [esFieldName]: values.reduce((acc, val) => { return { ...acc, [val.toString()]: true } }, {}), }) } - getValuesForFilter(filters: FieldFilters): Observable { - const filter = filters[this.esFieldName] + + getValuesForFilter( + filters: FieldFilters, + esFieldName: string = this.esFieldName + ): Observable { + const filter = filters[esFieldName] if (!filter) return of([]) const values = typeof filter === 'string' @@ -127,6 +140,57 @@ export class GnUiTranslationSearchField extends SimpleSearchField { } } +export class ThesaurusTranslationSearchField extends SimpleSearchField { + private thesaurusApiService = this.injector.get(ThesaurusApiService) + private langService = this.injector.get(LangService) + allTranslations = this.thesaurusApiService + .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([]) @@ -322,3 +386,106 @@ export class OwnerSearchField extends SimpleSearchField { return of([]) } } + +// ResourceContactField +// contact of the data not metadata +// data is the resource +export class ContactField extends SimpleSearchField { + protected repository = this.injector.get(RecordsRepositoryInterface) + protected searchApiService = this.injector.get(SearchApiService) + + // FIXME: this is required to register runtime fields; abstract this as well + protected esService = this.injector.get(ElasticsearchService) + private langService = this.injector.get(LangService) + private platformService = this.injector.get(PlatformServiceInterface) + public esFieldName: string + private version: Observable = this.platformService + .getApiVersion() + .pipe(map((version) => version)) + + constructor(public order: 'asc' | 'desc' = 'asc', public injector: Injector) { + super('OrgForResource', order, injector) + this.esFieldName = 'OrgForResourceObject.default' + } + + getFiltersForValues(values: FieldValue[]): Observable { + return this.version.pipe( + switchMap((version) => + version == '4.2.2' + ? super.getFiltersForValues(values) + : super.getFiltersForValues(values, this.esFieldName) + ) + ) + } + getValuesForFilter(filters: FieldFilters): Observable { + return this.version.pipe( + switchMap((version) => + version == '4.2.2' + ? super.getValuesForFilter(filters) + : super.getValuesForFilter(filters, this.esFieldName) + ) + ) + } + + getTranslatedAggregations() { + return this.searchApiService + .search( + 'bucket', + JSON.stringify( + this.esService.getSearchRequestBody({ + contactForResource: { + nested: { + path: 'contactForResource', + }, + aggs: { + default: { + terms: { + field: `contactForResource.organisationObject.default.keyword`, + exclude: '', + size: 5000, + order: { _key: this.order }, + }, + aggs: { + translation: { + terms: { + size: 50, + exclude: '', + field: `contactForResource.organisationObject.${this.langService.gnLang}.keyword`, + }, + }, + }, + }, + }, + }, + }) + ) + ) + .pipe( + map( + (response) => response.aggregations.contactForResource.default.buckets + ), + shareReplay() + ) + } + + getAvailableValues(): Observable { + // sort values by alphabetical order + return this.version.pipe( + switchMap((version) => + version == '4.2.2' + ? super.getAvailableValues() + : this.getTranslatedAggregations().pipe( + map((response) => + response.map((tmp) => { + const label = tmp.translation.buckets[0]?.key || tmp.key + return { + label: `${label} (${tmp.doc_count})`, + value: tmp.key, + } + }) + ) + ) + ) + ) + } +} diff --git a/package-lock.json b/package-lock.json index 159b377f88..a938a8fa4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "pg": "^8.9.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.0.0", + "semver": "^7.5.4", "tippy.js": "^6.3.7", "tslib": "^2.3.0", "typeorm": "^0.3.14", @@ -921,17 +922,6 @@ "@esbuild/win32-x64": "0.18.17" } }, - "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/magic-string": { "version": "0.30.1", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz", @@ -970,25 +960,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1602.0", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1602.0.tgz", @@ -1278,6 +1249,39 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular/cli/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@angular/common": { "version": "16.1.7", "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.1.7.tgz", @@ -6788,6 +6792,17 @@ "node": ">=8" } }, + "node_modules/@nx/angular/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nx/angular/node_modules/magic-string": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", @@ -6799,6 +6814,20 @@ "node": ">=12" } }, + "node_modules/@nx/angular/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nx/angular/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6810,6 +6839,11 @@ "node": ">=8" } }, + "node_modules/@nx/angular/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@nx/cypress": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-16.6.0.tgz", @@ -6834,6 +6868,36 @@ } } }, + "node_modules/@nx/cypress/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/cypress/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/cypress/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@nx/devkit": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-16.6.0.tgz", @@ -6850,6 +6914,36 @@ "nx": ">= 15 <= 17" } }, + "node_modules/@nx/devkit/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/devkit/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@nx/eslint-plugin": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-16.6.0.tgz", @@ -6992,6 +7086,33 @@ "node": ">=8" } }, + "node_modules/@nx/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/eslint-plugin/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nx/eslint-plugin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7004,6 +7125,12 @@ "node": ">=8" } }, + "node_modules/@nx/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@nx/jest": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-16.6.0.tgz", @@ -7166,6 +7293,31 @@ "node": ">=8" } }, + "node_modules/@nx/js/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/js/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@nx/js/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -7194,6 +7346,11 @@ "node": ">=8" } }, + "node_modules/@nx/js/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@nx/linter": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/linter/-/linter-16.6.0.tgz", @@ -7304,6 +7461,39 @@ "node": ">=8.6" } }, + "node_modules/@nx/nest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/nest/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/nest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@nx/node": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/node/-/node-16.6.0.tgz", @@ -7487,6 +7677,39 @@ "tslib": "^2.3.0" } }, + "node_modules/@nx/storybook/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/storybook/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@nx/storybook/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@nx/webpack": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-16.6.0.tgz", @@ -25662,6 +25885,31 @@ "node": ">=8" } }, + "node_modules/nx/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nx/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/nx/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -25686,6 +25934,11 @@ "node": ">=8" } }, + "node_modules/nx/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -28733,9 +28986,9 @@ } }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, diff --git a/package.json b/package.json index 72a8dc2c56..c569b15385 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "pg": "^8.9.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.0.0", + "semver": "^7.5.4", "tippy.js": "^6.3.7", "tslib": "^2.3.0", "typeorm": "^0.3.14", diff --git a/support-services/docker-entrypoint-initdb.d/dump b/support-services/docker-entrypoint-initdb.d/dump index 6a86fefc3d..66d62e47a3 100644 Binary files a/support-services/docker-entrypoint-initdb.d/dump and b/support-services/docker-entrypoint-initdb.d/dump differ diff --git a/translations/de.json b/translations/de.json index 8755763492..9819a448a9 100644 --- a/translations/de.json +++ b/translations/de.json @@ -26,10 +26,10 @@ "dashboard.records.noUser": "", "dashboard.records.publishedRecords": "", "dashboard.records.search": "", - "dashboard.records.users": "", - "dashboard.records.username": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "Dateiformat-Erkennung", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "Sammeln von Datensatzinformationen", "datafeeder.analysisProgressBar.illustration.samplingData": "Datenauswahl", @@ -207,6 +207,8 @@ "record.metadata.origin": "Über die Daten", "record.metadata.preview": "Vorschau", "record.metadata.publications": "Veröffentlichungen", + "record.metadata.quality": "", + "record.metadata.quality.details": "", "record.metadata.related": "Ähnliche Datensätze", "record.metadata.sheet": "Weitere Informationen erhalten Sie unter :", "record.metadata.title": "Titel", @@ -228,6 +230,7 @@ "results.showMore": "Mehr Ergebnisse anzeigen...", "results.sortBy.dateStamp": "Letzte Aktualisierungen", "results.sortBy.popularity": "Beliebtheit", + "results.sortBy.qualityScore": "", "results.sortBy.relevancy": "Relevanz", "search.autocomplete.error": "Vorschläge konnten nicht abgerufen werden:", "search.error.couldNotReachApi": "Die API konnte nicht erreicht werden", @@ -236,6 +239,7 @@ "search.field.any.placeholder": "Suche nach Datensätzen ...", "search.field.sortBy": "Sortieren nach:", "search.filters.clear": "Zurücksetzen", + "search.filters.contact": "Kontakt", "search.filters.format": "Formate", "search.filters.inspireKeyword": "INSPIRE-Schlüsselwort", "search.filters.isSpatial": "Ist räumliche Daten", @@ -253,10 +257,10 @@ "search.filters.license.unknown": "Unbekannt oder nicht vorhanden", "search.filters.maximize": "Erweitern", "search.filters.minimize": "Minimieren", - "search.filters.publicationYear": "Veröffentlichungsjahr", "search.filters.myRecords": "", "search.filters.myRecordsHelp": "", "search.filters.otherRecords": "", + "search.filters.publicationYear": "Veröffentlichungsjahr", "search.filters.publisher": "Organisationen", "search.filters.representationType": "", "search.filters.resourceType": "", diff --git a/translations/en.json b/translations/en.json index 19c040d9d0..2c99251c67 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}", - "catalog.figures.organisations": "{count, plural, =0{organisations} one{organisation} other{organisations}}", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "average", "chart.aggregation.count": "count", "chart.aggregation.max": "max", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "No users for this organization", "dashboard.records.publishedRecords": "published records", "dashboard.records.search": "Search for \"{searchText}\"", - "dashboard.records.users": "users", - "dashboard.records.username": "Username", "dashboard.records.userDetail": "Name", "dashboard.records.userEmail": "Email", + "dashboard.records.username": "Username", + "dashboard.records.users": "users", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "File format \n detection", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "Gathering dataset \n information", "datafeeder.analysisProgressBar.illustration.samplingData": "Sampling \n data", @@ -207,6 +207,8 @@ "record.metadata.origin": "About the data", "record.metadata.preview": "Preview", "record.metadata.publications": "publications", + "record.metadata.quality": "Metadata Quality", + "record.metadata.quality.details": "Details", "record.metadata.related": "Related records", "record.metadata.sheet": "More information available from:", "record.metadata.title": "Title", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "Data Update Status", "record.metadata.updatedOn": "Last Data Information Update", "record.metadata.usage": "Usage & constraints", - "record.metadata.quality": "Metadata Quality", - "record.metadata.quality.details": "Details", - "record.metadata.quality.title.success": "Title is completed", - "record.metadata.quality.title.failed": "Title is not completed", - "record.metadata.quality.description.success": "Description is completed", - "record.metadata.quality.description.failed": "Description is not completed", - "record.metadata.quality.topic.success": "Topic is completed", - "record.metadata.quality.topic.failed": "Topic is not completed", - "record.metadata.quality.keywords.success": "Keywords are completed", - "record.metadata.quality.keywords.failed": "Keywords are not completed", - "record.metadata.quality.legalConstraints.success": "Legal constraints are completed", - "record.metadata.quality.legalConstraints.failed": "Legal constraints are not completed", - "record.metadata.quality.contact.success": "Contact is completed", - "record.metadata.quality.contact.failed": "Contact is not completed", - "record.metadata.quality.updateFrequency.success": "Update frequency is completed", - "record.metadata.quality.updateFrequency.failed": "Update frequency is not completed", - "record.metadata.quality.organisation.success": "Organisation is completed", - "record.metadata.quality.organisation.failed": "Organisation is not completed", "record.more.details": "Read more", "record.tab.chart": "Chart", "record.tab.data": "Table", @@ -246,8 +230,8 @@ "results.showMore": "Show more results...", "results.sortBy.dateStamp": "Most recent", "results.sortBy.popularity": "Popularity", - "results.sortBy.relevancy": "Relevancy", "results.sortBy.qualityScore": "Quality score", + "results.sortBy.relevancy": "Relevancy", "search.autocomplete.error": "Suggestions could not be fetched:", "search.error.couldNotReachApi": "The API could not be reached", "search.error.receivedError": "An error was received", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "Search datasets ...", "search.field.sortBy": "Sort by:", "search.filters.clear": "Reset", + "search.filters.contact": "Contact", "search.filters.format": "Formats", "search.filters.inspireKeyword": "INSPIRE keyword", "search.filters.isSpatial": "Is spatial data", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "Unknown or absent", "search.filters.maximize": "Expand", "search.filters.minimize": "Minimize", - "search.filters.publicationYear": "Publication year", "search.filters.myRecords": "Show only my records", "search.filters.myRecordsHelp": "When this is enabled, records only created by myself are shown; records created by others will not show up.", "search.filters.otherRecords": "Showing records from another person", + "search.filters.publicationYear": "Publication year", "search.filters.publisher": "Organizations", "search.filters.representationType": "Representation type", "search.filters.resourceType": "Resource type", diff --git a/translations/es.json b/translations/es.json index d35079a512..2b12fdcb37 100644 --- a/translations/es.json +++ b/translations/es.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "conjuntos de datos", - "catalog.figures.organisations": "organizaciones", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "promedio", "chart.aggregation.count": "conteo", "chart.aggregation.max": "máximo", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Buscar \"{searchText}\"", - "dashboard.records.users": "", - "dashboard.records.username": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "", "datafeeder.analysisProgressBar.illustration.samplingData": "", @@ -207,6 +207,8 @@ "record.metadata.origin": "", "record.metadata.preview": "", "record.metadata.publications": "", + "record.metadata.quality": "", + "record.metadata.quality.details": "", "record.metadata.related": "", "record.metadata.sheet": "", "record.metadata.title": "", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "", "record.metadata.updatedOn": "", "record.metadata.usage": "", - "record.metadata.quality": "", - "record.metadata.quality.details": "", - "record.metadata.quality.title.success": "", - "record.metadata.quality.title.failed": "", - "record.metadata.quality.description.success": "", - "record.metadata.quality.description.failed": "", - "record.metadata.quality.topic.success": "", - "record.metadata.quality.topic.failed": "", - "record.metadata.quality.keywords.success": "", - "record.metadata.quality.keywords.failed": "", - "record.metadata.quality.legalConstraints.success": "", - "record.metadata.quality.legalConstraints.failed": "", - "record.metadata.quality.contact.success": "", - "record.metadata.quality.contact.failed": "", - "record.metadata.quality.updateFrequency.success": "", - "record.metadata.quality.updateFrequency.failed": "", - "record.metadata.quality.organisation.success": "", - "record.metadata.quality.organisation.failed": "", "record.more.details": "", "record.tab.chart": "", "record.tab.data": "", @@ -246,8 +230,8 @@ "results.showMore": "", "results.sortBy.dateStamp": "", "results.sortBy.popularity": "", - "results.sortBy.relevancy": "", "results.sortBy.qualityScore": "", + "results.sortBy.relevancy": "", "search.autocomplete.error": "", "search.error.couldNotReachApi": "", "search.error.receivedError": "", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "", "search.field.sortBy": "", "search.filters.clear": "", + "search.filters.contact": "", "search.filters.format": "", "search.filters.inspireKeyword": "", "search.filters.isSpatial": "", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "", "search.filters.maximize": "", "search.filters.minimize": "", - "search.filters.publicationYear": "", "search.filters.myRecords": "", "search.filters.myRecordsHelp": "", "search.filters.otherRecords": "", + "search.filters.publicationYear": "", "search.filters.publisher": "", "search.filters.representationType": "", "search.filters.resourceType": "", diff --git a/translations/fr.json b/translations/fr.json index c32b0b18d1..be9d5af691 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "{count, plural, =0{données} one{donnée} other{données}}", - "catalog.figures.organisations": "{count, plural, =0{organisations} one{organisation} other{organisations}}", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "moyenne", "chart.aggregation.count": "nombre", "chart.aggregation.max": "maximum", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "Aucun utilisateur pour cette organisation", "dashboard.records.publishedRecords": "données publiées", "dashboard.records.search": "Résultats pour \"{searchText}\"", - "dashboard.records.users": "utilisateurs", - "dashboard.records.username": "Nom d'utilisateur", "dashboard.records.userDetail": "Nom", "dashboard.records.userEmail": "Email", + "dashboard.records.username": "Nom d'utilisateur", + "dashboard.records.users": "utilisateurs", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "Détection du \n format de fichier", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "Récupération des informations \n sur le jeu de données", "datafeeder.analysisProgressBar.illustration.samplingData": "Sampling \n des données", @@ -207,6 +207,8 @@ "record.metadata.origin": "À propos des données", "record.metadata.preview": "Aperçu", "record.metadata.publications": "données", + "record.metadata.quality": "Qualité des métadonnées", + "record.metadata.quality.details": "Détails", "record.metadata.related": "Voir aussi", "record.metadata.sheet": "Plus d'informations à l'adresse suivante :", "record.metadata.title": "Titre", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "Statut de mise à jour des données", "record.metadata.updatedOn": "Dernière mise à jour des informations sur les données", "record.metadata.usage": "Conditions d'utilisation", - "record.metadata.quality": "Qualité des métadonnées", - "record.metadata.quality.details": "Détails", - "record.metadata.quality.title.success": "Titre est renseigné", - "record.metadata.quality.title.failed": "Titre n'est pas renseigné", - "record.metadata.quality.description.success": "Description est renseignée", - "record.metadata.quality.description.failed": "Description n'est pas renseignée", - "record.metadata.quality.topic.success": "Thème est renseigné", - "record.metadata.quality.topic.failed": "Thème n'est pas renseigné", - "record.metadata.quality.keywords.success": "Mots clés sont renseignés", - "record.metadata.quality.keywords.failed": "Mots clés ne sont pas renseignés", - "record.metadata.quality.legalConstraints.success": "Contraintes légales sont renseignées", - "record.metadata.quality.legalConstraints.failed": "Contraintes légales ne sont pas renseignées", - "record.metadata.quality.contact.success": "Contact est renseigné", - "record.metadata.quality.contact.failed": "Contact n'est pas renseigné", - "record.metadata.quality.updateFrequency.success": "Fréquence de mise à jour est renseignée", - "record.metadata.quality.updateFrequency.failed": "Fréquence de mise à jour n'est pas renseignée", - "record.metadata.quality.organisation.success": "Producteur est renseigné", - "record.metadata.quality.organisation.failed": "Producteur n'est pas renseigné", "record.more.details": "Détails", "record.tab.chart": "Graphique", "record.tab.data": "Tableau", @@ -246,8 +230,8 @@ "results.showMore": "Plus de résultats...", "results.sortBy.dateStamp": "Plus récent", "results.sortBy.popularity": "Popularité", - "results.sortBy.relevancy": "Pertinence", "results.sortBy.qualityScore": "Indicateur de qualité", + "results.sortBy.relevancy": "Pertinence", "search.autocomplete.error": "Les suggestions ne peuvent pas être récupérées", "search.error.couldNotReachApi": "Problème de connexion à l'API", "search.error.receivedError": "Erreur retournée", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "Rechercher une donnée...", "search.field.sortBy": "Trier par :", "search.filters.clear": "Réinitialiser", + "search.filters.contact": "Contact", "search.filters.format": "Formats", "search.filters.inspireKeyword": "Mot-clé INSPIRE", "search.filters.isSpatial": "Données spatiales", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "Non-reconnue ou absente", "search.filters.maximize": "Agrandir", "search.filters.minimize": "Réduire", - "search.filters.publicationYear": "Année de publication", "search.filters.myRecords": "Voir mes données", "search.filters.myRecordsHelp": "Quand activé, n'affiche que les données créées avec mon utilisateur. Les données créées par les autres utilisateurs ne sont pas affichées.", "search.filters.otherRecords": "Affichage des données d'un autre utilisateur", + "search.filters.publicationYear": "Année de publication", "search.filters.publisher": "Organisations", "search.filters.representationType": "Type de représentation", "search.filters.resourceType": "Type de ressource", diff --git a/translations/it.json b/translations/it.json index 73c62af3af..f3a10a848f 100644 --- a/translations/it.json +++ b/translations/it.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "dataset", - "catalog.figures.organisations": "organizzazioni", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "media", "chart.aggregation.count": "conteggio", "chart.aggregation.max": "massimo", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Cerca \"{searchText}\"", - "dashboard.records.users": "", - "dashboard.records.username": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "", "datafeeder.analysisProgressBar.illustration.samplingData": "", @@ -207,6 +207,8 @@ "record.metadata.origin": "", "record.metadata.preview": "", "record.metadata.publications": "", + "record.metadata.quality": "", + "record.metadata.quality.details": "", "record.metadata.related": "", "record.metadata.sheet": "", "record.metadata.title": "", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "", "record.metadata.updatedOn": "", "record.metadata.usage": "", - "record.metadata.quality": "", - "record.metadata.quality.details": "", - "record.metadata.quality.title.success": "", - "record.metadata.quality.title.failed": "", - "record.metadata.quality.description.success": "", - "record.metadata.quality.description.failed": "", - "record.metadata.quality.topic.success": "", - "record.metadata.quality.topic.failed": "", - "record.metadata.quality.keywords.success": "", - "record.metadata.quality.keywords.failed": "", - "record.metadata.quality.legalConstraints.success": "", - "record.metadata.quality.legalConstraints.failed": "", - "record.metadata.quality.contact.success": "", - "record.metadata.quality.contact.failed": "", - "record.metadata.quality.updateFrequency.success": "", - "record.metadata.quality.updateFrequency.failed": "", - "record.metadata.quality.organisation.success": "", - "record.metadata.quality.organisation.failed": "", "record.more.details": "", "record.tab.chart": "", "record.tab.data": "", @@ -246,8 +230,8 @@ "results.showMore": "", "results.sortBy.dateStamp": "", "results.sortBy.popularity": "", - "results.sortBy.relevancy": "", "results.sortBy.qualityScore": "", + "results.sortBy.relevancy": "", "search.autocomplete.error": "", "search.error.couldNotReachApi": "", "search.error.receivedError": "", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "", "search.field.sortBy": "", "search.filters.clear": "", + "search.filters.contact": "", "search.filters.format": "", "search.filters.inspireKeyword": "", "search.filters.isSpatial": "", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "", "search.filters.maximize": "", "search.filters.minimize": "", - "search.filters.publicationYear": "", "search.filters.myRecords": "", "search.filters.myRecordsHelp": "", "search.filters.otherRecords": "", + "search.filters.publicationYear": "", "search.filters.publisher": "", "search.filters.representationType": "", "search.filters.resourceType": "", diff --git a/translations/nl.json b/translations/nl.json index 00087862f2..f45077e8af 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "datasets", - "catalog.figures.organisations": "organisaties", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "gemiddelde", "chart.aggregation.count": "aantal", "chart.aggregation.max": "max", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Zoeken naar \"{searchText}\"", - "dashboard.records.users": "", - "dashboard.records.username": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "", "datafeeder.analysisProgressBar.illustration.samplingData": "", @@ -207,6 +207,8 @@ "record.metadata.origin": "", "record.metadata.preview": "", "record.metadata.publications": "", + "record.metadata.quality": "", + "record.metadata.quality.details": "", "record.metadata.related": "", "record.metadata.sheet": "", "record.metadata.title": "", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "", "record.metadata.updatedOn": "", "record.metadata.usage": "", - "record.metadata.quality": "", - "record.metadata.quality.details": "", - "record.metadata.quality.title.success": "", - "record.metadata.quality.title.failed": "", - "record.metadata.quality.description.success": "", - "record.metadata.quality.description.failed": "", - "record.metadata.quality.topic.success": "", - "record.metadata.quality.topic.failed": "", - "record.metadata.quality.keywords.success": "", - "record.metadata.quality.keywords.failed": "", - "record.metadata.quality.legalConstraints.success": "", - "record.metadata.quality.legalConstraints.failed": "", - "record.metadata.quality.contact.success": "", - "record.metadata.quality.contact.failed": "", - "record.metadata.quality.updateFrequency.success": "", - "record.metadata.quality.updateFrequency.failed": "", - "record.metadata.quality.organisation.success": "", - "record.metadata.quality.organisation.failed": "", "record.more.details": "", "record.tab.chart": "", "record.tab.data": "", @@ -246,8 +230,8 @@ "results.showMore": "", "results.sortBy.dateStamp": "", "results.sortBy.popularity": "", - "results.sortBy.relevancy": "", "results.sortBy.qualityScore": "", + "results.sortBy.relevancy": "", "search.autocomplete.error": "", "search.error.couldNotReachApi": "", "search.error.receivedError": "", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "", "search.field.sortBy": "", "search.filters.clear": "", + "search.filters.contact": "", "search.filters.format": "", "search.filters.inspireKeyword": "", "search.filters.isSpatial": "", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "", "search.filters.maximize": "", "search.filters.minimize": "", - "search.filters.publicationYear": "", "search.filters.myRecords": "", "search.filters.myRecordsHelp": "", "search.filters.otherRecords": "", + "search.filters.publicationYear": "", "search.filters.publisher": "", "search.filters.representationType": "", "search.filters.resourceType": "", diff --git a/translations/pt.json b/translations/pt.json index 83a73859c8..f1bbf5f261 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "conjuntos de dados", - "catalog.figures.organisations": "organizações", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "média", "chart.aggregation.count": "contagem", "chart.aggregation.max": "máximo", @@ -26,10 +26,10 @@ "dashboard.records.noUser": "", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Buscar por \"{searchText}\"", - "dashboard.records.users": "", - "dashboard.records.username": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "", "datafeeder.analysisProgressBar.illustration.samplingData": "", @@ -207,6 +207,8 @@ "record.metadata.origin": "", "record.metadata.preview": "", "record.metadata.publications": "", + "record.metadata.quality": "", + "record.metadata.quality.details": "", "record.metadata.related": "", "record.metadata.sheet": "", "record.metadata.title": "", @@ -214,24 +216,6 @@ "record.metadata.updateStatus": "", "record.metadata.updatedOn": "", "record.metadata.usage": "", - "record.metadata.quality": "", - "record.metadata.quality.details": "", - "record.metadata.quality.title.success": "", - "record.metadata.quality.title.failed": "", - "record.metadata.quality.description.success": "", - "record.metadata.quality.description.failed": "", - "record.metadata.quality.topic.success": "", - "record.metadata.quality.topic.failed": "", - "record.metadata.quality.keywords.success": "", - "record.metadata.quality.keywords.failed": "", - "record.metadata.quality.legalConstraints.success": "", - "record.metadata.quality.legalConstraints.failed": "", - "record.metadata.quality.contact.success": "", - "record.metadata.quality.contact.failed": "", - "record.metadata.quality.updateFrequency.success": "", - "record.metadata.quality.updateFrequency.failed": "", - "record.metadata.quality.organisation.success": "", - "record.metadata.quality.organisation.failed": "", "record.more.details": "", "record.tab.chart": "", "record.tab.data": "", @@ -246,8 +230,8 @@ "results.showMore": "", "results.sortBy.dateStamp": "", "results.sortBy.popularity": "", - "results.sortBy.relevancy": "", "results.sortBy.qualityScore": "", + "results.sortBy.relevancy": "", "search.autocomplete.error": "", "search.error.couldNotReachApi": "", "search.error.receivedError": "", @@ -255,6 +239,7 @@ "search.field.any.placeholder": "", "search.field.sortBy": "", "search.filters.clear": "", + "search.filters.contact": "", "search.filters.format": "", "search.filters.inspireKeyword": "", "search.filters.isSpatial": "", @@ -272,10 +257,10 @@ "search.filters.license.unknown": "", "search.filters.maximize": "", "search.filters.minimize": "", - "search.filters.publicationYear": "", "search.filters.myRecords": "", "search.filters.myRecordsHelp": "", "search.filters.otherRecords": "", + "search.filters.publicationYear": "", "search.filters.publisher": "", "search.filters.representationType": "", "search.filters.resourceType": "", diff --git a/translations/sk.json b/translations/sk.json index 55a57fd795..45e7b6d133 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -1,6 +1,6 @@ { - "catalog.figures.datasets": "datasety", - "catalog.figures.organisations": "organizácie", + "catalog.figures.datasets": "", + "catalog.figures.organisations": "", "chart.aggregation.average": "priemer", "chart.aggregation.count": "počet", "chart.aggregation.max": "maximum", @@ -22,7 +22,14 @@ "dashboard.records.myLibrary": "Moja knižnica", "dashboard.records.myOrg": "Organizácia", "dashboard.records.myRecords": "Moje záznamy", + "dashboard.records.noRecord": "", + "dashboard.records.noUser": "", + "dashboard.records.publishedRecords": "", "dashboard.records.search": "Hľadať \"{searchText}\"", + "dashboard.records.userDetail": "", + "dashboard.records.userEmail": "", + "dashboard.records.username": "", + "dashboard.records.users": "", "datafeeder.analysisProgressBar.illustration.fileFormatDetection": "Detekcia formátu súboru", "datafeeder.analysisProgressBar.illustration.gatheringDatasetInformation": "Zbieranie informácií o datasete", "datafeeder.analysisProgressBar.illustration.samplingData": "Vzorkovanie dát", @@ -219,6 +226,7 @@ "results.records.hits.displayedOn": "{displayed, plural, =0{Žiadny záznam.} one{1 záznam} other{{displayed} záznamov }} {hits, plural, other{zobrazených z {hits} celkovo.}}", "results.records.hits.empty.help.html": "Návrhy:
  • Vyskúšajte iné slová
  • Uveďte menej slov
", "results.records.hits.found": "{hits, plural, =0{Žiadne dokumenty nezodpovedajú zadanému vyhľadávaniu.} one{1 záznam nájdený.} other{{hits} záznamov nájdených.}}", + "results.records.hits.selected": "", "results.showMore": "Zobraziť viac výsledkov...", "results.sortBy.dateStamp": "Najnovšie", "results.sortBy.popularity": "Popularita", @@ -231,6 +239,7 @@ "search.field.any.placeholder": "Hľadať datasety ...", "search.field.sortBy": "Zoradiť podľa:", "search.filters.clear": "Obnoviť", + "search.filters.contact": "", "search.filters.format": "Formáty", "search.filters.inspireKeyword": "Kľúčové slová INSPIRE", "search.filters.isSpatial": "Je priestorový údaj", @@ -244,5 +253,33 @@ "search.filters.license.etalab-v2": "Open Licence v2.0 (Etalab)", "search.filters.license.odbl": "Open Data Commons ODbL", "search.filters.license.odc-by": "Open Data Commons ODC-By", - "search.filters.license.pddl": "Open Data Commons" + "search.filters.license.pddl": "Open Data Commons", + "search.filters.license.unknown": "", + "search.filters.maximize": "", + "search.filters.minimize": "", + "search.filters.myRecords": "", + "search.filters.myRecordsHelp": "", + "search.filters.otherRecords": "", + "search.filters.publicationYear": "", + "search.filters.publisher": "", + "search.filters.representationType": "", + "search.filters.resourceType": "", + "search.filters.standard": "", + "search.filters.title": "", + "search.filters.topic": "", + "search.filters.useSpatialFilter": "", + "search.filters.useSpatialFilterHelp": "", + "share.tab.permalink": "", + "share.tab.webComponent": "", + "table.loading.data": "", + "table.object.count": "", + "table.select.data": "", + "tooltip.html.copy": "", + "tooltip.url.copy": "", + "tooltip.url.open": "", + "wfs.featuretype.notfound": "", + "wfs.geojsongml.notsupported": "", + "wfs.unreachable.cors": "", + "wfs.unreachable.http": "", + "wfs.unreachable.unknown": "" }