geonetwork-ui 2.8.0-dev.749c3ea3b → 2.8.0-dev.82b7031fa

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 (83) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/common/resource-types.mjs +6 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +6 -4
  3. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/constant.mjs +2 -1
  4. package/esm2022/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.mjs +2 -2
  5. package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +3 -3
  6. package/esm2022/libs/feature/map/src/lib/map-state-container/map-state-container.component.mjs +2 -2
  7. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +1 -1
  8. package/esm2022/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.mjs +4 -4
  9. package/esm2022/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.mjs +1 -1
  10. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +3 -3
  11. package/esm2022/libs/feature/record/src/lib/stac-view/stac-view.component.mjs +140 -48
  12. package/esm2022/libs/feature/record/src/lib/stac-view/utils.mjs +26 -0
  13. package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +2 -2
  14. package/esm2022/libs/feature/search/src/lib/constants.mjs +2 -1
  15. package/esm2022/libs/feature/search/src/lib/utils/service/fields.mjs +36 -22
  16. package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +2 -1
  17. package/esm2022/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.mjs +3 -3
  18. package/esm2022/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.mjs +3 -3
  19. package/esm2022/libs/ui/map/src/lib/components/map-container/map-container.component.mjs +86 -32
  20. package/esm2022/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.mjs +1 -1
  21. package/esm2022/libs/ui/widgets/src/lib/loading-mask/loading-mask.component.mjs +3 -3
  22. package/esm2022/translations/de.json +2 -0
  23. package/esm2022/translations/en.json +2 -0
  24. package/esm2022/translations/es.json +2 -0
  25. package/esm2022/translations/fr.json +2 -0
  26. package/esm2022/translations/it.json +2 -0
  27. package/esm2022/translations/nl.json +2 -0
  28. package/esm2022/translations/pt.json +2 -0
  29. package/esm2022/translations/sk.json +2 -0
  30. package/fesm2022/{geonetwork-ui-date-locales-MYnkDJ5h.mjs → geonetwork-ui-date-locales-DhlIiWpT.mjs} +2 -2
  31. package/fesm2022/{geonetwork-ui-date-locales-MYnkDJ5h.mjs.map → geonetwork-ui-date-locales-DhlIiWpT.mjs.map} +1 -1
  32. package/fesm2022/geonetwork-ui.mjs +345 -137
  33. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  34. package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts +3 -0
  35. package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts.map +1 -1
  36. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  37. package/libs/api/repository/src/lib/gn4/elasticsearch/constant.d.ts.map +1 -1
  38. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts +5 -1
  39. package/libs/feature/record/src/lib/data-view/data-view.component.d.ts.map +1 -1
  40. package/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.d.ts +12 -5
  41. package/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.d.ts.map +1 -1
  42. package/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.d.ts +3 -1
  43. package/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.d.ts.map +1 -1
  44. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +5 -1
  45. package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
  46. package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts +25 -7
  47. package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts.map +1 -1
  48. package/libs/feature/record/src/lib/stac-view/utils.d.ts +7 -0
  49. package/libs/feature/record/src/lib/stac-view/utils.d.ts.map +1 -0
  50. package/libs/feature/search/src/lib/constants.d.ts.map +1 -1
  51. package/libs/feature/search/src/lib/utils/service/fields.d.ts.map +1 -1
  52. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
  53. package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts +24 -14
  54. package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts.map +1 -1
  55. package/package.json +5 -5
  56. package/src/libs/api/metadata-converter/src/lib/common/resource-types.ts +11 -0
  57. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +11 -3
  58. package/src/libs/api/repository/src/lib/gn4/elasticsearch/constant.ts +1 -0
  59. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +1 -0
  60. package/src/libs/feature/record/src/lib/data-view/data-view.component.ts +5 -1
  61. package/src/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.ts +10 -8
  62. package/src/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.ts +1 -1
  63. package/src/libs/feature/record/src/lib/map-view/map-view.component.html +1 -2
  64. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +5 -2
  65. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.css +5 -0
  66. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.html +27 -8
  67. package/src/libs/feature/record/src/lib/stac-view/stac-view.component.ts +201 -52
  68. package/src/libs/feature/record/src/lib/stac-view/utils.ts +57 -0
  69. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +1 -1
  70. package/src/libs/feature/search/src/lib/constants.ts +1 -0
  71. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +1 -0
  72. package/src/libs/feature/search/src/lib/utils/service/fields.ts +37 -33
  73. package/src/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.html +3 -3
  74. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.html +16 -14
  75. package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +144 -65
  76. package/translations/de.json +2 -0
  77. package/translations/en.json +2 -0
  78. package/translations/es.json +2 -0
  79. package/translations/fr.json +2 -0
  80. package/translations/it.json +2 -0
  81. package/translations/nl.json +2 -0
  82. package/translations/pt.json +2 -0
  83. package/translations/sk.json +2 -0
