fix(coral-admin): Adapt to the new schema. Most things are not working yet but at least it bundles

This commit is contained in:
Dan Zajdband
2016-11-07 11:57:34 -05:00
parent 42c9f60586
commit 53af608419
11 changed files with 47 additions and 88 deletions
+2 -4
View File
@@ -4,14 +4,13 @@
"description": "",
"main": "index.js",
"scripts": {
"build": "./node_modules/.bin/webpack --config webpack.config.js",
"build": "./node_modules/.bin/webpack --config webpack.config.js --watch",
"start": "./node_modules/.bin/webpack-dev-server --config webpack.config.dev.js --inline --hot --content-base public --port 3142"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"coral-framework": "0.0.1",
"hammerjs": "2.0.8",
"immutable": "3.8.1",
"keymaster": "1.6.2",
@@ -23,8 +22,7 @@
"react-router": "^3.0.0",
"redux": "3.6.0",
"redux-thunk": "2.1.0",
"timeago.js": "2.0.2",
"xenia-driver": "0.0.4"
"timeago.js": "2.0.2"
},
"devDependencies": {
"autoprefixer": "6.5.0",
+1 -1
View File
@@ -17,6 +17,6 @@
</head>
<body>
<div id="root"></div>
<script src="http://localhost:3142/bundle.js" charset="utf-8"></script>
<script src="undefined/bundle.js" charset="utf-8"></script>
</body>
</html>
-12
View File
@@ -1,12 +0,0 @@
{
"short_name": "Talk",
"name": "Talk",
"icons": [
{
"src": "https://coralproject.net/images/icon-coral-white.svg",
"sizes": "150x150"
}
],
"start_url": "./",
"display": "standalone"
}
+6 -5
View File
@@ -1,7 +1,7 @@
import React from 'react'
import { Provider } from 'react-redux'
import { Layout, Content } from 'react-mdl'
import { Layout } from 'react-mdl'
import 'material-design-lite'
import { Router, Route, browserHistory } from 'react-router'
import ModerationQueue from 'containers/ModerationQueue'
@@ -10,6 +10,7 @@ import store from 'services/store'
import CommentStream from 'containers/CommentStream'
import EmbedLink from 'components/EmbedLink'
import Configure from 'containers/Configure'
import config from 'services/config'
export default class App extends React.Component {
render (props) {
@@ -19,10 +20,10 @@ export default class App extends React.Component {
<Header>
<div>
<Router history={browserHistory}>
<Route path='/' component={ModerationQueue} />
<Route path='embed' component={CommentStream} />
<Route path='embedlink' compoent={EmbedLink} />
<Route path='configure' component={Configure} />
<Route path={config.base} component={ModerationQueue} />
<Route path={`${config.base}/embed`} component={CommentStream} />
<Route path={`${config.base}/embedlink`} component={EmbedLink} />
<Route path={`${config.base}/configure`} component={Configure} />
</Router>
</div>
</Header>
+9 -8
View File
@@ -12,14 +12,14 @@ export default props => (
<div className={styles.itemHeader}>
<div className={styles.author}>
<i className={`material-icons ${styles.avatar}`}>person</i>
<span>{props.comment.get('data').get('name') || lang.t('comment.anon')}</span>
<span className={styles.created}>{timeago().format(props.comment.get('data').get('createdAt') || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}</span>
{props.comment.get('data').get('flagged') ? <p className={styles.flagged}>{lang.t('comment.flagged')}</p> : null}
<span>{props.comment.get('name') || lang.t('comment.anon')}</span>
<span className={styles.created}>{timeago().format(props.comment.get('createdAt') || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}</span>
{props.comment.get('flagged') ? <p className={styles.flagged}>{lang.t('comment.flagged')}</p> : null}
</div>
<div className={styles.actions}>
{props.actions.map(action => canShowAction(action, props.comment) ? (
<Button className={styles.actionButton}
onClick={() => props.onClickAction(props.actionsMap[action].status, props.comment.get('item_id'))}
onClick={() => props.onClickAction(props.actionsMap[action].status, props.comment.get('_id'))}
fab colored>
<Icon name={props.actionsMap[action].icon} />
</Button>
@@ -27,16 +27,17 @@ export default props => (
</div>
</div>
<div className={styles.itemBody}>
<span className={styles.body}>{props.comment.get('data').get('body')}</span>
<span className={styles.body}>{props.comment.get('body')}</span>
</div>
</li>
)
// Check if an action can be performed over a comment
const canShowAction = (action, comment) => {
const status = comment.get('data').get('status')
const flagged = comment.get('data').get('flagged')
if (action === 'flag' && (status !== 'Untouched' || flagged === true)) {
const status = comment.get('status')
const flagged = comment.get('flagged')
if (action === 'flag' && (status || flagged === true)) {
return false
}
return true
@@ -112,8 +112,9 @@ export default class CommentList extends React.Component {
}
render () {
const {singleView, actions, commentIds, comments, hideActive} = this.props
const {singleView, commentIds, comments, hideActive} = this.props
const {active} = this.state
return (
<ul className={`${styles.list} ${singleView ? styles.singleView : ''}`}>
{commentIds.map((commentId, index) => (
@@ -122,7 +123,7 @@ export default class CommentList extends React.Component {
key={index}
index={index}
onClickAction={this.onClickAction}
actions={actions}
actions={this.props.actions}
actionsMap={actions}
isActive={commentId === active}
hideActive={hideActive} />
+6 -4
View File
@@ -1,20 +1,22 @@
import React from 'react'
import { Layout, Navigation, Drawer, Header } from 'react-mdl'
import { Link } from 'react-router'
import styles from './Header.css'
import config from 'services/config'
// App header. If we add a navbar it should be here
export default (props) => (
<Layout fixedDrawer>
<Header title='Talk'>
<Navigation>
<a className={styles.navLink} href='/'>Moderate</a>
<a className={styles.navLink} href='/configure'>Configure</a>
<Link className={styles.navLink} href={`/${config.base}/`}>Moderate</Link>
<Link className={styles.navLink} href={`/${config.base}/configure`}>Configure</Link>
</Navigation>
</Header>
<Drawer>
<Navigation>
<a className={styles.navLink} href='/'>Moderate</a>
<a className={styles.navLink} href='/configure'>Configure</a>
<Link className={styles.navLink} href={`/${config.base}/`}>Moderate</Link>
<Link className={styles.navLink} href={`/${config.base}/configure`}>Configure</Link>
</Navigation>
</Drawer>
{props.children}
@@ -74,7 +74,7 @@ class ModerationQueue extends React.Component {
<CommentList
isActive={activeTab === 'pending'}
singleView={singleView}
commentIds={comments.get('ids').filter(id => comments.get('byId').get(id).get('data').get('status') === 'Untouched')}
commentIds={comments.get('ids').filter(id => !comments.get('byId').get(id).get('status'))}
comments={comments.get('byId')}
onClickAction={(action, id) => this.onCommentAction(action, id)}
actions={['reject', 'approve']}
@@ -84,7 +84,7 @@ class ModerationQueue extends React.Component {
<CommentList
isActive={activeTab === 'rejected'}
singleView={singleView}
commentIds={comments.get('ids').filter(id => comments.get('byId').get(id).get('data').get('status') === 'Rejected')}
commentIds={comments.get('ids').filter(id => comments.get('byId').get(id).get('status') === 'rejected')}
comments={comments.get('byId')}
onClickAction={(action, id) => this.onCommentAction(action, id)}
actions={['approve']}
@@ -95,8 +95,8 @@ class ModerationQueue extends React.Component {
isActive={activeTab === 'rejected'}
singleView={singleView}
commentIds={comments.get('ids').filter(id => {
const data = comments.get('byId').get(id).get('data')
return data.get('status') === 'Untouched' && data.get('flagged') === true
const data = comments.get('byId').get(id)
return !data.get('status') && data.get('flagged') === true
})}
comments={comments.get('byId')}
onClickAction={(action, id) => this.onCommentAction(action, id)}
+1 -1
View File
@@ -46,7 +46,7 @@ const flag = (state, action) => {
// Replace the comment list with a new one
const replaceComments = (action, state) => {
const comments = fromJS(action.comments.reduce((prev, curr) => { prev[curr.item_id] = curr; return prev }, {}))
const comments = fromJS(action.comments.reduce((prev, curr) => { prev[curr._id] = curr; return prev }, {}))
return state.set('byId', comments).set('loading', false)
.set('ids', List(comments.keys()))
}
+13 -46
View File
@@ -7,9 +7,6 @@
* for the coral but also for wordpress comments, disqus and many more.
*/
import { talkHost, xeniaHost } from 'services/config'
import XeniaDriver from 'xenia-driver'
// Intercept redux actions and act over the ones we are interested
export default store => next => action => {
switch (action.type) {
@@ -30,64 +27,34 @@ export default store => next => action => {
next(action)
}
// Setup xenia driver
const xenia = XeniaDriver(`${xeniaHost}/v1`, {username: 'user', password: 'pass'})
// Get comments to fill each of the three lists on the mod queue
const fetchModerationQueueComments = store => xenia()
.collection('items')
.match({type: 'comment', 'data.status': 'Untouched', 'data.createdAt': { $exists: true }})
.sort(['data.createdAt', 1])
.skip(0).limit(50)
.addQuery().collection('items')
.match({type: 'comment', 'data.status': 'Rejected', 'data.createdAt': { $exists: true }})
.sort(['data.createdAt', 1])
.skip(0).limit(50)
.addQuery().collection('items')
.match({type: 'comment', 'data.status': 'Untouched', 'data.flagged': true, 'data.createdAt': { $exists: true }})
.sort(['data.createdAt', 1])
.skip(0).limit(50)
.exec()
const fetchModerationQueueComments = store =>
fetch(`/api/v1/queue`)
.then(res => res.json())
.then(res => store.dispatch({ type: 'COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS',
comments: res.results.map(res => res.Docs).reduce((p, c) => p.concat(c), []) }))
comments: res }))
.catch(error => store.dispatch({ type: 'COMMENTS_MODERATION_QUEUE_FETCH_FAILED', error }))
// Update a comment. Now to update a comment we need to send back the whole object
const updateComment = (store, comment) =>
fetch(`${talkHost}/v1/item`, {
method: 'PUT',
mode: 'cors',
body: JSON.stringify(comment)
fetch(`/api/v1/comments/${comment._id}/status`, {
method: 'POST',
body: JSON.stringify({ status: comment.status })
})
.then(res => res.json())
.then(res => store.dispatch({ type: 'COMMENT_UPDATE_SUCCESS', res }))
.catch(error => store.dispatch({ type: 'COMMENT_UPDATE_FAILED', error }))
// Create a new comment
const createComment = (store, name, comment) =>
fetch(`${talkHost}/v1/item`, {
fetch(`/api/v1/comments`, {
method: 'POST',
mode: 'cors',
body: JSON.stringify({
type: 'comment',
version: 1,
data: {
status: 'Untouched',
body: comment,
name: name,
createdAt: Date.now()
}
status: 'Untouched',
body: comment,
name: name,
createdAt: Date.now()
})
}).then(res => res.json())
.then(res => store.dispatch({ type: 'COMMENT_CREATE_SUCCESS', comment: res }))
.catch(error => store.dispatch({ type: 'COMMENT_CREATE_FAILED', error }))
// Get a comment stream. Now we don't have the concept of assets, this should
// be adapted to retrieve the current asset when the backend supports it
const fetchCommentStream = store => xenia()
.collection('items')
.match({type: 'comment', 'data.status': { $ne: 'Rejected' }, 'data.createdAt': { $exists: true }})
.sort(['data.createdAt', 1])
.skip(0).limit(100)
.exec()
.then(res => store.dispatch({ type: 'COMMENT_STREAM_FETCH_SUCCESS', comments: res.results[0].Docs }))
.catch(error => store.dispatch({ type: 'COMMENT_STREAM_FETCH_FAILED', error }))
+2 -1
View File
@@ -20,7 +20,7 @@ module.exports = {
'bundle': path.join(__dirname, 'src', 'index')
},
output: {
path: path.join(__dirname, 'public'),
path: path.join(__dirname, '..', '..', 'dist', 'coral-admin'),
filename: '[name].js'
},
module: {
@@ -41,6 +41,7 @@ module.exports = {
resolve: {
modules: [
path.resolve('./src'),
path.resolve('../'),
'node_modules'
]
},