Merge branch 'master' into recaptcha-support

This commit is contained in:
Riley Davis
2017-03-14 15:33:18 -06:00
committed by GitHub
15 changed files with 216 additions and 51 deletions
@@ -186,4 +186,5 @@
.actionButton {
transform: scale(.8);
margin: 0;
width: 140px;
}
@@ -0,0 +1,49 @@
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
const ActivityWidget = ({assets}) => {
return (
<div className={styles.widget}>
<h2 className={styles.heading}>Articles with the most conversations</h2>
<div className={styles.widgetHead}>
<p>{lang.t('streams.article')}</p>
<p>{lang.t('dashboard.comment_count')}</p>
</div>
<div className={styles.widgetTable}>
{
assets.length
? assets.map(asset => {
return (
<div className={styles.rowLinkify} key={asset.id}>
<Link className={styles.linkToModerate} to={`/admin/moderate/flagged/${asset.id}`}>Moderate</Link>
<p className={styles.widgetCount}>{asset.commentCount}</p>
<Link className={styles.linkToAsset} to={`${asset.url}#coralStreamEmbed_iframe`} target="_blank">
<p className={styles.assetTitle}>{asset.title}</p>
</Link>
<p className={styles.lede}>{asset.author} Published: {new Date(asset.created_at).toLocaleDateString()}</p>
</div>
);
})
: <div className={styles.rowLinkify}>{lang.t('dashboard.no_activity')}</div>
}
</div>
</div>
);
};
ActivityWidget.propTypes = {
assets: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
url: PropTypes.string,
commentCount: PropTypes.number,
author: PropTypes.string,
created_at: PropTypes.string
})).isRequired
};
export default ActivityWidget;
@@ -4,7 +4,7 @@ import {compose} from 'react-apollo';
import {connect} from 'react-redux';
import {getMetrics} from 'coral-admin/src/graphql/queries';
import FlagWidget from './FlagWidget';
import LikeWidget from './LikeWidget';
import ActivityWidget from './ActivityWidget';
import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
@@ -15,9 +15,22 @@ const refreshIntervalSeconds = 60 * 5;
class Dashboard extends React.Component {
state = {
noteHidden: false,
secondsUntilRefresh: refreshIntervalSeconds
constructor (props) {
super(props);
try {
if (window.localStorage.getItem('coral:dashboardNote') === null) {
window.localStorage.setItem('coral:dashboardNote', 'show');
}
} catch (e) {
// above will fail in Private Mode in some browsers.
}
this.state = {
secondsUntilRefresh: refreshIntervalSeconds,
dashboardNote: window.localStorage.getItem('coral:dashboardNote') || 'show'
};
}
componentWillMount () {
@@ -31,6 +44,16 @@ class Dashboard extends React.Component {
}, 1000);
}
dismissNote = () => {
try {
window.localStorage.setItem('coral:dashboardNote', 'hide');
} catch (e) {
// when setItem fails in Safari Private mode
this.setState({dashboardNote: 'hide'});
}
}
formatTime = () => {
const minutes = Math.floor(this.state.secondsUntilRefresh / 60);
let seconds = (this.state.secondsUntilRefresh % 60).toString();
@@ -47,20 +70,22 @@ class Dashboard extends React.Component {
return <Spinner />;
}
const {data: {assetsByLike, assetsByFlag}} = this.props;
const {data: {assetsByActivity, assetsByFlag}} = this.props;
const hideReloadNote = window.localStorage.getItem('coral:dashboardNote') === 'hide' ||
this.state.dashboardNote === 'hide'; // for Safari Incognito
return (
<div>
<p
style={{display: this.state.noteHidden ? 'none' : 'block'}}
style={{display: hideReloadNote ? 'none' : 'block'}}
className={styles.autoUpdate}
onClick={() => this.setState({noteHidden: true})}>
onClick={this.dismissNote}>
<b>×</b>
<Icon name='timer' /> <strong>{lang.t('dashboard.next-update', this.formatTime())}</strong> {lang.t('dashboard.auto-update')}
</p>
<div className={styles.Dashboard}>
<FlagWidget assets={assetsByFlag} />
<LikeWidget assets={assetsByLike} />
<ActivityWidget assets={assetsByActivity} />
</div>
</div>
);
@@ -1,4 +1,4 @@
import React from 'react';
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
@@ -6,8 +6,7 @@ import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
const FlagWidget = (props) => {
const {assets} = props;
const FlagWidget = ({assets}) => {
return (
<div className={styles.widget}>
@@ -39,4 +38,14 @@ const FlagWidget = (props) => {
);
};
FlagWidget.propTypes = {
assets: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
url: PropTypes.string,
action_summaries: PropTypes.array,
author: PropTypes.string,
created_at: PropTypes.string
})).isRequired
};
export default FlagWidget;
@@ -1,4 +1,4 @@
import React from 'react';
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
@@ -6,9 +6,7 @@ import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
const LikeWidget = (props) => {
const {assets} = props;
const LikeWidget = ({assets}) => {
return (
<div className={styles.widget}>
@@ -40,4 +38,14 @@ const LikeWidget = (props) => {
);
};
LikeWidget.propTypes = {
assets: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
url: PropTypes.string,
action_summaries: PropTypes.array,
author: PropTypes.string,
created_at: PropTypes.string
})).isRequired
};
export default LikeWidget;
@@ -19,7 +19,6 @@
padding-left: 10px;
font-size: 1.5rem;
font-weight: bold;
background-color: #e0e0e0;
}
.widgetTable {
@@ -4,6 +4,7 @@ fragment metrics on Asset {
url
author
created_at
commentCount
action_summaries {
type: __typename
actionCount
@@ -7,4 +7,7 @@ query Metrics ($from: Date!, $to: Date!) {
assetsByLike: assetMetrics(from: $from, to: $to, sort: LIKE) {
...metrics
}
assetsByActivity: assetMetrics(from: $from, to: $to, sort: ACTIVITY) {
...metrics
}
}
+2
View File
@@ -123,6 +123,7 @@
"no_flags": "There have been no flags in the last 5 minutes! Hooray!",
"no_likes": "There have been no likes in the last 5 minutes. All quiet.",
"flags": "Flags",
"no_activity": "There haven't been any comments anywhere in the last five minutes.",
"comment_count": "comments"
},
"streams": {
@@ -244,6 +245,7 @@
"no_flags": "¡Nadie ha marcado nada en los últimos 5 minutos! ¡Bravo!",
"no_likes": "A nadie le ha gustado algún comentario en los últimos 5 minutos. Todo tranquilo.",
"flags": "Marcados",
"no_activity": "No hubo comentarios en los ultimos 5 minutos",
"comment_count": "comentarios"
},
"streams": {
+25 -25
View File
@@ -157,31 +157,31 @@ class Comment extends React.Component {
<PubDate created_at={comment.created_at} />
<Content body={comment.body} />
<div className="commentActionsLeft comment__action-container">
<ActionButton>
<LikeButton
like={like}
id={comment.id}
postLike={postLike}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
currentUser={currentUser} />
</ActionButton>
<ActionButton>
<ReplyButton
onClick={() => setActiveReplyBox(comment.id)}
parentCommentId={parentId || comment.id}
currentUserId={currentUser && currentUser.id}
banned={false} />
</ActionButton>
<ActionButton>
<IfUserCanModifyBest user={currentUser}>
<BestButton
isBest={commentIsBest(comment)}
addBest={addBestTag}
removeBest={removeBestTag} />
</IfUserCanModifyBest>
</ActionButton>
</div>
<ActionButton>
<LikeButton
like={like}
id={comment.id}
postLike={postLike}
deleteAction={deleteAction}
showSignInDialog={showSignInDialog}
currentUser={currentUser} />
</ActionButton>
<ActionButton>
<ReplyButton
onClick={() => setActiveReplyBox(comment.id)}
parentCommentId={parentId || comment.id}
currentUserId={currentUser && currentUser.id}
banned={false} />
</ActionButton>
<ActionButton>
<IfUserCanModifyBest user={currentUser}>
<BestButton
isBest={commentIsBest(comment)}
addBest={addBestTag}
removeBest={removeBestTag} />
</IfUserCanModifyBest>
</ActionButton>
</div>
<div className="commentActionsRight comment__action-container">
<ActionButton>
<PermalinkButton articleURL={asset.url} commentId={comment.id} />
+3 -3
View File
@@ -5,9 +5,9 @@
"successNameUpdate": "Your username has been updated",
"contentNotAvailable": "This content is not available",
"loadMore": "View more",
"bannedAccountMsg": "Your account is currently suspended. This means that you cannot Like, Flag, or write comments. Please contact moderator@fakeurl.com for more information",
"bannedAccountMsg": "Your account is currently suspended. This means that you cannot Like, Report, or write comments. Please contact us if you have any questions.",
"editName": {
"msg": "Your account is currently suspended because your username has been deemed inappropriate. To restore your account, please enter a new username. You may contact moderator@fakeurl.com for more information.",
"msg": "Your account is currently suspended because your username has been deemed inappropriate. To restore your account, please enter a new username. Please contact us if you have any questions.",
"label": "New Username",
"button": "Submit",
"error": "Usernames can contain letters, numbers and _ only"
@@ -41,7 +41,7 @@
"successUpdateSettings": "La configuración de este articulo fue actualizada",
"successBioUpdate": "Tu bio fue actualizada",
"contentNotAvailable": "El contenido no se encuentra disponible",
"bannedAccountMsg": "Tu cuenta se encuentra suspendida. Esto significa que no puedes dar Like, Marcar o escribir commentarios. Por favor, contacta moderator@fakeurl for more information",
"bannedAccountMsg": "Tu cuenta se encuentra suspendida. Esto significa que no puedes dar Like, Marcar o escribir commentarios.",
"editNameMsg": "",
"loadMore": "Ver más",
"newCount": "Ver {0} {1} más",
+4 -4
View File
@@ -7,8 +7,8 @@
"step-1-header": "Report an issue",
"step-2-header": "Help us understand",
"step-3-header": "Thank you for your input",
"flag-username": "Flag username",
"flag-comment": "Flag comment",
"flag-username": "Report username",
"flag-comment": "Report comment",
"continue": "Continue",
"done": "Done",
"no-agree-comment": "I don't agree with this comment",
@@ -20,8 +20,8 @@
"no-like-bio": "I don't like this bio",
"marketing": "This looks like an ad/marketing",
"user-impersonating": "This user is impersonating",
"thank-you": "We value your safety and feedback. A moderator will review your flag.",
"flag-reason": "Reason for flag (Optional)",
"thank-you": "We value your safety and feedback. A moderator will review your report.",
"flag-reason": "Reason for reporting (Optional)",
"other": "Other"
},
"es": {