Compare commits

...

5 Commits

Author SHA1 Message Date
Hristo Terezov
9f027170dd fix(record):web/mobile match disable functionality 2020-05-28 16:01:47 -05:00
Hristo Terezov
436f255507 feat(recording): Disable buttons on active session 2020-05-28 15:56:07 -05:00
Hristo Terezov
fd972373af feat(subtitles): Disable for guests. 2020-05-28 15:55:42 -05:00
Hristo Terezov
adc368c535 feat(config):InsecureRoomNameWarning config option 2020-05-27 18:29:38 -05:00
Jaya Allamsetty
2191505d2c chore(deps): update lib-jitsi-meet
c94f6a570f
2020-05-26 16:39:45 -05:00
13 changed files with 141 additions and 202 deletions

View File

@@ -198,6 +198,7 @@
"kickParticipantTitle": "Kick this participant?",
"kickTitle": "Ouch! {{participantDisplayName}} kicked you out of the meeting",
"liveStreaming": "Live Streaming",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Not possible while recording is active",
"liveStreamingDisabledForGuestTooltip": "Guests can't start live streaming.",
"liveStreamingDisabledTooltip": "Start live stream disabled.",
"lockMessage": "Failed to lock the conference.",
@@ -231,6 +232,7 @@
"popupError": "Your browser is blocking pop-up windows from this site. Please enable pop-ups in your browser's security settings and try again.",
"popupErrorTitle": "Pop-up blocked",
"recording": "Recording",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
"recordingDisabledForGuestTooltip": "Guests can't start recordings.",
"recordingDisabledTooltip": "Start recording disabled.",
"rejoinNow": "Rejoin now",

4
package-lock.json generated
View File

