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
@@ -5,12 +5,12 @@
5
5
  >
6
6
  @for (item of items; track trackByFn(index); let index = $index) {
7
7
  <div class="sortable-box bg-white flex items-center" cdkDrag>
8
- <span
8
+ <ng-icon
9
9
  cdkDragHandle
10
- class="material-symbols-outlined mx-[10px] cursor-grab gn-ui-icon-medium flex-none"
11
- >
12
- drag_handle
13
- </span>
10
+ name="matDragHandleOutline"
11
+ size="20"
12
+ class="mx-[10px] cursor-grab flex-none"
13
+ ></ng-icon>
14
14
  <div class="flex-1">
15
15
  <ng-container
16
16
  *ngTemplateOutlet="
@@ -29,8 +29,8 @@
29
29
  class="ml-[8px] mr-[10px]"
30
30
  (buttonClick)="removeItem(index)"
31
31
  data-test="remove-item"
32
- ><span class="material-symbols-outlined gn-ui-icon-medium">close</span>
33
- </gn-ui-button>
32
+ ><ng-icon name="matCloseOutline" size="20"></ng-icon
33
+ ></gn-ui-button>
34
34
  </div>
35
35
  }
36
36
  </div>
@@ -15,6 +15,11 @@ import {
15
15
  TemplateRef,
16
16
  } from '@angular/core'
17
17
  import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
18
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
19
+ import {
20
+ matCloseOutline,
21
+ matDragHandleOutline,
22
+ } from '@ng-icons/material-icons/outline'
18
23
 
19
24
  @Component({
20
25
  selector: 'gn-ui-sortable-list',
@@ -22,7 +27,15 @@ import { ButtonComponent } from '../../../../../../libs/ui/inputs/src'
22
27
  styleUrls: ['sortable-list.component.css'],
23
28
  changeDetection: ChangeDetectionStrategy.OnPush,
24
29
  standalone: true,
25
- imports: [CommonModule, CdkDropList, CdkDrag, CdkDragHandle, ButtonComponent],
30
+ imports: [
31
+ CommonModule,
32
+ CdkDropList,
33
+ CdkDrag,
34
+ CdkDragHandle,
35
+ ButtonComponent,
36
+ NgIconComponent,
37
+ ],
38
+ providers: [provideIcons({ matDragHandleOutline, matCloseOutline })],
26
39
  })
