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

WMS popup functionality #173

Merged
merged 26 commits into from May 17, 2021
Merged

WMS popup functionality #173

merged 26 commits into from May 17, 2021

Conversation

JorgeMartinezG
Copy link
Collaborator

This PR closes #134

image

On a map click event, given the case that a selected layer has featureInfoProps array, prism executes a getFeatureInfo request to get information. The result is filtered given the labels in the array. For this PR, is used for mozambique wind buffers layer.

Deployment found here: http://homeless-giraffe.surge.sh/

Copy link
Member

@wadhwamatic wadhwamatic left a comment

Choose a reason for hiding this comment

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

Can we allow for the configuration to give a label to the returned field names?
event_name = Event name
pub_date = Publication date

And can we return the date in a more readable format, so the popup would read:
Event name: CHALANE-20
Publication date: 2020-12-30 07:34 UTC

@JorgeMartinezG
Copy link
Collaborator Author

Sure. Included in 7c4018a and redeployed to same url: http://homeless-giraffe.surge.sh

image

@wadhwamatic
Copy link
Member

Awesome. Great work Jorge. Looks good from my perspective. Over to @ericboucher for code review.

@ericboucher ericboucher requested a review from Ry-DS April 28, 2021 16:50
Copy link
Collaborator

@Ry-DS Ry-DS left a comment

Choose a reason for hiding this comment

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

Nice! Left some comments to help make the code more organized

