PLT-6215 Major post list refactor (#6501)

* Major post list refactor

* Fix post and thread deletion

* Fix preferences not selecting correctly

* Fix military time displaying

* Fix UP key for editing posts

* Fix ESLint error

* Various fixes and updates per feedback

* Fix for permalink view

* Revert to old scrolling method and various fixes

* Add floating timestamp, new message indicator, scroll arrows

* Update post loading for focus mode and add visibility limit

* Fix pinning posts and a react warning

* Add loading UI updates from Asaad

* Fix refreshing loop

* Temporarily bump post visibility limit

* Update infinite scrolling

* Remove infinite scrolling
Этот коммит содержится в:
Joram Wilander
2017-06-18 14:42:32 -04:00
коммит произвёл GitHub
родитель 0231e95f1c
Коммит ab67f6e257
90 изменённых файлов: 2464 добавлений и 3986 удалений

Просмотреть файл

@@ -0,0 +1,31 @@
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {removePost, addReaction} from 'mattermost-redux/actions/posts';
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {Preferences} from 'utils/constants.jsx';
import PostInfo from './post_info.jsx';
function mapStateToProps(state, ownProps) {
return {
...ownProps,
useMilitaryTime: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false),
isFlagged: getBool(state, Preferences.CATEGORY_FLAGGED_POST, ownProps.post.id)
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
removePost,
addReaction
}, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(PostInfo);

Просмотреть файл

@@ -0,0 +1,243 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import PostTime from 'components/post_view/post_time.jsx';
import PostFlagIcon from 'components/post_view/post_flag_icon.jsx';
import CommentIcon from 'components/common/comment_icon.jsx';
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
import DotMenu from 'components/dot_menu';
import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx';
import React from 'react';
import PropTypes from 'prop-types';
import {FormattedMessage} from 'react-intl';
export default class PostInfo extends React.PureComponent {
static propTypes = {
/*
* The post to render the info for
*/
post: PropTypes.object.isRequired,
/*
* Function called when the comment icon is clicked
*/
handleCommentClick: PropTypes.func.isRequired,
/*
* Funciton called when the post options dropdown is opened
*/
handleDropdownOpened: PropTypes.func.isRequired,
/*
* Set to display in 24 hour format
*/
useMilitaryTime: PropTypes.bool.isRequired,
/*
* Set to mark the post as flagged
*/
isFlagged: PropTypes.bool,
/*
* The number of replies in the same thread as this post
*/
replyCount: PropTypes.number,
/*
* Post identifiers for selenium tests
*/
lastPostCount: PropTypes.number,
/**
* Function to get the post list HTML element
*/
getPostList: PropTypes.func.isRequired,
actions: PropTypes.shape({
/*
* Function to remove the post
*/
removePost: PropTypes.func.isRequired,
/*
* Function to add a reaction to the post
*/
addReaction: PropTypes.func.isRequired
}).isRequired
}
constructor(props) {
super(props);
this.removePost = this.removePost.bind(this);
this.reactEmojiClick = this.reactEmojiClick.bind(this);
this.state = {
showEmojiPicker: false,
reactionPickerOffset: 21,
canEdit: PostUtils.canEditPost(props.post, this.editDisableAction)
};
}
toggleEmojiPicker = () => {
const showEmojiPicker = !this.state.showEmojiPicker;
this.setState({showEmojiPicker});
this.props.handleDropdownOpened(showEmojiPicker);
}
hideEmojiPicker = () => {
this.setState({showEmojiPicker: false});
this.props.handleDropdownOpened(false);
}
removePost() {
this.props.actions.removePost(this.props.post);
}
createRemovePostButton() {
return (
<a
href='#'
className='post__remove theme'
type='button'
onClick={this.removePost}
>
{'×'}
</a>
);
}
reactEmojiClick(emoji) {
const pickerOffset = 21;
this.setState({showEmojiPicker: false, reactionPickerOffset: pickerOffset});
const emojiName = emoji.name || emoji.aliases[0];
this.props.actions.addReaction(this.props.post.id, emojiName);
}
getDotMenu = () => {
return this.refs.dotMenu;
}
render() {
const post = this.props.post;
let idCount = -1;
if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) {
idCount = this.props.lastPostCount;
}
const isEphemeral = Utils.isPostEphemeral(post);
const isSystemMessage = PostUtils.isSystemMessage(post);
let comments = null;
let react = null;
if (!isEphemeral && !post.failed && !isSystemMessage) {
comments = (
<CommentIcon
idPrefix='commentIcon'
idCount={idCount}
handleCommentClick={this.props.handleCommentClick}
commentCount={this.props.replyCount}
id={post.channel_id + '_' + post.id}
/>
);
if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) {
react = (
<span>
<EmojiPickerOverlay
show={this.state.showEmojiPicker}
container={this.props.getPostList}
target={this.getDotMenu}
onHide={this.hideEmojiPicker}
onEmojiClick={this.reactEmojiClick}
/>
<a
href='#'
className='reacticon__container'
onClick={this.toggleEmojiPicker}
>
<i className='fa fa-smile-o'/>
</a>
</span>
);
}
}
let options;
if (isEphemeral) {
options = (
<div className='col col__remove'>
{this.createRemovePostButton()}
</div>
);
} else if (!post.failed) {
const dotMenu = (
<DotMenu
idPrefix={Constants.CENTER}
idCount={idCount}
post={this.props.post}
commentCount={this.props.replyCount}
isFlagged={this.props.isFlagged}
handleCommentClick={this.props.handleCommentClick}
handleDropdownOpened={this.props.handleDropdownOpened}
/>
);
if (dotMenu) {
options = (
<div
ref='dotMenu'
className='col col__reply'
>
{dotMenu}
{react}
{comments}
</div>
);
}
}
let pinnedBadge;
if (post.is_pinned) {
pinnedBadge = (
<span className='post__pinned-badge'>
<FormattedMessage
id='post_info.pinned'
defaultMessage='Pinned'
/>
</span>
);
}
return (
<div className='post__header--info'>
<div className='col'>
<PostTime
eventTime={post.create_at}
useMilitaryTime={this.props.useMilitaryTime}
postId={post.id}
/>
{pinnedBadge}
{this.state.showEmojiPicker}
<PostFlagIcon
idPrefix={'centerPostFlag'}
idCount={idCount}
postId={post.id}
isFlagged={this.props.isFlagged}
isEphemeral={isEphemeral}
/>
</div>
{options}
</div>
);
}
}