mirror of
https://github.com/wassname/talk.git
synced 2026-07-20 12:40:47 +08:00
Merge branch 'master' of github.com:coralproject/talk into featured-adm
This commit is contained in:
+1
-1
@@ -11,4 +11,4 @@
|
||||
"transform-async-to-generator",
|
||||
"transform-react-jsx"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,9 @@ import {TopRightMenu} from './TopRightMenu';
|
||||
import CommentContent from './CommentContent';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
|
||||
import InactiveCommentLabel from './InactiveCommentLabel';
|
||||
import {EditableCommentContent} from './EditableCommentContent';
|
||||
import {getActionSummary, iPerformedThisAction, forEachError} from 'coral-framework/utils';
|
||||
import {getActionSummary, iPerformedThisAction, forEachError, isCommentActive} from 'coral-framework/utils';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
const isStaff = (tags) => !tags.every((t) => t.tag.name !== 'STAFF');
|
||||
@@ -317,7 +318,10 @@ export default class Comment extends React.Component {
|
||||
} = this.props;
|
||||
|
||||
const view = this.getVisibileReplies();
|
||||
const isActive = ['NONE', 'ACCEPTED'].indexOf(comment.status) >= 0;
|
||||
|
||||
// Inactive comments can be viewed by moderators and admins (e.g. using permalinks).
|
||||
const isActive = isCommentActive(comment.status);
|
||||
|
||||
const {loadingState} = this.state;
|
||||
const isPending = comment.id.indexOf('pending') >= 0;
|
||||
const isHighlighted = highlighted === comment.id;
|
||||
@@ -435,7 +439,7 @@ export default class Comment extends React.Component {
|
||||
}
|
||||
</span>
|
||||
}
|
||||
{ (currentUser && (comment.user.id !== currentUser.id)) &&
|
||||
{ isActive && (currentUser && (comment.user.id !== currentUser.id)) &&
|
||||
|
||||
/* TopRightMenu allows currentUser to ignore other users' comments */
|
||||
<span className={cn(styles.topRight, styles.topRightMenu)}>
|
||||
@@ -445,6 +449,9 @@ export default class Comment extends React.Component {
|
||||
addNotification={addNotification} />
|
||||
</span>
|
||||
}
|
||||
{ !isActive &&
|
||||
<InactiveCommentLabel status={comment.status}/>
|
||||
}
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
.root {
|
||||
display: inline-block;
|
||||
color: white;
|
||||
background: grey;
|
||||
height: 22px;
|
||||
box-sizing: border-box;
|
||||
line-height: 19px;
|
||||
padding: 2px 6px 2px 4px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 14px;
|
||||
vertical-align: text-top;
|
||||
margin: 0;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.premod {
|
||||
background: #063B9A;
|
||||
}
|
||||
|
||||
.rejected {
|
||||
background: #d03235;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import styles from './InactiveCommentLabel.css';
|
||||
import {Icon} from 'coral-ui';
|
||||
import cn from 'classnames';
|
||||
|
||||
const InactiveCommentLabel = ({status, className, ...rest}) => {
|
||||
let label;
|
||||
let icon;
|
||||
|
||||
switch (status) {
|
||||
case 'PREMOD':
|
||||
label = t('modqueue.premod');
|
||||
icon = 'query_builder';
|
||||
break;
|
||||
case 'REJECTED':
|
||||
label = t('modqueue.rejected');
|
||||
icon = 'close';
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown inactive status ${status}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<span {...rest} className={cn(className, styles.root, styles[status.toLowerCase()])}>
|
||||
<Icon name={icon} className={styles.icon}/>
|
||||
<span className={styles.label}>{label}</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
InactiveCommentLabel.propTypes = {
|
||||
status: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default InactiveCommentLabel;
|
||||
@@ -13,6 +13,7 @@ import t, {timeago} from 'coral-framework/services/i18n';
|
||||
import {getSlotComponents} from 'coral-framework/helpers/plugins';
|
||||
import CommentBox from 'talk-plugin-commentbox/CommentBox';
|
||||
import QuestionBox from 'talk-plugin-questionbox/QuestionBox';
|
||||
import {isCommentActive} from 'coral-framework/utils';
|
||||
import {Button, TabBar, Tab, TabCount, TabContent, TabPane} from 'coral-ui';
|
||||
import cn from 'classnames';
|
||||
|
||||
@@ -105,7 +106,9 @@ class Stream extends React.Component {
|
||||
// even though the permalinked comment is the highlighted one, we're displaying its parent + replies
|
||||
let highlightedComment = comment && getTopLevelParent(comment);
|
||||
if (highlightedComment) {
|
||||
const isInactive = ['NONE', 'ACCEPTED'].indexOf(comment.status) === -1;
|
||||
|
||||
// Inactive comments can be viewed by moderators and admins (e.g. using permalinks).
|
||||
const isInactive = !isCommentActive(comment.status);
|
||||
if (comment.parent && isInactive) {
|
||||
|
||||
// the highlighted comment is not active and as such not in the replies, so we
|
||||
|
||||
@@ -267,6 +267,11 @@ Talk.render = function(el, opts) {
|
||||
console.warn(
|
||||
'This page does not include a canonical link tag. Talk has inferred this asset_url from the window object. Query params have been stripped, which may cause a single thread to be present across multiple pages.'
|
||||
);
|
||||
|
||||
if (!window.location.origin) {
|
||||
window.location.origin = `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}`;
|
||||
}
|
||||
|
||||
query.asset_url = window.location.origin + window.location.pathname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,3 +187,7 @@ export function buildUrl({protocol, hostname, port, pathname, search, hash} = wi
|
||||
export function getSlotFragmentSpreads(slots, resource) {
|
||||
return `...${slots.map((s) => `TalkSlot_${capitalize(s)}_${resource}`).join('\n...')}\n`;
|
||||
}
|
||||
|
||||
export function isCommentActive(commentStatus) {
|
||||
return ['NONE', 'ACCEPTED'].indexOf(commentStatus) >= 0;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,12 @@ const CONFIG = {
|
||||
// messages through the websocket to keep the socket alive.
|
||||
KEEP_ALIVE: process.env.TALK_KEEP_ALIVE || '30s',
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Cache configuration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
CACHE_EXPIRY_COMMENT_COUNT: process.env.TALK_CACHE_EXPIRY_COMMENT_COUNT || '1hr',
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Recaptcha configuration
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -45,6 +45,7 @@ These are only used during the webpack build.
|
||||
thread. (Default `3`)
|
||||
- `TALK_DEFAULT_STREAM_TAB` (_optional_) - specify the default stream tab in the
|
||||
admin. (Default `all`)
|
||||
- `TALK_DISABLE_EMBED_POLYFILL` (_optional_) - when set to `TRUE`, the build process will not include the [babel-polyfill](https://babeljs.io/docs/usage/polyfill/) in the embed.js target. (Default `FALSE`)
|
||||
|
||||
### Database
|
||||
|
||||
@@ -127,6 +128,11 @@ The default could be read as:
|
||||
- At the moment of writing, beheviour is not attached to the flagging
|
||||
reliability, but it is recorded.
|
||||
|
||||
### Cache
|
||||
|
||||
- `TALK_CACHE_EXPIRY_COMMENT_COUNT` (_optional_) - configure the duration for which
|
||||
comment counts are cached for. (Default `1hr`)
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins configuration can be found on the [Plugins]({{ "/docs/running/plugins/" | absolute_url }}) page.
|
||||
@@ -8,6 +8,10 @@ const {
|
||||
SEARCH_NON_NULL_OR_ACCEPTED_COMMENTS,
|
||||
SEARCH_OTHERS_COMMENTS
|
||||
} = require('../../perms/constants');
|
||||
const {
|
||||
CACHE_EXPIRY_COMMENT_COUNT
|
||||
} = require('../../config');
|
||||
const ms = require('ms');
|
||||
|
||||
const CommentModel = require('../../models/comment');
|
||||
const UsersService = require('../../services/users');
|
||||
@@ -481,11 +485,11 @@ module.exports = (context) => ({
|
||||
get: new DataLoader((ids) => getComments(context, ids)),
|
||||
getByQuery: (query) => getCommentsByQuery(context, query),
|
||||
getCountByQuery: (query) => getCommentCountByQuery(context, query),
|
||||
countByAssetID: new SharedCounterDataLoader('Comments.totalCommentCount', 3600, (ids) => getCountsByAssetID(context, ids)),
|
||||
countByAssetID: new SharedCounterDataLoader('Comments.totalCommentCount', ms(CACHE_EXPIRY_COMMENT_COUNT), (ids) => getCountsByAssetID(context, ids)),
|
||||
countByAssetIDPersonalized: (query) => getCountsByAssetIDPersonalized(context, query),
|
||||
parentCountByAssetID: new SharedCounterDataLoader('Comments.countByAssetID', 3600, (ids) => getParentCountsByAssetID(context, ids)),
|
||||
parentCountByAssetID: new SharedCounterDataLoader('Comments.countByAssetID', ms(CACHE_EXPIRY_COMMENT_COUNT), (ids) => getParentCountsByAssetID(context, ids)),
|
||||
parentCountByAssetIDPersonalized: (query) => getParentCountByAssetIDPersonalized(context, query),
|
||||
countByParentID: new SharedCounterDataLoader('Comments.countByParentID', 3600, (ids) => getCountsByParentID(context, ids)),
|
||||
countByParentID: new SharedCounterDataLoader('Comments.countByParentID', ms(CACHE_EXPIRY_COMMENT_COUNT), (ids) => getCountsByParentID(context, ids)),
|
||||
countByParentIDPersonalized: (query) => getCountByParentIDPersonalized(context, query),
|
||||
genRecentReplies: new DataLoader((ids) => genRecentReplies(context, ids)),
|
||||
genRecentComments: new DataLoader((ids) => genRecentComments(context, ids))
|
||||
|
||||
+13
-7
@@ -33,6 +33,7 @@ const buildEmbeds = [
|
||||
|
||||
const config = {
|
||||
devtool: 'cheap-module-source-map',
|
||||
target: 'web',
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
publicPath: '/client/',
|
||||
@@ -153,11 +154,15 @@ if (process.env.NODE_ENV === 'production') {
|
||||
|
||||
// Applies the base configuration to the following entries.
|
||||
const applyConfig = (entries, root = {}) => _.merge({}, config, {
|
||||
entry: entries.reduce((entry, {name, path}) => {
|
||||
entry[name] = [
|
||||
'babel-polyfill',
|
||||
path
|
||||
];
|
||||
entry: entries.reduce((entry, {name, path, disablePolyfill = false}) => {
|
||||
if (disablePolyfill) {
|
||||
entry[name] = path;
|
||||
} else {
|
||||
entry[name] = [
|
||||
'babel-polyfill',
|
||||
path
|
||||
];
|
||||
}
|
||||
|
||||
return entry;
|
||||
}, {})
|
||||
@@ -171,7 +176,8 @@ module.exports = [
|
||||
// Load in the root embed.
|
||||
{
|
||||
name: 'embed',
|
||||
path: path.join(__dirname, 'client/coral-embed/src/index')
|
||||
path: path.join(__dirname, 'client/coral-embed/src/index'),
|
||||
disablePolyfill: process.env.TALK_DISABLE_EMBED_POLYFILL === 'TRUE'
|
||||
}
|
||||
|
||||
], {
|
||||
@@ -183,7 +189,7 @@ module.exports = [
|
||||
// All framework targets/embeds/plugins.
|
||||
applyConfig([
|
||||
|
||||
// // Load in all the targets.
|
||||
// Load in all the targets.
|
||||
...buildTargets.map((target) => ({
|
||||
name: `${target}/bundle`,
|
||||
path: path.join(__dirname, 'client/', target, '/src/index')
|
||||
|
||||
Reference in New Issue
Block a user