diff --git a/circle.yml b/circle.yml index 160bc7bb9..6009a88e6 100644 --- a/circle.yml +++ b/circle.yml @@ -21,6 +21,8 @@ test: override: # Run the tests using the junit reporter. - MOCHA_FILE=$CIRCLE_TEST_REPORTS/junit/test-results.xml NPM_PACKAGE_CONFIG_MOCHA_REPORTER=mocha-junit-reporter npm run test + # Run the e2e test suite + - npm run e2e deployment: release: diff --git a/client/coral-configure/components/ConfigureCommentStream.js b/client/coral-configure/components/ConfigureCommentStream.js index 507c764d7..bf4ebe3e6 100644 --- a/client/coral-configure/components/ConfigureCommentStream.js +++ b/client/coral-configure/components/ConfigureCommentStream.js @@ -7,47 +7,50 @@ import translations from '../translations.json'; const lang = new I18n(translations); export default ({handleChange, handleApply, changed, ...props}) => ( -
-
-

{lang.t('configureCommentStream.title')}

-

{lang.t('configureCommentStream.description')}

- -
- -
+ cStyle={changed ? 'green' : 'darkGrey'} > + {lang.t('configureCommentStream.apply')} + + + + + + ); diff --git a/client/coral-configure/containers/ConfigureStreamContainer.js b/client/coral-configure/containers/ConfigureStreamContainer.js index 90835ab3f..dfe94de42 100644 --- a/client/coral-configure/containers/ConfigureStreamContainer.js +++ b/client/coral-configure/containers/ConfigureStreamContainer.js @@ -1,8 +1,9 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; +import {compose} from 'react-apollo'; -import {I18n} from '../../coral-framework'; -import {updateOpenStatus, updateConfiguration} from '../../coral-framework/actions/asset'; +import {I18n} from 'coral-framework'; +import {updateOpenStatus, updateConfiguration} from 'coral-framework/actions/asset'; import CloseCommentsInfo from '../components/CloseCommentsInfo'; import ConfigureCommentStream from '../components/ConfigureCommentStream'; @@ -13,11 +14,8 @@ class ConfigureStreamContainer extends Component { constructor (props) { super(props); - console.log('moderation', props.asset.settings.moderation); - this.state = { - premod: props.asset.settings.moderation === 'PRE', - premodLinks: false + changed: false }; this.toggleStatus = this.toggleStatus.bind(this); @@ -25,11 +23,18 @@ class ConfigureStreamContainer extends Component { this.handleApply = this.handleApply.bind(this); } - handleApply () { - const {premod, changed} = this.state; + handleApply (e) { + e.preventDefault(); + const {elements} = e.target; + const premod = elements.premod.checked; + + // const premodLinks = elements.premodLinks.checked; + const {changed} = this.state; + const newConfig = { moderation: premod ? 'PRE' : 'POST' }; + if (changed) { this.props.updateConfiguration(newConfig); setTimeout(() => { @@ -40,16 +45,16 @@ class ConfigureStreamContainer extends Component { } } - handleChange (e) { - const {name, checked} = e.target; + handleChange () { this.setState({ - [name]: checked, changed: true }); } toggleStatus () { - this.props.updateStatus(this.props.asset.closedAt === null ? 'closed' : 'open'); + this.props.updateStatus( + this.props.asset.closedAt === null ? 'closed' : 'open' + ); } getClosedIn () { @@ -60,13 +65,16 @@ class ConfigureStreamContainer extends Component { render () { const status = this.props.asset.closedAt === null ? 'open' : 'closed'; + const premod = this.props.asset.settings.moderation === 'PRE'; + return (

{status === 'open' ? 'Close' : 'Open'} Comment Stream

@@ -89,7 +97,6 @@ const mapDispatchToProps = dispatch => ({ updateConfiguration: newConfig => dispatch(updateConfiguration(newConfig)) }); -export default connect( - mapStateToProps, - mapDispatchToProps +export default compose( + connect(mapStateToProps, mapDispatchToProps) )(ConfigureStreamContainer); diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index f734bce0b..93c89ffb0 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -26,6 +26,11 @@ class Comment extends React.Component { } static propTypes = { + reactKey: PropTypes.string.isRequired, + + // id of currently opened ReplyBox. tracked in Stream.js + activeReplyBox: PropTypes.string.isRequired, + setActiveReplyBox: PropTypes.func.isRequired, refetch: PropTypes.func.isRequired, showSignInDialog: PropTypes.func.isRequired, postAction: PropTypes.func.isRequired, @@ -60,15 +65,6 @@ class Comment extends React.Component { }).isRequired } - onReplyBoxClick = () => { - if (this.props.currentUser) { - this.setState({replyBoxVisible: !this.state.replyBoxVisible}); - } else { - const offset = document.getElementById(`c_${this.props.comment.id}`).getBoundingClientRect().top - 75; - this.props.showSignInDialog(offset); - } - } - render () { const { comment, @@ -81,6 +77,8 @@ class Comment extends React.Component { addNotification, showSignInDialog, postAction, + setActiveReplyBox, + activeReplyBox, deleteAction } = this.props; @@ -106,7 +104,7 @@ class Comment extends React.Component {
setActiveReplyBox(comment.id)} parentCommentId={parentId || comment.id} currentUserId={currentUser && currentUser.id} banned={false} /> @@ -130,13 +128,13 @@ class Comment extends React.Component {
{ - this.state.replyBoxVisible + activeReplyBox === comment.id ? { - console.log('replyPostedHandler'); - this.setState({replyBoxVisible: false}); + setActiveReplyBox(''); refetch(); }} + setActiveReplyBox={setActiveReplyBox} parentId={parentId || comment.id} addNotification={addNotification} authorId={currentUser.id} @@ -149,6 +147,8 @@ class Comment extends React.Component { comment.replies.map(reply => { return ; }) diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index 5922266fa..416c7fef8 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -9,8 +9,8 @@ const {logout, showSignInDialog} = authActions; const {addNotification, clearNotification} = notificationActions; const {fetchAssetSuccess} = assetActions; -import {queryStream} from './graphql/queries'; -import {postComment, postAction, deleteAction} from './graphql/mutations'; +import {queryStream} from 'coral-framework/graphql/queries'; +import {postComment, postAction, deleteAction} from 'coral-framework/graphql/mutations'; import {Notification, notificationActions, authActions, assetActions, pym} from 'coral-framework'; import Stream from './Stream'; @@ -90,9 +90,12 @@ class Embed extends Component { render () { const {activeTab} = this.state; + const {closedAt} = this.props.asset; const {loading, asset, refetch} = this.props.data; const {loggedIn, isAdmin, user, showSignInDialog, signInOffset} = this.props.auth; + const openStream = closedAt === null; + const expandForLogin = showSignInDialog ? { minHeight: document.body.scrollHeight + 200 } : {}; @@ -109,7 +112,7 @@ class Embed extends Component { {loggedIn && } { - asset.closedAt === null + openStream ?
({ - items: state.items.toJS(), notification: state.notification.toJS(), auth: state.auth.toJS(), - userData: state.user.toJS() + userData: state.user.toJS(), + asset: state.asset.toJS() }); const mapDispatchToProps = dispatch => ({ diff --git a/client/coral-embed-stream/src/Stream.js b/client/coral-embed-stream/src/Stream.js index 73842a947..65743e6c7 100644 --- a/client/coral-embed-stream/src/Stream.js +++ b/client/coral-embed-stream/src/Stream.js @@ -1,49 +1,72 @@ import React, {PropTypes} from 'react'; import Comment from './Comment'; -const Stream = ({ - comments, - currentUser, - asset, - postItem, - addNotification, - postAction, - deleteAction, - showSignInDialog, - refetch -}) => { - return ( -
- { - comments.map(comment => { - return ; - }) - } -
- ); -}; +class Stream extends React.Component { -Stream.propTypes = { - refetch: PropTypes.func.isRequired, - addNotification: PropTypes.func.isRequired, - postItem: PropTypes.func.isRequired, - asset: PropTypes.object.isRequired, - comments: PropTypes.array.isRequired, - currentUser: PropTypes.shape({ - displayName: PropTypes.string, - id: PropTypes.string - }) -}; + static propTypes = { + refetch: PropTypes.func.isRequired, + addNotification: PropTypes.func.isRequired, + postItem: PropTypes.func.isRequired, + asset: PropTypes.object.isRequired, + comments: PropTypes.array.isRequired, + currentUser: PropTypes.shape({ + displayName: PropTypes.string, + id: PropTypes.string + }) + } + + constructor(props) { + super(props); + this.state = {activeReplyBox: ''}; + this.setActiveReplyBox = this.setActiveReplyBox.bind(this); + } + + setActiveReplyBox (reactKey) { + if (!this.props.currentUser) { + const offset = document.getElementById(`c_${reactKey}`).getBoundingClientRect().top - 75; + this.props.showSignInDialog(offset); + } else { + this.setState({activeReplyBox: reactKey}); + } + } + + render () { + const { + comments, + currentUser, + asset, + postItem, + addNotification, + postAction, + deleteAction, + showSignInDialog, + refetch + } = this.props; + + return ( +
+ { + comments.map(comment => { + return ; + }) + } +
+ ); + } +} export default Stream; diff --git a/client/coral-embed-stream/src/graphql/mutations/postComment.graphql b/client/coral-embed-stream/src/graphql/mutations/postComment.graphql deleted file mode 100644 index a9496f1fa..000000000 --- a/client/coral-embed-stream/src/graphql/mutations/postComment.graphql +++ /dev/null @@ -1,23 +0,0 @@ - - fragment commentView on Comment { - id - body - status - user { - name: displayName - } - actions { - type: action_type - count - current: current_user { - id - created_at - } - } - } - -mutation CreateComment ($asset_id: ID!, $parent_id: ID, $body: String!) { - createComment(asset_id:$asset_id, parent_id:$parent_id, body:$body) { - ...commentView - } -} diff --git a/client/coral-framework/actions/asset.js b/client/coral-framework/actions/asset.js index b8474857c..d5db289c3 100644 --- a/client/coral-framework/actions/asset.js +++ b/client/coral-framework/actions/asset.js @@ -10,30 +10,30 @@ export const fetchAssetRequest = () => ({type: actions.FETCH_ASSET_REQUEST}); export const fetchAssetSuccess = asset => ({type: actions.FETCH_ASSET_SUCCESS, asset}); export const fetchAssetFailure = error => ({type: actions.FETCH_ASSET_FAILURE, error}); -const updateConfigRequest = () => ({type: actions.UPDATE_CONFIG_REQUEST}); -const updateConfigSuccess = config => ({type: actions.UPDATE_CONFIG_SUCCESS, config}); -const updateConfigFailure = () => ({type: actions.UPDATE_CONFIG_FAILURE}); +const updateAssetSettingsRequest = () => ({type: actions.UPDATE_ASSET_SETTINGS_REQUEST}); +const updateAssetSettingsSuccess = settings => ({type: actions.UPDATE_ASSET_SETTINGS_SUCCESS, settings}); +const updateAssetSettingsFailure = () => ({type: actions.UPDATE_ASSET_SETTINGS_FAILURE}); export const updateConfiguration = newConfig => (dispatch, getState) => { const assetId = getState().asset.toJS().id; - dispatch(updateConfigRequest()); + dispatch(updateAssetSettingsRequest()); coralApi(`/assets/${assetId}/settings`, {method: 'PUT', body: newConfig}) .then(() => { dispatch(addNotification('success', lang.t('successUpdateSettings'))); - dispatch(updateConfigSuccess(newConfig)); + dispatch(updateAssetSettingsSuccess(newConfig)); }) - .catch(error => dispatch(updateConfigFailure(error))); + .catch(error => dispatch(updateAssetSettingsFailure(error))); }; export const updateOpenStream = closedBody => (dispatch, getState) => { const assetId = getState().asset.toJS().id; - dispatch(updateConfigRequest()); + dispatch(fetchAssetRequest()); coralApi(`/assets/${assetId}/status`, {method: 'PUT', body: closedBody}) .then(() => { dispatch(addNotification('success', lang.t('successUpdateSettings'))); - dispatch(updateConfigSuccess(closedBody)); + dispatch(fetchAssetSuccess(closedBody)); }) - .catch(error => dispatch(updateConfigFailure(error))); + .catch(error => dispatch(fetchAssetFailure(error))); }; const openStream = () => ({type: actions.OPEN_COMMENTS}); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index e815fd5d0..f7bce4808 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -3,7 +3,6 @@ import translations from './../translations'; const lang = new I18n(translations); import * as actions from '../constants/auth'; import coralApi, {base} from '../helpers/response'; -import {addItem} from './items'; // Dialog Actions export const showSignInDialog = (offset = 0) => ({type: actions.SHOW_SIGNIN_DIALOG, offset}); @@ -30,7 +29,6 @@ export const fetchSignIn = (formData) => (dispatch) => { const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length; dispatch(signInSuccess(user, isAdmin)); dispatch(hideSignInDialog()); - dispatch(addItem(user, 'users')); }) .catch(() => dispatch(signInFailure(lang.t('error.emailPasswordError')))); }; @@ -59,7 +57,6 @@ export const facebookCallback = (err, data) => dispatch => { const user = JSON.parse(data); dispatch(signInFacebookSuccess(user)); dispatch(hideSignInDialog()); - dispatch(addItem(user, 'users')); } catch (err) { dispatch(signInFacebookFailure(err)); return; diff --git a/client/coral-framework/actions/items.js b/client/coral-framework/actions/items.js deleted file mode 100644 index e289e9f60..000000000 --- a/client/coral-framework/actions/items.js +++ /dev/null @@ -1,268 +0,0 @@ -import coralApi from '../helpers/response'; -import {fromJS} from 'immutable'; -import {UPDATE_CONFIG} from '../constants/config'; - -/** -* Action name constants -*/ - -export const ADD_ITEM = 'ADD_ITEM'; -export const UPDATE_ITEM = 'UPDATE_ITEM'; -export const APPEND_ITEM_ARRAY = 'APPEND_ITEM_ARRAY'; - -/** - * Action creators - */ - - /* - * Adds an item to the local store without posting it to the server - * Useful for optimistic posting, etc. - * - * @params - * item - the item to be posted - * - */ - -export const addItem = (item, item_type) => { - if (!item.id) { - console.warn('addItem called without an item id.'); - } - return { - type: ADD_ITEM, - item, - item_type, - id: item.id - }; -}; - -/* -* Updates an item in the local store without posting it to the server -* Useful for item-level toggles, etc. -* -* @params -* id - the id of the item to be posted -* property - the property to be updated -* value - the value that the property should be set to -* item_type - the type of the item being updated (users, comments, etc) -* -*/ -export const updateItem = (id, property, value, item_type) => { - return { - type: UPDATE_ITEM, - id, - property, - value, - item_type - }; -}; - -/* -* Appends data to an array in an item in the local store without posting it to the server -* Useful for adding a recently posted reply to a comment, etc. -* -* @params -* id - the id of the item to be posted -* property - the property to be updated (should be an array) -* value - the value that should be added to the array -* add_to_front - boolean that defines whether value is added at the beginning (unshift) or end (push) -* item_type - the type of the item being updated (users, comments, etc) -* -*/ -export const appendItemArray = (id, property, value, add_to_front, item_type) => { - return { - type: APPEND_ITEM_ARRAY, - id, - property, - value, - add_to_front, - item_type - }; -}; - -/* -* Get Items from Query -* Gets a set of items from a predefined query -* -* @params -* Query - a predefiend query for retreiving items -* -* @returns -* A promise resolving to a set of items -* -* @dispatches -* A set of items to the item store -*/ -export function getStream (assetUrl) { - return (dispatch) => { - return coralApi(`/stream?asset_url=${encodeURIComponent(assetUrl)}`) - .then((json) => { - - /* Add items to the store */ - Object.keys(json).forEach(type => { - if (type === 'actions') { - json[type].forEach(action => { - action.id = `${action.action_type}_${action.item_id}`; - dispatch(addItem(action, 'actions')); - }); - } else if (type === 'settings') { - dispatch({type: UPDATE_CONFIG, config: fromJS(json[type])}); - } else { - json[type].forEach(item => { - dispatch(addItem(item, type)); - }); - } - }); - - const assetId = json.assets[0].id; - - /* Sort comments by date*/ - json.comments.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); - const rels = json.comments.reduce((h, item) => { - - /* Check for root and child comments. */ - if ( - item.asset_id === assetId && - !item.parent_id) { - h.rootComments.push(item.id); - } else if ( - item.asset_id === assetId - ) { - let children = h.childComments[item.parent_id] || []; - h.childComments[item.parent_id] = children.concat(item.id); - } - return h; - }, {rootComments: [], childComments: {}}); - - dispatch(updateItem(assetId, 'comments', rels.rootComments, 'assets')); - - Object.keys(rels.childComments).forEach(key => { - dispatch(updateItem(key, 'children', rels.childComments[key].reverse(), 'comments')); - }); - - /* Hydrate actions on comments */ - json.actions.forEach(action => { - dispatch(updateItem(action.item_id, action.action_type, action.id, 'comments')); - }); - - return (json); - }); - }; -} - -/* -* Get Items Array -* Gets a set of items from an array of item ids -* -* @params -* Query - a predefiend query for retreiving items -* -* @returns -* A promise resolving to a set of items -* -* @dispatches -* A set of items to the item store -*/ - -export function getItemsArray (ids) { - return (dispatch) => { - return coralApi(`/item/${ids}`) - .then((json) => { - for (let i = 0; i < json.items.length; i++) { - dispatch(addItem(json.items[i])); - } - return json.items; - }); - }; -} - -/* -* PutItem -* Puts an item -* -* @params -* Item - the item to be put -* -* @returns -* A promise resolving to an item is -* -* @dispatches -* The newly put item to the item store -*/ - -export function postItem (item, type, id, mutate) { - console.log( - item, - type, - id, - mutate - ); - mutate({ - variables: { - asset_id: id, - body: item, - parent_id: null - } - }).then(({data}) => { - console.log('it workt'); - console.log(data); - }); - - // return (dispatch) => { - // if (id) { - // item.id = id; - // } - // return coralApi(`/${type}`, {method: 'POST', body: item}) - // .then((json) => { - // dispatch(addItem({...item, id:json.id}, type)); - // return json; - // }); - // }; -} - -/* -* PostAction -* Posts an action to an item -* -* @params -* id - the id of the item on which the action is taking place -* action - the action object. -* Must include an 'action_type' string. -* May optionally include a `metadata` object with arbitrary action data. -* user - the user performing the action -* host - the coral host -* -* @returns -* A promise resolving to null or an error -* -*/ - -export function postAction (item_id, item_type, action) { - return (dispatch) => { - return coralApi(`/${item_type}/${item_id}/actions`, {method: 'POST', body: action}) - .then((json) => { - dispatch(updateItem(action.item_id, action.action_type, action.id, item_type)); - return json; - }); - }; -} - -/* -* DeleteAction -* Deletes an action to an item -* -* @params -* id - the id of the item on which the action is taking place -* action - the name of the action -* user - the user performing the action -* host - the coral host -* -* @returns -* A promise resolving to null or an error -* -*/ - -export function deleteAction (action_id) { - return () => { - return coralApi(`/actions/${action_id}`, {method: 'DELETE'}); - }; -} diff --git a/client/coral-framework/actions/user.js b/client/coral-framework/actions/user.js index 021c48eeb..4620262d3 100644 --- a/client/coral-framework/actions/user.js +++ b/client/coral-framework/actions/user.js @@ -1,7 +1,5 @@ import * as actions from '../constants/user'; -import * as assetActions from '../constants/assets'; import {addNotification} from '../actions/notification'; -import {addItem} from '../actions/items'; import coralApi from '../helpers/response'; import I18n from 'coral-framework/modules/i18n/i18n'; @@ -21,36 +19,3 @@ export const saveBio = (user_id, formData) => dispatch => { }) .catch(error => dispatch(saveBioFailure(error))); }; - -/** - * - * Get a list of comments by a single user - * - * @param {string} user_id - * @returns Promise - */ -export const fetchCommentsByUserId = userId => { - return (dispatch, getState) => { - dispatch({type: actions.COMMENTS_BY_USER_REQUEST}); - return coralApi(`/comments?user_id=${userId}`) - .then(({comments, assets}) => { - const state = getState(); - comments.forEach(comment => dispatch(addItem(comment, 'comments'))); - assets.forEach(asset => { - const prevAsset = state.items.getIn(['assets', asset.id]); - - if (prevAsset) { - - // Include data such as hydrated comments from assets already in the system. - dispatch(addItem({...prevAsset.toJS(), ...asset}, 'assets')); - } else { - dispatch(addItem(asset, 'assets')); - } - }); - - dispatch({type: actions.COMMENTS_BY_USER_SUCCESS, comments: comments.map(comment => comment.id)}); - dispatch({type: assetActions.MULTIPLE_ASSETS_SUCCESS, assets: assets.map(asset => asset.id)}); - }) - .catch(error => dispatch({type: actions.COMMENTS_BY_USER_FAILURE, error})); - }; -}; diff --git a/client/coral-framework/client.js b/client/coral-framework/client.js index 40a539634..b4a7a38df 100644 --- a/client/coral-framework/client.js +++ b/client/coral-framework/client.js @@ -2,6 +2,7 @@ import ApolloClient, {addTypename} from 'apollo-client'; import getNetworkInterface from './transport'; export const client = new ApolloClient({ + connectToDevTools: true, queryTransformer: addTypename, dataIdFromObject: (result) => { if (result.id && result.__typename) { // eslint-disable-line no-underscore-dangle diff --git a/client/coral-framework/constants/asset.js b/client/coral-framework/constants/asset.js index bfeb98441..40f746706 100644 --- a/client/coral-framework/constants/asset.js +++ b/client/coral-framework/constants/asset.js @@ -2,12 +2,9 @@ export const FETCH_ASSET_REQUEST = 'FETCH_ASSET_REQUEST'; export const FETCH_ASSET_FAILURE = 'FETCH_ASSET_FAILURE'; export const FETCH_ASSET_SUCCESS = 'FETCH_ASSET_SUCCESS'; -export const UPDATE_CONFIG_REQUEST = 'UPDATE_CONFIG_REQUEST'; -export const UPDATE_CONFIG_SUCCESS = 'UPDATE_CONFIG_SUCCESS'; -export const UPDATE_CONFIG_FAILURE = 'UPDATE_CONFIG_FAILURE'; - -export const UPDATE_CONFIG = 'UPDATE_CONFIG'; +export const UPDATE_ASSET_SETTINGS_REQUEST = 'UPDATE_ASSET_SETTINGS_REQUEST'; +export const UPDATE_ASSET_SETTINGS_SUCCESS = 'UPDATE_ASSET_SETTINGS_SUCCESS'; +export const UPDATE_ASSET_SETTINGS_FAILURE = 'UPDATE_ASSET_SETTINGS_FAILURE'; export const OPEN_COMMENTS = 'OPEN_COMMENTS'; export const CLOSE_COMMENTS = 'CLOSE_COMMENTS'; -export const ADD_ITEM = 'ADD_ITEM'; diff --git a/client/coral-framework/graphql/fragments/commentView.graphql b/client/coral-framework/graphql/fragments/commentView.graphql new file mode 100644 index 000000000..b54c00e67 --- /dev/null +++ b/client/coral-framework/graphql/fragments/commentView.graphql @@ -0,0 +1,20 @@ +fragment commentView on Comment { + id + body + created_at + user { + id + name: displayName + settings { + bio + } + } + actions { + type: action_type + count + current: current_user { + id + created_at + } + } +} diff --git a/client/coral-embed-stream/src/graphql/mutations/deleteAction.graphql b/client/coral-framework/graphql/mutations/deleteAction.graphql similarity index 100% rename from client/coral-embed-stream/src/graphql/mutations/deleteAction.graphql rename to client/coral-framework/graphql/mutations/deleteAction.graphql diff --git a/client/coral-embed-stream/src/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js similarity index 88% rename from client/coral-embed-stream/src/graphql/mutations/index.js rename to client/coral-framework/graphql/mutations/index.js index 383862455..b97e5ff22 100644 --- a/client/coral-embed-stream/src/graphql/mutations/index.js +++ b/client/coral-framework/graphql/mutations/index.js @@ -3,7 +3,12 @@ import POST_COMMENT from './postComment.graphql'; import POST_ACTION from './postAction.graphql'; import DELETE_ACTION from './deleteAction.graphql'; +import commentView from '../fragments/commentView.graphql'; + export const postComment = graphql(POST_COMMENT, { + options: () => ({ + fragments: commentView + }), props: ({mutate}) => ({ postItem: ({asset_id, body, parent_id} /* , type */ ) => { return mutate({ diff --git a/client/coral-embed-stream/src/graphql/mutations/postAction.graphql b/client/coral-framework/graphql/mutations/postAction.graphql similarity index 100% rename from client/coral-embed-stream/src/graphql/mutations/postAction.graphql rename to client/coral-framework/graphql/mutations/postAction.graphql diff --git a/client/coral-framework/graphql/mutations/postComment.graphql b/client/coral-framework/graphql/mutations/postComment.graphql new file mode 100644 index 000000000..499871766 --- /dev/null +++ b/client/coral-framework/graphql/mutations/postComment.graphql @@ -0,0 +1,7 @@ +#import "../fragments/commentView.graphql" + +mutation CreateComment ($asset_id: ID!, $parent_id: ID, $body: String!) { + createComment(asset_id:$asset_id, parent_id:$parent_id, body:$body) { + ...commentView + } +} diff --git a/client/coral-embed-stream/src/graphql/queries/index.js b/client/coral-framework/graphql/queries/index.js similarity index 66% rename from client/coral-embed-stream/src/graphql/queries/index.js rename to client/coral-framework/graphql/queries/index.js index db4e08cde..1a9e8d36e 100644 --- a/client/coral-embed-stream/src/graphql/queries/index.js +++ b/client/coral-framework/graphql/queries/index.js @@ -1,5 +1,6 @@ import {graphql} from 'react-apollo'; import STREAM_QUERY from './streamQuery.graphql'; +import MY_COMMENT_HISTORY from './myCommentHistory.graphql'; function getQueryVariable(variable) { let query = window.location.search.substring(1); @@ -13,5 +14,11 @@ function getQueryVariable(variable) { } export const queryStream = graphql(STREAM_QUERY, { - options: {variables: {asset_url: getQueryVariable('asset_url')}} + options: () => ({ + variables: { + asset_url: getQueryVariable('asset_url') + } + }) }); + +export const myCommentHistory = graphql(MY_COMMENT_HISTORY, {}); diff --git a/client/coral-framework/graphql/queries/myCommentHistory.graphql b/client/coral-framework/graphql/queries/myCommentHistory.graphql new file mode 100644 index 000000000..6a4309dac --- /dev/null +++ b/client/coral-framework/graphql/queries/myCommentHistory.graphql @@ -0,0 +1,9 @@ +query myCommentHistory { + me { + comments { + id + body + created_at + } + } +} diff --git a/client/coral-embed-stream/src/graphql/queries/streamQuery.graphql b/client/coral-framework/graphql/queries/streamQuery.graphql similarity index 62% rename from client/coral-embed-stream/src/graphql/queries/streamQuery.graphql rename to client/coral-framework/graphql/queries/streamQuery.graphql index 64bb46b47..77f8ed356 100644 --- a/client/coral-embed-stream/src/graphql/queries/streamQuery.graphql +++ b/client/coral-framework/graphql/queries/streamQuery.graphql @@ -1,24 +1,4 @@ - -fragment commentView on Comment { - id - body - created_at - user { - id - name: displayName - settings { - bio - } - } - actions { - type: action_type - count - current: current_user { - id - created_at - } - } -} +#import "../fragments/commentView.graphql" query AssetQuery($asset_url: String!) { asset(url: $asset_url) { diff --git a/client/coral-framework/index.js b/client/coral-framework/index.js index c21136d27..d2cd4197b 100644 --- a/client/coral-framework/index.js +++ b/client/coral-framework/index.js @@ -1,19 +1,17 @@ -import Notification from './modules/notification/Notification'; import store from './store'; -import * as itemActions from './actions/items'; +import pym from './PymConnection'; import I18n from './modules/i18n/i18n'; -import * as notificationActions from './actions/notification'; import * as authActions from './actions/auth'; import * as assetActions from './actions/asset'; -import pym from './PymConnection'; +import * as notificationActions from './actions/notification'; +import Notification from './modules/notification/Notification'; export { - Notification, - store, - itemActions, + pym, I18n, - notificationActions, + store, authActions, assetActions, - pym + Notification, + notificationActions }; diff --git a/client/coral-framework/reducers/asset.js b/client/coral-framework/reducers/asset.js index 495307aeb..f9d0a55e3 100644 --- a/client/coral-framework/reducers/asset.js +++ b/client/coral-framework/reducers/asset.js @@ -13,23 +13,12 @@ const initialState = Map({ export default function asset (state = initialState, action) { switch (action.type) { - case actions.FETCH_ASSET_SUCCESS : + case actions.FETCH_ASSET_SUCCESS: return state .merge(action.asset); - case actions.UPDATE_CONFIG: + case actions.UPDATE_ASSET_SETTINGS_SUCCESS: return state - .merge(action.config); - case actions.UPDATE_CONFIG_SUCCESS: - return state - .merge(action.config); - case actions.OPEN_COMMENTS: - return state - .set('status', 'open') - .set('closedAt', null); - case actions.CLOSE_COMMENTS: - return state - .set('status', 'closed') - .set('closedAt', Date.now()); + .setIn(['settings'], action.settings); default: return state; } diff --git a/client/coral-framework/reducers/index.js b/client/coral-framework/reducers/index.js index 8c1457bfe..720f15232 100644 --- a/client/coral-framework/reducers/index.js +++ b/client/coral-framework/reducers/index.js @@ -1,13 +1,11 @@ import auth from './auth'; import user from './user'; import asset from './asset'; -import items from './items'; import notification from './notification'; export default { auth, user, asset, - items, notification }; diff --git a/client/coral-framework/reducers/items.js b/client/coral-framework/reducers/items.js deleted file mode 100644 index 268557809..000000000 --- a/client/coral-framework/reducers/items.js +++ /dev/null @@ -1,30 +0,0 @@ -/* Items Reducer */ - -import {fromJS} from 'immutable'; -import * as actions from '../actions/items'; - -const initialState = fromJS({ - comments: {}, - users: {}, - assets: {}, - actions: {} -}); - -export default (state = initialState, action) => { - switch (action.type) { - case actions.ADD_ITEM: - return state.setIn([action.item_type, action.id], fromJS(action.item)); - case actions.UPDATE_ITEM: - return state.setIn([action.item_type, action.id, action.property], fromJS(action.value)); - case actions.APPEND_ITEM_ARRAY: - return state.updateIn([action.item_type, action.id, action.property], (prop) => { - if (action.add_to_front) { - return prop ? prop.unshift(fromJS(action.value)) : fromJS([action.value]); - } else { - return prop ? prop.push(fromJS(action.value)) : fromJS([action.value]); - } - }); - default: - return state; - } -}; diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index f368953a7..258681a08 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -13,6 +13,7 @@ class CommentBox extends Component { // comments: PropTypes.array, commentPostedHandler: PropTypes.func, postItem: PropTypes.func.isRequired, + cancelButtonClicked: PropTypes.func, assetId: PropTypes.string.isRequired, parentId: PropTypes.string, authorId: PropTypes.string.isRequired, @@ -89,7 +90,14 @@ class CommentBox extends Component { render () { const {styles, isReply, authorId, charCount} = this.props; + let {cancelButtonClicked} = this.props; const length = this.state.body.length; + + if (isReply && typeof cancelButtonClicked !== 'function') { + console.warn('the CommentBox component should have a cancelButtonClicked callback defined if it lives in a Reply'); + cancelButtonClicked = () => {}; + } + return
@@ -115,6 +123,19 @@ class CommentBox extends Component { }
+ { + isReply && ( + + ) + } { authorId && (