@@ -48,7 +48,11 @@ const Input = forwardRef(
);
},
);
function DateSelector({ availableDates = [], classes }: DateSelectorProps) {
function DateSelector({
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would use React.forwardRef, but in the future if we need a ref to the selector we'll run into issues. Up to you 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I used a ref just to know current value from DateSelector. In both cases we would need to create the ref within the Mapview component and pass it to the DateSelector one.

Another option would be to use Localstorage, but some additional change will be needed within the addLayer reducer function

src/components/MapView/Layers/ImpactLayer/index.tsx Outdated Show resolved Hide resolved
src/components/MapView/Layers/raster-utils.ts Outdated Show resolved Hide resolved
@@ -211,8 +278,43 @@ function MapView({ classes }: MapViewProps) {
containerStyle={{
height: '100%',
}}
onClick={() => {
onClick={(map: Map, evt: any) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any chance the library comes with a type for this? Would be nice to not use any. If it doesn't we could make an alias to any called MapEvent, or a bare bones type which has the fields we need.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I decided to use the any type, since many mapbox handlers use it as type across the project. It would be better to use any to keep consistency. If not, a change is needed for all mapbox event handlers with their respective type. But this should be addressed on another issue

src/components/MapView/index.tsx Outdated Show resolved Hide resolved
src/config/types.ts Outdated Show resolved Hide resolved
src/utils/server-utils.ts Outdated Show resolved Hide resolved
const requestLayers = layers.filter(l => l.baseUrl === url);
const layerNames = requestLayers.map(l => l.serverLayerName).join(',');

const requestParams = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

If there's a type that lines up with this, we should use it:
const requestParams: <Type> ={...}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Included in 075838b. Needed to add a CamelCase to snake transformation function

Copy link
Collaborator

Choose a reason for hiding this comment

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

Use lodash's snakeCase function https://lodash.com/docs/4.17.15#snakeCase


const wmsParams = { ...params, ...requestParams };

return fetch(formatUrl(`${url}/ows`, wmsParams))
Copy link
Collaborator

Choose a reason for hiding this comment

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

To make this more readable the async await paradigm could be used, so all these intermediary steps can just be await <task>

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Included in b1d8b95

src/components/MapView/index.tsx Outdated Show resolved Hide resolved
@JorgeMartinezG
Copy link
Collaborator Author

@Ry-DS Feedback implemented on most of the comments. Please check

@ericboucher ericboucher requested a review from Ry-DS May 5, 2021 02:46
@Ry-DS
Copy link
Collaborator

Ry-DS commented May 5, 2021

@JorgeMartinezG
did you address these?
#173 (comment)
#173 (comment)

They were hidden by GitHub because there were too many review comments haha. Let me know what you think of those 👍

Copy link
Collaborator

@Ry-DS Ry-DS left a comment

Choose a reason for hiding this comment

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

Getting closer! Make sure to check out the comments I linked above, and to wrap up this PR I'd like if we spent some time to ensure our types are as strong as they can be.

const params = getFeatureInfoParams(map, evt, dateFromRef);
makeFeatureInfoRequest(featureInfoLayers, params).then(
(result: any) => {
if (result === null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

falsey check instead just in case the value is undefined?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Included in 30953dd

src/config/types.ts Outdated Show resolved Hide resolved
url: string,
wmsParams: requestFeatureInfo,
layers: WMSLayerProps[],
): Promise<{ [name: string]: string }> {
Copy link
Collaborator

@Ry-DS Ry-DS May 5, 2021

Choose a reason for hiding this comment

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

On line 318 the API result is typed well, so we should be able to provide a good type as the output for this function. This can be done by typing the reduce functions used in this file. What do you think? We should always try to make our types as strong as possible.

layers: WMSLayerProps[],
): Promise<{ [name: string]: string }> {
// Transform to snake case.
const toSnakeWmsParams = Object.entries(wmsParams).reduce(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Replace with lodash's snakeCase function.
https://lodash.com/docs/4.17.15#snakeCase

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

included in 73987d1

Copy link
Collaborator

Choose a reason for hiding this comment

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

Might be clearer if called wmsParamsInSnakeCase, what do you think?

layers: WMSLayerProps[],
url: string,
params: FeatureInfoType,
): Promise<{ [name: string]: string }> {
Copy link
Collaborator

@Ry-DS Ry-DS May 5, 2021

Choose a reason for hiding this comment

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

Don't define the return type here and just let TS infer it. The plan (imo) is to strongly type the return of runFeatureInfoRequest and allow TS to infer the same type since you directly return the output of runFeatureInfoRequest

export async function makeFeatureInfoRequest(
layers: WMSLayerProps[],
params: FeatureInfoType,
): Promise<{ [name: string]: string } | null> {
Copy link
Collaborator

@Ry-DS Ry-DS May 5, 2021

Choose a reason for hiding this comment

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

Unless you're using an api without strong types, or an untyped library, we shouldn't make lose types like this. FOr MapEvent , it is fair to use any since the library doesn't give us a type, but from what I see we can make strong types using GeoJSON.FeatureCollection. If you can't see an easy way to create types for this let me know :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Geojson standard has a strong type, but properties field is a key, value container. It lets flexibility for including a wide range of possible keys and values. For PRISM and WFS, we extract the values from keys included within the layers.json file. I mean, we could add a type constraint for the response. However it would work only for a single layer, since ADAM have different property schemas accross its layers

Copy link
Member

Choose a reason for hiding this comment

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

I'm not diving into the details here, but would like to add that flexibility on the types of data returned from the WFS feature request is important. We're solving for one dataset now (ADAM tropical storms), but more will come down the road, and we won't know how information is structured for each layer until we get into the integration steps. So being able to manage various types within the configuration of the layer is preferred.

const requests = urls.map(url => fetchFeatureInfo(layers, url, params));

return Promise.all(requests)
.then(r => r.reduce((obj, item) => ({ ...obj, ...item }), {}))
Copy link
Collaborator

Choose a reason for hiding this comment

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

All these types will be stronger if we start using types for all the reduce calls in this file:

arr.reduce<{output: string}>((arg1, arg2)=>{},{});
//or 
arr.reduce((arg1, arg2)=>{},{} as {output: string});

@ericboucher
Copy link
Collaborator

Looking great @JorgeMartinezG! Let us know when you had a chance to look at the remaining comments

@JorgeMartinezG
Copy link
Collaborator Author

JorgeMartinezG commented May 17, 2021

I'm not sure, but most of the feedback has been addressed already. What was missing is some indicator in the popup that additional information is loading. I decided to add a LinearProgress and is addressed here: e8d0e89

Also, a change in a variable name in here: 1d5057e

Please note that popup now is limited only within country boundaries, since two different events (map and layer) might be triggered at the same time, two popups might appear.
Also, what was mentioned previously related to WFS response, we cannot know previously the response type within properties field, since schemas per layer differ. For instance, wind buffers has a label, and nodes has not.

This branch has been deployed to this endpoint: http://homeless-giraffe.surge.sh/

@ericboucher ericboucher merged commit 55f51dc into master May 17, 2021
@ericboucher ericboucher deleted the feature/134-wms-feature-info branch May 17, 2021 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add the ability for users to interact with 'WMS' vector data layer attributes
4 participants