diff options
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | api/templates/post_body.html | 2 | ||||
-rw-r--r-- | web/react/components/access_history_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/activity_log_modal.jsx | 5 | ||||
-rw-r--r-- | web/react/components/create_comment.jsx | 65 | ||||
-rw-r--r-- | web/react/components/create_post.jsx | 8 | ||||
-rw-r--r-- | web/react/components/edit_channel_modal.jsx | 18 | ||||
-rw-r--r-- | web/react/components/setting_picture.jsx | 6 | ||||
-rw-r--r-- | web/react/components/signup_team.jsx | 4 | ||||
-rw-r--r-- | web/react/components/signup_team_complete.jsx | 2 | ||||
-rw-r--r-- | web/react/components/team_settings.jsx | 3 | ||||
-rw-r--r-- | web/react/components/user_settings.jsx | 4 | ||||
-rw-r--r-- | web/react/stores/post_store.jsx | 28 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_access-history.scss | 4 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_headers.scss | 5 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_responsive.scss | 8 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_settings.scss | 8 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_signup.scss | 2 |
18 files changed, 137 insertions, 42 deletions
diff --git a/.travis.yml b/.travis.yml index 55ab2986e..fc2fb7646 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,11 @@ before_install: - "sudo sed -i'' 's/basedir[^=]\\+=.*$/basedir = \\/opt\\/mysql\\/server-5.6/' /etc/mysql/my.cnf" - "sudo /etc/init.d/mysql.server start" +install: + - export PATH=$PATH:$HOME/gopath/bin + - go get github.com/tools/godep + - godep restore + before_script: - mysql -e "CREATE DATABASE IF NOT EXISTS mattermost_test ;" -uroot - mysql -e "CREATE USER 'mmuser'@'%' IDENTIFIED BY 'mostest' ;" -uroot diff --git a/api/templates/post_body.html b/api/templates/post_body.html index 41a29d020..c0f4375d8 100644 --- a/api/templates/post_body.html +++ b/api/templates/post_body.html @@ -18,7 +18,7 @@ <tr> <td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;"> <h2 style="font-weight: normal; margin-top: 10px;">You were mentioned</h2> - <p>CHANNEL: {{.Props.ChannelName}}<br>{{.Props.SenderName}} - {{.Props.Hour}}:{{.Props.Minute}} GMT, {{.Props.Month}} {{.Props.Day}}<br><pre style="text-align:left;font-family: 'Lato', sans-serif;">{{.Props.PostMessage}}</pre></p> + <p>CHANNEL: {{.Props.ChannelName}}<br>{{.Props.SenderName}} - {{.Props.Hour}}:{{.Props.Minute}} GMT, {{.Props.Month}} {{.Props.Day}}<br><pre style="text-align:left;font-family: 'Lato', sans-serif; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">{{.Props.PostMessage}}</pre></p> <p style="margin: 20px 0 15px"> <a href="{{.Props.TeamLink}}" style="background: #2389D7; display: inline-block; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 170px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Go To Channel</a> </p> diff --git a/web/react/components/access_history_modal.jsx b/web/react/components/access_history_modal.jsx index b23b3213f..462f046f6 100644 --- a/web/react/components/access_history_modal.jsx +++ b/web/react/components/access_history_modal.jsx @@ -64,7 +64,7 @@ module.exports = React.createClass({ <div>{"URL: " + currentAudit.action.replace("/api/v1", "")}</div> </div> : - <a href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> + <a href="#" className="theme" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> } </div> {i < this.state.audits.length - 1 ? diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index d6f8f40eb..7cce807a9 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -68,6 +68,9 @@ module.exports = React.createClass({ else if (currentSession.props.platform === "Macintosh" || currentSession.props.platform === "iPhone") { devicePicture = "fa fa-apple"; } + else if (currentSession.props.platform === "Linux") { + devicePicture = "fa fa-linux"; + } activityList[i] = ( <div className="activity-log__table"> @@ -83,7 +86,7 @@ module.exports = React.createClass({ <div>{"Session ID: " + currentSession.alt_id}</div> </div> : - <a href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> + <a className="theme" href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> } </div> </div> diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 6ed0f0b34..3f8e9ed2e 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -5,6 +5,7 @@ var client = require('../utils/client.jsx'); var AsyncClient =require('../utils/async_client.jsx'); var SocketStore = require('../stores/socket_store.jsx'); var ChannelStore = require('../stores/channel_store.jsx'); +var PostStore = require('../stores/post_store.jsx'); var Textbox = require('./textbox.jsx'); var MsgTyping = require('./msg_typing.jsx'); var FileUpload = require('./file_upload.jsx'); @@ -43,6 +44,7 @@ module.exports = React.createClass({ client.createPost(post, ChannelStore.getCurrent(), function(data) { + PostStore.storeCommentDraft(this.props.rootId, null); this.setState({ messageText: '', submitting: false, post_error: null, server_error: null }); this.clearPreviews(); AsyncClient.getPosts(true, this.props.channelId); @@ -82,16 +84,33 @@ module.exports = React.createClass({ } }, handleUserInput: function(messageText) { + var draft = PostStore.getCommentDraft(this.props.rootId); + if (!draft) { + draft = { previews: [], uploadsInProgress: 0}; + } + draft.message = messageText; + PostStore.storeCommentDraft(this.props.rootId, draft); + $(".post-right__scroll").scrollTop($(".post-right__scroll")[0].scrollHeight); $(".post-right__scroll").perfectScrollbar('update'); this.setState({messageText: messageText}); }, handleFileUpload: function(newPreviews) { + var draft = PostStore.getCommentDraft(this.props.rootId); + if (!draft) { + draft = { message: '', uploadsInProgress: 0, previews: []} + } + $(".post-right__scroll").scrollTop($(".post-right__scroll")[0].scrollHeight); $(".post-right__scroll").perfectScrollbar('update'); - var oldPreviews = this.state.previews; + var previews = this.state.previews.concat(newPreviews); var num = this.state.uploadsInProgress; - this.setState({previews: oldPreviews.concat(newPreviews), uploadsInProgress:num-1}); + + draft.previews = previews; + draft.uploadsInProgress = num-1; + PostStore.storeCommentDraft(this.props.rootId, draft); + + this.setState({previews: previews, uploadsInProgress: num-1}); }, handleUploadError: function(err) { this.setState({ server_error: err }); @@ -107,10 +126,43 @@ module.exports = React.createClass({ break; } } + + var draft = PostStore.getCommentDraft(); + if (!draft) { + draft = { message: '', uploadsInProgress: 0}; + } + draft.previews = previews; + PostStore.storeCommentDraft(draft); + this.setState({previews: previews}); }, getInitialState: function() { - return { messageText: '', uploadsInProgress: 0, previews: [], submitting: false }; + PostStore.clearCommentDraftUploads(); + + var draft = PostStore.getCommentDraft(this.props.rootId); + messageText = ''; + uploadsInProgress = 0; + previews = []; + if (draft) { + messageText = draft.message; + uploadsInProgress = draft.uploadsInProgress; + previews = draft.previews + } + return { messageText: messageText, uploadsInProgress: uploadsInProgress, previews: previews, submitting: false }; + }, + componentWillReceiveProps: function(newProps) { + if(newProps.rootId !== this.props.rootId) { + var draft = PostStore.getCommentDraft(newProps.rootId); + messageText = ''; + uploadsInProgress = 0; + previews = []; + if (draft) { + messageText = draft.message; + uploadsInProgress = draft.uploadsInProgress; + previews = draft.previews + } + this.setState({ messageText: messageText, uploadsInProgress: uploadsInProgress, previews: previews }); + } }, setUploads: function(val) { var oldInProgress = this.state.uploadsInProgress @@ -126,6 +178,13 @@ module.exports = React.createClass({ var numToUpload = newInProgress - oldInProgress; if (numToUpload <= 0) return 0; + var draft = PostStore.getCommentDraft(this.props.rootId); + if (!draft) { + draft = { message: '', previews: []}; + } + draft.uploadsInProgress = newInProgress; + PostStore.storeCommentDraft(this.props.rootId, draft); + this.setState({uploadsInProgress: newInProgress}); return numToUpload; diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index a2448b569..91d070958 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -55,7 +55,7 @@ module.exports = React.createClass({ post.message, false, function(data) { - PostStore.storeDraft(data.channel_id, user_id, null); + PostStore.storeDraft(data.channel_id, null); this.setState({ messageText: '', submitting: false, post_error: null, previews: [], server_error: null, limit_error: null }); if (data.goto_location.length > 0) { @@ -78,7 +78,7 @@ module.exports = React.createClass({ client.createPost(post, ChannelStore.getCurrent(), function(data) { - PostStore.storeDraft(data.channel_id, data.user_id, null); + PostStore.storeDraft(data.channel_id, null); this.setState({ messageText: '', submitting: false, post_error: null, previews: [], server_error: null, limit_error: null }); this.resizePostHolder(); AsyncClient.getPosts(true); @@ -209,7 +209,7 @@ module.exports = React.createClass({ $(window).trigger('resize'); }, handleFileUpload: function(newPreviews, channel_id) { - var draft = PostStore.getDraft(channel_id, UserStore.getCurrentId()); + var draft = PostStore.getDraft(channel_id); if (!draft) { draft = {} draft['message'] = ''; @@ -230,7 +230,7 @@ module.exports = React.createClass({ } else { draft['previews'] = draft['previews'].concat(newPreviews); draft['uploadsInProgress'] = draft['uploadsInProgress'] > 0 ? draft['uploadsInProgress'] - 1 : 0; - PostStore.storeDraft(channel_id, UserStore.getCurrentId(), draft); + PostStore.storeDraft(channel_id, draft); } }, handleUploadError: function(err) { diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx index c0818959a..d055feacd 100644 --- a/web/react/components/edit_channel_modal.jsx +++ b/web/react/components/edit_channel_modal.jsx @@ -6,17 +6,24 @@ var AsyncClient = require('../utils/async_client.jsx'); module.exports = React.createClass({ handleEdit: function(e) { - var data = {} + var data = {}; data["channel_id"] = this.state.channel_id; if (data["channel_id"].length !== 26) return; data["channel_description"] = this.state.description.trim(); Client.updateChannelDesc(data, function(data) { + this.setState({ server_error: "" }); AsyncClient.getChannels(true); + $(this.refs.modal.getDOMNode()).modal('hide'); }.bind(this), function(err) { - AsyncClient.dispatchError(err, "updateChannelDesc"); + if (err.message === "Invalid channel_description parameter") { + this.setState({ server_error: "This description is too long, please enter a shorter one" }); + } + else { + this.setState({ server_error: err.message }); + } }.bind(this) ); }, @@ -27,13 +34,15 @@ module.exports = React.createClass({ var self = this; $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { var button = e.relatedTarget; - self.setState({ description: $(button).attr('data-desc'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid') }); + self.setState({ description: $(button).attr('data-desc'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), server_error: "" }); }); }, getInitialState: function() { return { description: "", title: "", channel_id: "" }; }, render: function() { + var server_error = this.state.server_error ? <div className='form-group has-error'><br/><label className='control-label'>{ this.state.server_error }</label></div> : null; + return ( <div className="modal fade" ref="modal" id="edit_channel" role="dialog" aria-hidden="true"> <div className="modal-dialog"> @@ -44,10 +53,11 @@ module.exports = React.createClass({ </div> <div className="modal-body"> <textarea className="form-control no-resize" rows="6" ref="channelDesc" maxLength="1024" value={this.state.description} onChange={this.handleUserInput}></textarea> + { server_error } </div> <div className="modal-footer"> <button type="button" className="btn btn-default" data-dismiss="modal">Close</button> - <button type="button" className="btn btn-primary" data-dismiss="modal" onClick={this.handleEdit}>Save</button> + <button type="button" className="btn btn-primary" onClick={this.handleEdit}>Save</button> </div> </div> </div> diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx index 62c889b7f..6cfb74d60 100644 --- a/web/react/components/setting_picture.jsx +++ b/web/react/components/setting_picture.jsx @@ -25,9 +25,9 @@ module.exports = React.createClass({ var img = null; if (this.props.picture) { - img = (<img ref="image" className="col-xs-5 profile-img" src=""/>); + img = (<img ref="image" className="profile-img" src=""/>); } else { - img = (<img ref="image" className="col-xs-5 profile-img" src={this.props.src}/>); + img = (<img ref="image" className="profile-img" src={this.props.src}/>); } var self = this; @@ -37,7 +37,7 @@ module.exports = React.createClass({ <li className="col-xs-12 section-title">{this.props.title}</li> <li className="col-xs-offset-3 col-xs-8"> <ul className="setting-list"> - <li className="row setting-list-item"> + <li className="setting-list-item"> {img} </li> <li className="setting-list-item"> diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx index cf982cc1e..362f79163 100644 --- a/web/react/components/signup_team.jsx +++ b/web/react/components/signup_team.jsx @@ -69,7 +69,9 @@ module.exports = React.createClass({ { name_error } </div> { server_error } - <button className="btn btn-md btn-primary" type="submit">Sign up for Free</button> + <div className="form-group"> + <button className="btn btn-md btn-primary" type="submit">Sign up for Free</button> + </div> <div className="form-group form-group--small"> <span><a href="/find_team">{"Find my " + strings.Team}</a></span> </div> diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx index 9ceeb6324..3e8a57308 100644 --- a/web/react/components/signup_team_complete.jsx +++ b/web/react/components/signup_team_complete.jsx @@ -246,7 +246,7 @@ TeamURLPage = React.createClass({ <h2>{utils.toTitleCase(strings.Team) + " URL"}</h2> <div className={ name_error ? "form-group has-error" : "form-group" }> <div className="row"> - <div className="col-sm-9"> + <div className="col-sm-11"> <div className="input-group"> <span className="input-group-addon">{ window.location.origin + "/" }</span> <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.name} autoFocus={true} onFocus={this.handleFocus}/> diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx index 166b1f38b..3bbb5e892 100644 --- a/web/react/components/team_settings.jsx +++ b/web/react/components/team_settings.jsx @@ -73,13 +73,12 @@ var FeatureTab = 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 "+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/>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> ); diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx index ad890334e..1fbbf16ed 100644 --- a/web/react/components/user_settings.jsx +++ b/web/react/components/user_settings.jsx @@ -577,9 +577,9 @@ var SecurityTab = React.createClass({ { passwordSection } <div className="divider-dark"/> <br></br> - <a data-toggle="modal" className="security-links" data-target="#access-history" href="#" onClick={this.handleHistoryOpen}><i className="fa fa-clock-o"></i>View Access History</a> + <a data-toggle="modal" className="security-links theme" data-target="#access-history" href="#" onClick={this.handleHistoryOpen}><i className="fa fa-clock-o"></i>View Access History</a> <b> </b> - <a data-toggle="modal" className="security-links" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Devices</a> + <a data-toggle="modal" className="security-links theme" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Devices</a> </div> </div> ); diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx index 1b3e1a119..0745fcdc3 100644 --- a/web/react/stores/post_store.jsx +++ b/web/react/stores/post_store.jsx @@ -149,19 +149,23 @@ var PostStore = assign({}, EventEmitter.prototype, { }, storeCurrentDraft: function(draft) { var channel_id = ChannelStore.getCurrentId(); - var user_id = UserStore.getCurrentId(); - BrowserStore.setItem("draft_" + channel_id + "_" + user_id, draft); + BrowserStore.setItem("draft_" + channel_id, draft); }, getCurrentDraft: function() { var channel_id = ChannelStore.getCurrentId(); - var user_id = UserStore.getCurrentId(); - return BrowserStore.getItem("draft_" + channel_id + "_" + user_id); + return BrowserStore.getItem("draft_" + channel_id); }, - storeDraft: function(channel_id, user_id, draft) { - BrowserStore.setItem("draft_" + channel_id + "_" + user_id, draft); + storeDraft: function(channel_id, draft) { + BrowserStore.setItem("draft_" + channel_id, draft); }, - getDraft: function(channel_id, user_id) { - return BrowserStore.getItem("draft_" + channel_id + "_" + user_id); + getDraft: function(channel_id) { + return BrowserStore.getItem("draft_" + channel_id); + }, + storeCommentDraft: function(parent_post_id, draft) { + BrowserStore.setItem("comment_draft_" + parent_post_id, draft); + }, + getCommentDraft: function(parent_post_id) { + return BrowserStore.getItem("comment_draft_" + parent_post_id); }, clearDraftUploads: function() { BrowserStore.actionOnItemsWithPrefix("draft_", function (key, value) { @@ -170,6 +174,14 @@ var PostStore = assign({}, EventEmitter.prototype, { BrowserStore.setItem(key, value); } }); + }, + clearCommentDraftUploads: function() { + BrowserStore.actionOnItemsWithPrefix("comment_draft_", function (key, value) { + if (value) { + value.uploadsInProgress = 0; + BrowserStore.setItem(key, value); + } + }); } }); diff --git a/web/sass-files/sass/partials/_access-history.scss b/web/sass-files/sass/partials/_access-history.scss index f54c9a122..412a2a1d0 100644 --- a/web/sass-files/sass/partials/_access-history.scss +++ b/web/sass-files/sass/partials/_access-history.scss @@ -12,7 +12,7 @@ } .access__date { font-weight: 600; - font-size: 16px; + font-size: 15px; width: 190px; } .access__report { @@ -21,7 +21,7 @@ } .report__time { font-weight: 600; - font-size: 16px; + font-size: 15px; } .report__info { color: #999; diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index eab4becac..4351e167b 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -92,10 +92,10 @@ .navbar-right { font-size: 0.85em; position: absolute; - top: 20px; + top: 10px; right: 22px; .dropdown-toggle { - padding: 0 10px; + padding: 10px; } .dropdown-menu { li a { @@ -119,6 +119,7 @@ } .header__info { color: #fff; + padding-left: 3px } .team__name, .user__name { display: block; diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index b4e4fa1df..3a2768a47 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -451,13 +451,15 @@ color: #fff; .search__form { border: none; - padding: 0 60px 0 25px; + padding: 0 60px 0 35px; .form-control { - line-height: 31px; + line-height: normal; background: none; color: #fff; border-radius: 0; - padding: 0 10px 0; + padding: 0; + border-bottom: 1px solid #FFF; + border-bottom: 1px solid rgba(#fff, 0.6); @include input-placeholder { color: rgba(#fff, 0.6); } diff --git a/web/sass-files/sass/partials/_settings.scss b/web/sass-files/sass/partials/_settings.scss index b8dc9e997..1fb078bb9 100644 --- a/web/sass-files/sass/partials/_settings.scss +++ b/web/sass-files/sass/partials/_settings.scss @@ -163,8 +163,10 @@ } .profile-img { - width:158px; - max-height:128px; + width:128px; + height:128px; + margin-bottom: 10px; + @include border-radius(128px); } .sel-btn { @@ -232,4 +234,4 @@ .color-btn { margin:4px; -}
\ No newline at end of file +} diff --git a/web/sass-files/sass/partials/_signup.scss b/web/sass-files/sass/partials/_signup.scss index 98931279b..db22718d2 100644 --- a/web/sass-files/sass/partials/_signup.scss +++ b/web/sass-files/sass/partials/_signup.scss @@ -6,7 +6,7 @@ } .signup-team__container { padding: 100px 0px 50px 0px; - max-width: 600px; + max-width: 380px; margin: 0 auto; font-size: 1.1em; position: relative; |