geonetwork-ui 2.6.0-dev.9d3ad45e2 → 2.6.0-dev.a0bd52a21

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.
Files changed (183) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +39 -4
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +8 -4
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +5 -2
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +3 -3
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +2 -2
  7. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/constant.mjs +2 -1
  8. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +3 -3
  9. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +75 -15
  10. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +7 -1
  11. package/esm2022/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.mjs +2 -1
  12. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  13. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  14. package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +266 -11
  15. package/esm2022/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-from-catalog.component.mjs +1 -1
  16. package/esm2022/libs/feature/record/src/lib/state/mdview.actions.mjs +3 -1
  17. package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +7 -1
  18. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +3 -1
  19. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +7 -1
  20. package/esm2022/libs/feature/record/src/lib/state/mdview.selectors.mjs +3 -1
  21. package/esm2022/libs/feature/search/src/lib/constants.mjs +3 -2
  22. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +5 -3
  23. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +13 -10
  24. package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +19 -34
  25. package/esm2022/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.mjs +59 -0
  26. package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +35 -10
  27. package/esm2022/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.mjs +5 -1
  28. package/esm2022/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.mjs +50 -29
  29. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +7 -3
  30. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +3 -3
  31. package/esm2022/libs/ui/layout/src/index.mjs +2 -1
  32. package/esm2022/libs/ui/layout/src/lib/cell-popin/cell-popin.component.mjs +110 -0
  33. package/esm2022/libs/ui/layout/src/lib/interactive-table/interactive-table.component.mjs +20 -10
  34. package/esm2022/libs/ui/layout/src/lib/truncated-text/truncated-text.component.mjs +15 -49
  35. package/esm2022/libs/ui/layout/src/lib/ui-layout.module.mjs +2 -2
  36. package/esm2022/libs/ui/search/src/index.mjs +2 -1
  37. package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +21 -12
  38. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +39 -18
  39. package/esm2022/libs/ui/search/src/lib/ui-search.module.mjs +10 -4
  40. package/esm2022/libs/util/i18n/src/lib/i18n.constants.mjs +42 -1
  41. package/esm2022/libs/util/i18n/src/lib/language-codes.mjs +24 -2
  42. package/esm2022/translations/de.json +41 -6
  43. package/esm2022/translations/en.json +41 -6
  44. package/esm2022/translations/es.json +40 -5
  45. package/esm2022/translations/fr.json +41 -6
  46. package/esm2022/translations/it.json +40 -5
  47. package/esm2022/translations/nl.json +40 -5
  48. package/esm2022/translations/pt.json +40 -5
  49. package/fesm2022/geonetwork-ui.mjs +1591 -719
  50. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  51. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  52. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +0 -1
  53. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
  54. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts +1 -0
  55. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts.map +1 -1
  56. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts.map +1 -1
  57. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  58. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  59. package/libs/api/repository/src/lib/gn4/elasticsearch/constant.d.ts.map +1 -1
  60. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts +1 -1
  61. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  62. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +13 -2
  63. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  64. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +2 -0
  65. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  66. package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts +1 -0
  67. package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts.map +1 -1
  68. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +20 -17
  69. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  70. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +6 -0
  71. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  72. package/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.d.ts +48 -3
  73. package/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.d.ts.map +1 -1
  74. package/libs/feature/record/src/lib/state/mdview.actions.d.ts +10 -0
  75. package/libs/feature/record/src/lib/state/mdview.actions.d.ts.map +1 -1
  76. package/libs/feature/record/src/lib/state/mdview.effects.d.ts +6 -0
  77. package/libs/feature/record/src/lib/state/mdview.effects.d.ts.map +1 -1
  78. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +2 -0
  79. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  80. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts +2 -0
  81. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts.map +1 -1
  82. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts +2 -0
  83. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts.map +1 -1
  84. package/libs/feature/search/src/lib/constants.d.ts.map +1 -1
  85. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts +2 -1
  86. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
  87. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +6 -5
  88. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
  89. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts +3 -6
  90. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -1
  91. package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts +14 -0
  92. package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts.map +1 -0
  93. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts +3 -0
  94. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
  95. package/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.d.ts.map +1 -1
  96. package/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.d.ts +20 -9
  97. package/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.d.ts.map +1 -1
  98. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +2 -1
  99. package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
  100. package/libs/ui/layout/src/index.d.ts +1 -0
  101. package/libs/ui/layout/src/index.d.ts.map +1 -1
  102. package/libs/ui/layout/src/lib/cell-popin/cell-popin.component.d.ts +28 -0
  103. package/libs/ui/layout/src/lib/cell-popin/cell-popin.component.d.ts.map +1 -0
  104. package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts +4 -2
  105. package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts.map +1 -1
  106. package/libs/ui/layout/src/lib/truncated-text/truncated-text.component.d.ts +5 -10
  107. package/libs/ui/layout/src/lib/truncated-text/truncated-text.component.d.ts.map +1 -1
  108. package/libs/ui/search/src/index.d.ts +1 -0
  109. package/libs/ui/search/src/index.d.ts.map +1 -1
  110. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +4 -3
  111. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
  112. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +10 -4
  113. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  114. package/libs/ui/search/src/lib/ui-search.module.d.ts +2 -1
  115. package/libs/ui/search/src/lib/ui-search.module.d.ts.map +1 -1
  116. package/libs/util/i18n/src/lib/i18n.constants.d.ts +1 -0
  117. package/libs/util/i18n/src/lib/i18n.constants.d.ts.map +1 -1
  118. package/libs/util/i18n/src/lib/language-codes.d.ts +23 -1
  119. package/libs/util/i18n/src/lib/language-codes.d.ts.map +1 -1
  120. package/package.json +1 -1
  121. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -1
  122. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +61 -4
  123. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +0 -1
  124. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +13 -3
  125. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +5 -1
  126. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +6 -3
  127. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +4 -1
  128. package/src/libs/api/repository/src/lib/gn4/elasticsearch/constant.ts +1 -0
  129. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  130. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +111 -15
  131. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
  132. package/src/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.ts +3 -0
  133. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +20 -14
  134. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +6 -0
  135. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +63 -0
  136. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +117 -11
  137. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.ts +316 -6
  138. package/src/libs/feature/record/src/lib/state/mdview.actions.ts +10 -0
  139. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +22 -0
  140. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +4 -0
  141. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +12 -0
  142. package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +9 -0
  143. package/src/libs/feature/search/src/lib/constants.ts +2 -1
  144. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +1 -1
  145. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +1 -0
  146. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +1 -0
  147. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +13 -3
  148. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +7 -75
  149. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +20 -51
  150. package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.html +69 -0
  151. package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.ts +61 -0
  152. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +48 -9
  153. package/src/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.ts +4 -0
  154. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +96 -37
  155. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.ts +60 -29
  156. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +2 -0
  157. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +1 -1
  158. package/src/libs/ui/layout/src/index.ts +1 -0
  159. package/src/libs/ui/layout/src/lib/cell-popin/cell-popin.component.html +40 -0
  160. package/src/libs/ui/layout/src/lib/cell-popin/cell-popin.component.ts +141 -0
  161. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +3 -2
  162. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +13 -6
  163. package/src/libs/ui/layout/src/lib/truncated-text/truncated-text.component.html +25 -42
  164. package/src/libs/ui/layout/src/lib/truncated-text/truncated-text.component.ts +10 -49
  165. package/src/libs/ui/layout/src/lib/ui-layout.module.ts +1 -1
  166. package/src/libs/ui/search/src/index.ts +1 -0
  167. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +16 -6
  168. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +15 -11
  169. package/src/libs/ui/search/src/lib/results-table/results-table.component.css +4 -0
  170. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +31 -27
  171. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +33 -15
  172. package/src/libs/ui/search/src/lib/ui-search.module.ts +3 -0
  173. package/src/libs/util/i18n/src/lib/i18n.constants.ts +42 -0
  174. package/src/libs/util/i18n/src/lib/language-codes.ts +23 -1
  175. package/tailwind.base.css +1 -1
  176. package/translations/de.json +41 -6
  177. package/translations/en.json +41 -6
  178. package/translations/es.json +40 -5
  179. package/translations/fr.json +41 -6
  180. package/translations/it.json +40 -5
  181. package/translations/nl.json +40 -5
  182. package/translations/pt.json +40 -5
  183. package/translations/sk.json +40 -5
