geonetwork-ui 2.5.0-dev.bd37f68b3 → 2.5.0-dev.caf47b863

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 (168) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +11 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
  3. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +34 -28
  4. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +22 -2
  5. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  6. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  7. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +7 -4
  8. package/esm2022/libs/feature/dataviz/src/lib/service/data.service.mjs +23 -15
  9. package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +7 -4
  10. package/esm2022/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.mjs +3 -3
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.mjs +2 -1
  12. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.mjs +2 -2
  13. package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +2 -2
  14. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +4 -3
  15. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +3 -2
  16. package/esm2022/libs/feature/record/src/lib/state/mdview.actions.mjs +4 -1
  17. package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +7 -2
  18. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +9 -1
  19. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +19 -1
  20. package/esm2022/libs/feature/record/src/lib/state/mdview.selectors.mjs +6 -1
  21. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +1 -1
  22. package/esm2022/libs/feature/search/src/lib/utils/service/fields.mjs +46 -1
  23. package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +3 -2
  24. package/esm2022/libs/ui/elements/src/index.mjs +2 -1
  25. package/esm2022/libs/ui/elements/src/lib/application-banner/application-banner.component.mjs +78 -0
  26. package/esm2022/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.mjs +3 -3
  27. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +2 -1
  28. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -4
  29. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +7 -2
  30. package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +14 -4
  31. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +10 -3
  32. package/esm2022/libs/util/data-fetcher/src/lib/data-fetcher.mjs +5 -4
  33. package/esm2022/libs/util/data-fetcher/src/lib/readers/base-cache.mjs +12 -0
  34. package/esm2022/libs/util/data-fetcher/src/lib/readers/base-file.mjs +3 -3
  35. package/esm2022/libs/util/data-fetcher/src/lib/readers/base.mjs +1 -1
  36. package/esm2022/libs/util/data-fetcher/src/lib/readers/csv.mjs +2 -2
  37. package/esm2022/libs/util/data-fetcher/src/lib/readers/excel.mjs +2 -2
  38. package/esm2022/libs/util/data-fetcher/src/lib/readers/geojson.mjs +2 -2
  39. package/esm2022/libs/util/data-fetcher/src/lib/readers/gml.mjs +5 -3
  40. package/esm2022/libs/util/data-fetcher/src/lib/readers/json.mjs +2 -2
  41. package/esm2022/libs/util/data-fetcher/src/lib/readers/wfs.mjs +19 -11
  42. package/esm2022/libs/util/data-fetcher/src/lib/utils.mjs +9 -7
  43. package/esm2022/translations/de.json +3 -4
  44. package/esm2022/translations/en.json +4 -13
  45. package/esm2022/translations/es.json +3 -4
  46. package/esm2022/translations/fr.json +15 -16
  47. package/esm2022/translations/it.json +20 -20
  48. package/esm2022/translations/nl.json +3 -4
  49. package/esm2022/translations/pt.json +3 -4
  50. package/fesm2022/geonetwork-ui.mjs +468 -219
  51. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  52. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  53. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +3 -0
  54. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
  55. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts +1 -0
  56. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  57. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +2 -1
  58. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  59. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +6 -0
  60. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  61. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +2 -1
  62. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  63. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts +2 -1
  64. package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts.map +1 -1
  65. package/libs/feature/dataviz/src/lib/service/data.service.d.ts +2 -2
  66. package/libs/feature/dataviz/src/lib/service/data.service.d.ts.map +1 -1
  67. package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts +2 -1
  68. package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts.map +1 -1
  69. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.d.ts.map +1 -1
  70. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.d.ts.map +1 -1
  71. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts +1 -0
  72. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts.map +1 -1
  73. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  74. package/libs/feature/record/src/lib/state/mdview.actions.d.ts +16 -1
  75. package/libs/feature/record/src/lib/state/mdview.actions.d.ts.map +1 -1
  76. package/libs/feature/record/src/lib/state/mdview.effects.d.ts +5 -0
  77. package/libs/feature/record/src/lib/state/mdview.effects.d.ts.map +1 -1
  78. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +2 -0
  79. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  80. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts +4 -1
  81. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts.map +1 -1
  82. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts +2 -0
  83. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts.map +1 -1
  84. package/libs/feature/search/src/lib/utils/service/fields.d.ts +10 -0
  85. package/libs/feature/search/src/lib/utils/service/fields.d.ts.map +1 -1
  86. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
  87. package/libs/ui/elements/src/index.d.ts +1 -0
  88. package/libs/ui/elements/src/index.d.ts.map +1 -1
  89. package/libs/ui/elements/src/lib/application-banner/application-banner.component.d.ts +16 -0
  90. package/libs/ui/elements/src/lib/application-banner/application-banner.component.d.ts.map +1 -0
  91. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
  92. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +2 -1
  93. package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
  94. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  95. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +4 -2
  96. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
  97. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +3 -1
  98. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  99. package/libs/util/data-fetcher/src/lib/data-fetcher.d.ts +2 -2
  100. package/libs/util/data-fetcher/src/lib/data-fetcher.d.ts.map +1 -1
  101. package/libs/util/data-fetcher/src/lib/readers/base-cache.d.ts +8 -0
  102. package/libs/util/data-fetcher/src/lib/readers/base-cache.d.ts.map +1 -0
  103. package/libs/util/data-fetcher/src/lib/readers/base-file.d.ts +2 -2
  104. package/libs/util/data-fetcher/src/lib/readers/base-file.d.ts.map +1 -1
  105. package/libs/util/data-fetcher/src/lib/readers/base.d.ts +2 -2
  106. package/libs/util/data-fetcher/src/lib/readers/base.d.ts.map +1 -1
  107. package/libs/util/data-fetcher/src/lib/readers/gml.d.ts +5 -3
  108. package/libs/util/data-fetcher/src/lib/readers/gml.d.ts.map +1 -1
  109. package/libs/util/data-fetcher/src/lib/readers/wfs.d.ts +7 -4
  110. package/libs/util/data-fetcher/src/lib/readers/wfs.d.ts.map +1 -1
  111. package/libs/util/data-fetcher/src/lib/utils.d.ts +2 -2
  112. package/libs/util/data-fetcher/src/lib/utils.d.ts.map +1 -1
  113. package/package.json +1 -1
  114. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +25 -0
  115. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +4 -0
  116. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +36 -27
  117. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +41 -2
  118. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +3 -1
  119. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +4 -1
  120. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +75 -0
  121. package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +4 -1
  122. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +42 -21
  123. package/src/libs/feature/dataviz/src/lib/table-view/table-view.component.ts +2 -1
  124. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.html +1 -1
  125. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.ts +1 -0
  126. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +1 -1
  127. package/src/libs/feature/editor/src/lib/fields.config.ts +1 -1
  128. package/src/libs/feature/record/src/lib/data-view/data-view.component.html +2 -0
  129. package/src/libs/feature/record/src/lib/data-view/data-view.component.ts +3 -0
  130. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +2 -1
  131. package/src/libs/feature/record/src/lib/state/mdview.actions.ts +16 -0
  132. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +21 -2
  133. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +15 -0
  134. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +30 -1
  135. package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +12 -0
  136. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +2 -0
  137. package/src/libs/feature/search/src/lib/utils/service/fields.ts +55 -0
  138. package/src/libs/ui/elements/src/index.ts +1 -0
  139. package/src/libs/ui/elements/src/lib/application-banner/application-banner.component.css +0 -0
  140. package/src/libs/ui/elements/src/lib/application-banner/application-banner.component.html +25 -0
  141. package/src/libs/ui/elements/src/lib/application-banner/application-banner.component.ts +70 -0
  142. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  143. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +2 -0
  144. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +3 -0
  145. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +6 -0
  146. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +37 -1
  147. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +8 -2
  148. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +2 -0
  149. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +6 -0
  150. package/src/libs/util/data-fetcher/src/lib/data-fetcher.ts +13 -4
  151. package/src/libs/util/data-fetcher/src/lib/readers/base-cache.ts +14 -0
  152. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +2 -1
  153. package/src/libs/util/data-fetcher/src/lib/readers/base.ts +2 -2
  154. package/src/libs/util/data-fetcher/src/lib/readers/csv.ts +1 -1
  155. package/src/libs/util/data-fetcher/src/lib/readers/excel.ts +1 -1
  156. package/src/libs/util/data-fetcher/src/lib/readers/geojson.ts +1 -1
  157. package/src/libs/util/data-fetcher/src/lib/readers/gml.ts +7 -7
  158. package/src/libs/util/data-fetcher/src/lib/readers/json.ts +1 -1
  159. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +34 -11
  160. package/src/libs/util/data-fetcher/src/lib/utils.ts +36 -32
  161. package/translations/de.json +3 -4
  162. package/translations/en.json +4 -13
  163. package/translations/es.json +3 -4
  164. package/translations/fr.json +15 -16
  165. package/translations/it.json +20 -20
  166. package/translations/nl.json +3 -4
  167. package/translations/pt.json +3 -4
  168. package/translations/sk.json +3 -4
