diff --git a/.eslintrc.json b/.eslintrc.json index d00d21106..d2356ace2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,5 +2,10 @@ "env": { "jest": true }, + "settings": { + "react": { + "version": "15.0" + } + }, "extends": "@coralproject/eslint-config-talk" } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..10041faa8 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +overrides: +- files: "bin/cli*" + options: + parser: babylon diff --git a/bin/cli-plugins b/bin/cli-plugins index f2e76de21..85132c39d 100755 --- a/bin/cli-plugins +++ b/bin/cli-plugins @@ -329,8 +329,7 @@ async function createSeedPlugin() { if (answers.addPluginsJson) { const pluginsJson = path.resolve(__dirname, '..', 'plugins.json'); - fs - .readJson(pluginsJson) + fs.readJson(pluginsJson) .then(j => { // This is a client-side plugin, let's push this. if (answers.client) { diff --git a/bin/cli-token b/bin/cli-token index 0d4dc4e10..2590ec106 100755 --- a/bin/cli-token +++ b/bin/cli-token @@ -49,7 +49,10 @@ async function revokeToken(tokenID) { async function createToken(userID, tokenName) { try { - let { pat: { id }, jwt } = await TokensService.create(userID, tokenName); + let { + pat: { id }, + jwt, + } = await TokensService.create(userID, tokenName); console.log(`Created Token[${id}] for User[${userID}] = ${jwt}`); diff --git a/client/coral-admin/src/actions/rejectUsernameDialog.js b/client/coral-admin/src/actions/rejectUsernameDialog.js new file mode 100644 index 000000000..946b36ef7 --- /dev/null +++ b/client/coral-admin/src/actions/rejectUsernameDialog.js @@ -0,0 +1,14 @@ +import { + SHOW_REJECT_USERNAME_DIALOG, + HIDE_REJECT_USERNAME_DIALOG, +} from '../constants/rejectUsernameDialog'; + +export const showRejectUsernameDialog = ({ userId, username }) => ({ + type: SHOW_REJECT_USERNAME_DIALOG, + userId, + username, +}); + +export const hideRejectUsernameDialog = () => ({ + type: HIDE_REJECT_USERNAME_DIALOG, +}); diff --git a/client/coral-admin/src/components/ActionsMenu.js b/client/coral-admin/src/components/ActionsMenu.js index 81b857a13..52370f9a7 100644 --- a/client/coral-admin/src/components/ActionsMenu.js +++ b/client/coral-admin/src/components/ActionsMenu.js @@ -76,7 +76,7 @@ ActionsMenu.propTypes = { icon: PropTypes.string, children: PropTypes.node, className: PropTypes.string, - label: PropTypes.string, + label: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), buttonClassNames: PropTypes.string, }; diff --git a/client/coral-admin/src/components/ActionsMenuItem.js b/client/coral-admin/src/components/ActionsMenuItem.js index 7370ba466..54816147a 100644 --- a/client/coral-admin/src/components/ActionsMenuItem.js +++ b/client/coral-admin/src/components/ActionsMenuItem.js @@ -15,7 +15,7 @@ const ActionsMenuItem = props => ( ActionsMenuItem.propTypes = { className: PropTypes.string, - children: PropTypes.string, + children: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), }; export default ActionsMenuItem; diff --git a/client/coral-admin/src/components/BanUserDialog.js b/client/coral-admin/src/components/BanUserDialog.js index f211a9f2c..fd8636320 100644 --- a/client/coral-admin/src/components/BanUserDialog.js +++ b/client/coral-admin/src/components/BanUserDialog.js @@ -19,7 +19,9 @@ class BanUserDialog extends React.Component { } handleMessageChange = e => { - const { target: { value: message } } = e; + const { + target: { value: message }, + } = e; this.setState({ message }); }; diff --git a/client/coral-admin/src/components/KarmaTooltip.js b/client/coral-admin/src/components/KarmaTooltip.js index 9c4184afd..d27597325 100644 --- a/client/coral-admin/src/components/KarmaTooltip.js +++ b/client/coral-admin/src/components/KarmaTooltip.js @@ -27,7 +27,9 @@ class KarmaTooltip extends React.Component { }; render() { - const { thresholds: { unreliable } } = this.props; + const { + thresholds: { unreliable }, + } = this.props; const { menuVisible } = this.state; return ( @@ -68,6 +70,7 @@ class KarmaTooltip extends React.Component { className={styles.link} href={t('user_detail.karma_docs_link')} target="_blank" + rel="noopener noreferrer" > {t('user_detail.learn_more')} diff --git a/client/coral-admin/src/components/RejectUsernameDialog.css b/client/coral-admin/src/components/RejectUsernameDialog.css new file mode 100644 index 000000000..57c9ca24a --- /dev/null +++ b/client/coral-admin/src/components/RejectUsernameDialog.css @@ -0,0 +1,80 @@ +.dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 400px; + top: 50%; + transform: translateY(-50%); + padding: 20px; + border-radius: 4px; +} + +.header { + color: black; + font-size: 1.5em; + font-weight: 500; + margin: 0 0 8px 0; +} + +.close { + display: block; + position: absolute; + top: 24px; + right: 20px; +} + +.closeButton { + font-size: 24px; + line-height: 14px; + color: #363636; + &:hover { + color: #6b6b6b; + } +} + +.legend { + padding: 0; + font-weight: bold; +} + +div.radioGroup { + margin-top: 6px; +} + +label.radioGroup { + + &:global(.is-checked) > :global(.mdl-radio__outer-circle), + > :global(.mdl-radio__outer-circle) { + border-color: #212121; + } + + > :global(.mdl-radio__inner-circle) { + background: #212121; + } + + > :global(.mdl-radio__label) { + font-size: 14px; + line-height: 20px; + } +} + +.messageInput { + border-radius: 3px; + width: 100%; + padding: 10px; + font-size: 14px; + box-sizing: border-box; +} + +.cancel { + margin-right: 5px; +} + +.perform { + min-width: 90px; +} + +.buttons { + margin-top: 8px; + margin-bottom: 6px; + text-align: right; +} diff --git a/client/coral-admin/src/components/RejectUsernameDialog.js b/client/coral-admin/src/components/RejectUsernameDialog.js new file mode 100644 index 000000000..b14384eb8 --- /dev/null +++ b/client/coral-admin/src/components/RejectUsernameDialog.js @@ -0,0 +1,138 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Dialog, BareButton } from 'coral-ui'; +import styles from './RejectUsernameDialog.css'; +import cn from 'classnames'; +import { RadioGroup, Radio } from 'react-mdl'; +import Button from 'coral-ui/components/Button'; +import { username as flagReason } from 'coral-framework/graphql/flagReasons'; +import t from 'coral-framework/services/i18n'; + +const initialState = { reason: flagReason.offensive, message: '' }; + +class RejectUsernameDialog extends React.Component { + state = initialState; + + componentWillReceiveProps(next) { + if (this.props.open && !next.open) { + this.setState(initialState); + } + } + + handleReasonChange = event => { + this.setState({ reason: event.target.value }); + }; + + handleMessageChange = event => { + this.setState({ message: event.target.value }); + }; + + handlePerform = () => { + this.props.onPerform({ + reason: this.state.reason, + message: this.state.message, + }); + }; + + render() { + const { open, onCancel } = this.props; + const { reason, message } = this.state; + return ( + +
+ + × + +
+
+

+ {t('reject_username_dialog.title')}: {this.props.username} +

+

+ {t('reject_username_dialog.description')} +

+
+ + {t('reject_username_dialog.reason')} + + + + {t('flag_reasons.username.offensive')} + + + {t('flag_reasons.username.nolike')} + + + {t('flag_reasons.username.impersonating')} + + + {t('flag_reasons.username.spam')} + + + {t('flag_reasons.username.other')} + + + {reason === flagReason.other && ( +
+ + {t('reject_username_dialog.message')} + +