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 - support to add layers from ESRI Rest services #5931

Merged
merged 4 commits into from
Nov 8, 2021

Conversation

josegar74
Copy link
Member

Extend the Add a Layer from > Services with ESRI Rest services:

esrirest_services

@josegar74 josegar74 added this to the 4.0.6 milestone Aug 24, 2021
@josegar74 josegar74 requested review from fxprunayre and jahow August 24, 2021 13:18
@matself
Copy link
Contributor

matself commented Aug 24, 2021

Good idea. See how this may improve the REST harvester as well. Beacuse REST harvesting from ESRI does not work. The Portal I mean.

Copy link
Contributor

@jahow jahow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't tested it but I made some comments on the code, hope that helps! cheers

addEsriRestFromScratch: function(map, url, name, createOnly, md) {
if (url === '') {
var error = "Trying to add an ESRI layer with no service URL. Layer name is " + name + ". Check the metadata or the map.";
console.warn(error);
return $q.reject(error);
}
var serviceUrl = url.replace(/(.*\/MapServer).*/, '$1');
var layer = !!name && parseInt(name).toString() === name
var layer = angular.isNumber(name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does not work with the comment block above, which is stating that name is a string

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name is not a string, at least from my tests. Check https://land.discomap.eea.europa.eu/arcgis/rest/services/Agriculture/agri_extensification_on_HNVfarmland06/MapServer?f=pjson

The name is taken from the layer ids, also id=0 is valid, and caused issues with !!name that was evaluated to false

"layers": [
  {
   "id": 0,

Comment on lines +1457 to +1458
* If the md object is given, we add it to the layer, or we try
* to retrieve it in the catalog
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This contradicts the name of the methods wich ends with FromScratch; I think it makes sense to rename this method addEsriRestLayer for example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method already existed, it's not from this pull request. Can you explain why contradicts the name of the methods which ends with FromScratch?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method already existed, it's not from this pull request.

I know, but this doesn't mean we cannot rename it.

"From scratch" means, in the context of the GN map service, that it does not need to be fed a capabilities document; besides, there is usually another "from capabilities" function that comes with it. For ESRI services it does not work like that so I suggest we remove the "from scratch" from the method name as it is misleading.

Copy link
Member Author

@josegar74 josegar74 Aug 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I don't see that much of an issue to use the FromScratch suffix (the method was already there, hasn't been added in this pull request), as the method doesn't use a capabilities document. But if it makes the code more clear will update it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, but I also disagree: while it may appear minor, an incorrect/misleading function name can significantly diminish the readability of the code. A widely accepted good practice is that whichever piece of code you alter should be cleaner after your changes than prior; this can include minor refactorings like this.

That said, I was simply making a comment about something that striked me as incorrect, not specifically requesting changes on your behalf.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already updated

*
* @param {ol.Map} map to add the layer
* @param {string} url of the service
* @param {string} name of the layer (identifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this was admittedly not clear at all before, the name parameter is optional I think. If not present, the name will be inferred from the URL. Why this is like that, I'm not sure... The logic around name and layer in this method is unclear to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me was quite confusing the usage of that parameters, just tried to document it. Please check as at least part of the original code was added by you, maybe you can remember the logic for that variables.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so I looked in more details and the name parameter is basically a stringified number used to identify a layer in a map. So 0, 1, 2 etc. The weird thing is that this variable is reused later on to store an arbitrary "layer name" in the form of mapId layerNumber, so for example my-map 0. On the other hand, the layer variable is used to store the layer name instead...

The confusing part is that a service url can contain a layer name (e.g. my-map/MapServer/0) and as such we can infer the layer name from the service url in case the provided layer name argument is incorrect (i.e. not a valid number in string format). This is all unnecessarily complicated, but I understand that this was out of your PR scope. I guess the bare minimum would be to make sure that the function is properly documented (especially the name and url arguments).

? name
: url.replace(/.*\/([^\/]*)\/MapServer\/?(.*)/, '$2');
name = url.replace(/.*\/([^\/]*)\/MapServer\/?(.*)/, '$1 $2');

var olLayer = getTheLayerFromMap(map, name, url);
// Use the url and the layer identifier to check if the layer exists
var olLayer = getTheLayerFromMap(map, layer, url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're switching from layer to name here, is that intentional? It looks like this could break things.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getTheLayerFromMap was not supporting ESRI Rest layers, so that code was useless and should be used the layer that is the idenfifier, not the string value that is also unclear why is implemented like this:

name = url.replace(/.*\/([^\/]*)\/MapServer\/?(.*)/, '$1 $2');

For example for https://land.discomap.eea.europa.eu/arcgis/rest/services/Agriculture/agri_extensification_on_HNVfarmland06/MapServer

sets name to agri_extensification_on_HNVfarmland06

For https://land.discomap.eea.europa.eu/arcgis/rest/services/Agriculture/agri_extensification_on_HNVfarmland06/MapServer/0

sets name to agri_extensification_on_HNVfarmland06 0

it's totally unclear the reason for that, but that can't be used to identify the layer in the map.

<div class="flex-col flex-grow">
<a href=""
class="truncate"
data-ng-click="addLayer(null, $event)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addLayer() would be enough here I think

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will update, copied from similar existing code for WMS services.

evt.stopPropagation();
};

scope.addLayer = function(c) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused function argument

'$translate',
function($translate) {

var label= $translate.instant('filter');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go on the scope and be used as {{ ::label }} in the template (might as well use angularjs for templating 😉 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also this would remove the dependency to $translate

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was copied for similar code in other existing directive...

controller.addEsriRestLayer(scope.member);
};

scope.isParentNode = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is weird, looks like this directive is built to handle nested layers, but does not actually support it. IIRC layers in ESRI map services are not organized in a tree like in the WMS, so I guess you could get rid of everything related to layer groups and simplify the whole thing.

Future maintainers will thank you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was copied from other directive for WMS, will cleanup this as I was not sure if nested was supported. I leaved in case that is supported to extend it later.

if (url) {
url = url + '?f=json';

if (gnUrlUtils.isValid(url)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the URL is not valid the returned promise will never resolve nor reject; I think you can remove this check and let $http fail like it should on a malformed URL.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will update.

timeout: timeout
})
.success(function(data, status, headers, config) {
if (!!data.mapName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this check mean? This might require a comment, because it looks like you received a valid response and still decided to throw a "capabilities failed" error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks if the response has a property mapName, that is expected to be in the ESRI Rest service document, to avoid you configure any url like https://github.com

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then it would make sense to return another error, like "The response was not a valid ESRI Rest document" or something like that. I'm not sure this is what happens with other services, we probably just let them fail once they try to parse a non existent property or because of the content-type.

Copy link
Contributor

@jahow jahow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the improvements! The AddEsriLayer method is still very confusing in its logic, but at least it is better documented now.

@matself
Copy link
Contributor

matself commented Sep 2, 2021

Great addition - I believe. I have just refreshed and built a brand new GN 4 instance. Do I need some configuration setting to get the ESRI option under Services?
Second, as asked above: Will it be possible to harvest REST services as well?

@josegar74
Copy link
Member Author

@matself the pull request is not yet merged in the main branch. I hope is merged soon to be available in the main branch (4.0.x version).

About the harvester, that's another feature, not the scope of this pull request. I recommend to open a new issue for this topic. Generally, contributions to GeoNetwork are made through user pull requests or if don't have the skills by hiring a developer who can develop the feature and make a pull request. At https://geonetwork-opensource.org/ you can find a list of some of the companies (among others) that work on GeoNetwork.

@josegar74 josegar74 merged commit 695c20e into geonetwork:main Nov 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants