geonetwork-ui 2.7.0-dev.b9840dab3 → 2.7.0-dev.d3eeddaf5

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 (140) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/dcat-ap/read-parts.mjs +4 -7
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +20 -20
  3. package/esm2022/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.mjs +3 -3
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +3 -3
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +3 -3
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +4 -4
  7. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +5 -5
  8. package/esm2022/libs/api/repository/src/index.mjs +2 -2
  9. package/esm2022/libs/api/repository/src/lib/gn4/auth/auth.service.mjs +5 -5
  10. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +55 -12
  11. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +3 -3
  12. package/esm2022/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.mjs +3 -3
  13. package/esm2022/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.mjs +3 -3
  14. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +3 -3
  15. package/esm2022/libs/api/repository/src/lib/metadata-language.token.mjs +3 -0
  16. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +11 -1
  17. package/esm2022/libs/feature/catalog/src/lib/sources/sources.service.mjs +3 -3
  18. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.mjs +79 -0
  19. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +8 -3
  20. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/index.mjs +2 -1
  21. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +77 -1
  22. package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +3 -5
  23. package/esm2022/libs/feature/router/src/lib/default/state/query-params.utils.mjs +4 -3
  24. package/esm2022/libs/feature/router/src/lib/default/state/router.facade.mjs +3 -2
  25. package/esm2022/libs/feature/search/src/lib/state/reducer.mjs +5 -2
  26. package/esm2022/libs/ui/elements/src/lib/api-card/api-card.component.mjs +3 -3
  27. package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +1 -4
  28. package/esm2022/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.mjs +7 -7
  29. package/esm2022/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.mjs +1 -6
  30. package/esm2022/libs/util/app-config/src/lib/app-config.mjs +3 -1
  31. package/esm2022/libs/util/app-config/src/lib/fixtures.mjs +2 -2
  32. package/esm2022/libs/util/app-config/src/lib/model.mjs +1 -1
  33. package/esm2022/libs/util/app-config/src/lib/parse-utils.mjs +5 -4
  34. package/esm2022/libs/util/i18n/src/lib/language-codes.mjs +50 -9
  35. package/esm2022/libs/util/shared/src/lib/record/quality-score.util.mjs +9 -8
  36. package/esm2022/libs/util/shared/src/lib/utils/geojson.mjs +58 -1
  37. package/esm2022/translations/de.json +52 -20
  38. package/esm2022/translations/en.json +53 -21
  39. package/esm2022/translations/es.json +39 -7
  40. package/esm2022/translations/fr.json +57 -25
  41. package/esm2022/translations/it.json +52 -20
  42. package/esm2022/translations/nl.json +39 -7
  43. package/esm2022/translations/pt.json +39 -7
  44. package/esm2022/translations/sk.json +43 -11
  45. package/fesm2022/geonetwork-ui.mjs +3021 -2910
  46. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  47. package/libs/api/metadata-converter/src/lib/dcat-ap/read-parts.d.ts.map +1 -1
  48. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts +1 -1
  49. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  50. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +2 -2
  51. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  52. package/libs/api/repository/src/index.d.ts +1 -1
  53. package/libs/api/repository/src/index.d.ts.map +1 -1
  54. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts +1 -2
  55. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  56. package/libs/api/repository/src/lib/metadata-language.token.d.ts +5 -0
  57. package/libs/api/repository/src/lib/metadata-language.token.d.ts.map +1 -0
  58. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +5 -1
  59. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  60. package/libs/feature/catalog/src/lib/sources/sources.service.d.ts.map +1 -1
  61. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.d.ts +28 -0
  62. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.d.ts.map +1 -0
  63. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +1 -0
  64. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  65. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts +1 -0
  66. package/libs/feature/editor/src/lib/components/record-form/form-field/index.d.ts.map +1 -1
  67. package/libs/feature/editor/src/lib/fields.config.d.ts +8 -1
  68. package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
  69. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts +2 -2
  70. package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
  71. package/libs/feature/router/src/lib/default/state/query-params.utils.d.ts.map +1 -1
  72. package/libs/feature/router/src/lib/default/state/router.facade.d.ts.map +1 -1
  73. package/libs/feature/search/src/lib/state/reducer.d.ts.map +1 -1
  74. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts +0 -1
  75. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
  76. package/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.d.ts.map +1 -1
  77. package/libs/util/app-config/src/lib/app-config.d.ts.map +1 -1
  78. package/libs/util/app-config/src/lib/model.d.ts +1 -0
  79. package/libs/util/app-config/src/lib/model.d.ts.map +1 -1
  80. package/libs/util/app-config/src/lib/parse-utils.d.ts.map +1 -1
  81. package/libs/util/i18n/src/lib/language-codes.d.ts +91 -31
  82. package/libs/util/i18n/src/lib/language-codes.d.ts.map +1 -1
  83. package/libs/util/shared/src/lib/record/quality-score.util.d.ts.map +1 -1
  84. package/libs/util/shared/src/lib/utils/geojson.d.ts +7 -2
  85. package/libs/util/shared/src/lib/utils/geojson.d.ts.map +1 -1
  86. package/package.json +11 -10
  87. package/src/libs/api/metadata-converter/src/lib/dcat-ap/read-parts.ts +3 -6
  88. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +47 -22
  89. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  90. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +2 -2
  91. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +2 -2
  92. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +3 -3
  93. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +6 -6
  94. package/src/libs/api/repository/src/index.ts +1 -1
  95. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +4 -4
  96. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +65 -14
  97. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +2 -2
  98. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +2 -2
  99. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +2 -2
  100. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +2 -2
  101. package/src/libs/api/repository/src/lib/metadata-language.token.ts +8 -0
  102. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +17 -1
  103. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +2 -5
  104. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.css +0 -0
  105. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.html +20 -0
  106. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-inspire-field/form-field-inspire-theme.component.ts +85 -0
  107. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +6 -0
  108. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +5 -0
  109. package/src/libs/feature/editor/src/lib/components/record-form/form-field/index.ts +1 -0
  110. package/src/libs/feature/editor/src/lib/fields.config.ts +85 -1
  111. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +8 -8
  112. package/src/libs/feature/router/src/lib/default/state/query-params.utils.ts +5 -2
  113. package/src/libs/feature/router/src/lib/default/state/router.facade.ts +2 -1
  114. package/src/libs/feature/search/src/lib/state/reducer.ts +4 -1
  115. package/src/libs/ui/elements/src/lib/api-card/api-card.component.html +4 -1
  116. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +0 -4
  117. package/src/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.ts +6 -6
  118. package/src/libs/ui/elements/src/lib/service-capabilities/service-capabilities.component.ts +0 -6
  119. package/src/libs/util/app-config/src/lib/app-config.ts +2 -0
  120. package/src/libs/util/app-config/src/lib/fixtures.ts +1 -1
  121. package/src/libs/util/app-config/src/lib/model.ts +1 -0
  122. package/src/libs/util/app-config/src/lib/parse-utils.ts +4 -7
  123. package/src/libs/util/i18n/src/lib/language-codes.ts +62 -11
  124. package/src/libs/util/shared/src/lib/record/quality-score.util.ts +13 -10
  125. package/src/libs/util/shared/src/lib/utils/geojson.ts +72 -2
  126. package/translations/de.json +52 -20
  127. package/translations/en.json +53 -21
  128. package/translations/es.json +39 -7
  129. package/translations/fr.json +57 -25
  130. package/translations/it.json +52 -20
  131. package/translations/nl.json +39 -7
  132. package/translations/pt.json +39 -7
  133. package/translations/sk.json +43 -11
  134. package/esm2022/libs/api/repository/src/lib/metadata-language.mjs +0 -3
  135. package/esm2022/libs/util/app-config/src/lib/constants.mjs +0 -439
  136. package/libs/api/repository/src/lib/metadata-language.d.ts +0 -3
  137. package/libs/api/repository/src/lib/metadata-language.d.ts.map +0 -1
  138. package/libs/util/app-config/src/lib/constants.d.ts +0 -2
  139. package/libs/util/app-config/src/lib/constants.d.ts.map +0 -1
  140. package/src/libs/api/repository/src/lib/metadata-language.ts +0 -3
