From 4e060b884b3243a22888c19a0a346837643bb4d5 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 21 Apr 2017 12:12:29 -0600 Subject: [PATCH 1/7] Fixed bug with status changes in the graph --- graph/mutators/comment.js | 4 ++-- services/comments.js | 31 +++++++++---------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index 982f7ade7..5cfc23794 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -180,9 +180,9 @@ const createPublicComment = (context, commentInput) => { * @param {String} status the new status of the comment */ -const setCommentStatus = ({loaders: {Comments}}, {id, status}) => { +const setCommentStatus = ({user, loaders: {Comments}}, {id, status}) => { return CommentsService - .setStatus(id, status) + .pushStatus(id, status, user ? user.id : null) .then((comment) => { // If the loaders are present, clear the caches for these values because we diff --git a/services/comments.js b/services/comments.js index 7e9cca20f..d77118705 100644 --- a/services/comments.js +++ b/services/comments.js @@ -213,7 +213,15 @@ module.exports = class CommentsService { * @return {Promise} */ static pushStatus(id, status, assigned_by = null) { - return CommentModel.update({id}, { + + // Check to see if the comment status is in the allowable set of statuses. + if (STATUSES.indexOf(status) === -1) { + + // Comment status is not supported! Error out here. + return Promise.reject(new Error(`status ${status} is not supported`)); + } + + return CommentModel.findOneAndUpdate({id}, { $push: { status_history: { type: status, @@ -292,25 +300,4 @@ module.exports = class CommentsService { return CommentModel.find(query); } - - /** - * Sets Comment Status - * @param {String} id identifier of the comment (uuid) - * @param {String} status the new status of the comment - * @return {Promise} - */ - - static setStatus(id, status) { - - // Check to see if the comment status is in the allowable set of statuses. - if (STATUSES.indexOf(status) === -1) { - - // Comment status is not supported! Error out here. - return Promise.reject(new Error(`status ${status} is not supported`)); - } - - return CommentModel.findOneAndUpdate({id}, { - $set: {status} - }); - } }; From d1ab279f7401c80e11a1f8dd84334ddd49ba128a Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 21 Apr 2017 13:26:32 -0600 Subject: [PATCH 2/7] add a little keyboard shortcut widget --- .../src/components/ModerationKeysModal.css | 44 +++++++++ .../src/components/ModerationKeysModal.js | 95 ++++++++++++++----- client/coral-admin/src/translations.json | 8 ++ 3 files changed, 122 insertions(+), 25 deletions(-) diff --git a/client/coral-admin/src/components/ModerationKeysModal.css b/client/coral-admin/src/components/ModerationKeysModal.css index a030b6efa..73697d930 100644 --- a/client/coral-admin/src/components/ModerationKeysModal.css +++ b/client/coral-admin/src/components/ModerationKeysModal.css @@ -18,3 +18,47 @@ border-radius: 4px; border: 1px solid #999; } + +.callToAction { + position: fixed; + left: 10px; + bottom: 10px; + width: 280px; + height: 200px; + background: white; + padding: 15px; + box-sizing: border-box; + box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.15); + + .ctaHeader { + font-size: 16px; + margin-bottom: 5px; + } + + ul { + padding-left: 0; + list-style: none; + margin: 0 0 10px 0; + } + + p, li { + font-size: 12px; + margin-bottom: 5px; + } + + li span:first-child, p:last-child span:first-child { + display: inline-block; + width: 120px; + } +} + +.closeButton { + float: right; + font-size: 20px; + cursor: pointer; +} + +.smallKey { + padding: 5px; + border: 1px solid #ccc; +} diff --git a/client/coral-admin/src/components/ModerationKeysModal.js b/client/coral-admin/src/components/ModerationKeysModal.js index 5a951e588..60933dee0 100644 --- a/client/coral-admin/src/components/ModerationKeysModal.js +++ b/client/coral-admin/src/components/ModerationKeysModal.js @@ -4,6 +4,8 @@ import React from 'react'; import Modal from 'components/Modal'; import styles from './ModerationKeysModal.css'; +const lang = new I18n(translations); + const shortcuts = [ { title: 'modqueue.navigation', @@ -23,29 +25,72 @@ const shortcuts = [ } ]; -export default ({open, onClose}) => ( - -

{lang.t('modqueue.shortcuts')}

-
- {shortcuts.map((shortcut, i) => ( - - - - - - - - {Object.keys(shortcut.shortcuts).map(key => ( - - - - - ))} - -
{lang.t(shortcut.title)}
{key}{lang.t(shortcut.shortcuts[key])}
- ))} -
-
-); +export default class ModerationKeysModal extends React.Component { + constructor (props) { + super(props); + try { + if (window.localStorage.getItem('coral:shortcutsNote') === null) { + window.localStorage.setItem('coral:shortcutsNote', 'show'); + } + } catch (e) { -const lang = new I18n(translations); + // above will fail in Private Mode in some browsers. + } + this.state = { + shortcutsNote: window.localStorage.getItem('coral:shortcutsNote') || 'show' + }; + } + + closeCallToAction = () => { + try { + window.localStorage.setItem('coral:shortcutsNote', 'hide'); + this.setState({foo: Math.random()}); // apparently this.forceUpdate() is bad, but we need a re-render + } catch (e) { + + // when setItem fails in Safari Private mode + this.setState({shortcutsNote: 'hide'}); + } + } + + render () { + const {open, onClose} = this.props; + const hideShortcutsNote = window.localStorage.getItem('coral:shortcutsNote') === 'hide' || + this.state.dashboardNote === 'hide'; // for Safari Incognito + return ( +
+
+
×
+

{lang.t('modqueue.mod-faster')}

+

{lang.t('modqueue.try-these')}:

+
    +
  • {lang.t('modqueue.approve')} t
  • +
  • {lang.t('modqueue.reject')} r
  • +
+

{lang.t('modqueue.view-more-shortcuts')} {lang.t('modqueue.shift-key')} + /

+
+ +

{lang.t('modqueue.shortcuts')}

+
+ {shortcuts.map((shortcut, i) => ( + + + + + + + + {Object.keys(shortcut.shortcuts).map(key => ( + + + + + ))} + +
{lang.t(shortcut.title)}
{key}{lang.t(shortcut.shortcuts[key])}
+ ))} +
+
+
+ ); + } +} diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index f317b71a7..9e167232e 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -44,6 +44,10 @@ "close": "Close", "actions": "Actions", "navigation": "Navigation", + "mod-faster": "Moderate faster with keyboard shortcuts", + "try-these": "Try these", + "view-more-shortcuts": "View more shortcuts", + "shift-key": "⇧", "approve": "Approve comment", "reject": "Reject comment", "nextcomment": "Go to the next comment", @@ -226,6 +230,10 @@ "rejected": "rechazado", "flagged": "marcado", "shortcuts": "Atajos de teclado", + "mod-faster": "Moderar más rápido con atajos del teclado", + "try-these": "Intenta estos", + "view-more-shortcuts": "Ver más atajos", + "shift-key": "⇧", "close": "Cerrar", "emptyqueue": "No se encontro ningún usuario. Están escondidos.", "showshortcuts": "Mostrar atajos", From c60cfebde73ec4f43bcadba4a7947e4686eeb7b9 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Mon, 24 Apr 2017 10:19:36 -0600 Subject: [PATCH 3/7] add some styles so mobile doesn't zoom the text box --- client/coral-embed-stream/style/default.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 13a200690..bf044172d 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -194,7 +194,8 @@ hr { padding: 5px; min-height: 100px; margin-top: 10px; - font-size: 14px; + font-size: 16px; + border: 1px solid #ccc; } .coral-plugin-commentbox-button-container { @@ -278,13 +279,13 @@ hr { .commentActionsRight, .replyActionsRight { display: flex; justify-content: flex-end; - width: 30%; + width: 50%; } .commentActionsLeft, .replyActionsLeft { display: flex; justify-content: flex-start; float: left; - width: 70%; + width: 50%; } .comment__action-container .material-icons { From ac2a636274b8cbf5741427f8390ff5fd439597f2 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 25 Apr 2017 01:04:26 +0700 Subject: [PATCH 4/7] Quickfix permalinks --- client/coral-embed-stream/src/Embed.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index c7c204288..51079097f 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -159,6 +159,10 @@ class Embed extends React.Component { const userBox = this.props.logout().then(refetch)} changeTab={this.changeTab}/>; + // TODO: This is a quickfix and will be replaced after our refactor. + const ignoredUsers = this.props.userData.ignoredUsers; + const commentIsIgnored = (comment) => ignoredUsers && ignoredUsers.includes(comment.user.id); + return (
@@ -242,6 +246,7 @@ class Embed extends React.Component { loadMore={this.props.loadMore} deleteAction={this.props.deleteAction} showSignInDialog={this.props.showSignInDialog} + commentIsIgnored={commentIsIgnored} key={highlightedComment.id} reactKey={highlightedComment.id} comment={highlightedComment} /> From b2428371c7799b7357578eebf826357537c2c5bb Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Mon, 24 Apr 2017 13:09:41 -0600 Subject: [PATCH 5/7] enable character counting on replies --- client/coral-embed-stream/src/Comment.js | 8 ++++++++ client/coral-embed-stream/src/Embed.js | 5 ++++- client/coral-embed-stream/src/Stream.js | 7 +++++++ client/coral-plugin-commentbox/CommentBox.js | 10 ++++++---- client/coral-plugin-replies/ReplyBox.js | 17 ++++++++++++++++- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index 674c03ec5..63b3ef8dc 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -64,6 +64,8 @@ class Comment extends React.Component { currentUser: PropTypes.shape({ id: PropTypes.string.isRequired }), + charCountEnable: PropTypes.bool.isRequired, + maxCharCount: PropTypes.number, comment: PropTypes.shape({ depth: PropTypes.number, action_summaries: PropTypes.array.isRequired, @@ -121,6 +123,8 @@ class Comment extends React.Component { ignoreUser, disableReply, commentIsIgnored, + maxCharCount, + charCountEnable, } = this.props; const likeSummary = getActionSummary('LikeActionSummary', comment); @@ -243,6 +247,8 @@ class Comment extends React.Component { commentPostedHandler={() => { setActiveReplyBox(''); }} + charCountEnable={charCountEnable} + maxCharCount={maxCharCount} setActiveReplyBox={setActiveReplyBox} parentId={parentId || comment.id} addNotification={addNotification} @@ -273,6 +279,8 @@ class Comment extends React.Component { addCommentTag={addCommentTag} removeCommentTag={removeCommentTag} ignoreUser={ignoreUser} + charCountEnable={charCountEnable} + maxCharCount={maxCharCount} showSignInDialog={showSignInDialog} reactKey={reply.id} key={reply.id} diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index 51079097f..fbe24c8c7 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -214,7 +214,8 @@ class Embed extends React.Component { isReply={false} currentUser={this.props.auth.user} authorId={user.id} - charCount={asset.settings.charCountEnable && asset.settings.charCount} /> + charCountEnable={asset.settings.charCountEnable} + maxCharCount={asset.settings.charCount} /> : null } @@ -278,6 +279,8 @@ class Embed extends React.Component { deleteAction={this.props.deleteAction} showSignInDialog={this.props.showSignInDialog} comments={asset.comments} + maxCharCount={asset.settings.charCount} + charCountEnable={asset.settings.charCountEnable} ignoredUsers={this.props.userData.ignoredUsers} />
ignoredUsers && ignoredUsers.includes(comment.user.id); return ( @@ -84,6 +89,8 @@ class Stream extends React.Component { key={comment.id} reactKey={comment.id} comment={comment} + maxCharCount={maxCharCount} + charCountEnable={charCountEnable} pluginProps={pluginProps} /> ) diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index 2a988711d..261c95414 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -121,11 +121,11 @@ class CommentBox extends Component { handleChange = e => this.setState({body: e.target.value}); render () { - const {styles, isReply, authorId, charCount} = this.props; + const {styles, isReply, authorId, maxCharCount} = this.props; let {cancelButtonClicked} = this.props; const length = this.state.body.length; - const enablePostComment = !length || (charCount && length > charCount); + const enablePostComment = !length || (maxCharCount && length > maxCharCount); if (isReply && typeof cancelButtonClicked !== 'function') { console.warn('the CommentBox component should have a cancelButtonClicked callback defined if it lives in a Reply'); @@ -150,8 +150,8 @@ class CommentBox extends Component { onChange={this.handleChange} rows={3}/>
-
charCount ? `${name}-char-max` : ''}`}> - {charCount && `${charCount - length} ${lang.t('characters-remaining')}`} +
maxCharCount ? `${name}-char-max` : ''}`}> + {maxCharCount && `${maxCharCount - length} ${lang.t('characters-remaining')}`}
Date: Mon, 24 Apr 2017 14:04:57 -0600 Subject: [PATCH 6/7] move the shortcuts note logic into redux state --- client/coral-admin/src/actions/moderation.js | 12 +++++++ .../src/components/ModerationKeysModal.js | 36 ++++--------------- .../coral-admin/src/constants/moderation.js | 1 + .../ModerationQueue/ModerationContainer.js | 5 ++- client/coral-admin/src/reducers/moderation.js | 6 +++- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/client/coral-admin/src/actions/moderation.js b/client/coral-admin/src/actions/moderation.js index 75ec5fc09..b7117181e 100644 --- a/client/coral-admin/src/actions/moderation.js +++ b/client/coral-admin/src/actions/moderation.js @@ -6,3 +6,15 @@ export const singleView = () => ({type: actions.SINGLE_VIEW}); // Ban User Dialog export const showBanUserDialog = (user, commentId, showRejectedNote) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId, showRejectedNote}); export const hideBanUserDialog = (showDialog) => ({type: actions.HIDE_BANUSER_DIALOG, showDialog}); + +// hide shortcuts note +export const hideShortcutsNote = () => { + try { + window.localStorage.setItem('coral:shortcutsNote', 'hide'); + } catch (e) { + + // above will fail in Safari private mode + } + + return {type: actions.HIDE_SHORTCUTS_NOTE}; +}; diff --git a/client/coral-admin/src/components/ModerationKeysModal.js b/client/coral-admin/src/components/ModerationKeysModal.js index 60933dee0..3d43c621d 100644 --- a/client/coral-admin/src/components/ModerationKeysModal.js +++ b/client/coral-admin/src/components/ModerationKeysModal.js @@ -1,6 +1,6 @@ import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations.json'; -import React from 'react'; +import React, {PropTypes} from 'react'; import Modal from 'components/Modal'; import styles from './ModerationKeysModal.css'; @@ -26,40 +26,18 @@ const shortcuts = [ ]; export default class ModerationKeysModal extends React.Component { - constructor (props) { - super(props); - try { - if (window.localStorage.getItem('coral:shortcutsNote') === null) { - window.localStorage.setItem('coral:shortcutsNote', 'show'); - } - } catch (e) { - // above will fail in Private Mode in some browsers. - } - this.state = { - shortcutsNote: window.localStorage.getItem('coral:shortcutsNote') || 'show' - }; - } - - closeCallToAction = () => { - try { - window.localStorage.setItem('coral:shortcutsNote', 'hide'); - this.setState({foo: Math.random()}); // apparently this.forceUpdate() is bad, but we need a re-render - } catch (e) { - - // when setItem fails in Safari Private mode - this.setState({shortcutsNote: 'hide'}); - } + static propTypes = { + hideShortcutsNote: PropTypes.func.isRequired, + shortcutsNoteVisible: PropTypes.string.isRequired } render () { - const {open, onClose} = this.props; - const hideShortcutsNote = window.localStorage.getItem('coral:shortcutsNote') === 'hide' || - this.state.dashboardNote === 'hide'; // for Safari Incognito + const {open, onClose, hideShortcutsNote, shortcutsNoteVisible} = this.props; return (
-
-
×
+
+
×

{lang.t('modqueue.mod-faster')}

{lang.t('modqueue.try-these')}:

    diff --git a/client/coral-admin/src/constants/moderation.js b/client/coral-admin/src/constants/moderation.js index f50cbb439..14672146e 100644 --- a/client/coral-admin/src/constants/moderation.js +++ b/client/coral-admin/src/constants/moderation.js @@ -2,3 +2,4 @@ export const TOGGLE_MODAL = 'TOGGLE_MODAL'; export const SINGLE_VIEW = 'SINGLE_VIEW'; export const SHOW_BANUSER_DIALOG = 'SHOW_BANUSER_DIALOG'; export const HIDE_BANUSER_DIALOG = 'HIDE_BANUSER_DIALOG'; +export const HIDE_SHORTCUTS_NOTE = 'HIDE_SHORTCUTS_NOTE'; diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index 3487f9fde..2c556f36f 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -10,7 +10,7 @@ import {banUser, setCommentStatus} from '../../graphql/mutations'; import {fetchSettings} from 'actions/settings'; import {updateAssets} from 'actions/assets'; -import {toggleModal, singleView, showBanUserDialog, hideBanUserDialog} from 'actions/moderation'; +import {toggleModal, singleView, showBanUserDialog, hideBanUserDialog, hideShortcutsNote} from 'actions/moderation'; import {Spinner} from 'coral-ui'; import BanUserDialog from '../../components/BanUserDialog'; @@ -183,6 +183,8 @@ class ModerationContainer extends Component { rejectComment={props.rejectComment} />
@@ -204,6 +206,7 @@ const mapDispatchToProps = dispatch => ({ fetchSettings: () => dispatch(fetchSettings()), showBanUserDialog: (user, commentId, showRejectedNote) => dispatch(showBanUserDialog(user, commentId, showRejectedNote)), hideBanUserDialog: () => dispatch(hideBanUserDialog(false)), + hideShortcutsNote: () => dispatch(hideShortcutsNote()), }); export default compose( diff --git a/client/coral-admin/src/reducers/moderation.js b/client/coral-admin/src/reducers/moderation.js index cf270543c..a40ac865f 100644 --- a/client/coral-admin/src/reducers/moderation.js +++ b/client/coral-admin/src/reducers/moderation.js @@ -6,7 +6,8 @@ const initialState = Map({ modalOpen: false, user: Map({}), commentId: null, - banDialog: false + banDialog: false, + shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show' }); export default function moderation (state = initialState, action) { @@ -31,6 +32,9 @@ export default function moderation (state = initialState, action) { case actions.SINGLE_VIEW: return state .set('singleView', !state.get('singleView')); + case actions.HIDE_SHORTCUTS_NOTE: + return state + .set('shortcutsNoteVisible', 'hide'); default : return state; } From 801ce13960a644e488b2c8141b510b139b151328 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Mon, 24 Apr 2017 14:19:01 -0600 Subject: [PATCH 7/7] my fix did not work. --- client/coral-embed-stream/style/default.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 32f30d800..087859e89 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -280,13 +280,13 @@ hr { .commentActionsRight, .replyActionsRight { display: flex; justify-content: flex-end; - width: 50%; + width: 30%; } .commentActionsLeft, .replyActionsLeft { display: flex; justify-content: flex-start; float: left; - width: 50%; + width: 70%; } .comment__action-container .material-icons {