geonetwork-ui 2.10.0-dev.fc6515c0b → 2.11.0-dev.2478042b2

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 (185) hide show
  1. package/fesm2022/geonetwork-ui.mjs +2326 -6755
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +309 -219
  4. package/index.d.ts.map +1 -1
  5. package/package.json +32 -42
  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 +49 -18
  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/elasticsearch.model.ts +13 -1
  25. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  26. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +11 -0
  27. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +21 -0
  28. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +52 -0
  29. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +24 -1
  30. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +77 -0
  31. package/src/libs/api/metadata-converter/src/lib/iso19139/utils/association-type.mapper.ts +12 -0
  32. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +79 -0
  33. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +8 -4
  34. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +25 -5
  35. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +106 -56
  36. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  37. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  38. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +37 -2
  39. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +61 -5
  40. package/src/libs/common/domain/src/lib/model/search/sort-by.model.ts +1 -5
  41. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  42. package/src/libs/common/domain/src/lib/model/user/group.model.ts +8 -0
  43. package/src/libs/common/domain/src/lib/model/user/index.ts +1 -0
  44. package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
  45. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +4 -3
  46. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +62 -0
  47. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  48. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +3 -2
  49. package/src/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.ts +2 -1
  50. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +22 -22
  51. package/src/libs/feature/editor/src/index.ts +1 -0
  52. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
  53. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
  54. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
  55. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  56. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.css +0 -0
  57. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.html +68 -0
  58. package/src/libs/feature/editor/src/lib/components/contact-details/contact-details-form.component.ts +41 -0
  59. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
  60. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
  61. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  62. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  63. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +4 -1
  64. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.css +0 -0
  65. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.html +33 -0
  66. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-associated-records/form-field-associated-records.component.ts +94 -0
  67. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +7 -7
  68. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.html +9 -2
  69. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +12 -0
  70. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  71. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  72. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  73. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  74. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-temporal-extents/form-field-temporal-extents.component.html +16 -12
  75. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-topics/form-field-topics.component.ts +2 -2
  76. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  77. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  78. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +0 -34
  79. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +34 -16
  80. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +17 -0
  81. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  82. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  83. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +76 -19
  84. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  85. package/src/libs/feature/editor/src/lib/fields.config.ts +359 -337
  86. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -3
  87. package/src/libs/feature/editor/src/lib/services/editor.service.ts +9 -13
  88. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  89. package/src/libs/feature/notify-reuse/src/index.ts +1 -0
  90. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.css +0 -0
  91. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.html +23 -0
  92. package/src/libs/feature/notify-reuse/src/lib/edit-delete-reuse-buttons/edit-delete-reuse-buttons.component.ts +114 -0
  93. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.html +111 -1
  94. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +219 -8
  95. package/src/libs/feature/notify-reuse/src/lib/utils/url.ts +16 -0
  96. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  97. package/src/libs/feature/record/src/lib/state/mdview.actions.ts +4 -8
  98. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +7 -16
  99. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -3
  100. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +4 -9
  101. package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +2 -7
  102. package/src/libs/feature/router/src/lib/default/router.service.ts +1 -1
  103. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  104. package/src/libs/feature/search/src/lib/sort-by/sort-by.component.ts +1 -1
  105. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  106. package/src/libs/ui/dataviz/src/index.ts +0 -1
  107. package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +6 -7
  108. package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +31 -19
  109. package/src/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.ts +2 -2
  110. package/src/libs/ui/elements/src/index.ts +1 -0
  111. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +48 -56
  112. package/src/libs/ui/elements/src/lib/contact-pill/contact-pill.component.html +7 -3
  113. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  114. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  115. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  116. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  117. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  118. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
  119. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
  120. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  121. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
  122. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +5 -8
  123. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
  124. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  125. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  126. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
  127. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
  128. package/src/libs/ui/inputs/src/lib/button/button.component.ts +4 -0
  129. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  130. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  131. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  132. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.css +0 -3
  133. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.html +11 -7
  134. package/src/libs/ui/inputs/src/lib/text-input/text-input.component.ts +56 -30
  135. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  136. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  137. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  138. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  139. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  140. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  141. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +4 -54
  142. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  143. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  144. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  145. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  146. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  147. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  148. package/src/libs/ui/widgets/src/lib/spinning-loader/spinning-loader.component.html +1 -1
  149. package/src/libs/util/app-config/src/lib/app-config.ts +35 -10
  150. package/src/libs/util/app-config/src/lib/model.ts +3 -0
  151. package/src/libs/util/app-config/src/lib/parse-utils.ts +27 -0
  152. package/src/libs/util/data-fetcher/src/lib/data-fetcher.ts +19 -22
  153. package/src/libs/util/data-fetcher/src/lib/engine/duckdb.ts +185 -0
  154. package/src/libs/util/data-fetcher/src/lib/engine/results.ts +63 -0
  155. package/src/libs/util/data-fetcher/src/lib/{sql-utils.ts → engine/sql-utils.ts} +28 -13
  156. package/src/libs/util/data-fetcher/src/lib/model.ts +2 -1
  157. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +53 -39
  158. package/src/libs/util/data-fetcher/src/lib/readers/base.ts +11 -0
  159. package/src/libs/util/data-fetcher/src/lib/readers/csv.ts +9 -47
  160. package/src/libs/util/data-fetcher/src/lib/readers/excel.ts +27 -27
  161. package/src/libs/util/data-fetcher/src/lib/readers/geojson.ts +5 -24
  162. package/src/libs/util/data-fetcher/src/lib/readers/gml.ts +5 -49
  163. package/src/libs/util/data-fetcher/src/lib/readers/json.ts +5 -23
  164. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +183 -124
  165. package/src/libs/util/data-fetcher/src/lib/utils.ts +0 -143
  166. package/src/libs/util/i18n/src/index.ts +0 -1
  167. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  168. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  169. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  170. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  171. package/src/libs/util/shared/src/lib/links/link-utils.ts +23 -1
  172. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  173. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  174. package/style.css +0 -1
  175. package/tailwind.base.css +15 -0
  176. package/translations/de.json +124 -51
  177. package/translations/en.json +129 -56
  178. package/translations/es.json +97 -24
  179. package/translations/fr.json +126 -53
  180. package/translations/it.json +125 -52
  181. package/translations/nl.json +96 -23
  182. package/translations/pt.json +97 -24
  183. package/translations/sk.json +98 -25
  184. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
  185. package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +0 -14
