-
Notifications
You must be signed in to change notification settings - Fork 33
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 OGC API service #848
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
be75c8f
update ogc-client
jahow 9f82dc5
wip
jahow 6b13d4a
Added component to load layers from a OGC API service
ronitjadhav 8baab12
fix unit tests
ronitjadhav 22f62e0
Made add-layer-from-ogc-api standalone component
ronitjadhav a3e1040
chore: upgrade ogc-client in npm package
jahow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
36 changes: 36 additions & 0 deletions
36
libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<div class="flex items-center mb-5"> | ||
<gn-ui-text-input | ||
[(value)]="ogcUrl" | ||
(valueChange)="urlChange.next($event)" | ||
[hint]="'map.ogc.urlInput.hint' | translate" | ||
class="w-96" | ||
> | ||
</gn-ui-text-input> | ||
</div> | ||
|
||
<div *ngIf="errorMessage" class="text-red-500 mt-2"> | ||
{{ errorMessage }} | ||
</div> | ||
|
||
<div *ngIf="loading"> | ||
<p class="loading-message" translate>map.loading.service</p> | ||
</div> | ||
|
||
<div *ngIf="!loading && layers.length > 0"> | ||
<h2 class="font-bold" translate>map.layers.available</h2> | ||
<ng-container *ngFor="let layer of layers"> | ||
<div class="flex items-center justify-between my-2 layer-item-tree"> | ||
<p class="max-w-xs overflow-hidden overflow-ellipsis whitespace-nowrap"> | ||
{{ layer }} | ||
</p> | ||
<gn-ui-button | ||
class="layer-add-btn" | ||
type="primary" | ||
(buttonClick)="addLayer(layer)" | ||
extraClass="text-sm !px-2 !py-1" | ||
translate | ||
><span translate> map.layer.add </span></gn-ui-button | ||
> | ||
</div> | ||
</ng-container> | ||
</div> |
82 changes: 82 additions & 0 deletions
82
libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { ComponentFixture, TestBed } from '@angular/core/testing' | ||
import { AddLayerFromOgcApiComponent } from './add-layer-from-ogc-api.component' | ||
import { MapFacade } from '../+state/map.facade' | ||
import { TranslateModule } from '@ngx-translate/core' | ||
import { NO_ERRORS_SCHEMA } from '@angular/core' | ||
import { MapContextLayerTypeEnum } from '../map-context/map-context.model' | ||
|
||
jest.mock('@camptocamp/ogc-client', () => ({ | ||
OgcApiEndpoint: class { | ||
constructor(private url) {} | ||
isReady() { | ||
if (this.url.indexOf('error') > -1) { | ||
return Promise.reject(new Error('Something went wrong')) | ||
} | ||
if (this.url.indexOf('wait') > -1) { | ||
return new Promise(() => { | ||
// do nothing | ||
}) | ||
} | ||
return Promise.resolve(this) | ||
} | ||
get featureCollections() { | ||
if (this.url.includes('error')) { | ||
return Promise.reject(new Error('Simulated loading error')) | ||
} | ||
return Promise.resolve(['layer1', 'layer2', 'layer3']) | ||
} | ||
getCollectionItemsUrl(collectionId) { | ||
return Promise.resolve( | ||
`http://example.com/collections/${collectionId}/items` | ||
) | ||
} | ||
}, | ||
})) | ||
|
||
describe('AddLayerFromOgcApiComponent', () => { | ||
let component: AddLayerFromOgcApiComponent | ||
let fixture: ComponentFixture<AddLayerFromOgcApiComponent> | ||
|
||
beforeEach(async () => { | ||
await TestBed.configureTestingModule({ | ||
imports: [TranslateModule.forRoot(), AddLayerFromOgcApiComponent], | ||
declarations: [], | ||
schemas: [NO_ERRORS_SCHEMA], | ||
}).compileComponents() | ||
|
||
fixture = TestBed.createComponent(AddLayerFromOgcApiComponent) | ||
component = fixture.componentInstance | ||
fixture.detectChanges() | ||
}) | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy() | ||
expect(component.errorMessage).toBeFalsy() | ||
expect(component.loading).toBe(false) | ||
expect(component.layers.length).toBe(0) | ||
}) | ||
|
||
describe('loadLayers', () => { | ||
it('should clear layers if OGC URL is empty', async () => { | ||
component.ogcUrl = '' | ||
await component.loadLayers() | ||
expect(component.layers.length).toBe(0) | ||
}) | ||
|
||
it('should load layers on valid OGC API service', async () => { | ||
component.ogcUrl = 'http://example.com/ogc' | ||
await component.loadLayers() | ||
expect(component.errorMessage).toBeFalsy() | ||
expect(component.loading).toBe(false) | ||
expect(component.layers).toEqual(['layer1', 'layer2', 'layer3']) | ||
}) | ||
|
||
it('should handle errors while loading layers', async () => { | ||
component.ogcUrl = 'http://example.com/error' | ||
await component.loadLayers() | ||
expect(component.errorMessage).toContain('Error loading layers:') | ||
expect(component.loading).toBe(false) | ||
expect(component.layers.length).toBe(0) | ||
}) | ||
}) | ||
}) |
80 changes: 80 additions & 0 deletions
80
libs/feature/map/src/lib/add-layer-from-ogc-api/add-layer-from-ogc-api.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { | ||
Component, | ||
OnInit, | ||
Output, | ||
EventEmitter, | ||
ChangeDetectionStrategy, | ||
Input, | ||
ChangeDetectorRef, | ||
} from '@angular/core' | ||
import { OgcApiEndpoint } from '@camptocamp/ogc-client' | ||
import { Subject, debounceTime } from 'rxjs' | ||
import { | ||
MapContextLayerModel, | ||
MapContextLayerTypeEnum, | ||
} from '../map-context/map-context.model' | ||
import { TranslateModule } from '@ngx-translate/core' | ||
import { UiInputsModule } from '@geonetwork-ui/ui/inputs' | ||
import { CommonModule } from '@angular/common' | ||
import { MapLayer } from '../+state/map.models' | ||
|
||
@Component({ | ||
selector: 'gn-ui-add-layer-from-ogc-api', | ||
templateUrl: './add-layer-from-ogc-api.component.html', | ||
styleUrls: ['./add-layer-from-ogc-api.component.css'], | ||
standalone: true, | ||
imports: [CommonModule, TranslateModule, UiInputsModule], | ||
}) | ||
export class AddLayerFromOgcApiComponent implements OnInit { | ||
@Input() ogcUrl: string | ||
@Output() layerAdded = new EventEmitter<MapLayer>() | ||
|
||
urlChange = new Subject<string>() | ||
layerUrl = '' | ||
loading = false | ||
layers: string[] = [] | ||
ogcEndpoint: OgcApiEndpoint = null | ||
errorMessage: string | null = null | ||
|
||
constructor(private changeDetectorRef: ChangeDetectorRef) {} | ||
|
||
ngOnInit() { | ||
this.urlChange.pipe(debounceTime(700)).subscribe(() => { | ||
this.loadLayers() | ||
this.changeDetectorRef.detectChanges() // manually trigger change detection | ||
}) | ||
} | ||
|
||
async loadLayers() { | ||
this.errorMessage = null | ||
try { | ||
this.loading = true | ||
if (this.ogcUrl.trim() === '') { | ||
this.layers = [] | ||
return | ||
} | ||
this.ogcEndpoint = await new OgcApiEndpoint(this.ogcUrl) | ||
|
||
// Currently only supports feature collections | ||
this.layers = await this.ogcEndpoint.featureCollections | ||
} catch (error) { | ||
const err = error as Error | ||
this.layers = [] | ||
this.errorMessage = 'Error loading layers: ' + err.message | ||
} finally { | ||
this.loading = false | ||
this.changeDetectorRef.markForCheck() | ||
} | ||
} | ||
|
||
async addLayer(layer: string) { | ||
this.layerUrl = await this.ogcEndpoint.getCollectionItemsUrl(layer) | ||
|
||
const layerToAdd: MapContextLayerModel = { | ||
name: layer, | ||
url: this.layerUrl, | ||
type: MapContextLayerTypeEnum.OGCAPI, | ||
} | ||
this.layerAdded.emit({ ...layerToAdd, title: layer }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we could make this a standalone component? that would push things towards the right direction :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done !!