geonetwork-ui 2.8.0-dev.e22966206 → 2.8.0-dev.e46888fcc

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 (158) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.mjs +3 -3
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +24 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +7 -7
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +3 -2
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +4 -3
  6. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/constant.mjs +1 -2
  7. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  8. package/esm2022/libs/feature/dataviz/src/index.mjs +1 -2
  9. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +9 -2
  10. package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +3 -3
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +23 -3
  12. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +2 -2
  13. package/esm2022/libs/feature/record/src/index.mjs +2 -1
  14. package/esm2022/libs/feature/record/src/lib/stac-view/stac-view.component.mjs +138 -0
  15. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +13 -1
  16. package/esm2022/libs/feature/search/src/lib/constants.mjs +1 -2
  17. package/esm2022/libs/ui/elements/src/index.mjs +3 -1
  18. package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +1 -1
  19. package/esm2022/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.mjs +37 -0
  20. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +5 -9
  21. package/esm2022/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.mjs +18 -0
  22. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.mjs +5 -5
  23. package/esm2022/libs/ui/inputs/src/index.mjs +2 -1
  24. package/esm2022/libs/ui/inputs/src/lib/date-picker/date-picker.component.mjs +21 -7
  25. package/esm2022/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.mjs +35 -0
  26. package/esm2022/libs/ui/layout/src/lib/paginable.interface.mjs +1 -1
  27. package/esm2022/libs/ui/layout/src/lib/previous-next-buttons/previous-next-buttons.component.mjs +13 -5
  28. package/esm2022/libs/util/i18n/src/lib/date-locales.mjs +33 -0
  29. package/esm2022/libs/util/shared/src/index.mjs +2 -1
  30. package/esm2022/libs/util/shared/src/lib/humanize-date.directive.mjs +33 -0
  31. package/esm2022/libs/util/shared/src/lib/services/date.service.mjs +19 -2
  32. package/esm2022/translations/de.json +12 -4
  33. package/esm2022/translations/en.json +12 -4
  34. package/esm2022/translations/es.json +8 -0
  35. package/esm2022/translations/fr.json +12 -4
  36. package/esm2022/translations/it.json +12 -4
  37. package/esm2022/translations/nl.json +8 -0
  38. package/esm2022/translations/pt.json +8 -0
  39. package/esm2022/translations/sk.json +9 -1
  40. package/fesm2022/geonetwork-ui-date-locales-MYnkDJ5h.mjs +35 -0
  41. package/fesm2022/geonetwork-ui-date-locales-MYnkDJ5h.mjs.map +1 -0
  42. package/fesm2022/geonetwork-ui.mjs +458 -156
  43. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  44. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  45. package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -1
  46. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +5 -1
  47. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  48. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  49. package/libs/api/repository/src/lib/gn4/elasticsearch/constant.d.ts.map +1 -1
  50. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +6 -1
  51. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  52. package/libs/feature/dataviz/src/index.d.ts +0 -1
  53. package/libs/feature/dataviz/src/index.d.ts.map +1 -1
  54. package/libs/feature/dataviz/src/lib/service/data.service.d.ts +2 -1
  55. package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
  56. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +2 -0
  57. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  58. package/libs/feature/record/src/index.d.ts +1 -0
  59. package/libs/feature/record/src/index.d.ts.map +1 -1
  60. package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts +35 -0
  61. package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts.map +1 -0
  62. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +4 -0
  63. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  64. package/libs/feature/search/src/lib/constants.d.ts.map +1 -1
  65. package/libs/ui/elements/src/index.d.ts +2 -0
  66. package/libs/ui/elements/src/index.d.ts.map +1 -1
  67. package/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.d.ts +8 -0
  68. package/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.d.ts.map +1 -0
  69. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +0 -2
  70. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
  71. package/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.d.ts +8 -0
  72. package/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.d.ts.map +1 -0
  73. package/libs/ui/inputs/src/index.d.ts +1 -0
  74. package/libs/ui/inputs/src/index.d.ts.map +1 -1
  75. package/libs/ui/inputs/src/lib/date-picker/date-picker.component.d.ts +5 -0
  76. package/libs/ui/inputs/src/lib/date-picker/date-picker.component.d.ts.map +1 -1
  77. package/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.d.ts +12 -0
  78. package/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.d.ts.map +1 -0
  79. package/libs/ui/layout/src/lib/paginable.interface.d.ts +3 -3
  80. package/libs/ui/layout/src/lib/paginable.interface.d.ts.map +1 -1
  81. package/libs/ui/layout/src/lib/previous-next-buttons/previous-next-buttons.component.d.ts +2 -1
  82. package/libs/ui/layout/src/lib/previous-next-buttons/previous-next-buttons.component.d.ts.map +1 -1
  83. package/libs/util/i18n/src/lib/date-locales.d.ts +5 -0
  84. package/libs/util/i18n/src/lib/date-locales.d.ts.map +1 -0
  85. package/libs/util/shared/src/index.d.ts +1 -0
  86. package/libs/util/shared/src/index.d.ts.map +1 -1
  87. package/libs/util/shared/src/lib/humanize-date.directive.d.ts +15 -0
  88. package/libs/util/shared/src/lib/humanize-date.directive.d.ts.map +1 -0
  89. package/libs/util/shared/src/lib/services/date.service.d.ts +4 -0
  90. package/libs/util/shared/src/lib/services/date.service.d.ts.map +1 -1
  91. package/package.json +1 -1
  92. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +2 -2
  93. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +1 -1
  94. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.service+eaux-usees.ts +1 -1
  95. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +5 -2
  96. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -1
  97. package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +1 -1
  98. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +2 -2
  99. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +1 -1
  100. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.service+napitswallonia.ts +1 -1
  101. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +26 -0
  102. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +13 -6
  103. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +6 -2
  104. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +4 -2
  105. package/src/libs/api/repository/src/lib/gn4/elasticsearch/constant.ts +0 -1
  106. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +8 -1
  107. package/src/libs/feature/dataviz/src/index.ts +0 -1
  108. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +14 -0
  109. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +1 -0
  110. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +3 -3
  111. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +30 -0
  112. package/src/libs/feature/editor/src/lib/fields.config.ts +1 -1
  113. package/src/libs/feature/record/src/index.ts +1 -0
  114. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.css +3 -0
  115. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.html +68 -0
  116. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.ts +190 -0
  117. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +19 -0
  118. package/src/libs/feature/search/src/lib/constants.ts +0 -1
  119. package/src/libs/ui/elements/src/index.ts +2 -0
  120. package/src/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.html +31 -0
  121. package/src/libs/ui/elements/src/lib/metadata-doi/metadata-doi.component.ts +30 -0
  122. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +16 -12
  123. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -9
  124. package/src/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.css +0 -0
  125. package/src/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.html +13 -0
  126. package/src/libs/ui/elements/src/lib/stac-items-result-grid/stac-items-result-grid.component.ts +15 -0
  127. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.html +1 -1
  128. package/src/libs/ui/elements/src/lib/user-feedback-item/user-feedback-item.component.ts +2 -2
  129. package/src/libs/ui/inputs/src/index.ts +1 -0
  130. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +17 -1
  131. package/src/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.css +0 -0
  132. package/src/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.html +15 -0
  133. package/src/libs/ui/inputs/src/lib/date-range-inputs/date-range-inputs.component.ts +41 -0
  134. package/src/libs/ui/layout/src/lib/paginable.interface.ts +3 -3
  135. package/src/libs/ui/layout/src/lib/previous-next-buttons/previous-next-buttons.component.html +12 -6
  136. package/src/libs/ui/layout/src/lib/previous-next-buttons/previous-next-buttons.component.ts +4 -1
  137. package/src/libs/util/i18n/src/lib/date-locales.ts +63 -0
  138. package/src/libs/util/shared/src/index.ts +1 -0
  139. package/src/libs/util/shared/src/lib/humanize-date.directive.ts +35 -0
  140. package/src/libs/util/shared/src/lib/services/date.service.ts +27 -1
  141. package/translations/de.json +12 -4
  142. package/translations/en.json +12 -4
  143. package/translations/es.json +8 -0
  144. package/translations/fr.json +12 -4
  145. package/translations/it.json +12 -4
  146. package/translations/nl.json +8 -0
  147. package/translations/pt.json +8 -0
  148. package/translations/sk.json +9 -1
  149. package/esm2022/libs/feature/dataviz/src/lib/stac-view/stac-view.component.mjs +0 -22
  150. package/esm2022/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.mjs +0 -59
  151. package/libs/feature/dataviz/src/lib/stac-view/stac-view.component.d.ts +0 -11
  152. package/libs/feature/dataviz/src/lib/stac-view/stac-view.component.d.ts.map +0 -1
  153. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts +0 -11
  154. package/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.d.ts.map +0 -1
  155. package/src/libs/feature/dataviz/src/lib/stac-view/stac-view.component.html +0 -5
  156. package/src/libs/feature/dataviz/src/lib/stac-view/stac-view.component.ts +0 -27
  157. package/src/libs/ui/elements/src/lib/user-feedback-item/time-since.pipe.ts +0 -54
  158. /package/src/libs/{feature/dataviz/src/lib/stac-view/stac-view.component.css → ui/elements/src/lib/metadata-doi/metadata-doi.component.css} +0 -0
