Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sponsor by MEL] Add feature Metadata Quality Widget #497

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ <h2 class="text-xl mr-4 font-title" translate>
</button>
<gn-ui-sort-by
[ngClass]="isOpen ? 'block text-white mb-1' : 'hidden sm:block'"
[isQualitySortable]="isQualitySortable"
></gn-ui-sort-by>
</div>
<div class="text-right">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ import { SearchFiltersComponent } from './search-filters.component'
import { TranslateModule } from '@ngx-translate/core'
import { By } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import {
AggregationsTypes,
FieldFilters,
} from '@geonetwork-ui/common/domain/search'
import { FieldFilters } from '@geonetwork-ui/common/domain/search'

jest.mock('@geonetwork-ui/util/app-config', () => ({
getOptionalSearchConfig: () => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ChangeDetectionStrategy,
Component,
Input,
OnInit,
QueryList,
ViewChildren,
Expand All @@ -24,6 +25,7 @@ export class SearchFiltersComponent implements OnInit {
filters: QueryList<FilterDropdownComponent>
searchConfig: { fieldName: string; title: string }[]
isOpen = false
@Input() isQualitySortable = false

constructor(
public searchFacade: SearchFacade,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<div class="container-lg mx-auto mt-8">
<datahub-search-filters></datahub-search-filters>
<datahub-search-filters
[isQualitySortable]="isQualitySortable"
></datahub-search-filters>
<div class="mt-6 rounded-lg text-gray-800 p-4 bg-slate-100">
<gn-ui-results-hits></gn-ui-results-hits>
</div>
<div class="mt-8">
<gn-ui-results-list-container
[metadataQualityDisplay]="metadataQualityDisplay"
(mdSelect)="onMetadataSelection($event)"
showMore="button"
></gn-ui-results-list-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'
import { RouterFacade } from '@geonetwork-ui/feature/router'
import { SearchFacade } from '@geonetwork-ui/feature/search'
import { CatalogRecord } from '@geonetwork-ui/common/domain/record'
import { MetadataQualityDisplay } from '@geonetwork-ui/ui/elements'
import {
MetadataQualityConfig,
getMetadataQualityConfig,
} from '@geonetwork-ui/util/app-config'

@Component({
selector: 'datahub-search-page',
Expand All @@ -10,13 +15,31 @@ import { CatalogRecord } from '@geonetwork-ui/common/domain/record'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SearchPageComponent implements OnInit {
isQualitySortable = false
metadataQualityDisplay = {} as MetadataQualityDisplay

constructor(
private searchRouter: RouterFacade,
private searchFacade: SearchFacade
) {}

ngOnInit() {
this.searchFacade.setResultsLayout('ROW')

const cfg: MetadataQualityConfig =
getMetadataQualityConfig() || ({} as MetadataQualityConfig)
this.isQualitySortable = cfg.SORTABLE === true
this.metadataQualityDisplay = {
widget: cfg.ENABLED && cfg.DISPLAY_WIDGET_IN_SEARCH !== false,
title: cfg.DISPLAY_TITLE,
description: cfg.DISPLAY_DESCRIPTION,
contact: cfg.DISPLAY_CONTACT,
keywords: cfg.DISPLAY_KEYWORDS,
legalConstraints: cfg.DISPLAY_LEGAL_CONSTRAINTS,
topic: cfg.DISPLAY_TOPIC,
updateFrequency: cfg.DISPLAY_UPDATE_FREQUENCY,
organisation: cfg.DISPLAY_ORGANISATION,
}
}

onMetadataSelection(metadata: CatalogRecord): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
<datahub-header-record
[metadata]="mdViewFacade.metadata$ | async"
></datahub-header-record>
<gn-ui-record-metadata></gn-ui-record-metadata>
<gn-ui-record-metadata
[metadataQualityDisplay]="metadataQualityDisplay"
></gn-ui-record-metadata>
</div>
20 changes: 20 additions & 0 deletions apps/datahub/src/app/record/record-page/record-page.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ChangeDetectionStrategy, Component, OnDestroy } from '@angular/core'
import { MdViewFacade } from '@geonetwork-ui/feature/record'
import { MetadataQualityDisplay } from '@geonetwork-ui/ui/elements'
import {
MetadataQualityConfig,
getMetadataQualityConfig,
} from '@geonetwork-ui/util/app-config'

@Component({
selector: 'datahub-record-page',
Expand All @@ -8,8 +13,23 @@ import { MdViewFacade } from '@geonetwork-ui/feature/record'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RecordPageComponent implements OnDestroy {
metadataQualityDisplay: MetadataQualityDisplay = {} as MetadataQualityDisplay

constructor(public mdViewFacade: MdViewFacade) {
document.documentElement.classList.add('record-page-active')
const cfg: MetadataQualityConfig =
getMetadataQualityConfig() || ({} as MetadataQualityConfig)
this.metadataQualityDisplay = {
widget: cfg.ENABLED && cfg.DISPLAY_WIDGET_IN_DETAIL !== false,
title: cfg.DISPLAY_TITLE,
description: cfg.DISPLAY_DESCRIPTION,
contact: cfg.DISPLAY_CONTACT,
keywords: cfg.DISPLAY_KEYWORDS,
legalConstraints: cfg.DISPLAY_LEGAL_CONSTRAINTS,
topic: cfg.DISPLAY_TOPIC,
updateFrequency: cfg.DISPLAY_UPDATE_FREQUENCY,
organisation: cfg.DISPLAY_ORGANISATION,
}
}
ngOnDestroy() {
document.documentElement.classList.remove('record-page-active')
Expand Down
30 changes: 30 additions & 0 deletions conf/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,36 @@ background_color = "#fdfbff"

# Search presets will be advertised to the user along the main search field.


### METADATA QUALITY SETTINGS

# This section contains settings used for fine-tuning the metadata quality experience
[metadata-quality]
# By default the widget is not activated to enable it, just add this parameter.
# enabled = true
# If u want to use metadata quality widget this configuration is required

# if you add an indexed field to calculate the qualityScore, the datahub search allow you to sort on this field with this parameter
# sortable = true

# by default the widget appears in 2 locations in the search list and in the detail page
# allow you to hide the widget in detail
# display_widget_in_detail = false
# allow you to hide the widget in search list
# display_widget_in_search = false
# If you want see the widget in the two locations, don't fill theses configurations

# By default the window popup all fields to view if they are filled or not but you can hide some
# display_title = false
# display_description = false
# display_topic = false
# display_keywords = false
# display_legal_constraints = false
# display_contact = false
# display_update_frequency = false
# display_organisation = false
# If you want see all fields, don't fill theses configurations

### MAP SETTINGS

# The map section allows to customize how maps are configured.
Expand Down
31 changes: 30 additions & 1 deletion libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ export class Gn4FieldMapper {
const landingPage = getAsUrl(this.metadataUrlService.getUrl(uuid))
return { ...output, uniqueIdentifier: uuid, landingPage }
},
qualityScore: (output, source) =>
this.addExtra(
{ qualityScore: selectField(source, 'qualityScore') },
output
),
resourceTitleObject: (output, source) => ({
...output,
title: selectFallback(
Expand Down Expand Up @@ -83,6 +88,15 @@ export class Gn4FieldMapper {
],
}
},
cl_topic: (output, source) => ({
...output,
themes: [
...(output.themes || []),
...getAsArray(
selectField<SourceWithUnknownProps[]>(source, 'cl_topic')
).map((topic) => selectTranslatedValue<string>(topic, this.lang3)),
],
}),
cl_status: (output, source) => ({
...output,
status: getStatusFromStatusCode(
Expand Down Expand Up @@ -163,7 +177,10 @@ export class Gn4FieldMapper {
}),
inspireTheme: (output, source) => ({
...output,
themes: getAsArray(selectField(source, 'inspireTheme_syn')),
themes: [
...(output.themes || []),
...getAsArray(selectField(source, 'inspireTheme_syn')),
],
}),
MD_ConstraintsUseLimitationObject: (output, source) =>
this.constraintField('MD_ConstraintsUseLimitationObject', output, source),
Expand Down Expand Up @@ -249,6 +266,18 @@ export class Gn4FieldMapper {
...output,
...(fieldName.endsWith('UseLimitationObject')
? {
legalConstraints:
fieldName === 'MD_LegalConstraintsUseLimitationObject'
? [
...(output.legalConstraints || []),
...selectField<SourceWithUnknownProps[]>(
source,
fieldName
).map((source: SourceWithUnknownProps) =>
selectTranslatedValue(source, this.lang3)
),
]
: output.legalConstraints || [],
useLimitations: [
...(output.useLimitations || []),
...selectField<SourceWithUnknownProps[]>(source, fieldName).map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ describe('Gn4MetadataMapper', () => {
landingPage: new URL(
'http://my.catalog.org/metadata/cf5048f6-5bbf-4e44-ba74-e6f429af51ea'
),
legalConstraints: ["Restriction légale d'utilisation à préciser"],
licenses: [
{
link: new URL(
Expand All @@ -635,7 +636,7 @@ describe('Gn4MetadataMapper', () => {
recordCreated: new Date('2021-10-05T12:48:57.678Z'),
recordUpdated: new Date('2021-10-05T12:48:57.678Z'),
status: 'under_development',
themes: ['Installations de suivi environnemental'],
themes: ['Installations de suivi environnemental', 'Océans'],
title: 'Surval - Données par paramètre',
uniqueIdentifier: 'cf5048f6-5bbf-4e44-ba74-e6f429af51ea',
updateFrequency: {
Expand Down
7 changes: 7 additions & 0 deletions libs/api/repository/src/lib/gn4/elasticsearch/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ export const ES_SOURCE_SUMMARY = [
'linkProtocol',
'contactForResource.organisation',
'contact.organisation',
'contact.email',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is redundant with FIELDS_SUMMARY.
I think that ES_SOURCE_SUMMARY should be removed, what do you think @jahow .

@gkeimeHDF it's not your responsability, but I don't think that you need this change, as this constant is just used in the related records request.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no big deal, there's probably some more cleanup to do but that doesn't have to be part of this PR; I'm fine either way

'userSavedCount',
'updateFrequency',
'cl_topic',
'cl_maintenanceAndUpdateFrequency',
'tag',
'MD_LegalConstraintsUseLimitationObject',
'qualityScore',
]

export const ES_QUERY_STRING_FIELDS = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,14 @@ describe('ElasticsearchService', () => {
'linkProtocol',
'contactForResource.organisation',
'contact.organisation',
'contact.email',
'userSavedCount',
'updateFrequency',
'cl_topic',
'cl_maintenanceAndUpdateFrequency',
'tag',
'MD_LegalConstraintsUseLimitationObject',
'qualityScore',
],
query: {
bool: {
Expand Down
3 changes: 2 additions & 1 deletion libs/common/domain/src/lib/record/metadata.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ export interface BaseRecord {
keywords: Array<string> // TODO: handle thesaurus and id
accessConstraints: Array<AccessConstraint>
useLimitations: Array<string>
legalConstraints?: Array<string>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what to think with these changes, you are updating the pivot format which has been carefuly designed from various standards. I let @jahow judge, maybe those properties were missing.

BTW How do we manage topic over themes ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

legal constraints are accessConstraints of type legal, so no need for a new field I would say

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Topics and themes are semantically the same thing I would say. In ISO they are in two different places but we can probably append them together in the themes array for now. Non-INSPIRE records will get their themes from the cl_topic field, whereas INSPIRE records will get them from the inspireTheme field.

Copy link
Contributor Author

@gkeimeHDF gkeimeHDF Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jahow legalConstraints doesn't go to accessConstraints, it go to useLimitations which is a string Array.

https://github.com/geonetwork/geonetwork-ui/blob/7a84a5b053a3d56ae57f563d8793a40b4cca528f/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts#L248C12-L248C12

The field is MD_LegalConstraintsUseLimitationObject

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jahow Des nouvelles sur le sujet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jahow @fgravin i still need an answer about legalConstraints. Should i use accessConstraints type "legal" then actually it won't works because there no accessContraints for this field but a useLimitations ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gkeimeHDF sorry for taking so long to answer. It's a tricky subject, I think we can leave it like that and improve it later on. Thanks!

licenses: Array<License>
overviews: Array<GraphicOverview>
extras?: Record<string, unknown>
landingPage?: URL
updateFrequency?: UpdateFrequency

// to add: iso19139.topicCategory
// to add: canonical url
Expand Down Expand Up @@ -136,7 +138,6 @@ export interface DatasetRecord extends BaseRecord {
kind: 'dataset'
contactsForResource: Array<Individual>
status: RecordStatus
updateFrequency: UpdateFrequency
datasetCreated?: Date
datasetUpdated?: Date
lineage: string // Explanation of the origin of this record (e.g: how, why)"
Expand Down
1 change: 1 addition & 0 deletions libs/common/domain/src/lib/search/sort-by.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export const SortByEnum: Record<string, SortByField> = {
CREATE_DATE: ['desc', 'createDate'],
POPULARITY: ['desc', 'userSavedCount'],
RELEVANCY: ['desc', '_score'],
QUALITY_SCORE: ['desc', 'qualityScore'],
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
</gn-ui-metadata-info>
</div>
<div>
<div *ngIf="hasMetadataQualityWidget">
<p class="text text-gray-700 text-xs mb-3 uppercase" translate>
record.metadata.quality
</p>
<gn-ui-metadata-quality
[metadata]="facade.metadata$ | async"
[metadataQualityDisplay]="metadataQualityDisplay"
></gn-ui-metadata-quality>
</div>
<gn-ui-metadata-contact
(organizationClick)="onOrganizationClick($event)"
[metadata]="facade.metadata$ | async"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { SourcesService } from '@geonetwork-ui/feature/catalog'
import { SearchService } from '@geonetwork-ui/feature/search'
import { ErrorType } from '@geonetwork-ui/ui/elements'
import { ErrorType, MetadataQualityDisplay } from '@geonetwork-ui/ui/elements'
import { BehaviorSubject, combineLatest } from 'rxjs'
import { filter, map, mergeMap, pluck } from 'rxjs/operators'
import { filter, map, mergeMap } from 'rxjs/operators'
import { MdViewFacade } from '../state/mdview.facade'
import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface'
import { Individual, Organization } from '@geonetwork-ui/common/domain/record'
import { Organization } from '@geonetwork-ui/common/domain/record'

@Component({
selector: 'gn-ui-record-metadata',
Expand All @@ -15,6 +15,8 @@ import { Individual, Organization } from '@geonetwork-ui/common/domain/record'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RecordMetadataComponent {
@Input() metadataQualityDisplay: MetadataQualityDisplay

displayMap$ = combineLatest([
this.facade.mapApiLinks$,
this.facade.geoDataLinks$,
Expand Down Expand Up @@ -75,4 +77,8 @@ export class RecordMetadataComponent {
.getFiltersForOrgs([org])
.subscribe((filters) => this.searchService.updateFilters(filters))
}

get hasMetadataQualityWidget() {
return this.metadataQualityDisplay?.widget === true
}
}
6 changes: 6 additions & 0 deletions libs/feature/search/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ export const FIELDS_SUMMARY: FieldName[] = [
'linkProtocol',
'contactForResource*.organisation*',
'contact*.organisation*',
'contact*.email',
'userSavedCount',
'cl_topic',
'cl_maintenanceAndUpdateFrequency',
'tag',
'MD_LegalConstraintsUseLimitationObject',
'qualityScore',
]

export const FIELDS_BRIEF: FieldName[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<gn-ui-results-list
[records]="facade.results$ | async"
[layoutConfig]="layoutConfig$ | async"
[metadataQualityDisplay]="metadataQualityDisplay"
[favoriteTemplate]="favoriteToggle"
[recordUrlGetter]="recordUrlGetter"
(mdSelect)="onMetadataSelection($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Observable } from 'rxjs'
import { filter, map } from 'rxjs/operators'
import { SearchFacade } from '../state/search.facade'
import { SearchError } from '../state/reducer'
import { ErrorType } from '@geonetwork-ui/ui/elements'
import { ErrorType, MetadataQualityDisplay } from '@geonetwork-ui/ui/elements'
import {
RESULTS_LAYOUT_CONFIG,
ResultsLayoutConfigItem,
Expand All @@ -28,6 +28,7 @@ export type ResultsListShowMoreStrategy = 'auto' | 'button' | 'none'
styleUrls: ['./results-list.container.component.css'],
})
export class ResultsListContainerComponent implements OnInit {
@Input() metadataQualityDisplay: MetadataQualityDisplay
@Input() layout: string
@Input() showMore: ResultsListShowMoreStrategy = 'auto'
@Output() mdSelect = new EventEmitter<CatalogRecord>()
Expand Down
Loading
Loading