@@ -164,18 +164,26 @@ export class DataService {
164
164
  wfsLink.url.toString(),
165
165
  wfsLink.name
166
166
  ).pipe(
167
- map((urls) => urls.all),
168
- map((urls) =>
169
- Object.keys(urls).map((format) => ({
170
- ...wfsLink,
171
- name: wfsLink.name,
172
- type: 'download',
173
- url: new URL(urls[format]),
174
- mimeType: getMimeTypeForFormat(
175
- getFileFormatFromServiceOutput(format)
176
- ),
177
- }))
178
- )
167
+ map((urls) => {
168
+ if (urls.geojson) {
169
+ urls.all['application/json'] = urls.geojson
170
+ }
171
+ return urls
172
+ }),
173
+ map((urls) => {
174
+ const resources: DatasetOnlineResource[] = Object.keys(urls.all).map(
175
+ (format) => ({
176
+ ...wfsLink,
177
+ name: wfsLink.name,
178
+ type: 'download' as const,
179
+ url: new URL(urls.all[format]),
180
+ mimeType: getMimeTypeForFormat(
181
+ getFileFormatFromServiceOutput(format)
182
+ ),
183
+ })
184
+ )
185
+ return resources
186
+ })
179
187
  )
180
188
  }
181
189
 
@@ -234,8 +242,11 @@ export class DataService {
234
242
  }))