@@ -108,6 +108,11 @@ export interface Keyword {
108
108
  translations?: KeywordTranslations
109
109
  }
110
110
 
111
+ export interface INSPIRE_theme {
112
+ value: string
113
+ label: string
114
+ }
115
+
111
116
  export interface BaseRecord {
112
117
  uniqueIdentifier: Uuid
113
118
  ownerOrganization: Organization
@@ -160,6 +165,17 @@ export type ServiceProtocol =
160
165
  | 'maplibre-style'
161
166
  | 'other'
162
167
 
168
+ marker('record.metadata.api.accessServiceProtocol.wms')
169
+ marker('record.metadata.api.accessServiceProtocol.wfs')
170
+ marker('record.metadata.api.accessServiceProtocol.wps')
171
+ marker('record.metadata.api.accessServiceProtocol.wmts')
172
+ marker('record.metadata.api.accessServiceProtocol.esriRest')
173
+ marker('record.metadata.api.accessServiceProtocol.ogcFeatures')
174
+ marker('record.metadata.api.accessServiceProtocol.GPFDL')
175
+ marker('record.metadata.api.accessServiceProtocol.tms')
176
+ marker('record.metadata.api.accessServiceProtocol.maplibre-style')
177
+ marker('record.metadata.api.accessServiceProtocol.other')
178
+
163
179
  export type OnlineResourceType = 'service' | 'download' | 'link' | 'endpoint'
164
180
 
165
181
  export interface DatasetServiceDistribution {
@@ -258,7 +274,7 @@ export interface ServiceRecord extends BaseRecord {
258
274
  export interface ReuseRecord extends BaseRecord {
259
275
  kind: 'reuse'
260
276
  lineage: string // Explanation of the origin of this record (e.g: how, why)"
261
- onlineResources: Array<OnlineLinkResource>
277
+ onlineResources: Array<DatasetOnlineResource>
262
278
  reuseType: ReuseType
263
279
  spatialExtents: Array<DatasetSpatialExtent>
264
280
  temporalExtents: Array<DatasetTemporalExtent>
@@ -4,7 +4,7 @@ import { Observable } from 'rxjs'
4
4
  import { filter, map, shareReplay } from 'rxjs/operators'
5
5
  import { CatalogSource } from './sources.model'
6
6
  import { TranslateService } from '@ngx-translate/core'
7
- import { getLang3FromLang2 } from '../../../../../../libs/util/i18n/src'
7
+ import { toLang3 } from '../../../../../../libs/util/i18n/src'
8
8
 
9
9
  @Injectable({
10
10
  providedIn: 'root',
@@ -23,10 +23,7 @@ export class SourcesService {
23
23
  return this.sources$.pipe(
24
24
  map((sources) => sources.filter((source) => source.uuid === uuid)[0]),
25
25
  filter((source) => !!source),
26
- map(
27
- (source) =>
28
- source.label[getLang3FromLang2(this.translateService.currentLang)]
29
- )
26
+ map((source) => source.label[toLang3(this.translateService.currentLang)])
30
27
  )
31
28
  }
32
29
  }
@@ -0,0 +1,20 @@
1
+ <div class="flex flex-col gap-3">
2
+ <div class="flex flex-col gap-4">
3
+ <gn-ui-autocomplete
4
+ [placeholder]="'editor.record.form.inspire.placeholder' | translate"
5
+ [displayWithFn]="displayWithFn"
6
+ [action]="autoCompleteAction"
7
+ (itemSelected)="handleItemSelection($event)"
8
+ [minCharacterCount]="1"
9
+ [clearOnSelection]="true"
10
+ ></gn-ui-autocomplete>
11
+ <div class="flex gap-2 flex-wrap">
12
+ <gn-ui-badge
13
+ *ngFor="let theme of themes"
14
+ [removable]="true"
15
+ (badgeRemoveClicked)="removeTheme(theme)"
16
+ >{{ getTranslatedTheme(theme) }}
17
+ </gn-ui-badge>
18
+ </div>
19
+ </div>
20
+ </div>
@@ -0,0 +1,85 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core'
2
+ import { CommonModule } from '@angular/common'
3
+ import { AutocompleteComponent, BadgeComponent } from '../../../../../../../../../libs/ui/inputs/src'
4
+ import { NgIconComponent } from '@ng-icons/core'
5
+ import { INSPIRE_THEMES } from '../../../../fields.config'
6
+ import { TranslatePipe, TranslateService } from '@ngx-translate/core'
7
+ import { of } from 'rxjs'
8
+
9
+ type AutocompleteItem = { title: string; value: string }
10
+
11
+ @Component({
12
+ selector: 'gn-ui-form-field-inspire-theme',
13
+ standalone: true,
14
+ imports: [
15
+ CommonModule,
16
+ AutocompleteComponent,
17
+ NgIconComponent,
18
+ BadgeComponent,
19
+ TranslatePipe,
20
+ ],
21
+ templateUrl: './form-field-inspire-theme.component.html',
22
+ styleUrl: './form-field-inspire-theme.component.css',
23
+ })
24
+ export class FormFieldInspireThemeComponent {
25
+ themes = []
26
+ @Input() set value(themes: string[]) {
27
+ this.themes = themes
28
+ }
29
+ @Output() valueChange: EventEmitter<string[]> = new EventEmitter()
30
+ availableThemes = INSPIRE_THEMES
31
+
32
+ displayWithFn = (item: AutocompleteItem) => {
33
+ return item?.title ? `${item.title}` : ''
34
+ }
35
+
36
+ autoCompleteAction = (query: string) => {
37
+ return of(
38
+ this.availableThemes
39
+ .filter((theme) =>
40
+ theme.value.toLowerCase().includes(query.toLowerCase())
41
+ )
42
+ .sort((a, b) => {
43
+ const aStarts = a.value.startsWith(query)
44
+ const bStarts = b.value.startsWith(query)
45
+
46
+ if (aStarts && !bStarts) return -1
47
+ if (!aStarts && bStarts) return 1
48
+ return 0
49
+ })
50
+ .map((theme) => {
51
+ return {
52
+ title: this.translateService.instant(theme.label),
53
+ value: theme.value,
54
+ }
55
+ })
56
+ )
57
+ }
58
+
59
+ constructor(private translateService: TranslateService) {}
60
+
61
+ handleItemSelection(item: AutocompleteItem) {
62
+ this.addTheme(item.value)
63
+ }
64
+
65
+ addTheme(theme: string) {
66
+ const duplicatedTheme = this.themes.find((t) => t === theme)
67
+ if (!duplicatedTheme) {
68
+ this.themes = [...this.themes, theme]
69
+ this.valueChange.emit(this.themes)
70
+ }
71
+ }
72
+
73
+ removeTheme(theme: string) {
74
+ console.log(this.themes)
75
+ this.themes = this.themes.filter((t) => t !== theme)
76
+ this.valueChange.emit(this.themes)
77
+ }
78
+
79
+ getTranslatedTheme(theme: string) {
80
+ const themeKey = this.availableThemes.find(
81
+ (avail) => avail.value === theme
82
+ )?.label
83
+ return themeKey ? this.translateService.instant(themeKey) : ''
84
+ }
85
+ }
@@ -109,6 +109,12 @@
109
109
  (valueChange)="valueChange.emit($event)"
110
110
  ></gn-ui-form-field-keywords>
111
111
  </ng-container>
112
+ <ng-container *ngSwitchCase="'topics'">
113
+ <gn-ui-form-field-inspire-theme
114
+ [value]="valueAsInspireTheme"
115
+ (valueChange)="valueChange.emit($event)"
116
+ ></gn-ui-form-field-inspire-theme>
117
+ </ng-container>
112
118
  <ng-container *ngSwitchCase="'licenses'">
113
119
  <gn-ui-form-field-license
114
120
  [label]="config.labelKey! | translate"
@@ -45,6 +45,7 @@ import { FormFieldConstraintsShortcutsComponent } from './form-field-constraints
45
45
  import { FormFieldConstraintsComponent } from './form-field-constraints/form-field-constraints.component'
46
46
  import { TextFieldModule } from '@angular/cdk/text-field'
47
47
  import { FormFieldSpatialToggleComponent } from './form-field-spatial-toggle/form-field-spatial-toggle.component'
48
+ import { FormFieldInspireThemeComponent } from './form-field-inspire-field/form-field-inspire-theme.component'
48
49
 
49
50
  @Component({
50
51
  selector: 'gn-ui-form-field',
@@ -73,6 +74,7 @@ import { FormFieldSpatialToggleComponent } from './form-field-spatial-toggle/for
73
74
  FormFieldConstraintsComponent,
74
75
  FormFieldConstraintsShortcutsComponent,
75
76
  FormFieldSpatialToggleComponent,
77
+ FormFieldInspireThemeComponent,
76
78
  TextFieldModule,
77
79
  ],
78
80
  })
@@ -128,6 +130,9 @@ export class FormFieldComponent {
128
130
  get valueAsKeywords() {
129
131
  return this.value as Array<Keyword>
130
132
  }
133
+ get valueAsInspireTheme() {
134
+ return this.value as Array<string>
135
+ }
131
136
  get valueAsConstraints() {
132
137
  return this.value as Array<Constraint>
133
138
  }
@@ -10,3 +10,4 @@ export * from './form-field-array/form-field-array.component'
10
10
  export * from './form-field-spatial-extent/form-field-spatial-extent.component'
11
11
  export * from './form-field.component'
12
12
  export * from './form-field-constraints-shortcuts/constraints.utils'
13
+ export * from './form-field-inspire-field/form-field-inspire-theme.component'
@@ -4,7 +4,10 @@ import {
4
4
  EditorField,
5
5
  EditorSection,
6
6
  } from './models/editor-config.model'
7
- import { Keyword } from '../../../../../libs/common/domain/src/lib/model/record'
7
+ import {
8
+ INSPIRE_theme,
9
+ Keyword,
10
+ } from '../../../../../libs/common/domain/src/lib/model/record'
8
11
 
9
12
  /**
10
13
  * This file contains the configuration of the fields that will be displayed in the editor.
@@ -64,6 +67,11 @@ export const RECORD_KEYWORDS_FIELD: EditorField = {
64
67
  formFieldConfig: {},
65
68
  }
66
69
 
70
+ export const RECORD_TOPICS_FIELD: EditorField = {
71
+ model: 'topics',
72
+ formFieldConfig: {},
73
+ }
74
+
67
75
  export const RECORD_RESOURCE_CREATED_FIELD: EditorField = {
68
76
  model: 'resourceCreated',
69
77
  formFieldConfig: {
@@ -235,6 +243,13 @@ export const CLASSIFICATION_SECTION: EditorSection = {
235
243
  fields: [RECORD_KEYWORDS_FIELD],
236
244
  }
237
245
 
246
+ export const INSPIRE_SECTION: EditorSection = {
247
+ labelKey: marker('editor.record.form.section.inspire.label'),
248
+ descriptionKey: marker('editor.record.form.section.inspire.description'),
249
+ hidden: false,
250
+ fields: [RECORD_TOPICS_FIELD],
251
+ }
252
+
238
253
  export const USE_AND_ACCESS_CONDITIONS_SECTION: EditorSection = {
239
254
  labelKey: marker('editor.record.form.section.useAndAccessConditions.label'),
240
255
  hidden: false,
@@ -274,6 +289,7 @@ export const DEFAULT_CONFIGURATION: EditorConfig = {
274
289
  sections: [
275
290
  TITLE_SECTION,
276
291
  CLASSIFICATION_SECTION,
292
+ INSPIRE_SECTION,
277
293
  ABOUT_SECTION,
278
294
  GEOGRAPHICAL_COVERAGE_SECTION,
279
295
  ],
@@ -341,3 +357,71 @@ export const SPATIAL_SCOPES: Keyword[] = [
341
357
  type: 'theme',
342
358
  },
343
359
  ]
360
+
361
+ /************************************************************
362
+ *************** INSPIRE THEMES **************
363
+ ************************************************************
364
+ */
365
+
366
+ export const INSPIRE_THEMES: INSPIRE_theme[] = [
367
+ { value: 'biota', label: 'editor.record.form.inspire.biota' },
368
+ { value: 'boundaries', label: 'editor.record.form.inspire.boundaries' },
369
+ {
370
+ value: 'climatologyMeteorologyAtmosphere',
371
+ label: 'editor.record.form.inspire.climatology',
372
+ },
373
+ { value: 'economy', label: 'editor.record.form.inspire.economy' },
374
+ { value: 'elevation', label: 'editor.record.form.inspire.elevation' },
375
+ { value: 'environment', label: 'editor.record.form.inspire.environnement' },
376
+ { value: 'farming', label: 'editor.record.form.inspire.farming' },
377
+ {
378
+ value: 'geoscientific information',
379
+ label: 'editor.record.form.inspire.geoscientific',
380
+ },
381
+ { value: 'health', label: 'editor.record.form.inspire.health' },
382
+ {
383
+ value: 'imageryBaseMapsEarthCover',
384
+ label: 'editor.record.form.inspire.imagery',
385
+ },
386
+ {
387
+ value: 'intelligenceMilitary',
388
+ label: 'editor.record.form.inspire.intelligence',
389
+ },
390
+ { value: 'Location', label: 'editor.record.form.inspire.location' },
391
+ { value: 'Oceans', label: 'editor.record.form.inspire.oceans' },
392
+ {
393
+ value: 'planningCadastre',
394
+ label: 'editor.record.form.inspire.planning',
395
+ },
396
+ { value: 'Society', label: 'editor.record.form.inspire.society' },
397
+ { value: 'Structure', label: 'editor.record.form.inspire.structure' },
398
+ {
399
+ value: 'Transportation',
400
+ label: 'editor.record.form.inspire.transportation',
401
+ },
402
+ {
403
+ value: 'utilitiesCommunication',
404
+ label: 'editor.record.form.inspire.utilities',
405
+ },
406
+ { value: 'inlandWaters', label: 'editor.record.form.inspire.waters' },
407
+ ]
408
+
409
+ marker('editor.record.form.inspire.biota')
410
+ marker('editor.record.form.inspire.boundaries')
411
+ marker('editor.record.form.inspire.climatology')
412
+ marker('editor.record.form.inspire.economy')
413
+ marker('editor.record.form.inspire.elevation')
414
+ marker('editor.record.form.inspire.environnement')
415
+ marker('editor.record.form.inspire.farming')
416
+ marker('editor.record.form.inspire.geoscientific')
417
+ marker('editor.record.form.inspire.health')
418
+ marker('editor.record.form.inspire.imagery')
419
+ marker('editor.record.form.inspire.intelligence')
420
+ marker('editor.record.form.inspire.location')
421
+ marker('editor.record.form.inspire.oceans')
422
+ marker('editor.record.form.inspire.planning')
423
+ marker('editor.record.form.inspire.society')
424
+ marker('editor.record.form.inspire.structure')
425
+ marker('editor.record.form.inspire.transportation')
426
+ marker('editor.record.form.inspire.utilities')
427
+ marker('editor.record.form.inspire.waters')
@@ -1,25 +1,25 @@
1
1
  import { Injectable } from '@angular/core'
2
- import { extend, Extent } from 'ol/extent'
3
- import GeoJSON from 'ol/format/GeoJSON'
2
+ import { extend } from 'ol/extent'
4
3
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
5
-
6
- const GEOJSON = new GeoJSON()
4
+ import { BoundingBox, getGeometryBoundingBox } from '../../../../../../libs/util/shared/src'
7
5
 
8
6
  @Injectable({
9
7
  providedIn: 'root',
10
8
  })
11
9
  export class MapUtilsService {
12
- getRecordExtent(record: Partial<CatalogRecord>): Extent {
10
+ getRecordExtent(record: Partial<CatalogRecord>): BoundingBox {
13
11
  if (!('spatialExtents' in record) || record.spatialExtents.length === 0) {
14
12
  return null
15
13
  }
16
14
  // extend all the spatial extents into an including bbox
17
15
  return record.spatialExtents.reduce(
18
16
  (prev, curr) => {
19
- if ('bbox' in curr) return extend(prev, curr.bbox)
17
+ if ('bbox' in curr) return extend(prev, curr.bbox) as BoundingBox
20
18
  else if ('geometry' in curr) {
21
- const geom = GEOJSON.readGeometry(curr.geometry)
22
- return extend(prev, geom.getExtent())
19
+ return extend(
20
+ prev,
21
+ getGeometryBoundingBox(curr.geometry)
22
+ ) as BoundingBox
23
23
  }
24
24
  return prev
25
25
  },
@@ -14,7 +14,10 @@ export function flattenQueryParams(
14
14
  Array.isArray(flattened[key]) &&
15
15
  (flattened[key] as string[]).length > 0
16
16
  ) {
17
- flattened[key] = [(flattened[key] as string[]).join(',')]
17
+ const encoded = (flattened[key] as string[]).map((value) =>
18
+ typeof value === 'string' ? value.replace(/,/g, '%2C') : value
19
+ )
20
+ flattened[key] = [encoded.join(',')]
18
21
  } else if (isDateRange(flattened[key] as DateRange)) {
19
22
  const start = (flattened[key] as DateRange).start
20
23
  const end = (flattened[key] as DateRange).end
@@ -48,7 +51,7 @@ export function expandQueryParams(
48
51
  ...(end && { end: new Date(`${end}T00:00:00`) }),
49
52
  }
50
53
  } else {
51
- expanded[key] = value.split(',')
54
+ expanded[key] = value.split(',').map((v) => v.replace(/%2C/g, ','))
52
55
  }
53
56
  }
54
57
  }
@@ -63,7 +63,8 @@ export class RouterFacade {
63
63
  }
64
64
 
65
65
  goToOrganization(organizationName: string) {
66
- const path = `${this.routerService.getOrganizationPageRoute()}/${organizationName}`
66
+ const safeOrgName = organizationName.replace(/\//g, '')
67
+ const path = `${this.routerService.getOrganizationPageRoute()}/${safeOrgName}`
67
68
  this.go({
68
69
  path,
69
70
  queryParamsHandling: '',
@@ -8,6 +8,7 @@ import {
8
8
  SortByField,
9
9
  } from '../../../../../../libs/common/domain/src/lib/model/search'
10
10
  import { DEFAULT_PAGE_SIZE, FIELDS_SUMMARY } from '../constants'
11
+ import { getOptionalSearchConfig } from '../../../../../../libs/util/app-config/src'
11
12
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
12
13
 
13
14
  export const SEARCH_FEATURE_KEY = 'searchState'
@@ -55,7 +56,9 @@ export const initSearch = (): SearchStateSearch => {
55
56
  },
56
57
  params: {
57
58
  filters: {},
58
- pageSize: DEFAULT_PAGE_SIZE,
59
+ pageSize: getOptionalSearchConfig()?.LIMIT
60
+ ? getOptionalSearchConfig().LIMIT
61
+ : DEFAULT_PAGE_SIZE,
59
62
  currentPage: 0,
60
63
  favoritesOnly: false,
61
64
  useSpatialFilter: true,
@@ -67,7 +67,10 @@
67
67
  [ngClass]="{
68
68
  '!bg-primary': currentlyActive,
69
69
  }"
70
- >{{ link.accessServiceProtocol }}</span
70
+ translate
71
+ >record.metadata.api.accessServiceProtocol.{{
72
+ link.accessServiceProtocol
73
+ }}</span
71
74
  >
72
75
  <span
73
76
  *ngIf="link.accessServiceProtocol === 'GPFDL'"
@@ -74,10 +74,6 @@ export class MetadataQualityComponent implements OnChanges {
74
74
  )
75
75
  }
76
76
 
77
- hasGetCapabilities(url: string): boolean {
78
- return url.toLowerCase().includes('capabilities')
79
- }
80
-
81
77
  initialize() {
82
78
  if (!this.propsToValidate) {
83
79
  this.propsToValidate = getAllKeysValidator()
@@ -6,16 +6,16 @@ import { matCheck, matWarningAmber } from '@ng-icons/material-icons/baseline'
6
6
 
7
7
  marker('record.metadata.quality.title.success')
8
8
  marker('record.metadata.quality.title.failed')
9
- marker('record.metadata.quality.description.success')
10
- marker('record.metadata.quality.description.failed')
11
- marker('record.metadata.quality.topic.success')
12
- marker('record.metadata.quality.topic.failed')
9
+ marker('record.metadata.quality.abstract.success')
10
+ marker('record.metadata.quality.abstract.failed')
11
+ marker('record.metadata.quality.topics.success')
12
+ marker('record.metadata.quality.topics.failed')
13
13
  marker('record.metadata.quality.keywords.success')
14
14
  marker('record.metadata.quality.keywords.failed')
15
15
  marker('record.metadata.quality.legalConstraints.success')
16
16
  marker('record.metadata.quality.legalConstraints.failed')
17
- marker('record.metadata.quality.contact.success')
18
- marker('record.metadata.quality.contact.failed')
17
+ marker('record.metadata.quality.contacts.success')
18
+ marker('record.metadata.quality.contacts.failed')
19
19
  marker('record.metadata.quality.updateFrequency.success')
20
20
  marker('record.metadata.quality.updateFrequency.failed')
21
21
  marker('record.metadata.quality.organisation.success')
@@ -136,12 +136,6 @@ export class ServiceCapabilitiesComponent implements OnInit {
136
136
  }
137
137
 
138
138
  selectLayer(layer: WfsFeatureTypeFull | WmsLayerFull | WmtsLayer) {
139
- if (layer === this.selectedLayer) {
140
- this.selectedLayer = null
141
- this.layerInformation = []
142
- return
143
- }
144
-
145
139
  this.selectedLayer = layer
146
140
  const filteredInfo = []
147
141
  Object.keys(layer).map((key) => {
@@ -231,6 +231,7 @@ export function loadAppConfig() {
231
231
  'filter_geometry_url',
232
232
  'search_preset',
233
233
  'advanced_filters',
234
+ 'limit',
234
235
  ],
235
236
  warnings,
236
237
  errors
@@ -257,6 +258,7 @@ export function loadAppConfig() {
257
258
  filters: param.filters,
258
259
  })),
259
260
  ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
261
+ LIMIT: parsedSearchSection.limit,
260
262
  } as SearchConfig)
261
263
 
262
264
  const parsedMetadataQualitySection = parseConfigSection(
@@ -124,7 +124,7 @@ export const wrongLanguageCodeConfigFixture = () => `
124
124
  [global]
125
125
  geonetwork4_api_url = "/geonetwork/srv/api"
126
126
  proxy_path = "/proxy/?url="
127
- metadata_language = "fra"
127
+ metadata_language = "abc"
128
128
 
129
129
  [map]
130
130
 
@@ -60,6 +60,7 @@ export interface SearchConfig {
60
60
  FILTER_GEOMETRY_DATA?: string
61
61
  SEARCH_PRESET?: SearchPreset[]
62
62
  ADVANCED_FILTERS?: []
63
+ LIMIT?: number
63
64
  }
64
65
 
65
66
  export interface MetadataQualityConfig {
@@ -1,4 +1,4 @@
1
- import { LANGUAGE_CODES_ISO_3 } from './constants'
1
+ import { toLang2 } from '../../../../../libs/util/i18n/src'
2
2
 
3
3
  const flatten = (
4
4
  base: string,
@@ -129,13 +129,10 @@ export function checkMetadataLanguage(
129
129
  parsedConfigSection: any,
130
130
  outWarnings: string[]
131
131
  ) {
132
- if (
133
- LANGUAGE_CODES_ISO_3.indexOf(
134
- parsedConfigSection.metadata_language.toLowerCase()
135
- ) === -1
136
- ) {
132
+ const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase())
133
+ if (lang2?.length !== 2) {
137
134
  outWarnings.push(
138
- `In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not in ISO 639-2/B format`
135
+ `In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`
139
136
  )
140
137
  }
141
138
  return parsedConfigSection
@@ -1,20 +1,32 @@
1
1
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
2
2
 
3
+ /**
4
+ * Taken from https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes
5
+ * Note: some languages have multiple 3-char codes, like 'fre' and 'fra'; in that case, the one to be used
6
+ * in priority is the one defined last
7
+ */
3
8
  const LANG_3_TO_2_MAPPER = {
4
9
  eng: 'en',
10
+ nld: 'nl', // duplicate for "dut"
5
11
  dut: 'nl',
12
+ fra: 'fr', // duplicate for "fre"
6
13
  fre: 'fr',
14
+ deu: 'de', // duplicate for "ger"
7
15
  ger: 'de',
8
16
  kor: 'ko',
9
17
  spa: 'es',
18
+ ces: 'cs', // duplicate for "cze"
10
19
  cze: 'cs',
11
20
  cat: 'ca',
12
21
  fin: 'fi',
22
+ isl: 'is', // duplicate for "ice"
13
23
  ice: 'is',
14
24
  ita: 'it',
15
25
  por: 'pt',
16
26
  rus: 'ru',
27
+ zho: 'zh', // duplicate for "chi"
17
28
  chi: 'zh',
29
+ slk: 'sk', // duplicate for "slo"
18
30
  slo: 'sk',
19
31
  roh: 'rm',
20
32
  ara: 'ar',
@@ -25,10 +37,12 @@ const LANG_3_TO_2_MAPPER = {
25
37
  tur: 'tr',
26
38
  arm: 'hy',
27
39
  aze: 'az',
40
+ kat: 'ka', // duplicate for "geo"
28
41
  geo: 'ka',
29
42
  ukr: 'uk',
43
+ cym: 'cy', // duplicate for "wel"
30
44
  wel: 'cy',
31
- }
45
+ } as const
32
46
 
33
47
  export const LANGUAGE_NAMES = {
34
48
  en: 'English',
@@ -58,26 +72,63 @@ export const LANGUAGE_NAMES = {
58
72
  ka: 'ქართული',
59
73
  uk: 'українська',
60
74
  wel: 'Cymraeg',
61
- }
75
+ } as const
76
+
77
+ export type LanguageCode3 = keyof typeof LANG_3_TO_2_MAPPER
78
+ export type LanguageCode2 = (typeof LANG_3_TO_2_MAPPER)[LanguageCode3]
62
79
 
63
80
  export const LANG_2_TO_3_MAPPER = Object.entries(LANG_3_TO_2_MAPPER).reduce(
64
81
  (mapperObject, langEntry) => {
65
82
  return { ...mapperObject, [langEntry[1]]: langEntry[0] }
66
83
  },
67
84
  {}
68
- )
85
+ ) as Record<LanguageCode2, LanguageCode3>
69
86
 
70
- export function getLang3FromLang2(lang2: string): string {
71
- return LANG_2_TO_3_MAPPER[lang2] ?? lang2
72
- }
87
+ /**
88
+ * This can be:
89
+ * - an ISO 639-2 language code in 3 characters (e.g. 'eng', 'fre', 'ger')
90
+ * - an ISO 639-1 language code in 2 characters (e.g. 'en', 'fr', 'de')
91
+ * - a 2-character language code with locale (e.g. 'fr_FR', 'fr_CA')
92
+ */
93
+ export type LanguageCodeLike = LanguageCode2 | LanguageCode3 | string
73
94
 
74
- export function getLang2FromLang3(lang3: string): string {
75
- return LANG_3_TO_2_MAPPER[lang3] ?? lang3
95
+ /**
96
+ * Converts a language code in any format to the ISO 639-2 format (3 characters)
97
+ * Returns the given string if the corresponding language code could not be recognized
98
+ */
99
+ export function toLang3(lang: LanguageCodeLike): LanguageCode3 | string {
100
+ if (!lang) {
101
+ // also handle falsy values just in case
102
+ return lang
103
+ }
104
+ if (lang.length === 3) {
105
+ return LANG_2_TO_3_MAPPER[LANG_3_TO_2_MAPPER[lang.toLowerCase()]] ?? lang
106
+ }
107
+ const lang2 = lang.toLowerCase().substring(0, 2)
108
+ return LANG_2_TO_3_MAPPER[lang2] ?? lang
76
109
  }
77
110
 
78
- export function getLocalizedIndexKey(lang2: string): string {
79
- const lang3 = getLang3FromLang2(lang2)
80
- return lang3 ? `lang${lang3}` : null
111
+ /**
112
+ * Converts a language code in any format to the ISO 639-1 format (2 characters)
113
+ * Returns the given string if the corresponding language code could not be recognized
114
+ */
115
+ export function toLang2(lang: LanguageCodeLike): LanguageCode2 | string {
116
+ if (!lang) {
117
+ // also handle falsy values just in case
118
+ return lang
119
+ }
120
+ if (lang.length === 3) {
121
+ return LANG_3_TO_2_MAPPER[lang.toLowerCase()] ?? lang
122
+ }
123
+ const lang2 = lang.toLowerCase().substring(0, 2)
124
+ if (lang2 in LANG_2_TO_3_MAPPER) {
125
+ return lang2
126
+ }
127
+ if (lang.match(/[a-z]{2}_[A-Z]{2}/)) {
128
+ // remove locale code even if the language code is not known
129
+ return lang2
130
+ }
131
+ return lang
81
132
  }
82
133
 
83
134
  marker('language.en')