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

Remove connections list module #8991

Merged
merged 22 commits into from
Mar 2, 2017
Merged

Conversation

obenland
Copy link
Member

Moves Publicize connections to be based on Redux.

This includes creating, updating, and deleting connections. This will also modernize the existing components and probably restructure them in a more modular fashion.

See #5046.

@matticbot
Copy link
Contributor

[ PUBLICIZE_CONNECTION_CREATE ]: ( state, { ID, siteId } ) => ( { ...state, [ ID ]: {
...state[ ID ], sites: [ ...state[ ID ].sites, siteId.toString() ]
[ PUBLICIZE_CONNECTION_CREATE ]: ( state, { connection: { keyring_connection_ID: ID, site_ID } } ) => ( { ...state, [ ID ]: {
...state[ ID ], sites: [ ...state[ ID ].sites, site_ID.toString() ]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is site_ID not always a fixed type?

This is also probably on the edge of readability for a one-liner. 👍 Thanks for the tests through, made what the reducer is doing pretty clear.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe I should test what happens if we mix strings and integers here, not sure

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think we should be very wary about destructuring more than a single level deep, as it becomes very difficult to read, especially with aliasing. Speaking of, naming should be id, not ID, per camelCasing guidelines.

Copy link
Member Author

@obenland obenland Nov 2, 2016

Choose a reason for hiding this comment

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

Is site_ID not always a fixed type?

The /me/keyring-connections endpoint returns the site IDs as an array of strings. While user_ID gets treated with an absint() before being returned, site IDs do not.
Also see #9068 (comment)

onDisconnectionSuccess: function() {
this.setState( { isDisconnecting: false } );
this.props.connections.off( 'destroy:error', this.onDisconnectionError );

notices.success( this.translate( 'The %(service)s account was successfully disconnected.', {
this.props.successNotice( this.props.translate( 'The %(service)s account was successfully disconnected.', {
Copy link
Contributor

Choose a reason for hiding this comment

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

If there's are appropriate redux action types to associate this with, adding these to notice middleware may make sense: https://github.com/Automattic/wp-calypso/blob/master/client/state/notices/middleware.js

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I'll do that when porting update/delete actions over to redux. So far only Create is full redux.

@@ -79,6 +63,7 @@ class SharingServicesGroup extends Component {

export default connect(
( state, { type } ) => ( {
initialized: !! getSelectedSiteId( state ),
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this relate to services being initialized?

Copy link
Member Author

Choose a reason for hiding this comment

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

If no site is selected, connecting services is moot. We can probably remove that, I assume it's from a time when we couldn't rely on having a selected site available?

var connectionsList = require( 'lib/connections-list' )(),
sites = require( 'lib/sites-list' )();
import connectionsList from 'lib/connections-list';
import sites from 'lib/sites-list';
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we perhaps either connect this or update the functions to take in a site object instead of a siteId?

Copy link
Member Author

Choose a reason for hiding this comment

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

Can we connect modules that are not react components?

Copy link
Contributor

Choose a reason for hiding this comment

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

You can create a component that renders nothing like we do for QueryComponents or if it doesn't make sense we can update the interfaces to pass in a site.


componentWillReceiveProps: function( nextProps ) {
this.onClose = this.onClose.bind( this );
this.onSelectedAccountChanged = this.onSelectedAccountChanged.bind( this );
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional, but we can also do in the function def:

onSelectedAccountChanged = () => {
}

Copy link
Contributor

@aduth aduth left a comment

Choose a reason for hiding this comment

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

This probably should have been many separate pull requests. My attentiveness wanes after the 20th file 😄

} );
}

export default AccountDialogAccount;
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: You could include the default export on the same line as the class declaration itself:

export default class AccountDialogAccount extends Component {

Or is there a preference toward exporting bottom-of-file?

{ action: 'connect', label: this.translate( 'Connect' ), isPrimary: true }
];
if ( this.isSelectedAccountConflicting() ) {
this.props.warningNotice( this.props.translate( 'The connection marked {{icon/}} will be replaced with your selection.', {
Copy link
Contributor

Choose a reason for hiding this comment

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

Am I correct in understanding that this will change the conflict notice from being inline to being a global notice? Does that work well with the dialog being shown? Perhaps also worth a design review.

Ref: 3513-gh-calypso-pre-oss

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, does including this in render run the risk of many notices being shown if renders occur unexpectedly?

const classes = classNames( 'account-dialog', {
'single-account': 1 === this.props.accounts.length
} ),
buttons = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be more readable if this were a separate const declaration, not comma-separated, especially since both of these variables are multi-line. What do you think?

];
if ( this.isSelectedAccountConflicting() ) {
this.props.warningNotice( this.props.translate( 'The connection marked {{icon/}} will be replaced with your selection.', {
components: { icon: <span className="noticon noticon-warning" /> },
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if it'd be considered in-scope, but noticons are deprecated in favor of <Gridicon /> and should ideally be updated.

isSavingSitewide: false
};

this.toggleSitewideConnection = this.toggleSitewideConnection.bind( this );
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't feel particularly strongly either way, but curious how you feel about class instance property initializers to simplify binding at the time of declaring the function?

toggleSitewideConnection = ( event ) => {

Copy link
Member Author

Choose a reason for hiding this comment

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

@gwwar had mentioned that to me as well. I like it, especially since it lets us avoid having to write out the constructor.

import ServiceTip from './service-tip';
import SocialLogo from 'components/social-logo';

const SharingService = React.createClass( {
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason you chose not to Component-ify this one?

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 still uses a mixin to monitor connections-list, I'm planning on doing it once all actions have moved over to using Redux

siteUserConnections: getSiteUserConnectionsForService(
state, getSelectedSiteId( state ), getCurrentUserId( state ), service.ID
),
user: getCurrentUser( state ),
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we're only using user.ID, maybe better to pass userId: getCurrentUserId( state ) ?

}
},

addConnection: function( service = this.props.service, keyringConnectionId, externalUserId = false ) {
const _this = this,
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 be unnecessary since the popupMonitor event handler uses an arrow function (this still refers to the component instance).

@@ -49,7 +48,10 @@ const EditorSharingAccordion = React.createClass( {
const targeted = connections.filter( ( connection ) => {
return ! includes( skipped, connection.keyring_connection_ID );
} );
const targetedServices = serviceConnections.getServicesFromConnections( targeted );
const targetedServices = uniq( targeted.map( ( connection ) => ( {
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe plain uniq is not what you want here:

https://lodash.com/docs/4.16.4#uniq

Instead, uniqBy is the one that lets you specify an iteratee:

https://lodash.com/docs/4.16.4#uniqBy

[ PUBLICIZE_CONNECTION_CREATE ]: ( state, { ID, siteId } ) => ( { ...state, [ ID ]: {
...state[ ID ], sites: [ ...state[ ID ].sites, siteId.toString() ]
[ PUBLICIZE_CONNECTION_CREATE ]: ( state, { connection: { keyring_connection_ID: ID, site_ID } } ) => ( { ...state, [ ID ]: {
...state[ ID ], sites: [ ...state[ ID ].sites, site_ID.toString() ]
Copy link
Contributor

Choose a reason for hiding this comment

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

I also think we should be very wary about destructuring more than a single level deep, as it becomes very difficult to read, especially with aliasing. Speaking of, naming should be id, not ID, per camelCasing guidelines.

@obenland obenland force-pushed the remove/connections-list-module branch from efb050d to 7a3ece6 Compare November 1, 2016 18:04
obenland added a commit that referenced this pull request Nov 1, 2016
obenland added a commit that referenced this pull request Nov 2, 2016
* Update keyring reducer to use correct format.

Turns out that publicize connection objects don’t actually look like I
thought the look like.

* Use full connection object when deleting a connection.

Allows the keyring reducer to remove a connection based on the
`keyring_connection_ID`.

* Return all connections for a specified service.

There may be more than one connection per service in the case of
publicize services.

* Introduce `getSiteUserConnectionsForService`

Avoids having to filter the selector in the component that uses it.

* Introduce `getAvailableExternalConnections`

A selector for available external accounts for a service.

* Simplify filtering of selector.

* Extract action object to make it reusable

* Handle update events for connections.

* Update API to accept a connection object

Simplifies its usage in components and allows us to pass its label to
error messages.

* Make keyring reducer easier to read.

See
#8991 (comment)

* Introduce a selector for connections that can be removed by the current user.

See https://github.com/Automattic/wp-calypso/pull/8991/files#r85749283

* Add missing function docs for new action creator.

* Avoid using variable name previously defined in outer scope.

Fixes an ESLint warning.

* Remove unnecessary fallback value.

`filter` always returns a new array.

Props @gwwar.
See
#9068 (comment)

* Limit variable destruction to one level deep.

See
#9068 (comment)

* Move selector for external accounts to sharing directory.

It’s a better place for the selector since it accesses both parts of
sharing, `keyring` and `publicize`. It also returns more of a custom
structure than either keyring or publicize connections.

See
#9068 (comment),
 #9068 (comment)

* Remove unused reference to `additional_external_users`.

See fddcca0.

* Remove unused parts of test state.

See fddcca0.

* Simplify how removable connections are being retrieved.

Checks capabilities based on the current user rather than the selected
site.

Props @gwwar.
See https://github.com/Automattic/wp-calypso/pull/9068/files#r86043229.
@obenland obenland force-pushed the remove/connections-list-module branch from 7a3ece6 to 733fdb0 Compare November 2, 2016 23:07
obenland added a commit that referenced this pull request Nov 2, 2016
Avoids having to define a constructor in 2/3 cases.

Props @gwwar.
See
#8991 (comment),
#8991 (comment)
@obenland obenland force-pushed the remove/connections-list-module branch from ada491a to ea75de9 Compare November 3, 2016 15:33
@obenland obenland force-pushed the remove/connections-list-module branch from ea75de9 to e851afc Compare November 3, 2016 15:35
@obenland obenland force-pushed the remove/connections-list-module branch from e851afc to 5fca738 Compare November 3, 2016 21:47
obenland added a commit that referenced this pull request Nov 3, 2016
Avoids having to define a constructor in 2/3 cases.

Props @gwwar.
See
#8991 (comment),
#8991 (comment)
@obenland obenland force-pushed the remove/connections-list-module branch from 5fca738 to bd3eb43 Compare November 8, 2016 23:09
@obenland obenland force-pushed the remove/connections-list-module branch from f2fbe8d to 949e357 Compare March 1, 2017 20:02
@matticbot matticbot added the [Size] XL Probably needs to be broken down into multiple smaller issues label Mar 1, 2017
}
} else {
// If an account wasn't selected from the dialog or the user cancels
// the connection, the dialog should simply close
this.props.connections.emit( 'create:error', { cancel: true } );
this.props.warningNotice( this.props.translate( 'The connection could not be made because no account was selected.', {
Copy link

Choose a reason for hiding this comment

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

ℹ️ This string is probably long enough that it doesn't need a context. Are you sure you don't want to use a translator comment instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

No need to use a context here. A translator comment is better suited ( i.e 'comment': 'Warning notice that appears If an account wasn't selected in the publicize/sharing dialog')

@matticbot matticbot added the [Size] XL Probably needs to be broken down into multiple smaller issues label Mar 1, 2017
@obenland obenland merged commit 2bc1668 into master Mar 2, 2017
@matticbot matticbot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Mar 2, 2017
@obenland obenland deleted the remove/connections-list-module branch March 2, 2017 17:25
@ockham
Copy link
Contributor

ockham commented Mar 2, 2017

Means we can tick off a bunch of items in #8726? 🎉

@obenland
Copy link
Member Author

obenland commented Mar 2, 2017

Oh, good point! I checked off two items that were fixed by this PR

obenland added a commit that referenced this pull request Mar 2, 2017
@artpi
Copy link
Contributor

artpi commented Mar 3, 2017

Whoa, nice to see that in!

obenland added a commit that referenced this pull request Mar 3, 2017
@mtias mtias added the [Feature] Sharing Features and settings for sharing posts across different platforms, including sharing buttons. label Mar 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Sharing Features and settings for sharing posts across different platforms, including sharing buttons. [Size] XL Probably needs to be broken down into multiple smaller issues State
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants