diff --git a/apps/datahub/src/styles.css b/apps/datahub/src/styles.css index 281c38d553..31624948a3 100644 --- a/apps/datahub/src/styles.css +++ b/apps/datahub/src/styles.css @@ -8,7 +8,7 @@ body { } .container-xs { - max-width: 500px; + max-width: calc(100% - 170px); } .container-sm { max-width: 640px; diff --git a/apps/search/src/assets/i18n/en.json b/apps/search/src/assets/i18n/en.json index c6570368b2..7a8853a9d3 100644 --- a/apps/search/src/assets/i18n/en.json +++ b/apps/search/src/assets/i18n/en.json @@ -22,8 +22,7 @@ "results.sortBy.dateStamp": "Last updates", "results.sortBy.popularity": "Popularity", "results.sortBy.relevancy": "Relevancy", - "results.sortBy.qualityScore": "Quality score", "search.field.any.placeholder": "Search datasets, services and maps ...", "search.field.sortBy": "Sort by", "search.loading": "Loading ..." -} +} \ No newline at end of file diff --git a/libs/feature/search/src/lib/utils/mapper/elasticsearch.field.mapper.ts b/libs/feature/search/src/lib/utils/mapper/elasticsearch.field.mapper.ts index 7e38cae0de..7c126ecc91 100644 --- a/libs/feature/search/src/lib/utils/mapper/elasticsearch.field.mapper.ts +++ b/libs/feature/search/src/lib/utils/mapper/elasticsearch.field.mapper.ts @@ -5,6 +5,7 @@ import { getFirstValue, LinkClassifierService, LinkUsage, + mapContact, MetadataLink, MetadataLinkType, MetadataRecord, @@ -33,7 +34,7 @@ export class ElasticsearchFieldMapper { constructor( private metadataUrlService: MetadataUrlService, private linkClassifier: LinkClassifierService - ) {} + ) { } protected fields: Record = { id: (output, source) => ({ @@ -153,7 +154,7 @@ export class ElasticsearchFieldMapper { constraints } }, - MD_LegalConstraintsOtherConstraintsObject: (output, source) => + MD_LegalConstraintsOtherConstraintsObject: (output, source) => this.constraintField( 'MD_LegalConstraintsOtherConstraintsObject', output, @@ -189,14 +190,14 @@ export class ElasticsearchFieldMapper { } private calculateQualityScore = (source) => { - const qualityScore:number = selectField(source, 'qualityScore'); + const qualityScore: number = selectField(source, 'qualityScore'); if (qualityScore != null) { return qualityScore; - } + } const metadataQualityConfig: MetadataQualityConfig = getMetadataQualityConfig(); let total = 0; let success = 0; - const check = (name:string) => { + const check = (name: string) => { const display = metadataQualityConfig[`DISPLAY_${name}`] !== false; if (display) total++; return display; @@ -250,14 +251,16 @@ export class ElasticsearchFieldMapper { private genericField = (output) => output - private constraintField = (fieldName: string, output, source) => ({ - ...output, - constraints: [ - ...(output.constraints || []), - ...selectField(source, fieldName).map(selectTranslatedValue), - ], - }) - + private constraintField = (fieldName: string, output, source) => { + const constraints = Array.isArray(output.constraints) ? output.constraints : []; + const fieldValues = selectField(source, fieldName); + const translatedValues = fieldValues.map(selectTranslatedValue); + const updatedConstraints = [...constraints, ...translatedValues]; + return { + ...output, + constraints: updatedConstraints, + }; + } getMappingFn(fieldName: string) { return fieldName in this.fields ? this.fields[fieldName] : this.genericField } diff --git a/libs/feature/search/src/lib/utils/mapper/elasticsearch.mapper.spec.ts b/libs/feature/search/src/lib/utils/mapper/elasticsearch.mapper.spec.ts index 45a2ecb1b6..3f1fbd43b0 100644 --- a/libs/feature/search/src/lib/utils/mapper/elasticsearch.mapper.spec.ts +++ b/libs/feature/search/src/lib/utils/mapper/elasticsearch.mapper.spec.ts @@ -20,23 +20,23 @@ class OrganisationsServiceMock { of( 'contact' in source ? { - ...record, - contact: { - name: 'Main Contact', + ...record, + contact: { + name: 'Main Contact', + email: 'q2suppor@ifremer.fr', + organisation: source.contact[0].organisation, + }, + resourceContacts: [ + { + name: 'Resource Contact 1', email: 'q2suppor@ifremer.fr', - organisation: source.contact[0].organisation, }, - resourceContacts: [ - { - name: 'Resource Contact 1', - email: 'q2suppor@ifremer.fr', - }, - { - name: 'Resource Contact 2', - email: 'q2suppor@ifremer.fr', - }, - ], - } + { + name: 'Resource Contact 2', + email: 'q2suppor@ifremer.fr', + }, + ], + } : record ) ) @@ -78,6 +78,7 @@ describe('ElasticsearchMapper', () => { abstract: 'The grid is based on proposal ', id: '12456', metadataUrl: 'url', + qualityScore: 25, thumbnailUrl: 'data:image/png;base64,', title: 'EEA reference grid for Germany (10km), May 2013', uuid: '20e9e1a1-83c1-4f13-89ef-c19767d6ee18f', @@ -90,6 +91,7 @@ describe('ElasticsearchMapper', () => { abstract: 'Reference layer of the rivers sensitive areas, ', id: '12442', metadataUrl: 'url', + qualityScore: 25, thumbnailUrl: 'data:image/png;base64,', title: 'Urban Waste Water Treatment Directive, Sensitive areas - rivers reported under UWWTD data call 2015, Nov. 2017', @@ -428,9 +430,13 @@ describe('ElasticsearchMapper', () => { ], metadataUrl: 'url', ownerInfo: 'testadmin|ADMIN|Test|Administrator', + qualityScore: 100, thumbnailUrl: 'https://sextant.ifremer.fr/geonetwork/srv/api/records/cf5048f6-5bbf-4e44-ba74-e6f429af51ea/attachments/parametres.gif', title: 'Surval - Données par paramètre', + topic: [ + 'Océans', + ], uuid: 'cf5048f6-5bbf-4e44-ba74-e6f429af51ea', contact: { name: 'Main Contact', @@ -512,11 +518,12 @@ describe('ElasticsearchMapper', () => { 'Sète', 'La Rochelle', ], + legalConstraints: [ + "Restriction légale d'utilisation à préciser", + ], lineage: 'Les données sont bancarisées dans la base de données Quadrige.', constraints: [ - 'Restriction lié à l’exercice du droit moral', - "Restriction légale d'utilisation à préciser", 'Pas de restriction d’accès public', 'Licence Ouverte version 2.0 https://www.etalab.gouv.fr/wp-content/uploads/2017/04/ETALAB-Licence-Ouverte-v2.0.pdf', ], diff --git a/libs/ui/elements/src/lib/metadata-quality-info/metadata-quality-info.component.ts b/libs/ui/elements/src/lib/metadata-quality-info/metadata-quality-info.component.ts index 685007462d..ce803a4443 100644 --- a/libs/ui/elements/src/lib/metadata-quality-info/metadata-quality-info.component.ts +++ b/libs/ui/elements/src/lib/metadata-quality-info/metadata-quality-info.component.ts @@ -17,15 +17,18 @@ export class MetadataQualityInfoComponent { @Input() value: boolean get display() { - const name_snake_upper = this.name.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`).toUpperCase(); - return this.metadataQualityConfig['DISPLAY_' + name_snake_upper] !== false; + if (this.name) { + const nameSnakeUpper = this.name.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`).toUpperCase(); + return this.metadataQualityConfig['DISPLAY_' + nameSnakeUpper] !== false; + } + return false; } get icon() { - return this.value ? 'check' : 'warning_amber' + return this.value ? 'check' : 'warning_amber' } get labelKey() { - return 'record.metadata.quality.' + this.name + '.' + (this.value ? 'success' : 'failed') + return `record.metadata.quality.${this.name}.${(this.value ? 'success' : 'failed')}` } } diff --git a/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.css b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.css index 823a66e3c1..a03aeeb609 100644 --- a/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.css +++ b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.css @@ -1,8 +1,3 @@ -:host-context(.picto)>.metadata-quality { - margin-bottom: 0px; -} - - :host-context(.picto) > .metadata-quality > .widget > p.text { display: none; } diff --git a/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.spec.ts b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.spec.ts index 24935b84cf..d3af3ac346 100644 --- a/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.spec.ts +++ b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.spec.ts @@ -4,6 +4,7 @@ import { RECORDS_FULL_FIXTURE } from '@geonetwork-ui/util/shared/fixtures' import { TranslateModule } from '@ngx-translate/core' import { ContentGhostComponent } from '../content-ghost/content-ghost.component' import { MetadataQualityComponent } from './metadata-quality.component' +import { By } from '@angular/platform-browser' describe('MetadataQualityComponent', () => { let component: MetadataQualityComponent @@ -26,4 +27,28 @@ describe('MetadataQualityComponent', () => { it('should create', () => { expect(component).toBeTruthy() }) + + it('focus should show menu / blur should hide', () => { + const progressBar = fixture.debugElement.query(By.css('gn-ui-progress-bar')) + progressBar.nativeElement.focus(); + expect(component.isMenuShown).toBe(true) + progressBar.nativeElement.blur(); + expect(component.isMenuShown).toBe(false) + }) + + it('mouseenter should show menu / mouseleave should hide', () => { + const metadataQuality = fixture.debugElement.query(By.css('.metadata-quality')) + + const mouseEnterEvent = new Event('mouseenter'); + metadataQuality.nativeElement.dispatchEvent(mouseEnterEvent); + expect(component.isMenuShown).toBe(true) + + const mouseLeaveEvent = new Event('mouseleave'); + metadataQuality.nativeElement.dispatchEvent(mouseLeaveEvent); + expect(component.isMenuShown).toBe(false) + }) + + it('content', () => { + expect(component.metadata?.contact?.organisation).toBe("Ifremer"); + }) }) diff --git a/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.stories.ts b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.stories.ts new file mode 100644 index 0000000000..c4caf98707 --- /dev/null +++ b/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.stories.ts @@ -0,0 +1,35 @@ +import { + TRANSLATE_DEFAULT_CONFIG, + UtilI18nModule, +} from '@geonetwork-ui/util/i18n' +import { TranslateModule } from '@ngx-translate/core' +import { Meta, moduleMetadata, Story } from '@storybook/angular' +import { MetadataQualityComponent } from './metadata-quality.component' +import { UiElementsModule } from '../ui-elements.module' +import { RECORDS_FULL_FIXTURE } from '@geonetwork-ui/util/shared/fixtures' + +export default { + title: 'Elements/MetadataQualityComponent', + component: MetadataQualityComponent, + decorators: [ + moduleMetadata({ + imports: [ + UiElementsModule, + UtilI18nModule, + TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG), + ], + }), + ], +} as Meta + +const Template: Story = ( + args: MetadataQualityComponent +) => ({ + component: MetadataQualityComponent, + props: args, +}) + +export const Primary = Template.bind({}) +Primary.args = { + metadata: RECORDS_FULL_FIXTURE[1], +} diff --git a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.spec.ts b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.spec.ts index c54f3ae446..9b7b3e1ef0 100644 --- a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.spec.ts +++ b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.spec.ts @@ -2,6 +2,13 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { ProgressBarComponent } from './progress-bar.component' +jest.mock('@geonetwork-ui/util/app-config', () => ({ + getThemeConfig: () => ({ + PROGRESS_BAR_TEXT_CLASS: '', + }), + isConfigLoaded: jest.fn(() => true), +})) + describe('ProgressBarComponent', () => { let component: ProgressBarComponent let fixture: ComponentFixture diff --git a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.stories.ts b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.stories.ts index 1cf8f5fcb5..d145bea253 100644 --- a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.stories.ts +++ b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.stories.ts @@ -1,6 +1,7 @@ import { moduleMetadata, Story, Meta } from '@storybook/angular' import { ProgressBarComponent } from './progress-bar.component' + export default { title: 'Widgets/ProgressBarComponent', component: ProgressBarComponent, diff --git a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.ts b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.ts index 6353f6f891..e1b5f1f94e 100644 --- a/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.ts +++ b/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core' -import { getThemeConfig } from '@geonetwork-ui/util/app-config' +import { getThemeConfig, isConfigLoaded } from '@geonetwork-ui/util/app-config' interface ColorScheme { outerBar: string @@ -15,7 +15,7 @@ interface ColorScheme { export class ProgressBarComponent { @Input() value = 0 @Input() type: 'primary' | 'secondary' | 'default' = 'default' - textClass = getThemeConfig().PROGRESS_BAR_TEXT_CLASS || 'font-bold' + textClass = isConfigLoaded() ? getThemeConfig().PROGRESS_BAR_TEXT_CLASS : 'font-bold' get progress() { return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0 diff --git a/libs/util/shared/src/lib/elasticsearch/elasticsearch.service.spec.ts b/libs/util/shared/src/lib/elasticsearch/elasticsearch.service.spec.ts index 52a3665544..90121b0de5 100644 --- a/libs/util/shared/src/lib/elasticsearch/elasticsearch.service.spec.ts +++ b/libs/util/shared/src/lib/elasticsearch/elasticsearch.service.spec.ts @@ -482,7 +482,14 @@ describe('ElasticsearchService', () => { 'linkProtocol', 'contactForResource.organisation', 'contact.organisation', + 'contact.email', 'userSavedCount', + "updateFrequency", + "cl_topic", + "cl_maintenanceAndUpdateFrequency", + "tag", + "MD_LegalConstraintsUseLimitationObject", + "qualityScore", ], query: { bool: { diff --git a/libs/util/shared/src/lib/fixtures/records.ts b/libs/util/shared/src/lib/fixtures/records.ts index 3b3ec174ad..319fca61de 100644 --- a/libs/util/shared/src/lib/fixtures/records.ts +++ b/libs/util/shared/src/lib/fixtures/records.ts @@ -159,4 +159,21 @@ export const RECORDS_FULL_FIXTURE: MetadataRecord[] = deepFreeze([ }, catalogUuid: '6731be1e-6533-44e0-9b8a-580b45e36e80', }, + { + id: '10421', + uuid: 'cf5048f6-5bbf-4e44-ba74-e6f429af51eb', + metadataUrl: 'url', + title: 'Test', + abstract: "La description du test", + updateFrequency: null, + keywords: [], + contact: { + name: 'Jean-Michel', + organisation: 'Ifremer', + email: 'q2suppor@ifremer.fr', + }, + topic: [], + legalConstraints: [], + qualityScore: 50 + } ])