feat: Add search to speaker stats (#9510)
* Additional setting to add search to speaker stats * Add translation for speaker stats search placeholder * Unset speaker stats search input autocomplete * Fix lint errors for speaker stats search * Change setting to disableSpeakerStatsSearch * Better Object.prototype.hasOwnProperty.call alternative * Make SpeakerStatsSearch a functional component * Align header with input and use material-ui styles instead of scss and remove SpeakerStats header and fix dialog close * Resolve code style remark in SpeakerStats constructor * Resolve component empty return value remark in SpeakerStatsSearch * Resolve get config property in outside function remark in SpeakerStatsSearch * Resolve unnecessary anonymous function remark in SpeakerStatsSearch
This commit is contained in:
parent
ae33755913
commit
c123ff9e15
|
@ -144,6 +144,9 @@ var config = {
|
|||
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
||||
// resolution: 720,
|
||||
|
||||
// Specifies whether there will be a search field in speaker stats or not
|
||||
// disableSpeakerStatsSearch: false,
|
||||
|
||||
// How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD.
|
||||
// Use -1 to disable.
|
||||
// maxFullResolutionParticipants: 2,
|
||||
|
|
|
@ -586,6 +586,7 @@
|
|||
},
|
||||
"speaker": "Говорещ",
|
||||
"speakerStats": {
|
||||
"search": "Търсене",
|
||||
"hours": "{{count}}ч",
|
||||
"minutes": "{{count}}мин",
|
||||
"name": "Име",
|
||||
|
|
|
@ -802,6 +802,7 @@
|
|||
},
|
||||
"speaker": "Sprecher/-in",
|
||||
"speakerStats": {
|
||||
"search": "Suche",
|
||||
"hours": "{{count}} Std. ",
|
||||
"minutes": "{{count}} Min. ",
|
||||
"name": "Name",
|
||||
|
|
|
@ -802,6 +802,7 @@
|
|||
},
|
||||
"speaker": "Speaker",
|
||||
"speakerStats": {
|
||||
"search": "Search",
|
||||
"hours": "{{count}}h",
|
||||
"minutes": "{{count}}m",
|
||||
"name": "Name",
|
||||
|
|
|
@ -98,6 +98,7 @@ export default [
|
|||
'disableRtx',
|
||||
'disableShortcuts',
|
||||
'disableShowMoreStats',
|
||||
'disableSpeakerStatsSearch',
|
||||
'disableSimulcast',
|
||||
'disableThirdPartyRequests',
|
||||
'disableTileView',
|
||||
|
|
|
@ -6,9 +6,11 @@ import { Dialog } from '../../base/dialog';
|
|||
import { translate } from '../../base/i18n';
|
||||
import { getLocalParticipant } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { escapeRegexp } from '../../base/util';
|
||||
|
||||
import SpeakerStatsItem from './SpeakerStatsItem';
|
||||
import SpeakerStatsLabels from './SpeakerStatsLabels';
|
||||
import SpeakerStatsSearch from './SpeakerStatsSearch';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
|
@ -41,7 +43,12 @@ type State = {
|
|||
/**
|
||||
* The stats summary provided by the JitsiConference.
|
||||
*/
|
||||
stats: Object
|
||||
stats: Object,
|
||||
|
||||
/**
|
||||
* The search input criteria.
|
||||
*/
|
||||
criteria: string,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,11 +69,13 @@ class SpeakerStats extends Component<Props, State> {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
stats: this.props.conference.getSpeakerStats()
|
||||
stats: this._getSpeakerStats(),
|
||||
criteria: ''
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._updateStats = this._updateStats.bind(this);
|
||||
this._onSearch = this._onSearch.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,8 +111,9 @@ class SpeakerStats extends Component<Props, State> {
|
|||
<Dialog
|
||||
cancelKey = { 'dialog.close' }
|
||||
submitDisabled = { true }
|
||||
titleKey = 'speakerStats.speakerStats'>
|
||||
titleKey = { 'speakerStats.speakerStats' }>
|
||||
<div className = 'speaker-stats'>
|
||||
<SpeakerStatsSearch onSearch = { this._onSearch } />
|
||||
<SpeakerStatsLabels />
|
||||
{ items }
|
||||
</div>
|
||||
|
@ -111,6 +121,32 @@ class SpeakerStats extends Component<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the internal state with the latest speaker stats.
|
||||
*
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_getSpeakerStats() {
|
||||
const stats = { ...this.props.conference.getSpeakerStats() };
|
||||
|
||||
if (this.state?.criteria) {
|
||||
const searchRegex = new RegExp(this.state.criteria, 'gi');
|
||||
|
||||
for (const id in stats) {
|
||||
if (stats[id].hasOwnProperty('_isLocalStats')) {
|
||||
const name = stats[id].isLocalStats() ? this.props._localDisplayName : stats[id].getDisplayName();
|
||||
|
||||
if (!name || !name.match(searchRegex)) {
|
||||
delete stats[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SpeakerStatsItem instance for the passed in user id.
|
||||
*
|
||||
|
@ -155,6 +191,22 @@ class SpeakerStats extends Component<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
_onSearch: () => void;
|
||||
|
||||
/**
|
||||
* Search the existing participants by name.
|
||||
*
|
||||
* @returns {void}
|
||||
* @param {string} criteria - The search parameter.
|
||||
* @protected
|
||||
*/
|
||||
_onSearch(criteria = '') {
|
||||
this.setState({
|
||||
...this.state,
|
||||
criteria: escapeRegexp(criteria)
|
||||
});
|
||||
}
|
||||
|
||||
_updateStats: () => void;
|
||||
|
||||
/**
|
||||
|
@ -164,9 +216,12 @@ class SpeakerStats extends Component<Props, State> {
|
|||
* @private
|
||||
*/
|
||||
_updateStats() {
|
||||
const stats = this.props.conference.getSpeakerStats();
|
||||
const stats = this._getSpeakerStats();
|
||||
|
||||
this.setState({ stats });
|
||||
this.setState({
|
||||
...this.state,
|
||||
stats
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* @flow */
|
||||
|
||||
import { FieldTextStateless as TextField } from '@atlaskit/field-text';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { getFieldValue } from '../../base/react';
|
||||
import { isSpeakerStatsSearchDisabled } from '../functions';
|
||||
|
||||
const useStyles = makeStyles(() => {
|
||||
return {
|
||||
speakerStatsSearch: {
|
||||
position: 'absolute',
|
||||
right: '50px',
|
||||
top: '-5px'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SpeakerStatsSearch}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The function to initiate the change in the speaker stats table.
|
||||
*/
|
||||
onSearch: Function,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* React component for display an individual user's speaker stats.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
function SpeakerStatsSearch({ onSearch }: Props) {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const [ searchValue, setSearchValue ] = useState<string>('');
|
||||
const onChange = useCallback((evt: Event) => {
|
||||
const value = getFieldValue(evt);
|
||||
|
||||
setSearchValue(value);
|
||||
|
||||
onSearch && onSearch(value);
|
||||
}, []);
|
||||
const disableSpeakerStatsSearch = useSelector(isSpeakerStatsSearchDisabled);
|
||||
|
||||
if (disableSpeakerStatsSearch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className = { classes.speakerStatsSearch }>
|
||||
<TextField
|
||||
autoComplete = 'off'
|
||||
autoFocus = { false }
|
||||
compact = { true }
|
||||
name = 'speakerStatsSearch'
|
||||
onChange = { onChange }
|
||||
placeholder = { t('speakerStats.search') }
|
||||
shouldFitContainer = { false }
|
||||
type = 'text'
|
||||
value = { searchValue } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SpeakerStatsSearch;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Checks if the speaker stats search is disabled.
|
||||
*
|
||||
* @param {*} state - The redux state.
|
||||
* @returns {boolean} - True if the speaker stats search is disabled and false otherwise.
|
||||
*/
|
||||
export function isSpeakerStatsSearchDisabled(state: Object) {
|
||||
return state['features/base/config']?.disableSpeakerStatsSearch;
|
||||
}
|
Loading…
Reference in New Issue