@@ -1,14 +1,16 @@
1
1
  <div class="mt-6 bg-white border border-gray-300 overflow-hidden rounded-lg">
2
2
  <div
3
- class="w-full min-h-[366px] flex md:flex-row flex-col border-b border-gray-300"
3
+ class="w-full h-[700px] md:h-[366px] flex md:flex-row flex-col border-b border-gray-300"
4
4
  >
5
- <div class="md:w-1/2 w-full flex-1 flex flex-col">
5
+ @let filterState = filterState$ | async;
6
+
7
+ <div class="w-full md:w-5/12 h-[366px] flex flex-col">
6
8
  <gn-ui-date-range-inputs
7
- [temporalExtent]="currentTemporalExtent$ | async"
9
+ [temporalExtent]="filterState.temporalExtent"
8
10
  (temporalExtentChange)="onTemporalExtentChange($event)"
9
11
  ></gn-ui-date-range-inputs>
10
12
 
11
- <div class="mt-auto mb-8 mx-8" *ngIf="isFilterModified">
13
+ <div class="mt-auto mb-8 mx-8" *ngIf="isFilterModified$ | async">
12
14
  <gn-ui-button
13
15
  id="reset-filters-button"
14
16
  type="light"
@@ -20,8 +22,25 @@
20
22
  </div>
21
23
  </div>
22
24
 
23
- <div class="md:w-1/2 w-full min-h-[280px] flex items-center justify-center">
24
- <span>Map...</span>
25
+ <div class="w-full md:w-7/12 h-[334px] md:h-[366px] flex flex-col">
26
+ <gn-ui-map-container
27
+ #mapContainer
28
+ [context]="mapContext$ | async"
29
+ (extentChange)="onSpatialExtentChange($event)"
30
+ (resolvedExtentChange)="onResolvedMapExtentChange($event)"
31
+ class="w-full h-full"
32
+ >
33
+ <div
34
+ class="bg-white rounded-xl shadow-xl absolute left-1/2 transform -translate-x-1/2 bottom-0 mb-2.5 px-4 py-2 z-10 max-w-[90%] w-max"
35
+ >
36
+ <gn-ui-check-toggle
37
+ [value]="filterState.isSpatialExtentFilterEnabled"
38
+ (toggled)="onSpatialFilterToggle($event)"
39
+ [label]="'stac.filter.enable' | translate"
40
+ [color]="'primary'"
41
+ ></gn-ui-check-toggle>
42
+ </div>
43
+ </gn-ui-map-container>
25
44
  </div>
26
45
  </div>
27
46
  <div
@@ -42,7 +61,7 @@
42
61
  </div>
43
62
  <ng-template #noResultsOrError>
44
63
  <gn-ui-popup-alert
45
- *ngIf="error"
64
+ *ngIf="error$ | async as error"
46
65
  type="warning"
47
66
  icon="matErrorOutlineOutline"
48
67
  class="absolute left-0 top-0 w-full block"
@@ -50,7 +69,7 @@
50
69
  <span translate>{{ error }}</span>
51
70
  </gn-ui-popup-alert>
52
71
  <div
53
- *ngIf="!error"
72
+ *ngIf="(error$ | async) === null"
54
73
  class="flex items-center justify-center flex-col h-full gap-[10px]"
