geonetwork-ui 2.7.0-dev.dbe423d28 → 2.7.0-dev.f29e01b0d

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 (87) hide show
  1. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +18 -4
  2. package/esm2022/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.mjs +1 -1
  3. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  4. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +10 -2
  5. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +31 -12
  6. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +73 -26
  7. package/esm2022/libs/ui/dataviz/src/lib/data-table/data-table.component.mjs +4 -3
  8. package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +4 -4
  9. package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +21 -43
  10. package/esm2022/libs/util/app-config/src/lib/app-config.mjs +3 -1
  11. package/esm2022/libs/util/app-config/src/lib/model.mjs +1 -1
  12. package/esm2022/libs/util/shared/src/index.mjs +2 -2
  13. package/esm2022/libs/util/shared/src/lib/links/link-utils.mjs +9 -1
  14. package/esm2022/libs/util/shared/src/lib/record/index.mjs +3 -0
  15. package/esm2022/libs/util/shared/src/lib/record/quality-score.util.mjs +45 -0
  16. package/esm2022/libs/util/shared/src/lib/record/record.util.mjs +56 -0
  17. package/esm2022/translations/de.json +1 -1
  18. package/esm2022/translations/en.json +1 -1
  19. package/esm2022/translations/es.json +1 -1
  20. package/esm2022/translations/fr.json +1 -1
  21. package/esm2022/translations/it.json +1 -1
  22. package/esm2022/translations/nl.json +1 -1
  23. package/esm2022/translations/pt.json +1 -1
  24. package/esm2022/translations/sk.json +1 -1
  25. package/fesm2022/geonetwork-ui.mjs +213 -92
  26. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  27. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +1 -0
  28. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  29. package/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.d.ts +1 -0
  30. package/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.d.ts.map +1 -1
  31. package/libs/common/domain/src/lib/platform.service.interface.d.ts +1 -0
  32. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  33. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts +3 -2
  34. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts.map +1 -1
  35. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts +8 -4
  36. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts.map +1 -1
  37. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +12 -5
  38. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  39. package/libs/ui/dataviz/src/lib/data-table/data-table.component.d.ts.map +1 -1
  40. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -1
  41. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts +7 -6
  42. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
  43. package/libs/util/app-config/src/lib/app-config.d.ts.map +1 -1
  44. package/libs/util/app-config/src/lib/model.d.ts +1 -0
  45. package/libs/util/app-config/src/lib/model.d.ts.map +1 -1
  46. package/libs/util/shared/src/index.d.ts +1 -1
  47. package/libs/util/shared/src/index.d.ts.map +1 -1
  48. package/libs/util/shared/src/lib/links/link-utils.d.ts +1 -0
  49. package/libs/util/shared/src/lib/links/link-utils.d.ts.map +1 -1
  50. package/libs/util/shared/src/lib/record/index.d.ts +3 -0
  51. package/libs/util/shared/src/lib/record/index.d.ts.map +1 -0
  52. package/libs/util/shared/src/lib/record/quality-score.util.d.ts +13 -0
  53. package/libs/util/shared/src/lib/record/quality-score.util.d.ts.map +1 -0
  54. package/libs/util/shared/src/lib/record/record.util.d.ts +3 -0
  55. package/libs/util/shared/src/lib/record/record.util.d.ts.map +1 -0
  56. package/package.json +1 -1
  57. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +25 -4
  58. package/src/libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model.ts +1 -0
  59. package/src/libs/common/domain/src/lib/platform.service.interface.ts +2 -0
  60. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +10 -1
  61. package/src/libs/feature/record/src/lib/data-view/data-view.component.html +2 -0
  62. package/src/libs/feature/record/src/lib/data-view/data-view.component.ts +34 -15
  63. package/src/libs/feature/record/src/lib/map-view/map-view.component.html +2 -0
  64. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +67 -22
  65. package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +6 -1
  66. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +1 -0
  67. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +5 -1
  68. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.html +1 -0
  69. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +21 -54
  70. package/src/libs/util/app-config/src/lib/app-config.ts +2 -0
  71. package/src/libs/util/app-config/src/lib/model.ts +1 -0
  72. package/src/libs/util/shared/src/index.ts +1 -1
  73. package/src/libs/util/shared/src/lib/links/link-utils.ts +9 -0
  74. package/src/libs/util/shared/src/lib/record/index.ts +2 -0
  75. package/src/libs/util/shared/src/lib/record/quality-score.util.ts +69 -0
  76. package/src/libs/util/shared/src/lib/{record.util.ts → record/record.util.ts} +1 -1
  77. package/translations/de.json +1 -1
  78. package/translations/en.json +1 -1
  79. package/translations/es.json +1 -1
  80. package/translations/fr.json +1 -1
  81. package/translations/it.json +1 -1
  82. package/translations/nl.json +1 -1
  83. package/translations/pt.json +1 -1
  84. package/translations/sk.json +1 -1
  85. package/esm2022/libs/util/shared/src/lib/record.util.mjs +0 -56
  86. package/libs/util/shared/src/lib/record.util.d.ts +0 -3
  87. package/libs/util/shared/src/lib/record.util.d.ts.map +0 -1
@@ -9,7 +9,7 @@ import {
9
9
  ViewChild,
10
10
  } from '@angular/core'
11
11
  import { MapUtilsService } from '../../../../../../libs/feature/map/src'
