Skip to content

Commit

Permalink
MM-9787: Transition [lr]hs open state to redux, fixing Safari race co…
Browse files Browse the repository at this point in the history
…ndition. (mattermost#991)

* move the [lr]hs open state into redux

This eliminates race conditions around toggling classes all over the
code base in an attempt to slide the various components around. It also
has the nice side effect of getting rid of doStrangeThings.

WebRTC remains in beta, and remains functional with these changes, but
the absolute minimum set of changes were made to integrate the old flux
store with the new state. This remains intentionally hacky, as the
medium-term vision is to rip this feature out and replace it as a
plugin.

* fix a rendering issue with PermalinkView

Now that opening the sidebar triggers a re-render (vs. just toggling
classes), the PermalinkView would incorrectly transition between valid
and invalid internal states even if the target permalink hadn't changed.
This resulted in a flashing when opening the sidebar, e.g. to view
flagged messages. This restricts the handling of a permalink event to
when the post id has actually changed.

* remove unused initTeamChangeActions in lhs actions
  • Loading branch information
lieut-data committed Mar 27, 2018
1 parent 0f5d6e5 commit c3b1c2f
Show file tree
Hide file tree
Showing 54 changed files with 1,260 additions and 610 deletions.
9 changes: 4 additions & 5 deletions actions/global_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import {loadChannelsForCurrentUser} from 'actions/channel_actions.jsx';
import {handleNewPost} from 'actions/post_actions.jsx';
import {stopPeriodicStatusUpdates} from 'actions/status_actions.jsx';
import {loadNewDMIfNeeded, loadNewGMIfNeeded, loadProfilesForSidebar} from 'actions/user_actions.jsx';
import {closeRightHandSide} from 'actions/views/rhs';
import {closeRightHandSide, closeMenu as closeRhsMenu} from 'actions/views/rhs';
import {close as closeLhs} from 'actions/views/lhs';
import * as WebsocketActions from 'actions/websocket_actions.jsx';
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
import BrowserStore from 'stores/browser_store.jsx';
Expand Down Expand Up @@ -472,10 +473,8 @@ export function clientLogout(redirectTo = '/') {

export function toggleSideBarRightMenuAction() {
dispatch(closeRightHandSide());

document.querySelector('.app__body .inner-wrap').classList.remove('move--right', 'move--left', 'move--left-small');
document.querySelector('.app__body .sidebar--left').classList.remove('move--right');
document.querySelector('.app__body .sidebar--right').classList.remove('move--left');
dispatch(closeLhs());
dispatch(closeRhsMenu());
document.querySelector('.app__body .sidebar--menu').classList.remove('move--left');
}

Expand Down
23 changes: 12 additions & 11 deletions actions/views/lhs.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {fetchMyChannelsAndMembers} from 'mattermost-redux/actions/channels';
import {ActionTypes} from 'utils/constants.jsx';

import {loadProfilesForSidebar} from 'actions/user_actions.jsx';
import {loadStatusesForChannelAndSidebar} from 'actions/status_actions.jsx';
import store from 'stores/redux_store.jsx';
export const toggle = () => (dispatch) => dispatch({
type: ActionTypes.TOGGLE_LHS,
});

const dispatch = store.dispatch;
const getState = store.getState;
export const open = () => (dispatch) => dispatch({
type: ActionTypes.OPEN_LHS,
});

export async function initTeamChangeActions(teamId) {
await fetchMyChannelsAndMembers(teamId)(dispatch, getState);
loadStatusesForChannelAndSidebar();
loadProfilesForSidebar();
}
export const close = () => (dispatch) => dispatch({
type: ActionTypes.CLOSE_LHS,
});
12 changes: 12 additions & 0 deletions actions/views/rhs.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,15 @@ export function closeRightHandSide() {
]));
};
}

export const toggleMenu = () => (dispatch) => dispatch({
type: ActionTypes.TOGGLE_RHS_MENU,
});

export const openMenu = () => (dispatch) => dispatch({
type: ActionTypes.OPEN_RHS_MENU,
});

export const closeMenu = () => (dispatch) => dispatch({
type: ActionTypes.CLOSE_RHS_MENU,
});
14 changes: 14 additions & 0 deletions actions/views/webrtc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {ActionTypes} from 'utils/constants.jsx';

