-
- { noResults ?
No results
- : results.order.map(function(id) {
- var post = results.posts[id];
- return
- }, this)
- }
-
+
);
}
-});
+}
+
+SearchResults.propTypes = {
+ isMentionSearch: React.PropTypes.bool
+};
diff --git a/web/react/components/search_results_header.jsx b/web/react/components/search_results_header.jsx
new file mode 100644
index 0000000000..694f0c55de
--- /dev/null
+++ b/web/react/components/search_results_header.jsx
@@ -0,0 +1,61 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+var Constants = require('../utils/constants.jsx');
+var ActionTypes = Constants.ActionTypes;
+
+export default class SearchResultsHeader extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleClose = this.handleClose.bind(this);
+ }
+
+ handleClose(e) {
+ e.preventDefault();
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_SEARCH,
+ results: null
+ });
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_SEARCH_TERM,
+ term: null,
+ do_search: false,
+ is_mention_search: false
+ });
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_POST_SELECTED,
+ results: null
+ });
+ }
+
+ render() {
+ var title = 'Search Results';
+
+ if (this.props.isMentionSearch) {
+ title = 'Recent Mentions';
+ }
+
+ return (
+
+ {title}
+
+
+ );
+ }
+}
+
+SearchResultsHeader.propTypes = {
+ isMentionSearch: React.PropTypes.bool
+};
\ No newline at end of file
diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx
new file mode 100644
index 0000000000..aa56f11743
--- /dev/null
+++ b/web/react/components/search_results_item.jsx
@@ -0,0 +1,105 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var PostStore = require('../stores/post_store.jsx');
+var ChannelStore = require('../stores/channel_store.jsx');
+var UserStore = require('../stores/user_store.jsx');
+var UserProfile = require('./user_profile.jsx');
+var utils = require('../utils/utils.jsx');
+var client = require('../utils/client.jsx');
+var AsyncClient = require('../utils/async_client.jsx');
+var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+var Constants = require('../utils/constants.jsx');
+var ActionTypes = Constants.ActionTypes;
+
+export default class SearchResultsItem extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleClick = this.handleClick.bind(this);
+ }
+
+ handleClick(e) {
+ e.preventDefault();
+
+ var self = this;
+
+ client.getPost(
+ this.props.post.channel_id,
+ this.props.post.id,
+ function success(data) {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_POST_SELECTED,
+ post_list: data,
+ from_search: PostStore.getSearchTerm()
+ });
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_SEARCH,
+ results: null,
+ is_mention_search: self.props.isMentionSearch
+ });
+ },
+ function success(err) {
+ AsyncClient.dispatchError(err, 'getPost');
+ }
+ );
+
+ var postChannel = ChannelStore.get(this.props.post.channel_id);
+ var teammate = '';
+
+ if (postChannel.type === 'D') {
+ teammate = utils.getDirectTeammate(this.props.post.channel_id).username;
+ }
+
+ utils.switchChannel(postChannel, teammate);
+ }
+
+ render() {
+ var message = utils.textToJsx(this.props.post.message, {searchTerm: this.props.term, noMentionHighlight: !this.props.isMentionSearch});
+ var channelName = '';
+ var channel = ChannelStore.get(this.props.post.channel_id);
+ var timestamp = UserStore.getCurrentUser().update_at;
+
+ if (channel) {
+ channelName = channel.display_name;
+ if (channel.type === 'D') {
+ channelName = 'Private Message';
+ }
+ }
+
+ return (
+
+
{channelName}
+
+

+
+
+
+
+ -
+
+
+
+
{message}
+
+
+ );
+ }
+}
+
+SearchResultsItem.propTypes = {
+ post: React.PropTypes.object,
+ isMentionSearch: React.PropTypes.bool,
+ term: React.PropTypes.string
+};
\ No newline at end of file
diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx
index 5b12ad7e9e..eaa8397337 100644
--- a/web/react/components/setting_picture.jsx
+++ b/web/react/components/setting_picture.jsx
@@ -1,25 +1,33 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-module.exports = React.createClass({
- setPicture: function(file) {
+export default class SettingPicture extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.setPicture = this.setPicture.bind(this);
+ }
+
+ setPicture(file) {
if (file) {
var reader = new FileReader();
var img = this.refs.image.getDOMNode();
- reader.onload = function(e) {
+ reader.onload = function load(e) {
$(img).attr('src', e.target.result);
};
reader.readAsDataURL(file);
}
- },
- componentWillReceiveProps: function(nextProps) {
+ }
+
+ componentWillReceiveProps(nextProps) {
if (nextProps.picture) {
this.setPicture(nextProps.picture);
}
- },
- render: function() {
+ }
+
+ render() {
var clientError = null;
if (this.props.client_error) {
clientError =
;
@@ -31,14 +39,31 @@ module.exports = React.createClass({
var img = null;
if (this.props.picture) {
- img = (
![]()
);
+ img = (
+
![]()
+ );
} else {
- img = (

);
+ img = (
+

+ );
}
var confirmButton;
if (this.props.loadingPicture) {
- confirmButton =

;
+ confirmButton = (
+

+ );
} else {
var confirmButtonClass = 'btn btn-sm';
if (this.props.submitActive) {
@@ -46,9 +71,15 @@ module.exports = React.createClass({
} else {
confirmButtonClass += ' btn-inactive disabled';
}
- confirmButton =
Save;
+
+ confirmButton = (
+
Save
+ );
}
- var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + config.ProfileWidth + 'px in width and ' + config.ProfileHeight + 'px height.'
+ var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + config.ProfileWidth + 'px in width and ' + config.ProfileHeight + 'px height.';
var self = this;
return (
@@ -65,13 +96,36 @@ module.exports = React.createClass({
{serverError}
{clientError}
- Select
+ Select
+
{confirmButton}
- Cancel
+ Cancel
);
}
-});
+}
+
+SettingPicture.propTypes = {
+ client_error: React.PropTypes.string,
+ server_error: React.PropTypes.string,
+ src: React.PropTypes.string,
+ picture: React.PropTypes.object,
+ loadingPicture: React.PropTypes.bool,
+ submitActive: React.PropTypes.bool,
+ submit: React.PropTypes.func,
+ title: React.PropTypes.string,
+ pictureChange: React.PropTypes.func
+};
\ No newline at end of file
diff --git a/web/react/components/setting_upload.jsx b/web/react/components/setting_upload.jsx
index 5963243080..a7ab03018c 100644
--- a/web/react/components/setting_upload.jsx
+++ b/web/react/components/setting_upload.jsx
@@ -1,36 +1,37 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-module.exports = React.createClass({
- displayName: 'Setting Upload',
- propTypes: {
- title: React.PropTypes.string.isRequired,
- submit: React.PropTypes.func.isRequired,
- fileTypesAccepted: React.PropTypes.string.isRequired,
- clientError: React.PropTypes.string,
- serverError: React.PropTypes.string,
- helpText: React.PropTypes.string
- },
- getInitialState: function() {
- return {
+export default class SettingsUpload extends React.Component {
+
+ constructor(props) {
+ super(props);
+
+ this.doFileSelect = this.doFileSelect.bind(this);
+ this.doSubmit = this.doSubmit.bind(this);
+ this.onFileSelect = this.onFileSelect.bind(this);
+
+ this.state = {
clientError: this.props.clientError,
serverError: this.props.serverError
};
- },
- componentWillReceiveProps: function() {
+ }
+
+ componentWillReceiveProps() {
this.setState({
clientError: this.props.clientError,
serverError: this.props.serverError
});
- },
- doFileSelect: function(e) {
+ }
+
+ doFileSelect(e) {
e.preventDefault();
this.setState({
clientError: '',
serverError: ''
});
- },
- doSubmit: function(e) {
+ }
+
+ doSubmit(e) {
e.preventDefault();
var inputnode = this.refs.uploadinput.getDOMNode();
if (inputnode.files && inputnode.files[0]) {
@@ -38,16 +39,18 @@ module.exports = React.createClass({
} else {
this.setState({clientError: 'No file selected.'});
}
- },
- onFileSelect: function(e) {
+ }
+
+ onFileSelect(e) {
var filename = $(e.target).val();
if (filename.substring(3, 11) === 'fakepath') {
filename = filename.substring(12);
}
$(e.target).closest('li').find('.file-status').addClass('hide');
$(e.target).closest('li').find('.file-name').removeClass('hide').html(filename);
- },
- render: function() {
+ }
+
+ render() {
var clientError = null;
if (this.state.clientError) {
clientError = (
@@ -67,7 +70,11 @@ module.exports = React.createClass({
);
}
-});
+}
+
+SettingsUpload.propTypes = {
+ title: React.PropTypes.string.isRequired,
+ submit: React.PropTypes.func.isRequired,
+ fileTypesAccepted: React.PropTypes.string.isRequired,
+ clientError: React.PropTypes.string,
+ serverError: React.PropTypes.string,
+ helpText: React.PropTypes.object
+};
\ No newline at end of file
diff --git a/web/react/components/sidebar_right_menu.jsx b/web/react/components/sidebar_right_menu.jsx
index 615bc4ef2a..fea889b338 100644
--- a/web/react/components/sidebar_right_menu.jsx
+++ b/web/react/components/sidebar_right_menu.jsx
@@ -5,12 +5,19 @@ var UserStore = require('../stores/user_store.jsx');
var client = require('../utils/client.jsx');
var utils = require('../utils/utils.jsx');
-module.exports = React.createClass({
- handleLogoutClick: function(e) {
+export default class SidebarRightMenu extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleLogoutClick = this.handleLogoutClick.bind(this);
+ }
+
+ handleLogoutClick(e) {
e.preventDefault();
client.logout();
- },
- render: function() {
+ }
+
+ render() {
var teamLink = '';
var inviteLink = '';
var teamSettingsLink = '';
@@ -23,14 +30,22 @@ module.exports = React.createClass({
inviteLink = (
- Invite New Member
+ Invite New Member
);
if (this.props.teamType === 'O') {
teamLink = (
- Get Team Invite Link
+ Get Team Invite Link
);
}
@@ -39,12 +54,20 @@ module.exports = React.createClass({
if (isAdmin) {
teamSettingsLink = (
- Team Settings
+ Team Settings
);
manageLink = (
- Manage Team
+ Manage Team
);
}
@@ -61,23 +84,48 @@ module.exports = React.createClass({
return (
);
}
-});
+}
+
+SidebarRightMenu.propTypes = {
+ teamType: React.PropTypes.string,
+ teamDisplayName: React.PropTypes.string
+};
\ No newline at end of file
diff --git a/web/react/components/team_import_tab.jsx b/web/react/components/team_import_tab.jsx
index e3415d7f44..627ff85f4b 100644
--- a/web/react/components/team_import_tab.jsx
+++ b/web/react/components/team_import_tab.jsx
@@ -4,26 +4,38 @@
var utils = require('../utils/utils.jsx');
var SettingUpload = require('./setting_upload.jsx');
-module.exports = React.createClass({
- displayName: 'Import Tab',
- getInitialState: function() {
- return {status: 'ready', link: ''};
- },
- onImportFailure: function() {
+export default class TeamImportTab extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onImportFailure = this.onImportFailure.bind(this);
+ this.onImportSuccess = this.onImportSuccess.bind(this);
+ this.doImportSlack = this.doImportSlack.bind(this);
+
+ this.state = {
+ status: 'ready',
+ link: ''
+ };
+ }
+
+ onImportFailure() {
this.setState({status: 'fail', link: ''});
- },
- onImportSuccess: function(data) {
+ }
+
+ onImportSuccess(data) {
this.setState({status: 'done', link: 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(data)});
- },
- doImportSlack: function(file) {
+ }
+
+ doImportSlack(file) {
this.setState({status: 'in-progress', link: ''});
utils.importSlack(file, this.onImportSuccess, this.onImportFailure);
- },
- render: function() {
+ }
+
+ render() {
var uploadHelpText = (
- Slack does not allow you to export files, images, private groups or direct messages stored in Slack. Therefore, Slack import to Mattermost only supports importing of text messages in your Slack team's public channels.
+ Slack does not allow you to export files, images, private groups or direct messages stored in Slack. Therefore, Slack import to Mattermost only supports importing of text messages in your Slack team's public channels.
The Slack import to Mattermost is in "Preview". Slack bot posts and channels with underscores do not yet import.
@@ -39,22 +51,25 @@ module.exports = React.createClass({
var messageSection;
switch (this.state.status) {
- case 'ready':
- messageSection = '';
+
+ case 'ready':
+ messageSection = '';
break;
- case 'in-progress':
- messageSection = (
-
Importing...
+ case 'in-progress':
+ messageSection = (
+
Importing...
);
break;
- case 'done':
- messageSection = (
-
Import successful: View Summary
+ case 'done':
+ messageSection = (
+
Import successful: View Summary
);
break;
- case 'fail':
- messageSection = (
-
Import failure: View Summary
+ case 'fail':
+ messageSection = (
+
Import failure: View Summary
);
break;
}
@@ -62,10 +77,22 @@ module.exports = React.createClass({
return (
-
-
Import
+
+ Import
-
+
Import
{uploadSection}
@@ -75,4 +102,4 @@ module.exports = React.createClass({
);
}
-});
+}
diff --git a/web/react/components/team_members.jsx b/web/react/components/team_members.jsx
index 616fd2c995..86c321d06c 100644
--- a/web/react/components/team_members.jsx
+++ b/web/react/components/team_members.jsx
@@ -2,77 +2,131 @@
// See License.txt for license information.
var UserStore = require('../stores/user_store.jsx');
-var ChannelStore = require('../stores/channel_store.jsx');
var MemberListTeam = require('./member_list_team.jsx');
-var Client = require('../utils/client.jsx');
var utils = require('../utils/utils.jsx');
function getStateFromStores() {
var users = UserStore.getProfiles();
- var member_list = [];
- for (var id in users) member_list.push(users[id]);
+ var memberList = [];
+ for (var id in users) {
+ if (users.hasOwnProperty(id)) {
+ memberList.push(users[id]);
+ }
+ }
+
+ memberList.sort(function sort(a, b) {
+ if (a.username < b.username) {
+ return -1;
+ }
+
+ if (a.username > b.username) {
+ return 1;
+ }
- member_list.sort(function(a,b) {
- if (a.username < b.username) return -1;
- if (a.username > b.username) return 1;
return 0;
});
return {
- member_list: member_list
+ member_list: memberList
};
}
-module.exports = React.createClass({
- componentDidMount: function() {
- UserStore.addChangeListener(this._onChange);
+export default class TeamMembers extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onChange = this.onChange.bind(this);
+
+ this.state = getStateFromStores();
+ }
+
+ componentDidMount() {
+ UserStore.addChangeListener(this.onChange);
var self = this;
- $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
- self.setState({ render_members: false });
+ $(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function show() {
+ self.setState({render_members: false});
});
- $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
- self.setState({ render_members: true });
+ $(this.refs.modal.getDOMNode()).on('show.bs.modal', function hide() {
+ self.setState({render_members: true});
});
- },
- componentWillUnmount: function() {
- UserStore.removeChangeListener(this._onChange);
- },
- _onChange: function() {
+ }
+
+ componentWillUnmount() {
+ UserStore.removeChangeListener(this.onChange);
+ }
+
+ onChange() {
var newState = getStateFromStores();
if (!utils.areStatesEqual(newState, this.state)) {
this.setState(newState);
}
- },
- getInitialState: function() {
- return getStateFromStores();
- },
- render: function() {
- var server_error = this.state.server_error ?
: null;
+ }
+
+ render() {
+ var serverError = null;
+
+ if (this.state.server_error) {
+ serverError =
;
+ }
+
+ var renderMembers = '';
+
+ if (this.state.render_members) {
+ renderMembers =
;
+ }
return (
-
-
-
-
-
-
{this.props.teamDisplayName + " Members"}
-
-
-
-
- { this.state.render_members ?
: "" }
+
+
+
+
+
+
{this.props.teamDisplayName + ' Members'}
+
+
+
+
+ {renderMembers}
+
+ {serverError}
- { server_error }
+
+
+
-
-
-
-
);
}
-});
+}
+
+TeamMembers.propTypes = {
+ teamDisplayName: React.PropTypes.string
+};
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index 9b0e906c52..282fb76813 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -8,56 +8,82 @@ var SecurityTab = require('./user_settings_security.jsx');
var GeneralTab = require('./user_settings_general.jsx');
var AppearanceTab = require('./user_settings_appearance.jsx');
-module.exports = React.createClass({
- displayName: 'UserSettings',
- propTypes: {
- activeTab: React.PropTypes.string,
- activeSection: React.PropTypes.string,
- updateSection: React.PropTypes.func,
- updateTab: React.PropTypes.func
- },
- componentDidMount: function() {
+export default class UserSettings extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onListenerChange = this.onListenerChange.bind(this);
+
+ this.state = {user: UserStore.getCurrentUser()};
+ }
+
+ componentDidMount() {
UserStore.addChangeListener(this.onListenerChange);
- },
- componentWillUnmount: function() {
+ }
+
+ componentWillUnmount() {
UserStore.removeChangeListener(this.onListenerChange);
- },
- onListenerChange: function () {
+ }
+
+ onListenerChange() {
var user = UserStore.getCurrentUser();
if (!utils.areStatesEqual(this.state.user, user)) {
this.setState({user: user});
}
- },
- getInitialState: function() {
- return {user: UserStore.getCurrentUser()};
- },
- render: function() {
+ }
+
+ render() {
if (this.props.activeTab === 'general') {
return (
-
+
);
} else if (this.props.activeTab === 'security') {
return (
-
+
);
} else if (this.props.activeTab === 'notifications') {
return (
-
+
);
} else if (this.props.activeTab === 'appearance') {
return (
);
- } else {
- return
;
}
+
+ return
;
}
-});
+}
+
+UserSettings.propTypes = {
+ activeTab: React.PropTypes.string,
+ activeSection: React.PropTypes.string,
+ updateSection: React.PropTypes.func,
+ updateTab: React.PropTypes.func
+};
\ No newline at end of file