diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods.js b/bigbluebutton-html5/imports/api/meetings/server/methods.js old mode 100644 new mode 100755 index 74401c1b1544f0637d7245e0574139d6ccdf3165..960ef8082efae97b4e628dc50ec470774f70c746 --- a/bigbluebutton-html5/imports/api/meetings/server/methods.js +++ b/bigbluebutton-html5/imports/api/meetings/server/methods.js @@ -2,9 +2,13 @@ import { Meteor } from 'meteor/meteor'; import endMeeting from './methods/endMeeting'; import toggleRecording from './methods/toggleRecording'; import transferUser from './methods/transferUser'; +import toggleLockSettings from './methods/toggleLockSettings'; +import toggleWebcamsOnlyForModerator from './methods/toggleWebcamsOnlyForModerator'; Meteor.methods({ endMeeting, toggleRecording, + toggleLockSettings, transferUser, + toggleWebcamsOnlyForModerator, }); diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js new file mode 100755 index 0000000000000000000000000000000000000000..ee59cf102e9ed1b70e138abff731bbe21d08edce --- /dev/null +++ b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js @@ -0,0 +1,37 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import RedisPubSub from '/imports/startup/server/redis'; + +export default function toggleLockSettings(credentials, meeting) { + const REDIS_CONFIG = Meteor.settings.private.redis; + const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; + const EVENT_NAME = 'ChangeLockSettingsInMeetingCmdMsg'; + + const { meetingId, requesterUserId } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(meeting.lockSettingsProp, { + disableCam: Boolean, + disableMic: Boolean, + disablePrivChat: Boolean, + disablePubChat: Boolean, + lockedLayout: Boolean, + lockOnJoin: Boolean, + lockOnJoinConfigurable: Boolean, + setBy: String, + }); + + const payload = { + disableCam: meeting.lockSettingsProp.disableCam, + disableMic: meeting.lockSettingsProp.disableMic, + disablePrivChat: meeting.lockSettingsProp.disablePrivChat, + disablePubChat: meeting.lockSettingsProp.disablePubChat, + lockedLayout: meeting.lockSettingsProp.lockedLayout, + lockOnJoin: meeting.lockSettingsProp.lockOnJoin, + lockOnJoinConfigurable: meeting.lockSettingsProp.lockOnJoinConfigurable, + setBy: requesterUserId, + }; + + RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js new file mode 100755 index 0000000000000000000000000000000000000000..75f052de76503bc36967c966e157d4cbcb6a063d --- /dev/null +++ b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js @@ -0,0 +1,22 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import RedisPubSub from '/imports/startup/server/redis'; + +export default function toggleWebcamsOnlyForModerator(credentials, meeting) { + const REDIS_CONFIG = Meteor.settings.private.redis; + const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; + const EVENT_NAME = 'UpdateWebcamsOnlyForModeratorCmdMsg'; + + const { meetingId, requesterUserId } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(meeting.usersProp.webcamsOnlyForModerator, Boolean); + + const payload = { + webcamsOnlyForModerator: meeting.usersProp.webcamsOnlyForModerator, + setBy: requesterUserId, + }; + + RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js index a8023da3626343ddc0c50c913caba9062494b8e0..f8011fd0d32225429338b6252eefd78af4307bc8 100644 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js @@ -69,10 +69,22 @@ export default function addMeeting(meeting) { meetingId, }; + const lockSettingsProp = { + disableCam: false, + disableMic: false, + disablePrivChat: false, + disablePubChat: false, + lockOnJoin: true, + lockOnJoinConfigurable: false, + lockedLayout: false, + setBy: 'temp', + }; + const modifier = { $set: Object.assign( { meetingId }, flat(meeting, { safe: true }), + { lockSettingsProp }, ), }; diff --git a/bigbluebutton-html5/imports/startup/server/logger.js b/bigbluebutton-html5/imports/startup/server/logger.js old mode 100755 new mode 100644 diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx index 865c0278339cdf30936bc7ab442068cf668c3b89..bada062b60acda6b11a2bdf8a9aca362dbb639fd 100755 --- a/bigbluebutton-html5/imports/ui/components/app/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx @@ -8,6 +8,7 @@ import Resizable from 're-resizable'; import browser from 'browser-detect'; import BreakoutRoomContainer from '/imports/ui/components/breakout-room/container'; import PollingContainer from '/imports/ui/components/polling/container'; +import PollContainer from '/imports/ui/components/poll/container'; import ToastContainer from '../toast/container'; import ModalContainer from '../modal/container'; import NotificationsBarContainer from '../notifications-bar/container'; @@ -16,7 +17,7 @@ import ChatAlertContainer from '../chat/alert/container'; import { styles } from './styles'; import UserListContainer from '../user-list/container'; import ChatContainer from '../chat/container'; -import PollContainer from '/imports/ui/components/poll/container'; + const MOBILE_MEDIA = 'only screen and (max-width: 40em)'; const USERLIST_COMPACT_WIDTH = 50; @@ -327,7 +328,7 @@ class App extends Component { render() { const { - userListIsOpen, customStyle, customStyleUrl, + userListIsOpen, customStyle, customStyleUrl, micsLocked, } = this.props; const { enableResize } = this.state; @@ -349,11 +350,11 @@ class App extends Component { </section> <PollingContainer /> <ModalContainer /> - <AudioContainer /> + {micsLocked ? null : <AudioContainer />} <ToastContainer /> <ChatAlertContainer /> - { customStyleUrl ? <link rel="stylesheet" type="text/css" href={customStyleUrl} /> : null } - { customStyle ? <link rel="stylesheet" type="text/css" href={`data:text/css;charset=UTF-8,${encodeURIComponent(customStyle)}`} /> : null } + {customStyleUrl ? <link rel="stylesheet" type="text/css" href={customStyleUrl} /> : null} + {customStyle ? <link rel="stylesheet" type="text/css" href={`data:text/css;charset=UTF-8,${encodeURIComponent(customStyle)}`} /> : null} </main> ); } diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx index 600aee257851fedf1a23fe30c9df4aa3645db74a..748cb89be8ec13593c8c45b0b900197986026cd7 100755 --- a/bigbluebutton-html5/imports/ui/components/app/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx @@ -70,6 +70,7 @@ const AppContainer = (props) => { export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) => { const currentUser = Users.findOne({ userId: Auth.userID }); + const meeting = Meetings.findOne({ meetingId: Auth.meetingID }); const isMeetingBreakout = meetingIsBreakout(); if (!currentUser.approved) { @@ -117,6 +118,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) pollIsOpen: Session.get('isPollOpen') && Session.get('isUserListOpen'), customStyle: getFromUserSettings('customStyle', false), customStyleUrl: getFromUserSettings('customStyleUrl', false), + micsLocked: (currentUser.locked && meeting.lockSettingsProp.disableMic), }; })(AppContainer))); diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx index 6e7124fad1da3e9b40beda8021e76b0b75e2701d..6211484d91a0473c476140b9080374fd5fee53ab 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -3,6 +3,9 @@ import { withTracker } from 'meteor/react-meteor-data'; import { withModalMounter } from '/imports/ui/components/modal/service'; import AudioManager from '/imports/ui/services/audio-manager'; import { makeCall } from '/imports/ui/services/api'; +import Users from '/imports/api/users/'; +import Meetings from '/imports/api/meetings'; +import Auth from '/imports/ui/services/auth'; import AudioControls from './component'; import AudioModalContainer from '../audio-modal/container'; import Service from '../service'; @@ -40,6 +43,12 @@ export default withModalMounter(withTracker(({ mountModal }) => disable: Service.isConnecting() || Service.isHangingUp(), glow: Service.isTalking() && !Service.isMuted(), handleToggleMuteMicrophone: () => Service.toggleMuteMicrophone(), - handleJoinAudio: () => mountModal(<AudioModalContainer />), + handleJoinAudio: () => { + const meeting = Meetings.findOne({ meetingId: Auth.meetingID }); + const currentUser = Users.findOne({ userId: Auth.userID }); + const micsLocked = (currentUser.locked && meeting.lockSettingsProp.disableMic); + + return micsLocked ? Service.joinListenOnly() : mountModal(<AudioModalContainer />); + }, handleLeaveAudio: () => Service.exitAudio(), }))(AudioControlsContainer)); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx b/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx new file mode 100755 index 0000000000000000000000000000000000000000..7c89ec1f1bbd035f3a1316caded8e3081dc9efb3 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx @@ -0,0 +1,251 @@ +import React, { Component } from 'react'; +import { defineMessages, injectIntl } from 'react-intl'; +import Button from '/imports/ui/components/button/component'; +import Toggle from '/imports/ui/components/switch/component'; +import cx from 'classnames'; +import ModalBase from '/imports/ui/components/modal/base/component'; +import { styles } from './styles'; + +const intlMessages = defineMessages({ + lockViewersTitle: { + id: 'app.lock-viewers.title', + description: 'lock-viewers title', + }, + closeLabel: { + id: 'app.shortcut-help.closeLabel', + description: 'label for close button', + }, + closeDesc: { + id: 'app.shortcut-help.closeDesc', + description: 'description for close button', + }, + lockViewersDescription: { + id: 'app.lock-viewers.description', + description: 'description for lock viewers feature', + }, + featuresLable: { + id: 'app.lock-viewers.featuresLable', + description: 'features label', + }, + lockStatusLabel: { + id: 'app.lock-viewers.lockStatusLabel', + description: 'description for close button', + }, + webcamLabel: { + id: 'app.lock-viewers.webcamLabel', + description: 'description for close button', + }, + otherViewersWebcamLabel: { + id: 'app.lock-viewers.otherViewersWebcamLabel', + description: 'description for close button', + }, + microphoneLable: { + id: 'app.lock-viewers.microphoneLable', + description: 'description for close button', + }, + publicChatLabel: { + id: 'app.lock-viewers.PublicChatLabel', + description: 'description for close button', + }, + privateChatLable: { + id: 'app.lock-viewers.PrivateChatLable', + description: 'description for close button', + }, + layoutLable: { + id: 'app.lock-viewers.Layout', + description: 'description for close button', + }, +}); + +class LockViewersComponent extends Component { + constructor(props) { + super(props); + const { + closeModal, + toggleLockSettings, + toggleWebcamsOnlyForModerator, + } = props; + + this.closeModal = closeModal; + this.toggleLockSettings = toggleLockSettings; + this.toggleWebcamsOnlyForModerator = toggleWebcamsOnlyForModerator; + } + + render() { + const { intl, meeting } = this.props; + + return ( + <ModalBase + overlayClassName={styles.overlay} + className={styles.modal} + onRequestClose={this.closeModal} + > + + <div className={styles.container}> + <div className={styles.header}> + <div className={styles.title}>{intl.formatMessage(intlMessages.lockViewersTitle)}</div> + <Button + data-test="modalBaseCloseButton" + className={styles.closeBtn} + label={intl.formatMessage(intlMessages.closeLabel)} + icon="close" + size="md" + hideLabel + onClick={this.closeModal} + /> + </div> + <div className={styles.description}> + {`${intl.formatMessage(intlMessages.lockViewersDescription)}`} + </div> + + <div className={styles.form}> + <header className={styles.subHeader}> + <div className={styles.bold}>{intl.formatMessage(intlMessages.featuresLable)}</div> + <div className={styles.bold}>{intl.formatMessage(intlMessages.lockStatusLabel)}</div> + </header> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.webcamLabel)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.lockSettingsProp.disableCam} + onChange={() => { + meeting.lockSettingsProp.disableCam = + !meeting.lockSettingsProp.disableCam; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.webcamLabel)} + /> + </div> + </div> + </div> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.otherViewersWebcamLabel)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.usersProp.webcamsOnlyForModerator} + onChange={() => { + meeting.usersProp.webcamsOnlyForModerator = + !meeting.usersProp.webcamsOnlyForModerator; + this.toggleWebcamsOnlyForModerator(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.otherViewersWebcamLabel)} + /> + </div> + </div> + </div> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.microphoneLable)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.lockSettingsProp.disableMic} + onChange={() => { + meeting.lockSettingsProp.disableMic = + !meeting.lockSettingsProp.disableMic; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.microphoneLable)} + /> + </div> + </div> + </div> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.publicChatLabel)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.lockSettingsProp.disablePubChat} + onChange={() => { + meeting.lockSettingsProp.disablePubChat = + !meeting.lockSettingsProp.disablePubChat; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.publicChatLabel)} + /> + </div> + </div> + </div> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.privateChatLable)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.lockSettingsProp.disablePrivChat} + onChange={() => { + meeting.lockSettingsProp.disablePrivChat = + !meeting.lockSettingsProp.disablePrivChat; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.privateChatLable)} + /> + </div> + </div> + </div> + <div className={styles.row}> + <div className={styles.col} aria-hidden="true"> + <div className={styles.formElement}> + <div className={styles.label}> + {intl.formatMessage(intlMessages.layoutLable)} + </div> + </div> + </div> + <div className={styles.col}> + <div className={cx(styles.formElement, styles.pullContentRight)}> + <Toggle + icons={false} + defaultChecked={meeting.lockSettingsProp.lockedLayout} + onChange={() => { + meeting.lockSettingsProp.lockedLayout = + !meeting.lockSettingsProp.lockedLayout; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.layoutLable)} + /> + </div> + </div> + </div> + </div> + </div> + </ModalBase> + ); + } +} + +export default injectIntl(LockViewersComponent); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx b/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx new file mode 100755 index 0000000000000000000000000000000000000000..2ce4edcc89e00bac16de77a4dbc5c48e4f60b8ea --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { withTracker } from 'meteor/react-meteor-data'; +import { withModalMounter } from '/imports/ui/components/modal/service'; +import { makeCall } from '/imports/ui/services/api'; +import Meetings from '/imports/api/meetings'; +import Auth from '/imports/ui/services/auth'; +import LockViewersComponent from './component'; + +const LockViewersContainer = props => <LockViewersComponent {...props} />; + +export default withModalMounter(withTracker(({ mountModal }) => ({ + closeModal() { + mountModal(null); + }, + + toggleLockSettings(meeting) { + makeCall('toggleLockSettings', meeting); + }, + + toggleWebcamsOnlyForModerator(meeting) { + makeCall('toggleWebcamsOnlyForModerator', meeting); + }, + meeting: (Meetings.findOne({ meetingId: Auth.meetingID })), +}))(LockViewersContainer)); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss b/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss new file mode 100755 index 0000000000000000000000000000000000000000..078b36e6daa2ef8be0ca1eaad6c887953eda040e --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss @@ -0,0 +1,118 @@ +@import '/imports/ui/stylesheets/mixins/focus'; +@import '/imports/ui/stylesheets/variables/_all'; +@import "/imports/ui/components/modal/simple/styles"; + +:root { + --modal-margin: 3rem; + --title-position-left: 2.2rem; + --closeBtn-position-left: 2.5rem; +} + +.title { + position: relative; + left: var(--title-position-left); + color: var(--color-gray-dark); + font-weight: bold; + font-size: var(--font-size-large); + text-align: center; +} + +.form { + display: flex; + flex-flow: column; +} + +.container { + margin: var(--modal-margin); + margin-bottom: var(--lg-padding-x); +} + +.subHeader { + display: flex; + flex-flow: row; + flex-grow: 1; + justify-content: space-between; + color: var(--color-gray-label); + font-size: var(--font-size-base); + margin-bottom: var(--title-position-left); +} + +.modal { + @extend .modal; + padding: var(--jumbo-padding-y); +} + +.overlay { + @extend .overlay; +} + +.description { + text-align: center; + color: var(--color-gray); + margin-bottom: var(--jumbo-padding-y) +} + +.row { + display: flex; + flex-flow: row; + flex-grow: 1; + justify-content: space-between; + margin-bottom: var(--md-padding-x); +} + +.col { + display: flex; + flex-grow: 1; + flex-basis: 0; + margin-right: var(--md-padding-x); +} + +.label { + color: var(--color-gray-label); + font-size: var(--font-size-small); + margin-bottom: var(--lg-padding-y); +} + +.formElement { + position: relative; + display: flex; + flex-flow: column; + flex-grow: 1; +} + +.pullContentRight { + display: flex; + justify-content: flex-end; + flex-flow: row; +} + +.bold { + font-weight: bold; +} + +.closeBtn { + position: relative; + background-color: var(--color-white); + left: var(--closeBtn-position-left); + bottom: var(--closeBtn-position-left); + + i { + color: var(--color-gray-light); + } + + &:focus, + &:hover { + background-color: var(--color-gray-lighter); + i { + color: var(--color-gray); + } + } +} + +.header { + margin: 0; + padding: 0; + border: none; + line-height: var(--title-position-left); + margin-bottom: var(--lg-padding-y); +} diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx index 3e689940efa29dc8d15164b34155a0cea5c0f528..69c2551259fbbf05e45d55e35b4b5e32043a64a0 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx @@ -9,6 +9,7 @@ import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component'; import DropdownContent from '/imports/ui/components/dropdown/content/component'; import DropdownList from '/imports/ui/components/dropdown/list/component'; import DropdownListItem from '/imports/ui/components/dropdown/list/item/component'; +import LockViewersContainer from '/imports/ui/components/lock-viewers/container'; import { styles } from './styles'; const propTypes = { @@ -19,7 +20,6 @@ const propTypes = { toggleMuteAllUsers: PropTypes.func.isRequired, toggleMuteAllUsersExceptPresenter: PropTypes.func.isRequired, toggleStatus: PropTypes.func.isRequired, - toggleLockView: PropTypes.func.isRequired, }; const intlMessages = defineMessages({ @@ -83,7 +83,8 @@ class UserOptions extends Component { } componentWillMount() { - const { intl, isMeetingMuted } = this.props; + const { intl, isMeetingMuted, mountModal } = this.props; + this.menuItems = _.compact([ (<DropdownListItem key={_.uniqueId('list-item-')} @@ -111,7 +112,7 @@ class UserOptions extends Component { icon="lock" label={intl.formatMessage(intlMessages.lockViewersLabel)} description={intl.formatMessage(intlMessages.lockViewersDesc)} - onClick={this.props.toggleLockView} + onClick={() => mountModal(<LockViewersContainer />)} />), ]); diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx index 59561dab0d68b6c8b63d9e3d42f5b3cd2899ce1f..cf5af07ef7fd03c58eb1b2b82f7c11597c1daffe 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import logger from '/imports/startup/client/logger'; import Auth from '/imports/ui/services/auth'; import mapUser from '/imports/ui/services/user/mapUser'; import Users from '/imports/api/users/'; @@ -26,7 +25,6 @@ export default class UserOptionsContainer extends Component { this.muteMeeting = this.muteMeeting.bind(this); this.muteAllUsersExceptPresenter = this.muteAllUsersExceptPresenter.bind(this); - this.handleLockView = this.handleLockView.bind(this); this.handleClearStatus = this.handleClearStatus.bind(this); } @@ -44,11 +42,6 @@ export default class UserOptionsContainer extends Component { muteAllExceptPresenter(currentUser.userId); } - handleLockView() { - // Temporary lock method, will be changed in future PR - logger.info('handleLockView function'); - } - handleClearStatus() { const { users, setEmojiStatus } = this.props; @@ -71,7 +64,6 @@ export default class UserOptionsContainer extends Component { <UserOptions toggleMuteAllUsers={this.muteMeeting} toggleMuteAllUsersExceptPresenter={this.muteAllUsersExceptPresenter} - toggleLockView={this.handleLockView} toggleStatus={this.handleClearStatus} isMeetingMuted={this.state.meetingMuted} /> : null diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index 7e390556857e62c8b575d5c16d99af51a5184a1f..abc96fb5fd3ec269087ef70abbe9bc798fb0f0d8 100755 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -359,6 +359,16 @@ "app.shortcut-help.closePrivateChat": "Close Private Chat", "app.shortcut-help.openActions": "Open Actions Menu", "app.shortcut-help.openStatus": "Open Status Menu", + "app.lock-viewers.title": "Lock Viewers", + "app.lock-viewers.description": "These options enable you to restrict certain features available to viewers, such as locking out their ability to use private chat. (These restrictions do no apply to moderators)", + "app.lock-viewers.featuresLable": "Feature", + "app.lock-viewers.lockStatusLabel": "Locked Status", + "app.lock-viewers.webcamLabel": "Webcam", + "app.lock-viewers.otherViewersWebcamLabel": "See other viewsers webcams", + "app.lock-viewers.microphoneLable": "Microphone", + "app.lock-viewers.PublicChatLabel": "Public Chat", + "app.lock-viewers.PrivateChatLable": "Private Chat", + "app.lock-viewers.Layout": "Layout", "app.videoPreview.cameraLabel": "Camera", "app.videoPreview.cancelLabel": "Cancel", "app.videoPreview.closeLabel": "Close",