export const initWebrtc = (userId, isCaller) => (dispatch) => dispatch({
type: ActionTypes.INIT_WEBRTC,
userId,
isCaller,
});

export const closeWebrtc = () => (dispatch) => dispatch({
type: ActionTypes.CLOSE_WEBRTC,
});
13 changes: 11 additions & 2 deletions components/channel_layout/center_channel/center_channel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {Route, Switch, Redirect} from 'react-router-dom';
import classNames from 'classnames';

import PermalinkView from 'components/permalink_view';
import Navbar from 'components/navbar';
Expand All @@ -14,6 +15,10 @@ export default class CenterChannel extends React.PureComponent {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
lastChannelPath: PropTypes.string.isRequired,
lhsOpen: PropTypes.bool.isRequired,
rhsOpen: PropTypes.bool.isRequired,
rhsMenuOpen: PropTypes.bool.isRequired,
webRtcOpen: PropTypes.bool.isRequired,
};

constructor(props) {
Expand All @@ -34,9 +39,13 @@ export default class CenterChannel extends React.PureComponent {
const url = this.props.match.url;
return (
<div
id='inner-wrap-webrtc'
key='inner-wrap'
className='inner-wrap channel__wrap'
className={classNames('inner-wrap', 'channel__wrap', {
'webrtc--show': this.props.webRtcOpen,
'move--right': this.props.lhsOpen,
'move--left': this.props.rhsOpen || this.props.webRtcOpen,
'move--left-small': this.props.rhsMenuOpen,
})}
>
<div className='row header'>
<div id='navbar'>
Expand Down
7 changes: 7 additions & 0 deletions components/channel_layout/center_channel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {getTeamByName} from 'mattermost-redux/selectors/entities/teams';

import Constants from 'utils/constants';
import {getGlobalItem} from 'selectors/storage';
import {getIsRhsOpen, getIsRhsMenuOpen} from 'selectors/rhs';
import {getIsLhsOpen} from 'selectors/lhs';
import {getIsWebrtcOpen} from 'selectors/webrtc';

import CenterChannel from './center_channel';

Expand All @@ -20,6 +23,10 @@ const getLastChannelPath = (state, teamName) => {

const mapStateToProps = (state, ownProps) => ({
lastChannelPath: `${ownProps.match.url}/channels/${getLastChannelPath(state, ownProps.match.params.team)}`,
lhsOpen: getIsLhsOpen(state),
rhsOpen: getIsRhsOpen(state),
rhsMenuOpen: getIsRhsMenuOpen(state),
webRtcOpen: getIsWebrtcOpen(state),
});

export default connect(mapStateToProps)(CenterChannel);
4 changes: 2 additions & 2 deletions components/channel_layout/channel_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import SidebarRightMenu from 'components/sidebar_right_menu';
import TeamSettingsModal from 'components/team_settings_modal.jsx';
import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
import UserSettingsModal from 'components/user_settings/modal';
import WebrtcNotification from 'components/webrtc/webrtc_notification.jsx';
import WebrtcSidebar from 'components/webrtc/webrtc_sidebar.jsx';
import WebrtcNotification from 'components/webrtc/notification';
import WebrtcSidebar from 'components/webrtc/sidebar';
import ModalController from 'components/modal_controller';
import TeamSidebar from 'components/team_sidebar';
import Sidebar from 'components/sidebar';
Expand Down
2 changes: 1 addition & 1 deletion components/create_post/create_post.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import MsgTyping from 'components/msg_typing';
import PostDeletedModal from 'components/post_deleted_modal.jsx';
import EmojiIcon from 'components/svg/emoji_icon';
import Textbox from 'components/textbox.jsx';
import TutorialTip from 'components/tutorial/tutorial_tip.jsx';
import TutorialTip from 'components/tutorial/tutorial_tip';

const KeyCodes = Constants.KeyCodes;

Expand Down
15 changes: 13 additions & 2 deletions components/navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getConfig} from 'mattermost-redux/selectors/entities/general';

import {closeRightHandSide, updateRhsState, showPinnedPosts} from 'actions/views/rhs';
import {
closeRightHandSide as closeRhs,
updateRhsState,
showPinnedPosts,
toggleMenu as toggleRhsMenu,
closeMenu as closeRhsMenu,
} from 'actions/views/rhs';
import {toggle as toggleLhs, close as closeLhs} from 'actions/views/lhs';
import {getRhsState} from 'selectors/rhs';
import {RHSStates} from 'utils/constants.jsx';

Expand All @@ -26,9 +33,13 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
closeRightHandSide,
updateRhsState,
showPinnedPosts,
toggleLhs,
closeLhs,
closeRhs,
toggleRhsMenu,
closeRhsMenu,
}, dispatch),
};
}
Expand Down
23 changes: 11 additions & 12 deletions components/navbar/navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ export default class Navbar extends React.Component {
isPinnedPosts: PropTypes.bool,
enableWebrtc: PropTypes.bool.isRequired,
actions: PropTypes.shape({
closeRightHandSide: PropTypes.func,
updateRhsState: PropTypes.func,
showPinnedPosts: PropTypes.func,
toggleLhs: PropTypes.func.isRequired,
closeLhs: PropTypes.func.isRequired,
closeRhs: PropTypes.func.isRequired,
toggleRhsMenu: PropTypes.func.isRequired,
closeRhsMenu: PropTypes.func.isRequired,
}),
};

Expand Down Expand Up @@ -137,27 +141,22 @@ export default class Navbar extends React.Component {
hideSidebars = (e) => {
var windowWidth = $(window).outerWidth();
if (windowWidth <= 768) {
this.props.actions.closeRightHandSide();
this.props.actions.closeRhs();

if (e.target.className !== 'navbar-toggle' && e.target.className !== 'icon-bar') {
$('.app__body .inner-wrap').removeClass('move--right move--left move--left-small');
$('.app__body .sidebar--left').removeClass('move--right');
$('.multi-teams .team-sidebar').removeClass('move--right');
$('.app__body .sidebar--right').removeClass('move--left');
$('.app__body .sidebar--menu').removeClass('move--left');
this.props.actions.closeLhs();
this.props.actions.closeRhs();
this.props.actions.closeRhsMenu();
}
}
}

toggleLeftSidebar = () => {
$('.app__body .inner-wrap').toggleClass('move--right');
$('.app__body .sidebar--left').toggleClass('move--right');
$('.multi-teams .team-sidebar').toggleClass('move--right');
this.props.actions.toggleLhs();
}

toggleRightSidebar = () => {
$('.app__body .inner-wrap').toggleClass('move--left-small');
$('.app__body .sidebar--menu').toggleClass('move--left');
this.props.actions.toggleRhsMenu();
}

showSearch = () => {
Expand Down
4 changes: 3 additions & 1 deletion components/permalink_view/permalink_view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export default class PermalinkView extends React.PureComponent {
}

componentWillReceiveProps(nextProps) {
this.doPermalinkEvent(nextProps);
if (this.props.match.params.postid !== nextProps.match.params.postid) {
this.doPermalinkEvent(nextProps);
}
}

doPermalinkEvent = async (props) => {
Expand Down
2 changes: 2 additions & 0 deletions components/search_bar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
showFlaggedPosts,
closeRightHandSide,
} from 'actions/views/rhs';
import {closeWebrtc} from 'actions/views/webrtc';
import {getRhsState, getSearchTerms, getIsSearchingTerm} from 'selectors/rhs';
import {RHSStates} from 'utils/constants.jsx';

Expand All @@ -35,6 +36,7 @@ function mapDispatchToProps(dispatch) {
showMentions,
showFlaggedPosts,
closeRightHandSide,
closeWebrtc,
}, dispatch),
};
}
Expand Down
11 changes: 2 additions & 9 deletions components/search_bar/search_bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default class SearchBar extends React.Component {
showMentions: PropTypes.func,
showFlaggedPosts: PropTypes.func,
closeRightHandSide: PropTypes.func,
closeWebrtc: PropTypes.func,
}),
};

Expand Down Expand Up @@ -64,15 +65,7 @@ export default class SearchBar extends React.Component {
}

handleClose = () => {
if (Utils.isMobile()) {
setTimeout(() => {
document.querySelector('.app__body .sidebar--menu').classList.add('visible');
document.querySelector('#sidebar-webrtc').classList.remove('webrtc--show');
document.querySelector('#inner-wrap-webrtc').classList.remove('webrtc--show');
document.querySelector('#inner-wrap-webrtc').classList.remove('move--left');
});
}

this.props.actions.closeWebrtc();
this.props.actions.closeRightHandSide();
}

Expand Down
9 changes: 7 additions & 2 deletions components/sidebar/header/sidebar_header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import PreferenceStore from 'stores/preference_store.jsx';
import {Constants, Preferences, TutorialSteps} from 'utils/constants.jsx';
import * as Utils from 'utils/utils.jsx';
import StatusDropdown from 'components/status_dropdown/index.jsx';
import {createMenuTip} from 'components/tutorial/tutorial_tip.jsx';
import MenuTutorialTip from 'components/tutorial/menu_tutorial_tip';

import SidebarHeaderDropdown from './dropdown';

Expand Down Expand Up @@ -89,7 +89,12 @@ export default class SidebarHeader extends React.Component {

let tutorialTip = null;
if (this.state.showTutorialTip) {
tutorialTip = createMenuTip(this.showDropdown);
tutorialTip = (
<MenuTutorialTip
toggleFunc={this.showDropdown}
onBottom={false}
/>
);
}

let teamNameWithToolTip = null;
Expand Down
11 changes: 8 additions & 3 deletions components/sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See License.txt for license information.

import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';

import {Preferences} from 'mattermost-redux/constants/index';
import {
Expand All @@ -25,6 +26,8 @@ import {getCurrentTeam, isCurrentUserCurrentTeamAdmin} from 'mattermost-redux/se
import {goToChannelById} from 'actions/channel_actions.jsx';
import {showCreateOption} from 'utils/channel_utils.jsx';
import {GroupUnreadChannels, Constants} from 'utils/constants.jsx';
import {close} from 'actions/views/lhs';
import {getIsLhsOpen} from 'selectors/lhs';

import Sidebar from './sidebar.jsx';

Expand Down Expand Up @@ -65,6 +68,7 @@ function mapStateToProps(state) {

return {
config,
isOpen: getIsLhsOpen(state),
showUnreadSection,
publicChannelIds,
privateChannelIds,
Expand All @@ -81,11 +85,12 @@ function mapStateToProps(state) {
};
}

function mapDispatchToProps() {
function mapDispatchToProps(dispatch) {
return {
actions: {
actions: bindActionCreators({
goToChannelById,
},
close,
}, dispatch),
};
}

Expand Down
10 changes: 6 additions & 4 deletions components/sidebar/sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {OverlayTrigger, Tooltip} from 'react-bootstrap';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
import {PropTypes} from 'prop-types';
import classNames from 'classnames';

import {browserHistory} from 'utils/browser_history';
import {trackEvent} from 'actions/diagnostics_actions.jsx';
Expand All @@ -33,6 +34,8 @@ export default class Sidebar extends React.PureComponent {
*/
config: PropTypes.object.isRequired,

isOpen: PropTypes.bool.isRequired,

/**
* List of public channels (ids)
*/
Expand Down Expand Up @@ -100,6 +103,7 @@ export default class Sidebar extends React.PureComponent {

actions: PropTypes.shape({
goToChannelById: PropTypes.func.isRequired,
close: PropTypes.func.isRequired,
}).isRequired,
};

Expand Down Expand Up @@ -162,9 +166,7 @@ export default class Sidebar extends React.PureComponent {
if (this.closedDirectChannel) {
this.closedDirectChannel = false;
} else {
$('.app__body .inner-wrap').removeClass('move--right');
$('.app__body .sidebar--left').removeClass('move--right');
$('.multi-teams .team-sidebar').removeClass('move--right');
this.props.actions.close();
}
}

Expand Down Expand Up @@ -657,7 +659,7 @@ export default class Sidebar extends React.PureComponent {

return (
<div
className='sidebar--left'
className={classNames('sidebar--left', {'move--right': this.props.isOpen && Utils.isMobile()})}
id='sidebar-left'
key='sidebar-left'
>
Expand Down
Loading

0 comments on commit c3b1c2f

Please sign in to comment.