From 0167031d17448b6b8daff8a7e3b7454c923448f0 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Thu, 14 Dec 2023 16:36:27 +1100 Subject: [PATCH 1/4] AUS-4076 Remove outdated service URLs --- src/environments/environment.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 19315c17..4f6aeb2c 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -11,11 +11,8 @@ export const environment = { production: false, getCSWRecordEndP: 'getKnownLayers.do', - //portalBaseUrl: 'http://localhost:8080/AuScope-Portal/', portalBaseUrl: 'http://localhost:8080/api/', - //portalBaseUrl: 'https://au-portal-dev.it.csiro.au/api/', portalProxyUrl: '/api/', - //authBaseUrl: 'https://au-portal-dev.it.csiro.au/api/', authBaseUrl: 'http://localhost:8080/api/', hostUrl: 'http://localhost:4200', nVCLAnalyticalUrl: 'https://nvclanalytics.azurewebsites.net/NVCLAnalyticalServices/', From ce50e4fc61c29b7a433fed1739ac03d92b45d5da Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Thu, 14 Dec 2023 16:41:10 +1100 Subject: [PATCH 2/4] AUS-4076 Improve map legend reliability - Use proxy for styled GetLegend POST requests - Use proxied POST requests for unstyled GetLegend - Use a constant for proxy endpoint API name - Use image bounds in GetLegend requests to help reduce CORS errors --- .../custompanel/custompanel.component.ts | 25 +++++--- .../menupanel/search/searchpanel.component.ts | 18 ++++-- src/app/services/legend/legend-ui.service.ts | 63 ++++++++++++------- 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/app/menupanel/custompanel/custompanel.component.ts b/src/app/menupanel/custompanel/custompanel.component.ts index ffb3403f..ac6c0f7e 100644 --- a/src/app/menupanel/custompanel/custompanel.component.ts +++ b/src/app/menupanel/custompanel/custompanel.component.ts @@ -1,5 +1,6 @@ import { Component, Output, Inject, EventEmitter } from '@angular/core'; -import { LayerHandlerService, LayerModel, RenderStatusService, KMLDocService, ResourceType } from '@auscope/portal-core-ui'; +import { LayerHandlerService, LayerModel, RenderStatusService, KMLDocService, ResourceType, + Constants } from '@auscope/portal-core-ui'; import { NgbdModalStatusReportComponent } from '../../toppanel/renderstatus/renderstatus.component'; import { BsModalService } from 'ngx-bootstrap/modal'; import { BsModalRef } from 'ngx-bootstrap/modal'; @@ -7,8 +8,7 @@ import { UILayerModel } from '../common/model/ui/uilayer.model'; import { UILayerModelService } from 'app/services/ui/uilayer-model.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import * as JSZip from 'jszip'; -import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; -import { saveAs } from 'file-saver'; +import { HttpClient } from '@angular/common/http'; import { throwError as observableThrowError, Observable } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; import { HttpResponse } from '@angular/common/http'; @@ -42,10 +42,15 @@ export class CustomPanelComponent { bsModalRef: BsModalRef; @Output() expanded: EventEmitter = new EventEmitter(); - constructor(private http: HttpClient, private layerHandlerService: LayerHandlerService, private renderStatusService: RenderStatusService, - private modalService: BsModalService, private uiLayerModelService: UILayerModelService, - public activeModalService: NgbModal, private kmlService: KMLDocService, - @Inject('env') private env) { + constructor(private http: HttpClient, + private layerHandlerService: LayerHandlerService, + private renderStatusService: RenderStatusService, + private modalService: BsModalService, + private uiLayerModelService: UILayerModelService, + public activeModalService: NgbModal, + private kmlService: KMLDocService, + @Inject('env') private env + ) { this.loading = false; this.statusMsg = 'Enter your OGC WMS service endpoint
e.g. "https://server.gov.au/service/wms"
or KML/KMZ URL and hit .'; } @@ -69,7 +74,7 @@ export class CustomPanelComponent { } /** - * Search list of available WMS layers given an OGC WMS URL or a KML URL + * Search list of available WMS layers given an OGC WMS URL, or try to load a KML/KMZ URL */ public search() { // Clear the status message @@ -104,7 +109,7 @@ export class CustomPanelComponent { // Extract a layer name from URL const layerName = url.pathname.split('/').pop(); // Use the proxy - const proxyUrl = this.env.portalBaseUrl + "getViaProxy.do?usewhitelist=false&url=" + searchUrl; + const proxyUrl = this.env.portalBaseUrl + Constants.PROXY_API + "?usewhitelist=false&url=" + searchUrl; this.getGoogleMapDoc(proxyUrl).subscribe(response => { let kml = response; @@ -151,7 +156,7 @@ export class CustomPanelComponent { // Extract a layer name from URL const layerName = url.pathname.split('/').pop(); // Use the proxy - const proxyUrl = this.env.portalBaseUrl + "getViaProxy.do?usewhitelist=false&url=" + searchUrl; + const proxyUrl = this.env.portalBaseUrl + Constants.PROXY_API + "?usewhitelist=false&url=" + searchUrl; // Add KMZ to map this.getGoogleMapDoc(proxyUrl).subscribe(response => { diff --git a/src/app/menupanel/search/searchpanel.component.ts b/src/app/menupanel/search/searchpanel.component.ts index 9afdfa13..e2af43bd 100644 --- a/src/app/menupanel/search/searchpanel.component.ts +++ b/src/app/menupanel/search/searchpanel.component.ts @@ -1,6 +1,7 @@ import { Component, ElementRef, HostListener, Inject, OnInit, ViewChild } from '@angular/core'; import { RectangleEditorObservable } from '@auscope/angular-cesium'; -import { Bbox, CsMapService, LayerHandlerService, LayerModel, ManageStateService, UtilitiesService } from '@auscope/portal-core-ui'; +import { Bbox, CsMapService, LayerHandlerService, LayerModel, + ManageStateService, UtilitiesService, Constants } from '@auscope/portal-core-ui'; import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { SearchService } from 'app/services/search/search.service'; import { Observable, Subject, Subscription } from 'rxjs'; @@ -89,9 +90,15 @@ export class SearchPanelComponent implements OnInit { highlightedSuggestionIndex = -1; constructor(private searchService: SearchService, - private csMapService: CsMapService, private layerHandlerService: LayerHandlerService, - private layerManagerService: LayerManagerService, private uiLayerModelService: UILayerModelService, - private manageStateService: ManageStateService, private modalService: NgbModal, private http: HttpClient, @Inject('env') private env) { } + private csMapService: CsMapService, + private layerHandlerService: LayerHandlerService, + private layerManagerService: LayerManagerService, + private uiLayerModelService: UILayerModelService, + private manageStateService: ManageStateService, + private modalService: NgbModal, + private http: HttpClient, + @Inject('env') private env + ) { } ngOnInit() { for (const service of OGC_SERVICES) { @@ -314,7 +321,7 @@ export class SearchPanelComponent implements OnInit { let url0 = onlineResourcesWFS.url; let url1 = url0 + '?service=WFS&request=GetFeature&version=1.0.0&outputFormat=csv&maxFeatures=1000000&typeName=' + typename; - let url = me.env.portalBaseUrl + 'getViaProxy.do?usewhitelist=false&'+ httpParams.append('url',url1 ).toString(); + let url = me.env.portalBaseUrl + Constants.PROXY_API + '?usewhitelist=false&' + httpParams.append('url',url1 ).toString(); let filename = typename + '.' + url0 + '.csv'; filename = filename.replace(/:|\/|\\/g,'-'); let ob = await this.http.get(url, { headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'), responseType: 'text'}).toPromise(); @@ -325,6 +332,7 @@ export class SearchPanelComponent implements OnInit { //console.log('downloaded:' + url); } } + /** * Display layer information dialog * diff --git a/src/app/services/legend/legend-ui.service.ts b/src/app/services/legend/legend-ui.service.ts index 6c58cb49..3a74626f 100644 --- a/src/app/services/legend/legend-ui.service.ts +++ b/src/app/services/legend/legend-ui.service.ts @@ -1,5 +1,5 @@ import { HttpClient, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { Injectable, Inject } from '@angular/core'; import { MatDialog, MatDialogConfig, MatDialogRef } from '@angular/material/dialog'; import { Constants, LayerModel, LayerStatusService, ManageStateService, OnlineResourceModel, SldService, UtilitiesService } from '@auscope/portal-core-ui'; import { LegendModalComponent } from 'app/modalwindow/legend/legend.modal.component'; @@ -14,8 +14,13 @@ export class LegendUiService { // Track which legends are open displayedLegends: Map> = new Map>(); - constructor(private manageStateService: ManageStateService, private sldService: SldService, - private layerStatusService: LayerStatusService, private http: HttpClient, private dialog: MatDialog) {} + constructor(private manageStateService: ManageStateService, + private sldService: SldService, + private layerStatusService: LayerStatusService, + private http: HttpClient, + private dialog: MatDialog, + @Inject('env') private env + ) {} /** * Get the first WMS OnlineResource for a layer @@ -59,10 +64,9 @@ export class LegendUiService { * * @param layerId the ID of the relevant layer * @param legendTitle the title for the dialog - * @param legendUrlList list of legend image URLs (either this or legendRequestList will be required) * @param legendRequestList list of image requests (either this or legendUrlList will be required) */ - private displayLegendDialog(layerId: string, legendTitle: string, /*legendUrlList: string[], */legendRequestList: Observable[]) { + private displayLegendDialog(layerId: string, legendTitle: string, legendRequestList: Observable[]) { const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.hasBackdrop = false; @@ -76,24 +80,15 @@ export class LegendUiService { this.displayedLegends.set(layerId, dialogRef); } - /** - * Retrieve the legend image data as a blob - * - * @param legendUrl the URL from which to retrieve the image data - * @returns a Blob observable of legend image data - */ - private getLegendImageData(legendUrl: string): Observable { - return this.http.post(legendUrl, { responseType: 'blob' }); - } - /** * Create HttpParams for the GetLegendGraphic requests + * @param url URL parameter for proxy request * @param layerName the layer name * @param collatedParam other layer specific collated parameters * @param sldBody the styled layer descriptor (SLD_BODY) - Optional * @returns a set of HttpParams for th eGetLegendGraphic request */ - private getHttpParams(layerName: string, collatedParam: any, sldBody?: string): HttpParams { + private getLegendHttpParams(url: string, layerName: string, collatedParam: any, sldBody?: string): HttpParams { let httpParams = new HttpParams() .set('SERVICE', 'WMS') .append('REQUEST', 'GetLegendGraphic') @@ -102,7 +97,9 @@ export class LegendUiService { .append('LAYER', layerName) .append('LAYERS', layerName) .append('SCALE', '1000000') - .append('LEGEND_OPTIONS', 'forceLabels:on;minSymbolSize:16'); + .append('LEGEND_OPTIONS', 'forceLabels:on;minSymbolSize:16') + .append('url', url) + .append('usewhitelist', 'false'); if (sldBody) { httpParams = httpParams.append('SLD_BODY', sldBody); } @@ -138,9 +135,10 @@ export class LegendUiService { * @param sldBody the SLD_BODY (if one is to be used) * @returns a GetLegendGraphic URL for GET requests */ - private createRequestUrl(wmsUrl: string, layerName: string, sldBody?: string): string { + private createLegendUrl(wmsUrl: string, layerName: string, sldBody?: string): string { wmsUrl = this.trimUrl(wmsUrl); let requestUrl = wmsUrl + '?SERVICE=WMS&REQUEST=GetLegendGraphic&VERSION=1.1.1&FORMAT=image/png&BGCOLOR=0xFFFFFF' + + '&WIDTH=40&HEIGHT=40' + '&LAYER=' + layerName + '&LAYERS=' + layerName + '&SCALE=1000000' + '&forceLabels=on&minSymbolSize=16'; if (sldBody) { requestUrl += '&SLD_BODY=' + encodeURI(sldBody); @@ -196,14 +194,20 @@ export class LegendUiService { if (!this.layerStatusService.isEndpointFailing(layer.id, wmsOnlineResource)) { // Some GET URLs were being truncated at the server despite not being very long, other servers were outright rejecting POST // requests, so create lists of GET URLs and POST requests to throw everything at the wall and see what sticks. - const httpParams = this.getHttpParams(wmsOnlineResource.name, collatedParam, sldBody); - const postRequest = this.http.post(this.trimUrl(resource.url), httpParams, { responseType: 'blob' }).pipe( + + // Assemble params, including 'GetLegend' params + let httpParams = this.getLegendHttpParams(this.trimUrl(resource.url), wmsOnlineResource.name, collatedParam, sldBody); + // Make a POST request with proxy + let proxyUrl = this.env.portalBaseUrl + Constants.PROXY_API; + const postRequest = this.http.post(proxyUrl, httpParams, { responseType: 'blob' }).pipe( catchError(() => { return of(undefined); }) ); legendRequestList.push(postRequest); - const requestUrl = this.createRequestUrl(resource.url, resource.name, sldBody); + + // Make a GET request, no proxy + const requestUrl = this.createLegendUrl(resource.url, resource.name, sldBody); const getRequest = this.http.get(requestUrl, { responseType: 'blob' }).pipe( catchError(() => { return of(undefined); @@ -214,13 +218,26 @@ export class LegendUiService { } this.displayLegendDialog(layer.id, layer.name, legendRequestList); } else { - const requestUrl = this.createRequestUrl(wmsOnlineResource.url, wmsOnlineResource.name, null); + // It comes here when there is no SLD_BODY parameter + + // Create a POST request with proxy, with the proxy this enables us to use HTTP services + // Assemble params, including 'GetLegend' params + let httpParams = this.getLegendHttpParams(this.trimUrl(wmsOnlineResource.url), wmsOnlineResource.name, collatedParam); + let proxyUrl = this.env.portalBaseUrl + Constants.PROXY_API; + const postRequest = this.http.post(proxyUrl, httpParams, { responseType: 'blob' }).pipe( + catchError(() => { + return of(undefined); + }) + ); + + // Create a GET request, no proxy + const requestUrl = this.createLegendUrl(wmsOnlineResource.url, wmsOnlineResource.name); const getRequest = this.http.get(requestUrl, { responseType: 'blob' }).pipe( catchError(() => { return of(undefined); }) ); - this.displayLegendDialog(layer.id, layer.name, [getRequest]); + this.displayLegendDialog(layer.id, layer.name, [getRequest, postRequest]); } }); } From 846a15afa7a9728bbd792892474c8670598b9701 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Thu, 14 Dec 2023 16:49:58 +1100 Subject: [PATCH 3/4] AUS-4076 Prevent shrunken preview maps --- .../infopanel/subpanel/subpanel.component.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/app/menupanel/common/infopanel/subpanel/subpanel.component.ts b/src/app/menupanel/common/infopanel/subpanel/subpanel.component.ts index 2bb4cd93..0decbeb3 100644 --- a/src/app/menupanel/common/infopanel/subpanel/subpanel.component.ts +++ b/src/app/menupanel/common/infopanel/subpanel/subpanel.component.ts @@ -116,6 +116,20 @@ export class InfoPanelSubComponent implements OnChanges { } // Gather up BBOX coordinates to calculate the centre and envelope const bbox = this.cswRecord.geographicElements[0]; + // Make sure that the view is only of Australia + // On most maps if we use world-wide bounds it will make the Australian features too small + if (bbox.westBoundLongitude < 100) { + bbox.westBoundLongitude = 100; + } + if (bbox.eastBoundLongitude > 160) { + bbox.eastBoundLongitude = 160; + } + if (bbox.southBoundLatitude < -50) { + bbox.southBoundLatitude = -50; + } + if (bbox.northBoundLatitude > -5) { + bbox.northBoundLatitude = -5; + } // Gather up lists of information URLs if (wmsOnlineResource) { From a7b1e358a1b8dd92b3826468feb730f12eaabac4 Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Thu, 14 Dec 2023 16:51:22 +1100 Subject: [PATCH 4/4] AUS-4076 Make legend larger to improve readability --- src/app/menupanel/menupanel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/menupanel/menupanel.scss b/src/app/menupanel/menupanel.scss index c82de65c..85a33955 100644 --- a/src/app/menupanel/menupanel.scss +++ b/src/app/menupanel/menupanel.scss @@ -42,7 +42,7 @@ p a { color: #000; } .infopanel-legend { - max-width: 220px; + max-width: 500px; } /* The bell icon in the alert panels used when adding various layers */