From cf0551d3e7ab92b4ba687423fed2eeae40fd7b7f Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 27 Mar 2018 14:10:53 -0600 Subject: [PATCH 01/16] Docs cleanup - Removed references to Facebook being a default plugin --- docs/source/01-01-talk-quickstart.md | 6 +----- docs/source/01-03-installation-from-source.md | 5 +---- docs/source/03-02-product-guide-commenter-features.md | 4 ++-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/docs/source/01-01-talk-quickstart.md b/docs/source/01-01-talk-quickstart.md index c18aea638..7e2adb2fe 100644 --- a/docs/source/01-01-talk-quickstart.md +++ b/docs/source/01-01-talk-quickstart.md @@ -167,14 +167,10 @@ TALK_REDIS_URL=redis://127.0.0.1:6379 TALK_ROOT_URL=http://127.0.0.1:3000 TALK_PORT=3000 TALK_JWT_SECRET=password -TALK_FACEBOOK_APP_ID=A-Facebook-App-ID -TALK_FACEBOOK_APP_SECRET=A-Facebook-App-Secret ``` This is only the bare minimum needed to run the demo, for more configuration -variables, check out the [Configuration](/talk/configuration/) section. Facebook login above -will definitely not work unless you change those values as well. - +variables, check out the [Configuration](/talk/configuration/) section. You can now start the application by running: diff --git a/docs/source/01-03-installation-from-source.md b/docs/source/01-03-installation-from-source.md index a460751f7..9f4b96d93 100644 --- a/docs/source/01-03-installation-from-source.md +++ b/docs/source/01-03-installation-from-source.md @@ -57,14 +57,11 @@ TALK_REDIS_URL=redis://127.0.0.1:6379 TALK_ROOT_URL=http://127.0.0.1:3000 TALK_PORT=3000 TALK_JWT_SECRET=password -TALK_FACEBOOK_APP_ID=A-Facebook-App-ID -TALK_FACEBOOK_APP_SECRET=A-Facebook-App-Secret ``` This is the bare minimum needed to start Talk, for more configuration variables, check out the [Configuration](/talk/configuration/) -section. Facebook login above will definitely not work unless you change those -values as well. +section. You can now start the application by running: diff --git a/docs/source/03-02-product-guide-commenter-features.md b/docs/source/03-02-product-guide-commenter-features.md index 390fdce50..3d60eeda9 100644 --- a/docs/source/03-02-product-guide-commenter-features.md +++ b/docs/source/03-02-product-guide-commenter-features.md @@ -24,7 +24,7 @@ All levels of comments and replies are able to be linked to via permalink. Perma ```text https://?commentId= ``` -{:.no-copy} + ### Threading @@ -44,7 +44,7 @@ talk-stream-comment-level-${depth} talk-stream-highlighted-comment talk-stream-pending-comment ``` -{:.no-copy} + ### Automatic Updates From 06b64ad2509128cf7d1d99fe560227408b200d4e Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 30 Mar 2018 10:55:15 -0300 Subject: [PATCH 02/16] routes --- client/coral-admin/src/AppRouter.js | 15 ++++++++++-- .../routes/Configure/components/Configure.js | 24 ++----------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index 9d68d592b..92cc80d1d 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -2,10 +2,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Router, Route, IndexRedirect, IndexRoute } from 'react-router'; -import Configure from 'routes/Configure'; import Install from 'routes/Install'; import Stories from 'routes/Stories'; import Community from 'routes/Community'; + +import Configure from 'routes/Configure'; +import StreamSettings from './routes/Configure/containers/StreamSettings'; +import ModerationSettings from './routes/Configure/containers/ModerationSettings'; +import TechSettings from './routes/Configure/containers/TechSettings'; + import { ModerationLayout, Moderation } from 'routes/Moderation'; import Layout from 'containers/Layout'; @@ -15,7 +20,13 @@ const routes = ( - + + + + + + + {/* Community Routes */} diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index efd428378..a988bcec5 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -2,26 +2,11 @@ import React, { Component } from 'react'; import { Button, List, Item } from 'coral-ui'; import styles from './Configure.css'; -import StreamSettings from '../containers/StreamSettings'; -import ModerationSettings from '../containers/ModerationSettings'; -import TechSettings from '../containers/TechSettings'; import t from 'coral-framework/services/i18n'; import { can } from 'coral-framework/services/perms'; import PropTypes from 'prop-types'; export default class Configure extends Component { - getSectionComponent(section) { - switch (section) { - case 'stream': - return StreamSettings; - case 'moderation': - return ModerationSettings; - case 'tech': - return TechSettings; - } - throw new Error(`Unknown section ${section}`); - } - render() { const { currentUser, @@ -30,7 +15,6 @@ export default class Configure extends Component { setActiveSection, activeSection, } = this.props; - const SectionComponent = this.getSectionComponent(activeSection); if (!can(currentUser, 'UPDATE_CONFIG')) { return ( @@ -73,12 +57,7 @@ export default class Configure extends Component { )} -
- -
+
{this.props.children}
); } @@ -92,4 +71,5 @@ Configure.propTypes = { canSave: PropTypes.bool.isRequired, setActiveSection: PropTypes.func.isRequired, activeSection: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, }; From 6982509233e52c14057fb12ecfc45c05d35a9cb9 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 30 Mar 2018 12:00:50 -0300 Subject: [PATCH 03/16] router and state lifted --- client/coral-admin/src/AppRouter.js | 1 + client/coral-admin/src/actions/configure.js | 8 +++ client/coral-admin/src/constants/configure.js | 3 ++ client/coral-admin/src/reducers/configure.js | 15 ++++++ .../routes/Configure/components/Configure.js | 49 +++++++++++++------ .../routes/Configure/containers/Configure.js | 42 +++++++++++++--- 6 files changed, 94 insertions(+), 24 deletions(-) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index 92cc80d1d..28255aeb5 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -25,6 +25,7 @@ const routes = ( + diff --git a/client/coral-admin/src/actions/configure.js b/client/coral-admin/src/actions/configure.js index acc30be1b..0f82832e0 100644 --- a/client/coral-admin/src/actions/configure.js +++ b/client/coral-admin/src/actions/configure.js @@ -11,3 +11,11 @@ export const clearPending = () => { export const setActiveSection = section => { return { type: actions.SET_ACTIVE_SECTION, section }; }; + +export const showSaveDialog = () => { + return { type: actions.SHOW_SAVE_DIALOG }; +}; + +export const hideSaveDialog = () => { + return { type: actions.HIDE_SAVE_DIALOG }; +}; diff --git a/client/coral-admin/src/constants/configure.js b/client/coral-admin/src/constants/configure.js index 05673b5aa..ed5f74578 100644 --- a/client/coral-admin/src/constants/configure.js +++ b/client/coral-admin/src/constants/configure.js @@ -3,3 +3,6 @@ const prefix = 'TALK_ADMIN_CONFIGURE'; export const UPDATE_PENDING = `${prefix}_UPDATE_PENDING`; export const CLEAR_PENDING = `${prefix}_CLEAR_PENDING`; export const SET_ACTIVE_SECTION = `${prefix}_SET_ACTIVE_SECTION`; + +export const SHOW_SAVE_DIALOG = `${prefix}_SHOW_SAVE_DIALOG`; +export const HIDE_SAVE_DIALOG = `${prefix}_HIDE_SAVE_DIALOG`; diff --git a/client/coral-admin/src/reducers/configure.js b/client/coral-admin/src/reducers/configure.js index 9809b0fa9..335cc4ce0 100644 --- a/client/coral-admin/src/reducers/configure.js +++ b/client/coral-admin/src/reducers/configure.js @@ -7,10 +7,23 @@ const initialState = { pending: {}, errors: {}, activeSection: 'stream', + saveDialog: false, }; export default function configure(state = initialState, action) { switch (action.type) { + case actions.SHOW_SAVE_DIALOG: { + return { + ...state, + saveDialog: true, + }; + } + case actions.HIDE_SAVE_DIALOG: { + return { + ...state, + saveDialog: false, + }; + } case actions.UPDATE_PENDING: { let next = state; if (action.updater) { @@ -45,6 +58,8 @@ export default function configure(state = initialState, action) { ...state, activeSection: action.section, }; + default: + return state; } return state; } diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index a988bcec5..4d9f0ff34 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -1,20 +1,14 @@ -import React, { Component } from 'react'; - -import { Button, List, Item } from 'coral-ui'; -import styles from './Configure.css'; -import t from 'coral-framework/services/i18n'; -import { can } from 'coral-framework/services/perms'; +import React from 'react'; import PropTypes from 'prop-types'; +import cn from 'classnames'; +import t from 'coral-framework/services/i18n'; +import { Button, List, Item, Dialog } from 'coral-ui'; +import { can } from 'coral-framework/services/perms'; +import styles from './Configure.css'; -export default class Configure extends Component { +class Configure extends React.Component { render() { - const { - currentUser, - canSave, - savePending, - setActiveSection, - activeSection, - } = this.props; + const { canSave, currentUser, root, savePending, settings } = this.props; if (!can(currentUser, 'UPDATE_CONFIG')) { return ( @@ -25,10 +19,27 @@ export default class Configure extends Component { ); } + const passProps = { + root, + settings, + }; + return (
+ + Are you sure? +
- + {t('configure.stream_settings')} @@ -57,7 +68,9 @@ export default class Configure extends Component { )}
-
{this.props.children}
+
+ {React.cloneElement(this.props.children, passProps)} +
); } @@ -72,4 +85,8 @@ Configure.propTypes = { setActiveSection: PropTypes.func.isRequired, activeSection: PropTypes.string.isRequired, children: PropTypes.node.isRequired, + saveDialog: PropTypes.bool, + hideSaveDialog: PropTypes.func.isRequired, }; + +export default Configure; diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index ce6ea0627..21f4b98e2 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; @@ -10,15 +10,28 @@ import { getDefinitionName } from 'coral-framework/utils'; import StreamSettings from './StreamSettings'; import TechSettings from './TechSettings'; import ModerationSettings from './ModerationSettings'; -import { clearPending, setActiveSection } from '../../../actions/configure'; +import { + clearPending, + setActiveSection, + showSaveDialog, + hideSaveDialog, +} from '../../../actions/configure'; import Configure from '../components/Configure'; +import { withRouter } from 'react-router'; -class ConfigureContainer extends Component { +class ConfigureContainer extends React.Component { savePending = async () => { await this.props.updateSettings(this.props.pending); this.props.clearPending(); }; + setActiveSection = section => { + // Check if pending + console.log('pending', this.props.pending); + this.props.setActiveSection(section); + this.props.router.push(`/admin/configure/${section}`); + }; + render() { if (this.props.data.error) { return
{this.props.data.error.message}
; @@ -30,14 +43,18 @@ class ConfigureContainer extends Component { return ( + > + {this.props.children} + ); } } @@ -74,6 +91,7 @@ const mapStateToProps = state => ({ pending: state.configure.pending, canSave: state.configure.canSave, activeSection: state.configure.activeSection, + saveDialog: state.configure.saveDialog, }); const mapDispatchToProps = dispatch => @@ -81,11 +99,14 @@ const mapDispatchToProps = dispatch => { clearPending, setActiveSection, + showSaveDialog, + hideSaveDialog, }, dispatch ); export default compose( + withRouter, connect(mapStateToProps, mapDispatchToProps), withUpdateSettings, withConfigureQuery, @@ -93,14 +114,19 @@ export default compose( )(ConfigureContainer); ConfigureContainer.propTypes = { + activeSection: PropTypes.string, updateSettings: PropTypes.func.isRequired, clearPending: PropTypes.func.isRequired, setActiveSection: PropTypes.func.isRequired, + showSaveDialog: PropTypes.func.isRequired, + hideSaveDialog: PropTypes.func.isRequired, + saveDialog: PropTypes.bool.isRequired, currentUser: PropTypes.object.isRequired, data: PropTypes.object.isRequired, root: PropTypes.object.isRequired, canSave: PropTypes.bool.isRequired, pending: PropTypes.object.isRequired, mergedSettings: PropTypes.object.isRequired, - activeSection: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, + router: PropTypes.object, }; From 394ebb8f2db32ad4d67864828c1cf12fed062177 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 30 Mar 2018 12:18:57 -0300 Subject: [PATCH 04/16] Save changes / discard changes dialohg --- .../routes/Configure/components/Configure.js | 6 +- .../routes/Configure/containers/Configure.js | 61 +++++++++++++------ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index 4d9f0ff34..fb55e25be 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -33,7 +33,9 @@ class Configure extends React.Component { onCancel={this.props.hideSaveDialog} title={t('bandialog.ban_user')} > - Are you sure? + There are unsaved changes, Are you sure you want to continue? + +
{ + await this.savePending(); + this.props.hideSaveDialog(); + }; + + discardChanges = () => { + this.props.clearPending(); + this.props.hideSaveDialog(); + }; + setActiveSection = section => { - // Check if pending - console.log('pending', this.props.pending); - this.props.setActiveSection(section); - this.props.router.push(`/admin/configure/${section}`); + if (this.shouldShowSaveDialog()) { + this.props.showSaveDialog(); + } else { + this.props.setActiveSection(section); + this.props.router.push(`/admin/configure/${section}`); + } + }; + + shouldShowSaveDialog = () => { + return !!Object.keys(this.props.pending).length; + }; + + onClickOutside = () => { + if (this.shouldShowSaveDialog()) { + this.props.showSaveDialog(); + } }; render() { @@ -42,19 +65,23 @@ class ConfigureContainer extends React.Component { } return ( - - {this.props.children} - + + + {this.props.children} + + ); } } From fe75d9543c3860116cae9d9c3b1ff33c98b0447a Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 30 Mar 2018 20:12:10 +0200 Subject: [PATCH 05/16] Restore Links --- .../client/components/AdminCommentContent.js | 9 ++++++++- .../client/components/CommentContent.js | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-rich-text/client/components/AdminCommentContent.js b/plugins/talk-plugin-rich-text/client/components/AdminCommentContent.js index 1b7e53ebf..f49d89055 100644 --- a/plugins/talk-plugin-rich-text/client/components/AdminCommentContent.js +++ b/plugins/talk-plugin-rich-text/client/components/AdminCommentContent.js @@ -1,12 +1,13 @@ import React from 'react'; import PropTypes from 'prop-types'; +import Linkify from 'react-linkify'; import styles from './AdminCommentContent.css'; import { AdminCommentContent as Content } from 'plugin-api/beta/client/components'; class AdminCommentContent extends React.Component { render() { const { comment, suspectWords, bannedWords } = this.props; - return ( + const content = ( ); + + if (!!comment.richTextBody) { + return content; + } + + return {content}; } } diff --git a/plugins/talk-plugin-rich-text/client/components/CommentContent.js b/plugins/talk-plugin-rich-text/client/components/CommentContent.js index 2cf481830..64aa96c82 100644 --- a/plugins/talk-plugin-rich-text/client/components/CommentContent.js +++ b/plugins/talk-plugin-rich-text/client/components/CommentContent.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { PLUGIN_NAME } from '../constants'; import cn from 'classnames'; import styles from './CommentContent.css'; +import Linkify from 'react-linkify'; class CommentContent extends React.Component { render() { @@ -14,7 +15,9 @@ class CommentContent extends React.Component { dangerouslySetInnerHTML={{ __html: comment.richTextBody }} /> ) : ( -
{comment.body}
+ +
{comment.body}
+
); } } From a509405f43645b163b568ccf533e288422bb4fbe Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 2 Apr 2018 13:33:50 -0300 Subject: [PATCH 06/16] alert route hook ready! --- .../routes/Configure/containers/Configure.js | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 6df911104..4affc53f5 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -3,7 +3,6 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; import { withQuery, withMergedSettings } from 'coral-framework/hocs'; -import ClickOutside from 'coral-framework/components/ClickOutside'; import { Spinner } from 'coral-ui'; import PropTypes from 'prop-types'; import { withUpdateSettings } from 'coral-framework/graphql/mutations'; @@ -49,12 +48,17 @@ class ConfigureContainer extends React.Component { return !!Object.keys(this.props.pending).length; }; - onClickOutside = () => { + routeLeave = () => { if (this.shouldShowSaveDialog()) { this.props.showSaveDialog(); + return false; } }; + componentDidMount() { + this.props.router.setRouteLeaveHook(this.props.route, this.routeLeave); + } + render() { if (this.props.data.error) { return
{this.props.data.error.message}
; @@ -65,23 +69,21 @@ class ConfigureContainer extends React.Component { } return ( - - - {this.props.children} - - + + {this.props.children} + ); } } @@ -156,4 +158,5 @@ ConfigureContainer.propTypes = { mergedSettings: PropTypes.object.isRequired, children: PropTypes.node.isRequired, router: PropTypes.object, + route: PropTypes.object, }; From 4ed04d1c39510ad3b81515e98f58200f514489b7 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 2 Apr 2018 14:12:02 -0300 Subject: [PATCH 07/16] Adding translations --- .../routes/Configure/components/Configure.js | 23 +++++++++---------- locales/en.yml | 4 ++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index fb55e25be..dcc9308b8 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -11,12 +11,7 @@ class Configure extends React.Component { const { canSave, currentUser, root, savePending, settings } = this.props; if (!can(currentUser, 'UPDATE_CONFIG')) { - return ( -

- You must be an administrator to access config settings. Please find - the nearest Admin and ask them to level you up! -

- ); + return

{t('configure.access_message')}

; } const passProps = { @@ -27,15 +22,19 @@ class Configure extends React.Component { return (
- There are unsaved changes, Are you sure you want to continue? - - + {t('configure.save_dialog_copy')} + +
Date: Mon, 2 Apr 2018 14:19:25 -0300 Subject: [PATCH 08/16] Spanish translations --- locales/es.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/locales/es.yml b/locales/es.yml index ba6cb8ad3..6919ce413 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -153,6 +153,10 @@ es: sign_out: "Desconectar" stories: Artículos stream_settings: "Configuración de Comentarios" + save_dialog_copy: "Hay cambios no guardados. Está seguro que desea continuar?" + save_settings: "Guardar configuración" + discard_changes: "Descartar Cambios" + access_message: "Usted debe ser un administrador para acceder a esta página. Encuentre a otro admin y actualice los permisos de su cuenta!" suspect_word_title: "Lista de palabras sospechosas" suspect_word_text: "Comentarios que contengan estas palabras o frases, considerando mayusculas y minúsculas, serán automáticamente destacadas en los comentarios publicados. Escribir una palabra y apretar Enter o Tabulador para agregarla. O pegar una lista de palabras separadas por coma." tech_settings: "Configuración Técnica" From d16ce17e36623fad4803c98c793e3b04d90fe76e Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 2 Apr 2018 14:35:09 -0300 Subject: [PATCH 09/16] SaveChangesDialog --- .../routes/Configure/components/Configure.js | 25 ++++------ .../components/SaveChangesDialog.css | 19 ++++++++ .../Configure/components/SaveChangesDialog.js | 46 +++++++++++++++++++ 3 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 client/coral-admin/src/routes/Configure/components/SaveChangesDialog.css create mode 100644 client/coral-admin/src/routes/Configure/components/SaveChangesDialog.js diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index dcc9308b8..137f685cf 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -1,10 +1,10 @@ import React from 'react'; import PropTypes from 'prop-types'; -import cn from 'classnames'; import t from 'coral-framework/services/i18n'; -import { Button, List, Item, Dialog } from 'coral-ui'; +import { Button, List, Item } from 'coral-ui'; import { can } from 'coral-framework/services/perms'; import styles from './Configure.css'; +import SaveChangesDialog from './SaveChangesDialog'; class Configure extends React.Component { render() { @@ -21,21 +21,12 @@ class Configure extends React.Component { return (
- - {t('configure.save_dialog_copy')} - - - +
( + + + × + + {t('configure.save_dialog_copy')} +
+ + +
+
+); + +SaveChangesDialog.propTypes = { + saveDialog: PropTypes.bool.isRequired, + hideSaveDialog: PropTypes.func.isRequired, + saveChanges: PropTypes.func.isRequired, + discardChanges: PropTypes.func.isRequired, +}; + +export default SaveChangesDialog; From e4358ac3a1d7d755c2db8857ba6de773be778ecb Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 2 Apr 2018 16:09:47 -0300 Subject: [PATCH 10/16] Style and translations --- .../components/SaveChangesDialog.css | 25 +++++++++++++++++-- .../Configure/components/SaveChangesDialog.js | 17 +++++++++---- locales/en.yml | 9 ++++--- locales/es.yml | 9 ++++--- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.css b/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.css index e77dbab34..f66a92e44 100644 --- a/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.css +++ b/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.css @@ -1,9 +1,11 @@ .buttonActions { - padding-top: 10px; + padding-top: 15px; + text-align: right; } .dialog { - padding: 20px; + padding: 25px; + min-width: 400px; } .close { @@ -16,4 +18,23 @@ font-weight: bold; color: #363636; cursor: pointer; +} + +.title { + font-size: 18px; + font-weight: 800; + margin-bottom: 20px; +} + +.cancel { + color: #363636; + margin-right: 15px; + display: inline-block; + &:hover { + cursor: pointer; + } +} + +.button { + margin-left: 5px; } \ No newline at end of file diff --git a/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.js b/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.js index f65dfdd09..fca87d2cd 100644 --- a/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.js +++ b/client/coral-admin/src/routes/Configure/components/SaveChangesDialog.js @@ -16,22 +16,29 @@ const SaveChangesDialog = ({ id="saveDialog" open={saveDialog} onCancel={hideSaveDialog} - title={t('configure.unsaved_changes')} > × - {t('configure.save_dialog_copy')} +
+ {t('configure.save_changes_dialog.unsaved_changes')} +
+ {t('configure.save_changes_dialog.copy')}
- + -
); diff --git a/locales/en.yml b/locales/en.yml index e3d87a522..6b2330f27 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -154,9 +154,6 @@ en: sign_out: "Sign Out" stories: Stories stream_settings: "Stream Settings" - save_dialog_copy: "There are unsaved changes, Are you sure you want to continue?" - save_settings: "Save Settings" - discard_changes: "Discard changes" access_message: "You must be an administrator to access config settings. Please find the nearest Admin and ask them to level you up!" suspect_word_title: "Suspect words list" suspect_word_text: "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list." @@ -164,6 +161,12 @@ en: title: "Configure Comment Stream" weeks: Weeks wordlist: "Banned Words" + save_changes_dialog: + unsaved_changes: "Unsaved changes" + copy: "You have made one or more changes without saving. Would you like to save or discard your changes?" + save_settings: "Save Settings" + discard: "Discard" + cancel: "Cancel" continue: "Continue" createdisplay: check_the_form: "Invalid Form. Please check the fields" diff --git a/locales/es.yml b/locales/es.yml index 6919ce413..4e7a2c51b 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -153,9 +153,6 @@ es: sign_out: "Desconectar" stories: Artículos stream_settings: "Configuración de Comentarios" - save_dialog_copy: "Hay cambios no guardados. Está seguro que desea continuar?" - save_settings: "Guardar configuración" - discard_changes: "Descartar Cambios" access_message: "Usted debe ser un administrador para acceder a esta página. Encuentre a otro admin y actualice los permisos de su cuenta!" suspect_word_title: "Lista de palabras sospechosas" suspect_word_text: "Comentarios que contengan estas palabras o frases, considerando mayusculas y minúsculas, serán automáticamente destacadas en los comentarios publicados. Escribir una palabra y apretar Enter o Tabulador para agregarla. O pegar una lista de palabras separadas por coma." @@ -163,6 +160,12 @@ es: title: "Configurar los comentarios" weeks: Semanas wordlist: "Palabras Suspendidas" + save_changes_dialog: + unsaved_changes: "Cambios no guardados" + copy: Has hecho uno o más cambios sin guardar. Deseas guardar o descartar tus cambios?" + save_settings: "Guardar configuración" + discard: "Descartar" + cancel: "Cancelar" continue: "Continuar" createdisplay: check_the_form: "Formulario Inválido. Por favor verifica los campos" From fb3233cf01a269d16a2a7072e79bfe4d781fc0e3 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 2 Apr 2018 17:01:49 -0600 Subject: [PATCH 11/16] IfSlotIsNotEmpty Bug --- client/coral-framework/components/IfSlotIsNotEmpty.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/coral-framework/components/IfSlotIsNotEmpty.js b/client/coral-framework/components/IfSlotIsNotEmpty.js index 6318e6447..1707a83b6 100644 --- a/client/coral-framework/components/IfSlotIsNotEmpty.js +++ b/client/coral-framework/components/IfSlotIsNotEmpty.js @@ -7,7 +7,7 @@ class IfSlotIsNotEmpty extends React.Component { isSlotEmpty(props = this.props) { const { slotElements } = props; return slotElements.length === 0 - ? false + ? true : slotElements.every(elements => elements.length === 0); } @@ -19,6 +19,7 @@ class IfSlotIsNotEmpty extends React.Component { IfSlotIsNotEmpty.propTypes = { slot: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + slotElements: PropTypes.array.isRequired, children: PropTypes.node.isRequired, passthrough: PropTypes.object.isRequired, }; From edbe49618a53c3a4091604e18f25266ec17f0842 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 3 Apr 2018 20:17:31 -0300 Subject: [PATCH 12/16] Adding size, and proptypes --- .../src/tabs/profile/components/Comment.js | 1 + .../client/components/Comment.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/client/coral-embed-stream/src/tabs/profile/components/Comment.js b/client/coral-embed-stream/src/tabs/profile/components/Comment.js index be13c2c50..171172dab 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/profile/components/Comment.js @@ -34,6 +34,7 @@ class Comment extends React.Component { defaultComponent={CommentContent} className={cn(styles.commentBody, 'my-comment-body')} passthrough={slotPassthrough} + size={1} />
@@ -87,4 +89,11 @@ class Comment extends React.Component { } } +Comment.propTypes = { + viewComment: PropTypes.func, + comment: PropTypes.object, + asset: PropTypes.object, + root: PropTypes.object, +}; + export default Comment; From e6b8cd32203036674aaf2eedd290bbd23b6cb7a0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 5 Apr 2018 14:19:11 -0600 Subject: [PATCH 13/16] fixes related to external auth --- client/coral-framework/actions/auth.js | 5 +++++ client/coral-framework/constants/auth.js | 2 ++ client/coral-framework/reducers/auth.js | 9 +++++++++ client/coral-framework/services/bootstrap.js | 8 +++++++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 17b1c38f9..5390153e6 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -57,6 +57,10 @@ export const setAuthToken = token => (dispatch, _, { localStorage }) => { localStorage.setItem('token', token); } + // Dispatch the set auth token action. For some browsers and situations, we + // may not be able to persist the auth token any other way. Keep it in redux! + dispatch({ type: actions.SET_AUTH_TOKEN, token }); + dispatch(checkLogin()); }; @@ -87,6 +91,7 @@ export const handleSuccessfulLogin = (user, token) => ( dispatch({ type: actions.HANDLE_SUCCESSFUL_LOGIN, user, + token, }); }; diff --git a/client/coral-framework/constants/auth.js b/client/coral-framework/constants/auth.js index 25e2f6a78..b340924c3 100644 --- a/client/coral-framework/constants/auth.js +++ b/client/coral-framework/constants/auth.js @@ -1,5 +1,7 @@ const prefix = `TALK_FRAMEWORK`; +export const SET_AUTH_TOKEN = `${prefix}_SET_AUTH_TOKEN`; + export const CHECK_LOGIN_REQUEST = `${prefix}_CHECK_LOGIN_REQUEST`; export const CHECK_LOGIN_SUCCESS = `${prefix}_CHECK_LOGIN_SUCCESS`; export const CHECK_LOGIN_FAILURE = `${prefix}_CHECK_LOGIN_FAILURE`; diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js index 3af606d0b..89478e30d 100644 --- a/client/coral-framework/reducers/auth.js +++ b/client/coral-framework/reducers/auth.js @@ -5,6 +5,7 @@ const initialState = { checkedInitialLogin: false, initialLoginError: null, user: null, + token: null, }; const purge = user => { @@ -14,12 +15,18 @@ const purge = user => { export default function auth(state = initialState, action) { switch (action.type) { + case actions.SET_AUTH_TOKEN: + return { + ...state, + token: action.token || null, + }; case actions.CHECK_LOGIN_FAILURE: return { ...state, initialLoginError: action.error, checkedInitialLogin: true, user: null, + token: null, }; case actions.CHECK_LOGIN_SUCCESS: return { @@ -31,11 +38,13 @@ export default function auth(state = initialState, action) { return { ...state, user: action.user ? purge(action.user) : null, + token: action.token || null, }; case actions.LOGOUT: return { ...state, user: null, + token: null, }; case actions.UPDATE_STATUS: { return { diff --git a/client/coral-framework/services/bootstrap.js b/client/coral-framework/services/bootstrap.js index e0bfbb950..9bfec2acd 100644 --- a/client/coral-framework/services/bootstrap.js +++ b/client/coral-framework/services/bootstrap.js @@ -47,6 +47,12 @@ const getAuthToken = (store, storage) => { } else if (!bowser.safari && !bowser.ios && storage) { // Use local storage auth tokens where there's a stable api. return storage.getItem('token'); + } else if (state.auth && state.auth.token) { + // Use the redux token state if the remaining methods fall out. If the embed + // is called with `embed.login(token)`, and the browser is not capable of + // storing the token in localStorage, then we would have persisted it to the + // redux state. + return state.auth.token; } return null; @@ -123,7 +129,7 @@ export async function createContext({ // Try to get the token from localStorage. If it isn't here, it may // be passed as a cookie. - // NOTE: THIS IS ONLY EVER EVALUATED ONCE, IN ORDER TO SEND A DIFFERNT + // NOTE: THIS IS ONLY EVER EVALUATED ONCE, IN ORDER TO SEND A DIFFERENT // TOKEN YOU MUST DISCONNECT AND RECONNECT THE WEBSOCKET CLIENT. return getAuthToken(store, localStorage); }; From ad56d3b99a65b629bdf1136456d1409fac089434 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 5 Apr 2018 17:24:11 -0300 Subject: [PATCH 14/16] Removin actions, using routes, and continuing the transition when the user makes an action --- client/coral-admin/src/actions/configure.js | 4 --- client/coral-admin/src/constants/configure.js | 1 - client/coral-admin/src/reducers/configure.js | 6 ---- .../routes/Configure/components/Configure.js | 4 +-- .../routes/Configure/containers/Configure.js | 36 +++++++++++++------ 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/client/coral-admin/src/actions/configure.js b/client/coral-admin/src/actions/configure.js index 0f82832e0..47c7fd25f 100644 --- a/client/coral-admin/src/actions/configure.js +++ b/client/coral-admin/src/actions/configure.js @@ -8,10 +8,6 @@ export const clearPending = () => { return { type: actions.CLEAR_PENDING }; }; -export const setActiveSection = section => { - return { type: actions.SET_ACTIVE_SECTION, section }; -}; - export const showSaveDialog = () => { return { type: actions.SHOW_SAVE_DIALOG }; }; diff --git a/client/coral-admin/src/constants/configure.js b/client/coral-admin/src/constants/configure.js index ed5f74578..9ab22580d 100644 --- a/client/coral-admin/src/constants/configure.js +++ b/client/coral-admin/src/constants/configure.js @@ -2,7 +2,6 @@ const prefix = 'TALK_ADMIN_CONFIGURE'; export const UPDATE_PENDING = `${prefix}_UPDATE_PENDING`; export const CLEAR_PENDING = `${prefix}_CLEAR_PENDING`; -export const SET_ACTIVE_SECTION = `${prefix}_SET_ACTIVE_SECTION`; export const SHOW_SAVE_DIALOG = `${prefix}_SHOW_SAVE_DIALOG`; export const HIDE_SAVE_DIALOG = `${prefix}_HIDE_SAVE_DIALOG`; diff --git a/client/coral-admin/src/reducers/configure.js b/client/coral-admin/src/reducers/configure.js index 335cc4ce0..c87463423 100644 --- a/client/coral-admin/src/reducers/configure.js +++ b/client/coral-admin/src/reducers/configure.js @@ -6,7 +6,6 @@ const initialState = { canSave: false, pending: {}, errors: {}, - activeSection: 'stream', saveDialog: false, }; @@ -53,11 +52,6 @@ export default function configure(state = initialState, action) { pending: {}, canSave: false, }; - case actions.SET_ACTIVE_SECTION: - return { - ...state, - activeSection: action.section, - }; default: return state; } diff --git a/client/coral-admin/src/routes/Configure/components/Configure.js b/client/coral-admin/src/routes/Configure/components/Configure.js index 137f685cf..4d88f8420 100644 --- a/client/coral-admin/src/routes/Configure/components/Configure.js +++ b/client/coral-admin/src/routes/Configure/components/Configure.js @@ -29,7 +29,7 @@ class Configure extends React.Component { />
@@ -76,7 +76,7 @@ Configure.propTypes = { root: PropTypes.object.isRequired, settings: PropTypes.object.isRequired, canSave: PropTypes.bool.isRequired, - setActiveSection: PropTypes.func.isRequired, + handleSectionChange: PropTypes.func.isRequired, activeSection: PropTypes.string.isRequired, children: PropTypes.node.isRequired, saveDialog: PropTypes.bool, diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 4affc53f5..1d1547373 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -12,7 +12,6 @@ import TechSettings from './TechSettings'; import ModerationSettings from './ModerationSettings'; import { clearPending, - setActiveSection, showSaveDialog, hideSaveDialog, } from '../../../actions/configure'; @@ -20,6 +19,8 @@ import Configure from '../components/Configure'; import { withRouter } from 'react-router'; class ConfigureContainer extends React.Component { + state = { nextRoute: '' }; + savePending = async () => { await this.props.updateSettings(this.props.pending); this.props.clearPending(); @@ -28,19 +29,32 @@ class ConfigureContainer extends React.Component { saveChanges = async () => { await this.savePending(); this.props.hideSaveDialog(); + this.gotoNextRoute(); }; - discardChanges = () => { - this.props.clearPending(); + discardChanges = async () => { + await this.props.clearPending(); this.props.hideSaveDialog(); + this.gotoNextRoute(); }; - setActiveSection = section => { + gotoNextRoute = () => { + const { nextRoute } = this.state; + if (nextRoute) { + this.props.router.push(nextRoute); + this.setState({ nextRoute: '' }); + } + }; + + handleSectionChange = async section => { + const nextRoute = `/admin/configure/${section}`; + if (this.shouldShowSaveDialog()) { + await this.setState({ nextRoute }); this.props.showSaveDialog(); } else { - this.props.setActiveSection(section); - this.props.router.push(`/admin/configure/${section}`); + // Just go to the section + this.props.router.push(nextRoute); } }; @@ -48,8 +62,9 @@ class ConfigureContainer extends React.Component { return !!Object.keys(this.props.pending).length; }; - routeLeave = () => { + routeLeave = ({ pathname }) => { if (this.shouldShowSaveDialog()) { + this.setState({ nextRoute: pathname }); this.props.showSaveDialog(); return false; } @@ -73,13 +88,13 @@ class ConfigureContainer extends React.Component { saveChanges={this.saveChanges} discardChanges={this.discardChanges} saveDialog={this.props.saveDialog} - activeSection={this.props.activeSection} + activeSection={this.props.routes[3].path} hideSaveDialog={this.props.hideSaveDialog} canSave={this.props.canSave} currentUser={this.props.currentUser} root={this.props.root} settings={this.props.mergedSettings} - setActiveSection={this.setActiveSection} + handleSectionChange={this.handleSectionChange} savePending={this.savePending} > {this.props.children} @@ -127,7 +142,6 @@ const mapDispatchToProps = dispatch => bindActionCreators( { clearPending, - setActiveSection, showSaveDialog, hideSaveDialog, }, @@ -146,7 +160,6 @@ ConfigureContainer.propTypes = { activeSection: PropTypes.string, updateSettings: PropTypes.func.isRequired, clearPending: PropTypes.func.isRequired, - setActiveSection: PropTypes.func.isRequired, showSaveDialog: PropTypes.func.isRequired, hideSaveDialog: PropTypes.func.isRequired, saveDialog: PropTypes.bool.isRequired, @@ -159,4 +172,5 @@ ConfigureContainer.propTypes = { children: PropTypes.node.isRequired, router: PropTypes.object, route: PropTypes.object, + routes: PropTypes.object, }; From 793b4736816e21fe9751bf5b7a1ff3e87b5dfb2c Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 5 Apr 2018 17:25:00 -0300 Subject: [PATCH 15/16] PropTypes --- client/coral-admin/src/routes/Configure/containers/Configure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 1d1547373..9f980d31b 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -172,5 +172,5 @@ ConfigureContainer.propTypes = { children: PropTypes.node.isRequired, router: PropTypes.object, route: PropTypes.object, - routes: PropTypes.object, + routes: PropTypes.array, }; From 93ccec6614b192a38ad2c479303089e356baee1a Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 6 Apr 2018 16:19:10 -0600 Subject: [PATCH 16/16] Fixes #1505 --- bin/cli-assets | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/bin/cli-assets b/bin/cli-assets index 78229d91b..210b9f22e 100755 --- a/bin/cli-assets +++ b/bin/cli-assets @@ -13,6 +13,7 @@ const CommentModel = require('../models/comment'); const AssetsService = require('../services/assets'); const mongoose = require('../services/mongoose'); const scraper = require('../services/scraper'); +const Context = require('../graph/context'); const inquirer = require('inquirer'); const { URL } = require('url'); @@ -52,22 +53,27 @@ async function refreshAssets(ageString) { const ageMs = parseDuration(ageString); const age = new Date(now - ageMs); - let assets = await AssetModel.find({ - $or: [ - { - scraped: { - $lte: age, + let assets = await AssetModel.find( + { + $or: [ + { + scraped: { + $lte: age, + }, }, - }, - { - scraped: null, - }, - ], - }); + { + scraped: null, + }, + ], + }, + { id: 1 } + ); + + // Create a graph context. + const ctx = Context.forSystem(); // Queue all the assets for scraping. - await Promise.all(assets.map(scraper.create)); - + await Promise.all(assets.map(({ id }) => scraper.create(ctx, id))); console.log('Assets were queued to be scraped'); util.shutdown(); } catch (e) {