-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Editor: Post revisions into redux (#12733)
* Post: Add `/revision` route + early infrastructure to load revisions: `QueryPostRevisions` * Post Revisions: Normalize revisions for state * Post Revisions: Add `requesting` to track the status of revisions requests in Redux * Post Revisions: Use `data-layer` instead of redux-thunk to fetch revisions * Post Revisions: Tests for reducers * Post Revisions: Tests for selectors
- Loading branch information
1 parent
971f415
commit 63bfc14
Showing
14 changed files
with
770 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
Query Post Revisions | ||
================ | ||
|
||
`<QueryPostRevisions />` is a React component used to request post revisions data. | ||
|
||
## Usage | ||
|
||
Render the component, passing `siteId` and `postId`. It does not accept any children, nor does it render any element to the page. You can use it adjacent to other sibling components which make use of the fetched data made available through the global application state. | ||
|
||
```jsx | ||
import React from 'react'; | ||
import QueryPostRevisions from 'components/data/query-post-revisions'; | ||
|
||
export default function PostRevisions( { revisions } ) { | ||
return ( | ||
<div> | ||
<QueryPostRevisions | ||
siteId={ 12345678 } | ||
postId={ 10 } | ||
/> | ||
<div>{ revisions }</div> | ||
</div> | ||
); | ||
} | ||
``` | ||
|
||
## Props | ||
|
||
### `siteId` | ||
|
||
<table> | ||
<tr><th>Type</th><td>Number</td></tr> | ||
<tr><th>Required</th><td>Yes</td></tr> | ||
</table> | ||
|
||
The site ID for which we request post revisions. | ||
|
||
|
||
### `postId` | ||
|
||
<table> | ||
<tr><th>Type</th><td>Number</td></tr> | ||
<tr><th>Required</th><td>Yes</td></tr> | ||
</table> | ||
|
||
The post ID for which we request post revisions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { Component, PropTypes } from 'react'; | ||
import { connect } from 'react-redux'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { requestPostRevisions } from 'state/posts/revisions/actions'; | ||
|
||
class QueryPostRevisions extends Component { | ||
componentWillMount() { | ||
this.request(); | ||
} | ||
|
||
componentDidUpdate( prevProps ) { | ||
if ( | ||
this.props.siteId === prevProps.siteId && | ||
this.props.postId === prevProps.postId | ||
) { | ||
return; | ||
} | ||
|
||
this.request(); | ||
} | ||
|
||
request() { | ||
this.props.requestPostRevisions( this.props.siteId, this.props.postId ); | ||
} | ||
|
||
render() { | ||
return null; | ||
} | ||
} | ||
|
||
QueryPostRevisions.propTypes = { | ||
postId: PropTypes.number, | ||
siteId: PropTypes.number, | ||
requestPostRevisions: PropTypes.func, | ||
}; | ||
|
||
export default connect( | ||
() => ( {} ), | ||
{ requestPostRevisions } | ||
)( QueryPostRevisions ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import revisions from './revisions'; | ||
|
||
export default revisions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { flow, map } from 'lodash'; | ||
import mapValues from 'lodash/fp/mapValues'; | ||
import pick from 'lodash/fp/pick'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { | ||
POST_REVISIONS_REQUEST, | ||
} from 'state/action-types'; | ||
import { dispatchRequest } from 'state/data-layer/wpcom-http/utils'; | ||
import { http } from 'state/data-layer/wpcom-http/actions'; | ||
import { | ||
receivePostRevisions, | ||
receivePostRevisionsSuccess, | ||
receivePostRevisionsFailure, | ||
} from 'state/posts/revisions/actions'; | ||
|
||
/** | ||
* Normalize a WP REST API Post Revisions ressource for consumption in Calypso | ||
* | ||
* @param {Object} revision Raw revision from the API | ||
* @returns {Object} the normalized revision | ||
*/ | ||
export function normalizeRevision( revision ) { | ||
if ( ! revision ) { | ||
return revision; | ||
} | ||
|
||
return { | ||
...revision, | ||
...flow( | ||
pick( [ 'title', 'content', 'excerpt' ] ), | ||
mapValues( ( val = {} ) => val.rendered ) | ||
)( revision ) | ||
}; | ||
} | ||
|
||
/** | ||
* Dispatches returned error from post revisions request | ||
* | ||
* @param {Function} dispatch Redux dispatcher | ||
* @param {Object} action Redux action | ||
* @param {String} action.siteId of the revisions | ||
* @param {String} action.postId of the revisions | ||
* @param {Function} next dispatches to next middleware in chain | ||
* @param {Object} rawError from HTTP request | ||
* @returns {Object} the dispatched action | ||
*/ | ||
export const receiveError = ( { dispatch }, { siteId, postId }, next, rawError ) => | ||
dispatch( receivePostRevisionsFailure( siteId, postId, rawError ) ); | ||
|
||
/** | ||
* Dispatches returned post revisions | ||
* | ||
* @param {Function} dispatch Redux dispatcher | ||
* @param {Object} action Redux action | ||
* @param {String} action.siteId of the revisions | ||
* @param {String} action.postId of the revisions | ||
* @param {Function} next dispatches to next middleware in chain | ||
* @param {Array} revisions raw data from post revisions API | ||
*/ | ||
export const receiveSuccess = ( { dispatch }, { siteId, postId }, next, revisions ) => { | ||
dispatch( receivePostRevisionsSuccess( siteId, postId ) ); | ||
dispatch( receivePostRevisions( siteId, postId, map( revisions, normalizeRevision ) ) ); | ||
}; | ||
|
||
/** | ||
* Dispatches a request to fetch post revisions | ||
* | ||
* @param {Function} dispatch Redux dispatcher | ||
* @param {Object} action Redux action | ||
*/ | ||
export const fetchPostRevisions = ( { dispatch }, action ) => { | ||
const { siteId, postId } = action; | ||
dispatch( http( { | ||
path: `/sites/${ siteId }/posts/${ postId }/revisions`, | ||
method: 'GET', | ||
query: { | ||
apiNamespace: 'wp/v2', | ||
}, | ||
}, action ) ); | ||
}; | ||
|
||
const dispatchPostRevisionsRequest = dispatchRequest( fetchPostRevisions, receiveSuccess, receiveError ); | ||
|
||
export default { | ||
[ POST_REVISIONS_REQUEST ]: [ dispatchPostRevisionsRequest ] | ||
}; |
114 changes: 114 additions & 0 deletions
114
client/state/data-layer/wpcom/posts/revisions/test/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { expect } from 'chai'; | ||
import { map } from 'lodash'; | ||
import sinon from 'sinon'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { | ||
fetchPostRevisions, | ||
normalizeRevision, | ||
receiveSuccess, | ||
receiveError, | ||
} from '../'; | ||
import { | ||
receivePostRevisions, | ||
receivePostRevisionsSuccess, | ||
receivePostRevisionsFailure, | ||
requestPostRevisions, | ||
} from 'state/posts/revisions/actions'; | ||
import { http } from 'state/data-layer/wpcom-http/actions'; | ||
|
||
const successfulPostRevisionsResponse = [ | ||
{ | ||
author: 1, | ||
date: '2017-04-20T12:14:40', | ||
date_gmt: '2017-04-20T12:14:40', | ||
id: 11, | ||
modified: '2017-04-21T12:14:40', | ||
modified_gmt: '2017-04-21T12:14:40', | ||
parent: 10, | ||
title: { | ||
rendered: 'Sed nobis ab earum', | ||
}, | ||
content: { | ||
rendered: '<p>Lorem ipsum</p>', | ||
}, | ||
excerpt: { | ||
rendered: '', | ||
}, | ||
}, | ||
]; | ||
|
||
const normalizedPostRevisions = [ | ||
{ | ||
author: 1, | ||
date: '2017-04-20T12:14:40', | ||
date_gmt: '2017-04-20T12:14:40', | ||
id: 11, | ||
modified: '2017-04-21T12:14:40', | ||
modified_gmt: '2017-04-21T12:14:40', | ||
parent: 10, | ||
title: 'Sed nobis ab earum', | ||
content: '<p>Lorem ipsum</p>', | ||
excerpt: '', | ||
}, | ||
]; | ||
|
||
describe( '#normalizeRevision', () => { | ||
it( 'should only keep the rendered version of `title`, `content` and `excerpt`', () => { | ||
expect( | ||
map( successfulPostRevisionsResponse, normalizeRevision ) | ||
).to.eql( normalizedPostRevisions ); | ||
} ); | ||
} ); | ||
|
||
describe( '#fetchPostRevisions', () => { | ||
it( 'should dispatch HTTP request to tag endpoint', () => { | ||
const action = requestPostRevisions( 12345678, 10 ); | ||
const dispatch = sinon.spy(); | ||
const next = sinon.spy(); | ||
|
||
fetchPostRevisions( { dispatch }, action, next ); | ||
|
||
expect( dispatch ).to.have.been.calledOnce; | ||
expect( dispatch ).to.have.been.calledWith( http( { | ||
method: 'GET', | ||
path: '/sites/12345678/posts/10/revisions', | ||
query: { | ||
apiNamespace: 'wp/v2', | ||
}, | ||
}, action ) ); | ||
} ); | ||
} ); | ||
|
||
describe( '#receiveSuccess', () => { | ||
it( 'should normalize the revisions and dispatch `receivePostRevisions` and `receivePostRevisionsSuccess`', () => { | ||
const action = requestPostRevisions( 12345678, 10 ); | ||
const dispatch = sinon.spy(); | ||
const next = sinon.spy(); | ||
|
||
receiveSuccess( { dispatch }, action, next, successfulPostRevisionsResponse ); | ||
|
||
expect( dispatch ).to.have.been.calledTwice; | ||
expect( dispatch ).to.have.been.calledWith( receivePostRevisionsSuccess( 12345678, 10 ) ); | ||
expect( dispatch ).to.have.been.calledWith( receivePostRevisions( 12345678, 10, normalizedPostRevisions ) ); | ||
} ); | ||
} ); | ||
|
||
describe( '#receiveError', () => { | ||
it( 'should dispatch `receivePostRevisionsFailure`', () => { | ||
const action = requestPostRevisions( 12345678, 10 ); | ||
const dispatch = sinon.spy(); | ||
const next = sinon.spy(); | ||
const rawError = new Error( 'Foo Bar' ); | ||
|
||
receiveError( { dispatch }, action, next, rawError ); | ||
|
||
expect( dispatch ).to.have.been.calledOnce; | ||
expect( dispatch ).to.have.been.calledWith( receivePostRevisionsFailure( 12345678, 10, rawError ) ); | ||
} ); | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.