summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/activity_log_modal.jsx3
-rw-r--r--web/react/components/create_post.jsx4
-rw-r--r--web/react/components/edit_channel_modal.jsx7
-rw-r--r--web/react/components/removed_from_channel_modal.jsx64
-rw-r--r--web/react/components/rename_channel_modal.jsx7
-rw-r--r--web/react/components/rename_team_modal.jsx11
-rw-r--r--web/react/components/sidebar.jsx14
-rw-r--r--web/react/components/signup_user_complete.jsx11
-rw-r--r--web/react/components/textbox.jsx37
-rw-r--r--web/react/components/user_settings.jsx52
10 files changed, 161 insertions, 49 deletions
diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx
index 7cce807a9..90f139e8b 100644
--- a/web/react/components/activity_log_modal.jsx
+++ b/web/react/components/activity_log_modal.jsx
@@ -102,8 +102,9 @@ module.exports = React.createClass({
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
- <h4 className="modal-title" id="myModalLabel">Active Devices</h4>
+ <h4 className="modal-title" id="myModalLabel">Active Sessions</h4>
</div>
+ <p className="session-help-text">Sessions are created when you log in with your email and password to a new browser on a device. Sessions let you use Mattermost for up to 30 days without having to log in again. If you want to log out sooner, use the "Logout" button below to end a session.</p>
<div ref="modalBody" className="modal-body">
<form role="form">
{ activityList }
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index b065dff83..327520210 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -32,7 +32,7 @@ module.exports = React.createClass({
post.message = this.state.messageText;
// if this is a reply, trim off any carets from the beginning of a message
- if (this.state.rootId && post.message.startsWith("^")) {
+ if (this.state.rootId && post.message[0] === "^") {
post.message = post.message.replace(/^\^+\s*/g, "");
}
@@ -275,7 +275,7 @@ module.exports = React.createClass({
messageText = draft['message'];
uploadsInProgress = draft['uploadsInProgress'];
}
- this.setState({ channel_id: channel_id, messageText: messageText, initialText: messageText, submitting: false, post_error: null, previews: previews, uploadsInProgress: uploadsInProgress });
+ this.setState({ channel_id: channel_id, messageText: messageText, initialText: messageText, submitting: false, limit_error: null, server_error: null, post_error: null, previews: previews, uploadsInProgress: uploadsInProgress });
}
},
_onActiveThreadChanged: function(rootId, parentId) {
diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx
index d055feacd..a35a531b5 100644
--- a/web/react/components/edit_channel_modal.jsx
+++ b/web/react/components/edit_channel_modal.jsx
@@ -30,12 +30,19 @@ module.exports = React.createClass({
handleUserInput: function(e) {
this.setState({ description: e.target.value });
},
+ handleClose: function() {
+ this.setState({description: "", server_error: ""});
+ },
componentDidMount: function() {
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'), server_error: "" });
});
+ $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose)
+ },
+ componentWillUnmount: function() {
+ $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose)
},
getInitialState: function() {
return { description: "", title: "", channel_id: "" };
diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx
new file mode 100644
index 000000000..a8889a92a
--- /dev/null
+++ b/web/react/components/removed_from_channel_modal.jsx
@@ -0,0 +1,64 @@
+// 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 BrowserStore = require('../stores/browser_store.jsx')
+var utils = require('../utils/utils.jsx');
+
+module.exports = React.createClass({
+ handleShow: function() {
+ var newState = {};
+ if(BrowserStore.getItem("channel-removed-state")) {
+ newState = BrowserStore.getItem("channel-removed-state");
+ BrowserStore.removeItem("channel-removed-state");
+ }
+
+ this.setState(newState);
+ },
+ handleClose: function() {
+ var townSquare = ChannelStore.getByName("town-square");
+ utils.switchChannel(townSquare);
+
+ this.setState({channelName: "", remover: ""})
+ },
+ componentDidMount: function() {
+ $(this.getDOMNode()).on('show.bs.modal',this.handleShow);
+ $(this.getDOMNode()).on('hidden.bs.modal',this.handleClose);
+ },
+ componentWillUnmount: function() {
+ $(this.getDOMNode()).off('show.bs.modal',this.handleShow);
+ $(this.getDOMNode()).off('hidden.bs.modal',this.handleClose);
+ },
+ getInitialState: function() {
+ return {channelName: "", remover: ""}
+ },
+ render: function() {
+ var currentUser = UserStore.getCurrentUser();
+ var channelName = this.state.channelName ? this.state.channelName : "the channel"
+ var remover = this.state.remover ? this.state.remover : "Someone"
+
+ if (currentUser != null) {
+ return (
+ <div className="modal fade" ref="modal" id="removed_from_channel" tabIndex="-1" role="dialog" aria-hidden="true">
+ <div className="modal-dialog">
+ <div className="modal-content">
+ <div className="modal-header">
+ <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+ <h4 className="modal-title">Removed from {channelName}</h4>
+ </div>
+ <div className="modal-body">
+ <p>{remover} removed you from {channelName}</p>
+ </div>
+ <div className="modal-footer">
+ <button type="button" className="btn btn-primary" data-dismiss="modal">Okay</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ } else {
+ return <div/>;
+ }
+ }
+}); \ No newline at end of file
diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx
index 2ae331626..9e4a25f85 100644
--- a/web/react/components/rename_channel_modal.jsx
+++ b/web/react/components/rename_channel_modal.jsx
@@ -89,12 +89,19 @@ module.exports = React.createClass({
this.refs.channel_name.getDOMNode().value = channel_name;
this.setState({ channel_name: channel_name })
},
+ handleClose: function() {
+ this.setState({display_name: "", channel_name: "", display_name_error: "", server_error: "", name_error: ""});
+ },
componentDidMount: function() {
var self = this;
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
var button = $(e.relatedTarget);
self.setState({ display_name: button.attr('data-display'), title: button.attr('data-name'), channel_id: button.attr('data-channelid') });
});
+ $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose);
+ },
+ componentWillUnmount: function() {
+ $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose);
},
getInitialState: function() {
return { display_name: "", channel_name: "", channel_id: "" };
diff --git a/web/react/components/rename_team_modal.jsx b/web/react/components/rename_team_modal.jsx
index a6da57b67..dfd775a3b 100644
--- a/web/react/components/rename_team_modal.jsx
+++ b/web/react/components/rename_team_modal.jsx
@@ -44,11 +44,14 @@ module.exports = React.createClass({
onNameChange: function() {
this.setState({ name: this.refs.name.getDOMNode().value })
},
+ handleClose: function() {
+ this.setState({ name: this.props.teamDisplayName, name_error: "", server_error: ""});
+ },
componentDidMount: function() {
- var self = this;
- $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
- self.setState({ name: self.props.teamDisplayName });
- });
+ $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', this.handleClose);
+ },
+ componentWillUnmount: function() {
+ $(this.refs.modal.getDOMNode()).off('hidden.bs.modal', this.handleClose);
},
getInitialState: function() {
return { name: this.props.teamDisplayName };
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 3cf67e410..5b8d6c542 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -7,6 +7,7 @@ var AsyncClient = require('../utils/async_client.jsx');
var SocketStore = require('../stores/socket_store.jsx');
var UserStore = require('../stores/user_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
+var BrowserStore = require('../stores/browser_store.jsx')
var utils = require('../utils/utils.jsx');
var SidebarHeader = require('./sidebar_header.jsx');
var SearchBox = require('./search_bar.jsx');
@@ -197,6 +198,19 @@ module.exports = React.createClass({
if (UserStore.getCurrentId() === msg.user_id) {
AsyncClient.getChannels(true);
}
+ } else if(msg.action === "user_removed") {
+ if(msg.user_id === UserStore.getCurrentId()) {
+ AsyncClient.getChannels(true);
+
+ if(msg.props.channel_id === ChannelStore.getCurrentId() && $('#removed_from_channel').length > 0) {
+ var sentState = {};
+ sentState.channelName = ChannelStore.getCurrent().display_name;
+ sentState.remover = UserStore.getProfile(msg.props.remover).username;
+
+ BrowserStore.setItem('channel-removed-state',sentState);
+ $('#removed_from_channel').modal('show');
+ }
+ }
}
},
updateTitle: function() {
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index dc5ba64aa..bbf1f670c 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -117,24 +117,24 @@ module.exports = React.createClass({
var signup_message;
if (auth_services.indexOf("gitlab") >= 0) {
- signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team} <a href={"/"+this.props.teamName+"/signup/gitlab"+window.location.search}>{"or sign up with GitLab."}</a></p>;
- } else {
- signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team + "."}</p>;
+ signup_message = <div><a className="btn btn-custom-login gitlab" href={"/"+this.props.teamName+"/signup/gitlab"+window.location.search}><span className="icon" />{"with GitLab"}</a>
+ <div className="or__container"><span>or</span></div></div>;
}
return (
<div>
<img className="signup-team-logo" src="/static/images/logo.png" />
- <h4>Welcome to { config.SiteName }</h4>
+ <h3 className="text-center extra-margin">Signup to { config.SiteName }</h3>
<div className="form-group form-group--small">
<span></span>
</div>
{ signup_message }
- <p>Your username can be made of lowercase letters and numbers.</p>
<label className="control-label">Username</label>
<div className={ name_error ? "form-group has-error" : "form-group" }>
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" />
{ name_error }
+ <p className="form__hint">Your username can be made of lowercase letters and numbers.</p>
+ <p className="form__hint">{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others"}</p>
</div>
{ email }
<label className="control-label">Password</label>
@@ -142,7 +142,6 @@ module.exports = React.createClass({
<input type="password" ref="password" className="form-control" placeholder="" maxLength="128" />
{ password_error }
</div>
- <p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others"}</p>
<p className={ this.state.original_email == "" ? "hidden" : ""}>{ yourEmailIs } You’ll use this address to sign in to {config.SiteName}.</p>
<div className="checkbox"><label><input type="checkbox" ref="email_service" /> It's ok to send me occassional email with updates about the {config.SiteName} service. </label></div>
<p><button onClick={this.handleSubmit} className="btn-primary btn">Create Account</button></p>
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index ad50b7920..bbd1f84b6 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -36,7 +36,6 @@ module.exports = React.createClass({
this.resize();
this.processMentions();
- this.updateTextdiv();
},
componentWillUnmount: function() {
PostStore.removeAddMentionListener(this._onChange);
@@ -87,7 +86,6 @@ module.exports = React.createClass({
this.processMentions();
this.doProcessMentions = false;
}
- this.updateTextdiv();
this.resize();
},
componentWillReceiveProps: function(nextProps) {
@@ -117,17 +115,6 @@ module.exports = React.createClass({
});
}, 1);
},
- updateTextdiv: function() {
- var html = utils.insertHtmlEntities(this.refs.message.getDOMNode().value);
- for (var k in this.mentions) {
- var m = this.mentions[k];
- var re = new RegExp('( |^)@' + m + '( |$|\n)', 'm');
- html = html.replace(re, '$1<span class="mention">@'+m+'</span>$2');
- }
- var re2 = new RegExp('(^$)(?![.\n])', 'gm');
- html = html.replace(re2, '<br/><br/>');
- $(this.refs.textdiv.getDOMNode()).html(html);
- },
handleChange: function() {
this.props.onUserInput(this.refs.message.getDOMNode().value);
this.resize();
@@ -181,7 +168,7 @@ module.exports = React.createClass({
}
},
processMentions: function() {
- /* First, find all the possible mentions, highlight them in the HTML and add
+ /* First, find all the possible mentions and add
them all to a list of mentions */
var text = utils.insertHtmlEntities(this.refs.message.getDOMNode().value);
@@ -192,9 +179,7 @@ module.exports = React.createClass({
var matches = text.match(re1);
if (!matches) {
- $(this.refs.textdiv.getDOMNode()).text(text);
this.updateMentionTab(null, []);
- this.mentions = [];
return;
}
@@ -207,7 +192,7 @@ module.exports = React.createClass({
}
/* Figure out what the user is currently typing. If it's a mention then we don't
- want to highlight it and add it to the mention list yet, so we remove it if
+ want to add it to the mention list yet, so we remove it if
there is only one occurence of that mention so far. */
var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
@@ -225,14 +210,13 @@ module.exports = React.createClass({
typingMention = text.substring(atIndex+1, caret);
}
- var re3 = new RegExp('@' + typingMention + '( |$|\n)', 'g');
+ var re2 = new RegExp('@' + typingMention + '( |$|\n)', 'g');
- if ((text.match(re3) || []).length === 1 && mentions.indexOf(typingMention) !== -1) {
+ if ((text.match(re2) || []).length === 1 && mentions.indexOf(typingMention) !== -1) {
mentions.splice(mentions.indexOf(typingMention), 1);
}
this.updateMentionTab(null, mentions);
- this.mentions = mentions;
},
checkForNewMention: function(text) {
var caret = utils.getCaretPosition(this.refs.message.getDOMNode());
@@ -287,15 +271,9 @@ module.exports = React.createClass({
elm.value = cmd;
this.handleChange();
},
- scroll: function() {
- var e = this.refs.message.getDOMNode();
- var d = this.refs.textdiv.getDOMNode();
- $(d).scrollTop($(e).scrollTop());
- },
resize: function() {
var e = this.refs.message.getDOMNode();
var w = this.refs.wrapper.getDOMNode();
- var d = this.refs.textdiv.getDOMNode();
var lht = parseInt($(e).css('lineHeight'),10);
var lines = e.scrollHeight / lht;
@@ -303,15 +281,11 @@ module.exports = React.createClass({
if (e.scrollHeight - mod < 167) {
$(e).css({'height':'auto','overflow-y':'hidden'}).height(e.scrollHeight - mod);
- $(d).css({'height':'auto','overflow-y':'hidden'}).height(e.scrollHeight - mod);
$(w).css({'height':'auto'}).height(e.scrollHeight+2);
} else {
$(e).css({'height':'auto','overflow-y':'scroll'}).height(167);
- $(d).css({'height':'auto','overflow-y':'scroll'}).height(167);
$(w).css({'height':'auto'}).height(167);
}
-
- $(d).scrollTop($(e).scrollTop());
},
handleFocus: function() {
var elm = this.refs.message.getDOMNode();
@@ -332,8 +306,7 @@ module.exports = React.createClass({
return (
<div ref="wrapper" className="textarea-wrapper">
<CommandList ref='commands' addCommand={this.addCommand} channelId={this.props.channelId} />
- <div className="form-control textarea-div" ref="textdiv"/>
- <textarea id={this.props.id} ref="message" className={"form-control custom-textarea " + this.state.connection} spellCheck="true" autoComplete="off" autoCorrect="off" rows="1" placeholder={this.props.createMessage} value={this.props.messageText} onInput={this.handleChange} onChange={this.handleChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} onScroll={this.scroll} onFocus={this.handleFocus} onBlur={this.handleBlur} onPaste={this.handlePaste} />
+ <textarea id={this.props.id} ref="message" className={"form-control custom-textarea " + this.state.connection} spellCheck="true" autoComplete="off" autoCorrect="off" rows="1" placeholder={this.props.createMessage} value={this.props.messageText} onInput={this.handleChange} onChange={this.handleChange} onKeyPress={this.handleKeyPress} onKeyDown={this.handleKeyDown} onFocus={this.handleFocus} onBlur={this.handleBlur} onPaste={this.handlePaste} />
</div>
);
}
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index 298f5ee70..e1ae6da52 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -11,6 +11,7 @@ var client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var utils = require('../utils/utils.jsx');
var Constants = require('../utils/constants.jsx');
+var assign = require('object-assign');
function getNotificationsStateFromStores() {
var user = UserStore.getCurrentUser();
@@ -95,11 +96,20 @@ var NotificationsTab = React.createClass({
}.bind(this)
);
},
+ handleClose: function() {
+ $(this.getDOMNode()).find(".form-control").each(function() {
+ this.value = "";
+ });
+
+ this.setState(assign({},getNotificationsStateFromStores(),{server_error: null}));
+ },
componentDidMount: function() {
UserStore.addChangeListener(this._onChange);
+ $('#user_settings1').on('hidden.bs.modal', this.handleClose);
},
componentWillUnmount: function() {
UserStore.removeChangeListener(this._onChange);
+ $('#user_settings1').off('hidden.bs.modal', this.handleClose);
},
_onChange: function() {
var newState = getNotificationsStateFromStores();
@@ -502,6 +512,18 @@ var SecurityTab = React.createClass({
handleDevicesOpen: function() {
$("#user_settings1").modal('hide');
},
+ handleClose: function() {
+ $(this.getDOMNode()).find(".form-control").each(function() {
+ this.value = "";
+ });
+ this.setState({current_password: '', new_password: '', confirm_password: '', server_error: null, password_error: null});
+ },
+ componentDidMount: function() {
+ $('#user_settings1').on('hidden.bs.modal', this.handleClose);
+ },
+ componentWillUnmount: function() {
+ $('#user_settings1').off('hidden.bs.modal', this.handleClose);
+ },
getInitialState: function() {
return { current_password: '', new_password: '', confirm_password: '' };
},
@@ -595,7 +617,7 @@ var SecurityTab = React.createClass({
<br></br>
<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 theme" 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 Sessions</a>
</div>
</div>
);
@@ -699,13 +721,15 @@ 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"});
+ var picture = this.state.picture;
+
+ if(picture.type !== "image/jpeg" && picture.type !== "image/png") {
+ this.setState({client_error: "Only JPG or PNG images may be used for profile pictures"});
return;
}
formData = new FormData();
- formData.append('image', this.state.picture, this.state.picture.name);
+ formData.append('image', picture, picture.name);
client.uploadProfileImage(formData,
function(data) {
@@ -751,6 +775,19 @@ var GeneralTab = React.createClass({
this.submitActive = false
this.props.updateSection(section);
},
+ handleClose: function() {
+ $(this.getDOMNode()).find(".form-control").each(function() {
+ this.value = "";
+ });
+
+ this.setState(assign({}, this.getInitialState(), {client_error: null, server_error: null, email_error: null}));
+ },
+ componentDidMount: function() {
+ $('#user_settings1').on('hidden.bs.modal', this.handleClose);
+ },
+ componentWillUnmount: function() {
+ $('#user_settings1').off('hidden.bs.modal', this.handleClose);
+ },
getInitialState: function() {
var user = this.props.user;
@@ -994,10 +1031,14 @@ var AppearanceTab = React.createClass({
var hex = utils.rgb2hex(e.target.style.backgroundColor);
this.setState({ theme: hex.toLowerCase() });
},
+ handleClose: function() {
+ this.setState({server_error: null});
+ },
componentDidMount: function() {
if (this.props.activeSection === "theme") {
$(this.refs[this.state.theme].getDOMNode()).addClass('active-border');
}
+ $('#user_settings1').on('hidden.bs.modal', this.handleClose);
},
componentDidUpdate: function() {
if (this.props.activeSection === "theme") {
@@ -1005,6 +1046,9 @@ var AppearanceTab = React.createClass({
$(this.refs[this.state.theme].getDOMNode()).addClass('active-border');
}
},
+ componentWillUnmount: function() {
+ $('#user_settings1').off('hidden.bs.modal', this.handleClose);
+ },
getInitialState: function() {
var user = UserStore.getCurrentUser();
var theme = config.ThemeColors != null ? config.ThemeColors[0] : "#2389d7";