geonetwork-ui 2.10.0-dev.4d4299840 → 2.10.0-dev.4edf16e9b

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 (126) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1295 -6231
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +178 -171
  4. package/index.d.ts.map +1 -1
  5. package/package.json +25 -35
  6. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
  7. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +6 -5
  8. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  9. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  10. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +5 -1
  11. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +3 -0
  12. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +4 -1
  13. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +4 -4
  14. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  15. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +12 -8
  16. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  17. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  18. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -22
  19. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +2 -5
  20. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  21. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -1
  22. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +51 -0
  23. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  24. package/src/libs/feature/editor/src/index.ts +1 -0
  25. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
  26. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
  27. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
  28. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  29. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +7 -6
  30. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +10 -8
  31. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
  32. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
  33. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  34. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  35. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +4 -1
  36. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +7 -7
  37. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  38. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  39. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  40. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  41. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
  42. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  43. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  44. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +0 -34
  45. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +27 -16
  46. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -0
  47. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  48. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  49. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +76 -19
  50. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  51. package/src/libs/feature/editor/src/lib/fields.config.ts +354 -337
  52. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +6 -3
  53. package/src/libs/feature/editor/src/lib/services/editor.service.ts +8 -12
  54. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  55. package/src/libs/feature/notify-reuse/src/index.ts +1 -0
  56. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
  57. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
  58. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
  59. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -1
  60. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +210 -8
  61. package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
  62. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  63. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  64. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  65. package/src/libs/ui/dataviz/src/index.ts +0 -1
  66. package/src/libs/ui/elements/src/index.ts +1 -0
  67. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +48 -56
  68. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +7 -3
  69. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  70. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  71. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  72. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  73. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  74. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
  75. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
  76. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  77. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
  78. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +5 -8
  79. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
  80. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  81. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  82. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
  83. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
  84. package/src/libs/ui/inputs/src/lib/button/button.component.ts +4 -0
  85. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  86. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  87. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  88. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
  89. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
  90. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
  91. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  92. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  93. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  94. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  95. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  96. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  97. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +4 -54
  98. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  99. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  100. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  101. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  102. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  103. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  104. package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
  105. package/src/libs/util/app-config/src/lib/app-config.ts +21 -9
  106. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
  107. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
  108. package/src/libs/util/i18n/src/index.ts +0 -1
  109. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  110. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  111. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  112. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  113. package/src/libs/util/shared/src/lib/links/link-utils.ts +22 -0
  114. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  115. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  116. package/style.css +0 -1
  117. package/tailwind.base.css +15 -0
  118. package/translations/de.json +102 -49
  119. package/translations/en.json +112 -59
  120. package/translations/es.json +76 -23
  121. package/translations/fr.json +109 -56
  122. package/translations/it.json +103 -50
  123. package/translations/nl.json +75 -22
  124. package/translations/pt.json +76 -23
  125. package/translations/sk.json +76 -23
  126. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
@@ -14,7 +14,7 @@ import {
14
14
  toDate,
15
15
  } from './atomic-operations'
16
16
  import { MetadataUrlService } from './metadata-url.service'
17
- import { Injectable, inject } from '@angular/core'
17
+ import { inject, Injectable } from '@angular/core'
18
18
  import { getStatusFromStatusCode } from '../iso19139/utils/status.mapper'
19
19
  import { getUpdateFrequencyFromFrequencyCode } from '../iso19139/utils/update-frequency.mapper'
20
20
  import {
@@ -49,7 +49,7 @@ export class Gn4FieldMapper {
49
49
  private translateService = inject(TranslateService)
50
50
 
51
51
  private get getLocalizedIndexKey() {
52
- return `lang${toLang3(this.translateService.currentLang)}`
52
+ return `lang${toLang3(this.translateService.getCurrentLang())}`
53
53
  }
54
54
 
55
55
  protected fields: Record<string, EsFieldMapperFn> = {
@@ -84,7 +84,7 @@ export class Gn4FieldMapper {
84
84
  'resourceAbstractObject',
85
85
  this.getLocalizedIndexKey
86
86
  ),
87
- 'no title'
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[]>(source, 'allKeywords'),
244
- this.getLocalizedIndexKey
243
+ selectField<Record<string, Thesaurus>>(source, 'allKeywords'),
244
+ this.getLocalizedIndexKey,
245
+ source
245
246
  ),
246
247
  }),
