• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geonetwork / geonetwork-ui / 12069834722

28 Nov 2024 01:27PM UTC coverage: 83.926% (+0.2%) from 83.736%
12069834722

push

github

jahow
chore: fix formatting on PULL_REQUEST_TEMPLATE.md

3159 of 4250 branches covered (74.33%)

Branch coverage included in aggregate %.

9116 of 10376 relevant lines covered (87.86%)

201.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.55
/libs/feature/record/src/lib/map-view/map-view.component.ts
1
import {
1✔
2
  AfterViewInit,
3
  ChangeDetectionStrategy,
4
  ChangeDetectorRef,
5
  Component,
6
  ViewChild,
7
} from '@angular/core'
8
import { MapUtilsService } from '@geonetwork-ui/feature/map'
1✔
9
import { getLinkLabel } from '@geonetwork-ui/util/shared'
1✔
10
import {
1✔
11
  BehaviorSubject,
12
  combineLatest,
13
  from,
14
  Observable,
15
  of,
16
  startWith,
17
  throwError,
18
  withLatestFrom,
19
} from 'rxjs'
20
import {
1✔
21
  catchError,
22
  distinctUntilChanged,
23
  finalize,
24
  map,
25
  switchMap,
26
  tap,
27
} from 'rxjs/operators'
28
import { MdViewFacade } from '../state/mdview.facade'
1✔
29
import { DataService } from '@geonetwork-ui/feature/dataviz'
1✔
30
import { DatasetOnlineResource } from '@geonetwork-ui/common/domain/model/record'
31
import {
1✔
32
  createViewFromLayer,
33
  MapContext,
34
  MapContextLayer,
35
} from '@geospatial-sdk/core'
36
import {
1✔
37
  FeatureDetailComponent,
38
  MapContainerComponent,
39
  prioritizePageScroll,
40
} from '@geonetwork-ui/ui/map'
41
import { Feature } from 'geojson'
42
import { NgIconComponent, provideIcons } from '@ng-icons/core'
1✔
43
import { matClose } from '@ng-icons/material-icons/baseline'
1✔
44
import { CommonModule } from '@angular/common'
1✔
45
import { DropdownSelectorComponent } from '@geonetwork-ui/ui/inputs'
1✔
46
import { TranslateModule } from '@ngx-translate/core'
1✔
47
import { ExternalViewerButtonComponent } from '../external-viewer-button/external-viewer-button.component'
1✔
48
import {
1✔
49
  LoadingMaskComponent,
50
  PopupAlertComponent,
51
} from '@geonetwork-ui/ui/widgets'
52

