geonetwork-ui 2.10.0-dev.fb2893f44 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/geonetwork-ui.mjs +1017 -468
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +112 -111
- package/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +11 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/eu.dcat-ap.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +22 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+roilaye.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/metadata-for-i18n.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +22 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/opendataswiss.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/sextant.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/vlaanderen.dcat-ap.records.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.converter.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +4 -3
- package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +4 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +13 -0
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +45 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +13 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +40 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +47 -1
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +12 -8
- package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +9 -20
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +12 -0
- package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -1
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +57 -0
- package/src/libs/feature/editor/src/index.ts +1 -0
- package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
- package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
- package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +7 -6
- package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +10 -8
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +1 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +27 -16
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -0
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +14 -5
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +41 -0
- package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
- package/src/libs/feature/editor/src/lib/fields.config.ts +295 -291
- package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +6 -3
- package/src/libs/feature/editor/src/lib/services/editor.service.ts +8 -12
- package/src/libs/feature/notify-reuse/src/index.ts +1 -0
- package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
- package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
- package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -1
- package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +219 -8
- package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
- package/src/libs/ui/elements/src/index.ts +1 -0
- package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +48 -56
- package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
- package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
- package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
- package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +4 -7
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
- package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
- package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
- package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
- package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
- package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
- package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
- package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
- package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
- package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
- package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
- package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
- package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
- package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
- package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
- package/src/libs/util/shared/src/lib/links/link-utils.ts +22 -0
- package/tailwind.base.css +9 -2
- package/translations/de.json +84 -31
- package/translations/en.json +94 -41
- package/translations/es.json +58 -5
- package/translations/fr.json +91 -38
- package/translations/it.json +85 -32
- package/translations/nl.json +57 -4
- package/translations/pt.json +58 -5
- package/translations/sk.json +58 -5
- package/material-styles.css +0 -483
- package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
|
@@ -420,6 +420,28 @@ Cette donnée a été intégrée dans la base de données routière (BDR). Les D
|
|
|
420
420
|
Ces données, intégrées dans la Banque de Données routières (BDR), ont fait l’objet d’une mise à jour massive en 2014-2015.
|
|
421
421
|
Depuis, ce sont les Districts routiers qui assurent la tenue à jour de ces informations directement dans la base de données.`,
|
|
422
422
|
sourceRecords: [],
|
|
423
|
+
associatedRecords: [
|
|
424
|
+
{
|
|
425
|
+
uuid: 'b1882436-3016-421e-9dfd-0326cca998f2',
|
|
426
|
+
associationType: 'crossReference',
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
uuid: 'b1741571-bbda-4732-a807-cbc36b64d54f',
|
|
430
|
+
associationType: 'crossReference',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
uuid: 'bdcb789c-4b02-4c0c-863a-98dac4ed0240',
|
|
434
|
+
associationType: 'crossReference',
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
uuid: 'c0112b86-a6e3-4df3-9da1-2927376076f4',
|
|
438
|
+
associationType: 'partOfSeamlessDatabase',
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
uuid: '7451e2bd-22e8-4a74-a999-01c58b630369',
|
|
442
|
+
associationType: 'largerWorkCitation',
|
|
443
|
+
},
|
|
444
|
+
],
|
|
423
445
|
otherConstraints: [],
|
|
424
446
|
overviews: [
|
|
425
447
|
{
|
|
@@ -83,6 +83,7 @@ export const SEXTANT_BATHYMETRY_DATASET_RECORD: DatasetRecord = {
|
|
|
83
83
|
Produit interne Ifremer.`,
|
|
84
84
|
lineage: '',
|
|
85
85
|
sourceRecords: [],
|
|
86
|
+
associatedRecords: [],
|
|
86
87
|
ownerOrganization: null,
|
|
87
88
|
recordUpdated: new Date('2020-06-03T22:34:05.000Z'),
|
|
88
89
|
resourceUpdated: new Date('2020-06-03T22:34:05.000Z'),
|
|
@@ -324,6 +325,7 @@ export const SEXTANT_CURRENTS_DATASET_RECORD: CatalogRecord = {
|
|
|
324
325
|
lineage:
|
|
325
326
|
'Sallée, J.B.; Speer, K and Morrow, R. Southern Ocean fronts and their variability to climate modes, Journ. of Climate, 2008, Vol. 21(12), pp. 3020-3039',
|
|
326
327
|
sourceRecords: [],
|
|
328
|
+
associatedRecords: [],
|
|
327
329
|
onlineResources: [
|
|
328
330
|
{
|
|
329
331
|
name: 'Digital Object Identifier (DOI)',
|
|
@@ -69,6 +69,7 @@ export const VLAANDEREN_DATASET_RECORD: DatasetRecord = {
|
|
|
69
69
|
topics: ['biodiversity'],
|
|
70
70
|
lineage: '',
|
|
71
71
|
sourceRecords: [],
|
|
72
|
+
associatedRecords: [],
|
|
72
73
|
recordUpdated: new Date('2024-09-19T01:15:09.732Z'),
|
|
73
74
|
resourceUpdated: new Date('2021-04-14T11:15+02:00'),
|
|
74
75
|
status: 'completed',
|
|
@@ -101,27 +101,68 @@ export const mapContact = (
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export
|
|
104
|
+
export interface KeywordTree {
|
|
105
|
+
default?: string[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolves a keyword's ancestor path within its thesaurus tree, or null for a
|
|
110
|
+
* root-level keyword (no ancestors to show). Tree entries are `^`-joined label
|
|
111
|
+
* paths (default language); they aren't index-aligned with the keywords, so we
|
|
112
|
+
* match on the last segment (not by position/URI), shortest path on poly-hierarchy.
|
|
113
|
+
*/
|
|
114
|
+
export const getKeywordHierarchyPath = (
|
|
115
|
+
keywordDefaultLabel: string,
|
|
116
|
+
tree?: KeywordTree | null
|
|
117
|
+
): string[] | null => {
|
|
118
|
+
if (!keywordDefaultLabel || !tree?.default) return null
|
|
119
|
+
const shortest = tree.default
|
|
120
|
+
.map((entry) => entry.split('^'))
|
|
121
|
+
.filter((path) => path[path.length - 1] === keywordDefaultLabel)
|
|
122
|
+
.reduce(
|
|
123
|
+
(shortest, path) =>
|
|
124
|
+
!shortest || path.length < shortest.length ? path : shortest,
|
|
125
|
+
null
|
|
126
|
+
)
|
|
127
|
+
return shortest?.length > 1 ? shortest : null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const mapKeywords = (
|
|
131
|
+
thesauri: Record<string, Thesaurus>,
|
|
132
|
+
language: string,
|
|
133
|
+
source?: SourceWithUnknownProps
|
|
134
|
+
) => {
|
|
105
135
|
const keywords = []
|
|
106
136
|
for (const thesaurusId in thesauri) {
|
|
107
137
|
const rawThesaurus = thesauri[thesaurusId]
|
|
138
|
+
// thesauri have an `id` (registered) or a `multilingualTitle` (cited);
|
|
139
|
+
// free-keyword groups only have a machine-key `title` like "otherKeywords-theme"
|
|
140
|
+
const { id, multilingualTitle, link = null } = rawThesaurus
|
|
108
141
|
let thesaurus = null
|
|
109
|
-
if (
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
142
|
+
if (id || multilingualTitle) {
|
|
143
|
+
const url = getAsUrl(link)
|
|
144
|
+
const name = multilingualTitle
|
|
145
|
+
? selectTranslatedValue<string>(multilingualTitle, language)
|
|
146
|
+
: rawThesaurus.title
|
|
113
147
|
thesaurus = {
|
|
114
|
-
id
|
|
148
|
+
...(id && { id }),
|
|
115
149
|
...(name && { name }),
|
|
116
150
|
...(url && { url }),
|
|
117
151
|
}
|
|
118
152
|
}
|
|
153
|
+
const tree =
|
|
154
|
+
source && selectField<KeywordTree>(source, `${thesaurusId}_tree`)
|
|
155
|
+
// free-keyword groups have no `theme` field; their type is in the group key
|
|
156
|
+
const typeCode =
|
|
157
|
+
rawThesaurus.theme || thesaurusId.match(/otherKeywords-(\w+)$/)?.[1]
|
|
119
158
|
for (const keyword of rawThesaurus.keywords) {
|
|
159
|
+
const hierarchyPath = getKeywordHierarchyPath(keyword.default, tree)
|
|
120
160
|
keywords.push({
|
|
121
161
|
label: selectTranslatedValue<string>(keyword, language),
|
|
122
|
-
type: getKeywordTypeFromKeywordTypeCode(
|
|
162
|
+
type: getKeywordTypeFromKeywordTypeCode(typeCode),
|
|
123
163
|
...(keyword.link && { key: keyword.link }),
|
|
124
164
|
...(thesaurus && { thesaurus }),
|
|
165
|
+
...(hierarchyPath && { hierarchyPath }),
|
|
125
166
|
})
|
|
126
167
|
}
|
|
127
168
|
}
|
|
@@ -84,7 +84,7 @@ export class Gn4FieldMapper {
|
|
|
84
84
|
'resourceAbstractObject',
|
|
85
85
|
this.getLocalizedIndexKey
|
|
86
86
|
),
|
|
87
|
-
'
|
|
87
|
+
this.translateService.instant('record.metadata.abstract.empty')
|
|
88
88
|
),
|
|
89
89
|
}),
|
|
90
90
|
overview: (output, source) => {
|
|
@@ -240,8 +240,9 @@ export class Gn4FieldMapper {
|
|
|
240
240
|
allKeywords: (output, source) => ({
|
|
241
241
|
...output,
|
|
242
242
|
keywords: mapKeywords(
|
|
243
|
-
selectField<Thesaurus
|
|
244
|
-
this.getLocalizedIndexKey
|
|
243
|
+
selectField<Record<string, Thesaurus>>(source, 'allKeywords'),
|
|
244
|
+
this.getLocalizedIndexKey,
|
|
245
|
+
source
|
|
245
246
|
),
|
|
246
247
|
}),
|
|
247
248
|
inspireTheme: (output, source) => ({
|
|
@@ -3,6 +3,7 @@ import { XmlElement } from '@rgrove/parse-xml'
|
|
|
3
3
|
import { Iso19139Converter } from '../iso19139'
|
|
4
4
|
import { renameElements } from '../xml-utils'
|
|
5
5
|
import {
|
|
6
|
+
readAssociatedRecords,
|
|
6
7
|
readContacts,
|
|
7
8
|
readContactsForResource,
|
|
8
9
|
readDefaultLanguage,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
readUniqueIdentifier,
|
|
21
22
|
} from './read-parts'
|
|
22
23
|
import {
|
|
24
|
+
writeAssociatedRecords,
|
|
23
25
|
writeContacts,
|
|
24
26
|
writeContactsForResource,
|
|
25
27
|
writeDefaultLanguage,
|
|
@@ -56,6 +58,7 @@ export class Iso191153Converter extends Iso19139Converter {
|
|
|
56
58
|
this.readers['landingPage'] = readLandingPage
|
|
57
59
|
this.readers['lineage'] = readLineage
|
|
58
60
|
this.readers['sourceRecords'] = readSourceRecords
|
|
61
|
+
this.readers['associatedRecords'] = readAssociatedRecords
|
|
59
62
|
this.readers['onlineResources'] = readOnlineResources
|
|
60
63
|
this.readers['defaultLanguage'] = readDefaultLanguage
|
|
61
64
|
this.readers['otherLanguages'] = readOtherLanguages
|
|
@@ -76,6 +79,7 @@ export class Iso191153Converter extends Iso19139Converter {
|
|
|
76
79
|
this.writers['landingPage'] = writeLandingPage
|
|
77
80
|
this.writers['lineage'] = writeLineage
|
|
78
81
|
this.writers['sourceRecords'] = writeSourceRecords
|
|
82
|
+
this.writers['associatedRecords'] = writeAssociatedRecords
|
|
79
83
|
this.writers['onlineResources'] = writeOnlineResources
|
|
80
84
|
this.writers['status'] = writeStatus
|
|
81
85
|
this.writers['spatialRepresentation'] = writeSpatialRepresentation
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
pipe,
|
|
19
19
|
} from '../function-utils'
|
|
20
20
|
import {
|
|
21
|
+
extractAssociatedRecords,
|
|
21
22
|
extractCharacterString,
|
|
22
23
|
extractDatasetOnlineResources,
|
|
23
24
|
extractDateTime,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
findIdentification,
|
|
31
32
|
} from '../iso19139/read-parts'
|
|
32
33
|
import {
|
|
34
|
+
AssociatedRecord,
|
|
33
35
|
Individual,
|
|
34
36
|
LanguageCode,
|
|
35
37
|
SourceRecord,
|
|
@@ -299,6 +301,17 @@ export function readSourceRecords(rootEl: XmlElement): SourceRecord[] {
|
|
|
299
301
|
)
|
|
300
302
|
}
|
|
301
303
|
|
|
304
|
+
export function readAssociatedRecords(rootEl: XmlElement): AssociatedRecord[] {
|
|
305
|
+
return pipe(
|
|
306
|
+
findIdentification(),
|
|
307
|
+
extractAssociatedRecords(
|
|
308
|
+
'mri:associatedResource',
|
|
309
|
+
'mri:MD_AssociatedResource',
|
|
310
|
+
pipe(findNestedElement('mri:metadataReference'), readAttribute('uuidref'))
|
|
311
|
+
)
|
|
312
|
+
)(rootEl)
|
|
313
|
+
}
|
|
314
|
+
|
|
302
315
|
function extractDateInfo(
|
|
303
316
|
type: 'creation' | 'revision' | 'publication'
|
|
304
317
|
): ChainableFunction<XmlElement, Date> {
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
DatasetRecord,
|
|
4
4
|
Individual,
|
|
5
5
|
LanguageCode,
|
|
6
|
+
ReuseRecord,
|
|
6
7
|
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
7
8
|
import {
|
|
8
9
|
allChildrenElement,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
appendChildTree,
|
|
11
12
|
createChild,
|
|
12
13
|
createElement,
|
|
14
|
+
createNestedElement,
|
|
13
15
|
findChildElement,
|
|
14
16
|
findChildOrCreate,
|
|
15
17
|
findChildrenElement,
|
|
@@ -566,9 +568,51 @@ export function writeOtherLanguages(record: DatasetRecord, rootEl: XmlElement) {
|
|
|
566
568
|
)(rootEl)
|
|
567
569
|
}
|
|
568
570
|
|
|
569
|
-
export function writeSourceRecords(
|
|
571
|
+
export function writeSourceRecords(
|
|
572
|
+
record: DatasetRecord | ReuseRecord,
|
|
573
|
+
rootEl: XmlElement
|
|
574
|
+
) {
|
|
570
575
|
pipe(
|
|
571
576
|
findNestedChildOrCreate('mdb:resourceLineage', 'mrl:LI_Lineage'),
|
|
572
577
|
appendSourceRecords(record.sourceRecords)
|
|
573
578
|
)(rootEl)
|
|
574
579
|
}
|
|
580
|
+
|
|
581
|
+
export function writeAssociatedRecords(
|
|
582
|
+
record: DatasetRecord | ReuseRecord,
|
|
583
|
+
rootEl: XmlElement
|
|
584
|
+
) {
|
|
585
|
+
pipe(
|
|
586
|
+
findOrCreateIdentification(),
|
|
587
|
+
removeChildrenByName('mri:associatedResource'),
|
|
588
|
+
appendChildren(
|
|
589
|
+
...record.associatedRecords
|
|
590
|
+
.filter((assoc) => assoc.uuid && assoc.associationType)
|
|
591
|
+
.map((assoc) =>
|
|
592
|
+
pipe(
|
|
593
|
+
createNestedElement(
|
|
594
|
+
'mri:associatedResource',
|
|
595
|
+
'mri:MD_AssociatedResource'
|
|
596
|
+
),
|
|
597
|
+
appendChildren(
|
|
598
|
+
pipe(
|
|
599
|
+
createNestedElement(
|
|
600
|
+
'mri:associationType',
|
|
601
|
+
'mri:DS_AssociationTypeCode'
|
|
602
|
+
),
|
|
603
|
+
writeAttribute(
|
|
604
|
+
'codeList',
|
|
605
|
+
'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'
|
|
606
|
+
),
|
|
607
|
+
writeAttribute('codeListValue', assoc.associationType)
|
|
608
|
+
),
|
|
609
|
+
pipe(
|
|
610
|
+
createElement('mri:metadataReference'),
|
|
611
|
+
writeAttribute('uuidref', assoc.uuid)
|
|
612
|
+
)
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
)(rootEl)
|
|
618
|
+
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from '../xml-utils'
|
|
22
22
|
import {
|
|
23
23
|
readAbstract,
|
|
24
|
+
readAssociatedRecords,
|
|
24
25
|
readContacts,
|
|
25
26
|
readContactsForResource,
|
|
26
27
|
readDefaultLanguage,
|
|
@@ -53,6 +54,7 @@ import {
|
|
|
53
54
|
} from './read-parts'
|
|
54
55
|
import {
|
|
55
56
|
writeAbstract,
|
|
57
|
+
writeAssociatedRecords,
|
|
56
58
|
writeContacts,
|
|
57
59
|
writeContactsForResource,
|
|
58
60
|
writeDefaultLanguage,
|
|
@@ -115,6 +117,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
115
117
|
overviews: readOverviews,
|
|
116
118
|
lineage: readLineage,
|
|
117
119
|
sourceRecords: readSourceRecords,
|
|
120
|
+
associatedRecords: readAssociatedRecords,
|
|
118
121
|
onlineResources: readOnlineResources,
|
|
119
122
|
temporalExtents: readTemporalExtents,
|
|
120
123
|
spatialExtents: readSpatialExtents,
|
|
@@ -157,6 +160,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
157
160
|
overviews: writeGraphicOverviews,
|
|
158
161
|
lineage: writeLineage,
|
|
159
162
|
sourceRecords: writeSourceRecords,
|
|
163
|
+
associatedRecords: writeAssociatedRecords,
|
|
160
164
|
onlineResources: writeOnlineResources,
|
|
161
165
|
temporalExtents: writeTemporalExtents,
|
|
162
166
|
spatialExtents: writeSpatialExtents,
|
|
@@ -205,7 +209,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
205
209
|
record.contacts.map((c) => fixLanguages(c.organization))
|
|
206
210
|
record.contactsForResource.map((c) => fixLanguages(c.organization))
|
|
207
211
|
fixLanguages(record.ownerOrganization)
|
|
208
|
-
if (record.kind === 'dataset') {
|
|
212
|
+
if (record.kind === 'dataset' || record.kind === 'reuse') {
|
|
209
213
|
record.spatialExtents.map(fixLanguages)
|
|
210
214
|
}
|
|
211
215
|
|
|
@@ -300,6 +304,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
300
304
|
const temporalExtents = this.readers['temporalExtents'](rootEl, tr)
|
|
301
305
|
const lineage = this.readers['lineage'](rootEl, tr)
|
|
302
306
|
const sourceRecords = this.readers['sourceRecords'](rootEl, tr)
|
|
307
|
+
const associatedRecords = this.readers['associatedRecords'](rootEl, tr)
|
|
303
308
|
const updateFrequency = this.readers['updateFrequency'](rootEl, tr)
|
|
304
309
|
|
|
305
310
|
return this.afterRecordRead({
|
|
@@ -308,6 +313,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
308
313
|
status,
|
|
309
314
|
lineage,
|
|
310
315
|
...(sourceRecords && { sourceRecords }),
|
|
316
|
+
associatedRecords,
|
|
311
317
|
...(spatialRepresentation && { spatialRepresentation }),
|
|
312
318
|
temporalExtents,
|
|
313
319
|
updateFrequency,
|
|
@@ -316,6 +322,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
316
322
|
} else if (kind === 'reuse') {
|
|
317
323
|
const lineage = this.readers['lineage'](rootEl, tr)
|
|
318
324
|
const sourceRecords = this.readers['sourceRecords'](rootEl, tr)
|
|
325
|
+
const associatedRecords = this.readers['associatedRecords'](rootEl, tr)
|
|
319
326
|
const temporalExtents = this.readers['temporalExtents'](rootEl, tr)
|
|
320
327
|
const reuseType = this.readers['reuseType'](rootEl, tr)
|
|
321
328
|
|
|
@@ -324,6 +331,7 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
324
331
|
kind,
|
|
325
332
|
lineage,
|
|
326
333
|
...(sourceRecords && { sourceRecords }),
|
|
334
|
+
associatedRecords,
|
|
327
335
|
temporalExtents,
|
|
328
336
|
reuseType,
|
|
329
337
|
} as ReuseRecord)
|
|
@@ -408,6 +416,8 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
408
416
|
|
|
409
417
|
if (record.kind === 'dataset') {
|
|
410
418
|
fieldChanged('status') && this.writers['status'](record, rootEl)
|
|
419
|
+
}
|
|
420
|
+
if (record.kind === 'dataset' || record.kind === 'reuse') {
|
|
411
421
|
fieldChanged('updateFrequency') &&
|
|
412
422
|
this.writers['updateFrequency'](record, rootEl)
|
|
413
423
|
fieldChanged('spatialRepresentation') &&
|
|
@@ -421,6 +431,8 @@ export class Iso19139Converter extends BaseConverter<string> {
|
|
|
421
431
|
this.writers['lineage'](record, rootEl)
|
|
422
432
|
fieldChanged('sourceRecords') &&
|
|
423
433
|
this.writers['sourceRecords'](record, rootEl)
|
|
434
|
+
fieldChanged('associatedRecords') &&
|
|
435
|
+
this.writers['associatedRecords'](record, rootEl)
|
|
424
436
|
}
|
|
425
437
|
|
|
426
438
|
fieldChanged('otherLanguages') &&
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AssociatedRecord,
|
|
2
3
|
Constraint,
|
|
3
4
|
ConstraintTranslations,
|
|
4
5
|
DatasetOnlineResource,
|
|
@@ -927,6 +928,45 @@ export function readSourceRecords(rootEl: XmlElement): SourceRecord[] {
|
|
|
927
928
|
)
|
|
928
929
|
}
|
|
929
930
|
|
|
931
|
+
export function extractAssociatedRecords(
|
|
932
|
+
containerName: string,
|
|
933
|
+
aggregateName: string,
|
|
934
|
+
readUuid: ChainableFunction<XmlElement, string>
|
|
935
|
+
): ChainableFunction<XmlElement, AssociatedRecord[]> {
|
|
936
|
+
return pipe(
|
|
937
|
+
findChildrenElement(containerName, false),
|
|
938
|
+
mapArray((el) => {
|
|
939
|
+
const aggregateEl = findChildElement(aggregateName, false)(el)
|
|
940
|
+
const uuid = readUuid(aggregateEl)
|
|
941
|
+
const associationType = pipe(
|
|
942
|
+
findNestedElement('gmd:associationType', 'gmd:DS_AssociationTypeCode'),
|
|
943
|
+
readAttribute('codeListValue')
|
|
944
|
+
)(aggregateEl)
|
|
945
|
+
if (!uuid || !associationType) return null
|
|
946
|
+
return { uuid, associationType }
|
|
947
|
+
}),
|
|
948
|
+
filterArray((r): r is AssociatedRecord => r !== null)
|
|
949
|
+
)
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
export function readAssociatedRecords(rootEl: XmlElement): AssociatedRecord[] {
|
|
953
|
+
return pipe(
|
|
954
|
+
findIdentification(),
|
|
955
|
+
extractAssociatedRecords(
|
|
956
|
+
'gmd:aggregationInfo',
|
|
957
|
+
'gmd:MD_AggregateInformation',
|
|
958
|
+
pipe(
|
|
959
|
+
findNestedElement(
|
|
960
|
+
'gmd:aggregateDataSetIdentifier',
|
|
961
|
+
'gmd:MD_Identifier',
|
|
962
|
+
'gmd:code'
|
|
963
|
+
),
|
|
964
|
+
extractCharacterString()
|
|
965
|
+
)
|
|
966
|
+
)
|
|
967
|
+
)(rootEl)
|
|
968
|
+
}
|
|
969
|
+
|
|
930
970
|
export function readUpdateFrequency(rootEl: XmlElement): UpdateFrequency {
|
|
931
971
|
return pipe(
|
|
932
972
|
findIdentification(),
|
|
@@ -1252,7 +1252,10 @@ export function appendSourceRecords(
|
|
|
1252
1252
|
)
|
|
1253
1253
|
}
|
|
1254
1254
|
|
|
1255
|
-
export function writeSourceRecords(
|
|
1255
|
+
export function writeSourceRecords(
|
|
1256
|
+
record: DatasetRecord | ReuseRecord,
|
|
1257
|
+
rootEl: XmlElement
|
|
1258
|
+
) {
|
|
1256
1259
|
pipe(
|
|
1257
1260
|
findNestedChildOrCreate(
|
|
1258
1261
|
'gmd:dataQualityInfo',
|
|
@@ -1264,6 +1267,49 @@ export function writeSourceRecords(record: DatasetRecord, rootEl: XmlElement) {
|
|
|
1264
1267
|
)(rootEl)
|
|
1265
1268
|
}
|
|
1266
1269
|
|
|
1270
|
+
export function writeAssociatedRecords(
|
|
1271
|
+
record: DatasetRecord | ReuseRecord,
|
|
1272
|
+
rootEl: XmlElement
|
|
1273
|
+
) {
|
|
1274
|
+
pipe(
|
|
1275
|
+
findOrCreateIdentification(),
|
|
1276
|
+
removeChildrenByName('gmd:aggregationInfo'),
|
|
1277
|
+
appendChildren(
|
|
1278
|
+
...record.associatedRecords
|
|
1279
|
+
.filter((assoc) => assoc.uuid && assoc.associationType)
|
|
1280
|
+
.map((assoc) =>
|
|
1281
|
+
pipe(
|
|
1282
|
+
createNestedElement(
|
|
1283
|
+
'gmd:aggregationInfo',
|
|
1284
|
+
'gmd:MD_AggregateInformation'
|
|
1285
|
+
),
|
|
1286
|
+
appendChildren(
|
|
1287
|
+
pipe(
|
|
1288
|
+
createNestedElement(
|
|
1289
|
+
'gmd:aggregateDataSetIdentifier',
|
|
1290
|
+
'gmd:MD_Identifier',
|
|
1291
|
+
'gmd:code'
|
|
1292
|
+
),
|
|
1293
|
+
writeCharacterString(assoc.uuid)
|
|
1294
|
+
),
|
|
1295
|
+
pipe(
|
|
1296
|
+
createNestedElement(
|
|
1297
|
+
'gmd:associationType',
|
|
1298
|
+
'gmd:DS_AssociationTypeCode'
|
|
1299
|
+
),
|
|
1300
|
+
writeAttribute(
|
|
1301
|
+
'codeList',
|
|
1302
|
+
'http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#DS_AssociationTypeCode'
|
|
1303
|
+
),
|
|
1304
|
+
writeAttribute('codeListValue', assoc.associationType)
|
|
1305
|
+
)
|
|
1306
|
+
)
|
|
1307
|
+
)
|
|
1308
|
+
)
|
|
1309
|
+
)
|
|
1310
|
+
)(rootEl)
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1267
1313
|
export function getServiceEndpointProtocol(endpoint: ServiceEndpoint): string {
|
|
1268
1314
|
switch (endpoint.accessServiceProtocol.toLowerCase()) {
|
|
1269
1315
|
case 'wfs':
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
HttpErrorResponse,
|
|
4
4
|
HttpHeaders,
|
|
5
5
|
} from '@angular/common/http'
|
|
6
|
-
import { Injectable, InjectionToken
|
|
6
|
+
import { inject, Injectable, InjectionToken } from '@angular/core'
|
|
7
7
|
import {
|
|
8
8
|
assertValidXml,
|
|
9
9
|
BaseConverter,
|
|
@@ -327,8 +327,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
327
327
|
return this.settingsService.allowEditHarvested$.pipe(
|
|
328
328
|
map((allowEditHarvested) => {
|
|
329
329
|
return (
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
(this.platformService.supportsAuthentication() &&
|
|
331
|
+
record.extras?.['edit'] &&
|
|
332
|
+
(!record.extras?.['isHarvested'] || allowEditHarvested)) ??
|
|
333
|
+
false
|
|
332
334
|
)
|
|
333
335
|
})
|
|
334
336
|
)
|
|
@@ -336,10 +338,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
336
338
|
|
|
337
339
|
private canEdit(record: CatalogRecord, allowEditHarvested: boolean): boolean {
|
|
338
340
|
return (
|
|
339
|
-
this.platformService.supportsAuthentication() &&
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
341
|
+
(this.platformService.supportsAuthentication() &&
|
|
342
|
+
record.extras?.['edit'] &&
|
|
343
|
+
(!record.extras?.['isHarvested'] || allowEditHarvested)) ??
|
|
344
|
+
false
|
|
343
345
|
)
|
|
344
346
|
}
|
|
345
347
|
|
|
@@ -361,8 +363,10 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
openRecordForEdition(
|
|
364
|
-
uniqueIdentifier: string
|
|
366
|
+
uniqueIdentifier: string,
|
|
367
|
+
disableDraft?: boolean
|
|
365
368
|
): Observable<[CatalogRecord, string, boolean] | null> {
|
|
369
|
+
this.disableDraft = disableDraft ?? this.disableDraft
|
|
366
370
|
const draft$ = this.disableDraft
|
|
367
371
|
? of(null)
|
|
368
372
|
: of(this.getRecordFromLocalStorage(uniqueIdentifier))
|
|
@@ -177,26 +177,15 @@ export class Gn4PlatformService implements PlatformServiceInterface {
|
|
|
177
177
|
const editorIds = meResponse.groupsWithEditor ?? []
|
|
178
178
|
const memberIds = meResponse.groupsWithRegisteredUser ?? []
|
|
179
179
|
const adminIds = meResponse.groupsWithUserAdmin ?? []
|
|
180
|
-
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
.map((id) => {
|
|
190
|
-
const group = groupsById.get(id)
|
|
191
|
-
return {
|
|
192
|
-
groupId: group.id,
|
|
193
|
-
groupName: group.name,
|
|
194
|
-
isMember: memberIds.includes(id),
|
|
195
|
-
canEdit: editorIds.includes(id),
|
|
196
|
-
canApprove: reviewerIds.includes(id),
|
|
197
|
-
canAdministrate: adminIds.includes(id),
|
|
198
|
-
}
|
|
199
|
-
})
|
|
180
|
+
|
|
181
|
+
return groups.map((group) => ({
|
|
182
|
+
groupId: group.id,
|
|
183
|
+
groupName: group.name,
|
|
184
|
+
isMember: memberIds.includes(group.id),
|
|
185
|
+
canEdit: editorIds.includes(group.id),
|
|
186
|
+
canApprove: reviewerIds.includes(group.id),
|
|
187
|
+
canAdministrate: adminIds.includes(group.id),
|
|
188
|
+
}))
|
|
200
189
|
})
|
|
201
190
|
)
|
|
202
191
|
}
|
|
@@ -104,6 +104,8 @@ export interface Keyword {
|
|
|
104
104
|
type: KeywordType
|
|
105
105
|
thesaurus?: ThesaurusModel
|
|
106
106
|
bbox?: [number, number, number, number]
|
|
107
|
+
// thesaurus hierarchy path incl. the keyword as last element; unset for root-level keywords
|
|
108
|
+
hierarchyPath?: string[]
|
|
107
109
|
|
|
108
110
|
translations?: KeywordTranslations
|
|
109
111
|
}
|
|
@@ -258,11 +260,20 @@ export interface SourceRecord {
|
|
|
258
260
|
href?: string
|
|
259
261
|
}
|
|
260
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Represents another record associated with this one (e.g. a parent/sibling dataset).
|
|
265
|
+
*/
|
|
266
|
+
export interface AssociatedRecord {
|
|
267
|
+
uuid: string
|
|
268
|
+
associationType: string
|
|
269
|
+
}
|
|
270
|
+
|
|
261
271
|
export interface DatasetRecord extends BaseRecord {
|
|
262
272
|
kind: 'dataset'
|
|
263
273
|
status: RecordStatus
|
|
264
274
|
lineage: string // Explanation of the origin of this record (e.g: how, why)"
|
|
265
275
|
sourceRecords: Array<SourceRecord>
|
|
276
|
+
associatedRecords: Array<AssociatedRecord>
|
|
266
277
|
onlineResources: Array<DatasetOnlineResource>
|
|
267
278
|
spatialExtents: Array<DatasetSpatialExtent>
|
|
268
279
|
temporalExtents: Array<DatasetTemporalExtent>
|
|
@@ -291,6 +302,7 @@ export interface ReuseRecord extends BaseRecord {
|
|
|
291
302
|
kind: 'reuse'
|
|
292
303
|
lineage: string // Explanation of the origin of this record (e.g: how, why)"
|
|
293
304
|
sourceRecords: Array<SourceRecord>
|
|
305
|
+
associatedRecords: Array<AssociatedRecord>
|
|
294
306
|
onlineResources: Array<DatasetOnlineResource>
|
|
295
307
|
reuseType: ReuseType
|
|
296
308
|
spatialExtents: Array<DatasetSpatialExtent>
|
|
@@ -39,7 +39,8 @@ export abstract class RecordsRepositoryInterface {
|
|
|
39
39
|
* @returns Observable<[CatalogRecord, string, boolean] | null>
|
|
40
40
|
*/
|
|
41
41
|
abstract openRecordForEdition(
|
|
42
|
-
uniqueIdentifier: string
|
|
42
|
+
uniqueIdentifier: string,
|
|
43
|
+
disableDraft?: boolean
|
|
43
44
|
): Observable<[CatalogRecord, string, boolean] | null>
|
|
44
45
|
|
|
45
46
|
/**
|