-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Clean/site list/sites dropdown #9624
Clean/site list/sites dropdown #9624
Conversation
Hi @brunoscopelliti ! It's fine to leave in the
They're interchangeable with our routes, but I would say that siteId is more reliable programmatically, while a slug is much more human readable. For example the following will render stats for the same site:
I'm not too familiar with the history of this component. @mtias did you have any extra background for why selected can be siteId or siteSlug, besides ease of use?
In that case I believe many of the callbacks either redirect to a url, or generate links, of which a site slug is much prettier than using the site id.
I think any human readable links should see a slug, while siteId is more dependable in internal code. Note that we need to be careful when handling slugs for Jetpack connected sites (#9207) That being said I think it's fair to point out that we'll want to have a selector that returns a site given a slug, especially when we begin to store more than just the selected site in the redux tree. |
Also, for context here's the line where we populate selected site in the redux tree. This occurs on any browser refresh, or when you select a site with the picker. https://github.com/Automattic/wp-calypso/blob/master/client/my-sites/controller.js#L172 I'd need to dig a bit in the component, but it might impact this selection loop. If you run into trouble, let us know and I can find a more straightforward component to port. |
Hi @gwwar, If you are not in hurry to have the Thanks to your answers, I think to know how to proceed now... but I've finished my time for today. |
I scraped the codebase; the only case in which we pass as There're a couple of other components, which use
Agree!
I've already this working on my fork, but I've not pushed yet cause I'm not sure is what we want. I think that ideally also
Agree, again :)
This won't be immediately necessary if we decide to use siteId. @gwwar What do you think? |
I've also a meta question :) I would like to maintain the branch in sync with master. # on master
git pull Automattic master
git push
# on this PR branch
git rebase master
git push -f |
Sounds reasonable to me though, let's hear from some other folks, maybe @mtias @ockham @aduth @ebinnion . If we do decide to update the contract I would recommend creating new targeted PR(s) to do so.
The workflow looks good to me. The push force flag is fine to use when you're working alone on a branch. You can also set up the remotes inversely: # do once:
git clone git@github.com:Automattic/wp-calypso.git
git remote add mine git@github.com:<your user name>/wp-calypso.git
# create a branch
git checkout -b my_branch
git push mine my_branch
# updating a local branch
git fetch origin
git checkout my_branch
git rebase -i origin/master
git push -f mine my_branch |
It makes sense :) ps. Thanks for the workflow advices! |
The work on the PR #9754 is completed, and waits a review.
|
I've put down a couple of notes... any other feedback is welcome. Anyway this is not yet ready to be merged, cause I noticed a strange behaviour. I've not yet understood the reason for this behaviour, but I'll keep you informed eventually. Update. Well, I've reduced further the circumstances in which this behaviour appears. The cause is that in this case the I will update the PR as soon as possible. |
I think this PR is now ready to be reviewed; I've left a few comments/questions too. @gwwar I've read in the other thread that you're going to take a vacation... enjoy it! I'll appreciate your feedback on this, when you will be back. |
Hi, @brunoscopelliti do you mind rebasing this branch with master? |
expect( sitesDropdown.hasClass( 'sites-dropdown' ) ).to.be.true; | ||
expect( sitesDropdown.hasClass( 'is-open' ) ).to.be.false; | ||
before( function() { | ||
ConnectedSitesDropdown = require( '../index.jsx' ).default; |
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.
Interesting case here, another option would be to import the unconnected class, and pass through the sites and selected siteId data. @gziolo do you have any opinions here?
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.
We have never tested Component wrapped with connect
so far. I'm not opposed to this approach. From what I see in this example you get additional verification for your connect method, which can be useful.
We could also avoid using redux-mock-store
by testing a plain component with all props injected when necessary. At the same time we could also export mapStateToProps
and test it independently.
My personal preference is the latter option, because it makes testing setup much easier.
@@ -177,6 +177,7 @@ | |||
"react-addons-test-utils": "15.4.0", | |||
"react-hot-loader": "1.3.0", | |||
"react-test-env": "0.2.0", | |||
"redux-mock-store": "1.2.1", |
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.
If we plan on adding a new dev dependency, don't forget to update the shrinkwrap file. You can do this by navigating to your local checkout and typing make shrinkwrap
which handles the process for you. To see what the script does see this doc
Hi @gwwar, I've rebased, and updated I guess you should be pretty busy at your return at work; I will appreciate your feedback on the questions still opened. Then we could decide how to proceed. |
Refactoring to ES6 class, extending PureComponent Using getSite selector in place of sites-list's getSite Replacing sites.getSite with component prop Make sure that 'sites' is populated in Redux store Restore unit tests Handle component loaded before 'me/sites' request Update components gallery example urlToSlug is a better way to get the site slug Added redux-mock-store to test the connected component Update shrinkwrap Test mapStateToProps instead of the connected component
Yup, I'm still catching up on pings @brunoscopelliti 😄 I'll try to get a proper look at this on Monday. |
|
||
const getAllSites = ( state ) => state.sites.items; | ||
|
||
const getFirstSiteId = ( state ) => Object.keys( state.sites.items )[ 0 ]; |
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.
We can add these as selectors in state/sites/selectors
if we think they'd be useful in an implementation.
|
||
displayName: 'SitesDropdown', | ||
this.state = { | ||
selectedSiteId: this.props.selectedSiteId |
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.
Why do we need this component state?
render(){ | ||
return ( | ||
<SitesDropdown | ||
selectedSiteId={ this.state.selectedSiteId } |
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.
It's probably better to defer to default handling in SitesDropdown than add logic in the example.
@@ -74,14 +79,15 @@ export default class SitesDropdown extends PureComponent { | |||
render() { | |||
return ( | |||
<div className={ classNames( 'sites-dropdown', { 'is-open': this.state.open } ) }> | |||
<QuerySites allSites={ true } /> |
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.
This will duplicate sites data in localstorage (SitesLIst) and indexedDB. Let's avoid this for now until we remove more usages of SitesList
this.onClose = this.onClose.bind( this ); | ||
|
||
const selectedSite = props.selectedSiteId |
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.
We still need to depend on SitesList for primary site until we're a bit further along in the project.
if ( primarySite && primarySite.slug !== this.state.selectedSiteSlug ) { | ||
this.setState( { | ||
selectedSiteSlug: primarySite.slug | ||
} ); |
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.
When we're ready, I would instead move this logic to getSelectedSiteSlug
or getSelectedSiteId
in state/sites/selectors
. Unless there's a special need, this can also be passed through as a connected prop vs setting this as component state.
Thanks @brunoscopelliti, I really appreciate the PR but we're not quite ready for this change-set yet. We want to avoid duplicating sites data in multiple stores, until we're confidant that we can really get rid of SitesList quickly. One good next step would be to create a PR that adds a memoized selector for Right now this is handled by SitesList that filters for a |
@brunoscopelliti This PR needs a rebase |
Thanks again @brunoscopelliti for taking a shot at this. With #13094 and #14026 landed, I think we can close out this PR |
Hi everybody,
@gwwar , as you suggested I am opening a pull request to track our work on this request; this is not ready to be merged now.
I've also a couple of questions for you;
I understand that you might be working on completely different things right now, so let me give you a little more context before asking the questions (sorry for the long text).
I am working on the
sites-dropdown
component.It permits the user to select what site should be considered as primary. It uses
site-selector
component for the selection logic, and considers as initially selected the site that is currently the user's primary site (indepentently from what is the currently selected site in the redux store).Since the component receives the currently primary site as
selected
prop, we can't usegetSelectedSite
from 'state/ui/selectors' to get the site that should be initially selected.Currently I am trying using
getSite
from 'state/sites/selectors'.Its signature is
( state, siteId ) => Site
. So it works on the basis of thesiteId
.Here, the problem is that sometimes the
sites-dropdown
component is used, specifing asselected
prop thesiteSlug
, instead of that thesiteId
.In these cases this PR, at the current state, introduces a bug.
From a quick search in the codebase I found that
sites-dropdown
is used only in the following components/pages.My first feeling was that we should uniform, and probably use always the
siteId
(since selectors work exclusively with it).I've started doing this but I felt that I was just increasing confusion around
siteId
, andslug
; I've now reverted those changes.For example
site-selector
when an option is selected, executesonSiteSelect
passing as argument theslug
(not thesiteId
), and this depend more deeper by thesite
component.At this regard my first question is: what do you consider the best way to identify a site (siteId or slug)?
The codebase is not completely uniform here; for example
site-selector
works mostly with the slug name. I guess this is due to the fact that selectors are a relatively new introduction, and you want to have uniformity one day.Eventually I would be happy to help.
A completely different approach would be to make
getRawSite
work both withsiteId
, both withslug
transparently.That's surely less work, but I am not sure it is the right thing to do. What do you think?
Can you think to other alternatives which haven't come to my mind?