@@ -10794,8 +10794,8 @@
}
},
"lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#3c8d411c96fdfa18c57111630f29880f3f72949e",
"from": "github:jitsi/lib-jitsi-meet#3c8d411c96fdfa18c57111630f29880f3f72949e",
"version": "github:jitsi/lib-jitsi-meet#c94f6a570f69ebfe18de6c1549cc76370c791468",
"from": "github:jitsi/lib-jitsi-meet#c94f6a570f69ebfe18de6c1549cc76370c791468",
"requires": {
"@jitsi/sdp-interop": "1.0.2",
"@jitsi/sdp-simulcast": "0.3.0",

View File

@@ -56,7 +56,7 @@
"js-utils": "github:jitsi/js-utils#cf11996bd866fdb47326c59a5d3bc24be17282d4",
"jsrsasign": "8.0.12",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#3c8d411c96fdfa18c57111630f29880f3f72949e",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#c94f6a570f69ebfe18de6c1549cc76370c791468",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.13",
"moment": "2.19.4",

View File

@@ -50,8 +50,9 @@ export default class AbstractInsecureRoomNameLabel extends PureComponent<Props>
*/
export function _mapStateToProps(state: Object): $Shape<Props> {
const { room } = state['features/base/conference'];
const { enableInsecureRoomNameWarning = false } = state['features/base/config'];
return {
_visible: room && isInsecureRoomName(room)
_visible: enableInsecureRoomNameWarning && room && isInsecureRoomName(room)
};
}

View File

@@ -1,6 +1,7 @@
// @flow
import { openDialog } from '../../../base/dialog';
import { IconLiveStreaming } from '../../../base/icons';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { getLocalParticipant } from '../../../base/participants';
import {
@@ -26,6 +27,16 @@ export type Props = AbstractButtonProps & {
*/
_isLiveStreamRunning: boolean,
/**
* True if the button needs to be disabled.
*/
_disabled: Boolean,
/**
* The tooltip to display when hovering over the button.
*/
_tooltip: ?String,
/**
* The redux {@code dispatch} function.
*/
@@ -40,12 +51,22 @@ export type Props = AbstractButtonProps & {
/**
* An abstract class of a button for starting and stopping live streaming.
*/
export default class AbstractLiveStreamButton<P: Props>
extends AbstractButton<P, *> {
export default class AbstractLiveStreamButton<P: Props> extends AbstractButton<P, *> {
accessibilityLabel = 'dialog.accessibilityLabel.liveStreaming';
icon = IconLiveStreaming;
label = 'dialog.startLiveStreaming';
toggledLabel = 'dialog.stopLiveStreaming';
/**
* Returns the tooltip that should be displayed when the button is disabled.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.props._tooltip || '';
}
/**
* Handles clicking / pressing the button.
*
@@ -61,6 +82,16 @@ export default class AbstractLiveStreamButton<P: Props>
));
}
/**
* Returns a boolean value indicating if this button is disabled or not.
*
* @protected
* @returns {boolean}
*/
_isDisabled() {
return this.props._disabled;
}
/**
* Indicates whether this button is in toggled state or not.
*
@@ -81,6 +112,7 @@ export default class AbstractLiveStreamButton<P: Props>
* @param {Props} ownProps - The own props of the Component.
* @private
* @returns {{
* _disabled: boolean,
* _isLiveStreamRunning: boolean,
* visible: boolean
* }}
@@ -88,9 +120,10 @@ export default class AbstractLiveStreamButton<P: Props>
export function _mapStateToProps(state: Object, ownProps: Props) {
let { visible } = ownProps;
// a button can be disabled/enabled only if enableFeaturesBasedOnToken
// is on
let disabledByFeatures;
// A button can be disabled/enabled only if enableFeaturesBasedOnToken
// is on or if the recording is running.
let _disabled;
let _tooltip = '';
if (typeof visible === 'undefined') {
// If the containing component provides the visible prop, that is one
@@ -106,14 +139,33 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
if (enableFeaturesBasedOnToken) {
visible = visible && String(features.livestreaming) === 'true';
disabledByFeatures = String(features.livestreaming) === 'disabled';
_disabled = String(features.livestreaming) === 'disabled';
if (!visible && !_disabled) {
_disabled = true;
visible = true;
// button and tooltip
if (state['features/base/jwt'].isGuest) {
_tooltip = 'dialog.liveStreamingDisabledForGuestTooltip';
} else {
_tooltip = 'dialog.liveStreamingDisabledTooltip';
}
}
}
}
// disable the button if the recording is running.
if (getActiveSession(state, JitsiRecordingConstants.mode.FILE)) {
_disabled = true;
_tooltip = 'dialog.liveStreamingDisabledBecauseOfActiveRecordingTooltip';
}
return {
_disabled,
_isLiveStreamRunning: Boolean(
getActiveSession(state, JitsiRecordingConstants.mode.STREAM)),
disabledByFeatures,
_tooltip,
visible
};
}

View File

@@ -1,21 +1,9 @@
// @flow
import { translate } from '../../../../base/i18n';
import { IconLiveStreaming } from '../../../../base/icons';
import { LIVE_STREAMING_ENABLED, getFeatureFlag } from '../../../../base/flags';
import { translate } from '../../../../base/i18n';
import { connect } from '../../../../base/redux';
import AbstractLiveStreamButton, {
_mapStateToProps as _abstractMapStateToProps,
type Props
} from '../AbstractLiveStreamButton';
/**
* An implementation of a button for starting and stopping live streaming.
*/
class LiveStreamButton extends AbstractLiveStreamButton<Props> {
icon = IconLiveStreaming;
}
import AbstractLiveStreamButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractLiveStreamButton';
/**
* Maps (parts of) the redux state to the associated props for this component.
@@ -36,4 +24,4 @@ export function mapStateToProps(state: Object, ownProps: Object) {
};
}
export default translate(connect(mapStateToProps)(LiveStreamButton));
export default translate(connect(mapStateToProps)(AbstractLiveStreamButton));

View File

@@ -1,62 +1,15 @@
// @flow
import { translate } from '../../../../base/i18n';
import { IconLiveStreaming } from '../../../../base/icons';
import { connect } from '../../../../base/redux';
import AbstractLiveStreamButton, {
_mapStateToProps as _abstractMapStateToProps,
type Props as AbstractProps
type Props
} from '../AbstractLiveStreamButton';
declare var interfaceConfig: Object;
type Props = AbstractProps & {
/**
* True if the button should be disabled, false otherwise.
*
* NOTE: On web, if the feature is not disabled on purpose, then we still
* show the button but disabled and with a tooltip rendered on it,
* explaining why it's not available.
*/
_disabled: boolean,
/**
* Tooltip for the button when it's disabled in a certain way.
*/
_liveStreamDisabledTooltipKey: ?string
}
/**
* An implementation of a button for starting and stopping live streaming.
*/
class LiveStreamButton extends AbstractLiveStreamButton<Props> {
icon = IconLiveStreaming;
/**
* Returns the tooltip that should be displayed when the button is disabled.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.props._liveStreamDisabledTooltipKey || '';
}
/**
* Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not.
*
* @override
* @protected
* @returns {boolean}
*/
_isDisabled() {
return this.props._disabled;
}
}
/**
* Maps (parts of) the redux state to the associated props for the
* {@code LiveStreamButton} component.
@@ -75,36 +28,14 @@ function _mapStateToProps(state: Object, ownProps: Props) {
const abstractProps = _abstractMapStateToProps(state, ownProps);
let { visible } = ownProps;
const _disabledByFeatures = abstractProps.disabledByFeatures;
let _disabled = false;
let _liveStreamDisabledTooltipKey;
if (!abstractProps.visible
&& _disabledByFeatures !== undefined && !_disabledByFeatures) {
_disabled = true;
// button and tooltip
if (state['features/base/jwt'].isGuest) {
_liveStreamDisabledTooltipKey
= 'dialog.liveStreamingDisabledForGuestTooltip';
} else {
_liveStreamDisabledTooltipKey
= 'dialog.liveStreamingDisabledTooltip';
}
}
if (typeof visible === 'undefined') {
visible = interfaceConfig.TOOLBAR_BUTTONS.includes('livestreaming')
&& (abstractProps.visible
|| Boolean(_liveStreamDisabledTooltipKey));
visible = interfaceConfig.TOOLBAR_BUTTONS.includes('livestreaming') && abstractProps.visible;
}
return {
...abstractProps,
_disabled,
_liveStreamDisabledTooltipKey,
visible
};
}
export default translate(connect(_mapStateToProps)(LiveStreamButton));
export default translate(connect(_mapStateToProps)(AbstractLiveStreamButton));

View File

@@ -6,6 +6,7 @@ import {
} from '../../../analytics';
import { openDialog } from '../../../base/dialog';
import { IconToggleRecording } from '../../../base/icons';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import {
getLocalParticipant,
@@ -26,11 +27,21 @@ import { StartRecordingDialog, StopRecordingDialog } from './_';
*/
export type Props = AbstractButtonProps & {
/**
* True if the button needs to be disabled.
*/
_disabled: Boolean,
/**
* True if there is a running active recording, false otherwise.
*/
_isRecordingRunning: boolean,
/**
* The tooltip to display when hovering over the button.
*/
_tooltip: ?String,
/**
* The redux {@code dispatch} function.
*/
@@ -45,12 +56,22 @@ export type Props = AbstractButtonProps & {
/**
* An abstract implementation of a button for starting and stopping recording.
*/
export default class AbstractRecordButton<P: Props>
extends AbstractButton<P, *> {
export default class AbstractRecordButton<P: Props> extends AbstractButton<P, *> {
accessibilityLabel = 'toolbar.accessibilityLabel.recording';
icon = IconToggleRecording;
label = 'dialog.startRecording';
toggledLabel = 'dialog.stopRecording';
/**
* Returns the tooltip that should be displayed when the button is disabled.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.props._tooltip || '';
}
/**
* Handles clicking / pressing the button.
*
@@ -82,7 +103,7 @@ export default class AbstractRecordButton<P: Props>
* @returns {boolean}
*/
_isDisabled() {
return false;
return this.props._disabled;
}
/**
@@ -105,17 +126,18 @@ export default class AbstractRecordButton<P: Props>
* @param {Props} ownProps - The own props of the Component.
* @private
* @returns {{
* _disabled: boolean,
* _isRecordingRunning: boolean,
* disabledByFeatures: boolean,
* visible: boolean
* }}
*/
export function _mapStateToProps(state: Object, ownProps: Props): Object {
let { visible } = ownProps;
// a button can be disabled/enabled only if enableFeaturesBasedOnToken
// is on
let disabledByFeatures;
// a button can be disabled/enabled if enableFeaturesBasedOnToken
// is on or if the livestreaming is running.
let _disabled;
let _tooltip = '';
if (typeof visible === 'undefined') {
// If the containing component provides the visible prop, that is one
@@ -128,19 +150,35 @@ export function _mapStateToProps(state: Object, ownProps: Props): Object {
} = state['features/base/config'];
const { features = {} } = getLocalParticipant(state);
visible = isModerator
&& fileRecordingsEnabled;
visible = isModerator && fileRecordingsEnabled;
if (enableFeaturesBasedOnToken) {
visible = visible && String(features.recording) === 'true';
disabledByFeatures = String(features.recording) === 'disabled';
_disabled = String(features.recording) === 'disabled';
if (!visible && !_disabled) {
_disabled = true;
visible = true;
// button and tooltip
if (state['features/base/jwt'].isGuest) {
_tooltip = 'dialog.recordingDisabledForGuestTooltip';
} else {
_tooltip = 'dialog.recordingDisabledTooltip';
}
}
}
}
// disable the button if the livestreaming is running.
if (getActiveSession(state, JitsiRecordingConstants.mode.STREAM)) {
_disabled = true;
_tooltip = 'dialog.recordingDisabledBecauseOfActiveLiveStreamingTooltip';
}
return {
_isRecordingRunning:
Boolean(getActiveSession(state, JitsiRecordingConstants.mode.FILE)),
disabledByFeatures,
_disabled,
_isRecordingRunning: Boolean(getActiveSession(state, JitsiRecordingConstants.mode.FILE)),
_tooltip,
visible
};
}

View File

@@ -4,20 +4,8 @@ import { Platform } from 'react-native';
import { IOS_RECORDING_ENABLED, RECORDING_ENABLED, getFeatureFlag } from '../../../../base/flags';
import { translate } from '../../../../base/i18n';
import { IconToggleRecording } from '../../../../base/icons';
import { connect } from '../../../../base/redux';
import AbstractRecordButton, {
_mapStateToProps as _abstractMapStateToProps,
type Props
} from '../AbstractRecordButton';
/**
* An implementation of a button for starting and stopping recording.
*/
class RecordButton extends AbstractRecordButton<Props> {
icon = IconToggleRecording;
}
import AbstractRecordButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractRecordButton';
/**
* Maps (parts of) the redux state to the associated props for this component.
@@ -39,4 +27,4 @@ export function mapStateToProps(state: Object, ownProps: Object) {
};
}
export default translate(connect(mapStateToProps)(RecordButton));
export default translate(connect(mapStateToProps)(AbstractRecordButton));

View File

@@ -1,62 +1,15 @@
// @flow
import { translate } from '../../../../base/i18n';
import { IconToggleRecording } from '../../../../base/icons';
import { connect } from '../../../../base/redux';
import AbstractRecordButton, {
_mapStateToProps as _abstractMapStateToProps,
type Props as AbstractProps
type Props
} from '../AbstractRecordButton';
declare var interfaceConfig: Object;
type Props = AbstractProps & {
/**
* True if the button should be disabled, false otherwise.
*
* NOTE: On web, if the feature is not disabled on purpose, then we still
* show the button but disabled and with a tooltip rendered on it,
* explaining why it's not available.
*/
_disabled: boolean,
/**
* Tooltip for the button when it's disabled in a certain way.
*/
_fileRecordingsDisabledTooltipKey: ?string
}
/**
* An implementation of a button for starting and stopping recording.
*/
class RecordButton extends AbstractRecordButton<Props> {
icon = IconToggleRecording;
/**
* Returns the tooltip that should be displayed when the button is disabled.
*
* @private
* @returns {string}
*/
_getTooltip() {
return this.tooltip || '';
}
/**
* Helper function to be implemented by subclasses, which must return a
* boolean value indicating if this button is disabled or not.
*
* @override
* @protected
* @returns {boolean}
*/
_isDisabled() {
return this.props._disabled;
}
}
/**
* Maps (parts of) the redux state to the associated props for the
* {@code RecordButton} component.
@@ -75,36 +28,14 @@ export function _mapStateToProps(state: Object, ownProps: Props): Object {
const abstractProps = _abstractMapStateToProps(state, ownProps);
let { visible } = ownProps;
const _disabledByFeatures = abstractProps.disabledByFeatures;
let _disabled = false;
let _fileRecordingsDisabledTooltipKey;
if (!abstractProps.visible
&& _disabledByFeatures !== undefined && !_disabledByFeatures) {
_disabled = true;
// button and tooltip
if (state['features/base/jwt'].isGuest) {
_fileRecordingsDisabledTooltipKey
= 'dialog.recordingDisabledForGuestTooltip';
} else {
_fileRecordingsDisabledTooltipKey
= 'dialog.recordingDisabledTooltip';
}
}
if (typeof visible === 'undefined') {
visible = interfaceConfig.TOOLBAR_BUTTONS.includes('recording')
&& (abstractProps.visible
|| Boolean(_fileRecordingsDisabledTooltipKey));
visible = interfaceConfig.TOOLBAR_BUTTONS.includes('recording') && abstractProps.visible;
}
return {
...abstractProps,
visible,
_disabled,
_fileRecordingsDisabledTooltipKey
visible
};
}
export default translate(connect(_mapStateToProps)(RecordButton));
export default translate(connect(_mapStateToProps)(AbstractRecordButton));

View File

@@ -84,8 +84,9 @@ export class AbstractClosedCaptionButton
*/
export function _abstractMapStateToProps(state: Object, ownProps: Object) {
const { _requestingSubtitles } = state['features/subtitles'];
const { isGuest = true } = state['features/base/jwt'];
const { transcribingEnabled } = state['features/base/config'];
const { visible = Boolean(transcribingEnabled) } = ownProps;
const { visible = Boolean(transcribingEnabled && !isGuest) } = ownProps;
return {
_requestingSubtitles,

View File

@@ -32,7 +32,8 @@ class ClosedCaptionButton
*/
export function mapStateToProps(state: Object, ownProps: Object) {
const { transcribingEnabled } = state['features/base/config'];
const enabled = getFeatureFlag(state, CLOSE_CAPTIONS_ENABLED, true) && transcribingEnabled;
const { isGuest = true } = state['features/base/jwt'];
const enabled = getFeatureFlag(state, CLOSE_CAPTIONS_ENABLED, true) && transcribingEnabled && !isGuest;
const { visible = enabled } = ownProps;
return {

View File

@@ -20,6 +20,11 @@ type Props = {
*/
_calendarEnabled: boolean,
/**
* Whether the insecure room name functionality is enabled or not.
*/
_enableInsecureRoomNameWarning: boolean,
/**
* Whether the recent list is enabled
*/
@@ -214,7 +219,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
_onRoomChange(value: string) {
this.setState({
room: value,
insecureRoomName: value && isInsecureRoomName(value)
insecureRoomName: this.props._enableInsecureRoomNameWarning && value && isInsecureRoomName(value)
});
}
@@ -226,7 +231,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
* @returns {ReactElement}
*/
_renderInsecureRoomNameWarning() {
if (this.state.insecureRoomName) {
if (this.props._enableInsecureRoomNameWarning && this.state.insecureRoomName) {
return this._doRenderInsecureRoomNameWarning();
}
@@ -273,6 +278,7 @@ export class AbstractWelcomePage extends Component<Props, *> {
export function _mapStateToProps(state: Object) {
return {
_calendarEnabled: isCalendarEnabled(state),
_enableInsecureRoomNameWarning: state['features/base/config'].enableInsecureRoomNameWarning || false,
_recentListEnabled: isRecentListEnabled(),
_room: state['features/base/conference'].room,
_settings: state['features/base/settings']