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.
- package/esm2022/libs/api/metadata-converter/src/lib/common/resource-types.mjs +6 -1
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +6 -4
- package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/constant.mjs +2 -1
- package/esm2022/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +3 -3
- package/esm2022/libs/feature/map/src/lib/map-state-container/map-state-container.component.mjs +2 -2
- package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +1 -1
- package/esm2022/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.mjs +4 -4
- package/esm2022/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.mjs +1 -1
- package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +3 -3
- package/esm2022/libs/feature/record/src/lib/stac-view/stac-view.component.mjs +140 -48
- package/esm2022/libs/feature/record/src/lib/stac-view/utils.mjs +26 -0
- package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +2 -2
- package/esm2022/libs/feature/search/src/lib/constants.mjs +2 -1
- package/esm2022/libs/feature/search/src/lib/utils/service/fields.mjs +36 -22
- package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +2 -1
- package/esm2022/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.mjs +3 -3
- package/esm2022/libs/ui/inputs/src/lib/date-range-dropdown/date-range-dropdown.component.mjs +3 -3
- package/esm2022/libs/ui/map/src/lib/components/map-container/map-container.component.mjs +86 -32
- package/esm2022/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.mjs +1 -1
- package/esm2022/libs/ui/widgets/src/lib/loading-mask/loading-mask.component.mjs +3 -3
- package/esm2022/translations/de.json +2 -0
- package/esm2022/translations/en.json +2 -0
- package/esm2022/translations/es.json +2 -0
- package/esm2022/translations/fr.json +2 -0
- package/esm2022/translations/it.json +2 -0
- package/esm2022/translations/nl.json +2 -0
- package/esm2022/translations/pt.json +2 -0
- package/esm2022/translations/sk.json +2 -0
- package/fesm2022/{geonetwork-ui-date-locales-MYnkDJ5h.mjs → geonetwork-ui-date-locales-DhlIiWpT.mjs} +2 -2
- package/fesm2022/{geonetwork-ui-date-locales-MYnkDJ5h.mjs.map → geonetwork-ui-date-locales-DhlIiWpT.mjs.map} +1 -1
- package/fesm2022/geonetwork-ui.mjs +345 -137
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts +3 -0
- package/libs/api/metadata-converter/src/lib/common/resource-types.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/elasticsearch/constant.d.ts.map +1 -1
- package/libs/feature/record/src/lib/data-view/data-view.component.d.ts +5 -1
- package/libs/feature/record/src/lib/data-view/data-view.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.d.ts +12 -5
- package/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.d.ts +3 -1
- package/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts +5 -1
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts +25 -7
- package/libs/feature/record/src/lib/stac-view/stac-view.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/stac-view/utils.d.ts +7 -0
- package/libs/feature/record/src/lib/stac-view/utils.d.ts.map +1 -0
- package/libs/feature/search/src/lib/constants.d.ts.map +1 -1
- package/libs/feature/search/src/lib/utils/service/fields.d.ts.map +1 -1
- package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
- package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts +24 -14
- package/libs/ui/map/src/lib/components/map-container/map-container.component.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/libs/api/metadata-converter/src/lib/common/resource-types.ts +11 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +11 -3
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/constant.ts +1 -0
- package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +1 -0
- package/src/libs/feature/record/src/lib/data-view/data-view.component.ts +5 -1
- package/src/libs/feature/record/src/lib/gpf-api-dl/gpf-api-dl.component.ts +10 -8
- package/src/libs/feature/record/src/lib/gpf-api-dl-list-item/gpf-api-dl-list-item.component.ts +1 -1
- package/src/libs/feature/record/src/lib/map-view/map-view.component.html +1 -2
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +5 -2
- package/src/libs/feature/record/src/lib/stac-view/stac-view.component.css +5 -0
- package/src/libs/feature/record/src/lib/stac-view/stac-view.component.html +27 -8
- package/src/libs/feature/record/src/lib/stac-view/stac-view.component.ts +201 -52
- package/src/libs/feature/record/src/lib/stac-view/utils.ts +57 -0
- package/src/libs/feature/record/src/lib/state/mdview.effects.ts +1 -1
- package/src/libs/feature/search/src/lib/constants.ts +1 -0
- package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +1 -0
- package/src/libs/feature/search/src/lib/utils/service/fields.ts +37 -33
- package/src/libs/ui/inputs/src/lib/check-toggle/check-toggle.component.html +3 -3
- package/src/libs/ui/map/src/lib/components/map-container/map-container.component.html +16 -14
- package/src/libs/ui/map/src/lib/components/map-container/map-container.component.ts +144 -65
- package/translations/de.json +2 -0
- package/translations/en.json +2 -0
- package/translations/es.json +2 -0
- package/translations/fr.json +2 -0
- package/translations/it.json +2 -0
- package/translations/nl.json +2 -0
- package/translations/pt.json +2 -0
- 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
|
|
3
|
+
class="w-full h-[700px] md:h-[366px] flex md:flex-row flex-col border-b border-gray-300"
|
|
4
4
|
>
|
|
5
|
-
|
|
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]="
|
|
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-
|
|
24
|
-
<
|
|
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="
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
58
|
-
error = null
|
|
89
|
+
export class StacViewComponent implements OnInit, AfterViewInit {
|
|
90
|
+
@ViewChild('mapContainer') mapContainer: MapContainerComponent
|
|
59
91
|
|
|
60
92
|
initialTemporalExtent: DatasetTemporalExtent | null = null
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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(
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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((
|
|
130
|
-
this.initialTemporalExtent =
|
|
131
|
-
this.
|
|
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.
|
|
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.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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.
|
|
156
|
-
|
|
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
|
|
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
|
|
312
|
+
this.error$.next(this.translateService.instant(error.message))
|
|
170
313
|
console.warn(error.stack || error)
|
|
171
314
|
} else {
|
|
172
|
-
this.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.
|
|
328
|
+
this.filterState$.next({
|
|
329
|
+
...this.filterState$.value,
|
|
330
|
+
pageUrl: this.nextPageUrl,
|
|
331
|
+
})
|
|
186
332
|
}
|
|
187
333
|
goToPrevPage() {
|
|
188
|
-
this.
|
|
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((
|
|
71
|
+
catchError(() => of(MdViewActions.setRelated({ related: null })))
|
|
72
72
|
)
|
|
73
73
|
)
|
|
74
74
|
|
|
@@ -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:
|
|
511
|
-
.
|
|
512
|
-
|
|
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
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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="
|
|
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
|
|
2
|
-
<
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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>
|