55
74
  >
56
75
  <h2 class="text-center text-xl" translate>stac.results.noResults</h2>
@@ -1,33 +1,56 @@
1
1
  import { CommonModule } from '@angular/common'
2
- import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'
2
+ import {
3
+ AfterViewInit,
4
+ ChangeDetectionStrategy,
5
+ Component,
6
+ OnInit,
7
+ ViewChild,
8
+ } from '@angular/core'
3
9
  import {
4
10
  DatasetRecord,
5
11
  DatasetTemporalExtent,
6
12
  } from '../../../../../../libs/common/domain/src/lib/model/record'
7
- import { StacItemsResultGridComponent } from '../../../../../../libs/ui/elements/src'
8
13
  import {
9
14
  ButtonComponent,
10
15
  DateRangeInputsComponent,
16
+ CheckToggleComponent,
11
17
  } from '../../../../../../libs/ui/inputs/src'
18
+ import {
19
+ MapContainerComponent,
20
+ prioritizePageScroll,
21
+ } from '../../../../../../libs/ui/map/src'
22
+ import { Extent, MapContext } from '@geospatial-sdk/core/dist/model'
23
+ import { StacItemsResultGridComponent } from '../../../../../../libs/ui/elements/src'
12
24
  import { NgIconComponent, provideIcons } from '@ng-icons/core'
13
25
  import { matDeleteOutline } from '@ng-icons/material-icons/outline'
14
- import { TranslateDirective, TranslateService } from '@ngx-translate/core'
26
+ import {
27
+ TranslateDirective,
28
+ TranslatePipe,
29
+ TranslateService,
30
+ } from '@ngx-translate/core'
15
31
  import { DataService } from '../../../../../../libs/feature/dataviz/src'
16
32
  import {
17
33
  BehaviorSubject,
18
34
  catchError,
19
- combineLatest,
20
35
  debounceTime,
36
+ distinctUntilChanged,
21
37
  from,
22
38
  map,
23
39
  Observable,
24
40
  of,
41
+ shareReplay,
25
42
  switchMap,
26
43
  take,
27
44
  tap,
28
45
  } from 'rxjs'
29
46
  import { GetCollectionItemsOptions, StacItem } from '@camptocamp/ogc-client'
30
47
  import { MdViewFacade } from '../state'
48
+ import {
49
+ areSpatialExtentsEqual,
50
+ areTemporalExtentsEqual,
51
+ areFilterStatesEqual,
52
+ } from './utils'
53
+ import { MapUtilsService } from '../../../../../../libs/feature/map/src'
31
54
  import { PreviousNextButtonsComponent } from '../../../../../../libs/ui/layout/src'
32
55
  import { FetchError } from '../../../../../../libs/util/data-fetcher/src'
33
56
  import { PopupAlertComponent } from '../../../../../../libs/ui/widgets/src'
@@ -35,6 +58,13 @@ import { PopupAlertComponent } from '../../../../../../libs/ui/widgets/src'
35
58
  const STAC_ITEMS_PER_PAGE = 12
36
59
  const DEBOUNCE_TIME_MS = 500
37
60
 
61
+ export interface StacFilterState {
62
+ temporalExtent: DatasetTemporalExtent | null
63
+ spatialExtent: Extent | null
64
+ isSpatialExtentFilterEnabled: boolean
65
+ pageUrl: string | null
66
+ }
67
+
38
68
  @Component({
39
69
  selector: 'gn-ui-stac-view',
40
70
  templateUrl: './stac-view.component.html',
@@ -45,46 +75,74 @@ const DEBOUNCE_TIME_MS = 500
45
75
  CommonModule,
46
76
  NgIconComponent,
47
77
  TranslateDirective,
78
+ TranslatePipe,
48
79
  StacItemsResultGridComponent,
49
80
  DateRangeInputsComponent,
81
+ MapContainerComponent,
82
+ CheckToggleComponent,
50
83
  PreviousNextButtonsComponent,
51
84
  PopupAlertComponent,
52
85
  ButtonComponent,
53
86
  ],
54
87
  viewProviders: [provideIcons({ matDeleteOutline })],
55
88
  })
