diff options
Diffstat (limited to 'web/react')
-rw-r--r-- | web/react/components/channel_notifications.jsx | 6 | ||||
-rw-r--r-- | web/react/components/get_link_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/more_direct_channels.jsx | 2 | ||||
-rw-r--r-- | web/react/components/post.jsx | 18 | ||||
-rw-r--r-- | web/react/components/post_list.jsx | 109 | ||||
-rw-r--r-- | web/react/components/post_right.jsx | 20 | ||||
-rw-r--r-- | web/react/components/search_results.jsx | 8 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 11 | ||||
-rw-r--r-- | web/react/components/team_settings.jsx | 7 | ||||
-rw-r--r-- | web/react/components/user_settings.jsx | 19 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 20 |
11 files changed, 138 insertions, 84 deletions
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx index fa9ab42ae..638d16576 100644 --- a/web/react/components/channel_notifications.jsx +++ b/web/react/components/channel_notifications.jsx @@ -97,7 +97,7 @@ module.exports = React.createClass({ var inputs = []; inputs.push( - <div className="col-sm-12"> + <div> <div className="radio"> <label> <input type="radio" checked={notifyActive[0]} onClick={function(){self.handleRadioClick("all")}}>For all activity</input> @@ -158,7 +158,7 @@ module.exports = React.createClass({ var inputs = []; inputs.push( - <div className="col-sm-12"> + <div> <div className="btn-group" data-toggle="buttons-radio"> <button className={"btn btn-default "+quietActive[0]} onClick={function(){self.handleQuietToggle(true)}}>On</button> <button className={"btn btn-default "+quietActive[1]} onClick={function(){self.handleQuietToggle(false)}}>Off</button> @@ -167,7 +167,7 @@ module.exports = React.createClass({ ); inputs.push( - <div className="col-sm-12"> + <div> <br/> Enabling quiet mode will turn off desktop notifications and only mark the channel as unread if you have been mentioned. </div> diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx index 334591ee3..69e565185 100644 --- a/web/react/components/get_link_modal.jsx +++ b/web/react/components/get_link_modal.jsx @@ -42,7 +42,7 @@ module.exports = React.createClass({ </div> <div className="modal-footer"> <button type="button" className="btn btn-default" data-dismiss="modal">Close</button> - <button data-copy-btn type="button" className="btn btn-primary" data-clipboard-text={this.state.value}>Copy Link</button> + <button data-copy-btn type="button" className="btn btn-primary pull-left" data-clipboard-text={this.state.value}>Copy Link</button> </div> </div> </div> diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx index 2785dc8e0..182d8884d 100644 --- a/web/react/components/more_direct_channels.jsx +++ b/web/react/components/more_direct_channels.jsx @@ -49,7 +49,7 @@ module.exports = React.createClass({ <span aria-hidden="true">×</span> <span className="sr-only">Close</span> </button> - <h4 className="modal-title">More Direct Messages</h4> + <h4 className="modal-title">More Private Messages</h4> </div> <div className="modal-body"> <ul className="nav nav-pills nav-stacked"> diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index afe978495..04b5ba082 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -6,13 +6,14 @@ var PostBody = require('./post_body.jsx'); var PostInfo = require('./post_info.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var Constants = require('../utils/constants.jsx'); +var UserStore = require('../stores/user_store.jsx'); var ActionTypes = Constants.ActionTypes; module.exports = React.createClass({ componentDidMount: function() { - $('.edit-modal').on('show.bs.modal', function () { - $('.edit-modal .edit-modal-body').css('overflow-y', 'auto'); - $('.edit-modal .edit-modal-body').css('max-height', $(window).height() * 0.7); + $('.modal').on('show.bs.modal', function () { + $('.modal-body').css('overflow-y', 'auto'); + $('.modal-body').css('max-height', $(window).height() * 0.7); }); }, handleCommentClick: function(e) { @@ -56,7 +57,7 @@ module.exports = React.createClass({ var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null; - if(this.props.sameRoot){ + if (this.props.sameRoot){ rootUser = "same--root"; } else { @@ -64,13 +65,18 @@ module.exports = React.createClass({ } var postType = ""; - if(type != "Post"){ + if (type != "Post"){ postType = "post--comment"; } + var currentUserCss = ""; + if (UserStore.getCurrentId() === post.user_id) { + currentUserCss = "current--user"; + } + return ( <div> - <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType}> + <div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType + " " + currentUserCss}> { !this.props.hideProfilePic ? <div className="post-profile-img__container"> <img className="post-profile-img" src={"/api/v1/users/" + post.user_id + "/image"} height="36" width="36" /> diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index e37de8d88..169efc766 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -295,7 +295,7 @@ module.exports = React.createClass({ }, render: function() { var order = []; - var posts = {}; + var posts; var last_viewed = Number.MAX_VALUE; @@ -324,13 +324,7 @@ module.exports = React.createClass({ if (order.length > 0 && order.length % Constants.POST_CHUNK_SIZE === 0) { more_messages = <a ref="loadmore" className="more-messages-text theme" href="#" onClick={this.getMorePosts}>Load more messages</a>; } else if (channel.type === 'D') { - var userIds = channel.name.split('__'); - var teammate; - if (userIds.length === 2 && userIds[0] === user_id) { - teammate = UserStore.getProfile(userIds[1]); - } else if (userIds.length === 2 && userIds[1] === user_id) { - teammate = UserStore.getProfile(userIds[0]); - } + var teammate = utils.getDirectTeammate(channel.id) if (teammate) { var teammate_name = teammate.full_name.length > 0 ? teammate.full_name : teammate.username; @@ -342,13 +336,13 @@ module.exports = React.createClass({ <div className="channel-intro-profile"> <strong><UserProfile userId={teammate.id} /></strong> </div> - <p className="channel-intro-text">{"This is the start of your direct message history with " + teammate_name + "." }<br/>{"Direct messages and files shared here are not shown to people outside this area."}</p> + <p className="channel-intro-text">{"This is the start of your private message history with " + teammate_name + "." }<br/>{"Private messages and files shared here are not shown to people outside this area."}</p> </div> ); } else { more_messages = ( <div className="channel-intro"> - <p className="channel-intro-text">{"This is the start of your direct message history with this " + strings.Team + "mate. Direct messages and files shared here are not shown to people outside this area."}</p> + <p className="channel-intro-text">{"This is the start of your private message history with this " + strings.Team + "mate. Private messages and files shared here are not shown to people outside this area."}</p> </div> ); } @@ -414,55 +408,70 @@ module.exports = React.createClass({ } var postCtls = []; - var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date(); - var currentPostDay = new Date(); - for (var i = order.length-1; i >= 0; i--) { - var post = posts[order[i]]; - var parentPost; + if (posts != undefined) { + var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date(); + var currentPostDay = new Date(); - if (post.parent_id) { - parentPost = posts[post.parent_id]; - } else { - parentPost = null; - } + for (var i = order.length-1; i >= 0; i--) { + var post = posts[order[i]]; + var parentPost; - var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : ""; - var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false; + if (post.parent_id) { + parentPost = posts[post.parent_id]; + } else { + parentPost = null; + } - // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post - var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === ''; + var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : ""; + var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false; - // check if it's the last comment in a consecutive string of comments on the same post - var isLastComment = false; - if (utils.isComment(post)) { - // it is the last comment if it is last post in the channel or the next post has a different root post - isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id); - } + // we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post + var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === ''; - var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />; + // check if it's the last comment in a consecutive string of comments on the same post + var isLastComment = false; + if (utils.isComment(post)) { + // it is the last comment if it is last post in the channel or the next post has a different root post + isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id); + } - currentPostDay = utils.getDateForUnixTicks(post.create_at); - if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) { - postCtls.push( - <div className="date-separator"> - <hr className="separator__hr" /> - <div className="separator__text">{currentPostDay.toDateString()}</div> - </div> - ); - } + var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />; - if (post.create_at > last_viewed && !rendered_last_viewed) { - rendered_last_viewed = true; - postCtls.push( - <div className="new-separator"> - <hr id="new_message" className="separator__hr" /> - <div className="separator__text">New Messages</div> - </div> - ); + currentPostDay = utils.getDateForUnixTicks(post.create_at); + if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) { + postCtls.push( + <div className="date-separator"> + <hr className="separator__hr" /> + <div className="separator__text">{currentPostDay.toDateString()}</div> + </div> + ); + } + + if (post.create_at > last_viewed && !rendered_last_viewed) { + rendered_last_viewed = true; + postCtls.push( + <div className="new-separator"> + <hr id="new_message" className="separator__hr" /> + <div className="separator__text">New Messages</div> + </div> + ); + } + postCtls.push(postCtl); + previousPostDay = utils.getDateForUnixTicks(post.create_at); } - postCtls.push(postCtl); - previousPostDay = utils.getDateForUnixTicks(post.create_at); + } + else { + postCtls.push( + <div ref="loadingscreen" className="loading-screen"> + <div className="loading__content"> + <h3>Loading</h3> + <div id="round_1" className="round"></div> + <div id="round_2" className="round"></div> + <div id="round_3" className="round"></div> + </div> + </div> + ); } return ( diff --git a/web/react/components/post_right.jsx b/web/react/components/post_right.jsx index 43be60afa..2c28c5d9f 100644 --- a/web/react/components/post_right.jsx +++ b/web/react/components/post_right.jsx @@ -68,9 +68,14 @@ RootPost = React.createClass({ var filenames = this.props.post.filenames; var isOwner = UserStore.getCurrentId() == this.props.post.user_id; - var type = "Post" + var type = "Post"; if (this.props.post.root_id.length > 0) { - type = "Comment" + type = "Comment"; + } + + var currentUserCss = ""; + if (UserStore.getCurrentId() === this.props.post.user_id) { + currentUserCss = "current--user"; } if (filenames) { @@ -84,7 +89,7 @@ RootPost = React.createClass({ if (fileSplit.length < 2) continue; var ext = fileSplit[fileSplit.length-1]; - fileSplit.splice(fileSplit.length-1,1) + fileSplit.splice(fileSplit.length-1,1); var filePath = fileSplit.join('.'); var filename = filePath.split('/')[filePath.split('/').length-1]; @@ -111,7 +116,7 @@ RootPost = React.createClass({ } return ( - <div className="post post--root"> + <div className={"post post--root " + currentUserCss}> <div className="post-profile-img__container"> <img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" /> </div> @@ -170,6 +175,11 @@ CommentPost = React.createClass({ var commentClass = "post"; + var currentUserCss = ""; + if (UserStore.getCurrentId() === this.props.post.user_id) { + currentUserCss = "current--user"; + } + var postImageModalId = "rhs_comment_view_image_modal_" + this.props.post.id; var filenames = this.props.post.filenames; var isOwner = UserStore.getCurrentId() == this.props.post.user_id; @@ -219,7 +229,7 @@ CommentPost = React.createClass({ var message = utils.textToJsx(this.props.post.message); return ( - <div className={commentClass}> + <div className={commentClass + " " + currentUserCss}> <div className="post-profile-img__container"> <img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" /> </div> diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 51aefd3b8..003a38b7e 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -43,6 +43,7 @@ SearchItem = React.createClass({ e.preventDefault(); var self = this; + client.getPost( this.props.post.channel_id, this.props.post.id, @@ -64,6 +65,11 @@ SearchItem = React.createClass({ dispatchError(err, "getPost"); } ); + + var postChannel = ChannelStore.get(this.props.post.channel_id); + var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : ""; + + utils.switchChannel(postChannel,teammate); }, render: function() { @@ -73,7 +79,7 @@ SearchItem = React.createClass({ if (channel) { if (channel.type === 'D') { - channelName = "Direct Message"; + channelName = "Private Message"; } else { channelName = channel.display_name; } diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 10017c7ee..0e4d38fe0 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -269,13 +269,8 @@ var SidebarLoggedIn = React.createClass({ var channel = ChannelStore.getCurrent(); if (channel) { if (channel.type === 'D') { - userIds = channel.name.split('__'); - if (userIds.length < 2) return; - if (userIds[0] == UserStore.getCurrentId() && UserStore.getProfile(userIds[1])) { - document.title = UserStore.getProfile(userIds[1]).username + " " + document.title.substring(document.title.lastIndexOf("-")); - } else if (userIds[1] == UserStore.getCurrentId() && UserStore.getProfile(userIds[0])) { - document.title = UserStore.getProfile(userIds[0]).username + " " + document.title.substring(document.title.lastIndexOf("-")); - } + var teammate_username = utils.getDirectTeammate(channel.id).username + document.title = teammate_username + " " + document.title.substring(document.title.lastIndexOf("-")); } else { document.title = channel.display_name + " " + document.title.substring(document.title.lastIndexOf("-")) } @@ -414,7 +409,7 @@ var SidebarLoggedIn = React.createClass({ {privateChannelItems} </ul> <ul className="nav nav-pills nav-stacked"> - <li><h4>Direct Messages</h4></li> + <li><h4>Private Messages</h4></li> {directMessageItems} { this.state.hideDirectChannels.length > 0 ? <li><a href="#" data-toggle="modal" className="nav-more" data-target="#more_direct_channels" data-channels={JSON.stringify(this.state.hideDirectChannels)}>{"More ("+this.state.hideDirectChannels.length+")"}</a></li> diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx index a43e5d2f0..166b1f38b 100644 --- a/web/react/components/team_settings.jsx +++ b/web/react/components/team_settings.jsx @@ -78,13 +78,14 @@ var FeatureTab = React.createClass({ <button className={"btn btn-default "+valetActive[0]} onClick={function(){self.handleValetRadio("true")}}>On</button> <button className={"btn btn-default "+valetActive[1]} onClick={function(){self.handleValetRadio("false")}}>Off</button> </div> - <div><br/>Warning: Turning on the Valet feature and using it with any third party software increases the risk of a security breach.</div> + <div><br/>Valet is a preview feature for enabling a non-user account limited to basic member permissions that can be manipulated by 3rd parties.<br/><br/>IMPORTANT: The preview version of Valet should not be used without a secure connection and a trusted 3rd party, since user credentials are used to connect. OAuth2 will be used in the final release.</div> + <br></br> </div> ); valetSection = ( <SettingItemMax - title="Valet" + title="Valet (Preview - EXPERTS ONLY)" inputs={inputs} submit={this.submitValetFeature} server_error={server_error} @@ -102,7 +103,7 @@ var FeatureTab = React.createClass({ valetSection = ( <SettingItemMin - title="Valet" + title="Valet (Preview - EXPERTS ONLY)" describe={describe} updateSection={function(){self.props.updateSection("valet");}} /> diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx index f97a06db3..b4c3747af 100644 --- a/web/react/components/user_settings.jsx +++ b/web/react/components/user_settings.jsx @@ -179,7 +179,7 @@ var NotificationsTab = React.createClass({ </div> <div className="radio"> <label> - <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and direct messages</input> + <input type="radio" checked={notifyActive[1]} onClick={function(){self.handleNotifyRadio("mention")}}>Only for mentions and private messages</input> </label> <br/> </div> @@ -203,7 +203,7 @@ var NotificationsTab = React.createClass({ } else { var describe = ""; if (this.state.notify_level === "mention") { - describe = "Only for mentions and direct messages"; + describe = "Only for mentions and private messages"; } else if (this.state.notify_level === "none") { describe = "Never"; } else { @@ -282,7 +282,7 @@ var NotificationsTab = React.createClass({ <button className={"btn btn-default "+emailActive[0]} onClick={function(){self.handleEmailRadio("true")}}>On</button> <button className={"btn btn-default "+emailActive[1]} onClick={function(){self.handleEmailRadio("false")}}>Off</button> </div> - <div><br/>{"Email notifications are sent for mentions and direct messages after you have been away from " + config.SiteName + " for 5 minutes."}</div> + <div><br/>{"Email notifications are sent for mentions and private messages after you have been away from " + config.SiteName + " for 5 minutes."}</div> </div> ); @@ -809,6 +809,11 @@ var GeneralTab = React.createClass({ if(!this.submitActive) return; + if(this.state.picture.type !== "image/jpeg") { + this.setState({client_error: "Only JPG images may be used for profile pictures"}); + return; + } + formData = new FormData(); formData.append('image', this.state.picture, this.state.picture.name); @@ -839,11 +844,13 @@ var GeneralTab = React.createClass({ updatePicture: function(e) { if (e.target.files && e.target.files[0]) { this.setState({ picture: e.target.files[0] }); + + this.submitActive = true; + this.setState({client_error:null}) + } else { this.setState({ picture: null }); } - - this.submitActive = true }, updateSection: function(section) { this.setState({client_error:""}) @@ -984,7 +991,7 @@ var GeneralTab = React.createClass({ submit={this.submitPicture} src={"/api/v1/users/" + user.id + "/image"} server_error={server_error} - client_error={email_error} + client_error={client_error} updateSection={function(e){self.updateSection("");e.preventDefault();}} picture={this.state.picture} pictureChange={this.updatePicture} diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 70a47742f..f8a7d6450 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -2,6 +2,7 @@ // See License.txt for license information. var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); +var ChannelStore = require('../stores/channel_store.jsx') var UserStore = require('../stores/user_store.jsx'); var Constants = require('../utils/constants.jsx'); var ActionTypes = Constants.ActionTypes; @@ -726,6 +727,25 @@ module.exports.isComment = function(post) { return false; } +module.exports.getDirectTeammate = function(channel_id) { + var userIds = ChannelStore.get(channel_id).name.split('__'); + var curUserId = UserStore.getCurrentId(); + var teammate = {}; + + if(userIds.length != 2 || userIds.indexOf(curUserId) === -1) { + return teammate; + } + + for (var idx in userIds) { + if(userIds[idx] !== curUserId) { + teammate = UserStore.getProfile(userIds[idx]); + break; + } + } + + return teammate; +} + Image.prototype.load = function(url, progressCallback) { var thisImg = this; var xmlHTTP = new XMLHttpRequest(); |