Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

81 location url parameters #131

Merged
merged 25 commits into from
Jan 2, 2018

Conversation

mjclawar
Copy link
Contributor

@mjclawar mjclawar commented Dec 21, 2017

Description

This PR adds search, hash and href props to the dcc.Location component (in addition to the already-existing pathname) to better mimic the window.location API.
This addresses #81, with the caveat that dcc.Link does not have any changes to props that would allow a user to directly update search independently of hash (e.g., using dcc.Link(href="?testQuery=testValue") will wipe hash from dcc.Location. Note that this is the same behavior as window.location, so should be considered "correct", but it seemed like updating dcc.Link should be a different issue.

Implementation

  • The changes to dcc.Location pretty much extends the previous pathname-specific updateLocation approach. The only major difference is that if href changes in props compared to previous props and compared to window.location.href, href takes precedent over the combination of ${pathname}${searchVal}${hashVal} (see here).
  • gitignore was updated for IntelliJ .idea/, but can remove that if needed.
  • Added a package-lock.json

Tests added

This adds tests for html.A tags, dcc.Link, and html.Button clicks interacting with the updated dcc.Location component.
peek 2017-12-21 09-31

Copy link
Member

@chriddyp chriddyp left a comment

Choose a reason for hiding this comment

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

🎉 Very nice! This looks good to me. Thank you very much for the thorough PR and the complete tests. There are just a few comments, mostly on code style conventions.

@@ -1,6 +1,7 @@
{
"src/components/Checklist.react.js": {
"description": "Checklist is a component that encapsulates several checkboxes.\nThe values and labels of the checklist is specified in the `options`\nproperty and the checked items are specified with the `values` property.\nEach checkbox is rendered as an input with a surrounding label.",
"displayName": "Checklist",
Copy link
Member

@chriddyp chriddyp Dec 21, 2017

Choose a reason for hiding this comment

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

Interesting, I wonder why displayName started appearing recently. Maybe a new version of react-docgen?

"async-each": "1.0.1",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-bin
Copy link
Member

Choose a reason for hiding this comment

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

👍 thanks for adding this

@@ -1,39 +1,85 @@
import {Component, PropTypes} from 'react';
/* global window:true */

/**
* Update and track the current window.location object through the window.history state
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can update this a little bit so that it's more readable to the Python devs who don't know much about this stuff, like:

Update and track window.location (the URL) object through the window.history state.
Use in conjunction with the dash_core_components.Link object to make apps with multiple pages.

* The name of the prop in window.location and in the component's prop
*
* @returns {boolean}
* Returns true if the prop with fieldName is different and the window state needs to be updated
Copy link
Member

Choose a reason for hiding this comment

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

👍 Very nice comment, thanks for this!

const checkExistsUpdateWindowLocation = (fieldName) => {
const propVal = props[fieldName];

if (!propVal && window.location[fieldName] && setProps) { // Prop is undefined?
Copy link
Member

Choose a reason for hiding this comment

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

we use stronger checks for undefined here like R.type(propVal) == 'Undefined' or even !R.has(props, propVal) (http://ramdajs.com/docs/#type, http://ramdajs.com/docs/#has)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's actually a null in some cases (pathname when the page first loads, e.g.), so will update to (R.type(propVal) === 'Undefined' || propVal === null) if you prefer. I think that's why the original code had !propVal.

/** href in window.location - e.g., "/my/full/pathname?myargument=1#myhash" */
href: PropTypes.string,

/** Refresh the page when the location is updated? */
Copy link
Member

Choose a reason for hiding this comment

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

👍 very nice, thanks for adding these

output=Output(component_id='test-pathname', component_property='children'),
inputs=[Input(component_id='test-location', component_property='pathname')])
def update_location_on_page(pathname):
assert isinstance(pathname, str)
Copy link
Member

Choose a reason for hiding this comment

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

I believe that these asserts won't actually fail the test as the dash app is run in a subprocess in these tests. They'll still cause the callback to fail (which might implicitly break other assertions in the main process) but in either case we might want to put this assertion out of this context


self.startServer(app=app)

def _waiter():
Copy link
Member

Choose a reason for hiding this comment

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

👍 - this is great. can we move this to test/utils.py so that we can reuse it elsewhere?


# Check that pathname is updated through a Button click via props
self.driver.find_element_by_id('test-button').click()
time.sleep(1) # Need to wait for the callback to fire TODO is there a better way to wait?
Copy link
Member

Choose a reason for hiding this comment

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

There isn't really, besides using a wait_for with whatever you are waiting for

time.sleep(1) # Need to wait for the callback to fire TODO is there a better way to wait?

self.snapshot('link -- /new/pathname?testQuery=testValue')
self.assertEqual(self.driver.find_element_by_id('test-pathname').text, '/new/pathname')
Copy link
Member

Choose a reason for hiding this comment

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

for example, you should be able to remove the time.sleep and replace it with a wait_for here and place the snapshot below the assertions

@chriddyp
Copy link
Member

This addresses #81, with the caveat that dcc.Link does not have any changes to props that would allow a user to directly update search independently of hash (e.g., using dcc.Link(href="?testQuery=testValue") will wipe hash from dcc.Location. Note that this is the same behavior as window.location, so should be considered "correct", but it seemed like updating dcc.Link should be a different issue.

Could you open up a new issue about this? My guess is that we are OK here. I believe that the main use for dcc.Link will be just to set the href.

…ramda for type checking; batch updates for setProps vs each field sequentially
@chriddyp
Copy link
Member

@mjclawar - Let me know when you're ready for another review!

@mjclawar
Copy link
Contributor Author

All set for another review.

@mjclawar
Copy link
Contributor Author

@chriddyp had to push a change to uncomment the rest of the test suite. I think all the changes you requested should be in there now!

@chriddyp
Copy link
Member

chriddyp commented Jan 2, 2018

Thanks! It looks like tests are failing because of some dependency mismatched. I'll make a separate PR to lock down these versions in tests

@chriddyp chriddyp mentioned this pull request Jan 2, 2018
@chriddyp
Copy link
Member

chriddyp commented Jan 2, 2018

This looks good to me @mjclawar . Once we get the tests to pass (hopefully through #136 ), I'm happy to merge this.

@mjclawar
Copy link
Contributor Author

mjclawar commented Jan 2, 2018

Thanks -- wasn't sure why the tests were failing on CircleCI. Happy new year! 🎉

@chriddyp
Copy link
Member

chriddyp commented Jan 2, 2018

@mjclawar - #136 fixed the tests. Would you mind rebasing your branch off of master?

@mjclawar
Copy link
Contributor Author

mjclawar commented Jan 2, 2018

Rebased.

@chriddyp
Copy link
Member

chriddyp commented Jan 2, 2018

Tests passed! 🎉 Thank you @mjclawar , this was a great PR 🍻

@chriddyp chriddyp merged commit 4e54a67 into plotly:master Jan 2, 2018
@mjclawar mjclawar deleted the 81-location-url-parameters branch January 3, 2018 16:04
@mjclawar
Copy link
Contributor Author

mjclawar commented Jan 4, 2018

@chriddyp do you have an expected timeline for getting this published as the next version/how do you typically approach publishing for the dash packages? Thanks!

@chriddyp
Copy link
Member

chriddyp commented Jan 4, 2018

Hey @mjclawar - Thanks for the reminder! I just published v0.15.4 now

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants