feat(jwt) deprecate and remove enableFeaturesBasedOnToken
The new behavior is as follows: IF a user has a token and `features` is not set, we treat it as if the feature was enabled. IF a user has a token and `features` is set, we check if the feature name has a value of "true". `isJwtFeatureEnabled` also provides a way to specify the default value in case there is no token.
This commit is contained in:
parent
bf222c5094
commit
77d687952d
|
@ -618,9 +618,6 @@ var config = {
|
||||||
// Hides the email section under profile settings.
|
// Hides the email section under profile settings.
|
||||||
// hideEmailInSettings: false,
|
// hideEmailInSettings: false,
|
||||||
|
|
||||||
// Whether or not some features are checked based on token.
|
|
||||||
// enableFeaturesBasedOnToken: false,
|
|
||||||
|
|
||||||
// When enabled the password used for locking a room is restricted to up to the number of digits specified
|
// When enabled the password used for locking a room is restricted to up to the number of digits specified
|
||||||
// default: roomPasswordNumberOfDigits: false,
|
// default: roomPasswordNumberOfDigits: false,
|
||||||
// roomPasswordNumberOfDigits: 10,
|
// roomPasswordNumberOfDigits: 10,
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
"defaultEmail": "Your Default Email",
|
"defaultEmail": "Your Default Email",
|
||||||
"disabled": "You can't invite people.",
|
"disabled": "You can't invite people.",
|
||||||
"failedToAdd": "Failed to add participants",
|
"failedToAdd": "Failed to add participants",
|
||||||
"footerText": "Dialing out is disabled.",
|
|
||||||
"googleEmail": "Google Email",
|
"googleEmail": "Google Email",
|
||||||
"inviteMoreHeader": "You are the only one in the meeting",
|
"inviteMoreHeader": "You are the only one in the meeting",
|
||||||
"inviteMoreMailSubject": "Join {{appName}} meeting",
|
"inviteMoreMailSubject": "Join {{appName}} meeting",
|
||||||
|
@ -286,7 +285,6 @@
|
||||||
"linkMeetingTitle": "Link meeting to Salesforce",
|
"linkMeetingTitle": "Link meeting to Salesforce",
|
||||||
"liveStreaming": "Live Streaming",
|
"liveStreaming": "Live Streaming",
|
||||||
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Not possible while recording is active",
|
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "Not possible while recording is active",
|
||||||
"liveStreamingDisabledTooltip": "Start live stream disabled.",
|
|
||||||
"localUserControls": "Local user controls",
|
"localUserControls": "Local user controls",
|
||||||
"lockMessage": "Failed to lock the conference.",
|
"lockMessage": "Failed to lock the conference.",
|
||||||
"lockRoom": "Add meeting $t(lockRoomPassword)",
|
"lockRoom": "Add meeting $t(lockRoomPassword)",
|
||||||
|
@ -341,7 +339,6 @@
|
||||||
"recentlyUsedObjects": "Your recently used objects",
|
"recentlyUsedObjects": "Your recently used objects",
|
||||||
"recording": "Recording",
|
"recording": "Recording",
|
||||||
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "Not possible while a live stream is active",
|
||||||
"recordingDisabledTooltip": "Start recording disabled.",
|
|
||||||
"rejoinNow": "Rejoin now",
|
"rejoinNow": "Rejoin now",
|
||||||
"remoteControlAllowedMessage": "{{user}} accepted your remote control request!",
|
"remoteControlAllowedMessage": "{{user}} accepted your remote control request!",
|
||||||
"remoteControlDeniedMessage": "{{user}} rejected your remote control request!",
|
"remoteControlDeniedMessage": "{{user}} rejected your remote control request!",
|
||||||
|
|
|
@ -260,7 +260,6 @@ export interface IConfig {
|
||||||
enableDisplayNameInStats?: boolean;
|
enableDisplayNameInStats?: boolean;
|
||||||
enableEmailInStats?: boolean;
|
enableEmailInStats?: boolean;
|
||||||
enableEncodedTransformSupport?: boolean;
|
enableEncodedTransformSupport?: boolean;
|
||||||
enableFeaturesBasedOnToken?: boolean;
|
|
||||||
enableForcedReload?: boolean;
|
enableForcedReload?: boolean;
|
||||||
enableIceRestart?: boolean;
|
enableIceRestart?: boolean;
|
||||||
enableInsecureRoomNameWarning?: boolean;
|
enableInsecureRoomNameWarning?: boolean;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import jwtDecode from 'jwt-decode';
|
import jwtDecode from 'jwt-decode';
|
||||||
|
|
||||||
|
import { getLocalParticipant } from '../participants/functions';
|
||||||
import { parseURLParams } from '../util';
|
import { parseURLParams } from '../util';
|
||||||
|
|
||||||
import { MEET_FEATURES } from './constants';
|
import { MEET_FEATURES } from './constants';
|
||||||
|
@ -31,6 +32,31 @@ export function getJwtName(state: Object) {
|
||||||
return user?.name;
|
return user?.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given JWT feature is enabled.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The app state.
|
||||||
|
* @param {string} feature - The feature we want to check.
|
||||||
|
* @param {boolean} ifNoToken - Default value if there is no token.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function isJwtFeatureEnabled(state: Object, feature: string, ifNoToken: boolean = false) {
|
||||||
|
const { jwt } = state['features/base/jwt'];
|
||||||
|
|
||||||
|
if (!jwt) {
|
||||||
|
return ifNoToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { features } = getLocalParticipant(state) || {};
|
||||||
|
|
||||||
|
// If `features` is undefined, act as if everything is enabled.
|
||||||
|
if (typeof features === 'undefined') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(features[feature]) === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a given timestamp is a valid UNIX timestamp in seconds.
|
* Checks whether a given timestamp is a valid UNIX timestamp in seconds.
|
||||||
* We convert to miliseconds during the check since `Date` works with miliseconds for UNIX timestamp values.
|
* We convert to miliseconds during the check since `Date` works with miliseconds for UNIX timestamp values.
|
||||||
|
|
|
@ -402,17 +402,6 @@ export function getParticipantPresenceStatus(
|
||||||
return participantById.presence;
|
return participantById.presence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if there is at least 1 participant with screen sharing feature and false otherwise.
|
|
||||||
*
|
|
||||||
* @param {(Function|Object)} stateful - The (whole) redux state, or redux's
|
|
||||||
* {@code getState} function to be used to retrieve the state.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function haveParticipantWithScreenSharingFeature(stateful: IStore | Function) {
|
|
||||||
return toState(stateful)['features/base/participants'].haveParticipantWithScreenSharingFeature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selectors for getting all remote participants.
|
* Selectors for getting all remote participants.
|
||||||
*
|
*
|
||||||
|
|
|
@ -101,7 +101,6 @@ const DEFAULT_STATE = {
|
||||||
dominantSpeaker: undefined,
|
dominantSpeaker: undefined,
|
||||||
everyoneIsModerator: false,
|
everyoneIsModerator: false,
|
||||||
fakeParticipants: new Map(),
|
fakeParticipants: new Map(),
|
||||||
haveParticipantWithScreenSharingFeature: false,
|
|
||||||
local: undefined,
|
local: undefined,
|
||||||
localScreenShare: undefined,
|
localScreenShare: undefined,
|
||||||
overwrittenNameList: {},
|
overwrittenNameList: {},
|
||||||
|
@ -118,7 +117,6 @@ export interface IParticipantsState {
|
||||||
dominantSpeaker?: string;
|
dominantSpeaker?: string;
|
||||||
everyoneIsModerator: boolean;
|
everyoneIsModerator: boolean;
|
||||||
fakeParticipants: Map<string, Participant>;
|
fakeParticipants: Map<string, Participant>;
|
||||||
haveParticipantWithScreenSharingFeature: boolean;
|
|
||||||
local?: LocalParticipant;
|
local?: LocalParticipant;
|
||||||
localScreenShare?: Participant;
|
localScreenShare?: Participant;
|
||||||
overwrittenNameList: Object;
|
overwrittenNameList: Object;
|
||||||
|
@ -255,14 +253,6 @@ ReducerRegistry.register('features/base/participants', (state: IParticipantsStat
|
||||||
} else if (!state.everyoneIsModerator && isModerator) {
|
} else if (!state.everyoneIsModerator && isModerator) {
|
||||||
state.everyoneIsModerator = _isEveryoneModerator(state);
|
state.everyoneIsModerator = _isEveryoneModerator(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// haveParticipantWithScreenSharingFeature calculation:
|
|
||||||
const { features = {} } = participant;
|
|
||||||
|
|
||||||
// Currently we use only PARTICIPANT_UPDATED to set a feature to enabled and we never disable it.
|
|
||||||
if (String(features['screen-sharing']) === 'true') {
|
|
||||||
state.haveParticipantWithScreenSharingFeature = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -401,26 +391,6 @@ ReducerRegistry.register('features/base/participants', (state: IParticipantsStat
|
||||||
state.everyoneIsModerator = _isEveryoneModerator(state);
|
state.everyoneIsModerator = _isEveryoneModerator(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { features = {} } = oldParticipant || {};
|
|
||||||
|
|
||||||
if (state.haveParticipantWithScreenSharingFeature && String(features['screen-sharing']) === 'true') {
|
|
||||||
const { features: localFeatures = {} } = state.local || {};
|
|
||||||
|
|
||||||
if (String(localFeatures['screen-sharing']) !== 'true') {
|
|
||||||
state.haveParticipantWithScreenSharingFeature = false;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
for (const [ key, participant ] of state.remote) {
|
|
||||||
const { features: f = {} } = participant;
|
|
||||||
|
|
||||||
if (String(f['screen-sharing']) === 'true') {
|
|
||||||
state.haveParticipantWithScreenSharingFeature = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dominantSpeaker === id) {
|
if (dominantSpeaker === id) {
|
||||||
state.dominantSpeaker = undefined;
|
state.dominantSpeaker = undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,8 @@ import React from 'react';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { Avatar } from '../../../../base/avatar';
|
import { Avatar } from '../../../../base/avatar';
|
||||||
import { translate, translateToHTML } from '../../../../base/i18n';
|
import { translate } from '../../../../base/i18n';
|
||||||
import { Icon, IconPhone } from '../../../../base/icons';
|
import { Icon, IconPhone } from '../../../../base/icons';
|
||||||
import { getLocalParticipant } from '../../../../base/participants';
|
|
||||||
import { MultiSelectAutocomplete } from '../../../../base/react';
|
import { MultiSelectAutocomplete } from '../../../../base/react';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux';
|
||||||
import { isVpaasMeeting } from '../../../../jaas/functions';
|
import { isVpaasMeeting } from '../../../../jaas/functions';
|
||||||
|
@ -28,11 +27,6 @@ type Props = AbstractProps & {
|
||||||
*/
|
*/
|
||||||
_conference: Object,
|
_conference: Object,
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to show a footer text after the search results as a last element.
|
|
||||||
*/
|
|
||||||
_footerTextEnabled: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the meeting belongs to JaaS user.
|
* Whether the meeting belongs to JaaS user.
|
||||||
*/
|
*/
|
||||||
|
@ -83,7 +77,6 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
this._onSubmitKeyPress = this._onSubmitKeyPress.bind(this);
|
this._onSubmitKeyPress = this._onSubmitKeyPress.bind(this);
|
||||||
this._parseQueryResults = this._parseQueryResults.bind(this);
|
this._parseQueryResults = this._parseQueryResults.bind(this);
|
||||||
this._setMultiSelectElement = this._setMultiSelectElement.bind(this);
|
this._setMultiSelectElement = this._setMultiSelectElement.bind(this);
|
||||||
this._renderFooterText = this._renderFooterText.bind(this);
|
|
||||||
this._onKeyDown = this._onKeyDown.bind(this);
|
this._onKeyDown = this._onKeyDown.bind(this);
|
||||||
|
|
||||||
this._resourceClient = {
|
this._resourceClient = {
|
||||||
|
@ -135,7 +128,6 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
_sipInviteEnabled,
|
_sipInviteEnabled,
|
||||||
t
|
t
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const footerText = this._renderFooterText();
|
|
||||||
let isMultiSelectDisabled = this.state.addToCallInProgress;
|
let isMultiSelectDisabled = this.state.addToCallInProgress;
|
||||||
const loadingMessage = 'addPeople.searching';
|
const loadingMessage = 'addPeople.searching';
|
||||||
const noMatches = 'addPeople.noResults';
|
const noMatches = 'addPeople.noResults';
|
||||||
|
@ -163,7 +155,6 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
onKeyDown = { this._onKeyDown }>
|
onKeyDown = { this._onKeyDown }>
|
||||||
{ this._renderErrorMessage() }
|
{ this._renderErrorMessage() }
|
||||||
<MultiSelectAutocomplete
|
<MultiSelectAutocomplete
|
||||||
footer = { footerText }
|
|
||||||
isDisabled = { isMultiSelectDisabled }
|
isDisabled = { isMultiSelectDisabled }
|
||||||
loadingMessage = { t(loadingMessage) }
|
loadingMessage = { t(loadingMessage) }
|
||||||
noMatchesFound = { t(noMatches) }
|
noMatchesFound = { t(noMatches) }
|
||||||
|
@ -404,33 +395,6 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
|
|
||||||
_query: (string) => Promise<Array<Object>>;
|
_query: (string) => Promise<Array<Object>>;
|
||||||
|
|
||||||
_renderFooterText: () => Object;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the rendering of the footer text, if enabled.
|
|
||||||
*
|
|
||||||
* @returns {Object | undefined}
|
|
||||||
*/
|
|
||||||
_renderFooterText() {
|
|
||||||
const { _footerTextEnabled, t } = this.props;
|
|
||||||
let footerText;
|
|
||||||
|
|
||||||
if (_footerTextEnabled) {
|
|
||||||
footerText = {
|
|
||||||
content: <div className = 'footer-text-wrap'>
|
|
||||||
<div>
|
|
||||||
<span className = 'footer-telephone-icon'>
|
|
||||||
<Icon src = { IconPhone } />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{ translateToHTML(t, 'addPeople.footerText') }
|
|
||||||
</div>
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return footerText;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onClearItems: () => void;
|
_onClearItems: () => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -580,20 +544,8 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state) {
|
function _mapStateToProps(state) {
|
||||||
const { enableFeaturesBasedOnToken } = state['features/base/config'];
|
|
||||||
let footerTextEnabled = false;
|
|
||||||
|
|
||||||
if (enableFeaturesBasedOnToken) {
|
|
||||||
const { features = {} } = getLocalParticipant(state);
|
|
||||||
|
|
||||||
if (String(features['outbound-call']) !== 'true') {
|
|
||||||
footerTextEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
..._abstractMapStateToProps(state),
|
..._abstractMapStateToProps(state),
|
||||||
_footerTextEnabled: footerTextEnabled,
|
|
||||||
_isVpaas: isVpaasMeeting(state)
|
_isVpaas: isVpaasMeeting(state)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { getRoomName } from '../base/conference';
|
||||||
import { getInviteURL } from '../base/connection';
|
import { getInviteURL } from '../base/connection';
|
||||||
import { isIosMobileBrowser } from '../base/environment/utils';
|
import { isIosMobileBrowser } from '../base/environment/utils';
|
||||||
import { i18next } from '../base/i18n';
|
import { i18next } from '../base/i18n';
|
||||||
|
import { isJwtFeatureEnabled } from '../base/jwt/functions';
|
||||||
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
||||||
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
|
@ -410,11 +411,8 @@ export function isDialOutEnabled(state: Object): boolean {
|
||||||
*/
|
*/
|
||||||
export function isSipInviteEnabled(state: Object): boolean {
|
export function isSipInviteEnabled(state: Object): boolean {
|
||||||
const { sipInviteUrl } = state['features/base/config'];
|
const { sipInviteUrl } = state['features/base/config'];
|
||||||
const { features = {} } = getLocalParticipant(state) || {};
|
|
||||||
|
|
||||||
return state['features/base/jwt'].jwt
|
return isJwtFeatureEnabled(state, 'sip-outbound-call') && Boolean(sipInviteUrl);
|
||||||
&& Boolean(sipInviteUrl)
|
|
||||||
&& String(features['sip-outbound-call']) === 'true';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { IconLiveStreaming } from '../../../base/icons';
|
import { IconLiveStreaming } from '../../../base/icons';
|
||||||
|
import { isJwtFeatureEnabled } from '../../../base/jwt/functions';
|
||||||
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
|
||||||
import {
|
import { isLocalParticipantModerator } from '../../../base/participants';
|
||||||
getLocalParticipant,
|
|
||||||
isLocalParticipantModerator
|
|
||||||
} from '../../../base/participants';
|
|
||||||
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
|
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
|
||||||
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
|
||||||
import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
|
import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
|
||||||
|
@ -134,36 +132,22 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||||
|
|
||||||
// A button can be disabled/enabled only if enableFeaturesBasedOnToken
|
// A button can be disabled/enabled only if enableFeaturesBasedOnToken
|
||||||
// is on or if the recording is running.
|
// is on or if the recording is running.
|
||||||
let _disabled;
|
let _disabled = false;
|
||||||
let _tooltip = '';
|
let _tooltip = '';
|
||||||
|
|
||||||
if (typeof visible === 'undefined') {
|
if (typeof visible === 'undefined') {
|
||||||
// If the containing component provides the visible prop, that is one
|
// If the containing component provides the visible prop, that is one
|
||||||
// above all, but if not, the button should be autonomus and decide on
|
// above all, but if not, the button should be autonomous and decide on
|
||||||
// its own to be visible or not.
|
// its own to be visible or not.
|
||||||
const isModerator = isLocalParticipantModerator(state);
|
const isModerator = isLocalParticipantModerator(state);
|
||||||
const {
|
|
||||||
enableFeaturesBasedOnToken
|
|
||||||
} = state['features/base/config'];
|
|
||||||
const liveStreaming = getLiveStreaming(state);
|
const liveStreaming = getLiveStreaming(state);
|
||||||
const { features = {} } = getLocalParticipant(state);
|
|
||||||
|
|
||||||
visible = isModerator && liveStreaming.enabled;
|
visible = isModerator && liveStreaming.enabled;
|
||||||
|
visible = isJwtFeatureEnabled(state, 'livestreaming', visible);
|
||||||
if (enableFeaturesBasedOnToken) {
|
|
||||||
visible = visible && String(features.livestreaming) === 'true';
|
|
||||||
_disabled = String(features.livestreaming) === 'disabled';
|
|
||||||
|
|
||||||
if (!visible && !_disabled) {
|
|
||||||
_disabled = true;
|
|
||||||
visible = true;
|
|
||||||
_tooltip = 'dialog.liveStreamingDisabledTooltip';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable the button if the recording is running.
|
// disable the button if the recording is running.
|
||||||
if (getActiveSession(state, JitsiRecordingConstants.mode.FILE)) {
|
if (visible && getActiveSession(state, JitsiRecordingConstants.mode.FILE)) {
|
||||||
_disabled = true;
|
_disabled = true;
|
||||||
_tooltip = 'dialog.liveStreamingDisabledBecauseOfActiveRecordingTooltip';
|
_tooltip = 'dialog.liveStreamingDisabledBecauseOfActiveRecordingTooltip';
|
||||||
}
|
}
|
||||||
|
@ -176,8 +160,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_disabled,
|
_disabled,
|
||||||
_isLiveStreamRunning: Boolean(
|
_isLiveStreamRunning: Boolean(getActiveSession(state, JitsiRecordingConstants.mode.STREAM)),
|
||||||
getActiveSession(state, JitsiRecordingConstants.mode.STREAM)),
|
|
||||||
_tooltip,
|
_tooltip,
|
||||||
visible
|
visible
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { isMobileBrowser } from '../base/environment/utils';
|
import { isMobileBrowser } from '../base/environment/utils';
|
||||||
|
import { isJwtFeatureEnabled } from '../base/jwt/functions';
|
||||||
import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
|
||||||
import { getLocalParticipant, getRemoteParticipants, isLocalParticipantModerator } from '../base/participants';
|
import { getLocalParticipant, getRemoteParticipants, isLocalParticipantModerator } from '../base/participants';
|
||||||
import { isInBreakoutRoom } from '../breakout-rooms/functions';
|
import { isInBreakoutRoom } from '../breakout-rooms/functions';
|
||||||
|
@ -153,7 +154,7 @@ export function getRecordButtonProps(state: Object): ?string {
|
||||||
|
|
||||||
// a button can be disabled/enabled if enableFeaturesBasedOnToken
|
// a button can be disabled/enabled if enableFeaturesBasedOnToken
|
||||||
// is on or if the livestreaming is running.
|
// is on or if the livestreaming is running.
|
||||||
let disabled;
|
let disabled = false;
|
||||||
let tooltip = '';
|
let tooltip = '';
|
||||||
|
|
||||||
// If the containing component provides the visible prop, that is one
|
// If the containing component provides the visible prop, that is one
|
||||||
|
@ -161,29 +162,18 @@ export function getRecordButtonProps(state: Object): ?string {
|
||||||
// its own to be visible or not.
|
// its own to be visible or not.
|
||||||
const isModerator = isLocalParticipantModerator(state);
|
const isModerator = isLocalParticipantModerator(state);
|
||||||
const {
|
const {
|
||||||
enableFeaturesBasedOnToken,
|
|
||||||
recordingService,
|
recordingService,
|
||||||
localRecording
|
localRecording
|
||||||
} = state['features/base/config'];
|
} = state['features/base/config'];
|
||||||
const { features = {} } = getLocalParticipant(state);
|
|
||||||
const localRecordingEnabled = !localRecording?.disable && supportsLocalRecording();
|
const localRecordingEnabled = !localRecording?.disable && supportsLocalRecording();
|
||||||
|
|
||||||
const dropboxEnabled = isDropboxEnabled(state);
|
const dropboxEnabled = isDropboxEnabled(state);
|
||||||
|
|
||||||
visible = isModerator && (recordingService?.enabled || localRecordingEnabled || dropboxEnabled);
|
visible = isModerator && (recordingService?.enabled || localRecordingEnabled || dropboxEnabled);
|
||||||
|
visible = isJwtFeatureEnabled(state, 'recording', visible);
|
||||||
if (enableFeaturesBasedOnToken) {
|
|
||||||
visible = visible && String(features.recording) === 'true';
|
|
||||||
disabled = String(features.recording) === 'disabled';
|
|
||||||
if (!visible && !disabled) {
|
|
||||||
disabled = true;
|
|
||||||
visible = true;
|
|
||||||
tooltip = 'dialog.recordingDisabledTooltip';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable the button if the livestreaming is running.
|
// disable the button if the livestreaming is running.
|
||||||
if (getActiveSession(state, JitsiRecordingConstants.mode.STREAM)) {
|
if (visible && getActiveSession(state, JitsiRecordingConstants.mode.STREAM)) {
|
||||||
disabled = true;
|
disabled = true;
|
||||||
tooltip = 'dialog.recordingDisabledBecauseOfActiveLiveStreamingTooltip';
|
tooltip = 'dialog.recordingDisabledBecauseOfActiveLiveStreamingTooltip';
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,26 +10,20 @@ import { isDesktopShareButtonDisabled } from '../../functions';
|
||||||
|
|
||||||
type Props = AbstractButtonProps & {
|
type Props = AbstractButtonProps & {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not screensharing is initialized.
|
* Whether or not screensharing is initialized.
|
||||||
*/
|
*/
|
||||||
_desktopSharingEnabled: boolean,
|
_desktopSharingEnabled: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* The tooltip key to use when screensharing is disabled. Or undefined
|
|
||||||
* if non to be shown and the button to be hidden.
|
|
||||||
*/
|
|
||||||
_desktopSharingDisabledTooltipKey: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the local participant is screensharing.
|
* Whether or not the local participant is screensharing.
|
||||||
*/
|
*/
|
||||||
_screensharing: boolean,
|
_screensharing: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The redux {@code dispatch} function.
|
* The redux {@code dispatch} function.
|
||||||
*/
|
*/
|
||||||
dispatch: Function,
|
dispatch: Function,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +40,7 @@ class ShareDesktopButton extends AbstractButton<Props, *> {
|
||||||
* Retrieves tooltip dynamically.
|
* Retrieves tooltip dynamically.
|
||||||
*/
|
*/
|
||||||
get tooltip() {
|
get tooltip() {
|
||||||
const { _desktopSharingDisabledTooltipKey, _desktopSharingEnabled, _screensharing } = this.props;
|
const { _desktopSharingEnabled, _screensharing } = this.props;
|
||||||
|
|
||||||
if (_desktopSharingEnabled) {
|
if (_desktopSharingEnabled) {
|
||||||
if (_screensharing) {
|
if (_screensharing) {
|
||||||
|
@ -56,7 +50,7 @@ class ShareDesktopButton extends AbstractButton<Props, *> {
|
||||||
return 'toolbar.startScreenSharing';
|
return 'toolbar.startScreenSharing';
|
||||||
}
|
}
|
||||||
|
|
||||||
return _desktopSharingDisabledTooltipKey;
|
return 'dialog.shareYourScreenDisabled';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,23 +92,12 @@ class ShareDesktopButton extends AbstractButton<Props, *> {
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
let desktopSharingEnabled = JitsiMeetJS.isDesktopSharingEnabled();
|
|
||||||
const { enableFeaturesBasedOnToken } = state['features/base/config'];
|
|
||||||
let desktopSharingDisabledTooltipKey;
|
|
||||||
|
|
||||||
if (enableFeaturesBasedOnToken) {
|
|
||||||
// we enable desktop sharing if any participant already have this
|
|
||||||
// feature enabled
|
|
||||||
desktopSharingEnabled = state['features/base/participants'].haveParticipantWithScreenSharingFeature;
|
|
||||||
desktopSharingDisabledTooltipKey = 'dialog.shareYourScreenDisabled';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the screenshare button if the video sender limit is reached and there is no video or media share in
|
// Disable the screenshare button if the video sender limit is reached and there is no video or media share in
|
||||||
// progress.
|
// progress.
|
||||||
desktopSharingEnabled = desktopSharingEnabled && !isDesktopShareButtonDisabled(state);
|
const desktopSharingEnabled
|
||||||
|
= JitsiMeetJS.isDesktopSharingEnabled() && !isDesktopShareButtonDisabled(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_desktopSharingDisabledTooltipKey: desktopSharingDisabledTooltipKey,
|
|
||||||
_desktopSharingEnabled: desktopSharingEnabled,
|
_desktopSharingEnabled: desktopSharingEnabled,
|
||||||
_screensharing: isScreenVideoShared(state)
|
_screensharing: isScreenVideoShared(state)
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,6 @@ import JitsiMeetJS from '../../../base/lib-jitsi-meet';
|
||||||
import {
|
import {
|
||||||
getLocalParticipant,
|
getLocalParticipant,
|
||||||
hasRaisedHand,
|
hasRaisedHand,
|
||||||
haveParticipantWithScreenSharingFeature,
|
|
||||||
raiseHand
|
raiseHand
|
||||||
} from '../../../base/participants';
|
} from '../../../base/participants';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
|
@ -133,12 +132,6 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_desktopSharingButtonDisabled: boolean,
|
_desktopSharingButtonDisabled: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* The tooltip key to use when screensharing is disabled. Or undefined
|
|
||||||
* if non to be shown and the button to be hidden.
|
|
||||||
*/
|
|
||||||
_desktopSharingDisabledTooltipKey: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not screensharing is initialized.
|
* Whether or not screensharing is initialized.
|
||||||
*/
|
*/
|
||||||
|
@ -1274,12 +1267,7 @@ class Toolbox extends Component<Props> {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
_showDesktopSharingButton() {
|
_showDesktopSharingButton() {
|
||||||
const {
|
return this.props._desktopSharingEnabled;
|
||||||
_desktopSharingEnabled,
|
|
||||||
_desktopSharingDisabledTooltipKey
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return _desktopSharingEnabled || _desktopSharingDisabledTooltipKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1408,12 +1396,10 @@ class Toolbox extends Component<Props> {
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state, ownProps) {
|
function _mapStateToProps(state, ownProps) {
|
||||||
const { conference } = state['features/base/conference'];
|
const { conference } = state['features/base/conference'];
|
||||||
let desktopSharingEnabled = JitsiMeetJS.isDesktopSharingEnabled();
|
|
||||||
const {
|
const {
|
||||||
buttonsWithNotifyClick,
|
buttonsWithNotifyClick,
|
||||||
callStatsID,
|
callStatsID,
|
||||||
disableProfile,
|
disableProfile,
|
||||||
enableFeaturesBasedOnToken,
|
|
||||||
iAmRecorder,
|
iAmRecorder,
|
||||||
iAmSipGateway
|
iAmSipGateway
|
||||||
} = state['features/base/config'];
|
} = state['features/base/config'];
|
||||||
|
@ -1425,18 +1411,6 @@ function _mapStateToProps(state, ownProps) {
|
||||||
const localParticipant = getLocalParticipant(state);
|
const localParticipant = getLocalParticipant(state);
|
||||||
const localVideo = getLocalVideoTrack(state['features/base/tracks']);
|
const localVideo = getLocalVideoTrack(state['features/base/tracks']);
|
||||||
const { clientWidth } = state['features/base/responsive-ui'];
|
const { clientWidth } = state['features/base/responsive-ui'];
|
||||||
|
|
||||||
let desktopSharingDisabledTooltipKey;
|
|
||||||
|
|
||||||
if (enableFeaturesBasedOnToken) {
|
|
||||||
if (desktopSharingEnabled) {
|
|
||||||
// we enable desktop sharing if any participant already have this
|
|
||||||
// feature enabled and if the user supports it.
|
|
||||||
desktopSharingEnabled = haveParticipantWithScreenSharingFeature(state);
|
|
||||||
desktopSharingDisabledTooltipKey = 'dialog.shareYourScreenDisabled';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toolbarButtons = ownProps.toolbarButtons || getToolbarButtons(state);
|
const toolbarButtons = ownProps.toolbarButtons || getToolbarButtons(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1445,9 +1419,8 @@ function _mapStateToProps(state, ownProps) {
|
||||||
_chatOpen: state['features/chat'].isOpen,
|
_chatOpen: state['features/chat'].isOpen,
|
||||||
_clientWidth: clientWidth,
|
_clientWidth: clientWidth,
|
||||||
_conference: conference,
|
_conference: conference,
|
||||||
_desktopSharingEnabled: desktopSharingEnabled,
|
_desktopSharingEnabled: JitsiMeetJS.isDesktopSharingEnabled(),
|
||||||
_desktopSharingButtonDisabled: isDesktopShareButtonDisabled(state),
|
_desktopSharingButtonDisabled: isDesktopShareButtonDisabled(state),
|
||||||
_desktopSharingDisabledTooltipKey: desktopSharingDisabledTooltipKey,
|
|
||||||
_dialog: Boolean(state['features/base/dialog'].component),
|
_dialog: Boolean(state['features/base/dialog'].component),
|
||||||
_disabled: Boolean(iAmRecorder || iAmSipGateway),
|
_disabled: Boolean(iAmRecorder || iAmSipGateway),
|
||||||
_feedbackConfigured: Boolean(callStatsID),
|
_feedbackConfigured: Boolean(callStatsID),
|
||||||
|
|
Loading…
Reference in New Issue