Convering client to react-router.
Этот коммит содержится в:
@@ -220,3 +220,33 @@ export function sendEphemeralPost(message, channelId) {
|
||||
|
||||
emitPostRecievedEvent(post);
|
||||
}
|
||||
|
||||
export function loadTeamRequiredPage() {
|
||||
AsyncClient.getAllTeams();
|
||||
}
|
||||
|
||||
export function newLocalizationSelected(locale) {
|
||||
Client.getTranslations(
|
||||
locale,
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_LOCALE,
|
||||
locale,
|
||||
translations: data
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getTranslations');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function viewLoggedIn() {
|
||||
AsyncClient.getChannels();
|
||||
AsyncClient.getChannelExtraInfo();
|
||||
AsyncClient.getMyTeam();
|
||||
AsyncClient.getMe();
|
||||
|
||||
// Clear pending posts (shouldn't have pending posts if we are loading)
|
||||
PostStore.clearPendingPosts();
|
||||
}
|
||||
@@ -8,7 +8,7 @@ const Modal = ReactBootstrap.Modal;
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import {FormattedMessage, FormattedTime, FormattedDate} from 'mm-intl';
|
||||
|
||||
export default class ActivityLogModal extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -144,8 +144,21 @@ export default class ActivityLogModal extends React.Component {
|
||||
id='activity_log.firstTime'
|
||||
defaultMessage='First time active: {date}, {time}'
|
||||
values={{
|
||||
date: firstAccessTime.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}),
|
||||
time: lastAccessTime.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'})
|
||||
date: (
|
||||
<FormattedDate
|
||||
value={firstAccessTime}
|
||||
day='2-digit'
|
||||
month='long'
|
||||
year='numeric'
|
||||
/>
|
||||
),
|
||||
time: (
|
||||
<FormattedTime
|
||||
value={firstAccessTime}
|
||||
hour='2-digit'
|
||||
minute='2-digit'
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -206,8 +219,21 @@ export default class ActivityLogModal extends React.Component {
|
||||
id='activity_log.lastActivity'
|
||||
defaultMessage='Last activity: {date}, {time}'
|
||||
values={{
|
||||
date: lastAccessTime.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}),
|
||||
time: lastAccessTime.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'})
|
||||
date: (
|
||||
<FormattedDate
|
||||
value={lastAccessTime}
|
||||
day='2-digit'
|
||||
month='long'
|
||||
year='numeric'
|
||||
/>
|
||||
),
|
||||
time: (
|
||||
<FormattedTime
|
||||
value={lastAccessTime}
|
||||
hour='2-digit'
|
||||
minute='2-digit'
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,6 @@ import AdminStore from '../../stores/admin_store.jsx';
|
||||
import TeamStore from '../../stores/team_store.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import LoadingScreen from '../loading_screen.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import EmailSettingsTab from './email_settings.jsx';
|
||||
import LogSettingsTab from './log_settings.jsx';
|
||||
@@ -50,11 +49,6 @@ export default class AdminController extends React.Component {
|
||||
selected: props.tab || 'system_analytics',
|
||||
selectedTeam: props.teamId || null
|
||||
};
|
||||
|
||||
if (!props.tab) {
|
||||
var tokenIndex = Utils.getUrlParameter('session_token_index');
|
||||
history.replaceState(null, null, `/admin_console/${this.state.selected}?session_token_index=${tokenIndex}`);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -63,6 +57,9 @@ export default class AdminController extends React.Component {
|
||||
|
||||
AdminStore.addAllTeamsChangeListener(this.onAllTeamsListenerChange);
|
||||
AsyncClient.getAllTeams();
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('[data-toggle="popover"]').popover();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -175,7 +172,7 @@ export default class AdminController extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id='admin_controller'>
|
||||
<div
|
||||
className='sidebar--menu'
|
||||
id='sidebar-menu'
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import TeamStore from '../../stores/team_store.jsx';
|
||||
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
import {Link} from 'react-router';
|
||||
|
||||
function getStateFromStores() {
|
||||
return {currentTeam: TeamStore.getCurrent()};
|
||||
}
|
||||
@@ -18,16 +19,9 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
super(props);
|
||||
this.blockToggle = false;
|
||||
|
||||
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||
|
||||
this.state = getStateFromStores();
|
||||
}
|
||||
|
||||
handleLogoutClick(e) {
|
||||
e.preventDefault();
|
||||
Client.logout();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
|
||||
this.blockToggle = true;
|
||||
@@ -78,15 +72,12 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={this.handleLogoutClick}
|
||||
>
|
||||
<Link to={Utils.getTeamURLFromAddressBar() + '/logout'}>
|
||||
<FormattedMessage
|
||||
id='admin.nav.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className='divider'></li>
|
||||
<li>
|
||||
@@ -116,4 +107,4 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
import AdminSidebarHeader from './admin_sidebar_header.jsx';
|
||||
import SelectTeamModal from './select_team_modal.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -30,8 +29,6 @@ export default class AdminSidebar extends React.Component {
|
||||
handleClick(name, teamId, e) {
|
||||
e.preventDefault();
|
||||
this.props.selectTab(name, teamId);
|
||||
var tokenIndex = Utils.getUrlParameter('session_token_index');
|
||||
history.pushState({name, teamId}, null, `/admin_console/${name}/${teamId || ''}?session_token_index=${tokenIndex}`);
|
||||
}
|
||||
|
||||
isSelected(name, teamId) {
|
||||
@@ -73,7 +70,6 @@ export default class AdminSidebar extends React.Component {
|
||||
}
|
||||
|
||||
teamSelectedModal(teamId) {
|
||||
this.props.selectedTeams[teamId] = 'true';
|
||||
this.setState({showSelectModal: false});
|
||||
this.props.addSelectedTeam(teamId);
|
||||
this.forceUpdate();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
import AdminNavbarDropdown from './admin_navbar_dropdown.jsx';
|
||||
import UserStore from '../../stores/user_store.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -39,7 +38,7 @@ export default class SidebarHeader extends React.Component {
|
||||
profilePicture = (
|
||||
<img
|
||||
className='user__picture'
|
||||
src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at + '&' + Utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -65,4 +64,4 @@ export default class SidebarHeader extends React.Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ export default class UserItem extends React.Component {
|
||||
<td className='row member-div padding--equal'>
|
||||
<img
|
||||
className='post-profile-img pull-left'
|
||||
src={`/api/v1/users/${user.id}/image?time=${user.update_at}&${Utils.getSessionIndex()}`}
|
||||
src={`/api/v1/users/${user.id}/image?time=${user.update_at}`}
|
||||
height='36'
|
||||
width='36'
|
||||
/>
|
||||
|
||||
@@ -5,7 +5,7 @@ import UserStore from '../stores/user_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedDate, FormattedTime} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
sessionRevoked: {
|
||||
@@ -598,8 +598,23 @@ export function formatAuditInfo(audit, formatMessage) {
|
||||
}
|
||||
|
||||
const date = new Date(audit.create_at);
|
||||
let auditInfo = {};
|
||||
auditInfo.timestamp = date.toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'}) + ' - ' + date.toLocaleTimeString(global.window.mm_locale, {hour: '2-digit', minute: '2-digit'});
|
||||
const auditInfo = {};
|
||||
auditInfo.timestamp = (
|
||||
<div>
|
||||
<FormattedDate
|
||||
value={date}
|
||||
day='2-digit'
|
||||
month='short'
|
||||
year='numeric'
|
||||
/>
|
||||
{' - '}
|
||||
<FormattedTime
|
||||
value={date}
|
||||
hour='2-digit'
|
||||
minute='2-digit'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
auditInfo.userId = audit.user_id;
|
||||
auditInfo.desc = auditDesc;
|
||||
auditInfo.ip = audit.ip_address;
|
||||
|
||||
@@ -25,40 +25,43 @@ export default class CenterPanel extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onPreferenceChange = this.onPreferenceChange.bind(this);
|
||||
this.onChannelChange = this.onChannelChange.bind(this);
|
||||
this.onUserChange = this.onUserChange.bind(this);
|
||||
this.getStateFromStores = this.getStateFromStores.bind(this);
|
||||
this.validState = this.validState.bind(this);
|
||||
this.onStoresChange = this.onStoresChange.bind(this);
|
||||
|
||||
this.state = this.getStateFromStores();
|
||||
}
|
||||
getStateFromStores() {
|
||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
||||
this.state = {
|
||||
showTutorialScreens: tutorialStep === TutorialSteps.INTRO_SCREENS,
|
||||
return {
|
||||
showTutorialScreens: tutorialStep <= TutorialSteps.INTRO_SCREENS,
|
||||
showPostFocus: ChannelStore.getPostMode() === ChannelStore.POST_MODE_FOCUS,
|
||||
user: UserStore.getCurrentUser(),
|
||||
channel: ChannelStore.getCurrent(),
|
||||
profiles: JSON.parse(JSON.stringify(UserStore.getProfiles()))
|
||||
};
|
||||
}
|
||||
validState() {
|
||||
return this.state.user && this.state.channel && this.state.profiles;
|
||||
}
|
||||
onStoresChange() {
|
||||
this.setState(this.getStateFromStores());
|
||||
}
|
||||
componentDidMount() {
|
||||
PreferenceStore.addChangeListener(this.onPreferenceChange);
|
||||
ChannelStore.addChangeListener(this.onChannelChange);
|
||||
UserStore.addChangeListener(this.onUserChange);
|
||||
PreferenceStore.addChangeListener(this.onStoresChange);
|
||||
ChannelStore.addChangeListener(this.onStoresChange);
|
||||
UserStore.addChangeListener(this.onStoresChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
PreferenceStore.removeChangeListener(this.onPreferenceChange);
|
||||
ChannelStore.removeChangeListener(this.onChannelChange);
|
||||
UserStore.removeChangeListener(this.onUserChange);
|
||||
}
|
||||
onPreferenceChange() {
|
||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
||||
this.setState({showTutorialScreens: tutorialStep <= TutorialSteps.INTRO_SCREENS});
|
||||
}
|
||||
onChannelChange() {
|
||||
this.setState({showPostFocus: ChannelStore.getPostMode() === ChannelStore.POST_MODE_FOCUS});
|
||||
}
|
||||
onUserChange() {
|
||||
this.setState({user: UserStore.getCurrentUser(), profiles: JSON.parse(JSON.stringify(UserStore.getProfiles()))});
|
||||
PreferenceStore.removeChangeListener(this.onStoresChange);
|
||||
ChannelStore.removeChangeListener(this.onStoresChange);
|
||||
UserStore.removeChangeListener(this.onStoresChange);
|
||||
}
|
||||
render() {
|
||||
const channel = ChannelStore.getCurrent();
|
||||
if (!this.validState()) {
|
||||
return null;
|
||||
}
|
||||
const channel = this.state.channel;
|
||||
var handleClick = null;
|
||||
let postsContainer;
|
||||
let createPost;
|
||||
|
||||
@@ -57,20 +57,33 @@ export default class ChannelHeader extends React.Component {
|
||||
memberChannel: ChannelStore.getCurrentMember(),
|
||||
users: extraInfo.members,
|
||||
userCount: extraInfo.member_count,
|
||||
searchVisible: SearchStore.getSearchResults() !== null
|
||||
searchVisible: SearchStore.getSearchResults() !== null,
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
}
|
||||
validState() {
|
||||
if (!this.state.channel ||
|
||||
!this.state.memberChannel ||
|
||||
!this.state.users ||
|
||||
!this.state.userCount ||
|
||||
!this.state.currentUser) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
componentDidMount() {
|
||||
ChannelStore.addChangeListener(this.onListenerChange);
|
||||
ChannelStore.addExtraInfoChangeListener(this.onListenerChange);
|
||||
SearchStore.addSearchChangeListener(this.onListenerChange);
|
||||
PreferenceStore.addChangeListener(this.onListenerChange);
|
||||
UserStore.addChangeListener(this.onListenerChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeChangeListener(this.onListenerChange);
|
||||
ChannelStore.removeExtraInfoChangeListener(this.onListenerChange);
|
||||
SearchStore.removeSearchChangeListener(this.onListenerChange);
|
||||
PreferenceStore.removeChangeListener(this.onListenerChange);
|
||||
UserStore.removeChangeListener(this.onListenerChange);
|
||||
}
|
||||
onListenerChange() {
|
||||
const newState = this.getStateFromStores();
|
||||
@@ -98,7 +111,7 @@ export default class ChannelHeader extends React.Component {
|
||||
searchMentions(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const user = this.props.user;
|
||||
const user = this.state.currentUser;
|
||||
|
||||
let terms = '';
|
||||
if (user.notify_props && user.notify_props.mention_keys) {
|
||||
@@ -134,7 +147,7 @@ export default class ChannelHeader extends React.Component {
|
||||
});
|
||||
}
|
||||
render() {
|
||||
if (this.state.channel === null) {
|
||||
if (!this.validState()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -163,8 +176,8 @@ export default class ChannelHeader extends React.Component {
|
||||
</Popover>
|
||||
);
|
||||
let channelTitle = channel.display_name;
|
||||
const currentId = this.props.user.id;
|
||||
const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || Utils.isAdmin(this.props.user.roles);
|
||||
const currentId = this.state.currentUser.id;
|
||||
const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || Utils.isAdmin(this.state.currentUser.roles);
|
||||
const isDirect = (this.state.channel.type === 'D');
|
||||
|
||||
if (isDirect) {
|
||||
@@ -252,7 +265,7 @@ export default class ChannelHeader extends React.Component {
|
||||
<ToggleModalButton
|
||||
role='menuitem'
|
||||
dialogType={ChannelInviteModal}
|
||||
dialogProps={{channel}}
|
||||
dialogProps={{channel, currentUser: this.state.currentUser}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='chanel_header.addMembers'
|
||||
@@ -331,7 +344,11 @@ export default class ChannelHeader extends React.Component {
|
||||
<ToggleModalButton
|
||||
role='menuitem'
|
||||
dialogType={ChannelNotificationsModal}
|
||||
dialogProps={{channel}}
|
||||
dialogProps={{
|
||||
channel,
|
||||
channelMember: this.state.memberChannel,
|
||||
currentUser: this.state.currentUser
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='channel_header.notificationPreferences'
|
||||
@@ -497,5 +514,4 @@ export default class ChannelHeader extends React.Component {
|
||||
}
|
||||
|
||||
ChannelHeader.propTypes = {
|
||||
user: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import FilteredUserList from './filtered_user_list.jsx';
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
@@ -16,18 +16,15 @@ import {FormattedMessage} from 'mm-intl';
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class ChannelInviteModal extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onListenerChange = this.onListenerChange.bind(this);
|
||||
this.handleInvite = this.handleInvite.bind(this);
|
||||
|
||||
this.getStateFromStores = this.getStateFromStores.bind(this);
|
||||
this.createInviteButton = this.createInviteButton.bind(this);
|
||||
|
||||
// the state gets populated when the modal is shown
|
||||
this.state = {
|
||||
loading: true
|
||||
};
|
||||
this.state = this.getStateFromStores();
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (!this.props.show && !nextProps.show) {
|
||||
@@ -63,6 +60,20 @@ export default class ChannelInviteModal extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
const currentUser = UserStore.getCurrentUser();
|
||||
if (!currentUser) {
|
||||
return {
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
|
||||
const currentMember = ChannelStore.getCurrentMember();
|
||||
if (!currentMember) {
|
||||
return {
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
|
||||
const memberIds = extraInfo.members.map((user) => user.id);
|
||||
|
||||
var nonmembers = [];
|
||||
@@ -78,7 +89,9 @@ export default class ChannelInviteModal extends React.Component {
|
||||
|
||||
return {
|
||||
nonmembers,
|
||||
loading: false
|
||||
loading: false,
|
||||
currentUser,
|
||||
currentMember
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@@ -93,6 +106,11 @@ export default class ChannelInviteModal extends React.Component {
|
||||
UserStore.removeChangeListener(this.onListenerChange);
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeExtraInfoChangeListener(this.onListenerChange);
|
||||
ChannelStore.removeChangeListener(this.onListenerChange);
|
||||
UserStore.removeChangeListener(this.onListenerChange);
|
||||
}
|
||||
onListenerChange() {
|
||||
var newState = this.getStateFromStores();
|
||||
if (!Utils.areObjectsEqual(this.state, newState)) {
|
||||
@@ -144,7 +162,6 @@ export default class ChannelInviteModal extends React.Component {
|
||||
if (Utils.windowHeight() <= 1200) {
|
||||
maxHeight = Utils.windowHeight() - 300;
|
||||
}
|
||||
|
||||
content = (
|
||||
<FilteredUserList
|
||||
style={{maxHeight}}
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
/* This is a special React control with the sole purpose of making all the AsyncClient calls
|
||||
to the server on page load. This is to prevent other React controls from spamming
|
||||
AsyncClient with requests. */
|
||||
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import SocketStore from '../stores/socket_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import PostStore from '../stores/post_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import PreferenceStore from '../stores/preference_store.jsx';
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
socketError: {
|
||||
id: 'channel_loader.socketError',
|
||||
defaultMessage: 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.'
|
||||
},
|
||||
someone: {
|
||||
id: 'channel_loader.someone',
|
||||
defaultMessage: 'Someone'
|
||||
},
|
||||
posted: {
|
||||
id: 'channel_loader.posted',
|
||||
defaultMessage: 'Posted'
|
||||
},
|
||||
uploadedImage: {
|
||||
id: 'channel_loader.uploadedImage',
|
||||
defaultMessage: ' uploaded an image'
|
||||
},
|
||||
uploadedFile: {
|
||||
id: 'channel_loader.uploadedFile',
|
||||
defaultMessage: ' uploaded a file'
|
||||
},
|
||||
something: {
|
||||
id: 'channel_loader.something',
|
||||
defaultMessage: ' did something new'
|
||||
},
|
||||
wrote: {
|
||||
id: 'channel_loader.wrote',
|
||||
defaultMessage: ' wrote: '
|
||||
},
|
||||
connectionError: {
|
||||
id: 'channel_loader.connection_error',
|
||||
defaultMessage: 'There appears to be a problem with your internet connection.'
|
||||
},
|
||||
unknownError: {
|
||||
id: 'channel_loader.unknown_error',
|
||||
defaultMessage: 'We received an unexpected status code from the server.'
|
||||
}
|
||||
});
|
||||
|
||||
class ChannelLoader extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.intervalId = null;
|
||||
|
||||
this.onSocketChange = this.onSocketChange.bind(this);
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
SocketStore.setTranslations({
|
||||
socketError: formatMessage(holders.socketError),
|
||||
someone: formatMessage(holders.someone),
|
||||
posted: formatMessage(holders.posted),
|
||||
uploadedImage: formatMessage(holders.uploadedImage),
|
||||
uploadedFile: formatMessage(holders.uploadedFile),
|
||||
something: formatMessage(holders.something),
|
||||
wrote: formatMessage(holders.wrote)
|
||||
});
|
||||
|
||||
Client.setTranslations({
|
||||
connectionError: formatMessage(holders.connectionError),
|
||||
unknownError: formatMessage(holders.unknownError)
|
||||
});
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
componentDidMount() {
|
||||
/* Initial aysnc loads */
|
||||
AsyncClient.getPosts(ChannelStore.getCurrentId());
|
||||
AsyncClient.getChannels();
|
||||
AsyncClient.getChannelExtraInfo();
|
||||
AsyncClient.findTeams();
|
||||
AsyncClient.getMyTeam();
|
||||
setTimeout(() => AsyncClient.getStatuses(), 3000); // temporary until statuses are reworked a bit
|
||||
|
||||
/* Perform pending post clean-up */
|
||||
PostStore.clearPendingPosts();
|
||||
|
||||
/* Set up interval functions */
|
||||
this.intervalId = setInterval(() => AsyncClient.getStatuses(), 30000);
|
||||
|
||||
/* Device tracking setup */
|
||||
var iOS = (/(iPad|iPhone|iPod)/g).test(navigator.userAgent);
|
||||
if (iOS) {
|
||||
$('body').addClass('ios');
|
||||
}
|
||||
|
||||
/* Set up tracking for whether the window is active */
|
||||
window.isActive = true;
|
||||
|
||||
$(window).on('focus', function windowFocus() {
|
||||
AsyncClient.updateLastViewedAt();
|
||||
ChannelStore.resetCounts(ChannelStore.getCurrentId());
|
||||
ChannelStore.emitChange();
|
||||
window.isActive = true;
|
||||
});
|
||||
|
||||
$(window).on('blur', function windowBlur() {
|
||||
window.isActive = false;
|
||||
});
|
||||
|
||||
/* Start global change listeners setup */
|
||||
SocketStore.addChangeListener(this.onSocketChange);
|
||||
|
||||
/* Update CSS classes to match user theme */
|
||||
var user = UserStore.getCurrentUser();
|
||||
|
||||
if ($.isPlainObject(user.theme_props) && !$.isEmptyObject(user.theme_props)) {
|
||||
Utils.applyTheme(user.theme_props);
|
||||
} else {
|
||||
Utils.applyTheme(Constants.THEMES.default);
|
||||
}
|
||||
|
||||
// if preferences have already been stored in local storage do not wait until preference store change is fired and handled in channel.jsx
|
||||
const selectedFont = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT);
|
||||
Utils.applyFont(selectedFont);
|
||||
|
||||
$('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before');
|
||||
} else {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--after');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--before');
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('mouseenter mouseleave', '.search-item__container .post', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).closest('.search-item__container').find('.date-separator').addClass('hovered--after');
|
||||
$(this).closest('.search-item__container').next('div').find('.date-separator').addClass('hovered--before');
|
||||
} else {
|
||||
$(this).closest('.search-item__container').find('.date-separator').removeClass('hovered--after');
|
||||
$(this).closest('.search-item__container').next('div').find('.date-separator').removeClass('hovered--before');
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('mouseenter mouseleave', '.post.post--comment.same--root', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--comment');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--comment');
|
||||
} else {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--comment');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--comment');
|
||||
}
|
||||
});
|
||||
|
||||
/* Prevent backspace from navigating back a page */
|
||||
$(window).on('keydown.preventBackspace', (e) => {
|
||||
if (e.which === 8 && !$(e.target).is('input, textarea')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.intervalId);
|
||||
|
||||
$(window).off('focus');
|
||||
$(window).off('blur');
|
||||
|
||||
SocketStore.removeChangeListener(this.onSocketChange);
|
||||
|
||||
$('body').off('click.userpopover');
|
||||
$('body').off('mouseenter mouseleave', '.post');
|
||||
$('body').off('mouseenter mouseleave', '.post.post--comment.same--root');
|
||||
|
||||
$('.modal').off('show.bs.modal');
|
||||
|
||||
$(window).off('keydown.preventBackspace');
|
||||
}
|
||||
onSocketChange(msg) {
|
||||
if (msg && msg.user_id && msg.user_id !== UserStore.getCurrentId()) {
|
||||
UserStore.setStatus(msg.user_id, 'online');
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return <div/>;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelLoader.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(ChannelLoader);
|
||||
@@ -6,7 +6,6 @@ import SettingItemMin from './setting_item_min.jsx';
|
||||
import SettingItemMax from './setting_item_max.jsx';
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
@@ -15,7 +14,6 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onListenerChange = this.onListenerChange.bind(this);
|
||||
this.updateSection = this.updateSection.bind(this);
|
||||
|
||||
this.handleSubmitNotifyLevel = this.handleSubmitNotifyLevel.bind(this);
|
||||
@@ -26,58 +24,41 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
this.handleUpdateMarkUnreadLevel = this.handleUpdateMarkUnreadLevel.bind(this);
|
||||
this.createMarkUnreadLevelSection = this.createMarkUnreadLevelSection.bind(this);
|
||||
|
||||
const member = ChannelStore.getMember(props.channel.id);
|
||||
this.state = {
|
||||
notifyLevel: member.notify_props.desktop,
|
||||
markUnreadLevel: member.notify_props.mark_unread,
|
||||
channelId: ChannelStore.getCurrentId(),
|
||||
activeSection: ''
|
||||
activeSection: '',
|
||||
notifyLevel: '',
|
||||
unreadLevel: ''
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props.show && nextProps.show) {
|
||||
this.onListenerChange();
|
||||
ChannelStore.addChangeListener(this.onListenerChange);
|
||||
} else {
|
||||
ChannelStore.removeChangeListener(this.onListenerChange);
|
||||
}
|
||||
}
|
||||
onListenerChange() {
|
||||
const curChannelId = ChannelStore.getCurrentId();
|
||||
|
||||
if (!curChannelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newState = {channelId: curChannelId};
|
||||
const member = ChannelStore.getMember(curChannelId);
|
||||
|
||||
if (member.notify_props.desktop !== this.state.notifyLevel || member.notify_props.mark_unread !== this.state.mark_unread) {
|
||||
newState.notifyLevel = member.notify_props.desktop;
|
||||
newState.markUnreadLevel = member.notify_props.mark_unread;
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
}
|
||||
updateSection(section) {
|
||||
this.setState({activeSection: section});
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.props.show && nextProps.show) {
|
||||
this.setState({
|
||||
notifyLevel: nextProps.channelMember.notify_props.desktop,
|
||||
unreadLevel: nextProps.channelMember.notify_props.mark_unread
|
||||
});
|
||||
}
|
||||
}
|
||||
handleSubmitNotifyLevel() {
|
||||
var channelId = this.state.channelId;
|
||||
var channelId = this.props.channel.id;
|
||||
var notifyLevel = this.state.notifyLevel;
|
||||
|
||||
if (ChannelStore.getMember(channelId).notify_props.desktop === notifyLevel) {
|
||||
if (this.props.channelMember.notify_props.desktop === notifyLevel) {
|
||||
this.updateSection('');
|
||||
return;
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data.channel_id = channelId;
|
||||
data.user_id = UserStore.getCurrentId();
|
||||
data.user_id = this.props.currentUser.id;
|
||||
data.desktop = notifyLevel;
|
||||
|
||||
//TODO: This should be moved to event_helpers
|
||||
Client.updateNotifyProps(data,
|
||||
() => {
|
||||
// YUCK
|
||||
var member = ChannelStore.getMember(channelId);
|
||||
member.notify_props.desktop = notifyLevel;
|
||||
ChannelStore.setChannelMember(member);
|
||||
@@ -92,11 +73,8 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
this.setState({notifyLevel});
|
||||
}
|
||||
createNotifyLevelSection(serverError) {
|
||||
var handleUpdateSection;
|
||||
|
||||
const user = UserStore.getCurrentUser();
|
||||
const globalNotifyLevel = user.notify_props.desktop;
|
||||
|
||||
// Get glabal user setting for notifications
|
||||
const globalNotifyLevel = this.props.currentUser.notify_props.desktop;
|
||||
let globalNotifyLevelName;
|
||||
if (globalNotifyLevel === 'all') {
|
||||
globalNotifyLevelName = (
|
||||
@@ -128,13 +106,15 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
/>
|
||||
);
|
||||
|
||||
const notificationLevel = this.state.notifyLevel;
|
||||
|
||||
if (this.state.activeSection === 'desktop') {
|
||||
var notifyActive = [false, false, false, false];
|
||||
if (this.state.notifyLevel === 'default') {
|
||||
const notifyActive = [false, false, false, false];
|
||||
if (notificationLevel === 'default') {
|
||||
notifyActive[0] = true;
|
||||
} else if (this.state.notifyLevel === 'all') {
|
||||
} else if (notificationLevel === 'all') {
|
||||
notifyActive[1] = true;
|
||||
} else if (this.state.notifyLevel === 'mention') {
|
||||
} else if (notificationLevel === 'mention') {
|
||||
notifyActive[2] = true;
|
||||
} else {
|
||||
notifyActive[3] = true;
|
||||
@@ -196,7 +176,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
</div>
|
||||
);
|
||||
|
||||
handleUpdateSection = function updateSection(e) {
|
||||
const handleUpdateSection = function updateSection(e) {
|
||||
this.updateSection('');
|
||||
this.onListenerChange();
|
||||
e.preventDefault();
|
||||
@@ -224,7 +204,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
}
|
||||
|
||||
var describe;
|
||||
if (this.state.notifyLevel === 'default') {
|
||||
if (notificationLevel === 'default') {
|
||||
describe = (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.globalDefault'
|
||||
@@ -233,45 +213,44 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.notifyLevel === 'mention') {
|
||||
} else if (notificationLevel === 'mention') {
|
||||
describe = (<FormattedMessage id='channel_notifications.onlyMentions'/>);
|
||||
} else if (this.state.notifyLevel === 'all') {
|
||||
} else if (notificationLevel === 'all') {
|
||||
describe = (<FormattedMessage id='channel_notifications.allActivity'/>);
|
||||
} else {
|
||||
describe = (<FormattedMessage id='channel_notifications.never'/>);
|
||||
}
|
||||
|
||||
handleUpdateSection = function updateSection(e) {
|
||||
this.updateSection('desktop');
|
||||
e.preventDefault();
|
||||
}.bind(this);
|
||||
|
||||
return (
|
||||
<SettingItemMin
|
||||
title={sendDesktop}
|
||||
describe={describe}
|
||||
updateSection={handleUpdateSection}
|
||||
updateSection={() => {
|
||||
this.updateSection('desktop');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
handleSubmitMarkUnreadLevel() {
|
||||
const channelId = this.state.channelId;
|
||||
const markUnreadLevel = this.state.markUnreadLevel;
|
||||
const channelId = this.props.channel.id;
|
||||
const markUnreadLevel = this.state.unreadLevel;
|
||||
|
||||
if (ChannelStore.getMember(channelId).notify_props.mark_unread === markUnreadLevel) {
|
||||
if (this.props.channelMember.notify_props.mark_unread === markUnreadLevel) {
|
||||
this.updateSection('');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
channel_id: channelId,
|
||||
user_id: UserStore.getCurrentId(),
|
||||
user_id: this.props.currentUser.id,
|
||||
mark_unread: markUnreadLevel
|
||||
};
|
||||
|
||||
//TODO: This should be fixed, moved to event_helpers
|
||||
Client.updateNotifyProps(data,
|
||||
() => {
|
||||
// Yuck...
|
||||
var member = ChannelStore.getMember(channelId);
|
||||
member.notify_props.mark_unread = markUnreadLevel;
|
||||
ChannelStore.setChannelMember(member);
|
||||
@@ -283,8 +262,8 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
handleUpdateMarkUnreadLevel(markUnreadLevel) {
|
||||
this.setState({markUnreadLevel});
|
||||
handleUpdateMarkUnreadLevel(unreadLevel) {
|
||||
this.setState({unreadLevel});
|
||||
}
|
||||
|
||||
createMarkUnreadLevelSection(serverError) {
|
||||
@@ -303,7 +282,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
<label>
|
||||
<input
|
||||
type='radio'
|
||||
checked={this.state.markUnreadLevel === 'all'}
|
||||
checked={this.state.unreadLevel === 'all'}
|
||||
onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'all')}
|
||||
/>
|
||||
<FormattedMessage
|
||||
@@ -317,7 +296,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
<label>
|
||||
<input
|
||||
type='radio'
|
||||
checked={this.state.markUnreadLevel === 'mention'}
|
||||
checked={this.state.unreadLevel === 'mention'}
|
||||
onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'mention')}
|
||||
/>
|
||||
<FormattedMessage id='channel_notifications.onlyMentions'/>
|
||||
@@ -355,7 +334,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
} else {
|
||||
let describe;
|
||||
|
||||
if (!this.state.markUnreadLevel || this.state.markUnreadLevel === 'all') {
|
||||
if (!this.state.unreadLevel || this.state.unreadLevel === 'all') {
|
||||
describe = (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.allUnread'
|
||||
@@ -430,5 +409,7 @@ export default class ChannelNotificationsModal extends React.Component {
|
||||
ChannelNotificationsModal.propTypes = {
|
||||
show: React.PropTypes.bool.isRequired,
|
||||
onHide: React.PropTypes.func.isRequired,
|
||||
channel: React.PropTypes.object.isRequired
|
||||
channel: React.PropTypes.object.isRequired,
|
||||
channelMember: React.PropTypes.object.isRequired,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -2,34 +2,11 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import CenterPanel from '../components/center_panel.jsx';
|
||||
import Sidebar from '../components/sidebar.jsx';
|
||||
import SidebarRight from '../components/sidebar_right.jsx';
|
||||
import SidebarRightMenu from '../components/sidebar_right_menu.jsx';
|
||||
|
||||
export default class ChannelView extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='container-fluid'>
|
||||
<div
|
||||
className='sidebar--right'
|
||||
id='sidebar-right'
|
||||
>
|
||||
<SidebarRight/>
|
||||
</div>
|
||||
<div
|
||||
className='sidebar--menu'
|
||||
id='sidebar-menu'
|
||||
>
|
||||
<SidebarRightMenu/>
|
||||
</div>
|
||||
<div
|
||||
className='sidebar--left'
|
||||
id='sidebar-left'
|
||||
>
|
||||
<Sidebar/>
|
||||
</div>
|
||||
<CenterPanel/>
|
||||
</div>
|
||||
<CenterPanel/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -37,4 +14,5 @@ ChannelView.defaultProps = {
|
||||
};
|
||||
|
||||
ChannelView.propTypes = {
|
||||
params: React.PropTypes.object
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import EmailToSSO from './email_to_sso.jsx';
|
||||
import SSOToEmail from './sso_to_email.jsx';
|
||||
import TeamStore from '../../stores/team_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -10,11 +11,46 @@ export default class ClaimAccount extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onTeamChange = this.onTeamChange.bind(this);
|
||||
this.updateStateFromStores = this.updateStateFromStores.bind(this);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
componentWillMount() {
|
||||
this.setState({
|
||||
email: this.props.location.query.email,
|
||||
newType: this.props.location.query.new_type,
|
||||
oldType: this.props.location.query.old_type,
|
||||
teamName: this.props.params.team,
|
||||
teamDisplayName: ''
|
||||
});
|
||||
this.updateStateFromStores();
|
||||
}
|
||||
componentDidMount() {
|
||||
TeamStore.addChangeListener(this.onTeamChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
TeamStore.removeChangeListener(this.onTeamChange);
|
||||
}
|
||||
updateStateFromStores() {
|
||||
const team = TeamStore.getByName(this.state.teamName);
|
||||
let displayName = '';
|
||||
if (team) {
|
||||
displayName = team.displayName;
|
||||
}
|
||||
this.setState({
|
||||
teamDisplayName: displayName
|
||||
});
|
||||
}
|
||||
onTeamChange() {
|
||||
this.updateStateFromStores();
|
||||
}
|
||||
render() {
|
||||
if (this.state.teamDisplayName === '') {
|
||||
return (<div/>);
|
||||
}
|
||||
let content;
|
||||
if (this.props.email === '') {
|
||||
if (this.state.email === '') {
|
||||
content = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
@@ -23,36 +59,55 @@ export default class ClaimAccount extends React.Component {
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
} else if (this.props.currentType === '' && this.props.newType !== '') {
|
||||
} else if (this.state.oldType === '' && this.state.newType !== '') {
|
||||
content = (
|
||||
<EmailToSSO
|
||||
email={this.props.email}
|
||||
type={this.props.newType}
|
||||
teamName={this.props.teamName}
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
email={this.state.email}
|
||||
type={this.state.newType}
|
||||
teamName={this.state.teamName}
|
||||
teamDisplayName={this.state.teamDisplayName}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<SSOToEmail
|
||||
email={this.props.email}
|
||||
currentType={this.props.currentType}
|
||||
teamName={this.props.teamName}
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
email={this.state.email}
|
||||
currentType={this.state.oldType}
|
||||
teamName={this.state.teamName}
|
||||
teamDisplayName={this.state.teamDisplayName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return content;
|
||||
return (
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<div id='claim'>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ClaimAccount.defaultProps = {
|
||||
};
|
||||
ClaimAccount.propTypes = {
|
||||
currentType: React.PropTypes.string.isRequired,
|
||||
newType: React.PropTypes.string.isRequired,
|
||||
email: React.PropTypes.string.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired,
|
||||
teamDisplayName: React.PropTypes.string.isRequired
|
||||
params: React.PropTypes.object.isRequired,
|
||||
location: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -159,7 +159,7 @@ SSOToEmail.propTypes = {
|
||||
currentType: React.PropTypes.string.isRequired,
|
||||
email: React.PropTypes.string.isRequired,
|
||||
teamName: React.PropTypes.string.isRequired,
|
||||
teamDisplayName: React.PropTypes.string.isRequired
|
||||
teamDisplayName: React.PropTypes.string
|
||||
};
|
||||
|
||||
export default injectIntl(SSOToEmail);
|
||||
|
||||
@@ -9,7 +9,7 @@ import PostDeletedModal from './post_deleted_modal.jsx';
|
||||
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
@@ -165,7 +165,7 @@ class CreatePost extends React.Component {
|
||||
|
||||
const channel = ChannelStore.get(this.state.channelId);
|
||||
|
||||
EventHelpers.emitUserPostedEvent(post);
|
||||
GlobalActions.emitUserPostedEvent(post);
|
||||
this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null});
|
||||
|
||||
Client.createPost(post, channel,
|
||||
@@ -177,7 +177,7 @@ class CreatePost extends React.Component {
|
||||
member.last_viewed_at = Date.now();
|
||||
ChannelStore.setChannelMember(member);
|
||||
|
||||
EventHelpers.emitPostRecievedEvent(data);
|
||||
GlobalActions.emitPostRecievedEvent(data);
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.post.create_post.root_id.app_error') {
|
||||
|
||||
@@ -9,6 +9,8 @@ import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
export default class DeleteChannelModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -21,11 +23,11 @@ export default class DeleteChannelModal extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/town-square');
|
||||
Client.deleteChannel(
|
||||
this.props.channel.id,
|
||||
() => {
|
||||
AsyncClient.getChannels(true);
|
||||
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/town-square';
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'handleDelete');
|
||||
|
||||
82
web/react/components/do_verify_email.jsx
Обычный файл
82
web/react/components/do_verify_email.jsx
Обычный файл
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
export default class DoVerifyEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
verifyStatus: 'pending',
|
||||
serverError: ''
|
||||
};
|
||||
}
|
||||
componentWillMount() {
|
||||
const uid = this.props.location.query.uid;
|
||||
const hid = this.props.location.query.hid;
|
||||
const teamName = this.props.location.query.teamname;
|
||||
const email = this.props.location.query.email;
|
||||
|
||||
Client.verifyEmail(
|
||||
() => {
|
||||
browserHistory.push('/' + teamName + '/login?extra=verified&email=' + email);
|
||||
},
|
||||
(err) => {
|
||||
this.setState({verifyStatus: 'failure', serverError: err.message});
|
||||
},
|
||||
uid,
|
||||
hid
|
||||
);
|
||||
}
|
||||
render() {
|
||||
if (this.state.verifyStatus !== 'failure') {
|
||||
return (<LoadingScreen/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='email_verify.almost'
|
||||
defaultMessage='{siteName}: You are almost done'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage id='email_verify.verifyFailed'/>
|
||||
</p>
|
||||
<p className='alert alert-danger'>
|
||||
<i className='fa fa-times'/>
|
||||
{this.state.serverError}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DoVerifyEmail.defaultProps = {
|
||||
};
|
||||
DoVerifyEmail.propTypes = {
|
||||
location: React.PropTypes.object.isRequired
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as TextFormatting from '../utils/text_formatting.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
|
||||
export default class Docs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
UserStore.setCurrentUser(global.window.mm_user || {});
|
||||
|
||||
this.state = {text: ''};
|
||||
const errorState = {text: '## 404'};
|
||||
|
||||
if (props.site) {
|
||||
$.get(`/static/help/${props.site}_${global.window.mm_locale}.md`).then((response) => {
|
||||
this.setState({text: response});
|
||||
}, () => {
|
||||
this.setState(errorState);
|
||||
});
|
||||
} else {
|
||||
this.setState(errorState);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.state.text)}}
|
||||
>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Docs.defaultProps = {
|
||||
site: ''
|
||||
};
|
||||
Docs.propTypes = {
|
||||
site: React.PropTypes.string
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import Textbox from './textbox.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import PostStore from '../stores/post_store.jsx';
|
||||
@@ -45,7 +45,7 @@ class EditPostModal extends React.Component {
|
||||
delete tempState.editText;
|
||||
BrowserStore.setItem('edit_state_transfer', tempState);
|
||||
$('#edit_post').modal('hide');
|
||||
EventHelpers.showDeletePostModal(PostStore.getPost(this.state.channel_id, this.state.post_id), this.state.comments);
|
||||
GlobalActions.showDeletePostModal(PostStore.getPost(this.state.channel_id, this.state.post_id), this.state.comments);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
export default class EmailVerify extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleResend = this.handleResend.bind(this);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
handleResend() {
|
||||
const newAddress = window.location.href.replace('&resend_success=true', '');
|
||||
window.location.href = newAddress + '&resend=true';
|
||||
}
|
||||
render() {
|
||||
var title = '';
|
||||
var body = '';
|
||||
var resend = '';
|
||||
var resendConfirm = '';
|
||||
if (this.props.isVerified === 'true') {
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='email_verify.verified'
|
||||
defaultMessage='{siteName} Email Verified'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
);
|
||||
body = (
|
||||
<FormattedHTMLMessage
|
||||
id='email_verify.verifiedBody'
|
||||
defaultMessage='<p>Your email has been verified! Click <a href={url}>here</a> to log in.</p>'
|
||||
values={{
|
||||
url: this.props.teamURL + '?email=' + this.props.userEmail
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='email_verify.almost'
|
||||
defaultMessage='{siteName}: You are almost done'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
);
|
||||
body = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='email_verify.notVerifiedBody'
|
||||
defaultMessage='Please verify your email address. Check your inbox for an email.'
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
resend = (
|
||||
<button
|
||||
onClick={this.handleResend}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='email_verify.resend'
|
||||
defaultMessage='Resend Email'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
if (this.props.resendSuccess) {
|
||||
resendConfirm = (
|
||||
<div><br/><p className='alert alert-success'><i className='fa fa-check'></i>
|
||||
<FormattedMessage
|
||||
id='email_verify.sent'
|
||||
defaultMessage=' Verification email sent.'
|
||||
/>
|
||||
</p></div>);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>{title}</h3>
|
||||
<div>
|
||||
{body}
|
||||
{resend}
|
||||
{resendConfirm}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EmailVerify.defaultProps = {
|
||||
isVerified: 'false',
|
||||
teamURL: '',
|
||||
userEmail: '',
|
||||
resendSuccess: 'false'
|
||||
};
|
||||
EmailVerify.propTypes = {
|
||||
isVerified: React.PropTypes.string,
|
||||
teamURL: React.PropTypes.string,
|
||||
userEmail: React.PropTypes.string,
|
||||
resendSuccess: React.PropTypes.string
|
||||
};
|
||||
@@ -43,7 +43,7 @@ class FileAttachment extends React.Component {
|
||||
|
||||
if (type === 'image') {
|
||||
var self = this; // Need this reference since we use the given "this"
|
||||
$('<img/>').attr('src', fileInfo.path + '_thumb.jpg?' + utils.getSessionIndex()).load(function loadWrapper(path, name) {
|
||||
$('<img/>').attr('src', fileInfo.path + '_thumb.jpg').load(function loadWrapper(path, name) {
|
||||
return function loader() {
|
||||
$(this).remove();
|
||||
if (name in self.refs) {
|
||||
@@ -114,7 +114,7 @@ class FileAttachment extends React.Component {
|
||||
var re3 = new RegExp('\\)', 'g');
|
||||
var url = fileUrl.replace(re1, '%20').replace(re2, '%28').replace(re3, '%29');
|
||||
|
||||
$(imgDiv).css('background-image', 'url(' + url + '_thumb.jpg?' + utils.getSessionIndex() + ')');
|
||||
$(imgDiv).css('background-image', 'url(' + url + '_thumb.jpg)');
|
||||
}
|
||||
}
|
||||
removeBackgroundImage(name) {
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
var holders = defineMessages({
|
||||
submitError: {
|
||||
id: 'find_team.submitError',
|
||||
defaultMessage: 'Please enter a valid email address'
|
||||
},
|
||||
placeholder: {
|
||||
id: 'find_team.placeholder',
|
||||
defaultMessage: 'you@domain.com'
|
||||
}
|
||||
});
|
||||
|
||||
class FindTeam extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var state = { };
|
||||
|
||||
var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
|
||||
if (!email || !utils.isEmail(email)) {
|
||||
state.email_error = this.props.intl.formatMessage(holders.submitError);
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.email_error = '';
|
||||
|
||||
client.findTeamsSendEmail(email,
|
||||
function success() {
|
||||
state.sent = true;
|
||||
this.setState(state);
|
||||
}.bind(this),
|
||||
function fail(err) {
|
||||
state.email_error = err.message;
|
||||
this.setState(state);
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
var emailError = null;
|
||||
var emailErrorClass = 'form-group';
|
||||
|
||||
if (this.state.email_error) {
|
||||
emailError = <label className='control-label'>{this.state.email_error}</label>;
|
||||
emailErrorClass = 'form-group has-error';
|
||||
}
|
||||
|
||||
if (this.state.sent) {
|
||||
return (
|
||||
<div>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='find_team.findTitle'
|
||||
defaultMessage='Find Your Team'
|
||||
/>
|
||||
</h4>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='find_team.findDescription'
|
||||
defaultMessage='An email was sent with links to any teams to which you are a member.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='find_team.findTitle'
|
||||
defaultMessage='Find Your Team'
|
||||
/>
|
||||
</h4>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='find_team.getLinks'
|
||||
defaultMessage='Get an email with links to any teams to which you are a member.'
|
||||
/>
|
||||
</p>
|
||||
<div className='form-group'>
|
||||
<label className='control-label'>
|
||||
<FormattedMessage
|
||||
id='find_team.email'
|
||||
defaultMessage='Email'
|
||||
/>
|
||||
</label>
|
||||
<div className={emailErrorClass}>
|
||||
<input
|
||||
type='text'
|
||||
ref='email'
|
||||
className='form-control'
|
||||
placeholder={this.props.intl.formatMessage(holders.placeholder)}
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
{emailError}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className='btn btn-md btn-primary'
|
||||
type='submit'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='find_team.send'
|
||||
defaultMessage='Send'
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FindTeam.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(FindTeam);
|
||||
@@ -5,7 +5,7 @@ import * as utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import ModalStore from '../stores/modal_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
@@ -223,7 +223,7 @@ class InviteMemberModal extends React.Component {
|
||||
showGetTeamInviteLinkModal() {
|
||||
this.handleHide(false);
|
||||
|
||||
EventHelpers.showGetTeamInviteLinkModal();
|
||||
GlobalActions.showGetTeamInviteLinkModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
224
web/react/components/logged_in.jsx
Обычный файл
224
web/react/components/logged_in.jsx
Обычный файл
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import SocketStore from '../stores/socket_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import PreferenceStore from '../stores/preference_store.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import ErrorBar from '../components/error_bar.jsx';
|
||||
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
import SidebarRight from '../components/sidebar_right.jsx';
|
||||
import SidebarRightMenu from '../components/sidebar_right_menu.jsx';
|
||||
|
||||
// Modals
|
||||
import GetPostLinkModal from '../components/get_post_link_modal.jsx';
|
||||
import GetTeamInviteLinkModal from '../components/get_team_invite_link_modal.jsx';
|
||||
import EditPostModal from '../components/edit_post_modal.jsx';
|
||||
import DeletePostModal from '../components/delete_post_modal.jsx';
|
||||
import MoreChannelsModal from '../components/more_channels.jsx';
|
||||
import TeamSettingsModal from '../components/team_settings_modal.jsx';
|
||||
import RemovedFromChannelModal from '../components/removed_from_channel_modal.jsx';
|
||||
import RegisterAppModal from '../components/register_app_modal.jsx';
|
||||
import ImportThemeModal from '../components/user_settings/import_theme_modal.jsx';
|
||||
import InviteMemberModal from '../components/invite_member_modal.jsx';
|
||||
import SelectTeamModal from '../components/admin_console/select_team_modal.jsx';
|
||||
|
||||
const CLIENT_STATUS_INTERVAL = 30000;
|
||||
const BACKSPACE_CHAR = 8;
|
||||
|
||||
export default class LoggedIn extends React.Component {
|
||||
constructor(params) {
|
||||
super(params);
|
||||
|
||||
this.onUserChanged = this.onUserChanged.bind(this);
|
||||
}
|
||||
onUserChanged() {
|
||||
// Grab the current user
|
||||
const user = UserStore.getCurrentUser();
|
||||
|
||||
// Update segment indentify
|
||||
if (global.window.mm_config.SegmentDeveloperKey != null && global.window.mm_config.SegmentDeveloperKey !== '') {
|
||||
global.window.analytics.identify(user.id, {
|
||||
name: user.nickname,
|
||||
email: user.email,
|
||||
createdAt: user.create_at,
|
||||
username: user.username,
|
||||
team_id: user.team_id,
|
||||
id: user.id
|
||||
});
|
||||
}
|
||||
|
||||
// Update CSS classes to match user theme
|
||||
if (user) {
|
||||
if ($.isPlainObject(user.theme_props) && !$.isEmptyObject(user.theme_props)) {
|
||||
Utils.applyTheme(user.theme_props);
|
||||
} else {
|
||||
Utils.applyTheme(Constants.THEMES.default);
|
||||
}
|
||||
}
|
||||
}
|
||||
onSocketChange(msg) {
|
||||
if (msg && msg.user_id && msg.user_id !== UserStore.getCurrentId()) {
|
||||
UserStore.setStatus(msg.user_id, 'online');
|
||||
}
|
||||
}
|
||||
componentWillMount() {
|
||||
// Emit view action
|
||||
GlobalActions.viewLoggedIn();
|
||||
|
||||
// Listen for user
|
||||
UserStore.addChangeListener(this.onUserChanged);
|
||||
|
||||
// Add listner for socker store
|
||||
SocketStore.addChangeListener(this.onSocketChange);
|
||||
|
||||
// Get all statuses regularally. (Soon to be switched to websocket)
|
||||
this.intervalId = setInterval(() => AsyncClient.getStatuses(), CLIENT_STATUS_INTERVAL);
|
||||
|
||||
// Force logout of all tabs if one tab is logged out
|
||||
$(window).bind('storage', (e) => {
|
||||
// when one tab on a browser logs out, it sets __logout__ in localStorage to trigger other tabs to log out
|
||||
if (e.originalEvent.key === '__logout__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
|
||||
// make sure it isn't this tab that is sending the logout signal (only necessary for IE11)
|
||||
if (window.BrowserStore.isSignallingLogout(e.originalEvent.newValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('detected logout from a different tab'); //eslint-disable-line no-console
|
||||
browserHistory.push('/' + this.props.params.team);
|
||||
}
|
||||
|
||||
if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
|
||||
// make sure it isn't this tab that is sending the logout signal (only necessary for IE11)
|
||||
if (window.BrowserStore.isSignallingLogin(e.originalEvent.newValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('detected login from a different tab'); //eslint-disable-line no-console
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
// Because current CSS requires the root tag to have specific stuff
|
||||
$('#root').attr('class', 'channel-view');
|
||||
|
||||
// ???
|
||||
$('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--before');
|
||||
} else {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--after');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--before');
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('mouseenter mouseleave', '.search-item__container .post', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).closest('.search-item__container').find('.date-separator').addClass('hovered--after');
|
||||
$(this).closest('.search-item__container').next('div').find('.date-separator').addClass('hovered--before');
|
||||
} else {
|
||||
$(this).closest('.search-item__container').find('.date-separator').removeClass('hovered--after');
|
||||
$(this).closest('.search-item__container').next('div').find('.date-separator').removeClass('hovered--before');
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('mouseenter mouseleave', '.post.post--comment.same--root', function mouseOver(ev) {
|
||||
if (ev.type === 'mouseenter') {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--comment');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').addClass('hovered--comment');
|
||||
} else {
|
||||
$(this).parent('div').prev('.date-separator, .new-separator').removeClass('hovered--comment');
|
||||
$(this).parent('div').next('.date-separator, .new-separator').removeClass('hovered--comment');
|
||||
}
|
||||
});
|
||||
|
||||
// Device tracking setup
|
||||
var iOS = (/(iPad|iPhone|iPod)/g).test(navigator.userAgent);
|
||||
if (iOS) {
|
||||
$('body').addClass('ios');
|
||||
}
|
||||
|
||||
// Set up tracking for whether the window is active
|
||||
window.isActive = true;
|
||||
$(window).on('focus', () => {
|
||||
AsyncClient.updateLastViewedAt();
|
||||
ChannelStore.resetCounts(ChannelStore.getCurrentId());
|
||||
ChannelStore.emitChange();
|
||||
window.isActive = true;
|
||||
});
|
||||
$(window).on('blur', () => {
|
||||
window.isActive = false;
|
||||
});
|
||||
|
||||
// if preferences have already been stored in local storage do not wait until preference store change is fired and handled in channel.jsx
|
||||
const selectedFont = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT);
|
||||
Utils.applyFont(selectedFont);
|
||||
|
||||
// Pervent backspace from navigating back a page
|
||||
$(window).on('keydown.preventBackspace', (e) => {
|
||||
if (e.which === BACKSPACE_CHAR && !$(e.target).is('input, textarea')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
$('#root').attr('class', '');
|
||||
clearInterval(this.intervalId);
|
||||
|
||||
$(window).off('focus');
|
||||
$(window).off('blur');
|
||||
|
||||
SocketStore.removeChangeListener(this.onSocketChange);
|
||||
UserStore.removeChangeListener(this.onUserChanged);
|
||||
|
||||
$('body').off('click.userpopover');
|
||||
$('body').off('mouseenter mouseleave', '.post');
|
||||
$('body').off('mouseenter mouseleave', '.post.post--comment.same--root');
|
||||
|
||||
$('.modal').off('show.bs.modal');
|
||||
|
||||
$(window).off('keydown.preventBackspace');
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className='channel-view'>
|
||||
<ErrorBar/>
|
||||
<div className='container-fluid'>
|
||||
<SidebarRight/>
|
||||
<SidebarRightMenu/>
|
||||
{this.props.sidebar}
|
||||
{this.props.center}
|
||||
|
||||
<GetPostLinkModal/>
|
||||
<GetTeamInviteLinkModal/>
|
||||
<InviteMemberModal/>
|
||||
<ImportThemeModal/>
|
||||
<TeamSettingsModal/>
|
||||
<MoreChannelsModal/>
|
||||
<EditPostModal/>
|
||||
<DeletePostModal/>
|
||||
<RemovedFromChannelModal/>
|
||||
<RegisterAppModal/>
|
||||
<SelectTeamModal/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LoggedIn.defaultProps = {
|
||||
};
|
||||
|
||||
LoggedIn.propTypes = {
|
||||
children: React.PropTypes.object,
|
||||
sidebar: React.PropTypes.object,
|
||||
center: React.PropTypes.object,
|
||||
params: React.PropTypes.object
|
||||
};
|
||||
@@ -6,82 +6,118 @@ import LoginUsername from './login_username.jsx';
|
||||
import LoginLdap from './login_ldap.jsx';
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
export default class Login extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
this.getStateFromStores = this.getStateFromStores.bind(this);
|
||||
this.onTeamChange = this.onTeamChange.bind(this);
|
||||
|
||||
this.state = this.getStateFromStores();
|
||||
}
|
||||
componentDidMount() {
|
||||
TeamStore.addChangeListener(this.onTeamChange);
|
||||
Client.getMeLoggedIn((data) => {
|
||||
if (data && data.logged_in !== 'false') {
|
||||
browserHistory.push('/' + this.props.params.team + '/channels/town-square');
|
||||
}
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
TeamStore.removeChangeListener(this.onTeamChange);
|
||||
}
|
||||
getStateFromStores() {
|
||||
return {
|
||||
currentTeam: TeamStore.getByName(this.props.params.team)
|
||||
};
|
||||
}
|
||||
onTeamChange() {
|
||||
this.setState(this.getStateFromStores());
|
||||
}
|
||||
render() {
|
||||
const teamDisplayName = this.props.teamDisplayName;
|
||||
const teamName = this.props.teamName;
|
||||
const currentTeam = this.state.currentTeam;
|
||||
if (currentTeam == null) {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
const teamDisplayName = currentTeam.display_name;
|
||||
const teamName = currentTeam.name;
|
||||
|
||||
let loginMessage = [];
|
||||
if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/' + teamName + '/login/gitlab'}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/api/v1/oauth/gitlab/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
|
||||
loginMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
href={'/' + teamName + '/login/google'}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.google'
|
||||
defaultMessage='with Google Apps'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
<a
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
href={'/api/v1/oauth/google/login?team=' + encodeURIComponent(teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='login.google'
|
||||
defaultMessage='with Google Apps'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const extraParam = Utils.getUrlParameter('extra');
|
||||
let extraBox = '';
|
||||
if (extraParam) {
|
||||
let msg;
|
||||
if (extraParam === Constants.SIGNIN_CHANGE) {
|
||||
msg = (
|
||||
<FormattedMessage
|
||||
id='login.changed'
|
||||
defaultMessage=' Sign-in method changed successfully'
|
||||
/>
|
||||
);
|
||||
} else if (extraParam === Constants.SIGNIN_VERIFIED) {
|
||||
msg = (
|
||||
<FormattedMessage
|
||||
id='login.verified'
|
||||
defaultMessage=' Email Verified'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
extraBox = (
|
||||
<div className='alert alert-success'>
|
||||
<i className='fa fa-check'/>
|
||||
{msg}
|
||||
<FormattedMessage
|
||||
id='login.changed'
|
||||
defaultMessage=' Sign-in method changed successfully'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (extraParam === Constants.SIGNIN_VERIFIED) {
|
||||
extraBox = (
|
||||
<div className='alert alert-success'>
|
||||
<i className='fa fa-check'/>
|
||||
<FormattedMessage
|
||||
id='login.verified'
|
||||
defaultMessage=' Email Verified'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else if (extraParam === Constants.SESSION_EXPIRED) {
|
||||
extraBox = (
|
||||
<div className='alert alert-warning'>
|
||||
<i className='fa fa-exclamation-triangle'/>
|
||||
<FormattedMessage
|
||||
id='login.session_expired'
|
||||
defaultMessage=' Your session has expired. Please login again.'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -91,7 +127,7 @@ export default class Login extends React.Component {
|
||||
if (global.window.mm_config.EnableSignInWithEmail === 'true') {
|
||||
emailSignup = (
|
||||
<LoginEmail
|
||||
teamName={this.props.teamName}
|
||||
teamName={teamName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -125,7 +161,7 @@ export default class Login extends React.Component {
|
||||
}
|
||||
|
||||
let userSignUp = null;
|
||||
if (this.props.inviteId) {
|
||||
if (currentTeam.allow_open_invite) {
|
||||
userSignUp = (
|
||||
<div>
|
||||
<span>
|
||||
@@ -134,7 +170,7 @@ export default class Login extends React.Component {
|
||||
defaultMessage="Don't have an account? "
|
||||
/>
|
||||
<a
|
||||
href={'/signup_user_complete/?id=' + this.props.inviteId}
|
||||
href={'/signup_user_complete/?id=' + currentTeam.invite_id}
|
||||
className='signup-team-login'
|
||||
>
|
||||
<FormattedMessage
|
||||
@@ -168,73 +204,65 @@ export default class Login extends React.Component {
|
||||
if (global.window.mm_config.EnableLdap === 'true') {
|
||||
ldapLogin = (
|
||||
<LoginLdap
|
||||
teamName={this.props.teamName}
|
||||
teamName={teamName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let findTeams = null;
|
||||
if (!Utils.isMobileApp()) {
|
||||
findTeams = (
|
||||
<div className='form-group margin--extra form-group--small'>
|
||||
<span>
|
||||
<a href='/find_team'>
|
||||
<FormattedMessage
|
||||
id='login.find'
|
||||
defaultMessage='Find your other teams'
|
||||
/>
|
||||
</a></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let usernameLogin = null;
|
||||
if (global.window.mm_config.EnableSignInWithUsername === 'true') {
|
||||
usernameLogin = (
|
||||
<LoginUsername
|
||||
teamName={this.props.teamName}
|
||||
teamName={teamName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='signup-team__container'>
|
||||
<h5 className='margin--less'>
|
||||
<FormattedMessage
|
||||
id='login.signTo'
|
||||
defaultMessage='Sign in to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{teamDisplayName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='login.on'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
{extraBox}
|
||||
{loginMessage}
|
||||
{emailSignup}
|
||||
{usernameLogin}
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
{findTeams}
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h5 className='margin--less'>
|
||||
<FormattedMessage
|
||||
id='login.signTo'
|
||||
defaultMessage='Sign in to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{teamDisplayName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='login.on'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
{extraBox}
|
||||
{loginMessage}
|
||||
{emailSignup}
|
||||
{usernameLogin}
|
||||
{ldapLogin}
|
||||
{userSignUp}
|
||||
{forgotPassword}
|
||||
{teamSignUp}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Login.defaultProps = {
|
||||
teamName: '',
|
||||
teamDisplayName: ''
|
||||
};
|
||||
Login.propTypes = {
|
||||
teamName: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string,
|
||||
inviteId: React.PropTypes.string
|
||||
params: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -72,13 +73,7 @@ class LoginEmail extends React.Component {
|
||||
Client.loginByEmail(name, email, password,
|
||||
() => {
|
||||
UserStore.setLastEmail(email);
|
||||
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
window.location.href = decodeURIComponent(redirect);
|
||||
} else {
|
||||
window.location.href = '/' + name + '/channels/town-square';
|
||||
}
|
||||
browserHistory.push('/' + name + '/channels/town-square');
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
@@ -167,4 +162,4 @@ LoginEmail.propTypes = {
|
||||
teamName: React.PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LoginEmail);
|
||||
export default injectIntl(LoginEmail);
|
||||
|
||||
@@ -56,9 +56,13 @@ export default class Navbar extends React.Component {
|
||||
return {
|
||||
channel: ChannelStore.getCurrent(),
|
||||
member: ChannelStore.getCurrentMember(),
|
||||
users: ChannelStore.getCurrentExtraInfo().members
|
||||
users: ChannelStore.getCurrentExtraInfo().members,
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
}
|
||||
stateValid() {
|
||||
return this.state.channel && this.state.member && this.state.users && this.state.currentUser;
|
||||
}
|
||||
componentDidMount() {
|
||||
ChannelStore.addChangeListener(this.onChange);
|
||||
ChannelStore.addExtraInfoChangeListener(this.onChange);
|
||||
@@ -201,7 +205,7 @@ export default class Navbar extends React.Component {
|
||||
<ToggleModalButton
|
||||
role='menuitem'
|
||||
dialogType={ChannelInviteModal}
|
||||
dialogProps={{channel}}
|
||||
dialogProps={{channel, currentUser: this.state.currentUser}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar.addMembers'
|
||||
@@ -286,7 +290,11 @@ export default class Navbar extends React.Component {
|
||||
<ToggleModalButton
|
||||
role='menuitem'
|
||||
dialogType={ChannelNotificationsModal}
|
||||
dialogProps={{channel}}
|
||||
dialogProps={{
|
||||
channel,
|
||||
channelMember: this.state.member,
|
||||
currentUser: this.state.currentUser
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar.preferences'
|
||||
@@ -412,7 +420,11 @@ export default class Navbar extends React.Component {
|
||||
return buttons;
|
||||
}
|
||||
render() {
|
||||
var currentId = UserStore.getCurrentId();
|
||||
if (!this.stateValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentId = this.state.currentUser.id;
|
||||
var channel = this.state.channel;
|
||||
var channelTitle = this.props.teamDisplayName;
|
||||
var popoverContent;
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import AboutBuildModal from './about_build_modal.jsx';
|
||||
import TeamMembersModal from './team_members_modal.jsx';
|
||||
@@ -15,38 +12,20 @@ import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
function getStateFromStores() {
|
||||
const teams = [];
|
||||
const teamsObject = UserStore.getTeams();
|
||||
for (const teamId in teamsObject) {
|
||||
if (teamsObject.hasOwnProperty(teamId)) {
|
||||
teams.push(teamsObject[teamId]);
|
||||
}
|
||||
}
|
||||
|
||||
teams.sort(Utils.sortByDisplayName);
|
||||
return {teams};
|
||||
}
|
||||
import {Link} from 'react-router';
|
||||
|
||||
export default class NavbarDropdown extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.blockToggle = false;
|
||||
|
||||
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||
this.handleAboutModal = this.handleAboutModal.bind(this);
|
||||
this.onListenerChange = this.onListenerChange.bind(this);
|
||||
this.aboutModalDismissed = this.aboutModalDismissed.bind(this);
|
||||
|
||||
const state = getStateFromStores();
|
||||
state.showUserSettingsModal = false;
|
||||
state.showAboutModal = false;
|
||||
this.state = state;
|
||||
}
|
||||
handleLogoutClick(e) {
|
||||
e.preventDefault();
|
||||
client.logout();
|
||||
this.state = {
|
||||
showUserSettingsModal: false,
|
||||
showAboutModal: false
|
||||
};
|
||||
}
|
||||
handleAboutModal() {
|
||||
this.setState({showAboutModal: true});
|
||||
@@ -55,9 +34,6 @@ export default class NavbarDropdown extends React.Component {
|
||||
this.setState({showAboutModal: false});
|
||||
}
|
||||
componentDidMount() {
|
||||
UserStore.addTeamsChangeListener(this.onListenerChange);
|
||||
TeamStore.addChangeListener(this.onListenerChange);
|
||||
|
||||
$(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
|
||||
$('.sidebar--left .dropdown-menu').scrollTop(0);
|
||||
this.blockToggle = true;
|
||||
@@ -67,24 +43,15 @@ export default class NavbarDropdown extends React.Component {
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
UserStore.removeTeamsChangeListener(this.onListenerChange);
|
||||
TeamStore.removeChangeListener(this.onListenerChange);
|
||||
|
||||
$(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
|
||||
}
|
||||
onListenerChange() {
|
||||
var newState = getStateFromStores();
|
||||
if (!Utils.areObjectsEqual(newState, this.state)) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
var teamLink = '';
|
||||
var inviteLink = '';
|
||||
var manageLink = '';
|
||||
var sysAdminLink = '';
|
||||
var adminDivider = '';
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
var currentUser = this.props.currentUser;
|
||||
var isAdmin = false;
|
||||
var isSystemAdmin = false;
|
||||
var teamSettings = null;
|
||||
@@ -97,7 +64,7 @@ export default class NavbarDropdown extends React.Component {
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={EventHelpers.showInviteMemberModal}
|
||||
onClick={GlobalActions.showInviteMemberModal}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.inviteMember'
|
||||
@@ -112,7 +79,7 @@ export default class NavbarDropdown extends React.Component {
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={EventHelpers.showGetTeamInviteLinkModal}
|
||||
onClick={GlobalActions.showGetTeamInviteLinkModal}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.teamLink'
|
||||
@@ -158,7 +125,7 @@ export default class NavbarDropdown extends React.Component {
|
||||
sysAdminLink = (
|
||||
<li>
|
||||
<a
|
||||
href={'/admin_console?' + Utils.getSessionIndex()}
|
||||
href={'/admin_console'}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.console'
|
||||
@@ -171,31 +138,6 @@ export default class NavbarDropdown extends React.Component {
|
||||
|
||||
var teams = [];
|
||||
|
||||
if (this.state.teams.length > 1) {
|
||||
teams.push(
|
||||
<li
|
||||
className='divider'
|
||||
key='div'
|
||||
>
|
||||
</li>
|
||||
);
|
||||
|
||||
this.state.teams.forEach((team) => {
|
||||
if (team.name !== this.props.teamName) {
|
||||
teams.push(
|
||||
<li key={team.name}><a href={Utils.getWindowLocationOrigin() + '/' + team.name}>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.switchTeam'
|
||||
defaultMessage='Switch to {team}'
|
||||
values={{
|
||||
team: team.display_name
|
||||
}}
|
||||
/>
|
||||
</a></li>);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (global.window.mm_config.EnableTeamCreation === 'true') {
|
||||
teams.push(
|
||||
<li key='newTeam_li'>
|
||||
@@ -283,15 +225,12 @@ export default class NavbarDropdown extends React.Component {
|
||||
{inviteLink}
|
||||
{teamLink}
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={this.handleLogoutClick}
|
||||
>
|
||||
<Link to={'/' + this.props.teamName + '/logout'}>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{adminDivider}
|
||||
{teamSettings}
|
||||
@@ -333,5 +272,6 @@ NavbarDropdown.defaultProps = {
|
||||
NavbarDropdown.propTypes = {
|
||||
teamType: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string,
|
||||
teamName: React.PropTypes.string
|
||||
teamName: React.PropTypes.string,
|
||||
currentUser: React.PropTypes.object
|
||||
};
|
||||
|
||||
20
web/react/components/needs_team.jsx
Обычный файл
20
web/react/components/needs_team.jsx
Обычный файл
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
export default class NeedsTeam extends React.Component {
|
||||
componentWillMount() {
|
||||
GlobalActions.loadTeamRequiredPage();
|
||||
}
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
NeedsTeam.defaultProps = {
|
||||
};
|
||||
|
||||
NeedsTeam.propTypes = {
|
||||
children: React.PropTypes.object
|
||||
};
|
||||
70
web/react/components/not_logged_in.jsx
Обычный файл
70
web/react/components/not_logged_in.jsx
Обычный файл
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class NotLoggedIn extends React.Component {
|
||||
componentDidMount() {
|
||||
$('body').attr('class', 'white');
|
||||
$('#root').attr('class', 'container-fluid');
|
||||
}
|
||||
componentWillUnmount() {
|
||||
$('body').attr('class', '');
|
||||
$('#root').attr('class', '');
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className='inner__wrap'>
|
||||
<div className='row content'>
|
||||
{this.props.children}
|
||||
<div className='footer-push'></div>
|
||||
</div>
|
||||
<div className='row footer'>
|
||||
<div className='footer-pane col-xs-12'>
|
||||
<div className='col-xs-12'>
|
||||
<span className='pull-right footer-site-name'>{global.window.mm_config.SiteName}</span>
|
||||
</div>
|
||||
<div className='col-xs-12'>
|
||||
<span className='pull-right footer-link copyright'>{'© 2015 Mattermost, Inc.'}</span>
|
||||
<a
|
||||
id='help_link'
|
||||
className='pull-right footer-link'
|
||||
href={global.window.mm_config.HelpLink}
|
||||
>
|
||||
<FormattedMessage id='web.footer.help'/>
|
||||
</a>
|
||||
<a
|
||||
id='terms_link'
|
||||
className='pull-right footer-link'
|
||||
href={global.window.mm_config.TermsOfServiceLink}
|
||||
>
|
||||
<FormattedMessage id='web.footer.terms'/>
|
||||
</a>
|
||||
<a
|
||||
id='privacy_link'
|
||||
className='pull-right footer-link'
|
||||
href={global.window.mm_config.PrivacyPolicyLink}
|
||||
>
|
||||
<FormattedMessage id='web.footer.privacy'/>
|
||||
</a>
|
||||
<a
|
||||
id='about_link'
|
||||
className='pull-right footer-link'
|
||||
href={global.window.mm_config.AboutLink}
|
||||
>
|
||||
<FormattedMessage id='web.footer.about'/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NotLoggedIn.defaultProps = {
|
||||
};
|
||||
|
||||
NotLoggedIn.propTypes = {
|
||||
children: React.PropTypes.object
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import PasswordResetSendLink from './password_reset_send_link.jsx';
|
||||
import PasswordResetForm from './password_reset_form.jsx';
|
||||
|
||||
export default class PasswordReset extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
render() {
|
||||
if (this.props.isReset === 'false') {
|
||||
return (
|
||||
<PasswordResetSendLink
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
teamName={this.props.teamName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PasswordResetForm
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
teamName={this.props.teamName}
|
||||
hash={this.props.hash}
|
||||
data={this.props.data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PasswordReset.defaultProps = {
|
||||
isReset: '',
|
||||
teamName: '',
|
||||
teamDisplayName: '',
|
||||
hash: '',
|
||||
data: ''
|
||||
};
|
||||
PasswordReset.propTypes = {
|
||||
isReset: React.PropTypes.string,
|
||||
teamName: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string,
|
||||
hash: React.PropTypes.string,
|
||||
data: React.PropTypes.string
|
||||
};
|
||||
@@ -2,24 +2,11 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
error: {
|
||||
id: 'password_form.error',
|
||||
defaultMessage: 'Please enter at least {chars} characters.'
|
||||
},
|
||||
update: {
|
||||
id: 'password_form.update',
|
||||
defaultMessage: 'Your password has been updated successfully.'
|
||||
},
|
||||
pwd: {
|
||||
id: 'password_form.pwd',
|
||||
defaultMessage: 'Password'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
class PasswordResetForm extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -32,51 +19,50 @@ class PasswordResetForm extends React.Component {
|
||||
handlePasswordReset(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
var state = {};
|
||||
|
||||
var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
const password = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
state.error = formatMessage(holders.error, {chars: Constants.MIN_PASSWORD_LENGTH});
|
||||
this.setState(state);
|
||||
this.setState({
|
||||
error: (
|
||||
<FormattedMessage
|
||||
id='password_form.error'
|
||||
defaultMessage='Please enter at least {chars} characters.'
|
||||
chars={Constants.MIN_PASSWORD_LENGTH}
|
||||
/>
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
state.error = null;
|
||||
this.setState(state);
|
||||
this.setState({
|
||||
error: null
|
||||
});
|
||||
|
||||
var data = {};
|
||||
const data = {};
|
||||
data.new_password = password;
|
||||
data.hash = this.props.hash;
|
||||
data.data = this.props.data;
|
||||
data.name = this.props.teamName;
|
||||
data.hash = this.props.location.query.h;
|
||||
data.data = this.props.location.query.d;
|
||||
data.name = this.props.params.team;
|
||||
|
||||
Client.resetPassword(data,
|
||||
function resetSuccess() {
|
||||
this.setState({error: null, updateText: formatMessage(holders.update)});
|
||||
}.bind(this),
|
||||
function resetFailure(err) {
|
||||
this.setState({error: err.message, updateText: null});
|
||||
}.bind(this)
|
||||
() => {
|
||||
this.setState({error: null});
|
||||
browserHistory.push('/' + this.props.params.team + '/login');
|
||||
},
|
||||
(err) => {
|
||||
this.setState({error: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
render() {
|
||||
var updateText = null;
|
||||
if (this.state.updateText) {
|
||||
updateText = (<div className='form-group'><br/><label className='control-label reset-form'>{this.state.updateText}
|
||||
<FormattedHTMLMessage
|
||||
id='password_form.click'
|
||||
defaultMessage='Click <a href={url}>here</a> to log in.'
|
||||
values={{
|
||||
url: '/' + this.props.teamName + '/login'
|
||||
}}
|
||||
/>
|
||||
</label></div>);
|
||||
}
|
||||
|
||||
var error = null;
|
||||
if (this.state.error) {
|
||||
error = <div className='form-group has-error'><label className='control-label'>{this.state.error}</label></div>;
|
||||
error = (
|
||||
<div className='form-group has-error'>
|
||||
<label className='control-label'>
|
||||
{this.state.error}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
var formClass = 'form-group';
|
||||
@@ -84,7 +70,6 @@ class PasswordResetForm extends React.Component {
|
||||
formClass += ' has-error';
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
@@ -98,9 +83,8 @@ class PasswordResetForm extends React.Component {
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='password_form.enter'
|
||||
defaultMessage='Enter a new password for your {teamDisplayName} {siteName} account.'
|
||||
defaultMessage='Enter a new password for your {siteName} account.'
|
||||
values={{
|
||||
teamDisplayName: this.props.teamDisplayName,
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
@@ -111,7 +95,10 @@ class PasswordResetForm extends React.Component {
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder={formatMessage(holders.pwd)}
|
||||
placeholder={Utils.localizeMessage(
|
||||
'password_form.pwd',
|
||||
'Password'
|
||||
)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
@@ -125,7 +112,6 @@ class PasswordResetForm extends React.Component {
|
||||
defaultMessage='Change my password'
|
||||
/>
|
||||
</button>
|
||||
{updateText}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -134,17 +120,10 @@ class PasswordResetForm extends React.Component {
|
||||
}
|
||||
|
||||
PasswordResetForm.defaultProps = {
|
||||
teamName: '',
|
||||
teamDisplayName: '',
|
||||
hash: '',
|
||||
data: ''
|
||||
};
|
||||
PasswordResetForm.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string,
|
||||
hash: React.PropTypes.string,
|
||||
data: React.PropTypes.string
|
||||
params: React.PropTypes.object.isRequired,
|
||||
location: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(PasswordResetForm);
|
||||
export default PasswordResetForm;
|
||||
|
||||
@@ -4,26 +4,7 @@
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
error: {
|
||||
id: 'password_send.error',
|
||||
defaultMessage: 'Please enter a valid email address.'
|
||||
},
|
||||
link: {
|
||||
id: 'password_send.link',
|
||||
defaultMessage: '<p>A password reset link has been sent to <b>{email}</b> for your <b>{teamDisplayName}</b> team on {hostname}.</p>'
|
||||
},
|
||||
checkInbox: {
|
||||
id: 'password_send.checkInbox',
|
||||
defaultMessage: 'Please check your inbox.'
|
||||
},
|
||||
email: {
|
||||
id: 'password_send.email',
|
||||
defaultMessage: 'Email'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
class PasswordResetSendLink extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -31,48 +12,64 @@ class PasswordResetSendLink extends React.Component {
|
||||
|
||||
this.handleSendLink = this.handleSendLink.bind(this);
|
||||
|
||||
this.state = {};
|
||||
this.state = {
|
||||
error: '',
|
||||
updateText: ''
|
||||
};
|
||||
}
|
||||
handleSendLink(e) {
|
||||
e.preventDefault();
|
||||
var state = {};
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
|
||||
if (!email || !Utils.isEmail(email)) {
|
||||
state.error = formatMessage(holders.error);
|
||||
this.setState(state);
|
||||
this.setState({
|
||||
error: (
|
||||
<FormattedMessage
|
||||
id={'password_send.error'}
|
||||
defaultMessage={'Please enter a valid email address.'}
|
||||
/>
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
state.error = null;
|
||||
this.setState(state);
|
||||
// End of error checking clear error
|
||||
this.setState({
|
||||
error: ''
|
||||
});
|
||||
|
||||
var data = {};
|
||||
data.email = email;
|
||||
data.name = this.props.teamName;
|
||||
|
||||
data.name = this.props.params.team;
|
||||
client.sendPasswordReset(data,
|
||||
function passwordResetSent() {
|
||||
this.setState({error: null, updateText: formatMessage(holders.link, {email: email, teamDisplayName: this.props.teamDisplayName, hostname: window.location.hostname}), moreUpdateText: formatMessage(holders.checkInbox)});
|
||||
$(ReactDOM.findDOMNode(this.refs.reset_form)).hide();
|
||||
}.bind(this),
|
||||
function passwordResetFailedToSend(err) {
|
||||
this.setState({error: err.message, update_text: null, moreUpdateText: null});
|
||||
}.bind(this)
|
||||
);
|
||||
() => {
|
||||
this.setState({
|
||||
error: null,
|
||||
updateText: (
|
||||
<div className='reset-form alert alert-success'>
|
||||
<FormattedHTMLMessage
|
||||
id='password_send.link'
|
||||
defaultMessage='<p>A password reset link has been sent to <b>{email}</b></p>'
|
||||
email={email}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id={'password_send.checkInbox'}
|
||||
defaultMessage={'Please check your inbox.'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
$(ReactDOM.findDOMNode(this.refs.reset_form)).hide();
|
||||
},
|
||||
(err) => {
|
||||
this.setState({
|
||||
error: err.message,
|
||||
update_text: null
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
render() {
|
||||
var updateText = null;
|
||||
if (this.state.updateText) {
|
||||
updateText = (
|
||||
<div className='reset-form alert alert-success'
|
||||
dangerouslySetInnerHTML={{__html: this.state.updateText + this.state.moreUpdateText}}
|
||||
>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
var error = null;
|
||||
if (this.state.error) {
|
||||
error = <div className='form-group has-error'><label className='control-label'>{this.state.error}</label></div>;
|
||||
@@ -83,51 +80,60 @@ class PasswordResetSendLink extends React.Component {
|
||||
formClass += ' has-error';
|
||||
}
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='password_send.title'
|
||||
defaultMessage='Password Reset'
|
||||
id='web.header.back'
|
||||
/>
|
||||
</h3>
|
||||
{updateText}
|
||||
<form
|
||||
onSubmit={this.handleSendLink}
|
||||
ref='reset_form'
|
||||
>
|
||||
<p>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='password_send.description'
|
||||
defaultMessage='To reset your password, enter the email address you used to sign up for {teamName}.'
|
||||
values={{
|
||||
teamName: this.props.teamDisplayName
|
||||
}}
|
||||
id='password_send.title'
|
||||
defaultMessage='Password Reset'
|
||||
/>
|
||||
</p>
|
||||
<div className={formClass}>
|
||||
<input
|
||||
type='email'
|
||||
className='form-control'
|
||||
name='email'
|
||||
ref='email'
|
||||
placeholder={formatMessage(holders.email)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
{error}
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
</h3>
|
||||
{this.state.updateText}
|
||||
<form
|
||||
onSubmit={this.handleSendLink}
|
||||
ref='reset_form'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='password_send.reset'
|
||||
defaultMessage='Reset my password'
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='password_send.description'
|
||||
defaultMessage='To reset your password, enter the email address you used to sign up'
|
||||
/>
|
||||
</p>
|
||||
<div className={formClass}>
|
||||
<input
|
||||
type='email'
|
||||
className='form-control'
|
||||
name='email'
|
||||
ref='email'
|
||||
placeholder={Utils.localizeMessage(
|
||||
'password_send.email',
|
||||
'Email'
|
||||
)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
{error}
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='password_send.reset'
|
||||
defaultMessage='Reset my password'
|
||||
/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -135,13 +141,9 @@ class PasswordResetSendLink extends React.Component {
|
||||
}
|
||||
|
||||
PasswordResetSendLink.defaultProps = {
|
||||
teamName: '',
|
||||
teamDisplayName: ''
|
||||
};
|
||||
PasswordResetSendLink.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string
|
||||
params: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(PasswordResetSendLink);
|
||||
export default PasswordResetSendLink;
|
||||
|
||||
@@ -118,7 +118,7 @@ export default class PopoverListMembers extends React.Component {
|
||||
className='profile-img rounded pull-left'
|
||||
width='26px'
|
||||
height='26px'
|
||||
src={`/api/v1/users/${m.id}/image?time=${m.update_at}&${Utils.getSessionIndex()}`}
|
||||
src={`/api/v1/users/${m.id}/image?time=${m.update_at}`}
|
||||
/>
|
||||
<div className='pull-left'>
|
||||
<div
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import PostHeader from './post_header.jsx';
|
||||
import PostBody from './post_body.jsx';
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import PostStore from '../stores/post_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
|
||||
@@ -128,7 +127,6 @@ export default class Post extends React.Component {
|
||||
const post = this.props.post;
|
||||
const parentPost = this.props.parentPost;
|
||||
const posts = this.props.posts;
|
||||
const user = this.props.user || {};
|
||||
|
||||
if (!post.props) {
|
||||
post.props = {};
|
||||
@@ -156,13 +154,15 @@ export default class Post extends React.Component {
|
||||
}
|
||||
|
||||
let currentUserCss = '';
|
||||
if (UserStore.getCurrentId() === post.user_id && !post.props.from_webhook && !Utils.isSystemMessage(post)) {
|
||||
if (this.props.currentUser.id === post.user_id && !post.props.from_webhook && !Utils.isSystemMessage(post)) {
|
||||
currentUserCss = 'current--user';
|
||||
}
|
||||
|
||||
let timestamp = user.update_at;
|
||||
if (timestamp == null) {
|
||||
timestamp = UserStore.getCurrentUser().update_at;
|
||||
let timestamp = 0;
|
||||
if (!this.props.user || this.props.user.update_at == null) {
|
||||
timestamp = this.props.currentUser.update_at;
|
||||
} else {
|
||||
timestamp = this.props.user.update_at;
|
||||
}
|
||||
|
||||
let sameUserClass = '';
|
||||
@@ -182,7 +182,7 @@ export default class Post extends React.Component {
|
||||
|
||||
let profilePic = null;
|
||||
if (!this.props.hideProfilePic) {
|
||||
let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + Utils.getSessionIndex();
|
||||
let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp;
|
||||
if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') {
|
||||
if (post.props.override_icon_url) {
|
||||
src = post.props.override_icon_url;
|
||||
@@ -218,6 +218,7 @@ export default class Post extends React.Component {
|
||||
isLastComment={this.props.isLastComment}
|
||||
sameUser={this.props.sameUser}
|
||||
user={this.props.user}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
<PostBody
|
||||
post={post}
|
||||
@@ -245,5 +246,7 @@ Post.propTypes = {
|
||||
hideProfilePic: React.PropTypes.bool,
|
||||
isLastComment: React.PropTypes.bool,
|
||||
shouldHighlight: React.PropTypes.bool,
|
||||
displayNameType: React.PropTypes.string
|
||||
displayNameType: React.PropTypes.string,
|
||||
hasProfiles: React.PropTypes.bool,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -80,12 +80,10 @@ class PostBody extends React.Component {
|
||||
username = parentPost.props.override_username;
|
||||
}
|
||||
|
||||
if (global.window.mm_locale === 'en') {
|
||||
if (username.slice(-1) === 's') {
|
||||
apostrophe = '\'';
|
||||
} else {
|
||||
apostrophe = '\'s';
|
||||
}
|
||||
if (username.slice(-1) === 's') {
|
||||
apostrophe = '\'';
|
||||
} else {
|
||||
apostrophe = '\'s';
|
||||
}
|
||||
name = (
|
||||
<a
|
||||
|
||||
@@ -5,7 +5,8 @@ import PostsView from './posts_view.jsx';
|
||||
|
||||
import PostStore from '../stores/post_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -15,6 +16,7 @@ export default class PostFocusView extends React.Component {
|
||||
|
||||
this.onChannelChange = this.onChannelChange.bind(this);
|
||||
this.onPostsChange = this.onPostsChange.bind(this);
|
||||
this.onUserChange = this.onUserChange.bind(this);
|
||||
this.handlePostsViewScroll = this.handlePostsViewScroll.bind(this);
|
||||
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
||||
this.loadMorePostsBottom = this.loadMorePostsBottom.bind(this);
|
||||
@@ -26,18 +28,21 @@ export default class PostFocusView extends React.Component {
|
||||
scrollPostId: focusedPostId,
|
||||
postList: PostStore.getVisiblePosts(focusedPostId),
|
||||
atTop: PostStore.getVisibilityAtTop(focusedPostId),
|
||||
atBottom: PostStore.getVisibilityAtBottom(focusedPostId)
|
||||
atBottom: PostStore.getVisibilityAtBottom(focusedPostId),
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
ChannelStore.addChangeListener(this.onChannelChange);
|
||||
PostStore.addChangeListener(this.onPostsChange);
|
||||
UserStore.addChangeListener(this.onUserChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeChangeListener(this.onChannelChange);
|
||||
PostStore.removeChangeListener(this.onPostsChange);
|
||||
UserStore.removeChangeListener(this.onUserChange);
|
||||
}
|
||||
|
||||
onChannelChange() {
|
||||
@@ -46,6 +51,10 @@ export default class PostFocusView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
onUserChange() {
|
||||
this.setState({currentUser: UserStore.getCurrentUser()});
|
||||
}
|
||||
|
||||
onPostsChange() {
|
||||
const focusedPostId = PostStore.getFocusedPostId();
|
||||
if (focusedPostId == null) {
|
||||
@@ -65,11 +74,11 @@ export default class PostFocusView extends React.Component {
|
||||
}
|
||||
|
||||
loadMorePostsTop() {
|
||||
EventHelpers.emitLoadMorePostsFocusedTopEvent();
|
||||
GlobalActions.emitLoadMorePostsFocusedTopEvent();
|
||||
}
|
||||
|
||||
loadMorePostsBottom() {
|
||||
EventHelpers.emitLoadMorePostsFocusedBottomEvent();
|
||||
GlobalActions.emitLoadMorePostsFocusedBottomEvent();
|
||||
}
|
||||
|
||||
getIntroMessage() {
|
||||
@@ -89,6 +98,10 @@ export default class PostFocusView extends React.Component {
|
||||
const postsToHighlight = {};
|
||||
postsToHighlight[this.state.scrollPostId] = true;
|
||||
|
||||
if (!this.state.currentUser || !this.state.postList) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div id='post-list'>
|
||||
<PostsView
|
||||
@@ -106,6 +119,7 @@ export default class PostFocusView extends React.Component {
|
||||
messageSeparatorTime={0}
|
||||
postsToHighlight={postsToHighlight}
|
||||
profiles={this.props.profiles}
|
||||
currentUser={this.state.currentUser}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -14,16 +14,15 @@ export default class PostHeader extends React.Component {
|
||||
}
|
||||
render() {
|
||||
const post = this.props.post;
|
||||
const user = this.props.user;
|
||||
|
||||
let userProfile = <UserProfile user={user}/>;
|
||||
let userProfile = <UserProfile user={this.props.user}/>;
|
||||
let botIndicator;
|
||||
|
||||
if (post.props && post.props.from_webhook) {
|
||||
if (post.props.override_username && global.window.mm_config.EnablePostUsernameOverride === 'true') {
|
||||
userProfile = (
|
||||
<UserProfile
|
||||
user={user}
|
||||
user={this.props.user}
|
||||
overwriteName={post.props.override_username}
|
||||
disablePopover={true}
|
||||
/>
|
||||
@@ -54,6 +53,7 @@ export default class PostHeader extends React.Component {
|
||||
allowReply='true'
|
||||
isLastComment={this.props.isLastComment}
|
||||
sameUser={this.props.sameUser}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -68,10 +68,11 @@ PostHeader.defaultProps = {
|
||||
sameUser: false
|
||||
};
|
||||
PostHeader.propTypes = {
|
||||
post: React.PropTypes.object,
|
||||
post: React.PropTypes.object.isRequired,
|
||||
user: React.PropTypes.object,
|
||||
commentCount: React.PropTypes.number,
|
||||
isLastComment: React.PropTypes.bool,
|
||||
handleCommentClick: React.PropTypes.func,
|
||||
sameUser: React.PropTypes.bool
|
||||
currentUser: React.PropTypes.object.isRequired,
|
||||
commentCount: React.PropTypes.number.isRequired,
|
||||
isLastComment: React.PropTypes.bool.isRequired,
|
||||
handleCommentClick: React.PropTypes.func.isRequired,
|
||||
sameUser: React.PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import TimeSince from './time_since.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
@@ -27,8 +26,8 @@ export default class PostInfo extends React.Component {
|
||||
}
|
||||
createDropdown() {
|
||||
var post = this.props.post;
|
||||
var isOwner = UserStore.getCurrentId() === post.user_id;
|
||||
var isAdmin = Utils.isAdmin(UserStore.getCurrentUser().roles);
|
||||
var isOwner = this.props.currentUser.id === post.user_id;
|
||||
var isAdmin = Utils.isAdmin(this.props.currentUser.roles);
|
||||
|
||||
if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || Utils.isPostEphemeral(post)) {
|
||||
return '';
|
||||
@@ -47,21 +46,21 @@ export default class PostInfo extends React.Component {
|
||||
|
||||
if (this.props.allowReply === 'true') {
|
||||
dropdownContents.push(
|
||||
<li
|
||||
key='replyLink'
|
||||
role='presentation'
|
||||
>
|
||||
<a
|
||||
className='link__reply theme'
|
||||
href='#'
|
||||
onClick={this.props.handleCommentClick}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='post_info.reply'
|
||||
defaultMessage='Reply'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
key='replyLink'
|
||||
role='presentation'
|
||||
>
|
||||
<a
|
||||
className='link__reply theme'
|
||||
href='#'
|
||||
onClick={this.props.handleCommentClick}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='post_info.reply'
|
||||
defaultMessage='Reply'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,7 +92,7 @@ export default class PostInfo extends React.Component {
|
||||
<a
|
||||
href='#'
|
||||
role='menuitem'
|
||||
onClick={() => EventHelpers.showDeletePostModal(post, dataComments)}
|
||||
onClick={() => GlobalActions.showDeletePostModal(post, dataComments)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='post_info.del'
|
||||
@@ -157,11 +156,11 @@ export default class PostInfo extends React.Component {
|
||||
|
||||
handlePermalink(e) {
|
||||
e.preventDefault();
|
||||
EventHelpers.showGetPostLinkModal(this.props.post);
|
||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
||||
}
|
||||
|
||||
removePost() {
|
||||
EventHelpers.emitRemovePost(this.props.post);
|
||||
GlobalActions.emitRemovePost(this.props.post);
|
||||
}
|
||||
createRemovePostButton(post) {
|
||||
if (!Utils.isPostEphemeral(post)) {
|
||||
@@ -240,10 +239,11 @@ PostInfo.defaultProps = {
|
||||
sameUser: false
|
||||
};
|
||||
PostInfo.propTypes = {
|
||||
post: React.PropTypes.object,
|
||||
commentCount: React.PropTypes.number,
|
||||
isLastComment: React.PropTypes.bool,
|
||||
allowReply: React.PropTypes.string,
|
||||
handleCommentClick: React.PropTypes.func,
|
||||
sameUser: React.PropTypes.bool
|
||||
post: React.PropTypes.object.isRequired,
|
||||
commentCount: React.PropTypes.number.isRequired,
|
||||
isLastComment: React.PropTypes.bool.isRequired,
|
||||
allowReply: React.PropTypes.string.isRequired,
|
||||
handleCommentClick: React.PropTypes.func.isRequired,
|
||||
sameUser: React.PropTypes.bool.isRequired,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import PreferenceStore from '../stores/preference_store.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Post from './post.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
@@ -144,7 +143,7 @@ export default class PostsView extends React.Component {
|
||||
createPosts(posts, order) {
|
||||
const postCtls = [];
|
||||
let previousPostDay = new Date(0);
|
||||
const userId = UserStore.getCurrentId();
|
||||
const userId = this.props.currentUser.id;
|
||||
const profiles = this.props.profiles || {};
|
||||
|
||||
let renderedLastViewed = false;
|
||||
@@ -230,8 +229,8 @@ export default class PostsView extends React.Component {
|
||||
const shouldHighlight = this.props.postsToHighlight && this.props.postsToHighlight.hasOwnProperty(post.id);
|
||||
|
||||
let profile;
|
||||
if (UserStore.getCurrentId() === post.user_id) {
|
||||
profile = UserStore.getCurrentUser();
|
||||
if (this.props.currentUser.id === post.user_id) {
|
||||
profile = this.props.currentUser;
|
||||
} else {
|
||||
profile = profiles[post.user_id];
|
||||
}
|
||||
@@ -248,9 +247,10 @@ export default class PostsView extends React.Component {
|
||||
hideProfilePic={hideProfilePic}
|
||||
isLastComment={isLastComment}
|
||||
shouldHighlight={shouldHighlight}
|
||||
onClick={() => EventHelpers.emitPostFocusEvent(post.id)} //eslint-disable-line no-loop-func
|
||||
onClick={() => GlobalActions.emitPostFocusEvent(post.id)} //eslint-disable-line no-loop-func
|
||||
displayNameType={this.state.displayNameType}
|
||||
user={profile}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -525,7 +525,7 @@ PostsView.defaultProps = {
|
||||
PostsView.propTypes = {
|
||||
isActive: React.PropTypes.bool,
|
||||
postList: React.PropTypes.object,
|
||||
profiles: React.PropTypes.object,
|
||||
profiles: React.PropTypes.object.isRequired,
|
||||
scrollPostId: React.PropTypes.string,
|
||||
scrollType: React.PropTypes.number,
|
||||
postViewScrolled: React.PropTypes.func.isRequired,
|
||||
@@ -535,7 +535,8 @@ PostsView.propTypes = {
|
||||
showMoreMessagesBottom: React.PropTypes.bool,
|
||||
introText: React.PropTypes.element,
|
||||
messageSeparatorTime: React.PropTypes.number,
|
||||
postsToHighlight: React.PropTypes.object
|
||||
postsToHighlight: React.PropTypes.object,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
function FloatingTimestamp({isScrolling, post}) {
|
||||
|
||||
@@ -6,9 +6,10 @@ import LoadingScreen from './loading_screen.jsx';
|
||||
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import PostStore from '../stores/post_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
@@ -21,6 +22,7 @@ export default class PostsViewContainer extends React.Component {
|
||||
this.onChannelChange = this.onChannelChange.bind(this);
|
||||
this.onChannelLeave = this.onChannelLeave.bind(this);
|
||||
this.onPostsChange = this.onPostsChange.bind(this);
|
||||
this.onUserChange = this.onUserChange.bind(this);
|
||||
this.handlePostsViewScroll = this.handlePostsViewScroll.bind(this);
|
||||
this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
|
||||
this.handlePostsViewJumpRequest = this.handlePostsViewJumpRequest.bind(this);
|
||||
@@ -28,7 +30,8 @@ export default class PostsViewContainer extends React.Component {
|
||||
const currentChannelId = ChannelStore.getCurrentId();
|
||||
const state = {
|
||||
scrollType: PostsView.SCROLL_TYPE_BOTTOM,
|
||||
scrollPost: null
|
||||
scrollPost: null,
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
if (currentChannelId) {
|
||||
Object.assign(state, {
|
||||
@@ -54,12 +57,17 @@ export default class PostsViewContainer extends React.Component {
|
||||
ChannelStore.addLeaveListener(this.onChannelLeave);
|
||||
PostStore.addChangeListener(this.onPostsChange);
|
||||
PostStore.addPostsViewJumpListener(this.handlePostsViewJumpRequest);
|
||||
UserStore.addChangeListener(this.onUserChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
ChannelStore.removeChangeListener(this.onChannelChange);
|
||||
ChannelStore.removeLeaveListener(this.onChannelLeave);
|
||||
PostStore.removeChangeListener(this.onPostsChange);
|
||||
PostStore.removePostsViewJumpListener(this.handlePostsViewJumpRequest);
|
||||
UserStore.removeChangeListener(this.onUserChange);
|
||||
}
|
||||
onUserChange() {
|
||||
this.setState({currentUser: UserStore.getCurrentUser()});
|
||||
}
|
||||
handlePostsViewJumpRequest(type, post) {
|
||||
switch (type) {
|
||||
@@ -139,7 +147,7 @@ export default class PostsViewContainer extends React.Component {
|
||||
return PostStore.getVisiblePosts(id);
|
||||
}
|
||||
loadMorePostsTop() {
|
||||
EventHelpers.emitLoadMorePostsEvent();
|
||||
GlobalActions.emitLoadMorePostsEvent();
|
||||
}
|
||||
handlePostsViewScroll(atBottom) {
|
||||
if (atBottom) {
|
||||
@@ -165,6 +173,10 @@ export default class PostsViewContainer extends React.Component {
|
||||
const currentChannelId = channels[this.state.currentChannelIndex];
|
||||
const channel = ChannelStore.get(currentChannelId);
|
||||
|
||||
if (!this.state.currentUser || !channel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const postListCtls = [];
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
const isActive = (channels[i] === currentChannelId);
|
||||
@@ -185,6 +197,7 @@ export default class PostsViewContainer extends React.Component {
|
||||
introText={channel ? createChannelIntroMessage(channel) : null}
|
||||
messageSeparatorTime={this.state.currentLastViewed}
|
||||
profiles={this.props.profiles}
|
||||
currentUser={this.state.currentUser}
|
||||
/>
|
||||
);
|
||||
if (!postLists[i] && isActive) {
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as AsyncClient from '../utils/async_client.jsx';
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
import * as TextFormatting from '../utils/text_formatting.jsx';
|
||||
import twemoji from 'twemoji';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedDate} from 'mm-intl';
|
||||
|
||||
@@ -70,7 +70,7 @@ class RhsComment extends React.Component {
|
||||
}
|
||||
handlePermalink(e) {
|
||||
e.preventDefault();
|
||||
EventHelpers.showGetPostLinkModal(this.props.post);
|
||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.parseEmojis();
|
||||
@@ -151,7 +151,7 @@ class RhsComment extends React.Component {
|
||||
<a
|
||||
href='#'
|
||||
role='menuitem'
|
||||
onClick={() => EventHelpers.showDeletePostModal(post, 0)}
|
||||
onClick={() => GlobalActions.showDeletePostModal(post, 0)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='rhs_comment.del'
|
||||
@@ -253,7 +253,7 @@ class RhsComment extends React.Component {
|
||||
<div className='post__content'>
|
||||
<div className='post__img'>
|
||||
<img
|
||||
src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + Utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp}
|
||||
height='36'
|
||||
width='36'
|
||||
/>
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as Emoji from '../utils/emoticons.jsx';
|
||||
import FileAttachmentList from './file_attachment_list.jsx';
|
||||
import twemoji from 'twemoji';
|
||||
import PostBodyAdditionalContent from './post_body_additional_content.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class RhsRootPost extends React.Component {
|
||||
}
|
||||
handlePermalink(e) {
|
||||
e.preventDefault();
|
||||
EventHelpers.showGetPostLinkModal(this.props.post);
|
||||
GlobalActions.showGetPostLinkModal(this.props.post);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.parseEmojis();
|
||||
@@ -142,7 +142,7 @@ export default class RhsRootPost extends React.Component {
|
||||
<a
|
||||
href='#'
|
||||
role='menuitem'
|
||||
onClick={() => EventHelpers.showDeletePostModal(post, this.props.commentCount)}
|
||||
onClick={() => GlobalActions.showDeletePostModal(post, this.props.commentCount)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='rhs_root.del'
|
||||
@@ -211,7 +211,7 @@ export default class RhsRootPost extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp + '&' + Utils.getSessionIndex();
|
||||
let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp;
|
||||
if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') {
|
||||
if (post.props.override_icon_url) {
|
||||
src = post.props.override_icon_url;
|
||||
|
||||
90
web/react/components/root.jsx
Обычный файл
90
web/react/components/root.jsx
Обычный файл
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import LocalizationStore from '../stores/localization_store.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
export default class Root extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
locale: 'en',
|
||||
translations: null
|
||||
};
|
||||
|
||||
this.localizationChanged = this.localizationChanged.bind(this);
|
||||
}
|
||||
localizationChanged() {
|
||||
this.setState({locale: LocalizationStore.getLocale(), translations: LocalizationStore.getTranslations()});
|
||||
}
|
||||
componentWillMount() {
|
||||
// Setup localization listener
|
||||
LocalizationStore.addChangeListener(this.localizationChanged);
|
||||
|
||||
// Browser store check version
|
||||
BrowserStore.checkVersion();
|
||||
|
||||
window.onerror = (msg, url, line, column, stack) => {
|
||||
var l = {};
|
||||
l.level = 'ERROR';
|
||||
l.message = 'msg: ' + msg + ' row: ' + line + ' col: ' + column + ' stack: ' + stack + ' url: ' + url;
|
||||
|
||||
$.ajax({
|
||||
url: '/api/v1/admin/log_client',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
type: 'POST',
|
||||
data: JSON.stringify(l)
|
||||
});
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.ErrorStore.storeLastError({message: 'DEVELOPER MODE: A javascript error has occured. Please use the javascript console to capture and report the error (row: ' + line + ' col: ' + column + ').'});
|
||||
window.ErrorStore.emitChange();
|
||||
}
|
||||
};
|
||||
|
||||
// Ya....
|
||||
/*eslint-disable */
|
||||
if (window.mm_config.SegmentDeveloperKey != null && window.mm_config.SegmentDeveloperKey !== "") {
|
||||
!function(){var analytics=global.window.analytics=global.window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","group","track","ready","alias","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t){var e=document.createElement("script");e.type="text/javascript";e.async=!0;e.src=("https:"===document.location.protocol?"https://":"http://")+"cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(e,n)};analytics.SNIPPET_VERSION="3.0.1";
|
||||
analytics.load(window.mm_config.SegmentDeveloperKey);
|
||||
analytics.page();
|
||||
}}();
|
||||
} else {
|
||||
global.window.analytics = {};
|
||||
global.window.analytics.page = function(){};
|
||||
global.window.analytics.track = function(){};
|
||||
}
|
||||
/*eslint-enable */
|
||||
|
||||
// Get our localizaiton
|
||||
GlobalActions.newLocalizationSelected('en');
|
||||
}
|
||||
componentWillUnmount() {
|
||||
LocalizationStore.removeChangeListener(this.localizationChanged);
|
||||
}
|
||||
render() {
|
||||
if (this.state.translations == null) {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.state.locale}
|
||||
messages={this.state.translations}
|
||||
key={this.state.locale}
|
||||
>
|
||||
{this.props.children}
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
Root.defaultProps = {
|
||||
};
|
||||
|
||||
Root.propTypes = {
|
||||
children: React.PropTypes.object
|
||||
};
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import UserProfile from './user_profile.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as utils from '../utils/utils.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import * as TextFormatting from '../utils/text_formatting.jsx';
|
||||
|
||||
import Constants from '../utils/constants.jsx';
|
||||
@@ -22,7 +21,7 @@ export default class SearchResultsItem extends React.Component {
|
||||
handleClick(e) {
|
||||
e.preventDefault();
|
||||
|
||||
EventHelpers.emitPostFocusEvent(this.props.post.id);
|
||||
GlobalActions.emitPostFocusEvent(this.props.post.id);
|
||||
|
||||
if ($(window).width() < 768) {
|
||||
$('.sidebar--right').removeClass('move--left');
|
||||
@@ -32,7 +31,7 @@ export default class SearchResultsItem extends React.Component {
|
||||
|
||||
handleFocusRHSClick(e) {
|
||||
e.preventDefault();
|
||||
EventHelpers.emitPostFocusRightHandSideFromSearch(this.props.post, this.props.isMentionSearch);
|
||||
GlobalActions.emitPostFocusRightHandSideFromSearch(this.props.post, this.props.isMentionSearch);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -78,7 +77,7 @@ export default class SearchResultsItem extends React.Component {
|
||||
<div className='post__content'>
|
||||
<div className='post__img'>
|
||||
<img
|
||||
src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp + '&' + utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp}
|
||||
height='36'
|
||||
width='36'
|
||||
/>
|
||||
|
||||
111
web/react/components/should_verify_email.jsx
Обычный файл
111
web/react/components/should_verify_email.jsx
Обычный файл
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
export default class ShouldVerifyEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleResend = this.handleResend.bind(this);
|
||||
|
||||
this.state = {
|
||||
resendStatus: 'none'
|
||||
};
|
||||
}
|
||||
handleResend() {
|
||||
const teamName = this.props.location.query.teamname;
|
||||
const email = this.props.location.query.email;
|
||||
|
||||
this.setState({resendStatus: 'sending'});
|
||||
|
||||
Client.resendVerification(() => {
|
||||
this.setState({resendStatus: 'success'});
|
||||
},
|
||||
() => {
|
||||
this.setState({resendStatus: 'failure'});
|
||||
},
|
||||
teamName,
|
||||
email);
|
||||
}
|
||||
render() {
|
||||
let resendConfirm = '';
|
||||
if (this.state.resendStatus === 'success') {
|
||||
resendConfirm = (
|
||||
<div>
|
||||
<br/>
|
||||
<p className='alert alert-success'>
|
||||
<i className='fa fa-check'/>
|
||||
<FormattedMessage
|
||||
id='email_verify.sent'
|
||||
defaultMessage=' Verification email sent.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.resendStatus === 'failure') {
|
||||
resendConfirm = (
|
||||
<div>
|
||||
<br/>
|
||||
<p className='alert alert-danger'>
|
||||
<i className='fa fa-times'/>
|
||||
<FormattedMessage id='email_verify.failed'/>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='email_verify.almost'
|
||||
defaultMessage='{siteName}: You are almost done'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
<div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='email_verify.notVerifiedBody'
|
||||
defaultMessage='Please verify your email address. Check your inbox for an email.'
|
||||
/>
|
||||
</p>
|
||||
<button
|
||||
onClick={this.handleResend}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='email_verify.resend'
|
||||
defaultMessage='Resend Email'
|
||||
/>
|
||||
</button>
|
||||
{resendConfirm}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ShouldVerifyEmail.defaultProps = {
|
||||
};
|
||||
ShouldVerifyEmail.propTypes = {
|
||||
location: React.PropTypes.object.isRequired
|
||||
};
|
||||
@@ -129,7 +129,9 @@ export default class Sidebar extends React.Component {
|
||||
directChannels,
|
||||
hiddenDirectChannelCount,
|
||||
unreadCounts: JSON.parse(JSON.stringify(ChannelStore.getUnreadCounts())),
|
||||
showTutorialTip: tutorialStep === TutorialSteps.CHANNEL_POPOVER
|
||||
showTutorialTip: tutorialStep === TutorialSteps.CHANNEL_POPOVER,
|
||||
currentTeam: TeamStore.getCurrent(),
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -179,7 +181,7 @@ export default class Sidebar extends React.Component {
|
||||
}
|
||||
updateTitle() {
|
||||
const channel = ChannelStore.getCurrent();
|
||||
if (channel) {
|
||||
if (channel && this.state.currentTeam) {
|
||||
let currentSiteName = '';
|
||||
if (global.window.mm_config.SiteName != null) {
|
||||
currentSiteName = global.window.mm_config.SiteName;
|
||||
@@ -196,7 +198,7 @@ export default class Sidebar extends React.Component {
|
||||
const unread = this.getTotalUnreadCount();
|
||||
const mentionTitle = unread.mentions > 0 ? '(' + unread.mentions + ') ' : '';
|
||||
const unreadTitle = unread.msgs > 0 ? '* ' : '';
|
||||
document.title = mentionTitle + unreadTitle + currentChannelName + ' - ' + TeamStore.getCurrent().display_name + ' ' + currentSiteName;
|
||||
document.title = mentionTitle + unreadTitle + currentChannelName + ' - ' + this.state.currentTeam.display_name + ' ' + currentSiteName;
|
||||
}
|
||||
}
|
||||
onScroll() {
|
||||
@@ -401,7 +403,6 @@ export default class Sidebar extends React.Component {
|
||||
// set up click handler to switch channels (or create a new channel for non-existant ones)
|
||||
var handleClick = null;
|
||||
var href = '#';
|
||||
var teamURL = TeamStore.getCurrentTeamUrl();
|
||||
|
||||
if (!channel.fake) {
|
||||
handleClick = function clickHandler(e) {
|
||||
@@ -413,7 +414,7 @@ export default class Sidebar extends React.Component {
|
||||
|
||||
e.preventDefault();
|
||||
};
|
||||
} else if (channel.fake && teamURL) {
|
||||
} else if (channel.fake) {
|
||||
// It's a direct message channel that doesn't exist yet so let's create it now
|
||||
var otherUserId = Utils.getUserIdFromChannelName(channel);
|
||||
|
||||
@@ -434,7 +435,7 @@ export default class Sidebar extends React.Component {
|
||||
},
|
||||
() => {
|
||||
this.setState({loadingDMChannel: -1});
|
||||
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name;
|
||||
window.location.href = '/' + this.state.currentTeam.name;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -497,6 +498,11 @@ export default class Sidebar extends React.Component {
|
||||
);
|
||||
}
|
||||
render() {
|
||||
// Check if we have all info needed to render
|
||||
if (this.state.currentTeam == null || this.state.currentUser == null) {
|
||||
return (<div/>);
|
||||
}
|
||||
|
||||
this.badgesActive = false;
|
||||
|
||||
// keep track of the first and last unread channels so we can use them to set the unread indicators
|
||||
@@ -586,7 +592,10 @@ export default class Sidebar extends React.Component {
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className='sidebar--left'
|
||||
id='sidebar-left'
|
||||
>
|
||||
<NewChannelFlow
|
||||
show={showChannelModal}
|
||||
channelType={this.state.newChannelModalType}
|
||||
@@ -598,9 +607,10 @@ export default class Sidebar extends React.Component {
|
||||
/>
|
||||
|
||||
<SidebarHeader
|
||||
teamDisplayName={TeamStore.getCurrent().display_name}
|
||||
teamName={TeamStore.getCurrent().name}
|
||||
teamType={TeamStore.getCurrent().type}
|
||||
teamDisplayName={this.state.currentTeam.display_name}
|
||||
teamName={this.state.currentTeam.name}
|
||||
teamType={this.state.currentTeam.type}
|
||||
currentUser={this.state.currentUser}
|
||||
/>
|
||||
|
||||
<UnreadChannelIndicator
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
import NavbarDropdown from './navbar_dropdown.jsx';
|
||||
import TutorialTip from './tutorial/tutorial_tip.jsx';
|
||||
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import PreferenceStore from '../stores/preference_store.jsx';
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
import {FormattedHTMLMessage} from 'mm-intl';
|
||||
@@ -34,7 +32,7 @@ export default class SidebarHeader extends React.Component {
|
||||
PreferenceStore.removeChangeListener(this.onPreferenceChange);
|
||||
}
|
||||
getStateFromStores() {
|
||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, this.props.currentUser.id, 999);
|
||||
|
||||
return {showTutorialTip: tutorialStep === TutorialSteps.MENU_POPOVER};
|
||||
}
|
||||
@@ -77,7 +75,7 @@ export default class SidebarHeader extends React.Component {
|
||||
);
|
||||
}
|
||||
render() {
|
||||
var me = UserStore.getCurrentUser();
|
||||
var me = this.props.currentUser;
|
||||
var profilePicture = null;
|
||||
|
||||
if (!me) {
|
||||
@@ -88,7 +86,7 @@ export default class SidebarHeader extends React.Component {
|
||||
profilePicture = (
|
||||
<img
|
||||
className='user__picture'
|
||||
src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at + '&' + Utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -124,6 +122,7 @@ export default class SidebarHeader extends React.Component {
|
||||
teamType={this.props.teamType}
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
teamName={this.props.teamName}
|
||||
currentUser={this.props.currentUser}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -131,11 +130,12 @@ export default class SidebarHeader extends React.Component {
|
||||
}
|
||||
|
||||
SidebarHeader.defaultProps = {
|
||||
teamDisplayName: global.window.mm_config.SiteName,
|
||||
teamDisplayName: '',
|
||||
teamType: ''
|
||||
};
|
||||
SidebarHeader.propTypes = {
|
||||
teamDisplayName: React.PropTypes.string,
|
||||
teamName: React.PropTypes.string,
|
||||
teamType: React.PropTypes.string
|
||||
teamType: React.PropTypes.string,
|
||||
currentUser: React.PropTypes.object
|
||||
};
|
||||
|
||||
@@ -127,8 +127,13 @@ export default class SidebarRight extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='sidebar-right-container'>
|
||||
{content}
|
||||
<div
|
||||
className='sidebar--right'
|
||||
id='sidebar-right'
|
||||
>
|
||||
<div className='sidebar-right-container'>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import TeamMembersModal from './team_members_modal.jsx';
|
||||
import ToggleModalButton from './toggle_modal_button.jsx';
|
||||
import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
import * as utils from '../utils/utils.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
export default class SidebarRightMenu extends React.Component {
|
||||
componentDidMount() {
|
||||
@@ -19,18 +19,11 @@ export default class SidebarRightMenu extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
showUserSettingsModal: false
|
||||
};
|
||||
}
|
||||
|
||||
handleLogoutClick(e) {
|
||||
e.preventDefault();
|
||||
client.logout();
|
||||
}
|
||||
|
||||
render() {
|
||||
var teamLink = '';
|
||||
var inviteLink = '';
|
||||
@@ -42,14 +35,14 @@ export default class SidebarRightMenu extends React.Component {
|
||||
var isSystemAdmin = false;
|
||||
|
||||
if (currentUser != null) {
|
||||
isAdmin = utils.isAdmin(currentUser.roles);
|
||||
isSystemAdmin = utils.isSystemAdmin(currentUser.roles);
|
||||
isAdmin = Utils.isAdmin(currentUser.roles);
|
||||
isSystemAdmin = Utils.isSystemAdmin(currentUser.roles);
|
||||
|
||||
inviteLink = (
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={EventHelpers.showInviteMemberModal}
|
||||
onClick={GlobalActions.showInviteMemberModal}
|
||||
>
|
||||
<i className='fa fa-user'></i>
|
||||
<FormattedMessage
|
||||
@@ -65,7 +58,7 @@ export default class SidebarRightMenu extends React.Component {
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={EventHelpers.showGetTeamInviteLinkModal}
|
||||
onClick={GlobalActions.showGetTeamInviteLinkModal}
|
||||
>
|
||||
<i className='glyphicon glyphicon-link'></i>
|
||||
<FormattedMessage
|
||||
@@ -107,13 +100,13 @@ export default class SidebarRightMenu extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (isSystemAdmin && !utils.isMobile()) {
|
||||
if (isSystemAdmin && !Utils.isMobile()) {
|
||||
consoleLink = (
|
||||
<li>
|
||||
<a
|
||||
href={'/admin_console?' + utils.getSessionIndex()}
|
||||
href={'/admin_console'}
|
||||
>
|
||||
<i className='fa fa-wrench'></i>
|
||||
<i className='fa fa-wrench'></i>
|
||||
<FormattedMessage
|
||||
id='sidebar_right_menu.console'
|
||||
defaultMessage='System Console'
|
||||
@@ -168,7 +161,10 @@ export default class SidebarRightMenu extends React.Component {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className='sidebar--menu'
|
||||
id='sidebar-menu'
|
||||
>
|
||||
<div className='team__header theme'>
|
||||
<a
|
||||
className='team__name'
|
||||
@@ -196,16 +192,13 @@ export default class SidebarRightMenu extends React.Component {
|
||||
{manageLink}
|
||||
{consoleLink}
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={this.handleLogoutClick}
|
||||
>
|
||||
<Link to={Utils.getTeamURLFromAddressBar() + '/logout'}>
|
||||
<i className='fa fa-sign-out'></i>
|
||||
<FormattedMessage
|
||||
id='sidebar_right_menu.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className='divider'></li>
|
||||
{helpLink}
|
||||
|
||||
@@ -6,6 +6,8 @@ import EmailSignUpPage from './team_signup_with_email.jsx';
|
||||
import SSOSignupPage from './team_signup_with_sso.jsx';
|
||||
import LdapSignUpPage from './team_signup_with_ldap.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -14,6 +16,7 @@ export default class TeamSignUp extends React.Component {
|
||||
super(props);
|
||||
|
||||
this.updatePage = this.updatePage.bind(this);
|
||||
this.onTeamUpdate = this.onTeamUpdate.bind(this);
|
||||
|
||||
var count = 0;
|
||||
|
||||
@@ -46,11 +49,34 @@ export default class TeamSignUp extends React.Component {
|
||||
this.setState({page});
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (global.window.mm_config.EnableTeamListing === 'true') {
|
||||
AsyncClient.getAllTeams();
|
||||
this.onTeamUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
TeamStore.addChangeListener(this.onTeamUpdate);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
TeamStore.removeChangeListener(this.onTeamUpdate);
|
||||
}
|
||||
|
||||
onTeamUpdate() {
|
||||
this.setState({
|
||||
teams: TeamStore.getAll()
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
var teamListing = null;
|
||||
let teamListing = null;
|
||||
|
||||
if (global.window.mm_config.EnableTeamListing === 'true') {
|
||||
if (this.props.teams.length === 0) {
|
||||
if (this.state.teams == null) {
|
||||
teamListing = (<div/>);
|
||||
} else if (this.state.teams.length === 0) {
|
||||
if (global.window.mm_config.EnableTeamCreation !== 'true') {
|
||||
teamListing = (
|
||||
<div>
|
||||
@@ -72,23 +98,26 @@ export default class TeamSignUp extends React.Component {
|
||||
</h4>
|
||||
<div className='signup-team-all'>
|
||||
{
|
||||
this.props.teams.map((team) => {
|
||||
return (
|
||||
<div
|
||||
key={'team_' + team.name}
|
||||
className='signup-team-dir'
|
||||
>
|
||||
<a
|
||||
href={'/' + team.name}
|
||||
Object.values(this.state.teams).map((team) => {
|
||||
if (team.allow_team_listing) {
|
||||
return (
|
||||
<div
|
||||
key={'team_' + team.name}
|
||||
className='signup-team-dir'
|
||||
>
|
||||
<span className='signup-team-dir__name'>{team.display_name}</span>
|
||||
<span
|
||||
className='glyphicon glyphicon-menu-right right signup-team-dir__arrow'
|
||||
aria-hidden='true'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
<a
|
||||
href={'/' + team.name}
|
||||
>
|
||||
<span className='signup-team-dir__name'>{team.display_name}</span>
|
||||
<span
|
||||
className='glyphicon glyphicon-menu-right right signup-team-dir__arrow'
|
||||
aria-hidden='true'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
@@ -103,42 +132,26 @@ export default class TeamSignUp extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
let signupMethod = null;
|
||||
|
||||
if (global.window.mm_config.EnableTeamCreation !== 'true') {
|
||||
if (teamListing == null) {
|
||||
return (
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='signup_team.disabled'
|
||||
defaultMessage='Team creation has been disabled. Please contact an administrator for access.'
|
||||
/>
|
||||
</div>
|
||||
signupMethod = (
|
||||
<FormattedMessage
|
||||
id='signup_team.disabled'
|
||||
defaultMessage='Team creation has been disabled. Please contact an administrator for access.'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{teamListing}
|
||||
</div>
|
||||
} else if (this.state.page === 'choose') {
|
||||
signupMethod = (
|
||||
<ChoosePage
|
||||
updatePage={this.updatePage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.page === 'choose') {
|
||||
return (
|
||||
<div>
|
||||
{teamListing}
|
||||
<ChoosePage
|
||||
updatePage={this.updatePage}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.page === 'email') {
|
||||
return (
|
||||
<div>
|
||||
{teamListing}
|
||||
<EmailSignUpPage/>
|
||||
</div>
|
||||
} else if (this.state.page === 'email') {
|
||||
signupMethod = (
|
||||
<EmailSignUpPage/>
|
||||
);
|
||||
} else if (this.state.page === 'ldap') {
|
||||
return (
|
||||
@@ -148,35 +161,45 @@ export default class TeamSignUp extends React.Component {
|
||||
</div>
|
||||
);
|
||||
} else if (this.state.page === 'gitlab') {
|
||||
return (
|
||||
<div>
|
||||
{teamListing}
|
||||
<SSOSignupPage service={Constants.GITLAB_SERVICE}/>
|
||||
</div>
|
||||
signupMethod = (
|
||||
<SSOSignupPage service={Constants.GITLAB_SERVICE}/>
|
||||
);
|
||||
} else if (this.state.page === 'google') {
|
||||
return (
|
||||
<div>
|
||||
{teamListing}
|
||||
<SSOSignupPage service={Constants.GOOGLE_SERVICE}/>
|
||||
</div>
|
||||
signupMethod = (
|
||||
<SSOSignupPage service={Constants.GOOGLE_SERVICE}/>
|
||||
);
|
||||
} else if (this.state.page === 'none') {
|
||||
return (
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='signup_team.none'
|
||||
defaultMessage='No team creation method has been enabled. Please contact an administrator for access.'
|
||||
/>
|
||||
</div>
|
||||
signupMethod = (
|
||||
<FormattedMessage
|
||||
id='signup_team.none'
|
||||
defaultMessage='No team creation method has been enabled. Please contact an administrator for access.'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return (
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h1>{global.window.mm_config.SiteName}</h1>
|
||||
<h4 className='color--light'>
|
||||
<FormattedMessage
|
||||
id='web.root.singup_info'
|
||||
/>
|
||||
</h4>
|
||||
<div id='signup-team'>
|
||||
{teamListing}
|
||||
{signupMethod}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TeamSignUp.propTypes = {
|
||||
teams: React.PropTypes.array
|
||||
};
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import WelcomePage from './team_signup_welcome_page.jsx';
|
||||
import TeamDisplayNamePage from './team_signup_display_name_page.jsx';
|
||||
import TeamURLPage from './team_signup_url_page.jsx';
|
||||
import SendInivtesPage from './team_signup_send_invites_page.jsx';
|
||||
import UsernamePage from './team_signup_username_page.jsx';
|
||||
import PasswordPage from './team_signup_password_page.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class SignupTeamComplete extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.updateParent = this.updateParent.bind(this);
|
||||
|
||||
var initialState = BrowserStore.getGlobalItem(props.hash);
|
||||
|
||||
if (!initialState) {
|
||||
initialState = {};
|
||||
initialState.wizard = 'welcome';
|
||||
initialState.team = {};
|
||||
initialState.team.email = this.props.email;
|
||||
initialState.team.allowed_domains = '';
|
||||
initialState.invites = [];
|
||||
initialState.invites.push('');
|
||||
initialState.invites.push('');
|
||||
initialState.invites.push('');
|
||||
initialState.user = {};
|
||||
initialState.hash = this.props.hash;
|
||||
initialState.data = this.props.data;
|
||||
}
|
||||
|
||||
this.state = initialState;
|
||||
}
|
||||
updateParent(state, skipSet) {
|
||||
BrowserStore.setGlobalItem(this.props.hash, state);
|
||||
|
||||
if (!skipSet) {
|
||||
this.setState(state);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (this.state.wizard === 'welcome') {
|
||||
return (
|
||||
<WelcomePage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.wizard === 'team_display_name') {
|
||||
return (
|
||||
<TeamDisplayNamePage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.wizard === 'team_url') {
|
||||
return (
|
||||
<TeamURLPage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.wizard === 'send_invites') {
|
||||
return (
|
||||
<SendInivtesPage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.wizard === 'username') {
|
||||
return (
|
||||
<UsernamePage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.wizard === 'password') {
|
||||
return (
|
||||
<PasswordPage
|
||||
state={this.state}
|
||||
updateParent={this.updateParent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='signup_team_complete.completed'
|
||||
defaultMessage="You've already completed the signup process for this invitation or this invitation has expired."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignupTeamComplete.defaultProps = {
|
||||
hash: '',
|
||||
email: '',
|
||||
data: ''
|
||||
};
|
||||
SignupTeamComplete.propTypes = {
|
||||
hash: React.PropTypes.string,
|
||||
email: React.PropTypes.string,
|
||||
data: React.PropTypes.string
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import BrowserStore from '../../../stores/browser_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
export default class SignupTeamComplete extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.updateParent = this.updateParent.bind(this);
|
||||
}
|
||||
componentWillMount() {
|
||||
const data = JSON.parse(this.props.location.query.d);
|
||||
this.hash = this.props.location.query.h;
|
||||
|
||||
var initialState = BrowserStore.getGlobalItem(this.hash);
|
||||
|
||||
if (!initialState) {
|
||||
initialState = {};
|
||||
initialState.wizard = 'welcome';
|
||||
initialState.team = {};
|
||||
initialState.team.email = data.email;
|
||||
initialState.team.allowed_domains = '';
|
||||
initialState.invites = [];
|
||||
initialState.invites.push('');
|
||||
initialState.invites.push('');
|
||||
initialState.invites.push('');
|
||||
initialState.user = {};
|
||||
initialState.hash = this.hash;
|
||||
initialState.data = this.props.location.query.d;
|
||||
}
|
||||
|
||||
this.setState(initialState);
|
||||
}
|
||||
componentDidMount() {
|
||||
browserHistory.push('/signup_team_complete/welcome');
|
||||
}
|
||||
updateParent(state, skipSet) {
|
||||
BrowserStore.setGlobalItem(this.hash, state);
|
||||
|
||||
if (!skipSet) {
|
||||
this.setState(state);
|
||||
browserHistory.push('/signup_team_complete/' + state.wizard);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span classNameName='fa fa-chevron-left'/>
|
||||
<FormattedMessage id='web.header.back'/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container'>
|
||||
<div id='signup-team-complete'>
|
||||
{React.cloneElement(this.props.children, {
|
||||
state: this.state,
|
||||
updateParent: this.updateParent
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignupTeamComplete.defaultProps = {
|
||||
};
|
||||
SignupTeamComplete.propTypes = {
|
||||
location: React.PropTypes.object,
|
||||
children: React.PropTypes.node
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
import * as utils from '../../../utils/utils.jsx';
|
||||
import * as client from '../../../utils/client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -133,4 +133,4 @@ TeamSignupDisplayNamePage.propTypes = {
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupDisplayNamePage);
|
||||
export default injectIntl(TeamSignupDisplayNamePage);
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Utils from '../../../utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages} from 'mm-intl';
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
export default class FinishedPage extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='signup_team_complete.completed'
|
||||
defaultMessage="You've already completed the signup process for this invitation or this invitation has expired."
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import * as Client from '../../../utils/client.jsx';
|
||||
import BrowserStore from '../../../stores/browser_store.jsx';
|
||||
import UserStore from '../../../stores/user_store.jsx';
|
||||
import Constants from '../../../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
const holders = defineMessages({
|
||||
passwordError: {
|
||||
@@ -66,11 +67,11 @@ class TeamSignupPasswordPage extends React.Component {
|
||||
props.state.wizard = 'finished';
|
||||
props.updateParent(props.state, true);
|
||||
|
||||
window.location.href = '/' + teamSignup.team.name + '/channels/town-square';
|
||||
browserHistory.push('/' + teamSignup.team.name + '/channels/town-square');
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
window.location.href = '/verify_email?email=' + encodeURIComponent(teamSignup.team.email) + '&teamname=' + encodeURIComponent(teamSignup.team.name);
|
||||
browserHistory.push('/verify_email?email=' + encodeURIComponent(teamSignup.team.email) + '&teamname=' + encodeURIComponent(teamSignup.team.name));
|
||||
} else {
|
||||
this.setState({serverError: err.message});
|
||||
$('#finish-button').button('reset');
|
||||
@@ -211,4 +212,4 @@ TeamSignupPasswordPage.propTypes = {
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupPasswordPage);
|
||||
export default injectIntl(TeamSignupPasswordPage);
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import EmailItem from './team_signup_email_item.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as Client from '../../../utils/client.jsx';
|
||||
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import * as Utils from '../../../utils/utils.jsx';
|
||||
import * as Client from '../../../utils/client.jsx';
|
||||
import Constants from '../../../utils/constants.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
@@ -202,4 +202,4 @@ TeamSignupUrlPage.propTypes = {
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupUrlPage);
|
||||
export default injectIntl(TeamSignupUrlPage);
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import * as Utils from '../../../utils/utils.jsx';
|
||||
import * as Client from '../../../utils/client.jsx';
|
||||
import Constants from '../../../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -161,4 +161,4 @@ TeamSignupUsernamePage.propTypes = {
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupUsernamePage);
|
||||
export default injectIntl(TeamSignupUsernamePage);
|
||||
@@ -1,12 +1,14 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import * as Utils from '../../../utils/utils.jsx';
|
||||
import * as Client from '../../../utils/client.jsx';
|
||||
import BrowserStore from '../../../stores/browser_store.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
const holders = defineMessages({
|
||||
storageError: {
|
||||
id: 'team_signup_welcome.storageError',
|
||||
@@ -73,7 +75,7 @@ class TeamSignupWelcomePage extends React.Component {
|
||||
} else {
|
||||
this.props.state.wizard = 'finished';
|
||||
this.props.updateParent(this.props.state);
|
||||
window.location.href = '/signup_team_confirm/?email=' + encodeURIComponent(email);
|
||||
browserHistory.push('/signup_team_confirm/?email=' + encodeURIComponent(email));
|
||||
}
|
||||
}.bind(this),
|
||||
function error(err) {
|
||||
@@ -229,4 +231,4 @@ TeamSignupWelcomePage.propTypes = {
|
||||
state: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupWelcomePage);
|
||||
export default injectIntl(TeamSignupWelcomePage);
|
||||
@@ -6,30 +6,41 @@ import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
export default class SignupTeamConfirm extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='signup-team__container'>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='signup_team_confirm.title'
|
||||
defaultMessage='Sign up Complete'
|
||||
/>
|
||||
</h3>
|
||||
<p>
|
||||
<FormattedHTMLMessage
|
||||
id='signup_team_confirm.checkEmail'
|
||||
defaultMessage='Please check your email: <strong>{email}</strong><br />Your email contains a link to set up your team'
|
||||
values={{
|
||||
email: this.props.email
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<div>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div classNameName='signup-team__container'>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id='signup_team_confirm.title'
|
||||
defaultMessage='Sign up Complete'
|
||||
/>
|
||||
</h3>
|
||||
<p>
|
||||
<FormattedHTMLMessage
|
||||
id='signup_team_confirm.checkEmail'
|
||||
defaultMessage='Please check your email: <strong>{email}</strong><br />Your email contains a link to set up your team'
|
||||
values={{
|
||||
email: this.props.location.query.email
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignupTeamConfirm.defaultProps = {
|
||||
email: ''
|
||||
};
|
||||
SignupTeamConfirm.propTypes = {
|
||||
email: React.PropTypes.string
|
||||
location: React.PropTypes.object
|
||||
};
|
||||
|
||||
@@ -2,83 +2,130 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from '../utils/utils.jsx';
|
||||
import * as client from '../utils/client.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import UserStore from '../stores/user_store.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
import LoadingScreen from '../components/loading_screen.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
required: {
|
||||
id: 'signup_user_completed.required',
|
||||
defaultMessage: 'This field is required'
|
||||
},
|
||||
validEmail: {
|
||||
id: 'signup_user_completed.validEmail',
|
||||
defaultMessage: 'Please enter a valid email address'
|
||||
},
|
||||
reserved: {
|
||||
id: 'signup_user_completed.reserved',
|
||||
defaultMessage: 'This username is reserved, please choose a new one.'
|
||||
},
|
||||
usernameLength: {
|
||||
id: 'signup_user_completed.usernameLength',
|
||||
defaultMessage: 'Username must begin with a letter, and contain between {min} to {max} lowercase characters made up of numbers, letters, and the symbols \'.\', \'-\' and \'_\'.'
|
||||
},
|
||||
passwordLength: {
|
||||
id: 'signup_user_completed.passwordLength',
|
||||
defaultMessage: 'Please enter at least {min} characters'
|
||||
}
|
||||
});
|
||||
import {FormattedMessage, FormattedHTMLMessage} from 'mm-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
class SignupUserComplete extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.inviteInfoRecieved = this.inviteInfoRecieved.bind(this);
|
||||
|
||||
var initialState = BrowserStore.getGlobalItem(this.props.hash);
|
||||
this.state = {
|
||||
data: '',
|
||||
hash: '',
|
||||
usedBefore: false,
|
||||
email: '',
|
||||
teamDisplayName: '',
|
||||
teamName: '',
|
||||
teamId: ''
|
||||
};
|
||||
}
|
||||
componentWillMount() {
|
||||
let data = this.props.location.query.d;
|
||||
let hash = this.props.location.query.h;
|
||||
const inviteId = this.props.location.query.id;
|
||||
let usedBefore = false;
|
||||
let email = '';
|
||||
let teamDisplayName = '';
|
||||
let teamName = '';
|
||||
let teamId = '';
|
||||
|
||||
if (!initialState) {
|
||||
initialState = {};
|
||||
initialState.wizard = 'welcome';
|
||||
initialState.user = {};
|
||||
initialState.user.team_id = this.props.teamId;
|
||||
initialState.user.email = this.props.email;
|
||||
initialState.original_email = this.props.email;
|
||||
// If we have a hash in the url then we are attempting to access a private team
|
||||
if (hash) {
|
||||
const parsedData = JSON.parse(data);
|
||||
usedBefore = BrowserStore.getGlobalItem(hash);
|
||||
email = parsedData.email;
|
||||
teamDisplayName = parsedData.display_name;
|
||||
teamName = parsedData.name;
|
||||
teamId = parsedData.id;
|
||||
} else {
|
||||
Client.getInviteInfo(this.inviteInfoRecieved, null, inviteId);
|
||||
data = '';
|
||||
hash = '';
|
||||
}
|
||||
|
||||
this.state = initialState;
|
||||
this.setState({
|
||||
data,
|
||||
hash,
|
||||
usedBefore,
|
||||
email,
|
||||
teamDisplayName,
|
||||
teamName,
|
||||
teamId
|
||||
});
|
||||
}
|
||||
inviteInfoRecieved(data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
teamDisplayName: data.display_name,
|
||||
teamName: data.name,
|
||||
teamId: data.id
|
||||
});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
const providedEmail = ReactDOM.findDOMNode(this.refs.email).value.trim();
|
||||
if (!providedEmail) {
|
||||
this.setState({nameError: '', emailError: formatMessage(holders.required), passwordError: ''});
|
||||
this.setState({
|
||||
nameError: '',
|
||||
emailError: (<FormattedMessage id='signup_user_completed.required'/>),
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Utils.isEmail(providedEmail)) {
|
||||
this.setState({nameError: '', emailError: formatMessage(holders.validEmail), passwordError: ''});
|
||||
this.setState({
|
||||
nameError: '',
|
||||
emailError: (<FormattedMessage id='signup_user_completed.validEmail'/>),
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const providedUsername = ReactDOM.findDOMNode(this.refs.name).value.trim().toLowerCase();
|
||||
if (!providedUsername) {
|
||||
this.setState({nameError: formatMessage(holders.required), emailError: '', passwordError: '', serverError: ''});
|
||||
this.setState({
|
||||
nameError: (<FormattedMessage id='signup_user_completed.required'/>),
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const usernameError = Utils.isValidUsername(providedUsername);
|
||||
if (usernameError === 'Cannot use a reserved word as a username.') {
|
||||
this.setState({nameError: formatMessage(holders.reserved), emailError: '', passwordError: '', serverError: ''});
|
||||
this.setState({
|
||||
nameError: (<FormattedMessage id='signup_user_completed.reserved'/>),
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
} else if (usernameError) {
|
||||
this.setState({
|
||||
nameError: formatMessage(holders.usernameLength, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH}),
|
||||
nameError: (
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.usernameLength'
|
||||
min={Constants.MIN_USERNAME_LENGTH}
|
||||
max={Constants.MAX_USERNAME_LENGTH}
|
||||
/>
|
||||
),
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
@@ -88,41 +135,50 @@ class SignupUserComplete extends React.Component {
|
||||
|
||||
const providedPassword = ReactDOM.findDOMNode(this.refs.password).value.trim();
|
||||
if (!providedPassword || providedPassword.length < Constants.MIN_PASSWORD_LENGTH) {
|
||||
this.setState({nameError: '', emailError: '', passwordError: formatMessage(holders.passwordLength, {min: Constants.MIN_PASSWORD_LENGTH}), serverError: ''});
|
||||
this.setState({
|
||||
nameError: '',
|
||||
emailError: '',
|
||||
passwordError: (
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.passwordLength'
|
||||
min={Constants.MIN_PASSWORD_LENGTH}
|
||||
/>
|
||||
),
|
||||
serverError: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const user = {
|
||||
team_id: this.props.teamId,
|
||||
email: providedEmail,
|
||||
username: providedUsername,
|
||||
password: providedPassword,
|
||||
allow_marketing: true
|
||||
};
|
||||
|
||||
this.setState({
|
||||
user,
|
||||
nameError: '',
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
serverError: ''
|
||||
});
|
||||
|
||||
client.createUser(user, this.props.data, this.props.hash,
|
||||
() => {
|
||||
client.track('signup', 'signup_user_02_complete');
|
||||
const user = {
|
||||
team_id: this.state.teamId,
|
||||
email: providedEmail,
|
||||
username: providedUsername,
|
||||
password: providedPassword,
|
||||
allow_marketing: true
|
||||
};
|
||||
|
||||
client.loginByEmail(this.props.teamName, user.email, user.password,
|
||||
Client.createUser(user, this.state.data, this.state.hash,
|
||||
() => {
|
||||
Client.track('signup', 'signup_user_02_complete');
|
||||
|
||||
Client.loginByEmail(this.state.teamName, user.email, user.password,
|
||||
() => {
|
||||
UserStore.setLastEmail(user.email);
|
||||
if (this.props.hash > 0) {
|
||||
BrowserStore.setGlobalItem(this.props.hash, JSON.stringify({wizard: 'finished'}));
|
||||
if (this.state.hash > 0) {
|
||||
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
|
||||
}
|
||||
window.location.href = '/' + this.props.teamName + '/channels/town-square';
|
||||
browserHistory.push('/' + this.state.teamName + '/channels/town-square');
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
window.location.href = '/verify_email?email=' + encodeURIComponent(user.email) + '&teamname=' + encodeURIComponent(this.props.teamName);
|
||||
browserHistory.push('/should_verify_email?email=' + encodeURIComponent(user.email) + '&teamname=' + encodeURIComponent(this.state.teamName));
|
||||
} else {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
@@ -135,9 +191,10 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
}
|
||||
render() {
|
||||
client.track('signup', 'signup_user_01_welcome');
|
||||
Client.track('signup', 'signup_user_01_welcome');
|
||||
|
||||
if (this.state.wizard === 'finished') {
|
||||
// If we have been used then just display a message
|
||||
if (this.state.usedBefore) {
|
||||
return (
|
||||
<div>
|
||||
<FormattedMessage
|
||||
@@ -148,6 +205,12 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
// If we haven't got a team id yet we are waiting for
|
||||
// the client so just show the standard loading screen
|
||||
if (this.state.teamId === '') {
|
||||
return (<LoadingScreen/>);
|
||||
}
|
||||
|
||||
// set up error labels
|
||||
var emailError = null;
|
||||
var emailHelpText = (
|
||||
@@ -160,7 +223,7 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
var emailDivStyle = 'form-group';
|
||||
if (this.state.emailError) {
|
||||
emailError = <label className='control-label'>{this.state.emailError}</label>;
|
||||
emailError = (<label className='control-label'>{this.state.emailError}</label>);
|
||||
emailHelpText = '';
|
||||
emailDivStyle += ' has-error';
|
||||
}
|
||||
@@ -203,13 +266,13 @@ class SignupUserComplete extends React.Component {
|
||||
|
||||
// set up the email entry and hide it if an email was provided
|
||||
var yourEmailIs = '';
|
||||
if (this.state.user.email) {
|
||||
if (this.state.email) {
|
||||
yourEmailIs = (
|
||||
<FormattedHTMLMessage
|
||||
id='signup_user_completed.emailIs'
|
||||
defaultMessage="Your email address is <strong>{email}</strong>. You'll use this address to sign in to {siteName}."
|
||||
values={{
|
||||
email: this.state.user.email,
|
||||
email: this.state.email,
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
@@ -217,7 +280,7 @@ class SignupUserComplete extends React.Component {
|
||||
}
|
||||
|
||||
var emailContainerStyle = 'margin--extra';
|
||||
if (this.state.original_email) {
|
||||
if (this.state.email) {
|
||||
emailContainerStyle = 'hidden';
|
||||
}
|
||||
|
||||
@@ -234,7 +297,7 @@ class SignupUserComplete extends React.Component {
|
||||
type='email'
|
||||
ref='email'
|
||||
className='form-control'
|
||||
defaultValue={this.state.user.email}
|
||||
defaultValue={this.state.email}
|
||||
placeholder=''
|
||||
maxLength='128'
|
||||
autoFocus={true}
|
||||
@@ -249,20 +312,20 @@ class SignupUserComplete extends React.Component {
|
||||
var signupMessage = [];
|
||||
if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
|
||||
signupMessage.push(
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/' + this.props.teamName + '/signup/gitlab' + window.location.search}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
<a
|
||||
className='btn btn-custom-login gitlab'
|
||||
key='gitlab'
|
||||
href={'/api/v1/oauth/gitlab/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.gitlab'
|
||||
defaultMessage='with GitLab'
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
|
||||
@@ -270,7 +333,7 @@ class SignupUserComplete extends React.Component {
|
||||
<a
|
||||
className='btn btn-custom-login google'
|
||||
key='google'
|
||||
href={'/' + this.props.teamName + '/signup/google' + window.location.search}
|
||||
href={'/api/v1/oauth/google/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)}
|
||||
>
|
||||
<span className='icon'/>
|
||||
<span>
|
||||
@@ -318,16 +381,16 @@ class SignupUserComplete extends React.Component {
|
||||
/>
|
||||
</strong></h5>
|
||||
<div className={passwordDivStyle}>
|
||||
<input
|
||||
type='password'
|
||||
ref='password'
|
||||
className='form-control'
|
||||
placeholder=''
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
{passwordError}
|
||||
</div>
|
||||
<input
|
||||
type='password'
|
||||
ref='password'
|
||||
className='form-control'
|
||||
placeholder=''
|
||||
maxLength='128'
|
||||
spellCheck='false'
|
||||
/>
|
||||
{passwordError}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className='margin--extra'>
|
||||
@@ -373,58 +436,56 @@ class SignupUserComplete extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h5 className='margin--less'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.welcome'
|
||||
defaultMessage='Welcome to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{this.props.teamDisplayName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.onSite'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
<h4 className='color--light'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.lets'
|
||||
defaultMessage="Let's create your account"
|
||||
/>
|
||||
</h4>
|
||||
{signupMessage}
|
||||
{emailSignup}
|
||||
{serverError}
|
||||
</form>
|
||||
<div className='signup-header'>
|
||||
<a href='/'>
|
||||
<span classNameNameName='fa fa-chevron-left'/>
|
||||
<FormattedMessage id='web.header.back'/>
|
||||
</a>
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className='signup-team__container padding--less'>
|
||||
<form>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src='/static/images/logo.png'
|
||||
/>
|
||||
<h5 className='margin--less'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.welcome'
|
||||
defaultMessage='Welcome to:'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{this.state.teamName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.onSite'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
<h4 className='color--light'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.lets'
|
||||
defaultMessage="Let's create your account"
|
||||
/>
|
||||
</h4>
|
||||
{signupMessage}
|
||||
{emailSignup}
|
||||
{serverError}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignupUserComplete.defaultProps = {
|
||||
teamName: '',
|
||||
hash: '',
|
||||
teamId: '',
|
||||
email: '',
|
||||
data: null,
|
||||
teamDisplayName: ''
|
||||
};
|
||||
SignupUserComplete.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
teamName: React.PropTypes.string,
|
||||
hash: React.PropTypes.string,
|
||||
teamId: React.PropTypes.string,
|
||||
email: React.PropTypes.string,
|
||||
data: React.PropTypes.string,
|
||||
teamDisplayName: React.PropTypes.string
|
||||
location: React.PropTypes.object
|
||||
};
|
||||
|
||||
export default injectIntl(SignupUserComplete);
|
||||
export default SignupUserComplete;
|
||||
|
||||
@@ -40,7 +40,7 @@ class AtMentionSuggestion extends React.Component {
|
||||
icon = (
|
||||
<img
|
||||
className='mention-img'
|
||||
src={'/api/v1/users/' + item.id + '/image?time=' + item.update_at + '&' + Utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + item.id + '/image?time=' + item.update_at}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
import * as EventHelpers from '../../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../../action_creators/global_actions.jsx';
|
||||
import SuggestionStore from '../../stores/suggestion_store.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
@@ -48,7 +48,7 @@ export default class SuggestionBox extends React.Component {
|
||||
if (!(container.is(e.target) || container.has(e.target).length > 0)) {
|
||||
// we can't just use blur for this because it fires and hides the children before
|
||||
// their click handlers can be called
|
||||
EventHelpers.emitClearSuggestions(this.suggestionId);
|
||||
GlobalActions.emitClearSuggestions(this.suggestionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export default class SuggestionBox extends React.Component {
|
||||
const caret = Utils.getCaretPosition(textbox);
|
||||
const pretext = textbox.value.substring(0, caret);
|
||||
|
||||
EventHelpers.emitSuggestionPretextChanged(this.suggestionId, pretext);
|
||||
GlobalActions.emitSuggestionPretextChanged(this.suggestionId, pretext);
|
||||
|
||||
if (this.props.onUserInput) {
|
||||
this.props.onUserInput(textbox.value);
|
||||
@@ -89,13 +89,13 @@ export default class SuggestionBox extends React.Component {
|
||||
handleKeyDown(e) {
|
||||
if (SuggestionStore.hasSuggestions(this.suggestionId)) {
|
||||
if (e.which === KeyCodes.UP) {
|
||||
EventHelpers.emitSelectPreviousSuggestion(this.suggestionId);
|
||||
GlobalActions.emitSelectPreviousSuggestion(this.suggestionId);
|
||||
e.preventDefault();
|
||||
} else if (e.which === KeyCodes.DOWN) {
|
||||
EventHelpers.emitSelectNextSuggestion(this.suggestionId);
|
||||
GlobalActions.emitSelectNextSuggestion(this.suggestionId);
|
||||
e.preventDefault();
|
||||
} else if (e.which === KeyCodes.ENTER || e.which === KeyCodes.TAB) {
|
||||
EventHelpers.emitCompleteWordSuggestion(this.suggestionId);
|
||||
GlobalActions.emitCompleteWordSuggestion(this.suggestionId);
|
||||
e.preventDefault();
|
||||
} else if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(e);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as EventHelpers from '../../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../../action_creators/global_actions.jsx';
|
||||
import SuggestionStore from '../../stores/suggestion_store.jsx';
|
||||
|
||||
export default class SuggestionList extends React.Component {
|
||||
@@ -36,7 +36,7 @@ export default class SuggestionList extends React.Component {
|
||||
}
|
||||
|
||||
handleItemClick(term, e) {
|
||||
EventHelpers.emitCompleteWordSuggestion(this.props.suggestionId, term);
|
||||
GlobalActions.emitCompleteWordSuggestion(this.props.suggestionId, term);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
@@ -10,8 +10,36 @@ import {FormattedMessage} from 'mm-intl';
|
||||
const Modal = ReactBootstrap.Modal;
|
||||
|
||||
export default class TeamMembersModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.teamChanged = this.teamChanged.bind(this);
|
||||
|
||||
this.state = {
|
||||
team: TeamStore.getCurrent()
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.onShow();
|
||||
}
|
||||
|
||||
TeamStore.addChangeListener(this.teamChanged);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
TeamStore.removeChangeListener(this.teamChanged);
|
||||
}
|
||||
|
||||
teamChanged() {
|
||||
this.setState({team: TeamStore.getCurrent()});
|
||||
}
|
||||
|
||||
render() {
|
||||
const team = TeamStore.getCurrent();
|
||||
let teamDisplayName = '';
|
||||
if (this.state.team) {
|
||||
teamDisplayName = this.state.team.display_name;
|
||||
}
|
||||
|
||||
let maxHeight = 1000;
|
||||
if (Utils.windowHeight() <= 1200) {
|
||||
@@ -29,7 +57,7 @@ export default class TeamMembersModal extends React.Component {
|
||||
id='team_member_modal.members'
|
||||
defaultMessage='{team} Members'
|
||||
values={{
|
||||
team: team.display_name
|
||||
team: teamDisplayName
|
||||
}}
|
||||
/>
|
||||
</Modal.Header>
|
||||
|
||||
@@ -28,6 +28,9 @@ export default class TeamSettings extends React.Component {
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (!this.state.team) {
|
||||
return null;
|
||||
}
|
||||
var result;
|
||||
switch (this.props.activeTab) {
|
||||
case 'general':
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as Utils from '../utils/utils.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
import {browserHistory} from 'react-router';
|
||||
|
||||
const holders = defineMessages({
|
||||
emailError: {
|
||||
@@ -47,9 +48,9 @@ class EmailSignUpPage extends React.Component {
|
||||
Client.signupTeam(team.email,
|
||||
(data) => {
|
||||
if (data.follow_link) {
|
||||
window.location.href = data.follow_link;
|
||||
browserHistory.push(data.follow_link);
|
||||
} else {
|
||||
window.location.href = `/signup_team_confirm/?email=${encodeURIComponent(team.email)}`;
|
||||
browserHistory.push(`/signup_team_confirm/?email=${encodeURIComponent(team.email)}`);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
@@ -117,4 +118,4 @@ EmailSignUpPage.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(EmailSignUpPage);
|
||||
export default injectIntl(EmailSignUpPage);
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function UserListRow({user, actions}) {
|
||||
>
|
||||
<img
|
||||
className='profile-img'
|
||||
src={`/api/v1/users/${user.id}/image?time=${user.update_at}&${Utils.getSessionIndex()}`}
|
||||
src={`/api/v1/users/${user.id}/image?time=${user.update_at}`}
|
||||
/>
|
||||
<div
|
||||
className='user-list-item__details'
|
||||
|
||||
@@ -26,22 +26,27 @@ export default class UserProfile extends React.Component {
|
||||
}
|
||||
}
|
||||
render() {
|
||||
var name = Utils.displayUsername(this.props.user.id);
|
||||
let name = '...';
|
||||
let email = '';
|
||||
let profileImg = '';
|
||||
if (this.props.user) {
|
||||
name = Utils.displayUsername(this.props.user.id);
|
||||
email = this.props.user.email;
|
||||
profileImg = '/api/v1/users/' + this.props.user.id + '/image?time=' + this.props.user.update_at;
|
||||
}
|
||||
|
||||
if (this.props.overwriteName) {
|
||||
name = this.props.overwriteName;
|
||||
} else if (!name) {
|
||||
name = '...';
|
||||
}
|
||||
|
||||
if (this.props.overwriteImage) {
|
||||
profileImg = this.props.overwriteImage;
|
||||
}
|
||||
|
||||
if (this.props.disablePopover) {
|
||||
return <div>{name}</div>;
|
||||
}
|
||||
|
||||
var profileImg = '/api/v1/users/' + this.props.user.id + '/image?time=' + this.props.user.update_at + '&' + Utils.getSessionIndex();
|
||||
if (this.props.overwriteImage) {
|
||||
profileImg = this.props.overwriteImage;
|
||||
}
|
||||
|
||||
var dataContent = [];
|
||||
dataContent.push(
|
||||
<img
|
||||
@@ -69,14 +74,14 @@ export default class UserProfile extends React.Component {
|
||||
dataContent.push(
|
||||
<div
|
||||
data-toggle='tooltip'
|
||||
title={this.props.user.email}
|
||||
title={email}
|
||||
key='user-popover-email'
|
||||
>
|
||||
<a
|
||||
href={'mailto:' + this.props.user.email}
|
||||
href={'mailto:' + email}
|
||||
className='text-nowrap text-lowercase user-popover__email'
|
||||
>
|
||||
{this.props.user.email}
|
||||
{email}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
@@ -114,7 +119,7 @@ UserProfile.defaultProps = {
|
||||
disablePopover: false
|
||||
};
|
||||
UserProfile.propTypes = {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
user: React.PropTypes.object,
|
||||
overwriteName: React.PropTypes.string,
|
||||
overwriteImage: React.PropTypes.string,
|
||||
disablePopover: React.PropTypes.bool
|
||||
|
||||
@@ -5,6 +5,7 @@ import SettingItemMax from '../setting_item_max.jsx';
|
||||
|
||||
import * as Client from '../../utils/client.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import * as GlobalActions from '../../action_creators/global_actions.jsx';
|
||||
|
||||
import {FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -41,7 +42,7 @@ export default class ManageLanguage extends React.Component {
|
||||
submitUser(user) {
|
||||
Client.updateUser(user,
|
||||
() => {
|
||||
window.location.reload(true);
|
||||
GlobalActions.newLocalizationSelected(user.locale);
|
||||
},
|
||||
(err) => {
|
||||
let serverError;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import SettingItemMin from '../setting_item_min.jsx';
|
||||
import SettingItemMax from '../setting_item_max.jsx';
|
||||
import * as EventHelpers from '../../dispatcher/event_helpers.jsx';
|
||||
import * as GlobalActions from '../../action_creators/global_actions.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
|
||||
@@ -28,7 +28,7 @@ class DeveloperTab extends React.Component {
|
||||
}
|
||||
register() {
|
||||
this.props.closeModal();
|
||||
EventHelpers.showRegisterAppModal();
|
||||
GlobalActions.showRegisterAppModal();
|
||||
}
|
||||
render() {
|
||||
var appSection;
|
||||
|
||||
@@ -13,7 +13,7 @@ import Constants from '../../utils/constants.jsx';
|
||||
import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedDate} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
usernameReserved: {
|
||||
@@ -712,7 +712,7 @@ class UserSettingsGeneralTab extends React.Component {
|
||||
<SettingPicture
|
||||
title={formatMessage(holders.profilePicture)}
|
||||
submit={this.submitPicture}
|
||||
src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + Utils.getSessionIndex()}
|
||||
src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update}
|
||||
server_error={serverError}
|
||||
client_error={clientError}
|
||||
updateSection={(e) => {
|
||||
@@ -729,7 +729,14 @@ class UserSettingsGeneralTab extends React.Component {
|
||||
let minMessage = formatMessage(holders.uploadImage);
|
||||
if (user.last_picture_update) {
|
||||
minMessage = formatMessage(holders.imageUpdated, {
|
||||
date: new Date(user.last_picture_update).toLocaleDateString(global.window.mm_locale, {month: 'short', day: '2-digit', year: 'numeric'})
|
||||
date: (
|
||||
<FormattedDate
|
||||
value={new Date(user.last_picture_update)}
|
||||
day='2-digit'
|
||||
month='short'
|
||||
year='numeric'
|
||||
/>
|
||||
)
|
||||
});
|
||||
}
|
||||
pictureSection = (
|
||||
@@ -805,4 +812,4 @@ UserSettingsGeneralTab.propTypes = {
|
||||
collapseModal: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(UserSettingsGeneralTab);
|
||||
export default injectIntl(UserSettingsGeneralTab);
|
||||
|
||||
@@ -73,27 +73,35 @@ class UserSettingsModal extends React.Component {
|
||||
|
||||
this.updateTab = this.updateTab.bind(this);
|
||||
this.updateSection = this.updateSection.bind(this);
|
||||
this.onUserChanged = this.onUserChanged.bind(this);
|
||||
|
||||
this.state = {
|
||||
active_tab: 'general',
|
||||
active_section: '',
|
||||
showConfirmModal: false,
|
||||
enforceFocus: true
|
||||
enforceFocus: true,
|
||||
currentUser: UserStore.getCurrentUser()
|
||||
};
|
||||
|
||||
this.requireConfirm = false;
|
||||
}
|
||||
|
||||
onUserChanged() {
|
||||
this.setState({currentUser: UserStore.getCurrentUser()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.handleShow();
|
||||
}
|
||||
UserStore.addChangeListener(this.onUserChanged);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.show && !prevProps.show) {
|
||||
this.handleShow();
|
||||
}
|
||||
UserStore.removeChangeListener(this.onUserChanged);
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
@@ -235,8 +243,10 @@ class UserSettingsModal extends React.Component {
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
var isAdmin = Utils.isAdmin(currentUser.roles);
|
||||
if (this.state.currentUser == null) {
|
||||
return (<div/>);
|
||||
}
|
||||
var isAdmin = Utils.isAdmin(this.state.currentUser.roles);
|
||||
var tabs = [];
|
||||
|
||||
tabs.push({name: 'general', uiName: formatMessage(holders.general), icon: 'glyphicon glyphicon-cog'});
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as AsyncClient from '../../utils/async_client.jsx';
|
||||
import * as Utils from '../../utils/utils.jsx';
|
||||
import Constants from '../../utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedTime, FormattedDate} from 'mm-intl';
|
||||
|
||||
const holders = defineMessages({
|
||||
currentPasswordError: {
|
||||
@@ -218,11 +218,24 @@ class SecurityTab extends React.Component {
|
||||
var describe;
|
||||
var d = new Date(this.props.user.last_password_update);
|
||||
|
||||
const locale = global.window.mm_locale;
|
||||
const hours12 = !Utils.isMilitaryTime();
|
||||
describe = formatMessage(holders.lastUpdated, {
|
||||
date: d.toLocaleDateString(locale, {month: 'short', day: '2-digit', year: 'numeric'}),
|
||||
time: d.toLocaleTimeString(locale, {hour12: hours12, hour: '2-digit', minute: '2-digit'})
|
||||
date: (
|
||||
<FormattedDate
|
||||
value={d}
|
||||
day='2-digit'
|
||||
month='short'
|
||||
year='numeric'
|
||||
/>
|
||||
),
|
||||
time: (
|
||||
<FormattedTime
|
||||
value={d}
|
||||
hour12={hours12}
|
||||
hour='2-digit'
|
||||
minute='2-digit'
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
updateSectionStatus = function updateSection() {
|
||||
@@ -251,7 +264,7 @@ class SecurityTab extends React.Component {
|
||||
<div>
|
||||
<a
|
||||
className='btn btn-primary'
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email)}
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='user.settings.security.switchEmail'
|
||||
@@ -269,7 +282,7 @@ class SecurityTab extends React.Component {
|
||||
<div>
|
||||
<a
|
||||
className='btn btn-primary'
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email) + '&new_type=' + Constants.GITLAB_SERVICE}
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='user.settings.security.switchGitlab'
|
||||
@@ -287,7 +300,7 @@ class SecurityTab extends React.Component {
|
||||
<div>
|
||||
<a
|
||||
className='btn btn-primary'
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email) + '&new_type=' + Constants.GOOGLE_SERVICE}
|
||||
href={'/' + teamName + '/claim?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GOOGLE_SERVICE}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='user.settings.security.switchGoogle'
|
||||
@@ -456,4 +469,4 @@ SecurityTab.propTypes = {
|
||||
setEnforceFocus: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(SecurityTab);
|
||||
export default injectIntl(SecurityTab);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"marked": "mattermost/marked#cb85e5cc81bc7937dbb73c3c53d9532b1b97e3ca",
|
||||
"mm-intl": "mattermost/mm-intl#805442fd474fa40cd586ddeda404dbbe8e60626d",
|
||||
"object-assign": "4.0.1",
|
||||
"react": "0.14.3",
|
||||
"react-router": "2.0.0",
|
||||
"twemoji": "1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ErrorBar from '../components/error_bar.jsx';
|
||||
import SelectTeamModal from '../components/admin_console/select_team_modal.jsx';
|
||||
import AdminController from '../components/admin_console/admin_controller.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<AdminController
|
||||
tab={this.props.map.ActiveTab}
|
||||
teamId={this.props.map.TeamId}
|
||||
/>
|
||||
<SelectTeamModal/>
|
||||
</div>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_admin_console_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('admin_controller')
|
||||
);
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ChannelView from '../components/channel_view.jsx';
|
||||
import ChannelLoader from '../components/channel_loader.jsx';
|
||||
import ErrorBar from '../components/error_bar.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
import GetPostLinkModal from '../components/get_post_link_modal.jsx';
|
||||
import GetTeamInviteLinkModal from '../components/get_team_invite_link_modal.jsx';
|
||||
import EditPostModal from '../components/edit_post_modal.jsx';
|
||||
import DeletePostModal from '../components/delete_post_modal.jsx';
|
||||
import MoreChannelsModal from '../components/more_channels.jsx';
|
||||
import TeamSettingsModal from '../components/team_settings_modal.jsx';
|
||||
import RemovedFromChannelModal from '../components/removed_from_channel_modal.jsx';
|
||||
import RegisterAppModal from '../components/register_app_modal.jsx';
|
||||
import ImportThemeModal from '../components/user_settings/import_theme_modal.jsx';
|
||||
import InviteMemberModal from '../components/invite_member_modal.jsx';
|
||||
|
||||
import * as EventHelpers from '../dispatcher/event_helpers.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<div className='channel-view'>
|
||||
<ChannelLoader/>
|
||||
<ErrorBar/>
|
||||
<ChannelView/>
|
||||
<GetPostLinkModal/>
|
||||
<GetTeamInviteLinkModal/>
|
||||
<InviteMemberModal/>
|
||||
<ImportThemeModal/>
|
||||
<TeamSettingsModal/>
|
||||
<MoreChannelsModal/>
|
||||
<EditPostModal/>
|
||||
<DeletePostModal/>
|
||||
<RemovedFromChannelModal/>
|
||||
<RegisterAppModal/>
|
||||
</div>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_channel_page = function setup(props, team, channel) {
|
||||
if (props.PostId === '') {
|
||||
EventHelpers.emitChannelClickEvent(channel);
|
||||
} else {
|
||||
EventHelpers.emitPostFocusEvent(props.PostId);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('channel_view')
|
||||
);
|
||||
};
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ClaimAccount from '../components/claim/claim_account.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<ClaimAccount
|
||||
email={this.props.map.Email}
|
||||
currentType={this.props.map.CurrentType}
|
||||
newType={this.props.map.NewType}
|
||||
teamName={this.props.map.TeamName}
|
||||
teamDisplayName={this.props.map.TeamDisplayName}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_claim_account_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('claim')
|
||||
);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import Docs from '../components/docs.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<Docs site={this.props.map.Site}/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.mm_user = global.window.mm_user || {};
|
||||
|
||||
global.window.setup_documentation_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('docs')
|
||||
);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import FindTeam from '../components/find_team.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<FindTeam/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_find_team_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('find-team')
|
||||
);
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import TeamStore from '../stores/team_store.jsx';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
|
||||
function setupHomePage() {
|
||||
var last = null;
|
||||
if (last == null || last.length === 0) {
|
||||
window.location = TeamStore.getCurrentTeamUrl() + '/channels/' + Constants.DEFAULT_CHANNEL;
|
||||
} else {
|
||||
window.location = TeamStore.getCurrentTeamUrl() + '/channels/' + last;
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_home_page = setupHomePage;
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import Login from '../components/login.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<Login
|
||||
teamDisplayName={this.props.map.TeamDisplayName}
|
||||
teamName={this.props.map.TeamName}
|
||||
inviteId={this.props.map.InviteId}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_login_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('login')
|
||||
);
|
||||
};
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import PasswordReset from '../components/password_reset.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<PasswordReset
|
||||
isReset={this.props.map.IsReset}
|
||||
teamDisplayName={this.props.map.TeamDisplayName}
|
||||
teamName={this.props.map.TeamName}
|
||||
hash={this.props.map.Hash}
|
||||
data={this.props.map.Data}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_password_reset_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('reset')
|
||||
);
|
||||
};
|
||||
290
web/react/pages/root.jsx
Обычный файл
290
web/react/pages/root.jsx
Обычный файл
@@ -0,0 +1,290 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
|
||||
import Root from '../components/root.jsx';
|
||||
import Login from '../components/login.jsx';
|
||||
import LoggedIn from '../components/logged_in.jsx';
|
||||
import NotLoggedIn from '../components/not_logged_in.jsx';
|
||||
import NeedsTeam from '../components/needs_team.jsx';
|
||||
import PasswordResetSendLink from '../components/password_reset_send_link.jsx';
|
||||
import PasswordResetForm from '../components/password_reset_form.jsx';
|
||||
import ChannelView from '../components/channel_view.jsx';
|
||||
import Sidebar from '../components/sidebar.jsx';
|
||||
import * as AsyncClient from '../utils/async_client.jsx';
|
||||
import PreferenceStore from '../stores/preference_store.jsx';
|
||||
import ChannelStore from '../stores/channel_store.jsx';
|
||||
import ErrorStore from '../stores/error_store.jsx';
|
||||
import BrowserStore from '../stores/browser_store.jsx';
|
||||
import SignupTeam from '../components/signup_team.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
import * as GlobalActions from '../action_creators/global_actions.jsx';
|
||||
import SignupTeamConfirm from '../components/signup_team_confirm.jsx';
|
||||
import SignupUserComplete from '../components/signup_user_complete.jsx';
|
||||
import ShouldVerifyEmail from '../components/should_verify_email.jsx';
|
||||
import DoVerifyEmail from '../components/do_verify_email.jsx';
|
||||
import AdminConsole from '../components/admin_console/admin_controller.jsx';
|
||||
import ClaimAccount from '../components/claim/claim_account.jsx';
|
||||
|
||||
import SignupTeamComplete from '../components/signup_team_complete/components/signup_team_complete.jsx';
|
||||
import WelcomePage from '../components/signup_team_complete/components/team_signup_welcome_page.jsx';
|
||||
import TeamDisplayNamePage from '../components/signup_team_complete/components/team_signup_display_name_page.jsx';
|
||||
import TeamURLPage from '../components/signup_team_complete/components/team_signup_url_page.jsx';
|
||||
import SendInivtesPage from '../components/signup_team_complete/components/team_signup_send_invites_page.jsx';
|
||||
import UsernamePage from '../components/signup_team_complete/components/team_signup_username_page.jsx';
|
||||
import PasswordPage from '../components/signup_team_complete/components/team_signup_password_page.jsx';
|
||||
import FinishedPage from '../components/signup_team_complete/components/team_signup_finished.jsx';
|
||||
|
||||
// This is for anything that needs to be done for ALL react components.
|
||||
// This runs before we start to render anything.
|
||||
function preRenderSetup(callwhendone) {
|
||||
const d1 = Client.getClientConfig(
|
||||
(data, textStatus, xhr) => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
global.window.mm_config = data;
|
||||
|
||||
var serverVersion = xhr.getResponseHeader('X-Version-ID');
|
||||
|
||||
if (serverVersion !== BrowserStore.getLastServerVersion()) {
|
||||
if (!BrowserStore.getLastServerVersion() || BrowserStore.getLastServerVersion() === '') {
|
||||
BrowserStore.setLastServerVersion(serverVersion);
|
||||
} else {
|
||||
BrowserStore.setLastServerVersion(serverVersion);
|
||||
window.location.reload(true);
|
||||
console.log('Detected version update refreshing the page'); //eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getClientConfig');
|
||||
}
|
||||
);
|
||||
|
||||
const d2 = Client.getClientLicenceConfig(
|
||||
(data) => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
global.window.mm_license = data;
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getClientLicenceConfig');
|
||||
}
|
||||
);
|
||||
|
||||
// Set these here so they don't fail in client.jsx track
|
||||
global.window.analytics = {};
|
||||
global.window.analytics.page = () => {
|
||||
// Do Nothing
|
||||
};
|
||||
global.window.analytics.track = () => {
|
||||
// Do Nothing
|
||||
};
|
||||
|
||||
$.when(d1, d2).done(callwhendone);
|
||||
}
|
||||
|
||||
function preLoggedIn(nextState, replace, callback) {
|
||||
const d1 = Client.getAllPreferences(
|
||||
(data) => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
PreferenceStore.setPreferences(data);
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getAllPreferences');
|
||||
}
|
||||
);
|
||||
|
||||
const d2 = AsyncClient.getChannels();
|
||||
|
||||
$.when(d1, d2).done(() => callback());
|
||||
}
|
||||
|
||||
function onChannelChange(nextState) {
|
||||
const channelName = nextState.params.channel;
|
||||
|
||||
// Make sure we have all the channels
|
||||
AsyncClient.getChannels(true);
|
||||
|
||||
// Get our channel's ID
|
||||
const channel = ChannelStore.getByName(channelName);
|
||||
|
||||
// User clicked channel
|
||||
GlobalActions.emitChannelClickEvent(channel);
|
||||
}
|
||||
|
||||
function onRootEnter(nextState, replace, callback) {
|
||||
if (nextState.location.pathname === '/') {
|
||||
Client.getMeLoggedIn((data) => {
|
||||
if (!data || data.logged_in === 'false') {
|
||||
replace({pathname: '/signup_team'});
|
||||
callback();
|
||||
} else {
|
||||
replace({pathname: '/' + data.team_name + '/channels/town-square'});
|
||||
callback();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
|
||||
function onPermalinkEnter(nextState) {
|
||||
const postId = nextState.params.postid;
|
||||
|
||||
GlobalActions.emitPostFocusEvent(postId);
|
||||
}
|
||||
|
||||
function onLoggedOut(nextState) {
|
||||
const teamName = nextState.params.team;
|
||||
Client.logout(
|
||||
() => {
|
||||
browserHistory.push('/' + teamName + '/login');
|
||||
BrowserStore.signalLogout();
|
||||
BrowserStore.clear();
|
||||
ErrorStore.clearLastError();
|
||||
},
|
||||
() => {
|
||||
browserHistory.push('/' + teamName + '/login');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function renderRootComponent() {
|
||||
ReactDOM.render((
|
||||
<Router
|
||||
history={browserHistory}
|
||||
>
|
||||
<Route
|
||||
path='/'
|
||||
component={Root}
|
||||
onEnter={onRootEnter}
|
||||
>
|
||||
<Route
|
||||
component={LoggedIn}
|
||||
onEnter={preLoggedIn}
|
||||
>
|
||||
<Route
|
||||
path=':team/channels/:channel'
|
||||
onEnter={onChannelChange}
|
||||
components={{
|
||||
sidebar: Sidebar,
|
||||
center: ChannelView
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path=':team/pl/:postid'
|
||||
onEnter={onPermalinkEnter}
|
||||
components={{
|
||||
sidebar: Sidebar,
|
||||
center: ChannelView
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path=':team/logout'
|
||||
onEnter={onLoggedOut}
|
||||
components={{
|
||||
sidebar: null,
|
||||
center: null
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path='admin_console'
|
||||
components={{
|
||||
sidebar: null,
|
||||
center: AdminConsole
|
||||
}}
|
||||
/>
|
||||
</Route>
|
||||
<Route component={NotLoggedIn}>
|
||||
<Route
|
||||
path='signup_team'
|
||||
component={SignupTeam}
|
||||
/>
|
||||
<Route
|
||||
path='signup_team_complete'
|
||||
component={SignupTeamComplete}
|
||||
>
|
||||
<IndexRoute component={FinishedPage}/>
|
||||
<Route
|
||||
path='welcome'
|
||||
component={WelcomePage}
|
||||
/>
|
||||
<Route
|
||||
path='team_display_name'
|
||||
component={TeamDisplayNamePage}
|
||||
/>
|
||||
<Route
|
||||
path='team_url'
|
||||
component={TeamURLPage}
|
||||
/>
|
||||
<Route
|
||||
path='invites'
|
||||
component={SendInivtesPage}
|
||||
/>
|
||||
<Route
|
||||
path='username'
|
||||
component={UsernamePage}
|
||||
/>
|
||||
<Route
|
||||
path='password'
|
||||
component={PasswordPage}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path='signup_user_complete'
|
||||
component={SignupUserComplete}
|
||||
/>
|
||||
<Route
|
||||
path='signup_team_confirm'
|
||||
component={SignupTeamConfirm}
|
||||
/>
|
||||
<Route
|
||||
path='should_verify_email'
|
||||
component={ShouldVerifyEmail}
|
||||
/>
|
||||
<Route
|
||||
path='do_verify_email'
|
||||
component={DoVerifyEmail}
|
||||
/>
|
||||
<Route
|
||||
path=':team'
|
||||
component={NeedsTeam}
|
||||
>
|
||||
<IndexRedirect to='login'/>
|
||||
<Route
|
||||
path='login'
|
||||
component={Login}
|
||||
/>
|
||||
<Route
|
||||
path='claim'
|
||||
component={ClaimAccount}
|
||||
/>
|
||||
<Route
|
||||
path='reset_password'
|
||||
component={PasswordResetSendLink}
|
||||
/>
|
||||
<Route
|
||||
path='reset_password_complete'
|
||||
component={PasswordResetForm}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
</Router>
|
||||
),
|
||||
document.getElementById('root'));
|
||||
}
|
||||
|
||||
global.window.setup_root = () => {
|
||||
// Do the pre-render setup and call renderRootComponent when done
|
||||
preRenderSetup(renderRootComponent);
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import SignupTeam from '../components/signup_team.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired,
|
||||
teams: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<SignupTeam teams={this.props.teams}/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_signup_team_page = function setup(props) {
|
||||
var teams = [];
|
||||
|
||||
for (var prop in props) {
|
||||
if (props.hasOwnProperty(prop)) {
|
||||
if (prop !== 'Title' && prop !== 'Locale' && prop !== 'Info') {
|
||||
teams.push({name: prop, display_name: props[prop]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Root
|
||||
map={props}
|
||||
teams={teams}
|
||||
/>,
|
||||
document.getElementById('signup-team')
|
||||
);
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import SignupTeamComplete from '../components/signup_team_complete.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<SignupTeamComplete
|
||||
email={this.props.map.Email}
|
||||
hash={this.props.map.Hash}
|
||||
data={this.props.map.Data}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_signup_team_complete_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('signup-team-complete')
|
||||
);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import SignupTeamConfirm from '../components/signup_team_confirm.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<SignupTeamConfirm
|
||||
email={this.props.map.Email}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_signup_team_confirm_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('signup-team-confirm')
|
||||
);
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import SignupUserComplete from '../components/signup_user_complete.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<SignupUserComplete
|
||||
teamId={this.props.map.TeamId}
|
||||
teamName={this.props.map.TeamName}
|
||||
teamDisplayName={this.props.map.TeamDisplayName}
|
||||
email={this.props.map.Email}
|
||||
hash={this.props.map.Hash}
|
||||
data={this.props.map.Data}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setup_signup_user_complete_page = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('signup-user-complete')
|
||||
);
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import EmailVerify from '../components/email_verify.jsx';
|
||||
import * as Client from '../utils/client.jsx';
|
||||
|
||||
var IntlProvider = ReactIntl.IntlProvider;
|
||||
|
||||
class Root extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
translations: null,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes() {
|
||||
return {
|
||||
map: React.PropTypes.object.isRequired
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Client.getTranslations(
|
||||
this.props.map.Locale,
|
||||
(data) => {
|
||||
this.setState({
|
||||
translations: data,
|
||||
loaded: true
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loaded: true
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<IntlProvider
|
||||
locale={this.props.map.Locale}
|
||||
messages={this.state.translations}
|
||||
>
|
||||
<EmailVerify
|
||||
isVerified={this.props.map.IsVerified}
|
||||
teamURL={this.props.map.TeamURL}
|
||||
userEmail={this.props.map.UserEmail}
|
||||
resendSuccess={this.props.map.ResendSuccess}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global.window.setupVerifyPage = function setup(props) {
|
||||
ReactDOM.render(
|
||||
<Root map={props}/>,
|
||||
document.getElementById('verify')
|
||||
);
|
||||
};
|
||||
@@ -121,7 +121,11 @@ class AdminStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
getSelectedTeams() {
|
||||
return BrowserStore.getItem('seleted_teams');
|
||||
const result = BrowserStore.getItem('seleted_teams');
|
||||
if (!result) {
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
saveSelectedTeams(teams) {
|
||||
@@ -156,7 +160,3 @@ AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => {
|
||||
});
|
||||
|
||||
export default AdminStore;
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.AdminStore = AdminStore;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,3 @@ AnalyticsStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
});
|
||||
|
||||
export default AnalyticsStore;
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.AnalyticsStore = AnalyticsStore;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import {generateId} from '../utils/utils.jsx';
|
||||
|
||||
function getPrefix() {
|
||||
if (global.window.mm_user) {
|
||||
return global.window.mm_user.id + '_';
|
||||
if (global.window.mm_current_user_id) {
|
||||
return global.window.mm_current_user_id + '_';
|
||||
}
|
||||
|
||||
return 'unknown_';
|
||||
@@ -31,7 +31,9 @@ class BrowserStoreClass {
|
||||
this.isSignallingLogout = this.isSignallingLogout.bind(this);
|
||||
this.signalLogin = this.signalLogin.bind(this);
|
||||
this.isSignallingLogin = this.isSignallingLogin.bind(this);
|
||||
}
|
||||
|
||||
checkVersion() {
|
||||
var currentVersion = sessionStorage.getItem('storage_version');
|
||||
if (currentVersion !== global.window.mm_config.Version) {
|
||||
sessionStorage.clear();
|
||||
|
||||
@@ -350,7 +350,3 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
});
|
||||
|
||||
export default ChannelStore;
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.ChannelStore = ChannelStore;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,4 @@ class FileStore extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new FileStore();
|
||||
export default instance;
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.FileStore = instance;
|
||||
}
|
||||
export default new FileStore();
|
||||
|
||||
60
web/react/stores/localization_store.jsx
Обычный файл
60
web/react/stores/localization_store.jsx
Обычный файл
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
import Constants from '../utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
class LocalizationStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.currentLocale = 'en';
|
||||
this.currentTranslations = null;
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
setCurrentLocale(locale, translations) {
|
||||
this.currentLocale = locale;
|
||||
this.currentTranslations = translations;
|
||||
}
|
||||
|
||||
getLocale() {
|
||||
return this.currentLocale;
|
||||
}
|
||||
|
||||
getTranslations() {
|
||||
return this.currentTranslations;
|
||||
}
|
||||
}
|
||||
|
||||
var LocalizationStore = new LocalizationStoreClass();
|
||||
LocalizationStore.setMaxListeners(0);
|
||||
|
||||
LocalizationStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_LOCALE:
|
||||
LocalizationStore.setCurrentLocale(action.locale, action.translations);
|
||||
LocalizationStore.emitChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default LocalizationStore;
|
||||
@@ -45,7 +45,3 @@ class ModalStoreClass extends EventEmitter {
|
||||
|
||||
const ModalStore = new ModalStoreClass();
|
||||
export default ModalStore;
|
||||
|
||||
if (window.mm_config.EnableDeveloper === 'true') {
|
||||
window.ModalStore = ModalStore;
|
||||
}
|
||||
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user