@@ -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,
@@ -12,11 +12,13 @@ import {
12
12
  } from '../../../../../../../libs/common/domain/src/lib/model/record'
13
13
  import { KeywordType } from '../../../../../../../libs/common/domain/src/lib/model/thesaurus'
14
14
  import { UserModel } from '../../../../../../../libs/common/domain/src/lib/model/user/user.model'
15
+ import { GroupModel } from '../../../../../../../libs/common/domain/src/lib/model/user/group.model'
15
16
  import {
16
17
  PlatformServiceInterface,
17
18
  UploadEvent,
18
19
  } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
19
20
  import {
21
+ GroupsApiService,
20
22
  MeApiService,
21
23
  RecordsApiService,
22
24
  RegistriesApiService,
@@ -57,6 +59,7 @@ export const DISABLE_AUTH = new InjectionToken<boolean>('gnDisableAuth', {
57
59
  export class Gn4PlatformService implements PlatformServiceInterface {
58
60
  private meApi = inject(MeApiService)
59
61
  private usersApi = inject(UsersApiService)
62
+ private groupsApi = inject(GroupsApiService)
60
63
  private mapper = inject(Gn4PlatformMapper)
61
64
  private toolsApiService = inject(ToolsApiService)
62
65
  private registriesApiService = inject(RegistriesApiService)
@@ -97,7 +100,7 @@ export class Gn4PlatformService implements PlatformServiceInterface {
97
100
  private keywordsByThesauri: Record<string, Observable<Keyword[]>> = {}
98
101
 
99
102
  private get lang3() {
100
- return toLang3(this.translateService.currentLang)
103
+ return toLang3(this.translateService.getCurrentLang())
101
104
  }
102
105
 
103
106
  constructor() {
@@ -155,6 +158,38 @@ export class Gn4PlatformService implements PlatformServiceInterface {
155
158
  return this.users$
156
159
  }
157
160
 
161
+ getUserPermissionsByGroup(): Observable<GroupModel[]> {
162
+ if (this.disableAuth) return of([])
163
+ return combineLatest([this.meApi.getMe(), this.groupsApi.getGroups()]).pipe(
164
+ map(([meResponse, groups]) => {
165
+ if (!meResponse) return []
166
+ if (meResponse.admin) {
167
+ return groups.map((group) => ({
168
+ groupId: group.id,
169
+ groupName: group.name,
170
+ isMember: true,
171
+ canEdit: true,
172
+ canApprove: true,
173
+ canAdministrate: true,
174
+ }))
175
+ }
176
+ const reviewerIds = meResponse.groupsWithReviewer ?? []
177
+ const editorIds = meResponse.groupsWithEditor ?? []
178
+ const memberIds = meResponse.groupsWithRegisteredUser ?? []
179
+ const adminIds = meResponse.groupsWithUserAdmin ?? []
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
+ }))
189
+ })
190
+ )
191
+ }
192
+
158
193
  translateKey(key: string): Observable<string> {
159
194
  // if the key is a URI, use the registries API to look for the translation
160
195
  if (key.match(/^https?:\/\//)) {
@@ -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
@@ -254,10 +251,67 @@ export interface DatasetTemporalExtent {
254
251
  end?: Date
255
252
  }
256
253
 
254
+ /**
255
+ * Represents a source dataset referenced from a lineage entry.
256
+ */
257
+ export interface SourceRecord {
258
+ uuid?: string
259
+ title?: string
260
+ href?: string
261
+ }
262
+
263
+ marker('domain.record.associationType.crossReference')
264
+ marker('domain.record.associationType.largerWorkCitation')
265
+ marker('domain.record.associationType.partOfSeamlessDatabase')
266
+ marker('domain.record.associationType.stereoMate')
267
+ marker('domain.record.associationType.isComposedOf')
268
+ marker('domain.record.associationType.collectiveTitle')
269
+ marker('domain.record.associationType.series')
270
+ marker('domain.record.associationType.dependency')
271
+ marker('domain.record.associationType.revisionOf')
272
+
273
+ // DS_AssociationTypeCode values of the ISO19115-3 codelist, any unrecognized value
274
+ // being mapped to 'crossReference'
275
+ export const associationTypeValues = [
276
+ 'crossReference',
277
+ 'largerWorkCitation',
278
+ 'partOfSeamlessDatabase',
279
+ 'stereoMate',
280
+ 'isComposedOf',
281
+ 'collectiveTitle',
282
+ 'series',
283
+ 'dependency',
284
+ 'revisionOf',
285
+ ] as const
286
+
287
+ export type AssociationType = (typeof associationTypeValues)[number]
288
+
289
+ /**
290
+ * Represents another record associated with this one (e.g. a parent/sibling dataset).
291
+ */
292
+ export interface AssociatedRecord {
293
+ uniqueIdentifier: string
294
+ associationType: AssociationType
295
+ }
296
+
297
+ /**
298
+ * Nature of the link between a record and another one; the association type is
299
+ * only known for 'sibling' relations, as it is held by the declaring record.
300
+ */
301
+ export type RecordRelation = 'source' | 'sourceOf' | 'sibling' | 'associated'
302
+
303
+ export interface LinkedRecord {
304
+ record: CatalogRecord
305
+ relation: RecordRelation
306
+ associationType?: AssociationType
307
+ }
308
+
257
309
  export interface DatasetRecord extends BaseRecord {
258
310
  kind: 'dataset'
259
311
  status: RecordStatus
260
312
  lineage: string // Explanation of the origin of this record (e.g: how, why)"
313
+ sourceRecords: Array<SourceRecord>
314
+ associatedRecords: Array<AssociatedRecord>
261
315
  onlineResources: Array<DatasetOnlineResource>
262
316
  spatialExtents: Array<DatasetSpatialExtent>
263
317
  temporalExtents: Array<DatasetTemporalExtent>
@@ -285,6 +339,8 @@ export interface ServiceRecord extends BaseRecord {
285
339
  export interface ReuseRecord extends BaseRecord {
286
340
  kind: 'reuse'
287
341
  lineage: string // Explanation of the origin of this record (e.g: how, why)"
342
+ sourceRecords: Array<SourceRecord>
343
+ associatedRecords: Array<AssociatedRecord>
288
344
  onlineResources: Array<DatasetOnlineResource>
289
345
  reuseType: ReuseType
290
346
  spatialExtents: Array<DatasetSpatialExtent>
@@ -6,9 +6,5 @@ export const SortByEnum: Record<string, SortByField> = {
6
6
  RELEVANCY: ['desc', '_score'],
7
7
  QUALITY_SCORE: ['desc', 'qualityScore'],
8
8
  CHANGE_DATE: ['desc', 'changeDate'],
9
- RESOURCE_DATES: [
10
- ['desc', 'revisionDateForResource'],
11
- ['desc', 'publicationDateForResource'],
12
- ['desc', 'creationDateForResource'],
13
- ],
9
+ RESOURCE_DATE: ['desc', 'resourceDate.date'],
14
10
  }
@@ -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
@@ -0,0 +1,8 @@
1
+ export interface GroupModel {
2
+ groupId: number
3
+ groupName: string
4
+ isMember: boolean
5
+ canEdit: boolean
6
+ canApprove: boolean
7
+ canAdministrate: boolean
8
+ }
@@ -1 +1,2 @@
1
1
  export * from './user.model'
2
+ export * from './group.model'
@@ -1,5 +1,6 @@
1
1
  import type { Observable } from 'rxjs'
2
2
  import type { UserModel } from './model/user/user.model'
3
+ import type { GroupModel } from './model/user/group.model'
3
4
  import type { Organization } from './model/record/organization.model'
4
5
  import { CatalogRecord, Keyword, UserFeedback } from './model/record'
5
6
  import { KeywordType } from './model/thesaurus'
@@ -28,6 +29,7 @@ export abstract class PlatformServiceInterface {
28
29
  abstract getMe(): Observable<UserModel>
29
30
  abstract isAnonymous(): Observable<boolean>
30
31
  abstract getUsers(): Observable<UserModel[]>
32
+ abstract getUserPermissionsByGroup(): Observable<GroupModel[]>
31
33
  abstract getUsersByOrganization(
32
34
  organisation: Organization
33
35
  ): Observable<UserModel[]>
@@ -10,6 +10,7 @@ import {
10
10
  CatalogRecord,
11
11
  DatasetFeatureCatalog,
12
12
  LanguageCode,
13
+ LinkedRecord,
13
14
  } from '../model/record'
14
15
 
15
16
  export abstract class RecordsRepositoryInterface {
@@ -23,8 +24,7 @@ export abstract class RecordsRepositoryInterface {
23
24
  abstract getSimilarRecords(
24
25
  similarTo: CatalogRecord
25
26
  ): Observable<CatalogRecord[]>
26
- abstract getSources(record: CatalogRecord): Observable<CatalogRecord[]>
27
- abstract getSourceOf(record: CatalogRecord): Observable<CatalogRecord[]>
27
+ abstract getLinkedRecords(record: CatalogRecord): Observable<LinkedRecord[]>
28
28
  abstract fuzzySearch(query: string): Observable<SearchResults>
29
29
  abstract canDuplicate(record: CatalogRecord): boolean
30
30
  abstract canDelete(record: CatalogRecord): Observable<boolean>
@@ -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
 
@@ -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
  }
@@ -2,9 +2,9 @@ import {
2
2
  ChangeDetectionStrategy,
3
3
  ChangeDetectorRef,
4
4
  Component,
5
+ inject,
5
6
  Input,
6
7
  Output,
7
- inject,
8
8
  } from '@angular/core'
9
9
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
10
10
  import {
@@ -183,7 +183,7 @@ export class ChartViewComponent {
183
183
  yChoices$ = this.properties$.pipe(
184
184
  map((properties) =>
185
185
  properties
186
- .filter((prop) => prop.type === 'number' || prop.type === 'date')
186
+ .filter((prop) => prop.type === 'number')
187
187
  .map((prop) => ({ value: prop.name, label: prop.label || prop.name }))
188
188
  ),
189
189
  tap((choices) => {
@@ -222,6 +222,7 @@ export class ChartViewComponent {
222
222
  switchMap(([dataset, xProp, yProp, aggregation]) => {
223
223
  const fieldAgg: FieldAggregation =
224
224
  aggregation === 'count' ? ['count'] : [aggregation, yProp]
225
+ this.loading = true
225
226
  return dataset
226
227
  .groupBy(['distinct', xProp])
227
228
  .aggregate(fieldAgg)
@@ -2,11 +2,11 @@ import {
2
2
  ChangeDetectionStrategy,
3
3
  ChangeDetectorRef,
4
4
  Component,
5
+ inject,
5
6
  Input,
6
7
  OnDestroy,
7
8
  OnInit,
8
9
  ViewChild,
9
- inject,
10
10
  } from '@angular/core'
11
11
  import {
12
12
  DataTableComponent,
@@ -75,6 +75,7 @@ export class GeoTableViewComponent implements OnInit, OnDestroy {
75
75
  }
76
76
 
77
77
  private async initMapContext(): Promise<MapContext> {
78
+ this.dataset.load()
78
79
  this.dataset.selectAll()
79
80
  return {
80
81
  layers: [
@@ -1,15 +1,15 @@
1
- import { Injectable, inject } from '@angular/core'
1
+ import { inject, Injectable } from '@angular/core'
2
2
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
3
3
  import {
4
+ GetCollectionItemsOptions,
4
5
  OgcApiCollectionInfo,
5
6
  OgcApiEndpoint,
6
7
  OgcApiRecord,
7
- WfsEndpoint,
8
- WfsVersion,
9
- TmsEndpoint,
10
8
  StacEndpoint,
11
- GetCollectionItemsOptions,
12
9
  StacItemsDocument,
10
+ TmsEndpoint,
11
+ WfsEndpoint,
12
+ WfsVersion,
13
13
  } from '@camptocamp/ogc-client'
14
14
  import {
15
15
  BaseReader,
@@ -26,7 +26,7 @@ import {
26
26
  } from '../../../../../../libs/util/shared/src'
27
27
  import type { FeatureCollection } from 'geojson'
28
28
  import { from, Observable, throwError } from 'rxjs'
29
- import { catchError, map, switchMap, tap } from 'rxjs/operators'
29
+ import { catchError, map, switchMap } from 'rxjs/operators'
30
30
  import {
31
31
  DatasetOnlineResource,
32
32
  DatasetServiceDistribution,
@@ -347,14 +347,11 @@ export class DataService {
347
347
  if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
348
348
  const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString())
349
349
  return from(
350
- openDataset(
351
- wfsUrlEndpoint,
352
- 'wfs',
353
- {
354
- wfsFeatureType: link.name,
355
- },
356
- cacheActive
357
- )
350
+ openDataset(wfsUrlEndpoint, {
351
+ typeHint: 'wfs',
352
+ wfsFeatureType: link.name,
353
+ enableCache: cacheActive,
354
+ })
358
355
  )
359
356
  } else if (link.type === 'download') {
360
357
  const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString())
@@ -364,7 +361,10 @@ export class DataService {
364
361
  ? (format as SupportedType)
365
362
  : undefined
366
363
  return from(
367
- openDataset(linkProxifiedUrl, supportedType, undefined, cacheActive)
364
+ openDataset(linkProxifiedUrl, {
365
+ typeHint: supportedType,
366
+ enableCache: cacheActive,
367
+ })
368
368
  ).pipe()
369
369
  } else if (
370
370
  link.type === 'service' &&
@@ -374,7 +374,9 @@ export class DataService {
374
374
  link.url.toString(),
375
375
  'geojson'
376
376
  )
377
- return from(openDataset(url, 'geojson', undefined, cacheActive)).pipe()
377
+ return from(
378
+ openDataset(url, { typeHint: 'geojson', enableCache: cacheActive })
379
+ ).pipe()
378
380
  } else if (
379
381
  link.type === 'service' &&
380
382
  link.accessServiceProtocol === 'ogcFeatures'
@@ -395,12 +397,10 @@ export class DataService {
395
397
  }
396
398
  const urlWithoutLimit = new URL(geojsonUrl)
397
399
  urlWithoutLimit.searchParams.delete('limit')
398
- return openDataset(
399
- urlWithoutLimit.toString(),
400
- 'geojson',
401
- undefined,
402
- cacheActive
403
- )
400
+ return openDataset(urlWithoutLimit.toString(), {
401
+ typeHint: 'geojson',
402
+ enableCache: cacheActive,
403
+ })
404
404
  })
405
405
  )
406
406
  }
@@ -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,