diff --git a/bin/cli b/bin/cli index 33560c53b..52d67c9af 100755 --- a/bin/cli +++ b/bin/cli @@ -9,13 +9,17 @@ const program = require('./commander'); program .command('serve', 'serve the application') + .command('settings', 'interact with the application settings') .command('assets', 'interact with assets') .command('setup', 'setup the application') .command('jobs', 'work with the job queues') .command('token', 'work with the access tokens') .command('users', 'work with the application auth') .command('migration', 'provides utilities for migrating the database') - .command('plugins', 'provides utilities for interacting with the plugin system') + .command( + 'plugins', + 'provides utilities for interacting with the plugin system' + ) .parse(process.argv); /** @@ -25,7 +29,10 @@ program * labled with the PID written out by the parent process. */ process.once('exit', () => { - if ((program.runningCommand.killed === false) && (program.runningCommand.exitCode === null)) { + if ( + program.runningCommand.killed === false && + program.runningCommand.exitCode === null + ) { program.runningCommand.kill('SIGINT'); } }); diff --git a/bin/cli-settings b/bin/cli-settings new file mode 100755 index 000000000..f8768046c --- /dev/null +++ b/bin/cli-settings @@ -0,0 +1,59 @@ +#!/usr/bin/env node + +const program = require('./commander'); +const inquirer = require('inquirer'); +const mongoose = require('../services/mongoose'); +const SettingsService = require('../services/settings'); +const util = require('./util'); + +// Register the shutdown criteria. +util.onshutdown([() => mongoose.disconnect()]); + +/** + * Change the organization name + */ +async function changeOrgName() { + try { + let settings = await SettingsService.retrieve(); + + let {organizationName} = await inquirer.prompt([ + { + name: 'organizationName', + message: 'Organization Name', + default: settings.organizationName + } + ]); + + if (settings.organizationName !== organizationName) { + settings.organizationName = organizationName; + + await SettingsService.update(settings); + + console.log('Settings were updated.'); + } else { + console.log('No update needed, no change was made.'); + } + } catch (err) { + console.error(err); + util.shutdown(1); + } + + util.shutdown(); +} + +//============================================================================== +// Setting up the program command line arguments. +//============================================================================== + +program + .command('change-org-name') + .description('change the organization name') + .action(changeOrgName); + +program.parse(process.argv); + +// If there is no command listed, output help. +if (!process.argv.slice(2).length) { + program.outputHelp(); + util.shutdown(); +} diff --git a/client/coral-embed-stream/src/actions/stream.js b/client/coral-embed-stream/src/actions/stream.js index 9b5d94a9b..75c665315 100644 --- a/client/coral-embed-stream/src/actions/stream.js +++ b/client/coral-embed-stream/src/actions/stream.js @@ -1,4 +1,4 @@ -import {pym} from 'coral-framework'; +import pym from 'coral-framework/services/pym'; import * as actions from '../constants/stream'; export const setActiveReplyBox = (id) => ({type: actions.SET_ACTIVE_REPLY_BOX, id}); diff --git a/client/coral-embed-stream/src/components/Comment.css b/client/coral-embed-stream/src/components/Comment.css index 4ff0586da..4c8a9fc86 100644 --- a/client/coral-embed-stream/src/components/Comment.css +++ b/client/coral-embed-stream/src/components/Comment.css @@ -1,11 +1,41 @@ -.Reply { - position: relative; +.root { + margin-top: 16px; + margin-left: 20px; margin-bottom: 15px; + position: relative; } -.Comment { - margin-bottom: 15px; - position: relative; +.rootLevel0 { + margin-left: 0px; +} + +.comment { + padding-left: 20px; +} + +.commentLevel0 { + padding-left: 0px; +} + +.commentLevel1 { + border-left: 3px #212121 solid; +} + +.commentLevel2 { + border-left: 2px #6a6a6a solid; +} + +.commentLevel3 { + border-left: 2px #9e9e9e solid; +} + +.commentLevel4 { + border-left: 2px #c1c1c1 solid; +} + +.highlightedComment { + padding-left: 20px; + border-left: 3px solid rgb(35,118,216); } .pendingComment { diff --git a/client/coral-embed-stream/src/components/Comment.js b/client/coral-embed-stream/src/components/Comment.js index 2e854633b..7cc8b1480 100644 --- a/client/coral-embed-stream/src/components/Comment.js +++ b/client/coral-embed-stream/src/components/Comment.js @@ -9,6 +9,9 @@ import {can} from 'coral-framework/services/perms'; import {TransitionGroup} from 'react-transition-group'; import cn from 'classnames'; import styles from './Comment.css'; +import {THREADING_LEVEL} from '../constants/stream'; +import merge from 'lodash/merge'; +import mapValues from 'lodash/mapValues'; import { BestButton, @@ -316,6 +319,7 @@ export default class Comment extends React.Component { postDontAgree, setActiveReplyBox, activeReplyBox, + loadMore, deleteAction, disableReply, maxCharCount, @@ -331,9 +335,12 @@ export default class Comment extends React.Component { const view = this.getVisibileReplies(); const {loadingState} = this.state; + const isReply = !!parentId; + const isPending = comment.id.indexOf('pending') >= 0; + const isHighlighted = highlighted === comment.id; const hasMoreComments = comment.replies && (comment.replies.hasNextPage || comment.replies.nodes.length > view.length); - const replyCount = this.hasIgnoredReplies() ? '' : comment.replyCount; + const moreRepliesCount = this.hasIgnoredReplies() ? -1 : comment.replyCount - view.length; const flagSummary = getActionSummary('FlagActionSummary', comment); const dontAgreeSummary = getActionSummary( 'DontAgreeActionSummary', @@ -346,11 +353,6 @@ export default class Comment extends React.Component { myFlag = dontAgreeSummary.find((s) => s.current_user); } - let commentClass = parentId - ? `reply ${styles.Reply}` - : `comment ${styles.Comment}`; - commentClass += comment.id.indexOf('pending') >= 0 ? ` ${styles.pendingComment}` : ''; - // call a function, and if it errors, call addNotification('error', ...) (e.g. to show user a snackbar) const notifyOnError = (fn, errorToMessage) => async function(...args) { @@ -386,7 +388,7 @@ export default class Comment extends React.Component { ); /** - * classNamesToAdd + * conditionClassNames * adds classNames based on condition * classnames is an array of objects with key as classnames and value as conditions * i.e: @@ -396,35 +398,45 @@ export default class Comment extends React.Component { * * This will add myClassName to comments tagged with STAFF TAG. * **/ - - const classNamesToAdd = commentClassNames.reduce((acc, className) => { - let res = []; - - // Adding classNames based on tags - Object.keys(className).forEach((cn) => { - const condition = className[cn]; - condition.tags.forEach((tag) => { - if (hasTag(comment.tags, tag)) { - res = [...res, cn]; - } - }); + const conditionalClassNames = + mapValues(merge({}, ...commentClassNames), (condition) => { + if (condition.tags) { + return condition.tags.some((tag) => hasTag(comment.tags, tag)); + } + return false; }); - // TODO: Compare rest of the comment obj to the condition if needed + const rootClassName = cn( + 'talk-stream-comment-wrapper', + `talk-stream-comment-wrapper-level-${depth}`, + styles.root, + styles[`rootLevel${depth}`], + { + ...conditionalClassNames, + [styles.enter]: this.state.animateEnter, + }, + ); - return [...acc, ...res]; - }, []); + const commentClassName = cn( + 'talk-stream-comment', + `talk-stream-comment-level-${depth}`, + styles.comment, + styles[`commentLevel${depth}`], + { + [styles.pendingComment]: isPending, + [styles.highlightedComment]: isHighlighted, + 'talk-stream-pending-comment': isPending, + 'talk-stream-highlighted-comment': isHighlighted, + } + ); return (