Merge pull request #2064 from hmhealey/plt882
PLT-882 Ephemeral Messages and Out-Of-Channel mentions
Этот коммит содержится в:
@@ -40,10 +40,6 @@ const holders = defineMessages({
|
||||
write: {
|
||||
id: 'create_post.write',
|
||||
defaultMessage: 'Write a message...'
|
||||
},
|
||||
deleteMsg: {
|
||||
id: 'create_post.deleteMsg',
|
||||
defaultMessage: '(message deleted)'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -70,7 +66,6 @@ class CreatePost extends React.Component {
|
||||
this.sendMessage = this.sendMessage.bind(this);
|
||||
|
||||
PostStore.clearDraftUploads();
|
||||
PostStore.deleteMessage(this.props.intl.formatMessage(holders.deleteMsg));
|
||||
|
||||
const draft = this.getCurrentDraft();
|
||||
|
||||
@@ -506,4 +501,4 @@ CreatePost.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(CreatePost);
|
||||
export default injectIntl(CreatePost);
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class DeletePostModal extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
PostStore.removePost(this.state.post.id, this.state.post.channel_id);
|
||||
PostStore.deletePost(this.state.post);
|
||||
AsyncClient.getPosts(this.state.post.channel_id);
|
||||
},
|
||||
(err) => {
|
||||
|
||||
@@ -44,7 +44,6 @@ class PostBody extends React.Component {
|
||||
|
||||
this.state = {
|
||||
links: linkData.links,
|
||||
message: linkData.text,
|
||||
post: this.props.post,
|
||||
hasUserProfiles: profiles && Object.keys(profiles).length > 1
|
||||
};
|
||||
@@ -106,7 +105,9 @@ class PostBody extends React.Component {
|
||||
if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) {
|
||||
this.embed = this.createEmbed(linkData.links[0]);
|
||||
}
|
||||
this.setState({links: linkData.links, message: linkData.text});
|
||||
this.setState({
|
||||
links: linkData.links
|
||||
});
|
||||
}
|
||||
|
||||
createEmbed(link) {
|
||||
@@ -310,6 +311,23 @@ class PostBody extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let message;
|
||||
if (this.props.post.state === Constants.POST_DELETED) {
|
||||
message = (
|
||||
<FormattedMessage
|
||||
id='post_body.deleted'
|
||||
defaultMessage='(message deleted)'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
message = (
|
||||
<span
|
||||
onClick={TextFormatting.handleClick}
|
||||
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message)}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{comment}
|
||||
@@ -320,11 +338,7 @@ class PostBody extends React.Component {
|
||||
className={postClass}
|
||||
>
|
||||
{loading}
|
||||
<span
|
||||
ref='message_span'
|
||||
onClick={TextFormatting.handleClick}
|
||||
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.message)}}
|
||||
/>
|
||||
{message}
|
||||
</div>
|
||||
<PostBodyAdditionalContent
|
||||
post={this.state.post}
|
||||
@@ -346,4 +360,4 @@ PostBody.propTypes = {
|
||||
handleCommentClick: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(PostBody);
|
||||
export default injectIntl(PostBody);
|
||||
|
||||
@@ -23,13 +23,14 @@ export default class PostInfo extends React.Component {
|
||||
};
|
||||
|
||||
this.handlePermalinkCopy = this.handlePermalinkCopy.bind(this);
|
||||
this.removePost = this.removePost.bind(this);
|
||||
}
|
||||
createDropdown() {
|
||||
var post = this.props.post;
|
||||
var isOwner = UserStore.getCurrentId() === post.user_id;
|
||||
var isAdmin = Utils.isAdmin(UserStore.getCurrentUser().roles);
|
||||
|
||||
if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) {
|
||||
if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || Utils.isPostEphemeral(post)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -166,6 +167,25 @@ export default class PostInfo extends React.Component {
|
||||
this.setState({copiedLink: false});
|
||||
}
|
||||
}
|
||||
removePost() {
|
||||
EventHelpers.emitRemovePost(this.props.post);
|
||||
}
|
||||
createRemovePostButton(post) {
|
||||
if (!Utils.isPostEphemeral(post)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href='#'
|
||||
className='post__remove theme'
|
||||
type='button'
|
||||
onClick={this.removePost}
|
||||
>
|
||||
{'×'}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
var post = this.props.post;
|
||||
var comments = '';
|
||||
@@ -178,7 +198,7 @@ export default class PostInfo extends React.Component {
|
||||
commentCountText = '';
|
||||
}
|
||||
|
||||
if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && post.state !== Constants.POST_DELETED) {
|
||||
if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !Utils.isPostEphemeral(post)) {
|
||||
comments = (
|
||||
<a
|
||||
href='#'
|
||||
@@ -264,6 +284,7 @@ export default class PostInfo extends React.Component {
|
||||
>
|
||||
{permalinkOverlay}
|
||||
</Overlay>
|
||||
{this.createRemovePostButton(post)}
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import Constants from '../utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
export function emitChannelClickEvent(channel) {
|
||||
AsyncClient.getChannels(true);
|
||||
@@ -180,3 +181,27 @@ export function emitPreferenceChangedEvent(preference) {
|
||||
preference
|
||||
});
|
||||
}
|
||||
|
||||
export function emitRemovePost(post) {
|
||||
AppDispatcher.handleViewAction({
|
||||
type: Constants.ActionTypes.REMOVE_POST,
|
||||
post
|
||||
});
|
||||
}
|
||||
|
||||
export function sendEphemeralPost(message, channelId) {
|
||||
const timestamp = Utils.getTimestamp();
|
||||
const post = {
|
||||
id: Utils.generateId(),
|
||||
user_id: '0',
|
||||
channel_id: channelId || ChannelStore.getCurrentId(),
|
||||
message,
|
||||
type: Constants.POST_TYPE_EPHEMERAL,
|
||||
create_at: timestamp,
|
||||
update_at: timestamp,
|
||||
filenames: [],
|
||||
props: {}
|
||||
};
|
||||
|
||||
emitPostRecievedEvent(post);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ class PostStoreClass extends EventEmitter {
|
||||
this.clearFocusedPost = this.clearFocusedPost.bind(this);
|
||||
this.clearChannelVisibility = this.clearChannelVisibility.bind(this);
|
||||
|
||||
this.deletePost = this.deletePost.bind(this);
|
||||
this.removePost = this.removePost.bind(this);
|
||||
|
||||
this.getPendingPosts = this.getPendingPosts.bind(this);
|
||||
@@ -65,10 +66,6 @@ class PostStoreClass extends EventEmitter {
|
||||
this.clearPendingPosts = this.clearPendingPosts.bind(this);
|
||||
this.updatePendingPost = this.updatePendingPost.bind(this);
|
||||
|
||||
this.storeUnseenDeletedPost = this.storeUnseenDeletedPost.bind(this);
|
||||
this.getUnseenDeletedPosts = this.getUnseenDeletedPosts.bind(this);
|
||||
this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this);
|
||||
|
||||
// These functions are bad and work should be done to remove this system when the RHS dies
|
||||
this.storeSelectedPost = this.storeSelectedPost.bind(this);
|
||||
this.getSelectedPost = this.getSelectedPost.bind(this);
|
||||
@@ -211,28 +208,6 @@ class PostStoreClass extends EventEmitter {
|
||||
postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order);
|
||||
}
|
||||
|
||||
// Add deleted posts
|
||||
if (this.postsInfo[id].hasOwnProperty('deletedPosts')) {
|
||||
Object.assign(postList.posts, this.postsInfo[id].deletedPosts);
|
||||
|
||||
for (const postID in this.postsInfo[id].deletedPosts) {
|
||||
if (this.postsInfo[id].deletedPosts.hasOwnProperty(postID)) {
|
||||
postList.order.push(postID);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge would be faster
|
||||
postList.order.sort((a, b) => {
|
||||
if (postList.posts[a].create_at > postList.posts[b].create_at) {
|
||||
return -1;
|
||||
}
|
||||
if (postList.posts[a].create_at < postList.posts[b].create_at) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
return postList;
|
||||
}
|
||||
|
||||
@@ -286,15 +261,6 @@ class PostStoreClass extends EventEmitter {
|
||||
if (combinedPosts.order.indexOf(pid) === -1) {
|
||||
combinedPosts.order.push(pid);
|
||||
}
|
||||
} else {
|
||||
if (pid in combinedPosts.posts) {
|
||||
Reflect.deleteProperty(combinedPosts.posts, pid);
|
||||
}
|
||||
|
||||
const index = combinedPosts.order.indexOf(pid);
|
||||
if (index !== -1) {
|
||||
combinedPosts.order.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,6 +331,22 @@ class PostStoreClass extends EventEmitter {
|
||||
this.postsInfo[id].atBottom = atBottom;
|
||||
}
|
||||
|
||||
deletePost(post) {
|
||||
const postList = this.postsInfo[post.channel_id].postList;
|
||||
|
||||
if (isPostListNull(postList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (post.id in postList.posts) {
|
||||
// make sure to copy the post so that component state changes work properly
|
||||
postList.posts[post.id] = Object.assign({}, post, {
|
||||
state: Constants.POST_DELETED,
|
||||
filenames: []
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removePost(post) {
|
||||
const channelId = post.channel_id;
|
||||
this.makePostsInfo(channelId);
|
||||
@@ -439,37 +421,6 @@ class PostStoreClass extends EventEmitter {
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
storeUnseenDeletedPost(post) {
|
||||
let posts = this.getUnseenDeletedPosts(post.channel_id);
|
||||
|
||||
if (!posts) {
|
||||
posts = {};
|
||||
}
|
||||
|
||||
post.message = this.delete_message;
|
||||
post.state = Constants.POST_DELETED;
|
||||
post.filenames = [];
|
||||
|
||||
posts[post.id] = post;
|
||||
|
||||
this.makePostsInfo(post.channel_id);
|
||||
this.postsInfo[post.channel_id].deletedPosts = posts;
|
||||
}
|
||||
|
||||
getUnseenDeletedPosts(channelId) {
|
||||
if (this.postsInfo.hasOwnProperty(channelId)) {
|
||||
return this.postsInfo[channelId].deletedPosts;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
clearUnseenDeletedPosts(channelId) {
|
||||
if (this.postsInfo.hasOwnProperty(channelId)) {
|
||||
Reflect.deleteProperty(this.postsInfo[channelId], 'deletedPosts');
|
||||
}
|
||||
}
|
||||
|
||||
storeSelectedPost(postList) {
|
||||
this.selectedPost = postList;
|
||||
}
|
||||
@@ -581,9 +532,6 @@ class PostStoreClass extends EventEmitter {
|
||||
|
||||
return commentCount;
|
||||
}
|
||||
deleteMessage(msg) {
|
||||
this.delete_message = msg;
|
||||
}
|
||||
}
|
||||
|
||||
var PostStore = new PostStoreClass();
|
||||
@@ -615,7 +563,6 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
case ActionTypes.CLICK_CHANNEL:
|
||||
PostStore.clearFocusedPost();
|
||||
PostStore.clearChannelVisibility(action.id, true);
|
||||
PostStore.clearUnseenDeletedPosts(action.prev);
|
||||
break;
|
||||
case ActionTypes.CREATE_POST:
|
||||
PostStore.storePendingPost(action.post);
|
||||
@@ -623,7 +570,10 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
PostStore.jumpPostsViewToBottom();
|
||||
break;
|
||||
case ActionTypes.POST_DELETED:
|
||||
PostStore.storeUnseenDeletedPost(action.post);
|
||||
PostStore.deletePost(action.post);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.REMOVE_POST:
|
||||
PostStore.removePost(action.post);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
|
||||
@@ -109,6 +109,7 @@ class SocketStoreClass extends EventEmitter {
|
||||
handleMessage(msg) {
|
||||
switch (msg.action) {
|
||||
case SocketEvents.POSTED:
|
||||
case SocketEvents.EPHEMERAL_MESSAGE:
|
||||
handleNewPostEvent(msg, this.translations);
|
||||
break;
|
||||
|
||||
@@ -179,7 +180,6 @@ function handleNewPostEvent(msg, translations) {
|
||||
mentions = JSON.parse(msg.props.mentions);
|
||||
}
|
||||
|
||||
const channelType = msgProps.channel_type;
|
||||
const channel = ChannelStore.get(msg.channel_id);
|
||||
const user = UserStore.getCurrentUser();
|
||||
const member = ChannelStore.getMember(msg.channel_id);
|
||||
@@ -191,7 +191,7 @@ function handleNewPostEvent(msg, translations) {
|
||||
|
||||
if (notifyLevel === 'none') {
|
||||
return;
|
||||
} else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channelType !== Constants.DM_CHANNEL) {
|
||||
} else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== Constants.DM_CHANNEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ export default {
|
||||
LEAVE_CHANNEL: null,
|
||||
CREATE_POST: null,
|
||||
POST_DELETED: null,
|
||||
REMOVE_POST: null,
|
||||
|
||||
RECIEVED_CHANNELS: null,
|
||||
RECIEVED_CHANNEL: null,
|
||||
@@ -78,7 +79,8 @@ export default {
|
||||
USER_ADDED: 'user_added',
|
||||
USER_REMOVED: 'user_removed',
|
||||
TYPING: 'typing',
|
||||
PREFERENCE_CHANGED: 'preference_changed'
|
||||
PREFERENCE_CHANGED: 'preference_changed',
|
||||
EPHEMERAL_MESSAGE: 'ephemeral_message'
|
||||
},
|
||||
|
||||
//SPECIAL_MENTIONS: ['all', 'channel'],
|
||||
@@ -126,6 +128,7 @@ export default {
|
||||
POST_LOADING: 'loading',
|
||||
POST_FAILED: 'failed',
|
||||
POST_DELETED: 'deleted',
|
||||
POST_TYPE_EPHEMERAL: 'system_ephemeral',
|
||||
POST_TYPE_JOIN_LEAVE: 'system_join_leave',
|
||||
SYSTEM_MESSAGE_PREFIX: 'system_',
|
||||
SYSTEM_MESSAGE_PROFILE_NAME: 'System',
|
||||
|
||||
@@ -1355,3 +1355,7 @@ export function languages() {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
export function isPostEphemeral(post) {
|
||||
return post.type === Constants.POST_TYPE_EPHEMERAL || post.state === Constants.POST_DELETED;
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ body.ios {
|
||||
@include legacy-pie-clearfix;
|
||||
|
||||
&:hover {
|
||||
.dropdown, .comment-icon__container, .post__reply {
|
||||
.dropdown, .comment-icon__container, .post__reply, .post__remove {
|
||||
visibility: visible;
|
||||
}
|
||||
.permalink-icon {
|
||||
@@ -646,6 +646,13 @@ body.ios {
|
||||
}
|
||||
}
|
||||
|
||||
.post__remove {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
margin-right: 5px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.post__body {
|
||||
word-wrap: break-word;
|
||||
padding: 0.2em 0.5em 0em;
|
||||
|
||||
@@ -566,7 +566,6 @@
|
||||
"create_post.comment": "Comment",
|
||||
"create_post.post": "Post",
|
||||
"create_post.write": "Write a message...",
|
||||
"create_post.deleteMsg": "(message deleted)",
|
||||
"create_post.tutorialTip": "<h4>Sending Messages</h4><p>Type here to write a message and press <strong>Enter</strong> to post it.</p><p>Click the <strong>Attachment</strong> button to upload an image or a file.</p>",
|
||||
"delete_channel.channel": "channel",
|
||||
"delete_channel.group": "group",
|
||||
@@ -772,6 +771,7 @@
|
||||
"members_popover.title": "Members",
|
||||
"post_attachment.collapse": "▲ collapse text",
|
||||
"post_attachment.more": "▼ read more",
|
||||
"post_body.deleted": "(message deleted)",
|
||||
"post_body.plusOne": " plus 1 other file",
|
||||
"post_body.plusMore": " plus {count} other files",
|
||||
"post_body.commentedOn": "Commented on {name}{apostrophe} message: ",
|
||||
@@ -1257,4 +1257,4 @@
|
||||
"intro_messages.beginning": "Beginning of {name}",
|
||||
"intro_messages.invite": "Invite others to this {type}",
|
||||
"intro_messages.setHeader": "Set a Header"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,7 +585,6 @@
|
||||
"create_comment.file": "Subiendo archivo",
|
||||
"create_comment.files": "Subiendo archivos",
|
||||
"create_post.comment": "Comentario",
|
||||
"create_post.deleteMsg": "(mensaje eliminado)",
|
||||
"create_post.post": "Mensaje",
|
||||
"create_post.tutorialTip": "<h4>Enviar Mensajes</h4> <p>Escribe aquí para redactar un mensaje y presiona <strong>Retorno</strong> para enviarlo.</p><p>Pincha el botón de <strong>Adjuntar</strong> para subir una imagen o archivo.</p>",
|
||||
"create_post.write": "Escribe un mensaje...",
|
||||
@@ -805,6 +804,7 @@
|
||||
"post_attachment.collapse": "▲ colapsar texto",
|
||||
"post_attachment.more": "▼ leer más",
|
||||
"post_body.commentedOn": "Comentó el mensaje de {name}{apostrophe}: ",
|
||||
"post_body.deleted": "(mensaje eliminado)",
|
||||
"post_body.plusMore": " más {count} otros archivos",
|
||||
"post_body.plusOne": " más 1 archivo",
|
||||
"post_body.retry": "Reintentar",
|
||||
@@ -1216,4 +1216,4 @@
|
||||
"view_image_popover.download": "Descargar",
|
||||
"view_image_popover.file": "Archivo {count} de {total}",
|
||||
"view_image_popover.publicLink": "Obtener Enlace Público"
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user