247
248
  inspireTheme: (output, source) => ({
@@ -1,4 +1,4 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import { Configuration } from '../../../../../../libs/data-access/gn4/src'
3
3
  import { TranslateService } from '@ngx-translate/core'
4
4
  import { toLang3 } from '../../../../../../libs/util/i18n/src'
@@ -13,7 +13,7 @@ export class MetadataUrlService {
13
13
  getUrl(uuid: string, apiPath: string = this.apiConfiguration.basePath) {
14
14
  const prefix = `${apiPath}/../`
15
15
  return `${prefix}${toLang3(
16
- this.translate.currentLang
16
+ this.translate.getCurrentLang()
17
17
  )}/catalog.search#/metadata/${uuid}`
18
18
  }
19
19
  }
@@ -62,6 +62,7 @@ type ThesaurusName = string
62
62
  export interface Thesaurus {
63
63
  id?: string
64
64
  title?: string
65
+ multilingualTitle?: MultilingualField
65
66
  theme?: string
66
67
  link?: string
67
68
  keywords: MultilingualField[]
@@ -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,
@@ -566,7 +567,10 @@ export function writeOtherLanguages(record: DatasetRecord, rootEl: XmlElement) {
566
567
  )(rootEl)
567
568
  }
568
569
 
569
- export function writeSourceRecords(record: DatasetRecord, rootEl: XmlElement) {
570
+ export function writeSourceRecords(
571
+ record: DatasetRecord | ReuseRecord,
572
+ rootEl: XmlElement
573
+ ) {
570
574
  pipe(
571
575
  findNestedChildOrCreate('mdb:resourceLineage', 'mrl:LI_Lineage'),
572
576
  appendSourceRecords(record.sourceRecords)
@@ -417,6 +417,9 @@ export class Iso19139Converter extends BaseConverter<string> {
417
417
  this.writers['temporalExtents'](record, rootEl)
418
418
  fieldChanged('spatialExtents') &&
419
419
  this.writers['spatialExtents'](record, rootEl)
420
+ }
421
+
422
+ if (record.kind === 'dataset' || record.kind === 'reuse') {
420
423
  ;(fieldChanged('lineage') || fieldChanged('translations')) &&
421
424
  this.writers['lineage'](record, rootEl)
422
425
  fieldChanged('sourceRecords') &&
@@ -1252,7 +1252,10 @@ export function appendSourceRecords(
1252
1252
  )
1253
1253
  }
1254
1254
 
1255
- export function writeSourceRecords(record: DatasetRecord, rootEl: XmlElement) {
1255
+ export function writeSourceRecords(
1256
+ record: DatasetRecord | ReuseRecord,
1257
+ rootEl: XmlElement
1258
+ ) {
1256
1259
  pipe(
1257
1260
  findNestedChildOrCreate(
1258
1261
  'gmd:dataQualityInfo',
@@ -1,4 +1,4 @@
1
- import { Injectable, InjectionToken, inject } from '@angular/core'
1
+ import { inject, Injectable, InjectionToken } from '@angular/core'
2
2
  import { toLang2, toLang3 } from '../../../../../../../libs/util/i18n/src'
3
3
  import { TranslateService } from '@ngx-translate/core'
4
4
  import { Location } from '@angular/common'
@@ -48,8 +48,8 @@ export class AuthService {
48
48
  '${current_path}',
49
49
  this.location.prepareExternalUrl(this.location.path())
50
50
  )
51
- .replace('${lang2}', toLang2(this.translateService.currentLang))
52
- .replace('${lang3}', toLang3(this.translateService.currentLang))
51
+ .replace('${lang2}', toLang2(this.translateService.getCurrentLang()))
52
+ .replace('${lang3}', toLang3(this.translateService.getCurrentLang()))
53
53
  }
54
54
 
55
55
  get logoutUrl() {
@@ -59,7 +59,7 @@ export class AuthService {
59
59
  get settingsUrl() {
60
60
  return this.baseSettingsUrl.replace(
61
61
  '${lang3}',
62
- toLang3(this.translateService.currentLang)
62
+ toLang3(this.translateService.getCurrentLang())
63
63
  )
64
64
  }
65
65
  }
@@ -1,4 +1,4 @@
1
- import { Injectable, Injector, inject } from '@angular/core'
1
+ import { inject, Injectable, Injector } from '@angular/core'
2
2
  import type { Geometry } from 'geojson'
3
3
  import {
4
4
  ES_QUERY_FIELDS_PRIORITY,
@@ -234,7 +234,7 @@ export class ElasticsearchService {
234
234
  if (this.metadataLang) {
235
235
  const lang3 = toLang3(
236
236
  this.isCurrentSearchLang()
237
- ? this.translateService.currentLang
237
+ ? this.translateService.getCurrentLang()
238
238
  : this.metadataLang
239
239
  )
240
240
  return `lang${lang3}`
@@ -3,7 +3,7 @@ import {
3
3
  HttpErrorResponse,
4
4
  HttpHeaders,
5
5
  } from '@angular/common/http'
6
- import { Injectable, InjectionToken, inject } from '@angular/core'
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
- record.extras['edit'] &&
331
- (!record.extras['isHarvested'] || allowEditHarvested)
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
- record.kind === 'dataset' &&
341
- record.extras['edit'] &&
342
- (!record.extras['isHarvested'] || allowEditHarvested)
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))
@@ -52,7 +52,7 @@ export class OrganizationsFromGroupsService
52
52
  organisationsCount$ = this.organisations$.pipe(map((orgs) => orgs.length))
53
53
 
54
54
  private get lang3() {
55
- return toLang3(this.translateService.currentLang)
55
+ return toLang3(this.translateService.getCurrentLang())
56
56
  }
57
57
 
58
58
  constructor(
@@ -128,7 +128,7 @@ export class OrganizationsFromMetadataService
128
128
  ) {}
129
129
 
130
130
  private get langIndex() {
131
- return `lang${toLang3(this.translateService.currentLang)}`
131
+ return `lang${toLang3(this.translateService.getCurrentLang())}`
132
132
  }
133
133
 
134
134
  equalsNormalizedStrings(
@@ -1,5 +1,5 @@
1
1
  import { HttpClient, HttpEventType } from '@angular/common/http'
2
- import { Injectable, InjectionToken, inject } from '@angular/core'
2
+ import { inject, Injectable, InjectionToken } from '@angular/core'
3
3
  import {
4
4
  KeywordApiResponse,
5
5
  ThesaurusApiResponse,
@@ -100,7 +100,7 @@ export class Gn4PlatformService implements PlatformServiceInterface {
100
100
  private keywordsByThesauri: Record<string, Observable<Keyword[]>> = {}
101
101
 
102
102
  private get lang3() {
103
- return toLang3(this.translateService.currentLang)
103
+ return toLang3(this.translateService.getCurrentLang())
104
104
  }
105
105
 
106
106
  constructor() {
@@ -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
- const groupsById = new Map(groups.map((g) => [g.id, g]))
181
- return [
182
- ...new Set([
183
- ...reviewerIds,
184
- ...editorIds,
185
- ...groups.map((g) => g.id),
186
- ]),
187
- ]
188
- .filter((id) => groupsById.has(id))
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,15 +104,12 @@ 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
  }
110
112
 
111
- export interface INSPIRE_topic {
112
- value: string
113
- label: string
114
- }
115
-
116
113
  export interface ResourceIdentifier {
117
114
  code: string
118
115
  codeSpace?: string
@@ -1,7 +1,8 @@
1
1
  export type KeywordType = 'place' | 'temporal' | 'theme' | 'other'
2
2
 
3
3
  export interface ThesaurusModel {
4
- id: string
4
+ // absent when the source provides no identifier for the thesaurus
5
+ id?: string
5
6
  name?: string
6
7
  url?: URL
7
8
  thesaurusKey?: string
@@ -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
  /**
@@ -3,6 +3,7 @@ import {
3
3
  DatasetRecord,
4
4
  DatasetSpatialExtent,
5
5
  Keyword,
6
+ ReuseRecord,
6
7
  ServiceRecord,
7
8
  } from '../../../../../libs/common/domain/src/lib/model/record'
8
9
 
@@ -1027,3 +1028,53 @@ export const multilingualDatasetFixture: () => DatasetRecord = () => ({
1027
1028
  topics: [],
1028
1029
  recordUpdated: null,
1029
1030
  })
1031
+
1032
+ export const simpleReuseRecordFixture = (): ReuseRecord => ({
1033
+ abstract: `Sample reuse record`,
1034
+ kind: 'reuse',
1035
+ reuseType: 'application',
1036
+ recordUpdated: new Date('2023-03-17T07:38:08.875Z'),
1037
+ recordPublished: null,
1038
+ ownerOrganization: null,
1039
+ licenses: [],
1040
+ legalConstraints: [],
1041
+ securityConstraints: [],
1042
+ otherConstraints: [],
1043
+ contacts: [],
1044
+ contactsForResource: [],
1045
+ keywords: [],
1046
+ topics: [],
1047
+ spatialExtents: [],
1048
+ temporalExtents: [],
1049
+ lineage: 'bla',
1050
+ sourceRecords: [],
1051
+ overviews: [],
1052
+ defaultLanguage: null,
1053
+ otherLanguages: [],
1054
+ title: 'Sites de gestion des déchets miniers - Service de visualisation WMS',
1055
+ onlineResources: [
1056
+ {
1057
+ name: 'Rapport de disponibilité du service WMS',
1058
+ description:
1059
+ 'Ce service de visualisation WMS permet de consulter la série de couches de données "Sites de gestion des déchets miniers - Série".',
1060
+ mimeType: 'text/html',
1061
+ type: 'link',
1062
+ url: new URL(
1063
+ 'https://geoservices.wallonie.be/rapportDisponibilite/wms/sites_de_gestion_des_dechets_miniers_srie.html'
1064
+ ),
1065
+ accessRestricted: false,
1066
+ },
1067
+ ],
1068
+ uniqueIdentifier: '00b22798-ec8e-4500-89e8-90eeeda45919',
1069
+ landingPage: new URL(
1070
+ 'http://localhost:4200/geonetwork/srv/fre/catalog.search#/metadata/00b22798-ec8e-4500-89e8-90eeeda45919'
1071
+ ),
1072
+ extras: {
1073
+ isPublishedToAll: true,
1074
+ id: '723',
1075
+ isHarvested: true,
1076
+ ownerInfo: 'admin|admin|admin|Administrator',
1077
+ edit: true,
1078
+ },
1079
+ recordCreated: new Date('2023-03-17T07:38:08.875Z'),
1080
+ })
@@ -1,4 +1,4 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import { SourcesApiService } from '../../../../../../libs/data-access/gn4/src'
3
3
  import { Observable } from 'rxjs'
4
4
  import { filter, map, shareReplay } from 'rxjs/operators'
@@ -21,7 +21,10 @@ export class SourcesService {
21
21
  return this.sources$.pipe(
22
22
  map((sources) => sources.filter((source) => source.uuid === uuid)[0]),
23
23
  filter((source) => !!source),
24
- map((source) => source.label[toLang3(this.translateService.currentLang)])
24
+ map(
25
+ (source) =>
26
+ source.label[toLang3(this.translateService.getCurrentLang())]
27
+ )
25
28
  )
26
29
  }
27
30
  }
@@ -3,6 +3,7 @@ export * from './lib/+state/editor.facade'
3
3
  export * from './lib/+state/editor.models'
4
4
  export * from './lib/+state/editor.reducer'
5
5
  export * from './lib/+state/editor.selectors'
6
+ export * from './lib/components/contact-details/contact-details-form.component'
6
7
  export * from './lib/components/import-record/import-record.component'
7
8
  export * from './lib/components/metadata-quality-panel/metadata-quality-panel.component'
8
9
  export * from './lib/components/multilingual-panel/multilingual-panel.component'
@@ -29,7 +29,10 @@ export const markRecordAsChanged = createAction(
29
29
  '[Editor] Mark record as changed'
30
30
  )
31
31
 
32
- export const saveRecord = createAction('[Editor] Save record')
32
+ export const saveRecord = createAction(
33
+ '[Editor] Save record',
34
+ props<{ publish: boolean }>()
35
+ )
33
36
  export const saveRecordSuccess = createAction('[Editor] Save record success')
34
37
  export const saveRecordFailure = createAction(
35
38
  '[Editor] Save record failure',
@@ -28,30 +28,37 @@ export class EditorEffects {
28
28
  this.store.select(selectRecordSource),
29
29
  this.store.select(selectEditorConfig)
30
30
  ),
31
- switchMap(([, record, recordSource, fieldsConfig]) =>
32
- this.editorService.saveRecord(record, recordSource, fieldsConfig).pipe(
33
- switchMap(([savedRecord, savedRecordSource]) => {
34
- const actions: Action[] = [EditorActions.saveRecordSuccess()]
31
+ switchMap(([{ publish }, record, recordSource, fieldsConfig]) =>
32
+ this.editorService
33
+ .saveRecord(record, recordSource, fieldsConfig, publish)
34
+ .pipe(
35
+ switchMap(([savedRecord, savedRecordSource]) => {
36
+ const actions: Action[] = [EditorActions.saveRecordSuccess()]
37
+
38
+ if (publish) {
39
+ // saving without publishing doesn't unpublish
40
+ actions.push(EditorActions.isPublished({ isPublished: true }))
41
+ }
35
42
 
36
- if (!record?.uniqueIdentifier) {
37
- actions.push(
38
- EditorActions.openRecord({
39
- record: savedRecord,
40
- recordSource: savedRecordSource,
43
+ if (!record?.uniqueIdentifier) {
44
+ actions.push(
45
+ EditorActions.openRecord({
46
+ record: savedRecord,
47
+ recordSource: savedRecordSource,
48
+ })
49
+ )
50
+ }
51
+
52
+ return of(...actions)
53
+ }),
54
+ catchError((error) =>
55
+ of(
56
+ EditorActions.saveRecordFailure({
57
+ error,
41
58
  })
42
59
  )
43
- }
44
-
45
- return of(...actions)
46
- }),
47
- catchError((error) =>
48
- of(
49
- EditorActions.saveRecordFailure({
50
- error,
51
- })
52
60
  )
53
61
  )
54
- )
55
62
  )
56
63
  )
57
64
  )
@@ -54,7 +54,11 @@ export class EditorFacade {
54
54
  }
55
55
 
56
56
  saveRecord() {
57
- this.store.dispatch(EditorActions.saveRecord())
57
+ this.store.dispatch(EditorActions.saveRecord({ publish: false }))
58
+ }
59
+
60
+ saveAndPublishRecord() {
61
+ this.store.dispatch(EditorActions.saveRecord({ publish: true }))
58
62
  }
59
63
 
60
64
  undoRecordDraft() {
@@ -8,7 +8,6 @@ import {
8
8
 
9
9
  import { FormFieldRichComponent } from '../record-form/form-field/form-field-rich/form-field-rich.component'
10
10
  import { ButtonComponent, UrlInputComponent } from '../../../../../../../libs/ui/inputs/src'
11
- import { MatIconModule } from '@angular/material/icon'
12
11
  import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
13
12
  import { Constraint } from '../../../../../../../libs/common/domain/src/lib/model/record'
14
13
  import {
@@ -26,7 +25,6 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
26
25
  FormFieldRichComponent,
27
26
  UrlInputComponent,
28
27
  ButtonComponent,
29
- MatIconModule,
30
28
  TranslateDirective,
31
29
  TranslatePipe,
32
30
  NgIconComponent,
@@ -7,8 +7,8 @@
7
7
  <gn-ui-text-input
8
8
  class="block w-full"
9
9
  extraClass="w-full"
10
- [(value)]="contact.lastName"
11
- (valueChange)="emitContactChange()"
10
+ [value]="contact.lastName ?? ''"
11
+ (valueChange)="handleChange({ lastName: $event })"
12
12
  [placeholder]="
13
13
  'editor.record.form.field.contactDetails.lastName.placeholder'
14
14
  | translate
@@ -23,8 +23,8 @@
23
23
  <gn-ui-text-input
24
24
  class="block w-full"
25
25
  extraClass="w-full"
26
- [(value)]="contact.firstName"
27
- (valueChange)="emitContactChange()"
26
+ [value]="contact.firstName ?? ''"
27
+ (valueChange)="handleChange({ firstName: $event })"
28
28
  [placeholder]="
29
29
  'editor.record.form.field.contactDetails.firstName.placeholder'
30
30
  | translate
@@ -40,8 +40,9 @@
40
40
  <gn-ui-text-input
41
41
  class="block w-full"
42
42
  extraClass="w-full"
43
- [value]="contact.organization?.email ?? ''"
44
- (valueChange)="handleOrganizationChange({ email: $event })"
43
+ [type]="'email'"
44
+ [value]="contact.email ?? ''"
45
+ (valueChange)="handleChange({ email: $event })"
45
46
  [placeholder]="
46
47
  'editor.record.form.field.contactDetails.email.placeholder' | translate
47
48
  "
@@ -24,16 +24,18 @@ export class ContactDetailsFormComponent {
24
24
  @Input() contact: Individual
25
25
  @Output() contactChange = new EventEmitter<Individual>()
26
26
 
27
- emitContactChange() {
28
- this.contactChange.emit(this.contact)
27
+ // emit a fresh contact on each change; never mutate the @Input
28
+ handleChange(change: Partial<Individual>) {
29
+ this.contactChange.emit({ ...this.contact, ...change })
29
30
  }
30
31
 
31
32
  handleOrganizationChange(change: Partial<Organization>) {
32
- this.contact.organization = {
33
- ...(this.contact.organization ?? ({} as Organization)),
34
- ...change,
35
- } as Organization
36
-
37
- this.emitContactChange()
33
+ this.contactChange.emit({
34
+ ...this.contact,
35
+ organization: {
36
+ ...(this.contact.organization ?? ({} as Organization)),
37
+ ...change,
38
+ } as Organization,
39
+ })
38
40
  }
39
41
  }
@@ -11,20 +11,11 @@
11
11
  ></gn-ui-autocomplete>
12
12
  <div class="flex gap-2 flex-wrap">
13
13
  @for (keyword of keywords; track keyword) {
14
- <gn-ui-badge
15
- [removable]="true"
16
- (badgeRemoveClicked)="removeKeyword(keyword)"
17
- >{{ keyword.label }}
18
- @if (isPlaceWithoutExtent(keyword)) {
19
- <ng-icon
20
- [title]="
21
- 'editor.record.form.keywords.place.withoutExtent' | translate
22
- "
23
- class="badge-warning"
24
- name="matWarningAmberOutline"
25
- ></ng-icon>
26
- }
27
- </gn-ui-badge>
14
+ <gn-ui-keyword-badge
15
+ [keyword]="keyword"
16
+ [editable]="true"
17
+ (keywordRemove)="removeKeyword($event)"
18
+ ></gn-ui-keyword-badge>
28
19
  }
29
20
  </div>
30
21
  </div>
@@ -7,40 +7,20 @@ import {
7
7
  inject,
8
8
  } from '@angular/core'
9
9
  import { PlatformServiceInterface } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
10
- import { AutocompleteComponent, BadgeComponent } from '../../../../../../../libs/ui/inputs/src'
10
+ import { AutocompleteComponent } from '../../../../../../../libs/ui/inputs/src'
11
+ import { KeywordBadgeComponent } from '../../../../../../../libs/ui/elements/src'
11
12
  import { map } from 'rxjs'
12
13
  import { Keyword } from '../../../../../../../libs/common/domain/src/lib/model/record'
13
14
  import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
14
- import { TranslatePipe } from '@ngx-translate/core'
15
- import {
16
- NgIconComponent,
17
- provideIcons,
18
- provideNgIconsConfig,
19
- } from '@ng-icons/core'
20
- import { matWarningAmberOutline } from '@ng-icons/material-icons/outline'
21
15
 
22
16
  type AutocompleteItem = { title: string; value: Keyword }
23
17
 
24
18
  @Component({
25
19
  selector: 'gn-ui-generic-keywords',
26
20
  templateUrl: './generic-keywords.component.html',
27
- styleUrls: ['./generic-keywords.component.css'],
28
21
  changeDetection: ChangeDetectionStrategy.OnPush,
29
22
  standalone: true,
30
- imports: [
31
- AutocompleteComponent,
32
- NgIconComponent,
33
- BadgeComponent,
34
- TranslatePipe,
35
- ],
36
- providers: [
37
- provideIcons({
38
- matWarningAmberOutline,
39
- }),
40
- provideNgIconsConfig({
41
- size: '1.5em',
42
- }),
43
- ],
23
+ imports: [AutocompleteComponent, KeywordBadgeComponent],
44
24
  })
45
25
  export class GenericKeywordsComponent {
46
26
  private platformService = inject(PlatformServiceInterface)
@@ -87,9 +67,4 @@ export class GenericKeywordsComponent {
87
67
  this.changedKeywords.emit(this.keywords)
88
68
  this.deletedKeyword.emit(keyword)
89
69
  }
90
-
91
- isPlaceWithoutExtent(keyword: Keyword): boolean {
92
- if (keyword.type !== 'place') return false
93
- return !keyword.bbox
94
- }
95
70
  }