diff --git a/Makefile b/Makefile
index d8250c07f6..305926e5bc 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ travis:
@cd web/react/ && npm install
@echo Checking for style guide compliance
- cd web/react && $(ESLINT) components/* dispatcher/* pages/* stores/* utils/*
+ cd web/react && $(ESLINT) --quiet components/* dispatcher/* pages/* stores/* utils/*
@$(GO) build $(GOFLAGS) ./...
@$(GO) install $(GOFLAGS) -a ./...
diff --git a/README.md b/README.md
index fd695071c3..fc6698208c 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ There are multiple ways to install Mattermost depending on your needs.
#### Development Install
-- [Developer Machine Setup](scripts/README_DEV.md) - Setup your local machine development environment using Docker on Mac OSX or Ubuntu.
+- [Developer Machine Setup](doc/install/dev-setup.md) - Setup your local machine development environment using Docker on Mac OSX or Ubuntu.
#### Production Deployment
diff --git a/web/react/.eslintrc b/web/react/.eslintrc
index ab000e9413..53cc759139 100644
--- a/web/react/.eslintrc
+++ b/web/react/.eslintrc
@@ -4,7 +4,9 @@
"jsx": true,
"blockBindings": true,
"modules": true,
- "classes": true
+ "classes": true,
+ "arrowFunctions": true,
+ "defaultParams": true,
},
"plugins": [
"react"
@@ -21,36 +23,36 @@
"rules": {
"comma-dangle": [2, "never"],
"no-cond-assign": [2, "except-parens"],
- "no-console": 1,
- "no-constant-condition": 1,
- "no-debugger": 1,
+ "no-console": 2,
+ "no-constant-condition": 2,
+ "no-debugger": 2,
"no-dupe-args": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
- "no-empty": 1,
- "no-ex-assign": 1,
+ "no-empty": 2,
+ "no-ex-assign": 2,
"no-extra-semi": 2,
- "no-func-assign": 1,
+ "no-func-assign": 2,
"no-inner-declarations": 0,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
+ "no-unexpected-multiline": 2,
"no-unreachable": 2,
"valid-typeof": 2,
- "no-unexpected-multiline": 2,
- "block-scoped-var": 1,
- "complexity": [0, 8],
+ "block-scoped-var": 2,
+ "complexity": [1, 8],
"consistent-return": 2,
"curly": [2, "all"],
- "dot-notation": 2,
"dot-location": [2, "object"],
+ "dot-notation": 2,
"eqeqeq": [2, "smart"],
- "guard-for-in": 1,
- "no-alert": 1,
+ "guard-for-in": 2,
+ "no-alert": 2,
"no-array-constructor": 2,
"no-caller": 2,
- "no-div-regex": 1,
- "no-else-return": 1,
+ "no-div-regex": 2,
+ "no-else-return": 2,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
@@ -58,7 +60,7 @@
"no-implied-eval": 2,
"no-iterator": 2,
"no-labels": 2,
- "no-lone-blocks": 1,
+ "no-lone-blocks": 2,
"no-loop-func": 2,
"no-multi-spaces": [2, { "exceptions": { "Property": false } }],
"no-multi-str": 0,
@@ -78,10 +80,11 @@
"no-self-compare": 2,
"no-sequences": 2,
"no-throw-literal": 2,
- "no-unused-expressions": 2,
"no-undef-init": 2,
+ "no-unused-expressions": 2,
+ "no-useless-concat": 1,
"no-void": 2,
- "no-warning-comments": 0,
+ "no-warning-comments": 1,
"no-with": 2,
"radix": 2,
"vars-on-top": 0,
@@ -135,14 +138,33 @@
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"wrap-regex": 2,
+ // ES6 stuff
+ "arrow-parens": [2, "always"],
+ "arrow-spacing": [2, { "before": true, "after": true }],
+ "constructor-super": 2,
+ "generator-star-spacing": [2, {"before": false, "after": true}],
+ "no-class-assign": 2,
+ "no-const-assign": 2,
+ "no-dupe-class-members": 2,
+ "no-this-before-super": 2,
+ "no-var": 0,
+ "object-shorthand": [1, "always"],
+ "prefer-arrow-callback": 1,
+ "prefer-const": 1,
+ "prefer-spread": 2,
+ "prefer-reflect": 1,
+ "prefer-template": 0,
+ "require-yield": 2,
+
// React Specific
"react/display-name": [2, { "acceptTranspilerName": true }],
"react/jsx-boolean-value": [2, "always"],
+ "react/jsx-closing-bracket-location": [2, { "location": "tag-aligned" }],
"react/jsx-curly-spacing": [2, "never"],
+ "react/jsx-indent-props": [2, 4],
"react/jsx-max-props-per-line": [2, { "maximum": 1 }],
- // SOON "react/jsx-indent-props": [2, 4],
"react/jsx-no-duplicate-props": [2, { "ignoreCase": false }],
- "react/jsx-no-literals": 0,
+ "react/jsx-no-literals": 1,
"react/jsx-no-undef": 2,
"react/jsx-quotes": [2, "single", "avoid-escape"],
"react/jsx-uses-react": 2,
@@ -151,10 +173,11 @@
"react/no-did-mount-set-state": 2,
"react/no-did-update-set-state": 2,
"react/no-multi-comp": 2,
+ "react/no-set-state": 0,
"react/no-unknown-property": 2,
"react/prop-types": 2,
- "react/sort-comp": 0,
"react/self-closing-comp": 2,
+ "react/sort-comp": 0,
"react/wrap-multilines": 2
}
}
diff --git a/web/react/components/channel_info_modal.jsx b/web/react/components/channel_info_modal.jsx
index fae86b4b9c..fdd9a5c179 100644
--- a/web/react/components/channel_info_modal.jsx
+++ b/web/react/components/channel_info_modal.jsx
@@ -34,27 +34,27 @@ export default class CommandList extends React.Component {
return (
{channel.display_name}
@@ -75,9 +75,9 @@ export default class CommandList extends React.Component {
diff --git a/web/react/components/channel_invite_modal.jsx b/web/react/components/channel_invite_modal.jsx
index f76ede604c..5feeb4e889 100644
--- a/web/react/components/channel_invite_modal.jsx
+++ b/web/react/components/channel_invite_modal.jsx
@@ -146,8 +146,8 @@ export default class ChannelInviteModal extends React.Component {
aria-hidden='true'
>
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx
index 1736465977..83067240dd 100644
--- a/web/react/components/channel_notifications.jsx
+++ b/web/react/components/channel_notifications.jsx
@@ -162,6 +162,13 @@ export default class ChannelNotifications extends React.Component {
e.preventDefault();
}.bind(this);
+ let curChannel = ChannelStore.get(this.state.channelId);
+ let extraInfo = (These settings will override the global notification settings);
+
+ if (curChannel && curChannel.display_name) {
+ extraInfo = (These settings will override the global notification settings for the {curChannel.display_name} channel);
+ }
+
return (
);
}
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index ce4ebac9e9..871b72a434 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -117,7 +117,6 @@ export default class CreatePost extends React.Component {
Client.createPost(post, channel,
function handlePostSuccess(data) {
- this.resizePostHolder();
AsyncClient.getPosts();
let member = ChannelStore.getMember(channel.id);
@@ -129,7 +128,7 @@ export default class CreatePost extends React.Component {
type: ActionTypes.RECIEVED_POST,
post: data
});
- }.bind(this),
+ },
function handlePostError(err) {
let state = {};
@@ -149,9 +148,6 @@ export default class CreatePost extends React.Component {
);
}
}
- componentDidUpdate() {
- this.resizePostHolder();
- }
postMsgKeyPress(e) {
if (e.which === 13 && !e.shiftKey && !e.altKey) {
e.preventDefault();
@@ -166,7 +162,6 @@ export default class CreatePost extends React.Component {
}
}
handleUserInput(messageText) {
- this.resizePostHolder();
this.setState({messageText: messageText});
let draft = PostStore.getCurrentDraft();
@@ -296,7 +291,8 @@ export default class CreatePost extends React.Component {
+ uploadsInProgress={this.state.uploadsInProgress}
+ />
);
}
@@ -317,11 +313,13 @@ export default class CreatePost extends React.Component {
+ ref='textbox'
+ />
+ channelId=''
+ />
{postError}
diff --git a/web/react/components/edit_post_modal.jsx b/web/react/components/edit_post_modal.jsx
index fef60c7150..ad7bd30b51 100644
--- a/web/react/components/edit_post_modal.jsx
+++ b/web/react/components/edit_post_modal.jsx
@@ -88,7 +88,8 @@ export default class EditPostModal extends React.Component {
id='edit_post'
role='dialog'
tabIndex='-1'
- aria-hidden='true' >
+ aria-hidden='true'
+ >
@@ -97,7 +98,8 @@ export default class EditPostModal extends React.Component {
className='close'
data-dismiss='modal'
aria-label='Close'
- onClick={this.handleEditClose}>
+ onClick={this.handleEditClose}
+ >
×
Edit {this.state.title}
@@ -110,20 +112,22 @@ export default class EditPostModal extends React.Component {
createMessage='Edit the post...'
id='edit_textbox'
ref='editbox'
- />
+ />
{error}
diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx
index 396e201f80..95948c8dd7 100644
--- a/web/react/components/email_verify.jsx
+++ b/web/react/components/email_verify.jsx
@@ -24,12 +24,14 @@ export default class EmailVerify extends React.Component {
} else {
title = config.SiteName + ' Email Not Verified';
body =
Please verify your email address. Check your inbox for an email.
;
- resend = (
);
+ resend = (
+
+ );
}
return (
diff --git a/web/react/components/error_bar.jsx b/web/react/components/error_bar.jsx
index 95f3e572ce..87d94a41dc 100644
--- a/web/react/components/error_bar.jsx
+++ b/web/react/components/error_bar.jsx
@@ -69,7 +69,8 @@ export default class ErrorBar extends React.Component {
+ onClick={this.handleClose}
+ >
×
diff --git a/web/react/components/file_attachment.jsx b/web/react/components/file_attachment.jsx
index 5d78550372..78693df989 100644
--- a/web/react/components/file_attachment.jsx
+++ b/web/react/components/file_attachment.jsx
@@ -101,10 +101,13 @@ export default class FileAttachment extends React.Component {
var thumbnail;
if (type === 'image') {
- thumbnail = (
);
+ thumbnail = (
+
+ );
} else {
thumbnail =
;
}
@@ -135,20 +138,23 @@ export default class FileAttachment extends React.Component {
return (
+ key={filename}
+ >
+ data-target={'#' + this.props.modalId}
+ >
{thumbnail}
+ className='post-image__name'
+ >
{trimmedFilename}
diff --git a/web/react/components/file_attachment_list.jsx b/web/react/components/file_attachment_list.jsx
index d93f461e86..abe72089ae 100644
--- a/web/react/components/file_attachment_list.jsx
+++ b/web/react/components/file_attachment_list.jsx
@@ -28,7 +28,8 @@ export default class FileAttachmentList extends React.Component {
filename={filenames[i]}
index={i}
modalId={modalId}
- handleImageClick={this.handleImageClick} />
+ handleImageClick={this.handleImageClick}
+ />
);
}
@@ -42,7 +43,8 @@ export default class FileAttachmentList extends React.Component {
userId={this.props.userId}
modalId={modalId}
startId={this.state.startImgId}
- filenames={filenames} />
+ filenames={filenames}
+ />
);
}
diff --git a/web/react/components/find_team.jsx b/web/react/components/find_team.jsx
index 4040a771dd..52988886c2 100644
--- a/web/react/components/find_team.jsx
+++ b/web/react/components/find_team.jsx
@@ -77,7 +77,10 @@ export default class FindTeam extends React.Component {
+ type='submit'
+ >
+ Send
+
);
diff --git a/web/react/components/member_list.jsx b/web/react/components/member_list.jsx
index f8b07e05ba..65495b569f 100644
--- a/web/react/components/member_list.jsx
+++ b/web/react/components/member_list.jsx
@@ -23,14 +23,16 @@ export default class MemberList extends React.Component {
return (
{members.map(function mymembers(member) {
- return ();
+ return (
+
+ );
}, this)}
{message}
diff --git a/web/react/components/member_list_item.jsx b/web/react/components/member_list_item.jsx
index bfce0f49f7..9a31a2e30d 100644
--- a/web/react/components/member_list_item.jsx
+++ b/web/react/components/member_list_item.jsx
@@ -36,8 +36,10 @@ export default class MemberListItem extends React.Component {
invite = (
- Add
+ className='btn btn-sm btn-primary member-invite'
+ >
+
+ {' Add'}
);
} else if (isAdmin && !isMemberAdmin && (member.id !== UserStore.getCurrentId())) {
@@ -50,7 +52,9 @@ export default class MemberListItem extends React.Component {
Make Admin
+ onClick={self.handleMakeAdmin}
+ >
+ Make Admin
);
}
@@ -62,7 +66,9 @@ export default class MemberListItem extends React.Component {
Remove Member
+ onClick={self.handleRemove}
+ >
+ Remove Member
);
}
@@ -75,14 +81,16 @@ export default class MemberListItem extends React.Component {
type='button'
id='channel_header_dropdown'
data-toggle='dropdown'
- aria-expanded='true' >
+ aria-expanded='true'
+ >
{member.roles || 'Member'}
+ aria-labelledby='channel_header_dropdown'
+ >
{makeAdminOption}
{handleRemoveOption}
@@ -98,7 +106,8 @@ export default class MemberListItem extends React.Component {
className='post-profile-img pull-left'
src={'/api/v1/users/' + member.id + '/image?time=' + timestamp}
height='36'
- width='36' />
+ width='36'
+ />
{member.username}
{member.email}
{invite}
diff --git a/web/react/components/mention.jsx b/web/react/components/mention.jsx
index 72a2a6251a..3a09e843d3 100644
--- a/web/react/components/mention.jsx
+++ b/web/react/components/mention.jsx
@@ -19,11 +19,14 @@ export default class Mention extends React.Component {
if (this.props.id === 'allmention' || this.props.id === 'channelmention') {
icon =
;
} else if (this.props.id != null) {
- icon = (
- );
+ icon = (
+
+
+
+ );
} else {
icon =
;
}
diff --git a/web/react/components/mention_list.jsx b/web/react/components/mention_list.jsx
index afea30161e..46a9d76ae5 100644
--- a/web/react/components/mention_list.jsx
+++ b/web/react/components/mention_list.jsx
@@ -216,7 +216,8 @@ export default class MentionList extends React.Component {
listId={index}
isFocused={isFocused}
handleMouseEnter={this.handleMouseEnter.bind(this, index)}
- handleClick={this.handleClick} />
+ handleClick={this.handleClick}
+ />
);
index++;
}
@@ -240,11 +241,13 @@ export default class MentionList extends React.Component {
return (
+ style={style}
+ >
+ id='mentionsbox'
+ >
{mentions}
diff --git a/web/react/components/more_channels.jsx b/web/react/components/more_channels.jsx
index 08b2d74601..ba8be12b28 100644
--- a/web/react/components/more_channels.jsx
+++ b/web/react/components/more_channels.jsx
@@ -86,15 +86,21 @@ export default class MoreChannels extends React.Component {
{channels.map(function cMap(channel, index) {
var joinButton;
if (self.state.joiningChannel === index) {
- joinButton = (

);
+ joinButton = (
+

+ );
} else {
- joinButton = (
);
+ joinButton = (
+
+ );
}
return (
@@ -152,7 +158,9 @@ export default class MoreChannels extends React.Component {
data-channeltype={this.state.channelType}
type='button'
className='btn btn-primary channel-create-btn'
- onClick={this.handleNewChannel}>Create New Channel
+ onClick={this.handleNewChannel}
+ >
+ Create New Channel
diff --git a/web/react/components/navbar_dropdown.jsx b/web/react/components/navbar_dropdown.jsx
index a949205daf..99cdfa1ad7 100644
--- a/web/react/components/navbar_dropdown.jsx
+++ b/web/react/components/navbar_dropdown.jsx
@@ -61,15 +61,17 @@ export default class NavbarDropdown extends React.Component {
if (currentUser != null) {
isAdmin = currentUser.roles.indexOf('admin') > -1;
- inviteLink = (
-
- Invite New Member
-
- );
+ inviteLink = (
+
+
+ Invite New Member
+
+
+ );
if (this.props.teamType === 'O') {
teamLink = (
@@ -89,15 +91,17 @@ export default class NavbarDropdown extends React.Component {
}
if (isAdmin) {
- manageLink = (
-
- Manage Team
-
- );
+ manageLink = (
+
+
+ Manage Team
+
+
+ );
teamSettings = (
- );
+ teams.push(
+
+
+ );
if (this.state.teams.length > 1 && this.state.currentTeam) {
var curTeamName = this.state.currentTeam.name;
this.state.teams.forEach(function listTeams(teamName) {
diff --git a/web/react/components/new_channel.jsx b/web/react/components/new_channel.jsx
index a02a4c1c0e..1a11fc652c 100644
--- a/web/react/components/new_channel.jsx
+++ b/web/react/components/new_channel.jsx
@@ -134,14 +134,16 @@ export default class NewChannelModal extends React.Component {
ref='modal'
tabIndex='-1'
role='dialog'
- aria-hidden='true'>
+ aria-hidden='true'
+ >
@@ -157,7 +159,8 @@ export default class NewChannelModal extends React.Component {
ref='display_name'
className='form-control'
placeholder='Enter display name'
- maxLength='22' />
+ maxLength='22'
+ />
{displayNameError}
@@ -167,7 +170,8 @@ export default class NewChannelModal extends React.Component {
className='form-control'
ref='channel_name'
placeholder="lowercase alphanumeric's only"
- maxLength='22' />
+ maxLength='22'
+ />
{nameError}
@@ -177,7 +181,8 @@ export default class NewChannelModal extends React.Component {
ref='channel_desc'
rows='3'
placeholder='Description'
- maxLength='1024' />
+ maxLength='1024'
+ />
{serverError}
@@ -185,13 +190,15 @@ export default class NewChannelModal extends React.Component {
diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx
index 5f4aeb9610..37de4ecc04 100644
--- a/web/react/components/post.jsx
+++ b/web/react/components/post.jsx
@@ -143,7 +143,8 @@ export default class Post extends React.Component {
className='post-profile-img'
src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp}
height='36'
- width='36' />
+ width='36'
+ />
);
}
@@ -152,7 +153,8 @@ export default class Post extends React.Component {
+ className={'post ' + sameUserClass + ' ' + rootUser + ' ' + postType + ' ' + currentUserCss}
+ >
{profilePic}
+ isLastComment={this.props.isLastComment}
+ />
+ retryPost={this.retryPost}
+ />
+ allowReply='true'
+ />
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 88fb9aec82..d9b8f20ce3 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -5,14 +5,26 @@ const FileAttachmentList = require('./file_attachment_list.jsx');
const UserStore = require('../stores/user_store.jsx');
const Utils = require('../utils/utils.jsx');
const Constants = require('../utils/constants.jsx');
+const twemoji = require('twemoji');
export default class PostBody extends React.Component {
constructor(props) {
super(props);
+ this.parseEmojis = this.parseEmojis.bind(this);
+
const linkData = Utils.extractLinks(this.props.post.message);
this.state = {links: linkData.links, message: linkData.text};
}
+ parseEmojis() {
+ twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ }
+ componentDidMount() {
+ this.parseEmojis();
+ }
+ componentDidUpdate() {
+ this.parseEmojis();
+ }
componentWillReceiveProps(nextProps) {
const linkData = Utils.extractLinks(nextProps.post.message);
this.setState({links: linkData.links, message: linkData.text});
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index c5db3956d0..6fa87ca4a0 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -559,7 +559,7 @@ export default class PostList extends React.Component {
>
+ />
New Messages
);
diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx
index e74ab7f138..f1a90102c1 100644
--- a/web/react/components/rhs_comment.jsx
+++ b/web/react/components/rhs_comment.jsx
@@ -12,12 +12,14 @@ var FileAttachmentList = require('./file_attachment_list.jsx');
var Client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var ActionTypes = Constants.ActionTypes;
+var twemoji = require('twemoji');
export default class RhsComment extends React.Component {
constructor(props) {
super(props);
this.retryComment = this.retryComment.bind(this);
+ this.parseEmojis = this.parseEmojis.bind(this);
this.state = {};
}
@@ -51,6 +53,12 @@ export default class RhsComment extends React.Component {
PostStore.updatePendingPost(post);
this.forceUpdate();
}
+ parseEmojis() {
+ twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ }
+ componentDidMount() {
+ this.parseEmojis();
+ }
shouldComponentUpdate(nextProps) {
if (!Utils.areStatesEqual(nextProps.post, this.props.post)) {
return true;
@@ -58,6 +66,9 @@ export default class RhsComment extends React.Component {
return false;
}
+ componentDidUpdate() {
+ this.parseEmojis();
+ }
render() {
var post = this.props.post;
@@ -161,7 +172,8 @@ export default class RhsComment extends React.Component {
filenames={post.filenames}
modalId={'rhs_comment_view_image_modal_' + post.id}
channelId={post.channel_id}
- userId={post.user_id} />
+ userId={post.user_id}
+ />
);
}
diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx
index a407e6470d..83b57b955c 100644
--- a/web/react/components/rhs_root_post.jsx
+++ b/web/react/components/rhs_root_post.jsx
@@ -6,12 +6,23 @@ var UserProfile = require('./user_profile.jsx');
var UserStore = require('../stores/user_store.jsx');
var utils = require('../utils/utils.jsx');
var FileAttachmentList = require('./file_attachment_list.jsx');
+var twemoji = require('twemoji');
+var Constants = require('../utils/constants.jsx');
export default class RhsRootPost extends React.Component {
constructor(props) {
super(props);
+
+ this.parseEmojis = this.parseEmojis.bind(this);
+
this.state = {};
}
+ parseEmojis() {
+ twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ }
+ componentDidMount() {
+ this.parseEmojis();
+ }
shouldComponentUpdate(nextProps) {
if (!utils.areStatesEqual(nextProps.post, this.props.post)) {
return true;
@@ -19,6 +30,9 @@ export default class RhsRootPost extends React.Component {
return false;
}
+ componentDidUpdate() {
+ this.parseEmojis();
+ }
render() {
var post = this.props.post;
var message = utils.textToJsx(post.message);
@@ -99,7 +113,8 @@ export default class RhsRootPost extends React.Component {
filenames={post.filenames}
modalId={'rhs_view_image_modal_' + post.id}
channelId={post.channel_id}
- userId={post.user_id} />
+ userId={post.user_id}
+ />
);
}
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index d99177bda2..2f23d80d9f 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -18,7 +18,6 @@ export default class RhsThread extends React.Component {
this.onChange = this.onChange.bind(this);
this.onChangeAll = this.onChangeAll.bind(this);
- this.onTimeChange = this.onTimeChange.bind(this);
this.state = this.getStateFromStores();
}
@@ -44,7 +43,6 @@ export default class RhsThread extends React.Component {
componentDidMount() {
PostStore.addSelectedPostChangeListener(this.onChange);
PostStore.addChangeListener(this.onChangeAll);
- UserStore.addStatusesChangeListener(this.onTimeChange);
this.resize();
$(window).resize(function resize() {
this.resize();
@@ -58,7 +56,6 @@ export default class RhsThread extends React.Component {
componentWillUnmount() {
PostStore.removeSelectedPostChangeListener(this.onChange);
PostStore.removeChangeListener(this.onChangeAll);
- UserStore.removeStatusesChangeListener(this.onTimeChange);
}
onChange() {
var newState = this.getStateFromStores();
@@ -96,14 +93,6 @@ export default class RhsThread extends React.Component {
this.setState(newState);
}
}
- onTimeChange() {
- for (var id in this.state.postList.posts) {
- if (!this.refs[id]) {
- continue;
- }
- this.refs[id].forceUpdate();
- }
- }
resize() {
var height = $(window).height() - $('#error_bar').outerHeight() - 100;
$('.post-right__scroll').css('height', height + 'px');
@@ -173,8 +162,7 @@ export default class RhsThread extends React.Component {
return (
-
+
{searchForm}
+ onClick={this.handleClose}
+ >
+ onClick={this.clearFocus}
+ >
Cancel
diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx
index e67e458afa..b1bab1d486 100644
--- a/web/react/components/setting_item_max.jsx
+++ b/web/react/components/setting_item_max.jsx
@@ -15,16 +15,20 @@ export default class SettingItemMax extends React.Component {
var extraInfo = null;
if (this.props.extraInfo) {
- extraInfo = this.props.extraInfo;
+ extraInfo = (
{this.props.extraInfo}
);
}
var submit = '';
if (this.props.submit) {
- submit = (
- Submit);
+ submit = (
+
+ Submit
+
+ );
}
var inputs = this.props.inputs;
@@ -46,7 +50,8 @@ export default class SettingItemMax extends React.Component {
+ onClick={this.props.updateSection}
+ >
Cancel
diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx
index 6eaa4a96e8..a53112651b 100644
--- a/web/react/components/setting_picture.jsx
+++ b/web/react/components/setting_picture.jsx
@@ -98,12 +98,13 @@ export default class SettingPicture extends React.Component {
{serverError}
{clientError}
- Select
+ Select
+
{confirmButton}
diff --git a/web/react/components/setting_upload.jsx b/web/react/components/setting_upload.jsx
index 66afdfb411..5979091c4c 100644
--- a/web/react/components/setting_upload.jsx
+++ b/web/react/components/setting_upload.jsx
@@ -2,7 +2,6 @@
// See License.txt for license information.
export default class SettingsUpload extends React.Component {
-
constructor(props) {
super(props);
@@ -70,14 +69,19 @@ export default class SettingsUpload extends React.Component {
-
- Select file
+
+ Select file
+
+
+ onClick={this.doSubmit}
+ >
Import
diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx
index fb79f8b1e0..0056d7a2f4 100644
--- a/web/react/components/sidebar_header.jsx
+++ b/web/react/components/sidebar_header.jsx
@@ -29,10 +29,12 @@ export default class SidebarHeader extends React.Component {
}
if (me.last_picture_update) {
- profilePicture = (
);
+ profilePicture = (
+
+ );
}
return (
diff --git a/web/react/components/sidebar_right.jsx b/web/react/components/sidebar_right.jsx
index 9aeda6626a..9137151540 100644
--- a/web/react/components/sidebar_right.jsx
+++ b/web/react/components/sidebar_right.jsx
@@ -71,10 +71,12 @@ export default class SidebarRight extends React.Component {
if (this.state.search_visible) {
content = ;
} else if (this.state.post_right_visible) {
- content = ();
+ content = (
+
+ );
}
return (
diff --git a/web/react/components/sidebar_right_menu.jsx b/web/react/components/sidebar_right_menu.jsx
index 9c5733799a..bd10a6ef14 100644
--- a/web/react/components/sidebar_right_menu.jsx
+++ b/web/react/components/sidebar_right_menu.jsx
@@ -68,7 +68,8 @@ export default class SidebarRightMenu extends React.Component {
href='#'
data-toggle='modal'
data-target='#team_members'
- >Manage Team
+ >
+ Manage Team
);
}
diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx
index 1d45548dad..dc0d1d3761 100644
--- a/web/react/components/signup_team_complete.jsx
+++ b/web/react/components/signup_team_complete.jsx
@@ -44,52 +44,66 @@ export default class SignupTeamComplete extends React.Component {
}
render() {
if (this.state.wizard === 'welcome') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'team_display_name') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'team_url') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'allowed_domains') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'send_invites') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'username') {
- return ();
+ return (
+
+ );
}
if (this.state.wizard === 'password') {
- return ();
+ return (
+
+ );
}
return (You've already completed the signup process for this invitation or this invitation has expired.
);
diff --git a/web/react/components/team_import_tab.jsx b/web/react/components/team_import_tab.jsx
index 627ff85f4b..1ab348465a 100644
--- a/web/react/components/team_import_tab.jsx
+++ b/web/react/components/team_import_tab.jsx
@@ -46,7 +46,8 @@ export default class TeamImportTab extends React.Component {
title='Import from Slack'
submit={this.doImportSlack}
helpText={uploadHelpText}
- fileTypesAccepted='.zip'/>
+ fileTypesAccepted='.zip'
+ />
);
var messageSection;
@@ -62,14 +63,30 @@ export default class TeamImportTab extends React.Component {
break;
case 'done':
messageSection = (
- Import successful: View Summary
- );
+
+
+ {' Import successful: '}
+
+ {'View Summary'}
+
+
+ );
break;
case 'fail':
messageSection = (
- Import failure: View Summary
+
+
+ {' Import failure: '}
+
+ {'View Summary'}
+
+
);
break;
}
diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx
index 71780c677b..acce6ab495 100644
--- a/web/react/components/team_signup_choose_auth.jsx
+++ b/web/react/components/team_signup_choose_auth.jsx
@@ -22,7 +22,7 @@ export default class ChooseAuthPage extends React.Component {
this.props.updatePage('service', Constants.GITLAB_SERVICE);
}.bind(this)
}
- >
+ >
Create new {strings.Team} with GitLab Account
@@ -40,7 +40,7 @@ export default class ChooseAuthPage extends React.Component {
this.props.updatePage('email', '');
}.bind(this)
}
- >
+ >
Create new {strings.Team} with email address
diff --git a/web/react/components/team_signup_display_name_page.jsx b/web/react/components/team_signup_display_name_page.jsx
index 5d0e4c7b36..1849f82229 100644
--- a/web/react/components/team_signup_display_name_page.jsx
+++ b/web/react/components/team_signup_display_name_page.jsx
@@ -52,8 +52,8 @@ export default class TeamSignupDisplayNamePage extends React.Component {
-
{'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}
+
+ {'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}
+
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index 0408a262dc..b4518fe804 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -121,7 +121,6 @@ export default class Textbox extends React.Component {
}
this.addedMention = false;
this.refs.commands.getSuggestedCommands(nextProps.messageText);
- this.resize();
}
updateMentionTab(mentionText) {
// using setTimeout so dispatch isn't called during an in progress dispatch
@@ -135,7 +134,6 @@ export default class Textbox extends React.Component {
}
handleChange() {
this.props.onUserInput(React.findDOMNode(this.refs.message).value);
- this.resize();
}
handleKeyPress(e) {
const text = React.findDOMNode(this.refs.message).value;
@@ -244,6 +242,8 @@ export default class Textbox extends React.Component {
const e = React.findDOMNode(this.refs.message);
const w = React.findDOMNode(this.refs.wrapper);
+ let prevHeight = $(e).height();
+
const lht = parseInt($(e).css('lineHeight'), 10);
const lines = e.scrollHeight / lht;
let mod = 15;
@@ -259,6 +259,10 @@ export default class Textbox extends React.Component {
$(e).css({height: 'auto', 'overflow-y': 'scroll'}).height(167);
$(w).css({height: 'auto'}).height(167);
}
+
+ if (prevHeight !== $(e).height()) {
+ this.props.onHeightChange();
+ }
}
handleFocus() {
const elm = React.findDOMNode(this.refs.message);
@@ -316,5 +320,6 @@ Textbox.propTypes = {
messageText: React.PropTypes.string.isRequired,
onUserInput: React.PropTypes.func.isRequired,
onKeyPress: React.PropTypes.func.isRequired,
+ onHeightChange: React.PropTypes.func.isRequired,
createMessage: React.PropTypes.string.isRequired
};
diff --git a/web/react/components/user_settings_notifications.jsx b/web/react/components/user_settings_notifications.jsx
index 5fe6bbb4e8..33db1a332d 100644
--- a/web/react/components/user_settings_notifications.jsx
+++ b/web/react/components/user_settings_notifications.jsx
@@ -1,7 +1,6 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-var ChannelStore = require('../stores/channel_store.jsx');
var UserStore = require('../stores/user_store.jsx');
var SettingItemMin = require('./setting_item_min.jsx');
var SettingItemMax = require('./setting_item_max.jsx');
@@ -69,11 +68,9 @@ function getNotificationsStateFromStores() {
}
}
- var curChannel = ChannelStore.getCurrent().display_name;
-
return {notifyLevel: desktop, enableEmail: email, soundNeeded: soundNeeded, enableSound: sound,
usernameKey: usernameKey, mentionKey: mentionKey, customKeys: customKeys, customKeysChecked: customKeys.length > 0,
- firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey, curChannel: curChannel};
+ firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey};
}
export default class NotificationsTab extends React.Component {
@@ -147,12 +144,10 @@ export default class NotificationsTab extends React.Component {
}
componentDidMount() {
UserStore.addChangeListener(this.onListenerChange);
- ChannelStore.addChangeListener(this.onListenerChange);
$('#user_settings').on('hidden.bs.modal', this.handleClose);
}
componentWillUnmount() {
UserStore.removeChangeListener(this.onListenerChange);
- ChannelStore.removeChangeListener(this.onListenerChange);
$('#user_settings').off('hidden.bs.modal', this.handleClose);
this.props.updateSection('');
}
@@ -271,12 +266,6 @@ export default class NotificationsTab extends React.Component {
e.preventDefault();
}.bind(this);
- let extraInfo = (
-
- These settings will override the global notification settings for the {this.state.curChannel} channel
-
- );
-
desktopSection = (
);
} else {
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index ed88c3df45..b0eaba5d62 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -307,7 +307,8 @@ export default class ViewImageModal extends React.Component {
ref='previewArrowLeft'
className='modal-prev-bar'
href='#'
- onClick={this.handlePrev}>
+ onClick={this.handlePrev}
+ >
);
@@ -317,7 +318,8 @@ export default class ViewImageModal extends React.Component {
ref='previewArrowRight'
className='modal-next-bar'
href='#'
- onClick={this.handleNext}>
+ onClick={this.handleNext}
+ >
);
@@ -351,7 +353,7 @@ export default class ViewImageModal extends React.Component {
ref='imageFooter'
className='modal-button-bar'
>
-
{'File ' + (this.state.imgId + 1) + ' of ' + this.props.filenames.length}
+
{'File ' + (this.state.imgId + 1) + ' of ' + this.props.filenames.length}
{publicLink}
../static/js/bundle.min.js",
+ "build": "NODE_ENV=production browserify ./**/*.jsx | uglifyjs -c -m --screw-ie8 > ../static/js/bundle.min.js",
"test": "jest"
},
"browserify": {
diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx
index d56b309fab..71a03cde03 100644
--- a/web/react/pages/channel.jsx
+++ b/web/react/pages/channel.jsx
@@ -73,7 +73,8 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
React.render(
,
+ teamType={teamType}
+ />,
document.getElementById('sidebar-left')
);
@@ -190,7 +191,8 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
React.render(
,
+ teamType={teamType}
+ />,
document.getElementById('sidebar-menu')
);
@@ -226,7 +228,8 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
React.render(
,
+ overlayType='center'
+ />,
document.getElementById('file_upload_overlay')
);
}
diff --git a/web/react/pages/login.jsx b/web/react/pages/login.jsx
index e7305889d3..424ae0e848 100644
--- a/web/react/pages/login.jsx
+++ b/web/react/pages/login.jsx
@@ -8,7 +8,8 @@ function setupLoginPage(teamDisplayName, teamName, authServices) {
,
+ authServices={authServices}
+ />,
document.getElementById('login')
);
}
diff --git a/web/react/pages/signup_team_complete.jsx b/web/react/pages/signup_team_complete.jsx
index 43e3aae655..72f9992a8b 100644
--- a/web/react/pages/signup_team_complete.jsx
+++ b/web/react/pages/signup_team_complete.jsx
@@ -8,7 +8,8 @@ function setupSignupTeamCompletePage(email, data, hash) {
,
+ data={data}
+ />,
document.getElementById('signup-team-complete')
);
}
diff --git a/web/react/pages/signup_user_complete.jsx b/web/react/pages/signup_user_complete.jsx
index 71b526e5d3..eaf93a61cd 100644
--- a/web/react/pages/signup_user_complete.jsx
+++ b/web/react/pages/signup_user_complete.jsx
@@ -12,7 +12,8 @@ function setupSignupUserCompletePage(email, name, uiName, id, data, hash, authSe
email={email}
hash={hash}
data={data}
- authServices={authServices} />,
+ authServices={authServices}
+ />,
document.getElementById('signup-user-complete')
);
}
diff --git a/web/react/pages/verify.jsx b/web/react/pages/verify.jsx
index f42913315e..7077b40b88 100644
--- a/web/react/pages/verify.jsx
+++ b/web/react/pages/verify.jsx
@@ -8,7 +8,8 @@ global.window.setupVerifyPage = function setupVerifyPage(isVerified, teamURL, us
,
+ userEmail={userEmail}
+ />,
document.getElementById('verify')
);
};
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index 3a6ca1b891..18b7ff59c8 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -103,6 +103,7 @@ module.exports = {
MONTHS: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
MAX_DMS: 20,
MAX_POST_LEN: 4000,
+ EMOJI_SIZE: 16,
ONLINE_ICON_SVG: "",
OFFLINE_ICON_SVG: "",
MENU_ICON: "",