53
@Component({
54
  selector: 'gn-ui-map-view',
55
  templateUrl: './map-view.component.html',
56
  styleUrls: ['./map-view.component.css'],
57
  changeDetection: ChangeDetectionStrategy.OnPush,
58
  standalone: true,
59
  imports: [
60
    CommonModule,
61
    DropdownSelectorComponent,
62
    MapContainerComponent,
63
    FeatureDetailComponent,
64
    PopupAlertComponent,
65
    TranslateModule,
66
    LoadingMaskComponent,
67
    NgIconComponent,
68
    ExternalViewerButtonComponent,
69
  ],
70
  viewProviders: [provideIcons({ matClose })],
71
})
72
export class MapViewComponent implements AfterViewInit {
1✔
73
  @ViewChild('mapContainer') mapContainer: MapContainerComponent
74

75
  selection: Feature
76

77
  compatibleMapLinks$ = combineLatest([
36✔
78
    this.mdViewFacade.mapApiLinks$,
79
    this.mdViewFacade.geoDataLinksWithGeometry$,
80
  ]).pipe(
81
    map(([mapApiLinks, geoDataLinksWithGeometry]) => {
82
      return [...mapApiLinks, ...geoDataLinksWithGeometry]
108✔
83
    })
84
  )
85

86
  dropdownChoices$ = this.compatibleMapLinks$.pipe(
36✔
87
    map((links) =>
88
      links.length
36✔
89
        ? links.map((link, index) => ({
52✔
90
            label: getLinkLabel(link),
91
            value: index,
92
          }))
93
        : [{ label: 'No preview layer', value: 0 }]
94
    )
95
  )
96
  selectedLinkIndex$ = new BehaviorSubject(0)
36✔
97

98
  loading = false
36✔
99
  error = null
36✔
100

101
  selectedLink$ = combineLatest([
36✔
102
    this.compatibleMapLinks$,
103
    this.selectedLinkIndex$.pipe(distinctUntilChanged()),
104
  ]).pipe(map(([links, index]) => links[index]))
90✔
105

106
  currentLayers$ = this.selectedLink$.pipe(
36✔
107
    switchMap((link) => {
108
      if (!link) {
45✔
109
        return of([])
4✔
110
      }
111
      this.loading = true
41✔
112
      this.error = null
41✔
113
      return this.getLayerFromLink(link).pipe(
41✔
114
        map((layer) => [layer]),
35✔
115
        catchError((e) => {
116
          this.error = e.message
1✔
117
          console.warn(e.stack || e.message)
1!
118
          return of([])
1✔
119
        }),
120
        finalize(() => (this.loading = false))
41✔
121
      )
122
    })
123
  )
124

125
  mapContext$: Observable<MapContext> = this.currentLayers$.pipe(
36✔
126
    switchMap((layers) =>
127
      from(createViewFromLayer(layers[0])).pipe(
40✔
128
        catchError(() => of(null)), // could not zoom on the layer: use the record extent
2✔
129
        map((view) => ({
27✔
130
          layers,
131
          view,
132
        })),
133
        tap(() => {
134
          this.resetSelection()
27✔
135
        })
136
      )
137
    ),
138
    startWith({
139
      layers: [],
140
      view: null,
141
    }),
142
    withLatestFrom(this.mdViewFacade.metadata$),
143
    map(([context, metadata]) => {
144
      if (context.view) return context
63✔
145
      const extent = this.mapUtils.getRecordExtent(metadata)
60✔
146
      const view = extent ? { extent } : null
60✔
147
      return {
60✔
148
        ...context,
149
        view,
150
      }
151
    })
152
  )
153

154
  constructor(
155
    private mdViewFacade: MdViewFacade,
36!
156
    private mapUtils: MapUtilsService,
36!
157
    private dataService: DataService,
36!
158
    private changeRef: ChangeDetectorRef
36✔
159
  ) {}
160

161
  async ngAfterViewInit() {
162
    const map = await this.mapContainer.openlayersMap
36✔
163
    prioritizePageScroll(map.getInteractions())
36✔
164
  }
165

166
  onMapFeatureSelect(features: Feature[]): void {
167
    this.resetSelection()
3✔
168
    this.selection = features?.length > 0 && features[0]
3✔
169
    if (this.selection) {
3✔
170
      // FIXME: restore styling of selected feature
171
      // this.selection.setStyle(this.selectionStyle)
172
    }
173
    this.changeRef.detectChanges()
3✔
174
  }
175

176
  resetSelection(): void {
177
    if (this.selection) {
31✔
178
      // FIXME: restore styling of selected feature
179
      // this.selection.setStyle(null)
180
    }
181
    this.selection = null
31✔
182
  }
183

184
  getLayerFromLink(link: DatasetOnlineResource): Observable<MapContextLayer> {
185
    if (link.type === 'service' && link.accessServiceProtocol === 'wms') {
41✔
186
      return of({
28✔
187
        url: link.url.toString(),
188
        type: 'wms',
189
        name: link.name,
190
      })
191
    } else if (
13✔
192
      link.type === 'service' &&
19✔
193
      link.accessServiceProtocol === 'wmts'
194
    ) {
195
      return of({
1✔
196
        url: link.url.toString(),
197
        type: 'wmts',
198
        name: link.name,
199
      })
200
    } else if (
12✔
201
      (link.type === 'service' &&
29✔
202
        (link.accessServiceProtocol === 'wfs' ||
203
          link.accessServiceProtocol === 'esriRest' ||
204
          link.accessServiceProtocol === 'ogcFeatures')) ||
205
      link.type === 'download'
206
    ) {
207
      return this.dataService.readAsGeoJson(link).pipe(
12✔
208
        map((data) => ({
6✔
209
          type: 'geojson',
210
          data,
211
        }))
212
      )
213
    }
214
    return throwError(() => 'protocol not supported')
×
215
  }
216

217
  selectLinkToDisplay(link: number) {
218
    this.selectedLinkIndex$.next(link)
9✔
219
  }
220
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc