diff options
author | Joram Wilander <jwawilander@gmail.com> | 2017-04-25 11:46:02 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2017-04-25 11:46:02 -0400 |
commit | 6c4c706313eb765eb00c639f381646be74f27b69 (patch) | |
tree | 6068feaa9668dcd74601730ac1a5abfb366402b1 /webapp/components/activity_log_modal | |
parent | cc07c005074348de87854f1c953a549e8772fa03 (diff) | |
download | chat-6c4c706313eb765eb00c639f381646be74f27b69.tar.gz chat-6c4c706313eb765eb00c639f381646be74f27b69.tar.bz2 chat-6c4c706313eb765eb00c639f381646be74f27b69.zip |
Start moving webapp to Redux (#6140)
* Start moving webapp to Redux
* Fix localforage import
* Updates per feedback
* Feedback udpates and a few fixes
* Minor updates
* Fix statuses, config not loading properly, getMe sanitizing too much
* Fix preferences
* Fix user autocomplete
* Fix sessions and audits
* Fix error handling for all redux actions
* Use new directory structure for components and containers
* Refresh immediately on logout instead of after timeout
* Add fetch polyfill
Diffstat (limited to 'webapp/components/activity_log_modal')
-rw-r--r-- | webapp/components/activity_log_modal/activity_log_modal.jsx | 301 | ||||
-rw-r--r-- | webapp/components/activity_log_modal/index.js | 25 |
2 files changed, 326 insertions, 0 deletions
diff --git a/webapp/components/activity_log_modal/activity_log_modal.jsx b/webapp/components/activity_log_modal/activity_log_modal.jsx new file mode 100644 index 000000000..c94909754 --- /dev/null +++ b/webapp/components/activity_log_modal/activity_log_modal.jsx @@ -0,0 +1,301 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import LoadingScreen from 'components/loading_screen.jsx'; + +import UserStore from 'stores/user_store.jsx'; + +import * as Utils from 'utils/utils.jsx'; + +import $ from 'jquery'; +import React from 'react'; +import {Modal} from 'react-bootstrap'; +import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl'; + +export default class ActivityLogModal extends React.Component { + static propTypes = { + onHide: React.PropTypes.func.isRequired, + actions: React.PropTypes.shape({ + getSessions: React.PropTypes.func.isRequired, + revokeSession: React.PropTypes.func.isRequired + }).isRequired + } + + constructor(props) { + super(props); + + this.submitRevoke = this.submitRevoke.bind(this); + this.onListenerChange = this.onListenerChange.bind(this); + this.handleMoreInfo = this.handleMoreInfo.bind(this); + this.onHide = this.onHide.bind(this); + this.onShow = this.onShow.bind(this); + + const state = this.getStateFromStores(); + state.moreInfo = []; + state.show = true; + + this.state = state; + } + + getStateFromStores() { + return { + sessions: UserStore.getSessions(), + clientError: null + }; + } + + submitRevoke(altId, e) { + e.preventDefault(); + var modalContent = $(e.target).closest('.modal-content'); + modalContent.addClass('animation--highlight'); + setTimeout(() => { + modalContent.removeClass('animation--highlight'); + }, 1500); + this.props.actions.revokeSession(UserStore.getCurrentId(), altId); + } + + onShow() { + this.props.actions.getSessions(UserStore.getCurrentId()); + if (!Utils.isMobile()) { + $('.modal-body').perfectScrollbar(); + } + } + + onHide() { + this.setState({show: false}); + } + + componentDidMount() { + UserStore.addSessionsChangeListener(this.onListenerChange); + this.onShow(); + } + + componentWillUnmount() { + UserStore.removeSessionsChangeListener(this.onListenerChange); + } + + onListenerChange() { + const newState = this.getStateFromStores(); + if (!Utils.areObjectsEqual(newState.sessions, this.state.sessions)) { + this.setState(newState); + } + } + + handleMoreInfo(index) { + const newMoreInfo = this.state.moreInfo; + newMoreInfo[index] = true; + this.setState({moreInfo: newMoreInfo}); + } + + render() { + const activityList = []; + + for (let i = 0; i < this.state.sessions.length; i++) { + const currentSession = this.state.sessions[i]; + const lastAccessTime = new Date(currentSession.last_activity_at); + const firstAccessTime = new Date(currentSession.create_at); + let devicePlatform = currentSession.props.platform; + let devicePicture = ''; + + if (currentSession.props.platform === 'Windows') { + devicePicture = 'fa fa-windows'; + } else if (currentSession.device_id && currentSession.device_id.indexOf('apple') === 0) { + devicePicture = 'fa fa-apple'; + devicePlatform = ( + <FormattedMessage + id='activity_log_modal.iphoneNativeApp' + defaultMessage='iPhone Native App' + /> + ); + } else if (currentSession.device_id && currentSession.device_id.indexOf('android') === 0) { + devicePlatform = ( + <FormattedMessage + id='activity_log_modal.androidNativeApp' + defaultMessage='Android Native App' + /> + ); + devicePicture = 'fa fa-android'; + } else if (currentSession.props.platform === 'Macintosh' || + currentSession.props.platform === 'iPhone') { + devicePicture = 'fa fa-apple'; + } else if (currentSession.props.platform === 'Linux') { + if (currentSession.props.os.indexOf('Android') >= 0) { + devicePlatform = ( + <FormattedMessage + id='activity_log_modal.android' + defaultMessage='Android' + /> + ); + devicePicture = 'fa fa-android'; + } else { + devicePicture = 'fa fa-linux'; + } + } else if (currentSession.props.os.indexOf('Linux') !== -1) { + devicePicture = 'fa fa-linux'; + } + + if (currentSession.props.browser.indexOf('Desktop App') !== -1) { + devicePlatform = ( + <FormattedMessage + id='activity_log_modal.desktop' + defaultMessage='Native Desktop App' + /> + ); + } + + let moreInfo; + if (this.state.moreInfo[i]) { + moreInfo = ( + <div> + <div> + <FormattedMessage + id='activity_log.firstTime' + defaultMessage='First time active: {date}, {time}' + values={{ + date: ( + <FormattedDate + value={firstAccessTime} + day='2-digit' + month='long' + year='numeric' + /> + ), + time: ( + <FormattedTime + value={firstAccessTime} + hour='2-digit' + minute='2-digit' + /> + ) + }} + /> + </div> + <div> + <FormattedMessage + id='activity_log.os' + defaultMessage='OS: {os}' + values={{ + os: currentSession.props.os + }} + /> + </div> + <div> + <FormattedMessage + id='activity_log.browser' + defaultMessage='Browser: {browser}' + values={{ + browser: currentSession.props.browser + }} + /> + </div> + <div> + <FormattedMessage + id='activity_log.sessionId' + defaultMessage='Session ID: {id}' + values={{ + id: currentSession.id + }} + /> + </div> + </div> + ); + } else { + moreInfo = ( + <a + className='theme' + href='#' + onClick={this.handleMoreInfo.bind(this, i)} + > + <FormattedMessage + id='activity_log.moreInfo' + defaultMessage='More info' + /> + </a> + ); + } + + activityList[i] = ( + <div + key={'activityLogEntryKey' + i} + className='activity-log__table' + > + <div className='activity-log__report'> + <div className='report__platform'><i className={devicePicture}/>{devicePlatform}</div> + <div className='report__info'> + <div> + <FormattedMessage + id='activity_log.lastActivity' + defaultMessage='Last activity: {date}, {time}' + values={{ + date: ( + <FormattedDate + value={lastAccessTime} + day='2-digit' + month='long' + year='numeric' + /> + ), + time: ( + <FormattedTime + value={lastAccessTime} + hour='2-digit' + minute='2-digit' + /> + ) + }} + /> + </div> + {moreInfo} + </div> + </div> + <div className='activity-log__action'> + <button + onClick={this.submitRevoke.bind(this, currentSession.id)} + className='btn btn-primary' + > + <FormattedMessage + id='activity_log.logout' + defaultMessage='Logout' + /> + </button> + </div> + </div> + ); + } + + let content; + if (this.state.sessions.loading) { + content = <LoadingScreen/>; + } else { + content = <form role='form'>{activityList}</form>; + } + + return ( + <Modal + dialogClassName='modal--scroll' + show={this.state.show} + onHide={this.onHide} + onExited={this.props.onHide} + bsSize='large' + > + <Modal.Header closeButton={true}> + <Modal.Title> + <FormattedMessage + id='activity_log.activeSessions' + defaultMessage='Active Sessions' + /> + </Modal.Title> + </Modal.Header> + <Modal.Body ref='modalBody'> + <p className='session-help-text'> + <FormattedMessage + id='activity_log.sessionsDescription' + defaultMessage="Sessions are created when you log in to a new browser on a device. Sessions let you use Mattermost without having to log in again for a time period specified by the System Admin. If you want to log out sooner, use the 'Logout' button below to end a session." + /> + </p> + {content} + </Modal.Body> + </Modal> + ); + } +} diff --git a/webapp/components/activity_log_modal/index.js b/webapp/components/activity_log_modal/index.js new file mode 100644 index 000000000..1c4890c65 --- /dev/null +++ b/webapp/components/activity_log_modal/index.js @@ -0,0 +1,25 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import {revokeSession, getSessions} from 'mattermost-redux/actions/users'; + +import ActivityLogModal from './activity_log_modal.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + getSessions, + revokeSession + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(ActivityLogModal); |