56
- export class StacViewComponent implements OnInit {
57
- isFilterModified = false
58
- error = null
89
+ export class StacViewComponent implements OnInit, AfterViewInit {
90
+ @ViewChild('mapContainer') mapContainer: MapContainerComponent
59
91
 
60
92
  initialTemporalExtent: DatasetTemporalExtent | null = null
61
- currentTemporalExtent$ = new BehaviorSubject<DatasetTemporalExtent | null>(
62
- null
63
- )
64
-
93
+ initialSpatialExtent: Extent | null = null
94
+ resolvedInitialSpatialExtent: Extent | null = null
65
95
  initialPageUrl: string
66
96
  previousPageUrl: string
67
97
  nextPageUrl: string
68
- currentPageUrl$ = new BehaviorSubject<string | null>(null)
69
98
 
70
- items$: Observable<StacItem[]> = combineLatest([
71
- this.currentPageUrl$,
72
- this.currentTemporalExtent$,
73
- ]).pipe(
99
+ error$ = new BehaviorSubject<string | null>(null)
100
+ mapContext$ = new BehaviorSubject<MapContext>({
101
+ layers: [],
102
+ view: null,
103
+ })
104
+ filterState$ = new BehaviorSubject<StacFilterState>({
105
+ temporalExtent: null,
106
+ spatialExtent: null,
107
+ isSpatialExtentFilterEnabled: true,
108
+ pageUrl: null,
109
+ })
110
+
111
+ isFilterModified$ = this.filterState$.pipe(
112
+ map((filterState) => {
113
+ const isTemporalModified = !areTemporalExtentsEqual(
114
+ filterState.temporalExtent,
115
+ this.initialTemporalExtent
116
+ )
117
+
118
+ const isSpatialModified =
119
+ this.resolvedInitialSpatialExtent &&
120
+ filterState.spatialExtent !== null &&
121
+ filterState.isSpatialExtentFilterEnabled &&
122
+ !areSpatialExtentsEqual(
123
+ filterState.spatialExtent,
124
+ this.resolvedInitialSpatialExtent
125
+ )
126
+
127
+ return isTemporalModified || isSpatialModified
128
+ }),
129
+ shareReplay({ bufferSize: 1, refCount: false })
130
+ )
131
+
132
+ items$: Observable<StacItem[]> = this.filterState$.pipe(
74
133
  debounceTime(DEBOUNCE_TIME_MS),
75
- switchMap(([currentPageUrl, temporalExtent]) => {
76
- this.error = null
77
- const options: GetCollectionItemsOptions = {
78
- limit: STAC_ITEMS_PER_PAGE,
79
- }
80
- if (temporalExtent && (temporalExtent.start || temporalExtent.end)) {
81
- options.datetime = {
82
- ...(temporalExtent.start && { start: temporalExtent.start }),
83
- ...(temporalExtent.end && { end: temporalExtent.end }),
84
- }
134
+ distinctUntilChanged((prev, curr) => areFilterStatesEqual(prev, curr)),
135
+ switchMap((filterState) => {
136
+ if (filterState.pageUrl === null) {
137
+ return of([])
85
138
  }
139
+
140
+ this.error$.next(null)
86
141
  return from(
87
- this.dataService.getItemsFromStacApi(currentPageUrl, options)
142
+ this.dataService.getItemsFromStacApi(
143
+ filterState.pageUrl,
144
+ this.buildRequestOptions(filterState)
145
+ )
88
146
  ).pipe(
89
147
  tap((stacDocument) => {
90
148
  this.previousPageUrl =
@@ -99,12 +157,14 @@ export class StacViewComponent implements OnInit {
99
157
  return of([])
100
158
  })
101
159
  )
102
- })
160
+ }),
161
+ shareReplay({ bufferSize: 1, refCount: false })
103
162
  )
104
163
 
105
164
  constructor(
106
165
  private dataService: DataService,
107
166
  private metadataViewFacade: MdViewFacade,
167
+ private mapUtils: MapUtilsService,
108
168
  private translateService: TranslateService
109
169
  ) {}
110
170
 
@@ -118,17 +178,33 @@ export class StacViewComponent implements OnInit {
118
178
  ? (metadata as DatasetRecord).temporalExtents
119
179
  : []
120
180
 
121
- return temporalExtents.length > 0
122
- ? temporalExtents[0]
123
- : ({
124
- start: null,
125
- end: null,
126
- } as DatasetTemporalExtent)
181
+ const temporalExtent =
182
+ temporalExtents.length > 0
183
+ ? temporalExtents[0]
184
+ : ({
185
+ start: null,
186
+ end: null,
187
+ } as DatasetTemporalExtent)
188
+
189
+ const spatialExtent = this.mapUtils.getRecordExtent(metadata)
190
+ return { temporalExtent, spatialExtent }
127
191
  })
128
192
  )
129
- .subscribe((extent) => {
130
- this.initialTemporalExtent = extent
131
- this.currentTemporalExtent$.next(extent)
193
+ .subscribe(({ temporalExtent, spatialExtent }) => {
194
+ this.initialTemporalExtent = temporalExtent
195
+ this.initialSpatialExtent = spatialExtent
196
+
197
+ this.filterState$.next({
198
+ ...this.filterState$.value,
199
+ temporalExtent: this.initialTemporalExtent,
200
+ })
201
+
202
+ this.mapContext$.next({
203
+ ...this.mapContext$.value,
204
+ view: {
205
+ extent: spatialExtent,
206
+ },
207
+ })
132
208
  })
133
209
 
134
210
  this.metadataViewFacade.stacLinks$
@@ -139,37 +215,104 @@ export class StacViewComponent implements OnInit {
139
215
  .subscribe((link) => {
140
216
  if (link) {
141
217
  this.initialPageUrl = link.url.href
142
- this.currentPageUrl$.next(link.url.href)
218
+ this.filterState$.next({
219
+ ...this.filterState$.value,
220
+ pageUrl: link.url.href,
221
+ })
143
222
  }
144
223
  })
145
224
  }
146
225
 
226
+ async ngAfterViewInit() {
227
+ const map = await this.mapContainer.openlayersMap
228
+ prioritizePageScroll(map.getInteractions())
229
+ }
230
+
147
231
  onTemporalExtentChange(extent: DatasetTemporalExtent | null) {
148
- this.currentTemporalExtent$.next(extent)
149
- // make sure to use url without pagination token when temporal filter changes
150
- this.currentPageUrl$.next(this.initialPageUrl)
151
- this.isFilterModified = true
232
+ this.filterState$.next({
233
+ ...this.filterState$.value,
234
+ temporalExtent: extent,
235
+ pageUrl: this.initialPageUrl,
236
+ })
237
+ }
238
+
239
+ onSpatialExtentChange(extent: Extent) {
240
+ this.filterState$.next({
241
+ ...this.filterState$.value,
242
+ spatialExtent: extent,
243
+ pageUrl: this.initialPageUrl,
244
+ })
245
+ }
246
+
247
+ onResolvedMapExtentChange(extent: Extent) {
248
+ this.resolvedInitialSpatialExtent = extent
249
+ }
250
+
251
+ onSpatialFilterToggle(enabled: boolean) {
252
+ this.filterState$.next({
253
+ ...this.filterState$.value,
254
+ isSpatialExtentFilterEnabled: enabled,
255
+ pageUrl: this.initialPageUrl,
256
+ })
152
257
  }
153
258
 
154
259
  onResetFilters() {
155
- this.currentTemporalExtent$.next(this.initialTemporalExtent)
156
- this.isFilterModified = false
260
+ this.mapContext$.next({
261
+ ...this.mapContext$.value,
262
+ view: {
263
+ extent: this.initialSpatialExtent,
264
+ },
265
+ })
266
+
267
+ this.filterState$.next({
268
+ temporalExtent: this.initialTemporalExtent,
269
+ spatialExtent: this.resolvedInitialSpatialExtent,
270
+ isSpatialExtentFilterEnabled: true,
271
+ pageUrl: this.initialPageUrl,
272
+ })
273
+ }
274
+
275
+ private buildRequestOptions(
276
+ filterState: StacFilterState
277
+ ): GetCollectionItemsOptions {
278
+ const options: GetCollectionItemsOptions = {
279
+ limit: STAC_ITEMS_PER_PAGE,
280
+ }
281
+
282
+ if (
283
+ filterState.temporalExtent &&
284
+ (filterState.temporalExtent.start || filterState.temporalExtent.end)
285
+ ) {
286
+ options.datetime = {
287
+ ...(filterState.temporalExtent.start && {
288
+ start: filterState.temporalExtent.start,
289
+ }),
290
+ ...(filterState.temporalExtent.end && {
291
+ end: filterState.temporalExtent.end,
292
+ }),
293
+ }
294
+ }
295
+
296
+ if (filterState.isSpatialExtentFilterEnabled && filterState.spatialExtent) {
297
+ options.bbox = filterState.spatialExtent
298
+ }
299
+
300
+ return options
157
301
  }
158
302
 
159
303
  handleError(error: FetchError | Error | string) {
160
304
  if (error instanceof FetchError) {
161
- this.error = this.translateService.instant(
162
- `dataset.error.${error.type}`,
163
- {
305
+ this.error$.next(
306
+ this.translateService.instant(`dataset.error.${error.type}`, {
164
307
  info: error.info,
165
- }
308
+ })
166
309
  )
167
310
  console.warn(error.message)
168
311
  } else if (error instanceof Error) {
169
- this.error = this.translateService.instant(error.message)
312
+ this.error$.next(this.translateService.instant(error.message))
170
313
  console.warn(error.stack || error)
171
314
  } else {
172
- this.error = this.translateService.instant(error)
315
+ this.error$.next(this.translateService.instant(error))
173
316
  console.warn(error)
174
317
  }
175
318
  }
@@ -182,9 +325,15 @@ export class StacViewComponent implements OnInit {
182
325
  return this.nextPageUrl == null
183
326
  }
184
327
  goToNextPage() {
185
- this.currentPageUrl$.next(this.nextPageUrl)
328
+ this.filterState$.next({
329
+ ...this.filterState$.value,
330
+ pageUrl: this.nextPageUrl,
331
+ })
186
332
  }
187
333
  goToPrevPage() {
188
- this.currentPageUrl$.next(this.previousPageUrl)
334
+ this.filterState$.next({
335
+ ...this.filterState$.value,
336
+ pageUrl: this.previousPageUrl,
337
+ })
189
338
  }
190
339
  }
@@ -0,0 +1,57 @@
1
+ import { DatasetTemporalExtent } from '../../../../../../libs/common/domain/src/lib/model/record'
2
+ import { Extent } from '@geospatial-sdk/core/dist/model'
3
+ import { StacFilterState } from './stac-view.component'
4
+
5
+ export function areTemporalExtentsEqual(
6
+ previous: DatasetTemporalExtent | null,
7
+ current: DatasetTemporalExtent | null
8
+ ): boolean {
9
+ const previousStartTime = previous?.start?.getTime() ?? null
10
+ const previousEndTime = previous?.end?.getTime() ?? null
11
+
12
+ const currentStartTime = current?.start?.getTime() ?? null
13
+ const currentEndTime = current?.end?.getTime() ?? null
14
+
15
+ return (
16
+ previousStartTime === currentStartTime && previousEndTime === currentEndTime
17
+ )
18
+ }
19
+
20
+ export function areSpatialExtentsEqual(
21
+ previous: Extent | null,
22
+ current: Extent | null
23
+ ): boolean {
24
+ return (
25
+ previous?.[0] === current?.[0] &&
26
+ previous?.[1] === current?.[1] &&
27
+ previous?.[2] === current?.[2] &&
28
+ previous?.[3] === current?.[3]
29
+ )
30
+ }
31
+
32
+ export function areFilterStatesEqual(
33
+ previous: StacFilterState,
34
+ current: StacFilterState
35
+ ): boolean {
36
+ const sameTemporalExtents = areTemporalExtentsEqual(
37
+ previous.temporalExtent,
38
+ current.temporalExtent
39
+ )
40
+
41
+ const sameSpatialExtents =
42
+ !current.isSpatialExtentFilterEnabled ||
43
+ areSpatialExtentsEqual(previous.spatialExtent, current.spatialExtent)
44
+
45
+ const sameIsSpatialExtentFilterEnabled =
46
+ previous.isSpatialExtentFilterEnabled ===
47
+ current.isSpatialExtentFilterEnabled
48
+
49
+ const samePageUrl = previous.pageUrl === current.pageUrl
50
+
51
+ return (
52
+ sameTemporalExtents &&
53
+ sameSpatialExtents &&
54
+ sameIsSpatialExtentFilterEnabled &&
55
+ samePageUrl
56
+ )
57
+ }
@@ -68,7 +68,7 @@ export class MdViewEffects {
68
68
  map((related) => {
69
69
  return MdViewActions.setRelated({ related })
70
70
  }),
71
- catchError((error) => of(MdViewActions.setRelated({ related: null })))
71
+ catchError(() => of(MdViewActions.setRelated({ related: null })))
72
72
  )
73
73
  )
74
74
 
@@ -19,6 +19,7 @@ export const FIELDS_SUMMARY: FieldName[] = [
19
19
  'userSavedCount',
20
20
  'cl_topic',
21
21
  'cl_maintenanceAndUpdateFrequency',
22
+ 'cl_presentationForm',
22
23
  'MD_LegalConstraints*Object',
23
24
  'qualityScore',
24
25
  'allKeywords',
@@ -34,6 +34,7 @@ marker('search.filters.publicationYear')
34
34
  marker('search.filters.organization')
35
35
  marker('search.filters.representationType')
36
36
  marker('search.filters.resourceType')
37
+ marker('search.filters.recordKind')
37
38
  marker('search.filters.standard')
38
39
  marker('search.filters.topic')
39
40
  marker('search.filters.contact')
@@ -505,11 +505,15 @@ export class ResourceTypeLegacyField extends TranslatedSearchField {
505
505
 
506
506
  export class RecordKindField extends SimpleSearchField {
507
507
  TYPE_MAPPING = {
508
- dataset: ['dataset', 'series', 'featureCatalog'],
508
+ dataset: ['dataset', 'series', 'featureCatalog', 'document'],
509
509
  service: ['service'],
510
- reuse: Object.entries(PossibleResourceTypes)
511
- .filter(([_, v]) => v === 'reuse')
512
- .map(([k]) => k), // = ['application', 'map', 'staticMap', 'interactiveMap', ...]
510
+ reuse: [
511
+ ...Object.entries(PossibleResourceTypes)
512
+ .filter(([_, v]) => v === 'reuse')
513
+ .map(([k]) => k), // = ['application', 'map', 'staticMap', 'interactiveMap', ...]
514
+ 'dataset', // allow datasets and documents to be filtered as 'reuse' by cl_presentationForm
515
+ 'document',
516
+ ],
513
517
  }
514
518
 
515
519
  constructor(injector: Injector) {
@@ -517,38 +521,25 @@ export class RecordKindField extends SimpleSearchField {
517
521
  }
518
522
 
519
523
  getAvailableValues(): Observable<FieldAvailableValue[]> {
520
- return this.repository.aggregate(this.getAggregations()).pipe(
521
- map(
522
- (response) =>
523
- (response[this.esFieldName] as AggregationBuckets).buckets || []
524
- ),
525
- map((buckets: TermBucket[]) => {
526
- const counts = buckets.reduce(
527
- (acc, { term, count }) => {
528
- const value = term.toString()
529
- const key = this.TYPE_MAPPING.reuse.includes(value)
530
- ? 'reuse'
531
- : this.TYPE_MAPPING.dataset.includes(value)
532
- ? 'dataset'
533
- : value
534
-
535
- acc[key] = (acc[key] || 0) + count
536
- return acc
537
- },
538
- {} as Record<string, number>
539
- )
540
-
541
- return Object.keys(this.TYPE_MAPPING).map((type) => ({
542
- label: type,
543
- value: type,
544
- count: counts[type] ?? 0,
545
- }))
546
- })
547
- )
524
+ // simplified as available values now depend on 'resourceType' and 'cl_presentationForm' fields
525
+ return of([
526
+ {
527
+ label: 'dataset',
528
+ value: 'dataset',
529
+ },
530
+ {
531
+ label: 'service',
532
+ value: 'service',
533
+ },
534
+ {
535
+ label: 'reuse',
536
+ value: 'reuse',
537
+ },
538
+ ])
548
539
  }
549
540
 
550
541
  getFiltersForValues(values: FieldValue[]): Observable<FieldFilters> {
551
- const filters = {
542
+ const filters: FieldFilters = {
552
543
  [this.esFieldName]: values.reduce((acc, value) => {
553
544
  if (value === '') return { ...acc, [value]: true }
554
545
 
@@ -559,6 +550,19 @@ export class RecordKindField extends SimpleSearchField {
559
550
  }, {}),
560
551
  }
561
552
 
553
+ const presentationFormFilter = {}
554
+ if (values.includes('reuse') && !values.includes('dataset')) {
555
+ presentationFormFilter['mapDigital'] = true
556
+ presentationFormFilter['mapHardcopy'] = true
557
+ } else if (values.includes('dataset') && !values.includes('reuse')) {
558
+ presentationFormFilter['mapDigital'] = false
559
+ presentationFormFilter['mapHardcopy'] = false
560
+ }
561
+
562
+ if (Object.keys(presentationFormFilter).length > 0) {
563
+ filters['cl_presentationForm.key'] = presentationFormFilter
564
+ }
565
+
562
566
  return of(filters)
563
567
  }
564
568
 
@@ -1,8 +1,8 @@
1
1
  <label
2
- class="inline-flex relative items-start cursor-pointer"
2
+ class="flex relative items-center cursor-pointer w-full"
3
3
  [title]="title || label"
4
4
  >
5
- <span class="shrink-0">
5
+ <span class="shrink-0 relative">
6
6
  <input
7
7
  type="checkbox"
8
8
  class="sr-only peer"
@@ -18,5 +18,5 @@
18
18
  "
19
19
  ></div>
20
20
  </span>
21
- <span class="ml-3 mt-[2px] text-sm font-medium">{{ label }}</span>
21
+ <span class="ml-3 mt-[2px] text-sm font-medium flex-1">{{ label }}</span>
22
22
  </label>
@@ -1,16 +1,18 @@
1
- <div class="h-full w-full" #map></div>
2
- <div
3
- class="absolute inset-0 p-2 rounded z-40 transition-all flex flex-col justify-center items-center text-primary font-sans pointer-events-none"
4
- [ngClass]="
5
- (displayMessage$ | async) ? 'visible opacity-100' : 'invisible opacity-0'
6
- "
7
- >
1
+ <div class="relative h-full w-full" #map>
2
+ <ng-content></ng-content>
8
3
  <div
9
- class="absolute z-[-1] inset-0 bg-gradient-to-b from-white to-primary-lightest opacity-60"
10
- ></div>
11
- <ng-icon
12
- class="!w-16 !h-16 text-[64px] mb-4"
13
- name="matSwipeOutline"
14
- ></ng-icon>
15
- <p translate>map.navigation.message</p>
4
+ class="absolute inset-0 p-2 rounded z-40 transition-all flex flex-col justify-center items-center text-primary font-sans pointer-events-none"
5
+ [ngClass]="
6
+ (displayMessage$ | async) ? 'visible opacity-100' : 'invisible opacity-0'
7
+ "
8
+ >
9
+ <div
10
+ class="absolute z-[-1] inset-0 bg-gradient-to-b from-white to-primary-lightest opacity-60"
11
+ ></div>
12
+ <ng-icon
13
+ class="!w-16 !h-16 text-[64px] mb-4"
14
+ name="matSwipeOutline"
15
+ ></ng-icon>
16
+ <p translate>map.navigation.message</p>
17
+ </div>
16
18
  </div>