Skip to content

Commit

Permalink
Merge branch 'feature/switch-server-v2' into 'master'
Browse files Browse the repository at this point in the history
switch server v2

See merge request kchat/webapp!665
  • Loading branch information
antonbuks committed Mar 15, 2024
2 parents ccce5b2 + 22ef3a9 commit da8fcfc
Show file tree
Hide file tree
Showing 43 changed files with 1,241 additions and 35 deletions.
38 changes: 38 additions & 0 deletions webapp/channels/src/actions/servers_actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

/* eslint-disable max-lines */

import store from 'stores/redux_store';

import {SocketEvents} from 'utils/constants';

import {changeStatus, setBadges} from './views/servers';

const dispatch = store.dispatch;

type ServerMessage<T> = {
event: string;
serverId: string;
data: T;
}

export function handleServerEvent(msg: ServerMessage<any>) {
switch (msg.event) {
case SocketEvents.BADGE_UPDATED:
handleBadgeUpdated(msg);
break;
case SocketEvents.TEAM_STATUS_CHANGED:
handleChangeStatus(msg);
break;
}
}

export const handleBadgeUpdated = (msgProps: ServerMessage<{ badge: number }>) => {
dispatch(setBadges(msgProps.serverId, msgProps.data.badge));
};

export const handleChangeStatus = (msgProps: ServerMessage<{ status: string }>) => {
dispatch(changeStatus(msgProps.serverId, msgProps.data.status));
};

24 changes: 24 additions & 0 deletions webapp/channels/src/actions/views/servers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {Servers} from 'utils/constants';

export function setBadges(serverId: string, badges: number) {
return {
type: Servers.BADGE_UPDATED,
data: {
serverId,
badges,
},
};
}

export function changeStatus(serverId: string, status: string) {
return {
type: Servers.STATUS_UPDATED,
data: {
serverId,
status,
},
};
}
9 changes: 7 additions & 2 deletions webapp/channels/src/actions/websocket_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ import WebSocketClient from 'client/web_websocket_client';
import {loadPlugin, loadPluginsIfNecessary, removePlugin} from 'plugins';

import {callNoLongerExist, receivedCall} from './calls';
import {handleServerEvent} from './servers_actions';

const dispatch = store.dispatch;
const getState = store.getState;
Expand Down Expand Up @@ -198,6 +199,7 @@ export function initialize() {
WebSocketClient.addReconnectListener(reconnect);
WebSocketClient.addMissedMessageListener(restart);
WebSocketClient.addCloseListener(handleClose);
WebSocketClient.addOtherServerMessageListener(handleServerEvent);

WebSocketClient.initialize(
connUrl,
Expand All @@ -216,6 +218,7 @@ export function close() {
WebSocketClient.removeReconnectListener(reconnect);
WebSocketClient.removeMissedMessageListener(restart);
WebSocketClient.removeCloseListener(handleClose);
WebSocketClient.removeOtherServerMessageListener(handleServerEvent);
}

const pluginReconnectHandlers = {};
Expand Down Expand Up @@ -943,14 +946,16 @@ function handleKSuiteAdded(msg) {
window.origin,
);
}
doDispatch({type: TeamTypes.RECEIVED_TEAM, data: msg.data.team});
const currentTeamId = getCurrentTeamId(doGetState());
doDispatch({type: TeamTypes.RECEIVED_TEAM, data: msg.data.team, userId: msg.data.user_id, currentTeamId});
};
}