@@ -152,12 +152,22 @@ export class Gn4FieldMapper {
152
152
  )
153
153
  const languages = langList.map((lang) => LANG_3_TO_2_MAPPER[lang])
154
154
  const defaultLanguage = output.defaultLanguage ?? languages[0] ?? null // set the first language as main one as fallback
155
+
156
+ return {
157
+ ...output,
158
+ defaultLanguage,
159
+ }
160
+ },
161
+ otherLanguage: (output, source) => {
162
+ const langList = getAsArray(selectField<string>(source, 'otherLanguage'))
163
+ const languages = langList.map((lang) => LANG_3_TO_2_MAPPER[lang])
164
+ const defaultLanguage = output.defaultLanguage ?? languages[0] ?? null
155
165
  const otherLanguages = languages.filter(
156
166
  (lang) => lang !== defaultLanguage
157
167
  )
168
+
158
169
  return {
159
170
  ...output,
160
- defaultLanguage,
161
171
  otherLanguages,
162
172
  }
163
173
  },
@@ -294,12 +304,52 @@ export class Gn4FieldMapper {
294
304
  ) ?? {},
295
305
  '_source'
296
306
  )
297
- const featureCatalogIdentifier = selectField(
307
+ const featureCatalogIdentifier: string = selectField(
298
308
  <SourceWithUnknownProps>fcatSource,
299
309
  'uuid'
300
310
  )
301
- return featureCatalogIdentifier
302
- ? this.addExtra({ featureCatalogIdentifier }, output)
311
+ const sourceOfLinks = getAsArray(
312
+ selectField(
313
+ <SourceWithUnknownProps>selectField(source, 'related'),
314
+ 'hassources'
315
+ )
316
+ )
317
+ const sourceOfIdentifiers: string[] = sourceOfLinks
318
+ .filter((link) => link['origin'] === 'catalog')
319
+ .map((link) => {
320
+ return selectField(
321
+ selectField(<SourceWithUnknownProps>link, '_source'),
322
+ 'uuid'
323
+ )
324
+ })
325
+ const extraValues: Record<string, string | string[]> = {}
326
+ if (featureCatalogIdentifier) {
327
+ extraValues.featureCatalogIdentifier = featureCatalogIdentifier
328
+ }
329
+ if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
330
+ extraValues.sourceOfIdentifiers = sourceOfIdentifiers
331
+ }
332
+ return Object.keys(extraValues).length > 0
333
+ ? this.addExtra(extraValues, output)
334
+ : output
335
+ },
336
+ recordLink: (output, source) => {
337
+ const recordLinks = getAsArray(
338
+ selectField<SourceWithUnknownProps[]>(source, 'recordLink')
339
+ )
340
+ const sourcesIdentifiers: string[] = recordLinks
341
+ .filter(
342
+ (link) => link['origin'] === 'catalog' && link['type'] === 'sources'
343
+ )
344
+ .map((link) => selectField(<SourceWithUnknownProps>link, 'to'))
345
+
346
+ return sourcesIdentifiers && sourcesIdentifiers.length > 0
347
+ ? this.addExtra(
348
+ {
349
+ sourcesIdentifiers,
350
+ },
351
+ output
352
+ )
303
353
  : output
304
354
  },
