Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Map-Viewer] Add layer from WMS service #768

Merged
merged 8 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.input-container {
display: flex;
align-items: center;
margin-bottom: 20px;
}
jahow marked this conversation as resolved.
Show resolved Hide resolved

.error-message {
color: red;
margin-top: 10px;
}

.layer-title {
max-width: 300px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}

.child-layer {
display: flex;
align-items: center;
justify-content: space-between;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<div class="input-container">
<gn-ui-text-input
[(value)]="wmsUrl"
(valueChange)="urlChange.next($event); isInvalidUrl = false"
hint="Enter WMS service URL"
style="width: 400px"
class="wms-url-input"
>
</gn-ui-text-input>
</div>

<div *ngIf="isInvalidUrl" class="error-message">
{{ errorMessage }}
</div>

<div *ngIf="loading">
<p class="loading-message">Loading...</p>
</div>

<div *ngIf="!loading && layers.length > 0">
<h2 class="available-layers-header" style="font-weight: bolder">
Available Layers
</h2>
<div *ngFor="let layer of layers">
<gn-ui-expandable-panel title="{{ layer.title }}" [collapsed]="true">
<div *ngIf="layer.children.length > 0; else noChildren">
<div *ngFor="let child of layer.children" class="child-layer">
<span class="layer-title" [attr.title]="child.title">{{
child.title
}}</span>
<gn-ui-button
type="primary"
(buttonClick)="addLayer(child)"
style="font-size: 0.8em; padding: 5px 10px"
>Add</gn-ui-button
>
</div>
</div>
<ng-template #noChildren>
<div class="child-layer">
<p class="layer-title">{{ layer.title }}</p>
<gn-ui-button
type="primary"
(buttonClick)="addLayer(layer)"
style="font-size: 0.8em; padding: 5px 10px"
>Add</gn-ui-button
>
</div>
</ng-template>
</gn-ui-expandable-panel>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { AddLayerFromWmsComponent } from './add-layer-from-wms.component'
import { MapFacade } from '../+state/map.facade'
import { Store } from '@ngrx/store'
import { NO_ERRORS_SCHEMA } from '@angular/core'

class MapFacadeMock {
addLayer = jest.fn()
}

describe('AddLayerFromWmsComponent', () => {
let component: AddLayerFromWmsComponent
let fixture: ComponentFixture<AddLayerFromWmsComponent>
let mapFacade: MapFacade

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AddLayerFromWmsComponent],
providers: [
{
provide: MapFacade,
useClass: MapFacadeMock,
},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents()

mapFacade = TestBed.inject(MapFacade)
fixture = TestBed.createComponent(AddLayerFromWmsComponent)
component = fixture.componentInstance
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Component, ChangeDetectorRef, OnInit } from '@angular/core'
import { WmsEndpoint, WmsLayerSummary } from '@camptocamp/ogc-client'
import { MapFacade } from '../+state/map.facade'
import {
MapContextLayerModel,
MapContextLayerTypeEnum,
} from '../map-context/map-context.model'
import { Subject } from 'rxjs'
import { debounceTime } from 'rxjs/operators'

@Component({
selector: 'gn-ui-add-layer-from-wms',
templateUrl: './add-layer-from-wms.component.html',
styleUrls: ['./add-layer-from-wms.component.css'],
})
export class AddLayerFromWmsComponent implements OnInit {
wmsUrl = ''
loading = false
layers: (WmsLayerSummary & { children: WmsLayerSummary[] })[] = []
isInvalidUrl = false
wmsEndpoint: WmsEndpoint | null = null
urlChange = new Subject<string>()
errorMessage: string | null = null

constructor(
private mapFacade: MapFacade,
private changeDetectorRef: ChangeDetectorRef
) {}

ngOnInit() {
this.urlChange.pipe(debounceTime(700)).subscribe(() => this.loadLayers())
}

async loadLayers() {
try {
this.loading = true
this.isInvalidUrl = false

if (this.wmsUrl.trim() === '') {
this.layers = []
return
}

this.wmsEndpoint = new WmsEndpoint(this.wmsUrl)
await this.wmsEndpoint.isReady()

const layers = this.wmsEndpoint.getLayers()
this.layers = await Promise.all(
layers.map(async (layer) => {
const children =
this.wmsEndpoint.getLayerByName(layer.name).children || []
return {
...layer,
children,
}
})
)
} catch (error) {
const err = error as Error
console.error('Error loading layers:', err)
this.isInvalidUrl = true
this.layers = []
this.errorMessage = 'Error loading layers: ' + err.message
} finally {
this.loading = false
this.changeDetectorRef.markForCheck()
}
}

addLayer(layer: WmsLayerSummary) {
const layerToAdd: MapContextLayerModel = {
name: layer.name,
url: this.wmsUrl.toString(),
type: MapContextLayerTypeEnum.WMS,
}
this.mapFacade.addLayer({ ...layerToAdd, title: layer.title })
}
}
2 changes: 2 additions & 0 deletions libs/feature/map/src/lib/feature-map.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { MapContainerComponent } from './map-container/map-container.component'
import { AddLayerRecordPreviewComponent } from './add-layer-from-catalog/add-layer-record-preview/add-layer-record-preview.component'
import { UiElementsModule } from '@geonetwork-ui/ui/elements'
import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
import { AddLayerFromWmsComponent } from './add-layer-from-wms/add-layer-from-wms.component'

@NgModule({
declarations: [
Expand All @@ -29,6 +30,7 @@ import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
AddLayerFromCatalogComponent,
MapContainerComponent,
AddLayerRecordPreviewComponent,
AddLayerFromWmsComponent,
],
exports: [
MapContextComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
</div>
</mat-tab>
<mat-tab [label]="'map.add.layer.wms' | translate" bodyClass="h-full">
<div class="p-3 h-full">Add from WMS</div>
<div class="p-3">
<gn-ui-add-layer-from-wms></gn-ui-add-layer-from-wms>
</div>
</mat-tab>
<mat-tab [label]="'map.add.layer.wfs' | translate" bodyClass="h-full">
<div class="p-3 h-full">Add from WFS</div>
Expand Down
Loading