12
- import { getLinkLabel } from '../../../../../../libs/util/shared/src'
12
+ import { getLinkId, getLinkLabel } from '../../../../../../libs/util/shared/src'
13
13
  import {
14
14
  BehaviorSubject,
15
15
  combineLatest,
@@ -100,15 +100,28 @@ export class MapViewComponent implements AfterViewInit {
100
100
  @Input() set exceedsLimit(value: boolean) {
101
101
  this.excludeWfs$.next(value)
102
102
  }
103
+ linkFromConfig$ = new BehaviorSubject(null)
104
+ _selectedChoice = null
105
+ _styleFromConfig = null
106
+
107
+ linkMap: Map<string, DatasetOnlineResource> = new Map()
103
108
  @Input() set selectedView(value: string) {
104
- if (value === 'map') {
105
- this.selectedLink$.pipe(take(1)).subscribe((link) => {
106
- this.linkSelected.emit(link)
107
- })
109
+ this.selectedView$.next(value)
110
+ }
111
+ @Input() set datavizConfig(value: any) {
112
+ if (value.view === 'map') {
113
+ this.selectedView$.next(value.view)
114
+ if (value.styleTMSIndex) {
115
+ this._styleFromConfig = value.styleTMSIndex
116
+ }
117
+ if (value.source) {
118
+ this.linkFromConfig$.next(value.source)
119
+ }
108
120
  }
109
121
  }
110
122
  @Input() displaySource = true
111
123
  @Output() linkSelected = new EventEmitter<DatasetOnlineResource>()
124
+ @Output() styleSelected = new EventEmitter<number>()
112
125
  @ViewChild('mapContainer') mapContainer: MapContainerComponent
113
126
 
114
127
  excludeWfs$ = new BehaviorSubject(false)
@@ -119,12 +132,13 @@ export class MapViewComponent implements AfterViewInit {
119
132
  loading = false
120
133
  error = null
121
134
 
122
- selectLinkToDisplay(i: number) {
123
- this.selectedLinkIndex$.next(i)
135
+ selectLinkToDisplay(id: string) {
136
+ this.selectedLinkId$.next(id)
124
137
  }
125
138
 
126
139
  selectStyleToDisplay(i: number) {
127
- this.selectedStyleIndex$.next(i)
140
+ this.selectedStyleId$.next(i)
141
+ this.styleSelected.emit(i)
128
142
  }
129
143
 
130
144
  toggleLegend() {
@@ -146,29 +160,54 @@ export class MapViewComponent implements AfterViewInit {
146
160
  )
147
161
 
148
162
  dropdownChoices$ = this.compatibleMapLinks$.pipe(
149
- map((links) =>
150
- links.length
151
- ? links.map((link, index) => ({
163
+ map((links) => {
164
+ this.linkMap.clear()
165
+ links.forEach((link: DatasetOnlineResource) =>
166
+ this.linkMap.set(getLinkId(link), link)
167
+ )
168
+ return links.length
169
+ ? links.map((link) => ({
152
170
  label: getLinkLabel(link),
153
- value: index,
171
+ value: getLinkId(link),
154
172
  }))
155
- : [{ label: 'map.dropdown.placeholder', value: 0 }]
156
- )
173
+ : [{ label: 'map.dropdown.placeholder', value: '' }]
174
+ })
157
175
  )
158
176
 
159
- selectedLinkIndex$ = new BehaviorSubject(0)
160
- private selectedStyleIndex$ = new BehaviorSubject(0)
177
+ selectedView$ = new BehaviorSubject(null)
178
+ selectedLinkId$ = new BehaviorSubject(null)
179
+ selectedStyleId$ = new BehaviorSubject(null)
161
180
 
162
181
  selectedSourceLink$ = combineLatest([
163
182
  this.compatibleMapLinks$,
164
- this.selectedLinkIndex$.pipe(distinctUntilChanged()),
183
+ this.linkFromConfig$,
184
+ this.selectedLinkId$.pipe(distinctUntilChanged()),
185
+ this.selectedView$,
165
186
  ]).pipe(
166
187
  tap(() => {
167
188
  this.error = null
168
189
  }),
169
- map(([links, index]) => {
170
- this.linkSelected.emit(links[index])
171
- return links[index]
190
+ map(([compatibleLinks, configLink, id, view]) => {
191
+ if (view === 'map') {
192
+ if (
193
+ configLink &&
194
+ !id &&
195
+ compatibleLinks.some(
196
+ (link) => getLinkId(link) === getLinkId(configLink)
197
+ )
198
+ ) {
199
+ this._selectedChoice = getLinkId(configLink)
200
+ this.linkSelected.emit(configLink)
201
+ return configLink
202
+ } else if (id) {
203
+ this._selectedChoice = id
204
+ this.linkSelected.emit(this.linkMap.get(id))
205
+ return this.linkMap.get(id)
206
+ } else {
207
+ this.linkSelected.emit(compatibleLinks[0])
208
+ return compatibleLinks[0]
209
+ }
210
+ }
172
211
  })
173
212
  )
174
213
 
@@ -205,7 +244,13 @@ export class MapViewComponent implements AfterViewInit {
205
244
  }
206
245
  return of([])
207
246
  }),
208
- tap(() => this.selectedStyleIndex$.next(0)),
247
+ tap((styles) => {
248
+ if (this._styleFromConfig && this._styleFromConfig <= styles.length) {
249
+ this.selectedStyleId$.next(this._styleFromConfig)
250
+ } else {
251
+ this.selectedStyleId$.next(0)
252
+ }
253
+ }),
209
254
  shareReplay(1)
210
255
  )
211
256
 
@@ -228,7 +273,7 @@ export class MapViewComponent implements AfterViewInit {
228
273
  selectedLink$ = combineLatest([
229
274
  this.selectedSourceLink$,
230
275
  this.styleLinks$,
231
- this.selectedStyleIndex$.pipe(distinctUntilChanged()),
276
+ this.selectedStyleId$.pipe(distinctUntilChanged()),
232
277
  ]).pipe(
233
278
  map(([src, styles, styleIdx]) => (styles.length ? styles[styleIdx] : src)),
234
279
  shareReplay(1)
@@ -14,7 +14,11 @@ import {
14
14
  } from '@angular/core'
15
15
  import { MatSort, MatSortModule } from '@angular/material/sort'
16
16
  import { MatTableModule } from '@angular/material/table'
17
- import { TranslatePipe, TranslateService } from '@ngx-translate/core'
17
+ import {
18
+ TranslateDirective,
19
+ TranslatePipe,
20
+ TranslateService,
21
+ } from '@ngx-translate/core'
18
22
  import { DataTableDataSource } from './data-table.data.source'
19
23
  import { BaseReader, FetchError } from '../../../../../../libs/util/data-fetcher/src'
20
24
  import {
@@ -53,6 +57,7 @@ export interface TableItemModel {
53
57
  PopupAlertComponent,
54
58
  LetDirective,
55
59
  TranslatePipe,
60
+ TranslateDirective,
56
61
  ],
57
62
  providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }],
58
63
  selector: 'gn-ui-data-table',
@@ -68,6 +68,7 @@
68
68
  [smaller]="true"
69
69
  [metadata]="record"
70
70
  [metadataQualityDisplay]="metadataQualityDisplay"
71
+ [popoverDisplay]="true"
71
72
  ></gn-ui-metadata-quality>
72
73
  </div>
73
74
  <div
@@ -21,7 +21,11 @@ import { KindBadgeComponent } from '../kind-badge/kind-badge.component'
21
21
  import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
22
22
  import { MetadataQualityComponent } from '../metadata-quality/metadata-quality.component'
23
23
  import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
24
- import { removeWhitespace, stripHtml } from '../../../../../../libs/util/shared/src'
24
+ import {
25
+ removeWhitespace,
26
+ stripHtml,
27
+ type ValidatorMapperKeys,
28
+ } from '../../../../../../libs/util/shared/src'
25
29
 
26
30
  type CardSize = 'L' | 'M' | 'S' | 'XS'
27
31
 
@@ -10,6 +10,7 @@
10
10
  class="flex-grow"
11
11
  ></gn-ui-progress-bar>
12
12
  <gn-ui-popover
13
+ *ngIf="popoverDisplay"
13
14
  [content]="popoverItems"
14
15
  theme="light-border"
15
16
  [class]="smaller ? 'ml-2' : 'ml-2 mt-1'"
@@ -14,15 +14,16 @@ import {
14
14
  PopoverComponent,
15
15
  ProgressBarComponent,
16
16
  } from '../../../../../../libs/ui/widgets/src'
17
+ import {
18
+ getQualityValidators,
19
+ getAllKeysValidator,
20
+ type ValidatorMapperKeys,
21
+ } from '../../../../../../libs/util/shared/src'
17
22
  import { CommonModule } from '@angular/common'
18
23
  import { TranslateDirective } from '@ngx-translate/core'
19
24
  import { NgIcon, provideIcons, provideNgIconsConfig } from '@ng-icons/core'
20
25
  import { matInfoOutline } from '@ng-icons/material-icons/outline'
21
26
 
22
- type QualityChecks = {
23
- [key: string]: (metadata: Partial<CatalogRecord>) => boolean
24
- }
25
-
26
27
  @Component({
27
28
  selector: 'gn-ui-metadata-quality',
28
29
  templateUrl: './metadata-quality.component.html',
@@ -48,77 +49,43 @@ type QualityChecks = {
48
49
  ],
49
50
  })
50
51
  export class MetadataQualityComponent implements OnChanges {
51
- @Input() metadata: Partial<CatalogRecord>
52
+ @Input() metadata: CatalogRecord
52
53
  @Input() smaller = false
53
54
  @Input() metadataQualityDisplay: boolean
55
+ @Input() popoverDisplay = true
56
+ @Input() propsToValidate?: ValidatorMapperKeys[]
57
+ @Input() forceComputeScore = false // Instead of returning es' quality score
54
58
 
55
59
  items: MetadataQualityItem[] = []
56
60
 
57
61
  get qualityScore() {
58
- const qualityScore = this.metadata?.extras?.qualityScore
62
+ const qualityScore = !this.forceComputeScore
63
+ ? this.metadata?.extras?.qualityScore
64
+ : this.computedQualityScore
65
+
59
66
  return typeof qualityScore === 'number'
60
67
  ? qualityScore
61
- : this.calculatedQualityScore
68
+ : this.computedQualityScore
62
69
  }
63
70
 
64
- get calculatedQualityScore(): number {
71
+ get computedQualityScore(): number {
65
72
  return Math.round(
66
73
  (this.items.filter(({ value }) => value).length * 100) / this.items.length
67
74
  )
68
75
  }
69
76
 
70
- private add(name: string, value: boolean) {
71
- if (this.metadataQualityDisplay?.[name] !== false) {
72
- this.items.push({ name, value })
73
- }
74
- }
75
77
  hasGetCapabilities(url: string): boolean {
76
78
  return url.toLowerCase().includes('capabilities')
77
79
  }
78
80
 
79
- private readonly COMMON_CHECKS: QualityChecks = {
80
- title: (metadata) => !!metadata?.title,
81
- description: (metadata) => !!metadata?.abstract,
82
- keywords: (metadata) => (metadata?.keywords?.length ?? 0) > 0,
83
- legalConstraints: (metadata) =>
84
- (metadata?.legalConstraints?.length ?? 0) > 0,
85
- contact: (metadata) => !!metadata?.contacts?.[0]?.email,
86
- }
87
-
88
- private readonly SPECIFIC_CHECKS: Record<string, QualityChecks> = {
89
- dataset: {
90
- updateFrequency: (metadata) => !!metadata?.updateFrequency,
91
- topic: (metadata) => (metadata?.topics?.length ?? 0) > 0,
92
- organisation: (metadata) => !!metadata?.contacts?.[0]?.organization?.name,
93
- },
94
- service: {
95
- capabilities: (metadata) =>
96
- (metadata?.onlineResources ?? []).some((resource) =>
97
- this.hasGetCapabilities(resource?.url?.href ?? '')
98
- ),
99
- },
100
- reuse: {
101
- topic: (metadata) => (metadata?.topics?.length ?? 0) > 0,
102
- organisation: (metadata) => !!metadata?.contacts?.[0]?.organization?.name,
103
- source: (metadata) => !!metadata?.extras?.sourcesIdentifiers,
104
- },
105
- }
106
-
107
81
  initialize() {
108
- this.items = []
109
-
110
- Object.entries(this.COMMON_CHECKS).forEach(([name, check]) => {
111
- this.add(name, check(this.metadata))
112
- })
113
-
114
- const datasetType = this.metadata?.kind
115
- if (datasetType && this.SPECIFIC_CHECKS[datasetType]) {
116
- Object.entries(this.SPECIFIC_CHECKS[datasetType]).forEach(
117
- ([name, check]) => {
118
- this.add(name, check(this.metadata))
119
- }
120
- )
82
+ if (!this.propsToValidate) {
83
+ this.propsToValidate = getAllKeysValidator()
121
84
  }
85
+
86
+ this.items = getQualityValidators(this.metadata, this.propsToValidate).map(
87
+ ({ name, validator }) => ({ name, value: validator() })
88
+ )
122
89
  }
123
90
 
124
91
  ngOnChanges(changes: SimpleChanges): void {
@@ -102,6 +102,7 @@ export function loadAppConfig() {
102
102
  'web_component_embedder_url',
103
103
  'languages',
104
104
  'contact_email',
105
+ 'reuse_form_url',
105
106
  ],
106
107
  warnings,
107
108
  errors
@@ -131,6 +132,7 @@ export function loadAppConfig() {
131
132
  parsedGlobalSection.web_component_embedder_url,
132
133
  LANGUAGES: parsedGlobalSection.languages,
133
134
  CONTACT_EMAIL: parsedGlobalSection.contact_email,
135
+ REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
134
136
  } as GlobalConfig)
135
137
 
136
138
  const parsedLayersSections = parseMultiConfigSection(
@@ -11,6 +11,7 @@ export interface GlobalConfig {
11
11
  WEB_COMPONENT_EMBEDDER_URL?: string
12
12
  LANGUAGES?: string[]
13
13
  CONTACT_EMAIL?: string
14
+ REUSE_FORM_URL?: string
14
15
  }
15
16
 
16
17
  export interface LayerConfig {
@@ -3,4 +3,4 @@ export * from './lib/utils'
3
3
  export * from './lib/links'
4
4
  export * from './lib/image-fallback.directive'
5
5
  export * from './lib/gn-ui-version'
6
- export * from './lib/record.util'
6
+ export * from './lib/record'
@@ -230,6 +230,15 @@ export function getBadgeColor(linkFormat: FileFormat): string {
230
230
  return 'var(--color-gray-700)' // Default color ?
231
231
  }
232
232
 
233
+ export function getLinkId(link: DatasetOnlineResource): string {
234
+ const href = link.url.href ?? link.url
235
+ return `${getLinkLabel(link)
236
+ .replace(/é/g, 'e')
237
+ .replace(/è/g, 'e')
238
+ .normalize('NFD')
239
+ .replace(/[\u0300-\u036f]/g, '')}-${href}`
240
+ }
241
+
233
242
  export function getLinkLabel(
234
243
  link: DatasetOnlineResource | ServiceOnlineResource
235
244
  ): string {
@@ -0,0 +1,2 @@
1
+ export * from './quality-score.util'
2
+ export * from './record.util'
@@ -0,0 +1,69 @@
1
+ import {
2
+ CatalogRecord,
3
+ RecordKind,
4
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
5
+
6
+ type TValidatorMapper = {
7
+ [key: string]: (metadata: Partial<CatalogRecord>) => boolean
8
+ }
9
+
10
+ const ValidatorMapper: TValidatorMapper = {
11
+ title: (record) => !!record?.title,
12
+ description: (record) => !!record?.abstract,
13
+ keywords: (record) => (record?.keywords?.length ?? 0) > 0,
14
+ legalConstraints: (record) => (record?.legalConstraints?.length ?? 0) > 0,
15
+ contact: (record) => !!record?.contacts?.[0]?.email,
16
+ updateFrequency: (record) => !!record?.updateFrequency,
17
+ topic: (record) => (record?.topics?.length ?? 0) > 0,
18
+ organisation: (record) => !!record?.contacts?.[0]?.organization?.name,
19
+ capabilities: (record) =>
20
+ record?.onlineResources?.some((resource) =>
21
+ resource?.url?.href.toLowerCase().includes('capabilities')
22
+ ),
23
+ source: (record) => !!record?.extras?.sourcesIdentifiers,
24
+ } as const
25
+
26
+ export type ValidatorMapperKeys = keyof typeof ValidatorMapper & string
27
+
28
+ export function getAllKeysValidator() {
29
+ return Object.keys(ValidatorMapper)
30
+ }
31
+
32
+ function getMappersFromKind(kind: RecordKind) {
33
+ let kindKeys = <ValidatorMapperKeys[]>[]
34
+ const commonsKeys = <ValidatorMapperKeys[]>[
35
+ 'title',
36
+ 'description',
37
+ 'keywords',
38
+ 'legalConstraints',
39
+ 'contact',
40
+ ]
41
+
42
+ switch (kind) {
43
+ case 'service':
44
+ kindKeys = ['capabilities']
45
+ break
46
+ case 'reuse':
47
+ kindKeys = ['topic', 'organisation', 'source']
48
+ break
49
+ case 'dataset':
50
+ default:
51
+ kindKeys = ['updateFrequency', 'topic', 'organisation']
52
+ }
53
+
54
+ return [...commonsKeys, ...kindKeys]
55
+ }
56
+
57
+ export function getQualityValidators(
58
+ record: Partial<CatalogRecord>,
59
+ propsToValidate: ValidatorMapperKeys[]
60
+ ) {
61
+ const filteredProps = propsToValidate.filter((prop) =>
62
+ getMappersFromKind(record.kind).includes(prop)
63
+ )
64
+
65
+ return filteredProps.map((name) => ({
66
+ name,
67
+ validator: () => ValidatorMapper[name](record),
68
+ }))
69
+ }
@@ -10,7 +10,7 @@ import {
10
10
  OnlineLinkResource,
11
11
  Organization,
12
12
  ServiceEndpoint,
13
- } from '../../../../../libs/common/domain/src/lib/model/record'
13
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
14
14
 
15
15
  type TranslatedRecordObjects =
16
16
  | BaseRecord
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "Anzeigen",
377
- "record.card.metadata.contact": "",
378
377
  "record.externalViewer.open": "In externem Kartenviewer öffnen",
379
378
  "record.feature.catalog.number.total.attribute": "",
380
379
  "record.feature.catalog.number.total.object": "",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "",
581
580
  "service.metadata.other": "",
582
581
  "service.metadata.question": "",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "",
584
584
  "service.metadata.search.clear": "",
585
585
  "service.metadata.spatialExtent": "",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "Rollback",
375
375
  "record.action.switchLang": "Switch to default",
376
376
  "record.action.view": "View",
377
- "record.card.metadata.contact": "Metadata Contact",
378
377
  "record.externalViewer.open": "Open in the external map viewer",
379
378
  "record.feature.catalog.number.total.attribute": "Total amount of objects",
380
379
  "record.feature.catalog.number.total.object": "Total amount of attributes",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "No layer matches your search",
581
580
  "service.metadata.other": "Other information",
582
581
  "service.metadata.question": "Ask a question",
582
+ "service.metadata.reuse": "Declare a reuse",
583
583
  "service.metadata.search": "Search through the layer list",
584
584
  "service.metadata.search.clear": "Clear the layer search",
585
585
  "service.metadata.spatialExtent": "Spatial extent",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "",
377
- "record.card.metadata.contact": "",
378
377
  "record.externalViewer.open": "",
379
378
  "record.feature.catalog.number.total.attribute": "",
380
379
  "record.feature.catalog.number.total.object": "",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "",
581
580
  "service.metadata.other": "",
582
581
  "service.metadata.question": "",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "",
584
584
  "service.metadata.search.clear": "",
585
585
  "service.metadata.spatialExtent": "",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "Restaurer",
375
375
  "record.action.switchLang": "Marquer par défaut",
376
376
  "record.action.view": "Voir",
377
- "record.card.metadata.contact": "Contact de la métadonnée ",
378
377
  "record.externalViewer.open": "Ouvrir dans le visualiseur externe",
379
378
  "record.feature.catalog.number.total.attribute": "Nombre total d'attributs",
380
379
  "record.feature.catalog.number.total.object": "Nombre total d'objets",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "Aucune couche ne correspond à votre recherche",
581
580
  "service.metadata.other": "Autres informations",
582
581
  "service.metadata.question": "Poser une question",
582
+ "service.metadata.reuse": "Déclarer une réutilisation",
583
583
  "service.metadata.search": "Rechercher dans la liste des couches",
584
584
  "service.metadata.search.clear": "Effacer la recherche des couches",
585
585
  "service.metadata.spatialExtent": "Etendue spatiale",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "Annulla",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "Visualizza",
377
- "record.card.metadata.contact": "Contatto del metadata",
378
377
  "record.externalViewer.open": "Aprire nel visualizzatore esterno",
379
378
  "record.feature.catalog.number.total.attribute": "Quantità totale di oggetti",
380
379
  "record.feature.catalog.number.total.object": "Quantità totale di attributi",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "Nessun layer abbina la ricerca",
581
580
  "service.metadata.other": "Altri informazioni",
582
581
  "service.metadata.question": "Fare una domanda",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "Cerca nella lista del layers",
584
584
  "service.metadata.search.clear": "Cancella la ricerca del layers",
585
585
  "service.metadata.spatialExtent": "Estensione spaziale",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "",
377
- "record.card.metadata.contact": "",
378
377
  "record.externalViewer.open": "",
379
378
  "record.feature.catalog.number.total.attribute": "",
380
379
  "record.feature.catalog.number.total.object": "",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "",
581
580
  "service.metadata.other": "",
582
581
  "service.metadata.question": "",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "",
584
584
  "service.metadata.search.clear": "",
585
585
  "service.metadata.spatialExtent": "",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "",
377
- "record.card.metadata.contact": "",
378
377
  "record.externalViewer.open": "",
379
378
  "record.feature.catalog.number.total.attribute": "",
380
379
  "record.feature.catalog.number.total.object": "",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "",
581
580
  "service.metadata.other": "",
582
581
  "service.metadata.question": "",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "",
584
584
  "service.metadata.search.clear": "",
585
585
  "service.metadata.spatialExtent": "",
@@ -374,7 +374,6 @@
374
374
  "record.action.rollback": "",
375
375
  "record.action.switchLang": "",
376
376
  "record.action.view": "Zobraziť",
377
- "record.card.metadata.contact": "",
378
377
  "record.externalViewer.open": "Otvoriť v externom mapovom prehliadači",
379
378
  "record.feature.catalog.number.total.attribute": "",
380
379
  "record.feature.catalog.number.total.object": "",
@@ -580,6 +579,7 @@
580
579
  "service.metadata.filter.noLayers": "",
581
580
  "service.metadata.other": "",
582
581
  "service.metadata.question": "",
582
+ "service.metadata.reuse": "",
583
583
  "service.metadata.search": "",
584
584
  "service.metadata.search.clear": "",
585
585
  "service.metadata.spatialExtent": "",
@@ -1,56 +0,0 @@
1
- export function updateLanguages(record, defaultLanguage, otherLanguages) {
2
- function updateFieldTranslations(target, fieldName) {
3
- const fieldTranslations = {};
4
- for (const lang of otherLanguages) {
5
- const prevValue = record.defaultLanguage === lang
6
- ? target[fieldName]
7
- : target.translations?.[fieldName]?.[lang];
8
- fieldTranslations[lang] = prevValue ?? '';
9
- }
10
- const defaultPrevValue = record.defaultLanguage === defaultLanguage
11
- ? target[fieldName]
12
- : target.translations?.[fieldName]?.[defaultLanguage];
13
- return {
14
- ...target,
15
- [fieldName]: defaultPrevValue ?? '',
16
- translations: {
17
- ...target.translations,
18
- [fieldName]: fieldTranslations,
19
- },
20
- };
21
- }
22
- function updateTranslations(target, fieldNames) {
23
- let result = target;
24
- for (const field of fieldNames) {
25
- result = updateFieldTranslations(result, field);
26
- }
27
- return result;
28
- }
29
- const updatedRecord = updateTranslations(record, [
30
- 'title',
31
- 'abstract',
32
- 'lineage',
33
- ]);
34
- updatedRecord.keywords = updatedRecord.keywords.map((k) => updateTranslations(k, ['label', 'description']));
35
- updatedRecord.onlineResources = updatedRecord.onlineResources.map((o) => updateTranslations(o, ['name', 'description']));
36
- updatedRecord.licenses = updatedRecord.licenses.map((l) => updateTranslations(l, ['text']));
37
- updatedRecord.legalConstraints = updatedRecord.legalConstraints.map((c) => updateTranslations(c, ['text']));
38
- updatedRecord.securityConstraints = updatedRecord.securityConstraints.map((c) => updateTranslations(c, ['text']));
39
- updatedRecord.otherConstraints = updatedRecord.otherConstraints.map((c) => updateTranslations(c, ['text']));
40
- updatedRecord.contacts = updatedRecord.contacts.map((c) => ({
41
- ...c,
42
- organization: updateTranslations(c.organization, ['name']),
43
- }));
44
- updatedRecord.contactsForResource = updatedRecord.contactsForResource.map((c) => ({
45
- ...c,
46
- organization: updateTranslations(c.organization, ['name']),
47
- }));
48
- updatedRecord.ownerOrganization = updateTranslations(updatedRecord.ownerOrganization, ['name']);
49
- if (updatedRecord.kind === 'dataset') {
50
- updatedRecord.spatialExtents = updatedRecord.spatialExtents.map((e) => updateTranslations(e, ['description']));
51
- }
52
- updatedRecord.defaultLanguage = defaultLanguage;
53
- updatedRecord.otherLanguages = otherLanguages;
54
- return updatedRecord;
55
- }
56
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkLnV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL3V0aWwvc2hhcmVkL3NyYy9saWIvcmVjb3JkLnV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBeUJBLE1BQU0sVUFBVSxlQUFlLENBQzdCLE1BQVMsRUFDVCxlQUE2QixFQUM3QixjQUE4QjtJQUU5QixTQUFTLHVCQUF1QixDQUM5QixNQUFTLEVBQ1QsU0FBaUI7UUFFakIsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLENBQUE7UUFDNUIsS0FBSyxNQUFNLElBQUksSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNsQyxNQUFNLFNBQVMsR0FDYixNQUFNLENBQUMsZUFBZSxLQUFLLElBQUk7Z0JBQzdCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDO2dCQUNuQixDQUFDLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDOUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLEdBQUcsU0FBUyxJQUFJLEVBQUUsQ0FBQTtRQUMzQyxDQUFDO1FBQ0QsTUFBTSxnQkFBZ0IsR0FDcEIsTUFBTSxDQUFDLGVBQWUsS0FBSyxlQUFlO1lBQ3hDLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDO1lBQ25CLENBQUMsQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxlQUFlLENBQUMsQ0FBQTtRQUN6RCxPQUFPO1lBQ0wsR0FBRyxNQUFNO1lBQ1QsQ0FBQyxTQUFTLENBQUMsRUFBRSxnQkFBZ0IsSUFBSSxFQUFFO1lBQ25DLFlBQVksRUFBRTtnQkFDWixHQUFHLE1BQU0sQ0FBQyxZQUFZO2dCQUN0QixDQUFDLFNBQVMsQ0FBQyxFQUFFLGlCQUFpQjthQUMvQjtTQUNGLENBQUE7SUFDSCxDQUFDO0lBQ0QsU0FBUyxrQkFBa0IsQ0FDekIsTUFB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Qy9DLGFBQWEsQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFBO0lBQzdDLE9BQU8sYUFBYSxDQUFBO0FBQ3RCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBCYXNlUmVjb3JkLFxuICBDYXRhbG9nUmVjb3JkLFxuICBDb25zdHJhaW50LFxuICBEYXRhc2V0RG93bmxvYWREaXN0cmlidXRpb24sXG4gIERhdGFzZXRTZXJ2aWNlRGlzdHJpYnV0aW9uLFxuICBEYXRhc2V0U3BhdGlhbEV4dGVudCxcbiAgS2V5d29yZCxcbiAgTGFuZ3VhZ2VDb2RlLFxuICBPbmxpbmVMaW5rUmVzb3VyY2UsXG4gIE9yZ2FuaXphdGlvbixcbiAgU2VydmljZUVuZHBvaW50LFxufSBmcm9tICcuLi8uLi8uLi8uLi8uLi9saWJzL2NvbW1vbi9kb21haW4vc3JjL2xpYi9tb2RlbC9yZWNvcmQnXG5cbnR5cGUgVHJhbnNsYXRlZFJlY29yZE9iamVjdHMgPVxuICB8IEJhc2VSZWNvcmRcbiAgfCBDb25zdHJhaW50XG4gIHwgS2V5d29yZFxuICB8IERhdGFzZXRTZXJ2aWNlRGlzdHJpYnV0aW9uXG4gIHwgRGF0YXNldERvd25sb2FkRGlzdHJpYnV0aW9uXG4gIHwgT25saW5lTGlua1Jlc291cmNlXG4gIHwgU2VydmljZUVuZHBvaW50XG4gIHwgRGF0YXNldFNwYXRpYWxFeHRlbnRcbiAgfCBPcmdhbml6YXRpb25cblxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZUxhbmd1YWdlczxUIGV4dGVuZHMgQ2F0YWxvZ1JlY29yZD4oXG4gIHJlY29yZDogVCxcbiAgZGVmYXVsdExhbmd1YWdlOiBMYW5ndWFnZUNvZGUsXG4gIG90aGVyTGFuZ3VhZ2VzOiBMYW5ndWFnZUNvZGVbXVxuKTogVCB7XG4gIGZ1bmN0aW9uIHVwZGF0ZUZpZWxkVHJhbnNsYXRpb25zPFQgZXh0ZW5kcyBUcmFuc2xhdGVkUmVjb3JkT2JqZWN0cz4oXG4gICAgdGFyZ2V0OiBULFxuICAgIGZpZWxkTmFtZTogc3RyaW5nXG4gICk6IFQge1xuICAgIGNvbnN0IGZpZWxkVHJhbnNsYXRpb25zID0ge31cbiAgICBmb3IgKGNvbnN0IGxhbmcgb2Ygb3RoZXJMYW5ndWFnZXMpIHtcbiAgICAgIGNvbnN0IHByZXZWYWx1ZSA9XG4gICAgICAgIHJlY29yZC5kZWZhdWx0TGFuZ3VhZ2UgPT09IGxhbmdcbiAgICAgICAgICA/IHRhcmdldFtmaWVsZE5hbWVdXG4gICAgICAgICAgOiB0YXJnZXQudHJhbnNsYXRpb25zPy5bZmllbGROYW1lXT8uW2xhbmddXG4gICAgICBmaWVsZFRyYW5zbGF0aW9uc1tsYW5nXSA9IHByZXZWYWx1ZSA/PyAnJ1xuICAgIH1cbiAgICBjb25zdCBkZWZhdWx0UHJldlZhbHVlID1cbiAgICAgIHJlY29yZC5kZWZhdWx0TGFuZ3VhZ2UgPT09IGRlZmF1bHRMYW5ndWFnZVxuICAgICAgICA/IHRhcmdldFtmaWVsZE5hbWVdXG4gICAgICAgIDogdGFyZ2V0LnRyYW5zbGF0aW9ucz8uW2ZpZWxkTmFtZV0/LltkZWZhdWx0TGFuZ3VhZ2VdXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRhcmdldCxcbiAgICAgIFtmaWVsZE5hbWVdOiBkZWZhdWx0UHJldlZhbHVlID8/ICcnLFxuICAgICAgdHJhbnNsYXRpb25zOiB7XG4gICAgICAgIC4uLnRhcmdldC50cmFuc2xhdGlvbnMsXG4gICAgICAgIFtmaWVsZE5hbWVdOiBmaWVsZFRyYW5zbGF0aW9ucyxcbiAgICAgIH0sXG4gICAgfVxuICB9XG4gIGZ1bmN0aW9uIHVwZGF0ZVRyYW5zbGF0aW9uczxUIGV4dGVuZHMgVHJhbnNsYXRlZFJlY29yZE9iamVjdHM+KFxuICAgIHRhcmdldDogVCxcbiAgICBmaWVsZE5hbWVzOiBzdHJpbmdbXVxuICApOiBUIHtcbiAgICBsZXQgcmVzdWx0OiBUID0gdGFyZ2V0XG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiBmaWVsZE5hbWVzKSB7XG4gICAgICByZXN1bHQgPSB1cGRhdGVGaWVsZFRyYW5zbGF0aW9ucyhyZXN1bHQsIGZpZWxkKVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICBjb25zdCB1cGRhdGVkUmVjb3JkID0gdXBkYXRlVHJhbnNsYXRpb25zKHJlY29yZCwgW1xuICAgICd0aXRsZScsXG4gICAgJ2Fic3RyYWN0JyxcbiAgICAnbGluZWFnZScsXG4gIF0pXG4gIHVwZGF0ZWRSZWNvcmQua2V5d29yZHMgPSB1cGRhdGVkUmVjb3JkLmtleXdvcmRzLm1hcCgoaykgPT5cbiAgICB1cGRhdGVUcmFuc2xhdGlvbnMoaywgWydsYWJlbCcsICdkZXNjcmlwdGlvbiddKVxuICApXG4gIHVwZGF0ZWRSZWNvcmQub25saW5lUmVzb3VyY2VzID0gdXBkYXRlZFJlY29yZC5vbmxpbmVSZXNvdXJjZXMubWFwKChvKSA9PlxuICAgIHVwZGF0ZVRyYW5zbGF0aW9ucyhvLCBbJ25hbWUnLCAnZGVzY3JpcHRpb24nXSlcbiAgKVxuICB1cGRhdGVkUmVjb3JkLmxpY2Vuc2VzID0gdXBkYXRlZFJlY29yZC5saWNlbnNlcy5tYXAoKGwpID0+XG4gICAgdXBkYXRlVHJhbnNsYXRpb25zKGwsIFsndGV4dCddKVxuICApXG4gIHVwZGF0ZWRSZWNvcmQubGVnYWxDb25zdHJhaW50cyA9IHVwZGF0ZWRSZWNvcmQubGVnYWxDb25zdHJhaW50cy5tYXAoKGMpID0+XG4gICAgdXBkYXRlVHJhbnNsYXRpb25zKGMsIFsndGV4dCddKVxuICApXG4gIHVwZGF0ZWRSZWNvcmQuc2VjdXJpdHlDb25zdHJhaW50cyA9IHVwZGF0ZWRSZWNvcmQuc2VjdXJpdHlDb25zdHJhaW50cy5tYXAoXG4gICAgKGMpID0+IHVwZGF0ZVRyYW5zbGF0aW9ucyhjLCBbJ3RleHQnXSlcbiAgKVxuICB1cGRhdGVkUmVjb3JkLm90aGVyQ29uc3RyYWludHMgPSB1cGRhdGVkUmVjb3JkLm90aGVyQ29uc3RyYWludHMubWFwKChjKSA9PlxuICAgIHVwZGF0ZVRyYW5zbGF0aW9ucyhjLCBbJ3RleHQnXSlcbiAgKVxuICB1cGRhdGVkUmVjb3JkLmNvbnRhY3RzID0gdXBkYXRlZFJlY29yZC5jb250YWN0cy5tYXAoKGMpID0+ICh7XG4gICAgLi4uYyxcbiAgICBvcmdhbml6YXRpb246IHVwZGF0ZVRyYW5zbGF0aW9ucyhjLm9yZ2FuaXphdGlvbiwgWyduYW1lJ10pLFxuICB9KSlcbiAgdXBkYXRlZFJlY29yZC5jb250YWN0c0ZvclJlc291cmNlID0gdXBkYXRlZFJlY29yZC5jb250YWN0c0ZvclJlc291cmNlLm1hcChcbiAgICAoYykgPT4gKHtcbiAgICAgIC4uLmMsXG4gICAgICBvcmdhbml6YXRpb246IHVwZGF0ZVRyYW5zbGF0aW9ucyhjLm9yZ2FuaXphdGlvbiwgWyduYW1lJ10pLFxuICAgIH0pXG4gIClcbiAgdXBkYXRlZFJlY29yZC5vd25lck9yZ2FuaXphdGlvbiA9IHVwZGF0ZVRyYW5zbGF0aW9ucyhcbiAgICB1cGRhdGVkUmVjb3JkLm93bmVyT3JnYW5pemF0aW9uLFxuICAgIFsnbmFtZSddXG4gIClcblxuICBpZiAodXBkYXRlZFJlY29yZC5raW5kID09PSAnZGF0YXNldCcpIHtcbiAgICB1cGRhdGVkUmVjb3JkLnNwYXRpYWxFeHRlbnRzID0gdXBkYXRlZFJlY29yZC5zcGF0aWFsRXh0ZW50cy5tYXAoKGUpID0+XG4gICAgICB1cGRhdGVUcmFuc2xhdGlvbnMoZSwgWydkZXNjcmlwdGlvbiddKVxuICAgIClcbiAgfVxuXG4gIHVwZGF0ZWRSZWNvcmQuZGVmYXVsdExhbmd1YWdlID0gZGVmYXVsdExhbmd1YWdlXG4gIHVwZGF0ZWRSZWNvcmQub3RoZXJMYW5ndWFnZXMgPSBvdGhlckxhbmd1YWdlc1xuICByZXR1cm4gdXBkYXRlZFJlY29yZFxufVxuIl19