27
40
  export class SortableListComponent {
28
41
  @Input() elementTemplate: TemplateRef<unknown>
@@ -1,18 +1,11 @@
1
1
  import { ChangeDetectorRef, Component, inject, Input } from '@angular/core'
2
2
  import { CommonModule } from '@angular/common'
3
- import { Geometry } from 'geojson'
4
- import { GeoJSONFeatureCollection } from 'ol/format/GeoJSON.js'
5
- import GeoJSON from 'ol/format/GeoJSON.js'
6
- import { Polygon } from 'ol/geom.js'
7
- import {
8
- createViewFromLayer,
9
- MapContext,
10
- MapContextLayer,
11
- } from '@geospatial-sdk/core'
3
+ import { createViewFromLayer, MapContext } from '@geospatial-sdk/core'
12
4
  import { MapContainerComponent } from '../map-container/map-container.component'
13
5
  import { BehaviorSubject, from, Observable, of } from 'rxjs'
14
6
  import { map, switchMap, tap } from 'rxjs/operators'
15
7
  import { DatasetSpatialExtent } from '../../../../../../../libs/common/domain/src/lib/model/record'
8
+ import { createSpatialExtentLayer } from '../../map-utils'
16
9
 
17
10
  @Component({
18
11
  selector: 'gn-ui-spatial-extent',
@@ -30,39 +23,10 @@ export class SpatialExtentComponent {
30
23
  spatialExtents$ = new BehaviorSubject<DatasetSpatialExtent[]>([])
31
24
  mapContext$: Observable<MapContext> = this.spatialExtents$.pipe(
32
25
  switchMap((extents) => {
33
- if (extents.length === 0) {
26
+ const layer = createSpatialExtentLayer(extents)
27
+ if (!layer) {
34
28
  return of(null)
35
29
  }
36
- const featureCollection: GeoJSONFeatureCollection = {
37
- type: 'FeatureCollection',
38
- features: [],
39
- }
40
- extents.forEach((extent) => {
41
- if (extent.geometry) {
42
- featureCollection.features.push({
43
- type: 'Feature',
44
- properties: {},
45
- geometry: extent.geometry,
46
- })
47
- } else if (extent.bbox?.length >= 0) {
48
- featureCollection.features.push({
49
- type: 'Feature',
50
- properties: {},
51
- geometry: this.bboxCoordsToGeometry(extent.bbox),
52
- })
53
- }
54
- })
55
-
56
- const layer: MapContextLayer = {
57
- type: 'geojson',
58
- data: featureCollection,
59
- label: 'Spatial extents',
60
- style: {
61
- 'stroke-color': 'black',
62
- 'stroke-width': 2,
63
- 'fill-color': 'rgba(153, 153, 153, 0.3)',
64
- },
65
- }
66
30
  return from(createViewFromLayer(layer)).pipe(
67
31
  map((view) => ({ view, layers: [layer] }) as MapContext),
68
32
  tap(() => this._cdr.markForCheck())
@@ -71,18 +35,4 @@ export class SpatialExtentComponent {
71
35
  )
72
36
 
73
37
  error = ''
74
-
75
- bboxCoordsToGeometry(bbox: [number, number, number, number]): Geometry {
76
- const geometry = new Polygon([
77
- [
78
- [bbox[0], bbox[1]],
79
- [bbox[0], bbox[3]],
80
- [bbox[2], bbox[3]],
81
- [bbox[2], bbox[1]],
82
- [bbox[0], bbox[1]],
83
- ],
84
- ])
85
-
86
- return new GeoJSON().writeGeometryObject(geometry)
87
- }
88
38
  }
@@ -12,6 +12,54 @@ import {
12
12
  MouseWheelZoom,
13
13
  } from 'ol/interaction.js'
14
14
  import MapBrowserEvent from 'ol/MapBrowserEvent.js'
15
+ import type { DatasetSpatialExtent } from '../../../../../libs/common/domain/src/lib/model/record'
16
+ import type {
17
+ MapContextLayer,
18
+ MapContextLayerGeojson,
19
+ } from '@geospatial-sdk/core'
20
+ import { spatialExtentsToFeatureCollection } from '../../../../../libs/util/shared/src'
21
+
22
+ export type SpatialExtentLayerStyle = NonNullable<
23
+ MapContextLayerGeojson['style']
24
+ >
25
+
26
+ /**
27
+ * Default style for a spatial-extent layer: a solid black outline over a
28
+ * translucent grey fill.
29
+ */
30
+ export const DEFAULT_SPATIAL_EXTENT_STYLE: SpatialExtentLayerStyle = {
31
+ 'stroke-color': 'black',
32
+ 'stroke-width': 2,
33
+ 'fill-color': 'rgba(153, 153, 153, 0.3)',
34
+ }
35
+
36
+ /**
37
+ * Builds a GeoJSON map layer drawing the given spatial extents: each extent is
38
+ * rendered from its own geometry or, when only a bounding box is available,
39
+ * from a polygon derived from that box.
40
+ *
41
+ * @returns the layer, or `null` when none of the extents can be represented.
42
+ */
43
+ export function createSpatialExtentLayer(
44
+ extents: DatasetSpatialExtent[],
45
+ overrides?: {
46
+ label?: string
47
+ clickable?: boolean
48
+ style?: SpatialExtentLayerStyle
49
+ }
50
+ ): MapContextLayer | null {
51
+ const data = spatialExtentsToFeatureCollection(extents)
52
+ if (data.features.length === 0) {
53
+ return null
54
+ }
55
+ return {
56
+ type: 'geojson',
57
+ data,
58
+ label: 'Spatial extents',
59
+ style: DEFAULT_SPATIAL_EXTENT_STYLE,
60
+ ...overrides,
61
+ }
62
+ }
15
63
 
16
64
  export function prioritizePageScroll(interactions: Collection<Interaction>) {
17
65
  interactions.clear()
@@ -52,7 +52,7 @@ export class RecordPreviewFeedComponent extends RecordPreviewComponent {
52
52
  protected elementRef: ElementRef
53
53
  private translate = inject(TranslateService)
54
54
 
55
- timeFormat = new Duration(this.translate.currentLang, {})
55
+ timeFormat = new Duration(this.translate.getCurrentLang(), {})
56
56
 
57
57
  constructor() {
58
58
  const elementRef = inject(ElementRef)
@@ -52,10 +52,10 @@
52
52
  class="w-72 p-6 flex flex-col gap-3 mt-2 border border-gray-100 bg-white shadow-2xl rounded-2xl"
53
53
  >
54
54
  <span class="text-lg font-bold text-center">{{
55
- 'editor.record.delete.confirmation.title' | translate
55
+ 'editor.record.delete.confirmation.title' | translate: { recordKind }
56
56
  }}</span>
57
57
  <span class="text-center">{{
58
- 'editor.record.delete.confirmation.message' | translate
58
+ 'editor.record.delete.confirmation.message' | translate: { recordKind }
59
59
  }}</span>
60
60
  <div class="flex flex-row gap-8 justify-center">
61
61
  <gn-ui-button
@@ -65,14 +65,16 @@
65
65
  data-cy="confirm-button"
66
66
  [style.--gn-ui-button-width]="'100px'"
67
67
  >{{
68
- 'editor.record.delete.confirmation.confirmText' | translate
68
+ 'editor.record.delete.confirmation.confirmText'
69
+ | translate: { recordKind }
69
70
  }}</gn-ui-button
70
71
  >
71
72
  <gn-ui-button
72
73
  [style.--gn-ui-button-width]="'100px'"
73
74
  (buttonClick)="closeActionMenu.emit()"
74
75
  >{{
75
- 'editor.record.delete.confirmation.cancelText' | translate
76
+ 'editor.record.delete.confirmation.cancelText'
77
+ | translate: { recordKind }
76
78
  }}</gn-ui-button
77
79
  >
78
80
  </div>
@@ -84,10 +86,10 @@
84
86
  class="w-80 p-6 flex flex-col gap-3 mt-2 border border-gray-100 bg-white shadow-2xl rounded-2xl"
85
87
  >
86
88
  <span class="text-lg font-bold text-center">{{
87
- 'editor.record.undo.confirmation.title' | translate
89
+ 'editor.record.undo.confirmation.title' | translate: { recordKind }
88
90
  }}</span>
89
91
  <span class="text-center">{{
90
- 'editor.record.undo.confirmation.message' | translate
92
+ 'editor.record.undo.confirmation.message' | translate: { recordKind }
91
93
  }}</span>
92
94
  <div class="flex flex-row gap-8 justify-center">
93
95
  <gn-ui-button
@@ -97,14 +99,16 @@
97
99
  data-cy="confirm-button"
98
100
  [style.--gn-ui-button-width]="'120px'"
99
101
  >{{
100
- 'editor.record.undo.confirmation.confirmText' | translate
102
+ 'editor.record.undo.confirmation.confirmText'
103
+ | translate: { recordKind }
101
104
  }}</gn-ui-button
102
105
  >
103
106
  <gn-ui-button
104
107
  [style.--gn-ui-button-width]="'120px'"
105
108
  (buttonClick)="closeActionMenu.emit()"
106
109
  >{{
107
- 'editor.record.undo.confirmation.cancelText' | translate
110
+ 'editor.record.undo.confirmation.cancelText'
111
+ | translate: { recordKind }
108
112
  }}</gn-ui-button
109
113
  >
110
114
  </div>
@@ -2,15 +2,16 @@ import {
2
2
  ChangeDetectorRef,
3
3
  Component,
4
4
  EventEmitter,
5
+ inject,
5
6
  Input,
6
7
  Output,
7
8
  ViewChild,
8
- inject,
9
9
  } from '@angular/core'
10
10
  import { MatDialog, MatDialogModule } from '@angular/material/dialog'
11
11
  import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'
12
12
  import { ButtonComponent } from '../../../../../../../libs/ui/inputs/src'
13
13
  import { TranslateDirective, TranslatePipe } from '@ngx-translate/core'
14
+ import { RecordKind } from '../../../../../../../libs/common/domain/src/lib/model'
14
15
 
15
16
  type ActionMenuPage = 'mainMenu' | 'deleteMenu' | 'rollbackMenu'
16
17
 
@@ -35,6 +36,7 @@ export class ActionMenuComponent {
35
36
  @Input() isDuplicating: boolean
36
37
  @Input() canDelete = true
37
38
  @Input() page: 'draft' | 'main' | 'record'
39
+ @Input() recordKind: RecordKind
38
40
  @Output() duplicate = new EventEmitter<void>()
39
41
  @Output() delete = new EventEmitter<void>()
40
42
  @Output() closeActionMenu = new EventEmitter<void>()
@@ -172,6 +172,7 @@
172
172
  (delete)="handleDelete(item)"
173
173
  (closeActionMenu)="closeActionMenu()"
174
174
  (rollback)="handleRollback(item)"
175
+ [recordKind]="item.kind"
175
176
  >
176
177
  </gn-ui-action-menu>
177
178
  </ng-template>
@@ -28,7 +28,13 @@ export class PopoverComponent implements AfterViewInit, OnChanges, OnDestroy {
28
28
 
29
29
  @ViewChild('popoverContent', { static: false }) popoverContent: ElementRef
30
30
  @Input() content: string | TemplateRef<any>
31
- @Input() theme: 'light' | 'light-border' | 'translucent' | 'material' | ''
31
+ @Input() theme:
32
+ | 'light'
33
+ | 'light-border'
34
+ | 'translucent'
35
+ | 'material'
36
+ | 'dark'
37
+ | ''
32
38
 
33
39
  private tippyInstance: Instance
34
40
  private view: EmbeddedViewRef<any>
@@ -1,6 +1,6 @@
1
1
  <span>
2
2
  <svg
3
- class="animate-spin h-8 w-8 text-primary"
3
+ class="animate-spin"
4
4
  xmlns="http://www.w3.org/2000/svg"
5
5
  fill="none"
6
6
  viewBox="0 0 24 24"
@@ -2,6 +2,7 @@ import * as TOML from '@ltd/j-toml'
2
2
  import {
3
3
  checkMetadataLanguage,
4
4
  checkNewRecordDefaultLanguage,
5
+ checkNewRecordStandard,
5
6
  parseConfigSection,
6
7
  parseMultiConfigSection,
7
8
  parseTranslationsConfigSection,
@@ -17,10 +18,15 @@ import {
17
18
  SearchConfig,
18
19
  ThemeConfig,
19
20
  } from './model'
20
- import { TranslateCompiler, TranslateLoader } from '@ngx-translate/core'
21
+ import {
22
+ TranslateCompiler,
23
+ TranslateLoader,
24
+ TranslateModuleConfig,
25
+ } from '@ngx-translate/core'
21
26
  import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler'
22
- import { HttpClient } from '@angular/common/http'
23
27
  import { FileWithOverridesTranslateLoader } from './i18n/file-with-overrides.translate.loader'
28
+ import { TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader'
29
+ import { HttpClient } from '@angular/common/http'
24
30
 
25
31
  const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
26
32
  This error might show up in case of an invalid/malformed configuration file.
@@ -297,7 +303,7 @@ export function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
297
303
  parsed,
298
304
  'editing',
299
305
  [],
300
- ['new_record_default_language'],
306
+ ['new_record_default_language', 'new_record_standard'],
301
307
  warnings,
302
308
  errors
303
309
  )
@@ -310,6 +316,15 @@ export function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
310
316
  warnings
311
317
  )
312
318
  }
319
+ if (
320
+ parsedEditingSection !== null &&
321
+ parsedEditingSection.new_record_standard !== undefined
322
+ ) {
323
+ parsedEditingSection = checkNewRecordStandard(
324
+ parsedEditingSection,
325
+ warnings
326
+ )
327
+ }
313
328
  editorConfig =
314
329
  parsedEditingSection === null
315
330
  ? null
@@ -318,6 +333,9 @@ export function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
318
333
  parsedEditingSection.new_record_default_language as
319
334
  | string
320
335
  | undefined,
336
+ NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard as
337
+ | EditorConfig['NEW_RECORD_STANDARD']
338
+ | undefined,
321
339
  } as EditorConfig)
322
340
 
323
341
  customTranslations = parseTranslationsConfigSection(
@@ -348,16 +366,23 @@ export function _reset() {
348
366
  customTranslations = null
349
367
  }
350
368
 
351
- export const TRANSLATE_WITH_OVERRIDES_CONFIG = {
369
+ export const TRANSLATE_WITH_OVERRIDES_CONFIG: TranslateModuleConfig = {
352
370
  compiler: {
353
371
  provide: TranslateCompiler,
354
372
  useClass: TranslateMessageFormatCompiler,
355
373
  },
356
- loader: {
357
- provide: TranslateLoader,
358
- useFactory: function HttpLoaderFactory(http: HttpClient) {
359
- return new FileWithOverridesTranslateLoader(http, './assets/i18n/')
374
+ loader: [
375
+ {
376
+ provide: TRANSLATE_HTTP_LOADER_CONFIG,
377
+ useValue: {
378
+ prefix: './assets/i18n/',
379
+ suffix: '.json',
380
+ },
360
381
  },
361
- deps: [HttpClient],
362
- },
382
+ {
383
+ provide: TranslateLoader,
384
+ useClass: FileWithOverridesTranslateLoader,
385
+ deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
386
+ },
387
+ ],
363
388
  }
@@ -69,8 +69,11 @@ export interface MetadataQualityConfig {
69
69
  ENABLED: boolean
70
70
  }
71
71
 
72
+ export type NewRecordStandard = 'iso19139' | 'iso19115-3'
73
+
72
74
  export interface EditorConfig {
73
75
  NEW_RECORD_DEFAULT_LANGUAGE?: string
76
+ NEW_RECORD_STANDARD?: NewRecordStandard
74
77
  }
75
78
 
76
79
  export type CustomTranslations = { [translationKey: string]: string }
@@ -159,3 +159,30 @@ export function checkNewRecordDefaultLanguage(
159
159
  new_record_default_language: lang2,
160
160
  }
161
161
  }
162
+
163
+ export function checkNewRecordStandard(
164
+ parsedConfigSection: any,
165
+ outWarnings: string[]
166
+ ) {
167
+ const standard = parsedConfigSection.new_record_standard
168
+ const normalizedStandard =
169
+ typeof standard === 'string' ? standard.trim().toLowerCase() : null
170
+
171
+ if (
172
+ normalizedStandard === 'iso19139' ||
173
+ normalizedStandard === 'iso19115-3'
174
+ ) {
175
+ return {
176
+ ...parsedConfigSection,
177
+ new_record_standard: normalizedStandard,
178
+ }
179
+ }
180
+
181
+ outWarnings.push(
182
+ `In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`
183
+ )
184
+ return {
185
+ ...parsedConfigSection,
186
+ new_record_standard: undefined,
187
+ }
188
+ }
@@ -7,20 +7,19 @@ import { DataItem, DatasetHeaders, FetchError, SupportedType } from './model'
7
7
  import { inferDatasetType } from './utils'
8
8
  import { BaseReader } from './readers/base'
9
9
  import { GmlReader } from './readers/gml'
10
- import { WfsVersion } from '@camptocamp/ogc-client'
11
10
  import { WfsReader } from './readers/wfs'
12
11
 
12
+ interface OpenDatasetOptions {
13
+ typeHint?: SupportedType
14
+ wfsFeatureType?: string
15
+ enableCache?: boolean // by default cache will be used if this is not set to false
16
+ }
17
+
13
18
  export async function openDataset(
14
19
  url: string,
15
- typeHint?: SupportedType,
16
- options?: {
17
- namespace?: string
18
- wfsVersion?: WfsVersion
19
- wfsFeatureType?: string
20
- },
21
- cacheActive?: boolean
20
+ options?: OpenDatasetOptions
22
21
  ): Promise<BaseReader> {
23
- const fileType = await inferDatasetType(url, typeHint)
22
+ const fileType = await inferDatasetType(url, options?.typeHint)
24
23
  let reader:
25
24
  | CsvReader
26
25
  | JsonReader
@@ -43,19 +42,19 @@ export async function openDataset(
43
42
  reader = new ExcelReader(url)
44
43
  break
45
44
  case 'gml':
46
- reader = new GmlReader(url, options.namespace, options.wfsVersion)
45
+ reader = new GmlReader(url)
47
46
  break
48
47
  case 'wfs':
49
- reader = await WfsReader.createReader(url, options.wfsFeatureType)
48
+ reader = new WfsReader(url, options?.wfsFeatureType)
50
49
  break
51
50
  }
52
- reader.setCacheActive(cacheActive)
51
+ reader.enableCache(options?.enableCache ?? true)
53
52
  reader.load()
54
53
  return reader
55
- } catch (e: any) {
56
- //WfsReader may already raise a FetchError
54
+ } catch (e: unknown) {
55
+ // WfsReader may already raise a FetchError
57
56
  if (e instanceof FetchError) throw e
58
- else throw FetchError.parsingFailed(e.message)
57
+ else throw FetchError.parsingFailed((e as Error).message)
59
58
  }
60
59
  }
61
60
 
@@ -63,22 +62,20 @@ export async function openDataset(
63
62
  * This fetches the full dataset at the given URL and parses it according to its mime type.
64
63
  * All items in the dataset are converted to GeoJSON features, even if they do not bear any spatial geometry.
65
64
  * File type can be either inferred (from the HTTP headers or the URL), or hinted using the 2nd argument
66
- * File type is determined liked so:
65
+ * File type is determined like so:
67
66
  * 1. if a type hint is given, use it
68
67
  * 2. otherwise, look for a Content-Type header in the response with a supported mime type
69
68
  * 3. if no valid mime type was found, look for an explicit file extension in the url (.csv, .geojson etc.)
70
69
  */
71
70
  export async function readDataset(
72
71
  url: string,
73
- typeHint?: SupportedType,
74
- options?: any,
75
- cacheActive = true
72
+ options?: OpenDatasetOptions
76
73
  ): Promise<DataItem[]> {
77
- const reader = await openDataset(url, typeHint, options, cacheActive)
74
+ const reader = await openDataset(url, options)
78
75
  try {
79
76
  return await reader.read()
80
- } catch (e: any) {
81
- throw FetchError.parsingFailed(e.message)
77
+ } catch (e: unknown) {
78
+ throw FetchError.parsingFailed((e as Error).message)
82
79
  }
83
80
  }
84
81