geonetwork-ui 2.10.0-dev.fc6515c0b → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1459 -6139
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +214 -171
  4. package/index.d.ts.map +1 -1
  5. package/package.json +25 -35
  6. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +20 -0
  7. package/src/libs/api/metadata-converter/src/lib/fixtures/eu.dcat-ap.records.ts +4 -0
  8. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +23 -0
  9. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+ongules.ts +8 -0
  10. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.reuse+roilaye.ts +2 -0
  11. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +2 -0
  12. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +2 -0
  13. package/src/libs/api/metadata-converter/src/lib/fixtures/georhena.records.ts +2 -0
  14. package/src/libs/api/metadata-converter/src/lib/fixtures/metadata-for-i18n.records.ts +4 -0
  15. package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +23 -0
  16. package/src/libs/api/metadata-converter/src/lib/fixtures/opendataswiss.records.ts +2 -0
  17. package/src/libs/api/metadata-converter/src/lib/fixtures/sextant.records.ts +4 -0
  18. package/src/libs/api/metadata-converter/src/lib/fixtures/vlaanderen.dcat-ap.records.ts +2 -0
  19. package/src/libs/api/metadata-converter/src/lib/fixtures/wallonie.records.reuse.ts +9 -0
  20. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
  21. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.converter.ts +2 -0
  22. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +6 -5
  23. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  24. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  25. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +11 -0
  26. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +21 -0
  27. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +52 -0
  28. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +24 -1
  29. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +73 -0
  30. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +79 -0
  31. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +8 -4
  32. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  33. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +66 -40
  34. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  35. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  36. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +37 -2
  37. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +23 -5
  38. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  39. package/src/libs/common/domain/src/lib/model/user/group.model.ts +8 -0
  40. package/src/libs/common/domain/src/lib/model/user/index.ts +1 -0
  41. package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
  42. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +2 -1
  43. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +62 -0
  44. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  45. package/src/libs/feature/editor/src/index.ts +1 -0
  46. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
  47. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
  48. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
  49. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  50. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.css +0 -0
  51. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +68 -0
  52. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +41 -0
  53. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
  54. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
  55. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  56. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  57. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +4 -1
  58. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +7 -7
  59. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +9 -2
  60. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +12 -0
  61. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  62. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  63. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  64. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  65. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
  66. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  67. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  68. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +0 -34
  69. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +28 -16
  70. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -0
  71. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  72. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  73. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +76 -19
  74. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  75. package/src/libs/feature/editor/src/lib/fields.config.ts +354 -337
  76. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -3
  77. package/src/libs/feature/editor/src/lib/services/editor.service.ts +9 -13
  78. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  79. package/src/libs/feature/notify-reuse/src/index.ts +1 -0
  80. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
  81. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
  82. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
  83. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -1
  84. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +219 -8
  85. package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
  86. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  87. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  88. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  89. package/src/libs/ui/dataviz/src/index.ts +0 -1
  90. package/src/libs/ui/elements/src/index.ts +1 -0
  91. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +48 -56
  92. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +7 -3
  93. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  94. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  95. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  96. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  97. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  98. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
  99. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
  100. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  101. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
  102. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +5 -8
  103. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
  104. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  105. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  106. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
  107. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
  108. package/src/libs/ui/inputs/src/lib/button/button.component.ts +4 -0
  109. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  110. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  111. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  112. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
  113. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
  114. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
  115. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  116. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  117. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  118. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  119. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  120. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  121. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +4 -54
  122. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  123. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  124. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  125. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  126. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  127. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  128. package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
  129. package/src/libs/util/app-config/src/lib/app-config.ts +35 -10
  130. package/src/libs/util/app-config/src/lib/model.ts +3 -0
  131. package/src/libs/util/app-config/src/lib/parse-utils.ts +27 -0
  132. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
  133. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
  134. package/src/libs/util/i18n/src/index.ts +0 -1
  135. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  136. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  137. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  138. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  139. package/src/libs/util/shared/src/lib/links/link-utils.ts +23 -1
  140. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  141. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  142. package/style.css +0 -1
  143. package/tailwind.base.css +15 -0
  144. package/translations/de.json +110 -50
  145. package/translations/en.json +115 -55
  146. package/translations/es.json +84 -24
  147. package/translations/fr.json +112 -52
  148. package/translations/it.json +111 -51
  149. package/translations/nl.json +83 -23
  150. package/translations/pt.json +84 -24
  151. package/translations/sk.json +84 -24
  152. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
@@ -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
 
@@ -134,6 +135,8 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
134
135
  lineage: `This record was edited manually to test the conversion processes
135
136
 
136
137
  As such, **it is not very interesting at all.**`,
