2022-08-26 09:54:03 +00:00
|
|
|
/* eslint-disable lines-around-comment */
|
2022-09-13 07:36:00 +00:00
|
|
|
|
|
|
|
import { Theme } from '@mui/material';
|
|
|
|
import { withStyles } from '@mui/styles';
|
2021-12-15 13:18:41 +00:00
|
|
|
import clsx from 'clsx';
|
2019-04-15 16:23:28 +00:00
|
|
|
import React from 'react';
|
2022-08-26 09:54:03 +00:00
|
|
|
import { WithTranslation } from 'react-i18next';
|
|
|
|
import { connect } from 'react-redux';
|
2017-06-19 20:20:13 +00:00
|
|
|
|
2022-10-20 09:11:27 +00:00
|
|
|
import { IReduxState, IStore } from '../../../app/types';
|
2022-08-26 09:54:03 +00:00
|
|
|
import { translate } from '../../../base/i18n/functions';
|
|
|
|
import { MEDIA_TYPE } from '../../../base/media/constants';
|
2022-10-06 11:12:57 +00:00
|
|
|
import {
|
|
|
|
getLocalParticipant,
|
|
|
|
getParticipantById,
|
|
|
|
isScreenShareParticipant
|
|
|
|
} from '../../../base/participants/functions';
|
2022-10-24 09:51:18 +00:00
|
|
|
import Popover from '../../../base/popover/components/Popover.web';
|
2022-04-04 18:57:58 +00:00
|
|
|
import {
|
2022-09-27 07:10:28 +00:00
|
|
|
getTrackByMediaTypeAndParticipant,
|
|
|
|
getVirtualScreenshareParticipantTrack
|
2022-10-11 10:47:54 +00:00
|
|
|
} from '../../../base/tracks/functions';
|
2022-02-23 13:30:10 +00:00
|
|
|
import {
|
|
|
|
isTrackStreamingStatusInactive,
|
|
|
|
isTrackStreamingStatusInterrupted
|
|
|
|
} from '../../functions';
|
2019-04-15 16:23:28 +00:00
|
|
|
import AbstractConnectionIndicator, {
|
|
|
|
type Props as AbstractProps,
|
2022-09-27 07:10:28 +00:00
|
|
|
type State as AbstractState,
|
2022-11-11 11:11:30 +00:00
|
|
|
INDICATOR_DISPLAY_THRESHOLD,
|
|
|
|
mapStateToProps as _abstractMapStateToProps
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2019-04-15 16:23:28 +00:00
|
|
|
} from '../AbstractConnectionIndicator';
|
2017-07-05 18:17:30 +00:00
|
|
|
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-06-30 16:12:12 +00:00
|
|
|
import ConnectionIndicatorContent from './ConnectionIndicatorContent';
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2022-02-23 13:30:10 +00:00
|
|
|
import { ConnectionIndicatorIcon } from './ConnectionIndicatorIcon';
|
2018-10-30 05:02:23 +00:00
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
/**
|
|
|
|
* An array of display configurations for the connection indicator and its bars.
|
|
|
|
* The ordering is done specifically for faster iteration to find a matching
|
|
|
|
* configuration to the current connection strength percentage.
|
|
|
|
*
|
|
|
|
* @type {Object[]}
|
|
|
|
*/
|
2022-08-26 09:54:03 +00:00
|
|
|
const QUALITY_TO_WIDTH: Array<{
|
|
|
|
colorClass: string;
|
|
|
|
percent: number;
|
|
|
|
tip: string;
|
|
|
|
}> = [
|
2017-06-19 20:20:13 +00:00
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
// Full (3 bars)
|
2017-06-19 20:20:13 +00:00
|
|
|
{
|
2017-09-26 16:55:09 +00:00
|
|
|
colorClass: 'status-high',
|
|
|
|
percent: INDICATOR_DISPLAY_THRESHOLD,
|
2021-12-15 13:18:41 +00:00
|
|
|
tip: 'connectionindicator.quality.good'
|
2017-06-19 20:20:13 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// 2 bars
|
|
|
|
{
|
2017-09-26 16:55:09 +00:00
|
|
|
colorClass: 'status-med',
|
2018-06-22 00:30:19 +00:00
|
|
|
percent: 10,
|
2021-12-15 13:18:41 +00:00
|
|
|
tip: 'connectionindicator.quality.nonoptimal'
|
2017-06-19 20:20:13 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// 1 bar
|
|
|
|
{
|
2017-09-26 16:55:09 +00:00
|
|
|
colorClass: 'status-low',
|
2017-06-19 20:20:13 +00:00
|
|
|
percent: 0,
|
2021-12-15 13:18:41 +00:00
|
|
|
tip: 'connectionindicator.quality.poor'
|
2017-06-19 20:20:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
// Note: we never show 0 bars as long as there is a connection.
|
2017-06-19 20:20:13 +00:00
|
|
|
];
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
/**
|
|
|
|
* The type of the React {@code Component} props of {@link ConnectionIndicator}.
|
|
|
|
*/
|
2022-08-26 09:54:03 +00:00
|
|
|
type Props = AbstractProps & WithTranslation & {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disable/enable inactive indicator.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
_connectionIndicatorInactiveDisabled: boolean;
|
2018-10-30 05:02:23 +00:00
|
|
|
|
2021-09-09 12:50:22 +00:00
|
|
|
/**
|
2022-08-26 09:54:03 +00:00
|
|
|
* Whether the indicator popover is disabled.
|
2021-09-09 12:50:22 +00:00
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
_popoverDisabled: boolean;
|
2021-09-09 12:50:22 +00:00
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
/**
|
|
|
|
* Whether or not the component should ignore setting a visibility class for
|
|
|
|
* hiding the component when the connection quality is not strong.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
alwaysVisible: boolean;
|
2018-10-30 05:02:23 +00:00
|
|
|
|
2020-10-02 13:20:24 +00:00
|
|
|
/**
|
|
|
|
* The audio SSRC of this client.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
audioSsrc: number;
|
2020-10-02 13:20:24 +00:00
|
|
|
|
2021-12-15 13:18:41 +00:00
|
|
|
/**
|
|
|
|
* An object containing the CSS classes.
|
|
|
|
*/
|
2022-09-13 07:36:00 +00:00
|
|
|
classes: any;
|
2021-12-15 13:18:41 +00:00
|
|
|
|
2020-10-02 13:20:24 +00:00
|
|
|
/**
|
|
|
|
* The Redux dispatch function.
|
|
|
|
*/
|
2022-10-11 10:47:54 +00:00
|
|
|
dispatch: IStore['dispatch'];
|
2020-10-02 13:20:24 +00:00
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
/**
|
|
|
|
* Whether or not clicking the indicator should display a popover for more
|
|
|
|
* details.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
enableStatsDisplay: boolean;
|
2018-10-30 05:02:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The font-size for the icon.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
iconSize: number;
|
2018-10-30 05:02:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Relative to the icon from where the popover for more connection details
|
|
|
|
* should display.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
statsPopoverPosition: string;
|
2018-10-30 05:02:23 +00:00
|
|
|
};
|
|
|
|
|
2022-11-03 08:35:51 +00:00
|
|
|
interface IState extends AbstractState {
|
2021-11-01 09:39:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether popover is ivisible or not.
|
|
|
|
*/
|
2022-09-08 09:52:36 +00:00
|
|
|
popoverVisible: boolean;
|
2022-11-03 08:35:51 +00:00
|
|
|
}
|
2021-11-01 09:39:19 +00:00
|
|
|
|
2022-09-13 07:36:00 +00:00
|
|
|
const styles = (theme: Theme) => {
|
2021-12-15 13:18:41 +00:00
|
|
|
return {
|
|
|
|
container: {
|
|
|
|
display: 'inline-block'
|
|
|
|
},
|
|
|
|
|
|
|
|
hidden: {
|
|
|
|
display: 'none'
|
|
|
|
},
|
|
|
|
|
|
|
|
icon: {
|
|
|
|
padding: '6px',
|
|
|
|
borderRadius: '4px',
|
|
|
|
|
|
|
|
'&.status-high': {
|
|
|
|
backgroundColor: theme.palette.success01
|
|
|
|
},
|
|
|
|
|
|
|
|
'&.status-med': {
|
|
|
|
backgroundColor: theme.palette.warning01
|
|
|
|
},
|
|
|
|
|
|
|
|
'&.status-low': {
|
|
|
|
backgroundColor: theme.palette.iconError
|
|
|
|
},
|
|
|
|
|
|
|
|
'&.status-disabled': {
|
|
|
|
background: 'transparent'
|
|
|
|
},
|
|
|
|
|
|
|
|
'&.status-lost': {
|
|
|
|
backgroundColor: theme.palette.ui05
|
|
|
|
},
|
|
|
|
|
|
|
|
'&.status-other': {
|
|
|
|
backgroundColor: theme.palette.action01
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
inactiveIcon: {
|
|
|
|
padding: 0,
|
|
|
|
borderRadius: '50%'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-06-19 20:20:13 +00:00
|
|
|
/**
|
|
|
|
* Implements a React {@link Component} which displays the current connection
|
|
|
|
* quality percentage and has a popover to show more detailed connection stats.
|
|
|
|
*
|
2021-11-04 21:10:43 +00:00
|
|
|
* @augments {Component}
|
2017-06-19 20:20:13 +00:00
|
|
|
*/
|
2022-11-03 08:35:51 +00:00
|
|
|
class ConnectionIndicator extends AbstractConnectionIndicator<Props, IState> {
|
2017-06-19 20:20:13 +00:00
|
|
|
/**
|
|
|
|
* Initializes a new {@code ConnectionIndicator} instance.
|
|
|
|
*
|
|
|
|
* @param {Object} props - The read-only properties with which the new
|
|
|
|
* instance is to be initialized.
|
|
|
|
*/
|
2018-10-30 05:02:23 +00:00
|
|
|
constructor(props: Props) {
|
2017-06-19 20:20:13 +00:00
|
|
|
super(props);
|
|
|
|
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2017-06-19 20:20:13 +00:00
|
|
|
this.state = {
|
2017-09-26 16:55:09 +00:00
|
|
|
showIndicator: false,
|
2021-11-01 09:39:19 +00:00
|
|
|
stats: {},
|
|
|
|
popoverVisible: false
|
2017-06-19 20:20:13 +00:00
|
|
|
};
|
2021-11-01 09:39:19 +00:00
|
|
|
this._onShowPopover = this._onShowPopover.bind(this);
|
|
|
|
this._onHidePopover = this._onHidePopover.bind(this);
|
2017-06-19 20:20:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#render()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-12-15 13:18:41 +00:00
|
|
|
const { enableStatsDisplay, participantId, statsPopoverPosition, classes } = this.props;
|
2017-09-26 16:55:09 +00:00
|
|
|
const visibilityClass = this._getVisibilityClass();
|
|
|
|
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-11-08 07:55:02 +00:00
|
|
|
if (this.props._popoverDisabled) {
|
|
|
|
return this._renderIndicator();
|
|
|
|
}
|
2017-09-26 16:55:09 +00:00
|
|
|
|
2017-06-19 20:20:13 +00:00
|
|
|
return (
|
2017-08-22 19:22:06 +00:00
|
|
|
<Popover
|
2021-12-15 13:18:41 +00:00
|
|
|
className = { clsx(classes.container, visibilityClass) }
|
2021-07-08 11:19:17 +00:00
|
|
|
content = { <ConnectionIndicatorContent
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-07-08 11:19:17 +00:00
|
|
|
inheritedStats = { this.state.stats }
|
2021-11-01 09:39:19 +00:00
|
|
|
participantId = { participantId } /> }
|
|
|
|
disablePopover = { !enableStatsDisplay }
|
|
|
|
id = 'participant-connection-indicator'
|
|
|
|
onPopoverClose = { this._onHidePopover }
|
|
|
|
onPopoverOpen = { this._onShowPopover }
|
|
|
|
position = { statsPopoverPosition }
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-11-01 09:39:19 +00:00
|
|
|
visible = { this.state.popoverVisible }>
|
2021-11-08 07:55:02 +00:00
|
|
|
{ this._renderIndicator() }
|
2017-08-22 19:22:06 +00:00
|
|
|
</Popover>
|
2017-06-19 20:20:13 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
/**
|
|
|
|
* Returns a CSS class that interprets the current connection status as a
|
|
|
|
* color.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
_getConnectionColorClass() {
|
2022-02-23 13:30:10 +00:00
|
|
|
// TODO We currently do not have logic to emit and handle stats changes for tracks.
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2017-09-26 16:55:09 +00:00
|
|
|
const { percent } = this.state.stats;
|
|
|
|
|
2022-02-23 13:30:10 +00:00
|
|
|
const {
|
|
|
|
_isConnectionStatusInactive,
|
|
|
|
_isConnectionStatusInterrupted,
|
|
|
|
_connectionIndicatorInactiveDisabled
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2022-02-23 13:30:10 +00:00
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
if (_isConnectionStatusInactive) {
|
|
|
|
if (_connectionIndicatorInactiveDisabled) {
|
2021-10-25 14:11:54 +00:00
|
|
|
return 'status-disabled';
|
|
|
|
}
|
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
return 'status-other';
|
2022-02-23 13:30:10 +00:00
|
|
|
} else if (_isConnectionStatusInterrupted) {
|
2017-09-26 16:55:09 +00:00
|
|
|
return 'status-lost';
|
|
|
|
} else if (typeof percent === 'undefined') {
|
|
|
|
return 'status-high';
|
|
|
|
}
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
return this._getDisplayConfiguration(percent).colorClass;
|
2017-09-26 16:55:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-30 05:02:23 +00:00
|
|
|
/**
|
|
|
|
* Get the icon configuration from QUALITY_TO_WIDTH which has a percentage
|
|
|
|
* that matches or exceeds the passed in percentage. The implementation
|
|
|
|
* assumes QUALITY_TO_WIDTH is already sorted by highest to lowest
|
|
|
|
* percentage.
|
|
|
|
*
|
|
|
|
* @param {number} percent - The connection percentage, out of 100, to find
|
|
|
|
* the closest matching configuration for.
|
|
|
|
* @private
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
2022-08-26 09:54:03 +00:00
|
|
|
_getDisplayConfiguration(percent: number): any {
|
2018-10-30 05:02:23 +00:00
|
|
|
return QUALITY_TO_WIDTH.find(x => percent >= x.percent) || {};
|
|
|
|
}
|
|
|
|
|
2017-09-26 16:55:09 +00:00
|
|
|
/**
|
|
|
|
* Returns additional class names to add to the root of the component. The
|
|
|
|
* class names are intended to be used for hiding or showing the indicator.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
_getVisibilityClass() {
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2022-02-23 13:30:10 +00:00
|
|
|
const { _isConnectionStatusInactive, _isConnectionStatusInterrupted, classes } = this.props;
|
2017-09-26 16:55:09 +00:00
|
|
|
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2017-09-26 16:55:09 +00:00
|
|
|
return this.state.showIndicator
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2017-09-26 16:55:09 +00:00
|
|
|
|| this.props.alwaysVisible
|
2022-02-23 13:30:10 +00:00
|
|
|
|| _isConnectionStatusInterrupted
|
|
|
|
|| _isConnectionStatusInactive
|
2021-12-15 13:18:41 +00:00
|
|
|
? '' : classes.hidden;
|
2017-09-26 16:55:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 09:39:19 +00:00
|
|
|
/**
|
|
|
|
* Hides popover.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_onHidePopover() {
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-11-01 09:39:19 +00:00
|
|
|
this.setState({ popoverVisible: false });
|
|
|
|
}
|
|
|
|
|
2021-11-09 09:11:21 +00:00
|
|
|
/**
|
2021-11-01 09:39:19 +00:00
|
|
|
* Shows popover.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2021-11-09 09:11:21 +00:00
|
|
|
_onShowPopover() {
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-11-09 09:11:21 +00:00
|
|
|
this.setState({ popoverVisible: true });
|
|
|
|
}
|
2021-11-08 07:55:02 +00:00
|
|
|
|
|
|
|
|
2021-11-09 09:11:21 +00:00
|
|
|
/**
|
2021-11-08 07:55:02 +00:00
|
|
|
* Creates a ReactElement for displaying the indicator (GSM bar).
|
|
|
|
*
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
2021-11-09 09:11:21 +00:00
|
|
|
_renderIndicator() {
|
2022-02-23 13:30:10 +00:00
|
|
|
const {
|
|
|
|
_isConnectionStatusInactive,
|
|
|
|
_isConnectionStatusInterrupted,
|
|
|
|
_connectionIndicatorInactiveDisabled,
|
|
|
|
_videoTrack,
|
|
|
|
classes,
|
|
|
|
iconSize
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2022-02-23 13:30:10 +00:00
|
|
|
} = this.props;
|
|
|
|
|
2021-11-09 09:11:21 +00:00
|
|
|
return (
|
2021-12-15 13:18:41 +00:00
|
|
|
<div
|
2022-02-23 13:30:10 +00:00
|
|
|
style = {{ fontSize: iconSize }}>
|
|
|
|
<ConnectionIndicatorIcon
|
|
|
|
classes = { classes }
|
|
|
|
colorClass = { this._getConnectionColorClass() }
|
|
|
|
connectionIndicatorInactiveDisabled = { _connectionIndicatorInactiveDisabled }
|
|
|
|
isConnectionStatusInactive = { _isConnectionStatusInactive }
|
|
|
|
isConnectionStatusInterrupted = { _isConnectionStatusInterrupted }
|
|
|
|
track = { _videoTrack } />
|
2021-11-09 09:11:21 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2020-10-02 13:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maps part of the Redux state to the props of this component.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The Redux state.
|
|
|
|
* @param {Props} ownProps - The own props of the component.
|
|
|
|
* @returns {Props}
|
|
|
|
*/
|
2022-10-20 09:11:27 +00:00
|
|
|
export function _mapStateToProps(state: IReduxState, ownProps: Props) {
|
2020-10-28 20:06:59 +00:00
|
|
|
const { participantId } = ownProps;
|
2022-04-04 18:57:58 +00:00
|
|
|
const tracks = state['features/base/tracks'];
|
2022-02-23 13:30:10 +00:00
|
|
|
const participant = participantId ? getParticipantById(state, participantId) : getLocalParticipant(state);
|
2022-11-08 19:15:49 +00:00
|
|
|
let _videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
|
2022-02-23 13:30:10 +00:00
|
|
|
|
2022-11-08 19:15:49 +00:00
|
|
|
if (isScreenShareParticipant(participant)) {
|
|
|
|
_videoTrack = getVirtualScreenshareParticipantTrack(tracks, participantId);
|
2022-04-04 18:57:58 +00:00
|
|
|
}
|
|
|
|
|
2022-11-08 19:15:49 +00:00
|
|
|
const _isConnectionStatusInactive = isTrackStreamingStatusInactive(_videoTrack);
|
|
|
|
const _isConnectionStatusInterrupted = isTrackStreamingStatusInterrupted(_videoTrack);
|
2020-10-05 14:56:46 +00:00
|
|
|
|
2020-10-28 20:06:59 +00:00
|
|
|
return {
|
2022-11-11 11:11:30 +00:00
|
|
|
..._abstractMapStateToProps(state),
|
2021-09-09 12:50:22 +00:00
|
|
|
_connectionIndicatorInactiveDisabled:
|
2022-10-31 21:17:05 +00:00
|
|
|
Boolean(state['features/base/config'].connectionIndicators?.inactiveDisabled),
|
2022-11-08 19:15:49 +00:00
|
|
|
_isVirtualScreenshareParticipant: isScreenShareParticipant(participant),
|
2021-11-09 07:15:19 +00:00
|
|
|
_popoverDisabled: state['features/base/config'].connectionIndicators?.disableDetails,
|
2022-02-23 13:30:10 +00:00
|
|
|
_isConnectionStatusInactive,
|
2022-11-08 19:15:49 +00:00
|
|
|
_isConnectionStatusInterrupted,
|
|
|
|
_videoTrack
|
2020-10-28 20:06:59 +00:00
|
|
|
};
|
2020-10-02 13:20:24 +00:00
|
|
|
}
|
2022-10-31 21:17:05 +00:00
|
|
|
|
2021-12-15 13:18:41 +00:00
|
|
|
export default translate(connect(_mapStateToProps)(
|
2022-08-26 09:54:03 +00:00
|
|
|
// @ts-ignore
|
2021-12-15 13:18:41 +00:00
|
|
|
withStyles(styles)(ConnectionIndicator)));
|