@@ -68,7 +68,7 @@ export const GEOCAT_CH_DATASET_RECORD: DatasetRecord = {
68
68
  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.`,
69
69
  overviews: [],
70
70
  topics: ['planningCadastre', 'planningCadastre_Planning'],
71
- resourceIdentifier: 'ch.are.alpenkonvention',
71
+ resourceIdentifiers: [{ code: 'ch.are.alpenkonvention' }],
72
72
  keywords: [
73
73
  {
74
74
  thesaurus: {
@@ -2,7 +2,7 @@ import { ReuseRecord } from '../../../../../../libs/common/domain/src/lib/model/
2
2
 
3
3
  export const GEORHENA_REUSE_SOLAIRE_RECORD: ReuseRecord = {
4
4
  uniqueIdentifier: '015e6d20-0d69-4ae7-adfe-85c588aac141',
5
- resourceIdentifier: '04_2022_301',
5
+ resourceIdentifiers: [{ code: '04_2022_301' }],
6
6
  kind: 'reuse',
7
7
  otherLanguages: ['de', 'en'],
8
8
  defaultLanguage: 'fr',
@@ -71,7 +71,7 @@ Toutes ces données sont reprises dans BDR.`,
71
71
  recordCreated: new Date('2019-04-02T12:34:35'),
72
72
  recordUpdated: new Date('2022-06-16T05:01:21'),
73
73
  resourceCreated: new Date('2002-01-01'),
74
- resourceIdentifier: '2d974612-70b1-4662-a9f4-c43cbe453773',
74
+ resourceIdentifiers: [{ code: '2d974612-70b1-4662-a9f4-c43cbe453773' }],
75
75
  resourceUpdated: new Date('2022-06-16'),
76
76
  resourcePublished: new Date('2022-06-16'),
77
77
  onlineResources: [
@@ -645,7 +645,7 @@ export const METAWAL_SERVICE_RECORD: ServiceRecord = {
645
645
  },
646
646
  recordCreated: new Date('2019-04-02T12:31:58'),
647
647
  recordUpdated: new Date('2022-02-09T11:31:06.766Z'),
648
- resourceIdentifier: '6d2b6fdb-f1ea-4d48-8697-a0c05512f1dc',
648
+ resourceIdentifiers: [{ code: '6d2b6fdb-f1ea-4d48-8697-a0c05512f1dc' }],
649
649
  resourcePublished: new Date('2016-12-01'),
650
650
  securityConstraints: [],
651
651
  title:
@@ -2,7 +2,7 @@ import { ReuseRecord } from '../../../../../../libs/common/domain/src/lib/model/
2
2
 
3
3
  export const WALLONIE_REUSE_SPW_RECORD: ReuseRecord = {
4
4
  uniqueIdentifier: '83809bcd-1763-4d28-b820-2b9828083ba5',
5
- resourceIdentifier: '83809bcd-1763-4d28-b820-2b9828083ba5',
5
+ resourceIdentifiers: [{ code: '83809bcd-1763-4d28-b820-2b9828083ba5' }],
6
6
  kind: 'reuse',
7
7
  otherLanguages: [],
8
8
  defaultLanguage: 'fr',
@@ -2,7 +2,7 @@ import { ServiceRecord } from '../../../../../../libs/common/domain/src/lib/mode
2
2
 
3
3
  export const WALLONIE_SERVICE_NAPITSWALLONIA_RECORD: ServiceRecord = {
4
4
  uniqueIdentifier: 'fe1c1a3d-c75b-435c-a1d1-48426818f54d',
5
- resourceIdentifier: 'fe1c1a3d-c75b-435c-a1d1-48426818f54d',
5
+ resourceIdentifiers: [{ code: 'fe1c1a3d-c75b-435c-a1d1-48426818f54d' }],
6
6
  kind: 'service',
7
7
  otherLanguages: [],
8
8
  defaultLanguage: 'fr',
@@ -451,6 +451,32 @@ export class Gn4FieldMapper {
451
451
  }),
452
452
  }
453
453
  },
454
+ resourceIdentifier: (output, source) => {
455
+ const identifiers = getAsArray(selectField(source, 'resourceIdentifier'))
456
+
457
+ if (!identifiers.length) return output
458
+
459
+ const mappedIdentifiers = identifiers
460
+ .map((id) => {
461
+ const code = selectField<string>(id, 'code')
462
+ const codeSpace = selectField<string>(id, 'codeSpace')
463
+ const link = selectField<string>(id, 'link')
464
+
465
+ return {
466
+ code,
467
+ ...(codeSpace && { codeSpace }),
468
+ ...(link && { url: link }),
469
+ }
470
+ })
471
+ .filter((id) => id !== null)
472
+
473
+ if (!mappedIdentifiers.length) return output
474
+
475
+ return {
476
+ ...output,
477
+ resourceIdentifiers: mappedIdentifiers,
478
+ }
479
+ },
454
480
  }
455
481
 
456
482
  private genericField = (output) => output
@@ -92,7 +92,7 @@ export class Iso19139Converter extends BaseConverter<string> {
92
92
  recordUpdated: readRecordUpdated,
93
93
  recordCreated: () => undefined, // not supported in ISO19139
94
94
  recordPublished: () => undefined, // not supported in ISO19139
95
- resourceIdentifier: readResourceIdentifier,
95
+ resourceIdentifiers: readResourceIdentifier,
96
96
  resourceUpdated: readResourceUpdated,
97
97
  resourceCreated: readResourceCreated,
98
98
  resourcePublished: readResourcePublished,
@@ -133,7 +133,7 @@ export class Iso19139Converter extends BaseConverter<string> {
133
133
  recordUpdated: writeRecordUpdated,
134
134
  recordCreated: () => undefined, // not supported in ISO19139
135
135
  recordPublished: () => undefined, // not supported in ISO19139
136
- resourceIdentifier: writeResourceIdentifier,
136
+ resourceIdentifiers: writeResourceIdentifier,
137
137
  resourceUpdated: writeResourceUpdated,
138
138
  resourceCreated: writeResourceCreated,
139
139
  resourcePublished: writeResourcePublished,
@@ -240,12 +240,19 @@ export class Iso19139Converter extends BaseConverter<string> {
240
240
  const onlineResources = this.readers['onlineResources'](rootEl, tr)
241
241
  const otherLanguages = this.readers['otherLanguages'](rootEl, tr)
242
242
  const defaultLanguage = this.readers['defaultLanguage'](rootEl, tr)
243
- const resourceIdentifier = this.readers['resourceIdentifier'](rootEl, tr)
243
+ const resourceIdentifiers = this.readers['resourceIdentifiers'](
244
+ rootEl,
245
+ tr
246
+ ) as Array<{
247
+ code: string
248
+ codeSpace?: string
249
+ url?: string
250
+ }>
244
251
  const spatialExtents = this.readers['spatialExtents'](rootEl, tr)
245
252
 
246
253
  return {
247
254
  uniqueIdentifier,
248
- ...(resourceIdentifier && { resourceIdentifier }),
255
+ ...(resourceIdentifiers?.length > 0 && { resourceIdentifiers }),
249
256
  kind,
250
257
  otherLanguages,
251
258
  defaultLanguage,
@@ -388,8 +395,8 @@ export class Iso19139Converter extends BaseConverter<string> {
388
395
  this.writers['otherConstraints'](record, rootEl)
389
396
  fieldChanged('onlineResources') &&
390
397
  this.writers['onlineResources'](record, rootEl)
391
- fieldChanged('resourceIdentifier') &&
392
- this.writers['resourceIdentifier'](record, rootEl)
398
+ fieldChanged('resourceIdentifiers') &&
399
+ this.writers['resourceIdentifiers'](record, rootEl)
393
400
 
394
401
  if (record.kind === 'dataset') {
395
402
  fieldChanged('status') && this.writers['status'](record, rootEl)
@@ -1183,8 +1183,10 @@ export function readDefaultLanguage(rootEl: XmlElement): LanguageCode {
1183
1183
  )(rootEl)
1184
1184
  }
1185
1185
 
1186
- export function readResourceIdentifier(rootEl: XmlElement): string {
1187
- return pipe(
1186
+ export function readResourceIdentifier(
1187
+ rootEl: XmlElement
1188
+ ): Array<{ code: string; codeSpace?: string; url?: string }> {
1189
+ const code = pipe(
1188
1190
  findIdentification(),
1189
1191
  findNestedElement(
1190
1192
  'gmd:citation',
@@ -1195,4 +1197,6 @@ export function readResourceIdentifier(rootEl: XmlElement): string {
1195
1197
  ),
1196
1198
  extractCharacterString()
1197
1199
  )(rootEl)
1200
+
1201
+ return code ? [{ code }] : []
1198
1202
  }
@@ -1502,14 +1502,16 @@ export function writeResourceIdentifier(
1502
1502
  record: DatasetRecord,
1503
1503
  rootEl: XmlElement
1504
1504
  ) {
1505
+ const firstIdentifier = record.resourceIdentifiers?.[0]?.code
1506
+
1505
1507
  pipe(
1506
1508
  findOrCreateIdentification(),
1507
1509
  findNestedChildOrCreate('gmd:citation', 'gmd:CI_Citation'),
1508
1510
  removeChildrenByName('gmd:identifier'),
1509
- record.resourceIdentifier
1511
+ firstIdentifier
1510
1512
  ? pipe(
1511
1513
  createNestedChild('gmd:identifier', 'gmd:MD_Identifier', 'gmd:code'),
1512
- writeCharacterString(record.resourceIdentifier)
1514
+ writeCharacterString(firstIdentifier)
1513
1515
  )
1514
1516
  : noop
1515
1517
  )(rootEl)
@@ -7,7 +7,6 @@ export const ES_SOURCE_SUMMARY = [
7
7
  'resourceAbstractObject',
8
8
  'overview',
9
9
  'logo',
10
- 'codelist_status_text',
11
10
  'link',
12
11
  'linkProtocol',
13
12
  'contactForResource*.organisation*',
@@ -113,6 +113,12 @@ export interface INSPIRE_topic {
113
113
  label: string
114
114
  }
115
115
 
116
+ export interface ResourceIdentifier {
117
+ code: string
118
+ codeSpace?: string
119
+ url?: string
120
+ }
121
+
116
122
  export interface BaseRecord {
117
123
  uniqueIdentifier: Uuid
118
124
  ownerOrganization: Organization
@@ -135,7 +141,8 @@ export interface BaseRecord {
135
141
  updateFrequency?: UpdateFrequency
136
142
 
137
143
  // information related to the resource (dataset, service)
138
- resourceIdentifier?: string
144
+
145
+ resourceIdentifiers?: Array<ResourceIdentifier>
139
146
  contactsForResource: Array<Individual>
140
147
  resourceCreated?: Date
141
148
  resourcePublished?: Date
@@ -3,4 +3,3 @@ export * from './lib/chart-view/chart-view.component'
3
3
  export * from './lib/figure/figure-container/figure-container.component'
4
4
  export * from './lib/geo-table-view/geo-table-view.component'
5
5
  export * from './lib/table-view/table-view.component'
6
- export * from './lib/stac-view/stac-view.component'
@@ -7,6 +7,9 @@ import {
7
7
  WfsEndpoint,
8
8
  WfsVersion,
9
9
  TmsEndpoint,
10
+ StacEndpoint,
11
+ GetCollectionItemsOptions,
12
+ StacItemsDocument,
10
13
  } from '@camptocamp/ogc-client'
11
14
  import {
12
15
  BaseReader,
@@ -244,6 +247,17 @@ export class DataService {
244
247
  })
245
248
  }
246
249
 
250
+ async getItemsFromStacApi(
251
+ url: string,
252
+ options: GetCollectionItemsOptions
253
+ ): Promise<StacItemsDocument> {
254
+ return await StacEndpoint.getItemsFromUrl(url, options)
255
+ .then((response) => response)
256
+ .catch(() => {
257
+ throw new Error(`ogc.unreachable.unknown`)
258
+ })
259
+ }
260
+
247
261
  async getGeodataLinksFromTms(
248
262
  tmsLink: DatasetServiceDistribution,
249
263
  keepOriginalLink = false
@@ -40,6 +40,7 @@
40
40
  <div
41
41
  class="flex flex-col gap-2 w-full px-2"
42
42
  data-test="langAvailable"
43
+ [attr.data-test-lang]="lang"
43
44
  *ngFor="let lang of languages"
44
45
  >
45
46
  <gn-ui-button
@@ -69,11 +69,11 @@
69
69
  (valueChange)="valueChange.emit($event)"
70
70
  ></gn-ui-form-field-overviews>
71
71
  </ng-container>
72
- <ng-container *ngSwitchCase="'resourceIdentifier'">
72
+ <ng-container *ngSwitchCase="'resourceIdentifiers'">
73
73
  <gn-ui-form-field-simple
74
74
  [type]="'text'"
75
- [value]="valueAsString"
76
- (valueChange)="valueChange.emit($event)"
75
+ [value]="valueAsResourceIdentifierCode"
76
+ (valueChange)="handleResourceIdentifierChange($event)"
77
77
  ></gn-ui-form-field-simple>
78
78
  </ng-container>
79
79
  <ng-container *ngSwitchCase="'resourceCreated'">
@@ -142,4 +142,34 @@ export class FormFieldComponent {
142
142
  get valueAsOnlineResources() {
143
143
  return this.value as Array<OnlineResource>
144
144
  }
145
+ get valueAsResourceIdentifierCode() {
146
+ const identifiers = this.value as Array<{
147
+ code: string
148
+ codeSpace?: string
149
+ url?: string
150
+ }>
151
+ return identifiers?.[0]?.code || ''
152
+ }
153
+
154
+ handleResourceIdentifierChange(code: string) {
155
+ const identifiers = this.value as Array<{
156
+ code: string
157
+ codeSpace?: string
158
+ url?: string
159
+ }>
160
+
161
+ if (!code) {
162
+ this.valueChange.emit(identifiers?.slice(1) || [])
163
+ return
164
+ }
165
+
166
+ if (identifiers?.[0]) {
167
+ this.valueChange.emit([
168
+ { ...identifiers[0], code },
169
+ ...identifiers.slice(1),
170
+ ])
171
+ } else {
172
+ this.valueChange.emit([{ code }])
173
+ }
174
+ }
145
175
  }
@@ -81,7 +81,7 @@ export const RECORD_RESOURCE_CREATED_FIELD: EditorField = {
81
81
  }
82
82
 
83
83
  export const RESOURCE_IDENTIFIER_FIELD: EditorField = {
84
- model: 'resourceIdentifier',
84
+ model: 'resourceIdentifiers',
85
85
  formFieldConfig: {
86
86
  labelKey: marker('editor.record.form.field.resourceIdentifier'),
87
87
  },
@@ -8,3 +8,4 @@ export * from './lib/external-viewer-button/external-viewer-button.component'
8
8
  export * from './lib/gpf-api-dl/gpf-api-dl.component'
9
9
  export * from './lib/map-view/map-view.component'
10
10
  export * from './lib/record-meta/record-meta.component'
11
+ export * from './lib/stac-view/stac-view.component'
@@ -0,0 +1,3 @@
1
+ :host {
2
+ --gn-ui-button-padding: 7px 8px;
3
+ }
@@ -0,0 +1,68 @@
1
+ <div class="mt-6 bg-white border border-gray-300 overflow-hidden rounded-lg">
2
+ <div
3
+ class="w-full min-h-[366px] flex md:flex-row flex-col border-b border-gray-300"
4
+ >
5
+ <div class="md:w-1/2 w-full flex-1 flex flex-col">
6
+ <gn-ui-date-range-inputs
7
+ [temporalExtent]="currentTemporalExtent$ | async"
8
+ (temporalExtentChange)="onTemporalExtentChange($event)"
9
+ ></gn-ui-date-range-inputs>
10
+
11
+ <div class="mt-auto mb-8 mx-8" *ngIf="isFilterModified">
12
+ <gn-ui-button
13
+ id="reset-filters-button"
14
+ type="light"
15
+ (buttonClick)="onResetFilters()"
16
+ >
17
+ <span translate>stac.filter.reset</span>
18
+ <ng-icon name="matDeleteOutline" class="ml-2"></ng-icon>
19
+ </gn-ui-button>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="md:w-1/2 w-full min-h-[280px] flex items-center justify-center">
24
+ <span>Map...</span>
25
+ </div>
26
+ </div>
27
+ <div
28
+ class="relative mx-5 my-[30px] min-h-[274px] flex items-center justify-center flex-col"
29
+ >
30
+ <!-- Keep grid outside ngIf to keep items$ observable alive -->
31
+ <gn-ui-stac-items-result-grid
32
+ [items]="items$ | async"
33
+ ></gn-ui-stac-items-result-grid>
34
+ <div
35
+ *ngIf="(items$ | async)?.length > 0; else noResultsOrError"
36
+ class="mt-[20px] mx-auto flex justify-center"
37
+ >
38
+ <gn-ui-previous-next-buttons
39
+ [listComponent]="this"
40
+ [displayLabels]="true"
41
+ ></gn-ui-previous-next-buttons>
42
+ </div>
43
+ <ng-template #noResultsOrError>
44
+ <gn-ui-popup-alert
45
+ *ngIf="error"
46
+ type="warning"
47
+ icon="matErrorOutlineOutline"
48
+ class="absolute left-0 top-0 w-full block"
49
+ >
50
+ <span translate>{{ error }}</span>
51
+ </gn-ui-popup-alert>
52
+ <div
53
+ *ngIf="!error"
54
+ class="flex items-center justify-center flex-col h-full gap-[10px]"
55
+ >
56
+ <h2 class="text-center text-xl" translate>stac.results.noResults</h2>
57
+ <gn-ui-button
58
+ id="no-results-button"
59
+ type="secondary"
60
+ (buttonClick)="onResetFilters()"
61
+ >
62
+ <span translate>stac.filter.reset</span>
63
+ <ng-icon name="matDeleteOutline" class="ml-2"></ng-icon>
64
+ </gn-ui-button>
65
+ </div>
66
+ </ng-template>
67
+ </div>
68
+ </div>
@@ -0,0 +1,190 @@
1
+ import { CommonModule } from '@angular/common'
2
+ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'
3
+ import {
4
+ DatasetRecord,
5
+ DatasetTemporalExtent,
6
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
7
+ import { StacItemsResultGridComponent } from '../../../../../../libs/ui/elements/src'
8
+ import {
9
+ ButtonComponent,
10
+ DateRangeInputsComponent,
11
+ } from '../../../../../../libs/ui/inputs/src'
12
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
13
+ import { matDeleteOutline } from '@ng-icons/material-icons/outline'
14
+ import { TranslateDirective, TranslateService } from '@ngx-translate/core'
15
+ import { DataService } from '../../../../../../libs/feature/dataviz/src'
16
+ import {
17
+ BehaviorSubject,
18
+ catchError,
19
+ combineLatest,
20
+ debounceTime,
21
+ from,
22
+ map,
23
+ Observable,
24
+ of,
25
+ switchMap,
26
+ take,
27
+ tap,
28
+ } from 'rxjs'
29
+ import { GetCollectionItemsOptions, StacItem } from '@camptocamp/ogc-client'
30
+ import { MdViewFacade } from '../state'
31
+ import { PreviousNextButtonsComponent } from '../../../../../../libs/ui/layout/src'
32
+ import { FetchError } from '../../../../../../libs/util/data-fetcher/src'
33
+ import { PopupAlertComponent } from '../../../../../../libs/ui/widgets/src'
34
+
35
+ const STAC_ITEMS_PER_PAGE = 12
36
+ const DEBOUNCE_TIME_MS = 500
37
+
38
+ @Component({
39
+ selector: 'gn-ui-stac-view',
40
+ templateUrl: './stac-view.component.html',
41
+ styleUrls: ['./stac-view.component.css'],
42
+ changeDetection: ChangeDetectionStrategy.OnPush,
43
+ standalone: true,
44
+ imports: [
45
+ CommonModule,
46
+ NgIconComponent,
47
+ TranslateDirective,
48
+ StacItemsResultGridComponent,
49
+ DateRangeInputsComponent,
50
+ PreviousNextButtonsComponent,
51
+ PopupAlertComponent,
52
+ ButtonComponent,
53
+ ],
54
+ viewProviders: [provideIcons({ matDeleteOutline })],
55
+ })
56
+ export class StacViewComponent implements OnInit {
57
+ isFilterModified = false
58
+ error = null
59
+
60
+ initialTemporalExtent: DatasetTemporalExtent | null = null
61
+ currentTemporalExtent$ = new BehaviorSubject<DatasetTemporalExtent | null>(
62
+ null
63
+ )
64
+
65
+ initialPageUrl: string
66
+ previousPageUrl: string
67
+ nextPageUrl: string
68
+ currentPageUrl$ = new BehaviorSubject<string | null>(null)
69
+
70
+ items$: Observable<StacItem[]> = combineLatest([
71
+ this.currentPageUrl$,
72
+ this.currentTemporalExtent$,
73
+ ]).pipe(
74
+ debounceTime(DEBOUNCE_TIME_MS),
75
+ switchMap(([currentPageUrl, temporalExtent]) => {
76
+ this.error = null
77
+ const options: GetCollectionItemsOptions = {
78
+ limit: STAC_ITEMS_PER_PAGE,
79
+ }
80
+ if (temporalExtent && (temporalExtent.start || temporalExtent.end)) {
81
+ options.datetime = {
82
+ ...(temporalExtent.start && { start: temporalExtent.start }),
83
+ ...(temporalExtent.end && { end: temporalExtent.end }),
84
+ }
85
+ }
86
+ return from(
87
+ this.dataService.getItemsFromStacApi(currentPageUrl, options)
88
+ ).pipe(
89
+ tap((stacDocument) => {
90
+ this.previousPageUrl =
91
+ stacDocument.links.find((link) => link.rel === 'previous')?.href ||
92
+ null
93
+ this.nextPageUrl =
94
+ stacDocument.links.find((link) => link.rel === 'next')?.href || null
95
+ }),
96
+ map((stacDocument) => stacDocument.features),
97
+ catchError((err) => {
98
+ this.handleError(err)
99
+ return of([])
100
+ })
101
+ )
102
+ })
103
+ )
104
+
105
+ constructor(
106
+ private dataService: DataService,
107
+ private metadataViewFacade: MdViewFacade,
108
+ private translateService: TranslateService
109
+ ) {}
110
+
111
+ ngOnInit() {
112
+ this.metadataViewFacade.metadata$
113
+ .pipe(
114
+ take(1),
115
+ map((metadata) => {
116
+ const temporalExtents =
117
+ metadata?.kind === 'dataset'
118
+ ? (metadata as DatasetRecord).temporalExtents
119
+ : []
120
+
121
+ return temporalExtents.length > 0
122
+ ? temporalExtents[0]
123
+ : ({
124
+ start: null,
125
+ end: null,
126
+ } as DatasetTemporalExtent)
127
+ })
128
+ )
129
+ .subscribe((extent) => {
130
+ this.initialTemporalExtent = extent
131
+ this.currentTemporalExtent$.next(extent)
132
+ })
133
+
134
+ this.metadataViewFacade.stacLinks$
135
+ .pipe(
136
+ take(1),
137
+ map((links) => (links && links.length > 0 ? links[0] : null))
138
+ )
139
+ .subscribe((link) => {
140
+ if (link) {
141
+ this.initialPageUrl = link.url.href
142
+ this.currentPageUrl$.next(link.url.href)
143
+ }
144
+ })
145
+ }
146
+
147
+ onTemporalExtentChange(extent: DatasetTemporalExtent | null) {
148
+ this.currentTemporalExtent$.next(extent)
149
+ // make sure to use url without pagination token when temporal filter changes
150
+ this.currentPageUrl$.next(this.initialPageUrl)
151
+ this.isFilterModified = true
152
+ }
153
+
154
+ onResetFilters() {
155
+ this.currentTemporalExtent$.next(this.initialTemporalExtent)
156
+ this.isFilterModified = false
157
+ }
158
+
159
+ handleError(error: FetchError | Error | string) {
160
+ if (error instanceof FetchError) {
161
+ this.error = this.translateService.instant(
162
+ `dataset.error.${error.type}`,
163
+ {
164
+ info: error.info,
165
+ }
166
+ )
167
+ console.warn(error.message)
168
+ } else if (error instanceof Error) {
169
+ this.error = this.translateService.instant(error.message)
170
+ console.warn(error.stack || error)
171
+ } else {
172
+ this.error = this.translateService.instant(error)
173
+ console.warn(error)
174
+ }
175
+ }
176
+
177
+ // Paginable API
178
+ get isFirstPage() {
179
+ return this.previousPageUrl == null
180
+ }
181
+ get isLastPage() {
182
+ return this.nextPageUrl == null
183
+ }
184
+ goToNextPage() {
185
+ this.currentPageUrl$.next(this.nextPageUrl)
186
+ }
187
+ goToPrevPage() {
188
+ this.currentPageUrl$.next(this.previousPageUrl)
189
+ }
190
+ }
@@ -89,6 +89,25 @@ export class MdViewFacade {
89
89
  shareReplay(1)
90
90
  )
91
91
 
92
+ resourceDoi$ = this.metadata$.pipe(
93
+ map((record) => {
94
+ if (!record?.resourceIdentifiers?.length) return null
95
+ const doiIdentifier = record.resourceIdentifiers.find(
96
+ (id) =>
97
+ id.codeSpace?.toLowerCase().includes('doi.org') ||
98
+ id.code.startsWith('10.')
99
+ )
100
+
101
+ if (!doiIdentifier) return null
102
+
103
+ return {
104
+ code: doiIdentifier.code,
105
+ url: doiIdentifier.url ? doiIdentifier.url : null,
106
+ }
107
+ }),
108
+ shareReplay(1)
109
+ )
110
+
92
111
  apiLinks$ = this.allLinks$.pipe(
93
112
  map((links) =>
94
113
  links.filter((link) => this.linkClassifier.hasUsage(link, LinkUsage.API))
@@ -11,7 +11,6 @@ export const FIELDS_SUMMARY: FieldName[] = [
11
11
  'resourceAbstractObject',
12
12
  'overview',
13
13
  'logo',
14
- 'codelist_status_text',
15
14
  'link',
16
15
  'linkProtocol',
17
16
  'contactForResource*.organisation*',
@@ -14,6 +14,7 @@ export * from './lib/markdown-editor/markdown-editor.component'
14
14
  export * from './lib/markdown-parser/markdown-parser.component'
15
15
  export * from './lib/metadata-catalog/metadata-catalog.component'
16
16
  export * from './lib/metadata-contact/metadata-contact.component'
17
+ export * from './lib/metadata-doi/metadata-doi.component'
17
18
  export * from './lib/metadata-info/metadata-info.component'
18
19
  export * from './lib/metadata-quality-item/metadata-quality-item.component'
19
20
  export * from './lib/metadata-quality/metadata-quality.component'
@@ -26,3 +27,4 @@ export * from './lib/application-banner/application-banner.component'
26
27
  export * from './lib/internal-link-card/internal-link-card.component'
27
28
  export * from './lib/service-capabilities/service-capabilities.component'
28
29
  export * from './lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component'
30
+ export * from './lib/stac-items-result-grid/stac-items-result-grid.component'