235
243
  }
236
244
 
237
- readAsGeoJson(link: DatasetOnlineResource): Observable<FeatureCollection> {
238
- return this.getDataset(link).pipe(
245
+ readAsGeoJson(
246
+ link: DatasetOnlineResource,
247
+ cacheActive: boolean
248
+ ): Observable<FeatureCollection> {
249
+ return this.getDataset(link, cacheActive).pipe(
239
250
  switchMap((dataset) => dataset.selectAll().read()),
240
251
  map((features) => ({
241
252
  type: 'FeatureCollection',
@@ -244,13 +255,21 @@ export class DataService {
244
255
  )
245
256
  }
246
257
 
247
- getDataset(link: DatasetOnlineResource): Observable<BaseReader> {
258
+ getDataset(
259
+ link: DatasetOnlineResource,
260
+ cacheActive: boolean
261
+ ): Observable<BaseReader> {
248
262
  if (link.type === 'service' && link.accessServiceProtocol === 'wfs') {
249
263
  const wfsUrlEndpoint = this.proxy.getProxiedUrl(link.url.toString())
250
264
  return from(
251
- openDataset(wfsUrlEndpoint, 'wfs', {
252
- wfsFeatureType: link.name,
253
- })
265
+ openDataset(
266
+ wfsUrlEndpoint,
267
+ 'wfs',
268
+ {
269
+ wfsFeatureType: link.name,
270
+ },
271
+ cacheActive
272
+ )
254
273
  )
255
274
  } else if (link.type === 'download') {
256
275
  const linkProxifiedUrl = this.proxy.getProxiedUrl(link.url.toString())
@@ -259,7 +278,9 @@ export class DataService {
259
278
  SupportedTypes.indexOf(format as any) > -1
260
279
  ? (format as SupportedType)
261
280
  : undefined
262
- return from(openDataset(linkProxifiedUrl, supportedType)).pipe()
281
+ return from(
282
+ openDataset(linkProxifiedUrl, supportedType, undefined, cacheActive)
283
+ ).pipe()
263
284
  } else if (
264
285
  link.type === 'service' &&
265
286
  link.accessServiceProtocol === 'esriRest'
@@ -268,7 +289,7 @@ export class DataService {
268
289
  link.url.toString(),
269
290
  'geojson'
270
291
  )
271
- return from(openDataset(url, 'geojson')).pipe()
292
+ return from(openDataset(url, 'geojson', undefined, cacheActive)).pipe()
272
293
  } else if (
273
294
  link.type === 'service' &&
274
295
  link.accessServiceProtocol === 'ogcFeatures'
@@ -276,7 +297,7 @@ export class DataService {
276
297
  return from(this.getDownloadUrlsFromOgcApi(link.url.href)).pipe(
277
298
  switchMap((collectionInfo) => {
278
299
  const geojsonUrl = collectionInfo.jsonDownloadLink
279
- return openDataset(geojsonUrl, 'geojson')
300
+ return openDataset(geojsonUrl, 'geojson', undefined, cacheActive)
280
301
  }),
281
302
  tap((url) => {
282
303
  if (url === null) {
@@ -33,6 +33,7 @@ import { CommonModule } from '@angular/common'
33
33
  standalone: true,
34
34
  })
35
35
  export class TableViewComponent {
36
+ @Input() cacheActive = true
36
37
  @Input() set link(value: DatasetOnlineResource) {
37
38
  this.currentLink$.next(value)
38
39
  }
@@ -66,7 +67,7 @@ export class TableViewComponent {
66
67
  ) {}
67
68
 
68
69
  getDatasetReader(link: DatasetOnlineResource): Observable<BaseReader> {
69
- return this.dataService.getDataset(link)
70
+ return this.dataService.getDataset(link, this.cacheActive)
70
71
  }
71
72
 
72
73
  onTableSelect(event) {
@@ -2,7 +2,7 @@
2
2
  <gn-ui-form-field-rich
3
3
  class="mt-[-8px]"
4
4
  [label]="label"
5
- [hint]="hint | translate"
5
+ [placeholder]="hint | translate"
6
6
  [value]="constraint_.text ?? ''"
7
7
  (valueChange)="handleConstraintTextChange($event)"
8
8
  ></gn-ui-form-field-rich>
@@ -79,6 +79,7 @@ export class FormFieldContactsForResourceComponent
79
79
  'owner',
80
80
  'point_of_contact',
81
81
  'author',
82
+ 'publisher',
82
83
  ]
83
84
 
84
85
  roleSectionsToDisplay: Role[] = []
@@ -28,7 +28,7 @@ import { FormFieldWrapperComponent } from '../../../../../../../../../libs/ui/la
28
28
  export class FormFieldRichComponent {
29
29
  @Input() label: string
30
30
  @Input() hint: string
31
- @Input() placeholder = 'Votre texte ici' //TODO: translate
31
+ @Input() placeholder = ''
32
32
  @Input() value: string
33
33
 
34
34
  @Output() valueChange: EventEmitter<string> = new EventEmitter()
@@ -275,8 +275,8 @@ export const DEFAULT_CONFIGURATION: EditorConfig = {
275
275
  labelKey: marker('editor.record.form.page.description'),
276
276
  sections: [
277
277
  TITLE_SECTION,
278
- ABOUT_SECTION,
279
278
  CLASSIFICATION_SECTION,
279
+ ABOUT_SECTION,
280
280
  GEOGRAPHICAL_COVERAGE_SECTION,
281
281
  ],
282
282
  },
@@ -11,11 +11,13 @@
11
11
  <div class="relative h-[460px]">
12
12
  <gn-ui-table-view
13
13
  *ngIf="mode === 'table'"
14
+ [cacheActive]="cacheActive$ | async"
14
15
  [link]="selectedLink$ | async"
15
16
  ></gn-ui-table-view>
16
17
  <gn-ui-chart-view
17
18
  *ngIf="mode === 'chart'"
18
19
  (chartConfig$)="setChartConfig($event)"
20
+ [cacheActive]="cacheActive$ | async"
19
21
  [link]="selectedLink$ | async"
20
22
  ></gn-ui-chart-view>
21
23
  </div>
@@ -36,6 +36,9 @@ export class DataViewComponent {
36
36
  @Input() mode: 'table' | 'chart'
37
37
  @Input() displaySource = true
38
38
  @Output() chartConfig$ = new BehaviorSubject<DatavizConfigurationModel>(null)
39
+ cacheActive$ = this.mdViewFacade.isHighUpdateFrequency$.pipe(
40
+ map((highF) => !highF)
41
+ )
39
42
  compatibleDataLinks$ = combineLatest([
40
43
  this.mdViewFacade.dataLinks$,
41
44
  this.mdViewFacade.geoDataLinks$,
@@ -239,7 +239,8 @@ export class MapViewComponent implements AfterViewInit {
239
239
  link.accessServiceProtocol === 'ogcFeatures')) ||
240
240
  link.type === 'download'
241
241
  ) {
242
- return this.dataService.readAsGeoJson(link).pipe(
242
+ const cacheActive = true // TODO implement whether should be true or false
243
+ return this.dataService.readAsGeoJson(link, cacheActive).pipe(
243
244
  map((data) => ({
244
245
  type: 'geojson',
245
246
  data,
@@ -2,6 +2,7 @@ import { DatavizConfigurationModel } from '../../../../../../libs/common/domain/
2
2
  import { createAction, props } from '@ngrx/store'
3
3
  import {
4
4
  CatalogRecord,
5
+ DatasetFeatureCatalog,
5
6
  UserFeedback,
6
7
  } from '../../../../../../libs/common/domain/src/lib/model/record'
7
8
 
@@ -28,6 +29,21 @@ export const loadFullMetadataFailure = createAction(
28
29
  props<{ otherError?: string; notFound?: boolean }>()
29
30
  )
30
31
 
32
+ export const loadFeatureCatalog = createAction(
33
+ "[Metadata view] Load metadata's feature catalog",
34
+ props<{ metadata: CatalogRecord }>()
35
+ )
36
+
37
+ export const loadFeatureCatalogSuccess = createAction(
38
+ '[Metadata view] Load metadata feature catalog success',
39
+ props<{ datasetCatalog: DatasetFeatureCatalog | null }>()
40
+ )
41
+
42
+ export const loadFeatureCatalogFailure = createAction(
43
+ '[Metadata view] Load metadata feature catalog failure',
44
+ props<{ error?: string }>()
45
+ )
46
+
31
47
  export const closeMetadata = createAction('[Metadata view] close')
32
48
 
33
49
  /*
@@ -1,11 +1,10 @@
1
1
  import { Injectable } from '@angular/core'
2
2
  import { Actions, createEffect, ofType } from '@ngrx/effects'
3
3
  import { exhaustMap, mergeMap, of } from 'rxjs'
4
- import { catchError, map, switchMap } from 'rxjs/operators'
4
+ import { catchError, filter, map, switchMap, take } from 'rxjs/operators'
5
5
  import * as MdViewActions from './mdview.actions'
6
6
  import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
7
7
  import { PlatformServiceInterface } from '../../../../../../libs/common/domain/src/lib/platform.service.interface'
8
-
9
8
  @Injectable()
10
9
  export class MdViewEffects {
11
10
  constructor(
@@ -33,6 +32,26 @@ export class MdViewEffects {
33
32
  )
34
33
  )
35
34
 
35
+ loadFeatureCatalog$ = createEffect(() =>
36
+ this.actions$.pipe(
37
+ ofType(MdViewActions.loadFullMetadataSuccess),
38
+ filter(({ full }) => full !== undefined),
39
+ switchMap(({ full }) => this.recordsRepository.getFeatureCatalog(full)),
40
+ map((featureCatalog) =>
41
+ MdViewActions.loadFeatureCatalogSuccess({
42
+ datasetCatalog: featureCatalog,
43
+ })
44
+ ),
45
+ catchError((error) =>
46
+ of(
47
+ MdViewActions.loadFeatureCatalogFailure({
48
+ error: error.message,
49
+ })
50
+ )
51
+ )
52
+ )
53
+ )
54
+
36
55
  /*
37
56
  Related effects
38
57
  */
@@ -52,11 +52,26 @@ export class MdViewFacade {
52
52
  filter((md) => !!md)
53
53
  )
54
54
 
55
+ featureCatalog$ = this.store.pipe(select(MdViewSelectors.getFeatureCatalog))
56
+
55
57
  isIncomplete$ = this.store.pipe(
56
58
  select(MdViewSelectors.getMetadataIsIncomplete),
57
59
  filter((incomplete) => incomplete !== null)
58
60
  )
59
61
 
62
+ isHighUpdateFrequency$ = this.metadata$.pipe(
63
+ map((record) => {
64
+ if (record.updateFrequency instanceof Object) {
65
+ return (
66
+ record.updateFrequency.per === 'day' &&
67
+ record.updateFrequency.updatedTimes > 1
68
+ )
69
+ }
70
+
71
+ return record.updateFrequency === 'continual'
72
+ })
73
+ )
74
+
60
75
  error$ = this.store.pipe(select(MdViewSelectors.getMetadataError))
61
76
 
62
77
  related$ = this.store.pipe(select(MdViewSelectors.getRelated))
@@ -3,6 +3,7 @@ import * as MetadataViewActions from './mdview.actions'
3
3
  import { DatavizConfigurationModel } from '../../../../../../libs/common/domain/src/lib/model/dataviz/dataviz-configuration.model'
4
4
  import {
5
5
  CatalogRecord,
6
+ DatasetFeatureCatalog,
6
7
  UserFeedback,
7
8
  } from '../../../../../../libs/common/domain/src/lib/model/record'
8
9
 
@@ -17,6 +18,9 @@ export interface MetadataViewState {
17
18
  allUserFeedbacksLoading: boolean
18
19
  addUserFeedbackLoading: boolean
19
20
  chartConfig?: DatavizConfigurationModel
21
+ featureCatalog?: DatasetFeatureCatalog
22
+ featureCatalogLoading: boolean
23
+ featureCatalogError: string | null
20
24
  }
21
25
 
22
26
  export const initialMetadataViewState: MetadataViewState = {
@@ -24,6 +28,8 @@ export const initialMetadataViewState: MetadataViewState = {
24
28
  loadingFull: false,
25
29
  allUserFeedbacksLoading: false,
26
30
  addUserFeedbackLoading: false,
31
+ featureCatalogLoading: false,
32
+ featureCatalogError: null,
27
33
  }
28
34
 
29
35
  const metadataViewReducer = createReducer(
@@ -105,7 +111,30 @@ const metadataViewReducer = createReducer(
105
111
  addUserFeedbackLoading: false,
106
112
  allUserFeedbacksLoading: false,
107
113
  })
108
- )
114
+ ),
115
+
116
+ /**
117
+ * FeatureCatalog reducers
118
+ */
119
+
120
+ on(MetadataViewActions.loadFeatureCatalog, (state) => ({
121
+ ...state,
122
+ featureCatalogError: null,
123
+ featureCatalogLoading: true,
124
+ })),
125
+ on(
126
+ MetadataViewActions.loadFeatureCatalogSuccess,
127
+ (state, { datasetCatalog }) => ({
128
+ ...state,
129
+ featureCatalog: datasetCatalog,
130
+ featureCatalogLoading: false,
131
+ })
132
+ ),
133
+ on(MetadataViewActions.loadFeatureCatalogFailure, (state, { error }) => ({
134
+ ...state,
135
+ featureCatalogError: error,
136
+ featureCatalogLoading: false,
137
+ }))
109
138
  )
110
139
 
111
140
  export function reducer(
@@ -64,3 +64,15 @@ export const getAddUserFeedbacksLoading = createSelector(
64
64
  getMdViewState,
65
65
  (state: MetadataViewState) => state.addUserFeedbackLoading
66
66
  )
67
+
68
+ /*
69
+ Feature Catalog Selectors
70
+ */
71
+ export const getFeatureCatalog = createSelector(
72
+ getMdViewState,
73
+ (state: MetadataViewState) => state.featureCatalog
74
+ )
75
+ export const getFeatureCatalogIsLoading = createSelector(
76
+ getMdViewState,
77
+ (state: MetadataViewState) => state.featureCatalogLoading
78
+ )
@@ -1,6 +1,7 @@
1
1
  import { Injectable, Injector } from '@angular/core'
2
2
  import {
3
3
  AbstractSearchField,
4
+ AvailableServicesField,
4
5
  DateRangeSearchField,
5
6
  FieldValue,
6
7
  FullTextSearchField,
@@ -91,6 +92,7 @@ export class FieldsService {
91
92
  ),
92
93
  user: new UserSearchField(this.injector),
93
94
  changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
95
+ availableServices: new AvailableServicesField(this.injector),
94
96
  } as Record<string, AbstractSearchField>
95
97
 
96
98
  get supportedFields() {
@@ -9,6 +9,7 @@ import { PlatformServiceInterface } from '../../../../../../../libs/common/domai
9
9
  import {
10
10
  AggregationBuckets,
11
11
  AggregationsParams,
12
+ FieldFilter,
12
13
  FieldFilterByExpression,
13
14
  FieldFilters,
14
15
  TermBucket,
@@ -425,3 +426,57 @@ export class DateRangeSearchField extends SimpleSearchField {
425
426
  return 'dateRange'
426
427
  }
427
428
  }
429
+
430
+ marker('search.filters.availableServices.view')
431
+ marker('search.filters.availableServices.download')
432
+
433
+ export class AvailableServicesField extends SimpleSearchField {
434
+ private translateService = this.injector.get(TranslateService)
435
+
436
+ constructor(injector: Injector) {
437
+ super('availableServices', injector, 'asc')
438
+ }
439
+
440
+ linkProtocolViewFilter = '/OGC:WMT?S.*/'
441
+ linkProtocolDownloadFilter = '/OGC:WFS.*/'
442
+
443
+ protected async getBucketLabel(bucket: TermBucket) {
444
+ return firstValueFrom(
445
+ this.translateService.get(
446
+ `search.filters.availableServices.${bucket.term}`
447
+ )
448
+ )
449
+ }
450
+
451
+ protected getAggregations(): AggregationsParams {
452
+ return {
453
+ availableServices: {
454
+ type: 'filters',
455
+ filters: {
456
+ view: `+linkProtocol:${this.linkProtocolViewFilter}`,
457
+ download: `+linkProtocol:${this.linkProtocolDownloadFilter}`,
458
+ },
459
+ },
460
+ }
461
+ }
462
+
463
+ getFiltersForValues(values: FieldValue[]): Observable<FieldFilters> {
464
+ const filters: FieldFilter = {}
465
+ if (values.includes('view')) filters[this.linkProtocolViewFilter] = true
466
+ if (values.includes('download'))
467
+ filters[this.linkProtocolDownloadFilter] = true
468
+
469
+ return of({
470
+ linkProtocol: filters,
471
+ })
472
+ }
473
+
474
+ getValuesForFilter(filters: FieldFilters): Observable<FieldValue[]> {
475
+ const linkFilter = filters.linkProtocol
476
+ if (!linkFilter) return of([])
477
+ const values = []
478
+ if (linkFilter[this.linkProtocolViewFilter]) values.push('view')
479
+ if (linkFilter[this.linkProtocolDownloadFilter]) values.push('download')
480
+ return of(values)
481
+ }
482
+ }
@@ -22,3 +22,4 @@ export * from './lib/thumbnail/thumbnail.component'
22
22
  export * from './lib/ui-elements.module'
23
23
  export * from './lib/user-feedback-item/user-feedback-item.component'
24
24
  export * from './lib/user-preview/user-preview.component'
25
+ export * from './lib/application-banner/application-banner.component'
@@ -0,0 +1,25 @@
1
+ <div
2
+ *ngIf="message && bannerOpen"
3
+ class="absolute left-0 right-0 text-wrap bg-white mt-4 max-h-24"
4
+ >
5
+ <div
6
+ class="flex flex-row py-2.5 px-5 gap-5 justify-start border max-h-20"
7
+ [ngClass]="classList"
8
+ >
9
+ <div [ngClass]="message.length > 200 ? 'pt-5' : 'pt-1'">
10
+ <ng-icon [name]="icon"></ng-icon>
11
+ </div>
12
+ <div class="flex flex-col justify-start gap-2.5">
13
+ <span *ngIf="title" class="font-bold">{{ title }}</span>
14
+ <span class="font-medium max-w-2xl" [innerHTML]="message"></span>
15
+ </div>
16
+ <button
17
+ *ngIf="closeEnabled"
18
+ class="self-start"
19
+ type="button"
20
+ (click)="closeMessage()"
21
+ >
22
+ <ng-icon name="matCloseOutline"> </ng-icon>
23
+ </button>
24
+ </div>
25
+ </div>
@@ -0,0 +1,70 @@
1
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
+ import { CommonModule } from '@angular/common'
3
+ import {
4
+ NgIconComponent,
5
+ provideIcons,
6
+ provideNgIconsConfig,
7
+ } from '@ng-icons/core'
8
+ import {
9
+ matCloseOutline,
10
+ matInfoOutline,
11
+ matWarningAmberOutline,
12
+ } from '@ng-icons/material-icons/outline'
13
+ import { matWarning } from '@ng-icons/material-icons/baseline'
14
+
15
+ @Component({
16
+ selector: 'gn-ui-application-banner',
17
+ standalone: true,
18
+ imports: [CommonModule, NgIconComponent],
19
+ changeDetection: ChangeDetectionStrategy.OnPush,
20
+ templateUrl: './application-banner.component.html',
21
+ styleUrl: './application-banner.component.css',
22
+ providers: [
23
+ provideIcons({
24
+ matWarningAmberOutline,
25
+ matInfoOutline,
26
+ matCloseOutline,
27
+ matWarning,
28
+ }),
29
+ provideNgIconsConfig({ size: '1.5em' }),
30
+ ],
31
+ })
32
+ export class ApplicationBannerComponent {
33
+ @Input() message: string
34
+ @Input() title: string
35
+ @Input() closeEnabled = false
36
+ @Input() extraClass = ''
37
+ @Input() icon = ''
38
+ msgClass = ''
39
+ bannerOpen = true
40
+
41
+ @Input() set type(value: 'primary' | 'secondary' | 'light') {
42
+ switch (value) {
43
+ case 'primary':
44
+ this.msgClass = 'bg-primary-darkest border-primary text-white'
45
+ this.icon = 'matWarning'
46
+ break
47
+ case 'light':
48
+ this.msgClass =
49
+ 'bg-primary-opacity-10 border-primary-lightest text-black'
50
+ this.icon = 'matInfoOutline'
51
+ break
52
+ case 'secondary':
53
+ default:
54
+ this.msgClass = 'bg-primary-opacity-50 border-primary-darker text-black'
55
+ this.icon = 'matWarningAmberOutline'
56
+ break
57
+ }
58
+ }
59
+
60
+ get classList() {
61
+ if (this.message.length > 200) {
62
+ return `${this.msgClass} ${this.extraClass} overflow-y-scroll items-start`
63
+ }
64
+ return `${this.msgClass} ${this.extraClass} items-center`
65
+ }
66
+
67
+ closeMessage() {
68
+ this.bannerOpen = false
69
+ }
70
+ }
@@ -1,4 +1,4 @@
1
- import { Component, Input, ChangeDetectionStrategy } from '@angular/core'
1
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
2
2
  import { marked } from 'marked'
3
3
 
4
4
  @Component({
@@ -13,6 +13,6 @@ export class MarkdownParserComponent {
13
13
  @Input() whitoutStyles?: boolean
14
14
 
15
15
  get parsedMarkdown() {
16
- return marked.parse(this.textContent)
16
+ return marked.parse(this.textContent ?? '')
17
17
  }
18
18
  }
@@ -161,6 +161,8 @@ export class RecordApiFormComponent {
161
161
  maxFeatures: limit !== '-1' ? Number(limit) : undefined,
162
162
  limit: limit !== '-1' ? Number(limit) : -1,
163
163
  offset: offset !== '' ? Number(offset) : undefined,
164
+ outputCrs:
165
+ format === ('application/json' || 'geojson') ? 'EPSG:4326' : undefined,
164
166
  }
165
167
 
166
168
  if (this.endpoint instanceof WfsEndpoint) {
@@ -19,6 +19,7 @@ import { MarkdownParserComponent } from './markdown-parser/markdown-parser.compo
19
19
  import { ThumbnailComponent } from './thumbnail/thumbnail.component'
20
20
  import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
21
21
  import { UserPreviewComponent } from './user-preview/user-preview.component'
22
+ import { ApplicationBannerComponent } from './application-banner/application-banner.component'
22
23
 
23
24
  @NgModule({
24
25
  imports: [
@@ -40,6 +41,7 @@ import { UserPreviewComponent } from './user-preview/user-preview.component'
40
41
  MaxLinesComponent,
41
42
  TextInputComponent,
42
43
  ImageInputComponent,
44
+ ApplicationBannerComponent,
43
45
  ],
44
46
  providers: [
45
47
  provideNgIconsConfig({
@@ -53,6 +55,7 @@ import { UserPreviewComponent } from './user-preview/user-preview.component'
53
55
  UserPreviewComponent,
54
56
  MarkdownParserComponent,
55
57
  ImageInputComponent,
58
+ ApplicationBannerComponent,
56
59
  ],
57
60
  })
58
61
  export class UiElementsModule {}
@@ -147,6 +147,12 @@ export class AutocompleteComponent
147
147
  this.error = null
148
148
  }),
149
149
  switchMap((value) => this.action(value)),
150
+ tap((suggestions) => {
151
+ // forcing the panel to open if there are suggestions
152
+ if (suggestions.length > 0) {
153
+ this.triggerRef?.openPanel()
154
+ }
155
+ }),
150
156
  catchError((error: Error) => {
151
157
  this.error = error.message
152
158
  return of([])