function handleKSuiteDeleted(msg) {
return (doDispatch, doGetState) => {
const currentTeams = getMyKSuites(doGetState());
const newTeams = currentTeams.filter((team) => team.id !== msg.data.team.id);
const currentTeamId = getCurrentTeamId(doGetState());

if (isDesktopApp()) {
window.postMessage(
Expand All @@ -964,7 +969,7 @@ function handleKSuiteDeleted(msg) {
);
}

doDispatch({type: TeamTypes.RECEIVED_TEAM_DELETED, data: {id: msg.data.team.id}});
doDispatch({type: TeamTypes.RECEIVED_TEAM_DELETED, data: {id: msg.data.team.id, currentTeamId}});
doDispatch({type: TeamTypes.UPDATED_TEAM, data: msg.data.team});

if (!isDesktopApp()) {
Expand Down
2 changes: 1 addition & 1 deletion webapp/channels/src/components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ interface Props {
menuButton: MenuButtonProps;
menuButtonTooltip?: MenuButtonTooltipProps;
menu: MenuProps;
children: ReactNode[];
children: ReactNode[] | React.ReactNode;
menuButtonRef?: React.RefObject<HTMLButtonElement>;
}

Expand Down
2 changes: 1 addition & 1 deletion webapp/channels/src/components/root/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ export default class Root extends React.PureComponent<Props, State> {
<AnnouncementBarController/>
<SystemNotice/>
<GlobalHeader headerRef={this.headerResizerRef}/>
{!this.embeddedInIFrame && <TeamSidebar/>}
{!this.embeddedInIFrame && isDesktopApp() && <TeamSidebar/>}
<Switch>
{this.props.products?.map((product) => (
<Route
Expand Down
16 changes: 14 additions & 2 deletions webapp/channels/src/components/sidebar/add_channel_dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import classNames from 'classnames';
import React from 'react';
import {FormattedMessage, useIntl} from 'react-intl';

Expand All @@ -9,11 +10,13 @@ import {trackEvent} from 'actions/telemetry_actions';
import OverlayTrigger from 'components/overlay_trigger';
import Tooltip from 'components/tooltip';
import {CreateChannelsTour, InvitePeopleTour, JoinChannelsTour} from 'components/tours/onboarding_tour';
import PlusFilledIcon from 'components/widgets/icons/plus_filled_icon';
import Menu from 'components/widgets/menu/menu';
import MenuWrapper from 'components/widgets/menu/menu_wrapper';
import WorkTemplateModal from 'components/work_templates';

import {ModalIdentifiers} from 'utils/constants';
import {isDesktopApp} from 'utils/user_agent';

type Props = {
canCreateChannel: boolean;
Expand Down Expand Up @@ -184,7 +187,7 @@ const AddChannelDropdown = ({

return (
<MenuWrapper
className='AddChannelDropdown'
className={classNames('AddChannelDropdown', {isWebApp: !isDesktopApp()})}
onToggle={trackOpen}
open={isAddChannelOpen}
>
Expand All @@ -198,7 +201,16 @@ const AddChannelDropdown = ({
className={'AddChannelDropdown_dropdownButton'}
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channel Dropdown'})}
>
<i className='icon-plus'/>

{isDesktopApp() ? <i className='icon-plus'/> : (
<>
<PlusFilledIcon/>
<FormattedMessage
id={'admin.user_grid.new'}
defaultMessage='New'
/>
</>
)}
</button>
</>
</OverlayTrigger>
Expand Down
2 changes: 2 additions & 0 deletions webapp/channels/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import MoreChannels from 'components/more_channels';
import MoreDirectChannels from 'components/more_direct_channels';
import NewChannelModal from 'components/new_channel_modal/new_channel_modal';
import ResizableLhs from 'components/resizable_sidebar/resizable_lhs';
import SwitchServer from 'components/switch_server';

import Pluggable from 'plugins/pluggable';
import Constants, {ModalIdentifiers, RHSStates} from 'utils/constants';
Expand Down Expand Up @@ -249,6 +250,7 @@ export default class Sidebar extends React.PureComponent<Props, State> {
showWorkTemplateButton={this.props.showWorkTemplateButton}
/>
)}
{!isDesktopApp() && <SwitchServer/>}
<div
id='lhsNavigator'
role='application'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import Heading from '@infomaniak/compass-components/components/heading';
import Flex from '@infomaniak/compass-components/utilities/layout/Flex';
import classNames from 'classnames';
import React, {useCallback, useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import styled from 'styled-components';
Expand All @@ -21,6 +22,7 @@ import {useShowOnboardingTutorialStep} from 'components/tours/onboarding_tour';
import MenuWrapper from 'components/widgets/menu/menu_wrapper';

import Constants from 'utils/constants';
import {isDesktopApp} from 'utils/user_agent';

import type {GlobalState} from 'types/store';

Expand Down Expand Up @@ -51,6 +53,11 @@ const SidebarHeaderContainer = styled(Flex).attrs(() => ({
border-radius: 16px;
font-size: 18px;
}
&.isWebApp {
flex-direction: column;
height: auto;
}
`;

const HEADING_WIDTH = 200;
Expand Down Expand Up @@ -121,28 +128,31 @@ const SidebarHeader: React.FC<Props> = (props: Props): JSX.Element => {
<>
<SidebarHeaderContainer
id={'sidebar-header-container'}
className={classNames({isWebApp: !isDesktopApp()})}
>
<OverlayTrigger

delayShow={Constants.OVERLAY_TIME_DELAY}
placement='bottom'
overlay={currentTeam.description?.length ? (
<Tooltip id='team-name__tooltip'>{currentTeam.description}</Tooltip>
) : <></>}
>
<MenuWrapper
onToggle={handleMenuToggle}
className='SidebarHeaderMenuWrapper test-team-header'
{isDesktopApp() && (
<OverlayTrigger

delayShow={Constants.OVERLAY_TIME_DELAY}
placement='bottom'
overlay={currentTeam.description?.length ? (
<Tooltip id='team-name__tooltip'>{currentTeam.description}</Tooltip>
) : <></>}
>
<SidebarHeading>
<button className='style--none sidebar-header'>
<span className='title'>{currentTeam.display_name}</span>
<i className='icon icon-chevron-down'/>
</button>
</SidebarHeading>
<MainMenu id='sidebarDropdownMenu'/>
</MenuWrapper>
</OverlayTrigger>
<MenuWrapper
onToggle={handleMenuToggle}
className='SidebarHeaderMenuWrapper test-team-header'
>
<SidebarHeading>
<button className='style--none sidebar-header'>
<span className='title'>{currentTeam.display_name}</span>
<i className='icon icon-chevron-down'/>
</button>
</SidebarHeading>
<MainMenu id='sidebarDropdownMenu'/>
</MenuWrapper>
</OverlayTrigger>
)}
<AddChannelDropdown
showNewChannelModal={props.showNewChannelModal}
showMoreChannelsModal={props.showMoreChannelsModal}
Expand Down
33 changes: 33 additions & 0 deletions webapp/channels/src/components/switch_server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import type {ConnectedProps} from 'react-redux';
import {connect} from 'react-redux';
import {withRouter} from 'react-router-dom';

import {getTeamsOrderCookie} from 'mattermost-redux/utils/team_utils';

import {getCurrentServer, getOtherServers, getServersUnreadStatus, isMultiServer} from 'selectors/views/servers';

import type {GlobalState} from 'types/store';

import SwitchServer from './switch_server';

function mapStateToProps(state: GlobalState) {
const currentServer = getCurrentServer(state);
const servers = getOtherServers(state);

return {
servers,
currentServer,
unreadStatus: getServersUnreadStatus(state),
userTeamsOrderPreference: getTeamsOrderCookie(),
isMultiServer: isMultiServer(state),
};
}

const connector = connect(mapStateToProps, {});

export type PropsFromRedux = ConnectedProps<typeof connector>;

export default withRouter(connector(SwitchServer));
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React from 'react';
import type {FC} from 'react';

type Props = {
total: number;
}

const Counter: FC<Props> = ({total}) => {
return (
<span className='switch-counter'>
{total}
</span>
);
};

export default Counter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Counter from './counter';
export default Counter;

49 changes: 49 additions & 0 deletions webapp/channels/src/components/switch_server/switch_item/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import type {ConnectedProps} from 'react-redux';
import {connect} from 'react-redux';
import type {ActionCreatorsMapObject, Dispatch} from 'redux';
import {bindActionCreators} from 'redux';

import type {Team} from '@mattermost/types/teams';

import type {GenericAction, GetStateFunc} from 'mattermost-redux/types/actions';

import {switchTeam} from 'actions/team_actions';
import {makeGetBadgeCountForServerId} from 'selectors/views/servers';

import type {GlobalState} from 'types/store';
import type {Server} from 'types/store/servers';

import SwitchItem from './switch_item';

type OwnProps = {
server: Server;
}

function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
return {
unreadCounts: makeGetBadgeCountForServerId(state, ownProps.server.id),
disabled: ownProps.server.status !== 'ok',
};
}

type Actions = {
switchTeam: (url: string, team?: Team) => (dispatch: Dispatch<GenericAction>, getState: GetStateFunc) => void;
}

function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
return {
actions: bindActionCreators<ActionCreatorsMapObject, Actions>({
switchTeam,
}, dispatch),
};
}

const connector = connect(mapStateToProps, mapDispatchToProps);

export type PropsFromRedux = ConnectedProps<typeof connector>;

export default connector(SwitchItem);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Label from './label';
export default Label;

Loading

0 comments on commit da8fcfc

Please sign in to comment.