From 969ced9c125a1644b41a46b94c92b1c877286fa5 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Tue, 19 Nov 2024 14:14:03 +0100 Subject: [PATCH 1/5] feat(me-converter): add support for resource identifier edition feat(editor): add field for resource identifier edition --- ...eneric-dataset+geo2france-plu.iso19139.xml | 7 ------ .../src/lib/fixtures/geo2france.records.ts | 2 ++ .../src/lib/fixtures/geocat-ch.records.ts | 1 + .../src/lib/iso19139/iso19139.converter.ts | 9 +++++++ .../src/lib/iso19139/read-parts.spec.ts | 25 +++++++++++++++++++ .../src/lib/iso19139/read-parts.ts | 14 +++++++++++ .../src/lib/iso19139/write-parts.ts | 17 +++++++++++++ .../src/lib/model/record/metadata.model.ts | 1 + libs/feature/editor/src/lib/fields.config.ts | 8 ++++++ 9 files changed, 77 insertions(+), 7 deletions(-) diff --git a/libs/api/metadata-converter/src/lib/fixtures/generic-dataset+geo2france-plu.iso19139.xml b/libs/api/metadata-converter/src/lib/fixtures/generic-dataset+geo2france-plu.iso19139.xml index b48bdadf6..012e01de0 100644 --- a/libs/api/metadata-converter/src/lib/fixtures/generic-dataset+geo2france-plu.iso19139.xml +++ b/libs/api/metadata-converter/src/lib/fixtures/generic-dataset+geo2france-plu.iso19139.xml @@ -45,13 +45,6 @@ A very interesting dataset (un jeu de données très intéressant) - - - - https://www.geoportail-urbanisme.gouv.fr/document/60036_PLU_20220329 - - - diff --git a/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts b/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts index 6b20e5a56..156741f69 100644 --- a/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +++ b/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts @@ -146,4 +146,6 @@ Ce lot de données produit en 2019, a été numérisé à partir du PCI Vecteur defaultLanguage: 'fr', otherLanguages: [], translations: {}, + resourceIdentifier: + 'https://www.geoportail-urbanisme.gouv.fr/document/60036_PLU_20220329', } diff --git a/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts b/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts index 72450d8f8..afb3cbc13 100644 --- a/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +++ b/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts @@ -68,6 +68,7 @@ export const GEOCAT_CH_DATASET_RECORD: DatasetRecord = { abstract: `Perimeter der Alpenkonvention in der Schweiz. Die Alpenkonvention ist ein völkerrechtlicher Vertrag zwischen den acht Alpenländern Deutschland, Frankreich, Italien, Liechtenstein, Monaco, Österreich, Schweiz, Slowenien sowie der Europäischen Union. Das Ziel des Übereinkommens ist der Schutz der Alpen durch eine sektorübergreifende, ganzheitliche und nachhaltige Politik.`, overviews: [], topics: ['planningCadastre', 'planningCadastre_Planning'], + resourceIdentifier: 'ch.are.alpenkonvention', keywords: [ { thesaurus: { diff --git a/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts b/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts index 4a7d1b474..bf3f6e0e5 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts @@ -34,6 +34,7 @@ import { readOwnerOrganization, readRecordUpdated, readResourceCreated, + readResourceIdentifier, readResourcePublished, readResourceUpdated, readSecurityConstraints, @@ -61,6 +62,7 @@ import { writeOtherConstraints, writeRecordUpdated, writeResourceCreated, + writeResourceIdentifier, writeResourcePublished, writeResourceUpdated, writeSecurityConstraints, @@ -85,6 +87,7 @@ export class Iso19139Converter extends BaseConverter { recordUpdated: readRecordUpdated, recordCreated: () => undefined, // not supported in ISO19139 recordPublished: () => undefined, // not supported in ISO19139 + resourceIdentifier: readResourceIdentifier, resourceUpdated: readResourceUpdated, resourceCreated: readResourceCreated, resourcePublished: readResourcePublished, @@ -124,6 +127,7 @@ export class Iso19139Converter extends BaseConverter { recordUpdated: writeRecordUpdated, recordCreated: () => undefined, // not supported in ISO19139 recordPublished: () => undefined, // not supported in ISO19139 + resourceIdentifier: writeResourceIdentifier, resourceUpdated: writeResourceUpdated, resourceCreated: writeResourceCreated, resourcePublished: writeResourcePublished, @@ -232,6 +236,7 @@ export class Iso19139Converter extends BaseConverter { const onlineResources = this.readers['onlineResources'](rootEl, tr) const otherLanguages = this.readers['otherLanguages'](rootEl, tr) const defaultLanguage = this.readers['defaultLanguage'](rootEl, tr) + const resourceIdentifier = this.readers['resourceIdentifier'](rootEl, tr) if (kind === 'dataset') { const status = this.readers['status'](rootEl, tr) @@ -246,6 +251,7 @@ export class Iso19139Converter extends BaseConverter { return this.afterRecordRead({ uniqueIdentifier, + ...(resourceIdentifier && { resourceIdentifier }), kind, otherLanguages, defaultLanguage, @@ -280,6 +286,7 @@ export class Iso19139Converter extends BaseConverter { } else { return this.afterRecordRead({ uniqueIdentifier, + ...(resourceIdentifier && { resourceIdentifier }), kind, otherLanguages, defaultLanguage, @@ -370,6 +377,8 @@ export class Iso19139Converter extends BaseConverter { this.writers['otherConstraints'](record, rootEl) fieldChanged('onlineResources') && this.writers['onlineResources'](record, rootEl) + fieldChanged('resourceIdentifier') && + this.writers['resourceIdentifier'](record, rootEl) if (record.kind === 'dataset') { fieldChanged('status') && this.writers['status'](record, rootEl) diff --git a/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts b/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts index f33351c88..499ec464d 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/read-parts.spec.ts @@ -19,6 +19,7 @@ import { readContacts, readOnlineResources, readOwnerOrganization, + readResourceIdentifier, readSpatialExtents, readTemporalExtents, } from './read-parts' @@ -790,6 +791,30 @@ describe('read parts', () => { ]) }) }) + + describe('read resource identifier', () => { + beforeEach(() => { + const mdIdentificationInfo = getRootElement( + parseXmlString(` + + + + fr-200053742/2021/scot + + + `) + ) + pipe( + removeChildrenByName('gmd:MD_Metadata.identificationInfo'), + appendChildren(() => mdIdentificationInfo) + )(recordRootEl) + }) + it('returns the resource identifier', () => { + expect(readResourceIdentifier(recordRootEl)).toEqual( + 'fr-200053742/2021/scot' + ) + }) + }) }) }) }) diff --git a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts index e1838d904..4e88f7458 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts @@ -1124,3 +1124,17 @@ export function readDefaultLanguage(rootEl: XmlElement): LanguageCode { map((lang) => (lang ? LANG_3_TO_2_MAPPER[lang.toLowerCase()] : null)) )(rootEl) } + +export function readResourceIdentifier(rootEl: XmlElement): string { + return pipe( + findIdentification(), + findNestedElement( + 'gmd:citation', + 'gmd:CI_Citation', + 'gmd:identifier', + 'gmd:MD_Identifier', + 'gmd:code' + ), + extractCharacterString() + )(rootEl) +} diff --git a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts index bf87b7ba1..b41c13e5c 100644 --- a/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +++ b/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts @@ -1463,3 +1463,20 @@ export function writeDefaultLanguage( writeAttribute('codeListValue', lang3) )(rootEl) } + +export function writeResourceIdentifier( + record: DatasetRecord, + rootEl: XmlElement +) { + pipe( + findOrCreateIdentification(), + findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'), + removeChildrenByName('gmd:identifier'), + record.resourceIdentifier + ? pipe( + createNestedChild('gmd:identifier', 'gmd:MD_Identifier', 'gmd:code'), + writeCharacterString(record.resourceIdentifier) + ) + : noop + )(rootEl) +} diff --git a/libs/common/domain/src/lib/model/record/metadata.model.ts b/libs/common/domain/src/lib/model/record/metadata.model.ts index 1a4403b43..249ef189e 100644 --- a/libs/common/domain/src/lib/model/record/metadata.model.ts +++ b/libs/common/domain/src/lib/model/record/metadata.model.ts @@ -104,6 +104,7 @@ export interface BaseRecord { updateFrequency?: UpdateFrequency // information related to the resource (dataset, service) + resourceIdentifier?: string contactsForResource: Array resourceCreated?: Date resourcePublished?: Date diff --git a/libs/feature/editor/src/lib/fields.config.ts b/libs/feature/editor/src/lib/fields.config.ts index d64e1eb89..8e0d9b4df 100644 --- a/libs/feature/editor/src/lib/fields.config.ts +++ b/libs/feature/editor/src/lib/fields.config.ts @@ -66,6 +66,13 @@ export const RECORD_KEYWORDS_FIELD: EditorField = { }, } +export const RESOURCE_IDENTIFIER_FIELD: EditorField = { + model: 'resourceIdentifier', + formFieldConfig: { + labelKey: marker('editor.record.form.field.resourceIdentifier'), + }, +} + export const RECORD_RESOURCE_UPDATED_FIELD: EditorField = { model: 'resourceUpdated', formFieldConfig: { @@ -176,6 +183,7 @@ export const ABOUT_SECTION: EditorSection = { hidden: false, fields: [ RECORD_UNIQUE_IDENTIFIER_FIELD, + RESOURCE_IDENTIFIER_FIELD, RECORD_RESOURCE_UPDATED_FIELD, RECORD_UPDATED_FIELD, RECORD_UPDATE_FREQUENCY_FIELD, From 9d249e9ff9de41db2dd974244d513f924ce1914e Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Tue, 19 Nov 2024 14:16:16 +0100 Subject: [PATCH 2/5] chore: Adapt form-field-simple to handle output --- .../form-field-simple.component.html | 29 +++---------------- .../form-field-simple.component.spec.ts | 2 -- .../form-field-simple.component.ts | 26 ++--------------- .../form-field/form-field.component.html | 7 +++++ 4 files changed, 14 insertions(+), 50 deletions(-) diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.html index 587ff5eeb..0c60b599a 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.html @@ -1,29 +1,8 @@ - diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.spec.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.spec.ts index bcb0f8b7c..68d785a46 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.spec.ts +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.spec.ts @@ -1,7 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { FormFieldSimpleComponent } from './form-field-simple.component' -import { FormControl } from '@angular/forms' describe('FormFieldSimpleComponent', () => { let component: FormFieldSimpleComponent @@ -14,7 +13,6 @@ describe('FormFieldSimpleComponent', () => { fixture = TestBed.createComponent(FormFieldSimpleComponent) component = fixture.componentInstance - component.control = new FormControl() fixture.detectChanges() }) diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.ts index e09b00ef0..59a5cc016 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.ts +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-simple/form-field-simple.component.ts @@ -6,6 +6,7 @@ import { Input, Output, } from '@angular/core' +import { FormsModule } from '@angular/forms' @Component({ selector: 'gn-ui-form-field-simple', @@ -13,35 +14,14 @@ import { styleUrls: ['./form-field-simple.component.css'], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [CommonModule], + imports: [CommonModule, FormsModule], }) export class FormFieldSimpleComponent { - @Input() type: 'date' | 'url' | 'text' | 'number' | 'list' | 'toggle' + @Input() type: 'text' | 'number' @Input() readonly = false @Input() invalid = false @Input() placeholder = '' - @Input() options?: { label: string; value: unknown }[] @Input() value: unknown @Output() valueChange: EventEmitter = new EventEmitter() - - get inputType() { - switch (this.type) { - case 'url': - case 'text': - return 'text' - case 'date': - return 'datetime-local' - case 'number': - return 'number' - case 'toggle': - return 'checkbox' - default: - return '' - } - } - - get isSelect() { - return this.type === 'list' - } } diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html index 60344f8c6..dc579cb07 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html @@ -62,6 +62,13 @@ (valueChange)="valueChange.emit($event)" > + + + Date: Tue, 19 Nov 2024 14:18:06 +0100 Subject: [PATCH 3/5] chore: Adapt styles to match mockups --- apps/metadata-editor/src/styles.css | 4 ++++ .../form-field-license/form-field-license.component.html | 1 + .../form-field-update-frequency.component.html | 1 + .../lib/dropdown-selector/dropdown-selector.component.html | 5 ++--- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/metadata-editor/src/styles.css b/apps/metadata-editor/src/styles.css index 661c2e293..00d7988b6 100644 --- a/apps/metadata-editor/src/styles.css +++ b/apps/metadata-editor/src/styles.css @@ -32,3 +32,7 @@ body { .mat-mdc-button-base { line-height: normal; } + +.input-as-button { + @apply border-2 border-gray-300 hover:border-main bg-transparent gn-ui-text-input hover:text-main py-[11.5px] pl-[14px] pr-2; +} diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.html index 833e5f015..04cda64de 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-license/form-field-license.component.html @@ -5,6 +5,7 @@ [choices]="licenceOptions" [selected]="selectedLicence" (selectValue)="handleLicenceSelection($event)" + [extraBtnClass]="'input-as-button'" > diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html index 9d784ff97..aabad8b79 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html @@ -11,6 +11,7 @@ [selected]="selectedFrequency" (selectValue)="onSelectFrequencyValue($event)" [disabled]="!planned" + [extraBtnClass]="'input-as-button'" > diff --git a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html index ee8d7e8b7..ec5b79ad2 100644 --- a/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +++ b/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html @@ -9,9 +9,8 @@ Date: Tue, 19 Nov 2024 14:18:54 +0100 Subject: [PATCH 4/5] chore: Add translation key --- translations/de.json | 1 + translations/en.json | 1 + translations/es.json | 1 + translations/fr.json | 1 + translations/it.json | 1 + translations/nl.json | 1 + translations/pt.json | 1 + translations/sk.json | 1 + 8 files changed, 8 insertions(+) diff --git a/translations/de.json b/translations/de.json index d7f694a98..95b4d8cdc 100644 --- a/translations/de.json +++ b/translations/de.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "Allgemeine Einschränkung", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "Datensatz zuletzt aktualisiert", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "Letztes Aktualisierungsdatum", "editor.record.form.field.securityConstraints": "Sicherheitseinschränkung", "editor.record.form.field.spatialExtents": "", diff --git a/translations/en.json b/translations/en.json index 30ecb4b41..f1d82a8cd 100644 --- a/translations/en.json +++ b/translations/en.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "Other constraint", "editor.record.form.field.overviews": "Overviews", "editor.record.form.field.recordUpdated": "Record Updated", + "editor.record.form.field.resourceIdentifier": "Identifier", "editor.record.form.field.resourceUpdated": "Resource Updated", "editor.record.form.field.securityConstraints": "Security constraint", "editor.record.form.field.spatialExtents": "Spatial extents", diff --git a/translations/es.json b/translations/es.json index fcc99e4f0..31c6296fa 100644 --- a/translations/es.json +++ b/translations/es.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "", "editor.record.form.field.securityConstraints": "", "editor.record.form.field.spatialExtents": "", diff --git a/translations/fr.json b/translations/fr.json index b74b97fc4..1418fd556 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "Contrainte générale", "editor.record.form.field.overviews": "Aperçus", "editor.record.form.field.recordUpdated": "Date de dernière révision", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "Date de dernière révision", "editor.record.form.field.securityConstraints": "Contrainte de sécurité", "editor.record.form.field.spatialExtents": "Étendue spatiale", diff --git a/translations/it.json b/translations/it.json index 6c0d71efb..47cbbb54e 100644 --- a/translations/it.json +++ b/translations/it.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "", "editor.record.form.field.securityConstraints": "", "editor.record.form.field.spatialExtents": "", diff --git a/translations/nl.json b/translations/nl.json index 99409151a..51c6144b9 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "", "editor.record.form.field.securityConstraints": "", "editor.record.form.field.spatialExtents": "", diff --git a/translations/pt.json b/translations/pt.json index 2e15157d6..bee39fdfb 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "", "editor.record.form.field.securityConstraints": "", "editor.record.form.field.spatialExtents": "", diff --git a/translations/sk.json b/translations/sk.json index 64d84d7f8..f68bc7078 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -240,6 +240,7 @@ "editor.record.form.field.otherConstraints": "", "editor.record.form.field.overviews": "", "editor.record.form.field.recordUpdated": "", + "editor.record.form.field.resourceIdentifier": "", "editor.record.form.field.resourceUpdated": "", "editor.record.form.field.securityConstraints": "", "editor.record.form.field.spatialExtents": "", From cf6e8f15ec993b04c9b53ba614f82b52d7bf5e46 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Tue, 19 Nov 2024 16:25:03 +0100 Subject: [PATCH 5/5] chore: Add resourceId to dcat-ap --- .../api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts b/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts index 76fe1ecd7..6cfa74924 100644 --- a/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +++ b/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts @@ -55,6 +55,7 @@ export class DcatApConverter extends BaseConverter { spatialExtents: readSpatialExtents, keywords: readKeywords, topics: readTopics, + resourceIdentifier: () => undefined, recordUpdated: readRecordUpdated, recordCreated: readRecordCreated, resourceUpdated: readResourceUpdated, @@ -93,6 +94,7 @@ export class DcatApConverter extends BaseConverter { recordUpdated: () => undefined, recordCreated: () => undefined, recordPublished: () => undefined, + resourceIdentifier: () => undefined, resourceUpdated: () => undefined, resourceCreated: () => undefined, resourcePublished: () => undefined,