305
355
  isPublishedToAll: (output, source) =>
@@ -309,6 +359,13 @@ export class Gn4FieldMapper {
309
359
  },
310
360
  output
311
361
  ),
362
+ isHarvested: (output, source) =>
363
+ this.addExtra(
364
+ {
365
+ isHarvested: selectField(source, 'isHarvested') !== 'false',
366
+ },
367
+ output
368
+ ),
312
369
  edit: (output, source) =>
313
370
  this.addExtra(
314
371
  {
@@ -164,7 +164,6 @@ export type MetadataObject = Partial<{
164
164
  resourceDate: ResourceDate[]
165
165
  resourceEdition: string
166
166
  resourceIdentifier: ResourceIdentifier[]
167
- resourceLanguage: string[]
168
167
  resourceTemporalDateRange: ResourceTemporalDateRange[]
169
168
  resourceTemporalExtentDateRange: ResourceTemporalDateRange[]
170
169
  resourceTitleObject: MultilingualField
@@ -363,11 +363,18 @@ export function readOnlineResources(rootEl: XmlElement): OnlineResource[] {
363
363
  )(rootEl)
364
364
  }
365
365
 
366
- function readLocaleElement(): ChainableFunction<XmlElement, LanguageCode> {
366
+ export function readLocaleElement(): ChainableFunction<
367
+ XmlElement,
368
+ LanguageCode
369
+ > {
367
370
  return pipe(
368
371
  findChildElement('lan:LanguageCode'),
369
372
  readAttribute('codeListValue'),
370
- map((lang) => (lang ? LANG_3_TO_2_MAPPER[lang.toLowerCase()] : null))
373
+ map((lang) => {
374
+ const normalized = lang?.toLowerCase()
375
+ const iso2Lang = LANG_3_TO_2_MAPPER[normalized]
376
+ return iso2Lang ?? lang
377
+ })
371
378
  )
372
379
  }
373
380
 
@@ -381,6 +388,9 @@ export function readDefaultLanguage(rootEl: XmlElement): LanguageCode {
381
388
  export function readOtherLanguages(rootEl: XmlElement): LanguageCode[] {
382
389
  return pipe(
383
390
  findChildrenElement('mdb:otherLocale', false),
384
- mapArray(readLocaleElement())
391
+ mapArray(readLocaleElement()),
392
+ map((languages) =>
393
+ languages.filter((lang): lang is LanguageCode => lang !== null)
394
+ )
385
395
  )(rootEl)
386
396
  }
@@ -529,7 +529,11 @@ export function writeOnlineResources(
529
529
  }
530
530
 
531
531
  function writeLocaleElement(language: LanguageCode) {
532
- const lang3 = LANG_2_TO_3_MAPPER[language.toLowerCase()]
532
+ const normalizedLang = language.toLowerCase()
533
+ const lang3 =
534
+ normalizedLang.length === 2
535
+ ? LANG_2_TO_3_MAPPER[normalizedLang]
536
+ : normalizedLang
533
537
  return pipe(
534
538
  findChildOrCreate('lan:PT_Locale'),
535
539
  writeAttribute('id', language.toUpperCase()),
@@ -1162,11 +1162,14 @@ export function readOtherLanguages(rootEl: XmlElement): LanguageCode[] {
1162
1162
  findChildrenElement('gmd:locale', false),
1163
1163
  mapArray(
1164
1164
  pipe(
1165
- findChildElement('gmd:LanguageCode'),
1165
+ findChildElement('lan:LanguageCode'),
1166
1166
  readAttribute('codeListValue'),
1167
- map((lang) => LANG_3_TO_2_MAPPER[lang.toLowerCase()])
1167
+ map((lang) => LANG_3_TO_2_MAPPER[lang.toLowerCase()] ?? lang)
1168
1168
  )
1169
1169
  ),
1170
+ map((languages) =>
1171
+ languages.filter((lang): lang is LanguageCode => lang !== null)
1172
+ ),
1170
1173
  map((languages) => (languages.length ? languages : [defaultLanguage]))
1171
1174
  )(rootEl)
1172
1175
  }
@@ -1174,7 +1177,7 @@ export function readOtherLanguages(rootEl: XmlElement): LanguageCode[] {
1174
1177
  export function readDefaultLanguage(rootEl: XmlElement): LanguageCode {
1175
1178
  return pipe(
1176
1179
  findChildElement('gmd:language', false),
1177
- findChildElement('gmd:LanguageCode'),
1180
+ findChildElement('lan:LanguageCode'),
1178
1181
  readAttribute('codeListValue'),
1179
1182
  map((lang) => (lang ? LANG_3_TO_2_MAPPER[lang.toLowerCase()] : null))
1180
1183
  )(rootEl)
@@ -1471,7 +1471,10 @@ export function writeLanguages(record: DatasetRecord, rootEl: XmlElement) {
1471
1471
  writeAttribute('id', lang.toUpperCase()),
1472
1472
  createNestedChild('gmd:languageCode', 'gmd:LanguageCode'),
1473
1473
  writeAttribute('codeList', 'http://www.loc.gov/standards/iso639-2/'),
1474
- writeAttribute('codeListValue', LANG_2_TO_3_MAPPER[lang])
1474
+ writeAttribute(
1475
+ 'codeListValue',
1476
+ lang.length === 2 ? LANG_2_TO_3_MAPPER[lang] : lang
1477
+ )
1475
1478
  )
1476
1479
 
1477
1480
  // add new languages (only if other than default one)
@@ -19,6 +19,7 @@ export const ES_SOURCE_SUMMARY = [
19
19
  'cl_maintenanceAndUpdateFrequency',
20
20
  'tag',
21
21
  'MD_LegalConstraintsUseLimitationObject',
22
+ 'MD_LegalConstraintsOtherConstraintsObject',
22
23
  'qualityScore',
23
24
  ]
24
25
 
@@ -124,11 +124,11 @@ export class ElasticsearchService {
124
124
  this.runtimeFields[fieldName] = expression
125
125
  }
126
126
 
127
- getMetadataByIdPayload(uuid: string): EsSearchParams {
127
+ getMetadataByIdsPayload(uuids: string[]): EsSearchParams {
128
128
  return {
129
129
  query: {
130
130
  ids: {
131
- values: [uuid],
131
+ values: uuids,
132
132
  },
133
133
  },
134
134
  }
@@ -14,8 +14,8 @@ import {
14
14
  import { PublicationVersionError } from '../../../../../../libs/common/domain/src/lib/model/error'
15
15
  import {
16
16
  CatalogRecord,
17
- DatasetFeatureType,
18
17
  DatasetFeatureCatalog,
18
+ DatasetFeatureType,
19
19
  } from '../../../../../../libs/common/domain/src/lib/model/record'
20
20
  import {
21
21
  Aggregations,
@@ -29,10 +29,11 @@ import {
29
29
  import { PlatformServiceInterface } from '../../../../../../libs/common/domain/src/lib/platform.service.interface'
30
30
  import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
31
31
  import {
32
+ LanguagesApiService,
32
33
  RecordsApiService,
33
34
  SearchApiService,
34
- FeatureResponseApiModel,
35
35
  } from '../../../../../../libs/data-access/gn4/src'
36
+ import { LANG_3_TO_2_MAPPER } from '../../../../../../libs/util/i18n/src'
36
37
  import {
37
38
  combineLatest,
38
39
  exhaustMap,
@@ -47,6 +48,7 @@ import {
47
48
  import { catchError, map, tap } from 'rxjs/operators'
48
49
  import { lt } from 'semver'
49
50
  import { ElasticsearchService } from './elasticsearch'
51
+ import { Gn4SettingsService } from './settings/gn4-settings.service'
50
52
 
51
53
  const minPublicationApiVersion = '4.2.5'
52
54
 
@@ -65,7 +67,9 @@ export class Gn4Repository implements RecordsRepositoryInterface {
65
67
  private gn4SearchHelper: ElasticsearchService,
66
68
  private gn4Mapper: Gn4Converter,
67
69
  private gn4RecordsApi: RecordsApiService,
68
- private platformService: PlatformServiceInterface
70
+ private platformService: PlatformServiceInterface,
71
+ private gn4LanguagesApi: LanguagesApiService,
72
+ private settingsService: Gn4SettingsService
69
73
  ) {}
70
74
 
71
75
  search({
@@ -129,9 +133,9 @@ export class Gn4Repository implements RecordsRepositoryInterface {
129
133
  return this.gn4SearchApi
130
134
  .search(
131
135
  'bucket',
132
- ['fcats'],
136
+ ['fcats', 'hassources'],
133
137
  JSON.stringify(
134
- this.gn4SearchHelper.getMetadataByIdPayload(uniqueIdentifier)
138
+ this.gn4SearchHelper.getMetadataByIdsPayload([uniqueIdentifier])
135
139
  )
136
140
  )
137
141
  .pipe(
@@ -142,6 +146,27 @@ export class Gn4Repository implements RecordsRepositoryInterface {
142
146
  )
143
147
  }
144
148
 
149
+ getMultipleRecords(
150
+ uniqueIdentifiers: string[]
151
+ ): Observable<CatalogRecord[] | null> {
152
+ return this.gn4SearchApi
153
+ .search(
154
+ 'bucket',
155
+ undefined,
156
+ JSON.stringify(
157
+ this.gn4SearchHelper.getMetadataByIdsPayload(uniqueIdentifiers)
158
+ )
159
+ )
160
+ .pipe(
161
+ map((results: Gn4SearchResults) => results.hits.hits),
162
+ switchMap((records) =>
163
+ records && records.length > 0
164
+ ? this.gn4Mapper.readRecords(records)
165
+ : of(null)
166
+ )
167
+ )
168
+ }
169
+
145
170
  private mapEmbeddedFeatureCatalog(
146
171
  featureTypes: Array<DatasetFeatureType>
147
172
  ): DatasetFeatureCatalog {
@@ -150,12 +175,21 @@ export class Gn4Repository implements RecordsRepositoryInterface {
150
175
  name: featureType.typeName || '',
151
176
  definition: featureType.definition || '',
152
177
  attributes: Array.isArray(featureType.attributeTable)
153
- ? featureType.attributeTable.map((attr) => ({
154
- name: attr.name,
155
- code: attr.code,
156
- title: attr.definition,
157
- type: attr.type,
158
- }))
178
+ ? featureType.attributeTable.map((attr) => {
179
+ const values = attr.values
180
+ ?.filter((v) => v.code || v.label)
181
+ .map((v) => ({
182
+ code: v.code,
183
+ label: v.label,
184
+ }))
185
+ return {
186
+ name: attr.name,
187
+ code: attr.code,
188
+ definition: attr.definition,
189
+ type: attr.type,
190
+ ...(values?.length > 0 ? { values } : {}),
191
+ }
192
+ })
159
193
  : [],
160
194
  })),
161
195
  }
@@ -203,6 +237,24 @@ export class Gn4Repository implements RecordsRepositoryInterface {
203
237
  )
204
238
  }
205
239
 
240
+ getSources(record: CatalogRecord): Observable<CatalogRecord[]> {
241
+ const sourcesIdentifiers = record.extras?.['sourcesIdentifiers'] as string[]
242
+ if (sourcesIdentifiers && sourcesIdentifiers.length > 0) {
243
+ return this.getMultipleRecords(sourcesIdentifiers)
244
+ }
245
+ return of(null)
246
+ }
247
+
248
+ getSourceOf(record: CatalogRecord): Observable<CatalogRecord[]> {
249
+ const sourceOfIdentifiers = record.extras?.[
250
+ 'sourceOfIdentifiers'
251
+ ] as string[]
252
+ if (sourceOfIdentifiers && sourceOfIdentifiers.length > 0) {
253
+ return this.getMultipleRecords(sourceOfIdentifiers)
254
+ }
255
+ return of(null)
256
+ }
257
+
206
258
  aggregate(params: AggregationsParams): Observable<Aggregations> {
207
259
  // if aggregations are empty, return an empty object right away
208
260
  if (Object.keys(params).length === 0) return of({})
@@ -255,14 +307,46 @@ export class Gn4Repository implements RecordsRepositoryInterface {
255
307
  : of(true)
256
308
  }
257
309
 
258
- canEditRecord(uniqueIdentifier: string): Observable<boolean> {
259
- return this.getRecord(uniqueIdentifier).pipe(
260
- map((record) => {
261
- return record.extras['edit'] as boolean
310
+ canDuplicate(record: CatalogRecord): boolean {
311
+ return record.kind === 'dataset'
312
+ }
313
+
314
+ canDelete(record: CatalogRecord): Observable<boolean> {
315
+ return this.settingsService.allowEditHarvested$.pipe(
316
+ map((allowEditHarvested) => {
317
+ return (
318
+ record.extras['edit'] &&
319
+ (!record.extras['isHarvested'] || allowEditHarvested)
320
+ )
262
321
  })
263
322
  )
264
323
  }
265
324
 
325
+ private canEdit(record: CatalogRecord, allowEditHarvested: boolean): boolean {
326
+ return (
327
+ record.kind === 'dataset' &&
328
+ record.extras['edit'] &&
329
+ (!record.extras['isHarvested'] || allowEditHarvested)
330
+ )
331
+ }
332
+
333
+ canEditRecord(uniqueIdentifier: string): Observable<boolean> {
334
+ return combineLatest([
335
+ this.getRecord(uniqueIdentifier),
336
+ this.settingsService.allowEditHarvested$,
337
+ ]).pipe(
338
+ map(([record, allowEditHarvested]) =>
339
+ record ? this.canEdit(record, allowEditHarvested) : false
340
+ )
341
+ )
342
+ }
343
+
344
+ canEditIndexedRecord(record: CatalogRecord): Observable<boolean> {
345
+ return this.settingsService.allowEditHarvested$.pipe(
346
+ map((allowEditHarvested) => this.canEdit(record, allowEditHarvested))
347
+ )
348
+ }
349
+
266
350
  openRecordForEdition(
267
351
  uniqueIdentifier: string
268
352
  ): Observable<[CatalogRecord, string, boolean] | null> {
@@ -471,6 +555,18 @@ export class Gn4Repository implements RecordsRepositoryInterface {
471
555
  )
472
556
  }
473
557
 
558
+ getApplicationLanguages(): Observable<string[]> {
559
+ return this.gn4LanguagesApi
560
+ .getApplicationLanguages()
561
+ .pipe(
562
+ map((languages) =>
563
+ languages
564
+ .map((lang) => LANG_3_TO_2_MAPPER[lang.id ?? ''])
565
+ .filter((code): code is string => !!code)
566
+ )
567
+ )
568
+ }
569
+
474
570
  private getRecordAsXml(uniqueIdentifier: string): Observable<string | null> {
475
571
  return this.gn4RecordsApi
476
572
  .getRecordAs(
@@ -82,6 +82,13 @@ export class Gn4PlatformService implements PlatformServiceInterface {
82
82
  shareReplay(1)
83
83
  )
84
84
 
85
+ private readonly allowEditHarvestedMd$ = this.settings$.pipe(
86
+ map((info) => {
87
+ return info['system/harvester/enableEditing'] as boolean
88
+ }),
89
+ shareReplay(1)
90
+ )
91
+
85
92
  /**
86
93
  * A map of already loaded thesauri (groups of keywords); the key is a URI
87
94
  * @private
@@ -123,6 +130,10 @@ export class Gn4PlatformService implements PlatformServiceInterface {
123
130
  return this.apiVersion$
124
131
  }
125
132
 
133
+ getAllowEditHarvestedMd(): Observable<boolean> {
134
+ return this.allowEditHarvestedMd$
135
+ }
136
+
126
137
  getMe(): Observable<UserModel> {
127
138
  return this.me$
128
139
  }
@@ -11,6 +11,9 @@ export class Gn4SettingsService {
11
11
  'system/users/identicon'
12
12
  )
13
13
 
14
+ public allowEditHarvested$: Observable<boolean> =
15
+ this.getSettingsSetValueByKey('system/harvester/enableEditing')
16
+
14
17
  constructor(private siteApiService: SiteApiService) {}
15
18
 
16
19
  private getSettingsSetValueByKey(key: string) {
@@ -233,14 +233,6 @@ export interface DatasetRecord extends BaseRecord {
233
233
  spatialRepresentation?: SpatialRepresentationType
234
234
  }
235
235
 
236
- export type DatasetFeatureCatalog = {
237
- featureTypes: Array<{
238
- name: string
239
- definition: string
240
- attributes: Array<{ name: string; title: string; code: string }>
241
- }>
242
- }
243
-
244
236
  export interface ServiceEndpoint {
245
237
  url: URL
246
238
  accessServiceProtocol: ServiceProtocol
@@ -268,18 +260,32 @@ export interface ReuseRecord extends BaseRecord {
268
260
  temporalExtents: Array<DatasetTemporalExtent>
269
261
  }
270
262
 
263
+ export type DatasetFeatureCatalog = {
264
+ featureTypes: Array<{
265
+ name: string
266
+ definition: string
267
+ attributes: DatasetFeatureAttribute[]
268
+ }>
269
+ }
270
+ export interface DatasetFeatureAttributeValue {
271
+ code?: string
272
+ definition?: string
273
+ label?: string
274
+ }
275
+ export interface DatasetFeatureAttribute {
276
+ name: string
277
+ definition: string
278
+ type: string
279
+ code: string
280
+ values?: Array<DatasetFeatureAttributeValue>
281
+ }
271
282
  export interface DatasetFeatureType {
272
283
  aliases: string
273
284
  code: string
274
285
  isAbstract: string
275
286
  typeName: string
276
287
  definition: string
277
- attributeTable: Array<{
278
- name: string
279
- definition: string
280
- type: string
281
- code: string
282
- }>
288
+ attributeTable: Array<DatasetFeatureAttribute>
283
289
  }
284
290
 
285
291
  export type ReuseType = 'application' | 'map' | 'other'
@@ -19,8 +19,13 @@ export abstract class RecordsRepositoryInterface {
19
19
  abstract getSimilarRecords(
20
20
  similarTo: CatalogRecord
21
21
  ): Observable<CatalogRecord[]>
22
+ abstract getSources(record: CatalogRecord): Observable<CatalogRecord[]>
23
+ abstract getSourceOf(record: CatalogRecord): Observable<CatalogRecord[]>
22
24
  abstract fuzzySearch(query: string): Observable<SearchResults>
25
+ abstract canDuplicate(record: CatalogRecord): boolean
26
+ abstract canDelete(record: CatalogRecord): Observable<boolean>
23
27
  abstract canEditRecord(uniqueIdentifier: string): Observable<boolean>
28
+ abstract canEditIndexedRecord(record: CatalogRecord): Observable<boolean>
24
29
  /**
25
30
  * This emits once:
26
31
  * - record object; if a draft exists, this will return it
@@ -95,4 +100,5 @@ export abstract class RecordsRepositoryInterface {
95
100
  localRecord: CatalogRecord
96
101
  ): Observable<{ user: string; date: Date }>
97
102
  abstract getRecordPublicationStatus(uuid: string): Observable<boolean>
103
+ abstract getApplicationLanguages(): Observable<string[]>
98
104
  }
@@ -3,6 +3,7 @@ import {
3
3
  DatasetRecord,
4
4
  DatasetSpatialExtent,
5
5
  Keyword,
6
+ ServiceRecord,
6
7
  } from '../../../../../libs/common/domain/src/lib/model/record'
7
8
 
8
9
  export const datasetRecordsFixture: () => CatalogRecord[] = () => [
@@ -176,6 +177,20 @@ As such, **it is not very interesting at all.**`,
176
177
  link: '',
177
178
  definition: 'Nom de la rue',
178
179
  type: 'String (48)',
180
+ values: [
181
+ {
182
+ code: 'Pomme',
183
+ label: 'Les Pommiers',
184
+ description: 'Sous les pommiers',
185
+ },
186
+ {
187
+ code: 'Cotton',
188
+ label: 'Rue Cotton',
189
+ description: 'Rue Cotton',
190
+ },
191
+ { code: "Passage de l'échiquier" },
192
+ { description: 'Rue du Charlieu' },
193
+ ],
179
194
  },
180
195
  {
181
196
  code: 'RUE',
@@ -811,6 +826,54 @@ export const importDatasetRecordAsXmlFixture = (): string => `
811
826
  </gmd:identificationInfo>
812
827
  </gmd:MD_Metadata>`
813
828
 
829
+ export const simpleServiceRecordFixture = (): ServiceRecord => ({
830
+ kind: 'service',
831
+ status: null,
832
+ lineage: null,
833
+ recordUpdated: new Date('2023-03-17T07:38:08.875Z'),
834
+ recordPublished: null,
835
+ ownerOrganization: null,
836
+ licenses: [],
837
+ legalConstraints: [],
838
+ securityConstraints: [],
839
+ otherConstraints: [],
840
+ contacts: [],
841
+ contactsForResource: [],
842
+ keywords: [],
843
+ topics: [],
844
+ spatialExtents: [],
845
+ temporalExtents: [],
846
+ overviews: [],
847
+ defaultLanguage: null,
848
+ otherLanguages: [],
849
+ title: 'Sites de gestion des déchets miniers - Service de visualisation WMS',
850
+ onlineResources: [
851
+ {
852
+ name: 'Service de visualisation WMS',
853
+ description:
854
+ 'Adresse de connexion au service de visualisation WMS de la série de couches de données "Sites de gestion des déchets miniers"',
855
+ type: 'service',
856
+ url: new URL(
857
+ 'https://geoservices.wallonie.be/arcgis/services/SOL_SOUS_SOL/DECHETS_MINIERS/MapServer/WMSServer?request=GetCapabilities&service=WMS'
858
+ ),
859
+ accessServiceProtocol: 'wms',
860
+ accessRestricted: false,
861
+ },
862
+ ],
863
+ uniqueIdentifier: '00b22798-ec8e-4500-89e8-90eeeda45919',
864
+ landingPage: new URL(
865
+ 'http://localhost:4200/geonetwork/srv/fre/catalog.search#/metadata/00b22798-ec8e-4500-89e8-90eeeda45919'
866
+ ),
867
+ extras: {
868
+ isPublishedToAll: true,
869
+ id: '723',
870
+ isHarvested: true,
871
+ ownerInfo: 'admin|admin|admin|Administrator',
872
+ edit: true,
873
+ },
874
+ recordCreated: new Date('2023-03-17T07:38:08.875Z'),
875
+ })
876
+
814
877
  export const NATIONAL_KEYWORD = {
815
878
  key: 'http://inspire.ec.europa.eu/metadata-codelist/SpatialScope/national',
816
879
  label: 'National',