138
+ sourceRecords: [],
139
+ associatedRecords: [],
137
140
  licenses: [
138
141
  {
139
142
  text: 'Licence ODbL mai 2013 (basée sur ODbL 1.0)',
@@ -310,6 +313,8 @@ Malgré l'attention portée à la création de ces données, il est rappelé que
310
313
  ],
311
314
  lineage: `Document d’urbanisme numérisé conformément aux prescriptions nationales du CNIG par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.
312
315
  Ce lot de données produit en 2019, a été numérisé à partir du PCI Vecteur de 2019 et contrôlé par le Service d'Information Géographique de l'Agglomération de la Région de Compiègne.`,
316
+ sourceRecords: [],
317
+ associatedRecords: [],
313
318
  legalConstraints: [],
314
319
  securityConstraints: [],
315
320
  otherConstraints: [],
@@ -361,6 +366,8 @@ export const simpleDatasetRecordFixture = (): DatasetRecord => ({
361
366
  overviews: [],
362
367
  spatialExtents: [],
363
368
  temporalExtents: [],
369
+ sourceRecords: [],
370
+ associatedRecords: [],
364
371
  onlineResources: [
365
372
  {
366
373
  type: 'download',
@@ -413,6 +420,8 @@ export const simpleDatasetRecordWithFcatsFixture = (): DatasetRecord => ({
413
420
  overviews: [],
414
421
  spatialExtents: [],
415
422
  temporalExtents: [],
423
+ sourceRecords: [],
424
+ associatedRecords: [],
416
425
  onlineResources: [],
417
426
  updateFrequency: { per: 'month', updatedTimes: 3 },
418
427
  translations: {},
@@ -978,6 +987,8 @@ export const multilingualDatasetFixture: () => DatasetRecord = () => ({
978
987
  title: 'English Title',
979
988
  abstract: 'English Abstract',
980
989
  lineage: 'English Lineage',
990
+ sourceRecords: [],
991
+ associatedRecords: [],
981
992
  translations: {
982
993
  title: { fr: 'Titre Français', de: 'Titel DE' },
983
994
  abstract: { fr: 'Résumé Français', de: 'Beschreibung DE' },
@@ -1022,3 +1033,54 @@ export const multilingualDatasetFixture: () => DatasetRecord = () => ({
1022
1033
  topics: [],
1023
1034
  recordUpdated: null,
1024
1035
  })
1036
+
1037
+ export const simpleReuseRecordFixture = (): ReuseRecord => ({
1038
+ abstract: `Sample reuse record`,
1039
+ kind: 'reuse',
1040
+ reuseType: 'application',
1041
+ recordUpdated: new Date('2023-03-17T07:38:08.875Z'),
1042
+ recordPublished: null,
1043
+ ownerOrganization: null,
1044
+ licenses: [],
1045
+ legalConstraints: [],
1046
+ securityConstraints: [],
1047
+ otherConstraints: [],
1048
+ contacts: [],
1049
+ contactsForResource: [],
1050
+ keywords: [],
1051
+ topics: [],
1052
+ spatialExtents: [],
1053
+ temporalExtents: [],
1054
+ lineage: 'bla',
1055
+ sourceRecords: [],
1056
+ associatedRecords: [],
1057
+ overviews: [],
1058
+ defaultLanguage: null,
1059
+ otherLanguages: [],
1060
+ title: 'Sites de gestion des déchets miniers - Service de visualisation WMS',
1061
+ onlineResources: [
1062
+ {
1063
+ name: 'Rapport de disponibilité du service WMS',
1064
+ description:
1065
+ '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".',
1066
+ mimeType: 'text/html',
1067
+ type: 'link',
1068
+ url: new URL(
1069
+ 'https://geoservices.wallonie.be/rapportDisponibilite/wms/sites_de_gestion_des_dechets_miniers_srie.html'
1070
+ ),
1071
+ accessRestricted: false,
1072
+ },
1073
+ ],
1074
+ uniqueIdentifier: '00b22798-ec8e-4500-89e8-90eeeda45919',
1075
+ landingPage: new URL(
1076
+ 'http://localhost:4200/geonetwork/srv/fre/catalog.search#/metadata/00b22798-ec8e-4500-89e8-90eeeda45919'
1077
+ ),
1078
+ extras: {
1079
+ isPublishedToAll: true,
1080
+ id: '723',
1081
+ isHarvested: true,
1082
+ ownerInfo: 'admin|admin|admin|Administrator',
1083
+ edit: true,
1084
+ },
1085
+ recordCreated: new Date('2023-03-17T07:38:08.875Z'),
1086
+ })
@@ -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,
@@ -0,0 +1,68 @@
1
+ <div class="flex flex-col gap-7">
2
+ <div class="grid grid-cols-2 gap-4">
3
+ <div class="min-w-0">
4
+ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
5
+ editor.record.form.field.contactDetails.lastName
6
+ </h3>
7
+ <gn-ui-text-input
8
+ class="block w-full"
9
+ extraClass="w-full"
10
+ [value]="contact.lastName ?? ''"
11
+ (valueChange)="handleChange({ lastName: $event })"
12
+ [placeholder]="
13
+ 'editor.record.form.field.contactDetails.lastName.placeholder'
14
+ | translate
15
+ "
16
+ data-test="contactDetailsLastName"
17
+ ></gn-ui-text-input>
18
+ </div>
19
+ <div class="min-w-0">
20
+ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
21
+ editor.record.form.field.contactDetails.firstName
22
+ </h3>
23
+ <gn-ui-text-input
24
+ class="block w-full"
25
+ extraClass="w-full"
26
+ [value]="contact.firstName ?? ''"
27
+ (valueChange)="handleChange({ firstName: $event })"
28
+ [placeholder]="
29
+ 'editor.record.form.field.contactDetails.firstName.placeholder'
30
+ | translate
31
+ "
32
+ data-test="contactDetailsFirstName"
33
+ ></gn-ui-text-input>
34
+ </div>
35
+ </div>
36
+ <div>
37
+ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
38
+ editor.record.form.field.contactDetails.email
39
+ </h3>
40
+ <gn-ui-text-input
41
+ class="block w-full"
42
+ extraClass="w-full"
43
+ [type]="'email'"
44
+ [value]="contact.email ?? ''"
45
+ (valueChange)="handleChange({ email: $event })"
46
+ [placeholder]="
47
+ 'editor.record.form.field.contactDetails.email.placeholder' | translate
48
+ "
49
+ data-test="contactDetailsEmail"
50
+ ></gn-ui-text-input>
51
+ </div>
52
+ <div>
53
+ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
54
+ editor.record.form.field.contactDetails.organization
55
+ </h3>
56
+ <gn-ui-text-input
57
+ class="block w-full"
58
+ extraClass="w-full"
59
+ [value]="contact.organization?.name ?? ''"
60
+ (valueChange)="handleOrganizationChange({ name: $event })"
61
+ [placeholder]="
62
+ 'editor.record.form.field.contactDetails.organization.placeholder'
63
+ | translate
64
+ "
65
+ data-test="contactDetailsOrganization"
66
+ ></gn-ui-text-input>
67
+ </div>
68
+ </div>
@@ -0,0 +1,41 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ EventEmitter,
5
+ Input,
6
+ Output,
7
+ } from '@angular/core'
8
+ import {
9
+ Individual,
10
+ Organization,
11
+ } from '../../../../../../../libs/common/domain/src/lib/model/record'
12
+ import { TextInputComponent } from '../../../../../../../libs/ui/inputs/src'
13
+ import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
14
+
15
+ @Component({
16
+ selector: 'gn-ui-contact-details-form',
17
+ templateUrl: './contact-details-form.component.html',
18
+ styleUrls: ['./contact-details-form.component.css'],
19
+ changeDetection: ChangeDetectionStrategy.OnPush,
20
+ standalone: true,
21
+ imports: [TextInputComponent, TranslateDirective, TranslatePipe],
22
+ })
23
+ export class ContactDetailsFormComponent {
24
+ @Input() contact: Individual
25
+ @Output() contactChange = new EventEmitter<Individual>()
26
+
27
+ // emit a fresh contact on each change; never mutate the @Input
28
+ handleChange(change: Partial<Individual>) {
29
+ this.contactChange.emit({ ...this.contact, ...change })
30
+ }
31
+
32
+ handleOrganizationChange(change: Partial<Organization>) {
33
+ this.contactChange.emit({
34
+ ...this.contact,
35
+ organization: {
36
+ ...(this.contact.organization ?? ({} as Organization)),
37
+ ...change,
38
+ } as Organization,
39
+ })
40
+ }
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
  }
@@ -3,13 +3,13 @@
3
3
  editor.record.form.field.onlineResource.edit.protocol
4
4
  </h3>
5
5
  @if (protocolHint) {
6
- <span
7
- class="material-symbols-outlined m-2 gn-ui-icon-small"
6
+ <ng-icon
7
+ name="matHelpOutline"
8
+ size="16"
9
+ class="m-2"
8
10
  [matTooltip]="protocolHint"
9
11
  matTooltipPosition="above"
10
- >
11
- help
12
- </span>
12
+ ></ng-icon>
13
13
  }
14
14
  </div>
15
15
  <div class="flex flex-row items-center gap-4 h-[48px]">
@@ -30,6 +30,7 @@ import {
30
30
  provideNgIconsConfig,
31
31
  } from '@ng-icons/core'
32
32
  import { iconoirRefresh } from '@ng-icons/iconoir'
33
+ import { matHelpOutline } from '@ng-icons/material-icons/outline'
33
34
  import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
34
35
  import {
35
36
  BehaviorSubject,
@@ -65,7 +66,7 @@ marker(
65
66
  UrlInputComponent,
66
67
  ],
67
68
  providers: [
68
- provideIcons({ iconoirRefresh }),
69
+ provideIcons({ iconoirRefresh, matHelpOutline }),
69
70
  provideNgIconsConfig({
70
71
  size: '1.5em',
71
72
  }),
@@ -10,7 +10,7 @@ export class FieldFocusDirective {
10
10
 
11
11
  private el = inject(ElementRef)
12
12
 
13
- public focusField() {
13
+ public focusField(focusInnerTarget = true) {
14
14
  setTimeout(() => {
15
15
  const host = this.el.nativeElement as HTMLElement
16
16
  const glowClass = this.gnUiFieldFocusGlowClass
@@ -25,6 +25,9 @@ export class FieldFocusDirective {
25
25
  )
26
26
 
27
27
  host.scrollIntoView({ behavior: 'smooth', block: 'start' })
28
+ if (!focusInnerTarget) {
29
+ return
30
+ }
28
31
  const target =
29
32
  host.querySelector<HTMLElement>(
30
33
  'input, textarea, select, [contenteditable="true"]'
@@ -131,14 +131,14 @@ export class FormFieldConstraintsShortcutsComponent implements OnDestroy {
131
131
  map((c) => c.length > 0),
132
132
  distinctUntilChanged()
133
133
  )
134
- combineLatest([
135
- isConstraintNotEmpty$,
136
- this.anyToggleActivated$,
137
- ]).subscribe(([isNotEmpty, anyToggleActivated]) => {
138
- const visible = isNotEmpty && !anyToggleActivated
139
- this.editorFacade.setFieldVisibility({ model }, visible)
140
- })
134
+ combineLatest([isConstraintNotEmpty$, this.anyToggleActivated$])
135
+ .pipe(takeUntil(this.onDestroy$))
136
+ .subscribe(([isNotEmpty, anyToggleActivated]) => {
137
+ const visible = isNotEmpty && !anyToggleActivated
138
+ this.editorFacade.setFieldVisibility({ model }, visible)
139
+ })
141
140
  }
141
+ hideEmptyConstraints(this.legalConstraints$, 'legalConstraints')
142
142
  hideEmptyConstraints(this.securityConstraints$, 'securityConstraints')
143
143
  hideEmptyConstraints(this.otherConstraints$, 'otherConstraints')
144
144
  })
@@ -15,8 +15,15 @@
15
15
  (itemsOrderChange)="handleContactsChanged($event)"
16
16
  [elementTemplate]="contactTemplate"
17
17
  ></gn-ui-sortable-list>
18
- <ng-template #contactTemplate let-contact>
19
- <gn-ui-contact-card [contact]="contact"></gn-ui-contact-card>
18
+ <ng-template #contactTemplate let-contact let-index="index">
19
+ @if (modelSpecifier === 'contact:editableDetails') {
20
+ <gn-ui-contact-details-form
21
+ [contact]="contact"
22
+ (contactChange)="handleContactChanged($event, index)"
23
+ ></gn-ui-contact-details-form>
24
+ } @else {
25
+ <gn-ui-contact-card [contact]="contact"></gn-ui-contact-card>
26
+ }
20
27
  </ng-template>
21
28
  } @else {
22
29
  <div
@@ -28,6 +28,7 @@ import { UserModel } from '../../../../../../../../../libs/common/domain/src/lib
28
28
  import { PlatformServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/platform.service.interface'
29
29
  import { OrganizationsServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/organizations.service.interface'
30
30
  import { ContactCardComponent } from '../../../contact-card/contact-card.component'
31
+ import { ContactDetailsFormComponent } from '../../../contact-details/contact-details-form.component'
31
32
  import {
32
33
  createFuzzyFilter,
33
34
  getIndividualDisplayName,
@@ -35,6 +36,7 @@ import {
35
36
  } from '../../../../../../../../../libs/util/shared/src'
36
37
  import { map } from 'rxjs/operators'
37
38
  import { SortableListComponent } from '../../../../../../../../../libs/ui/layout/src'
39
+ import { FieldModelSpecifier } from '../../../../models/editor-config.model'
38
40
 
39
41
  @Component({
40
42
  selector: 'gn-ui-form-field-contacts',
@@ -47,6 +49,7 @@ import { SortableListComponent } from '../../../../../../../../../libs/ui/layout
47
49
  TranslateDirective,
48
50
  TranslatePipe,
49
51
  ContactCardComponent,
52
+ ContactDetailsFormComponent,
50
53
  SortableListComponent,
51
54
  ],
52
55
  })
@@ -56,6 +59,7 @@ export class FormFieldContactsComponent implements OnDestroy, OnChanges {
56
59
  private changeDetectorRef = inject(ChangeDetectorRef)
57
60
 
58
61
  @Input() value: Individual[]
62
+ @Input() modelSpecifier: FieldModelSpecifier
59
63
  @Output() valueChange: EventEmitter<Individual[]> = new EventEmitter()
60
64
 
61
65
  contacts: Individual[] = []
@@ -117,6 +121,14 @@ export class FormFieldContactsComponent implements OnDestroy, OnChanges {
117
121
  this.valueChange.emit(contacts)
118
122
  }
119
123
 
124
+ handleContactChanged(updatedContact: Individual, index: number) {
125
+ const contacts = this.contacts.map((contact, i) =>
126
+ i === index ? updatedContact : contact
127
+ )
128
+
129
+ this.handleContactsChanged(contacts)
130
+ }
131
+
120
132
  /**
121
133
  * gn-ui-autocomplete
122
134
  */
@@ -3,11 +3,11 @@ import {
3
3
  ChangeDetectorRef,
4
4
  Component,
5
5
  EventEmitter,
6
+ inject,
6
7
  Input,
7
8
  Output,
8
9
  TemplateRef,
9
10
  ViewChild,
10
- inject,
11
11
  } from '@angular/core'
12
12
  import { MatDialog } from '@angular/material/dialog'
13
13
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
@@ -3,11 +3,14 @@ import {
3
3
  ChangeDetectorRef,
4
4
  Component,
5
5
  EventEmitter,
6
+ inject,
6
7
  Input,
7
8
  Output,
8
- inject,
9
9
  } from '@angular/core'
10
- import { GraphicOverview } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
10
+ import {
11
+ GraphicOverview,
12
+ RecordKind,
13
+ } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
11
14
  import { ImageInputComponent } from '../../../../../../../../../libs/ui/elements/src'
12
15
  import { PlatformServiceInterface } from '../../../../../../../../../libs/common/domain/src/lib/platform.service.interface'
13
16
  import { NotificationsService } from '../../../../../../../../../libs/feature/notifications/src'
@@ -30,6 +33,7 @@ export class FormFieldOverviewsComponent {
30
33
  private cd = inject(ChangeDetectorRef)
31
34
 
32
35
  @Input() metadataUuid: string
36
+ @Input() recordKind: RecordKind
33
37
  @Input() value: Array<GraphicOverview>
34
38
  @Output() valueChange: EventEmitter<Array<GraphicOverview>> =
35
39
  new EventEmitter()
@@ -111,13 +115,16 @@ export class FormFieldOverviewsComponent {
111
115
  {
112
116
  type: 'error',
113
117
  title: this.translateService.instant(
114
- 'editor.record.resourceError.title'
118
+ 'editor.record.resourceError.title',
119
+ { recordKind: this.recordKind }
115
120
  ),
116
121
  text: `${this.translateService.instant(
117
- 'editor.record.resourceError.body'
122
+ 'editor.record.resourceError.body',
123
+ { recordKind: this.recordKind }
118
124
  )} ${error.message}`,
119
125
  closeMessage: this.translateService.instant(
120
- 'editor.record.resourceError.closeMessage'
126
+ 'editor.record.resourceError.closeMessage',
127
+ { recordKind: this.recordKind }
121
128
  ),
122
129
  },
123
130
  undefined,
@@ -9,11 +9,11 @@
9
9
  "
10
10
  (buttonClick)="togglePreview()"
11
11
  >
12
- <span
13
- class="material-symbols-outlined gn-ui-icon-small"
12
+ <ng-icon
13
+ [name]="preview ? 'matVisibilityOffOutline' : 'matVisibilityOutline'"
14
+ size="16"
14
15
  [ngClass]="{ 'text-primary': !preview }"
15
- >{{ preview ? 'visibility_off' : 'visibility' }}</span
16
- >
16
+ ></ng-icon>
17
17
  &nbsp;
18
18
  {{ preview ? 'Edit' : 'Preview' }}
19
19
  </gn-ui-button>