Merge pull request #13552 from antobinary/2.4-into-develop

chore: Merge 2.4 branch into develop
This commit is contained in:
Anton Georgiev 2021-10-22 16:27:56 -04:00 committed by GitHub
commit bb898fec8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 1134 additions and 338 deletions

View File

@ -15,7 +15,7 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to create breakout room for meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId,

View File

@ -15,7 +15,7 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
def handleSetLockSettings(msg: ChangeLockSettingsInMeetingCmdMsg): Unit = {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to change lock settings"
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -12,7 +12,7 @@ trait ChangeUserRoleCmdMsgHdlr extends RightsManagementTrait {
val outGW: OutMsgRouter
def handleChangeUserRoleCmdMsg(msg: ChangeUserRoleCmdMsg) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to change user role in meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -23,7 +23,7 @@ trait EjectUserFromMeetingCmdMsgHdlr extends RightsManagementTrait {
PermissionCheck.VIEWER_LEVEL,
liveMeeting.users2x,
msg.header.userId
)) {
) || liveMeeting.props.meetingProp.isBreakout) {
val reason = "No permission to eject user from meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -15,7 +15,7 @@ trait LogoutAndEndMeetingCmdMsgHdlr extends RightsManagementTrait {
val eventBus: InternalEventBus
def handleLogoutAndEndMeetingCmdMsg(msg: LogoutAndEndMeetingCmdMsg, state: MeetingState2x): Unit = {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to end meeting on logout."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -13,7 +13,7 @@ trait UpdateWebcamsOnlyForModeratorCmdMsgHdlr extends RightsManagementTrait {
def handleUpdateWebcamsOnlyForModeratorCmdMsg(msg: UpdateWebcamsOnlyForModeratorCmdMsg) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to change lock settings"
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -50,7 +50,7 @@ object Users2x {
def findAllExpiredUserLeftFlags(users: Users2x, meetingExpireWhenLastUserLeftInMs: Long): Vector[UserState] = {
if (meetingExpireWhenLastUserLeftInMs > 0) {
users.toVector filter (u => u.userLeftFlag.left && u.userLeftFlag.leftOn != 0 &&
System.currentTimeMillis() - u.userLeftFlag.leftOn > 1000)
System.currentTimeMillis() - u.userLeftFlag.leftOn > 30000)
} else {
// When meetingExpireWhenLastUserLeftInMs is set zero we need to
// remove user right away to end the meeting as soon as possible.

View File

@ -12,7 +12,7 @@ trait MuteAllExceptPresentersCmdMsgHdlr extends RightsManagementTrait {
val outGW: OutMsgRouter
def handleMuteAllExceptPresentersCmdMsg(msg: MuteAllExceptPresentersCmdMsg) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to mute all except presenters."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -13,7 +13,7 @@ trait MuteMeetingCmdMsgHdlr extends RightsManagementTrait {
def handleMuteMeetingCmdMsg(msg: MuteMeetingCmdMsg): Unit = {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to mute meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -14,7 +14,7 @@ trait SetGuestPolicyMsgHdlr extends RightsManagementTrait {
val outGW: OutMsgRouter
def handleSetGuestPolicyMsg(msg: SetGuestPolicyCmdMsg): Unit = {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId) || liveMeeting.props.meetingProp.isBreakout) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to set guest policy in meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, outGW, liveMeeting)

View File

@ -28,6 +28,14 @@ public class LearningDashboardService {
private static Logger log = LoggerFactory.getLogger(LearningDashboardService.class);
private static String learningDashboardFilesDir = "/var/bigbluebutton/learning-dashboard";
public File getJsonDataFile(String meetingId, String learningDashboardAccessToken) {
File baseDir = new File(this.getDestinationBaseDirectoryName(meetingId,learningDashboardAccessToken));
if (!baseDir.exists()) baseDir.mkdirs();
File jsonFile = new File(baseDir.getAbsolutePath() + File.separatorChar + "learning_dashboard_data.json");
return jsonFile;
}
public void writeJsonDataFile(String meetingId, String learningDashboardAccessToken, String activityJson) {
try {
@ -36,10 +44,7 @@ public class LearningDashboardService {
return;
}
File baseDir = new File(this.getDestinationBaseDirectoryName(meetingId,learningDashboardAccessToken));
if (!baseDir.exists()) baseDir.mkdirs();
File jsonFile = new File(baseDir.getAbsolutePath() + File.separatorChar + "learning_dashboard_data.json");
File jsonFile = this.getJsonDataFile(meetingId,learningDashboardAccessToken);
FileOutputStream fileOutput = new FileOutputStream(jsonFile);
fileOutput.write(activityJson.getBytes());

View File

@ -0,0 +1,40 @@
package org.bigbluebutton.api.model.request;
import org.bigbluebutton.api.model.constraint.UserSessionConstraint;
import javax.validation.constraints.NotNull;
import java.util.Map;
public class LearningDashboard implements Request<LearningDashboard.Params> {
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
private final String value;
Params(String value) { this.value = value; }
public String getValue() { return value; }
}
@UserSessionConstraint
private String sessionToken;
public String getSessionToken() {
return sessionToken;
}
public void setSessionToken(String sessionToken) {
this.sessionToken = sessionToken;
}
@Override
public void populateFromParamsMap(Map<String, String[]> params) {
if(params.containsKey(LearningDashboard.Params.SESSION_TOKEN.getValue())) setSessionToken(params.get(LearningDashboard.Params.SESSION_TOKEN.getValue())[0]);
}
@Override
public void convertParamsFromString() {
}
}

View File

@ -39,7 +39,8 @@ public class ValidationService {
GUEST_WAIT("guestWait", RequestType.GET),
ENTER("enter", RequestType.GET),
STUNS("stuns", RequestType.GET),
SIGN_OUT("signOut", RequestType.GET);
SIGN_OUT("signOut", RequestType.GET),
LEARNING_DASHBOARD("learningDashboard", RequestType.GET);
private final String name;
private final RequestType requestType;
@ -133,6 +134,9 @@ public class ValidationService {
case SIGN_OUT:
request = new SignOut();
break;
case LEARNING_DASHBOARD:
request = new LearningDashboard();
break;
}
case POST:
checksum = new PostChecksum(apiCall.getName(), checksumValue, params);

View File

@ -17,6 +17,8 @@ class App extends React.Component {
tab: 'overview',
meetingId: '',
learningDashboardAccessToken: '',
ldAccessTokenCopied: false,
sessionToken: '',
};
}
@ -30,6 +32,7 @@ class App extends React.Component {
setDashboardParams() {
let learningDashboardAccessToken = '';
let meetingId = '';
let sessionToken = '';
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
@ -38,6 +41,10 @@ class App extends React.Component {
meetingId = params.meeting;
}
if (typeof params.sessionToken !== 'undefined') {
sessionToken = params.sessionToken;
}
if (typeof params.report !== 'undefined') {
learningDashboardAccessToken = params.report;
} else {
@ -56,11 +63,12 @@ class App extends React.Component {
}
}
this.setState({ learningDashboardAccessToken, meetingId }, this.fetchActivitiesJson);
this.setState({ learningDashboardAccessToken, meetingId, sessionToken },
this.fetchActivitiesJson);
}
fetchActivitiesJson() {
const { learningDashboardAccessToken, meetingId } = this.state;
const { learningDashboardAccessToken, meetingId, sessionToken } = this.state;
if (learningDashboardAccessToken !== '') {
fetch(`${meetingId}/${learningDashboardAccessToken}/learning_dashboard_data.json`)
@ -71,14 +79,48 @@ class App extends React.Component {
}).catch(() => {
this.setState({ loading: false });
});
} else if (sessionToken !== '') {
const url = new URL('/bigbluebutton/api/learningDashboard', window.location);
fetch(`${url}?sessionToken=${sessionToken}`)
.then((response) => response.json())
.then((json) => {
if (json.response.returncode === 'SUCCESS') {
const jsonData = JSON.parse(json.response.data);
this.setState({ activitiesJson: jsonData, loading: false });
document.title = `Learning Dashboard - ${jsonData.name}`;
} else {
// When meeting is ended the sessionToken stop working, check for new cookies
this.setDashboardParams();
this.setState({ loading: false });
}
})
.catch(() => {
this.setState({ loading: false });
});
} else {
this.setState({ loading: false });
}
}
copyPublicLink() {
const { learningDashboardAccessToken, meetingId, ldAccessTokenCopied } = this.state;
const { intl } = this.props;
let url = window.location.href.split('?')[0];
url += `?meeting=${meetingId}&report=${learningDashboardAccessToken}&lang=${intl.locale}`;
navigator.clipboard.writeText(url);
if (ldAccessTokenCopied === false) {
this.setState({ ldAccessTokenCopied: true });
setTimeout(() => {
this.setState({ ldAccessTokenCopied: false });
}, 3000);
}
}
render() {
const {
activitiesJson, tab, learningDashboardAccessToken, loading,
activitiesJson, tab, sessionToken, loading,
learningDashboardAccessToken, ldAccessTokenCopied,
} = this.state;
const { intl } = this.props;
@ -162,19 +204,60 @@ class App extends React.Component {
}
function getErrorMessage() {
if (learningDashboardAccessToken === '') {
if (learningDashboardAccessToken === '' && sessionToken === '') {
return intl.formatMessage({ id: 'app.learningDashboard.errors.invalidToken', defaultMessage: 'Invalid session token' });
}
return intl.formatMessage({ id: 'app.learningDashboard.errors.dataUnavailable', defaultMessage: 'Data is no longer available' });
if (activitiesJson === {} || typeof activitiesJson.name === 'undefined') {
return intl.formatMessage({ id: 'app.learningDashboard.errors.dataUnavailable', defaultMessage: 'Data is no longer available' });
}
return '';
}
if (loading === false && typeof activitiesJson.name === 'undefined') return <ErrorMessage message={getErrorMessage()} />;
if (loading === false && getErrorMessage() !== '') return <ErrorMessage message={getErrorMessage()} />;
return (
<div className="mx-10">
<div className="flex items-start justify-between pb-3">
<h1 className="mt-3 text-2xl font-semibold whitespace-nowrap inline-block">
<FormattedMessage id="app.learningDashboard.dashboardTitle" defaultMessage="Learning Dashboard" />
&nbsp;
{
learningDashboardAccessToken !== ''
? (
<button type="button" onClick={() => { this.copyPublicLink(); }} className="text-sm font-medium text-blue-500 ease-out">
(
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4 inline"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
/>
</svg>
&nbsp;
<FormattedMessage id="app.learningDashboard.shareButton" defaultMessage="Share with others" />
)
</button>
)
: null
}
{
ldAccessTokenCopied === true
? (
<span className="text-xs text-gray-500 font-normal ml-2">
<FormattedMessage id="app.learningDashboard.linkCopied" defaultMessage="Link successfully copied!" />
</span>
)
: null
}
<br />
<span className="text-sm font-medium">{activitiesJson.name || ''}</span>
</h1>

View File

@ -60,7 +60,7 @@ class Dashboard extends React.Component {
setRtl() {
const { intlLocale } = this.state;
if (RTL_LANGUAGES.includes(intlLocale)) {
if (RTL_LANGUAGES.includes(intlLocale.substring(0, 2))) {
document.body.parentNode.setAttribute('dir', 'rtl');
}
}

View File

@ -1 +1 @@
BIGBLUEBUTTON_RELEASE=2.4-rc-2
BIGBLUEBUTTON_RELEASE=2.4-rc-3

View File

@ -178,13 +178,30 @@
}
.icon-bbb-volume_off:before {
content: "\e947";
content: "\e95f";
}
.icon-bbb-volume_up:before {
content: "\e947";
}
.icon-bbb-volume_level_1:before {
content: "\e960";
}
.icon-bbb-volume_level_2:before {
content: "\e961";
}
.icon-bbb-volume_level_3:before {
content: "\e962";
}
.icon-bbb-no_audio:before {
content: "\e963";
}
/* Aliases for emoji status */
.icon-bbb-time:before {
content: "\e908";

View File

@ -23,9 +23,18 @@ export default function handleMeetingEnd({ header, body }) {
}
};
Meetings.update({ meetingId },
{ $set: { meetingEnded: true, meetingEndedBy: userId, meetingEndedReason: reason } },
(err, num) => { cb(err, num, 'Meeting'); });
Meetings.find({ meetingId }).forEach((doc) => {
Meetings.update({ meetingId },
{
$set: {
meetingEnded: true,
meetingEndedBy: userId,
meetingEndedReason: reason,
learningDashboardAccessToken: doc.password.learningDashboardAccessToken,
},
},
(err, num) => { cb(err, num, 'Meeting'); });
});
Breakouts.update({ parentMeetingId: meetingId },
{ $set: { meetingEnded: true } },

View File

@ -56,10 +56,8 @@ function meetings() {
},
};
if (User.role === ROLE_MODERATOR) {
delete options.fields.password;
options.fields['password.viewerPass'] = false;
options.fields['password.moderatorPass'] = false;
if (User.role !== ROLE_MODERATOR) {
options.fields.learningDashboardAccessToken = false;
}
return Meetings.find(selector, options);

View File

@ -65,6 +65,8 @@ const currentParameters = [
'bbb_hide_presentation',
'bbb_show_participants_on_login',
'bbb_show_public_chat_on_login',
'bbb_hide_actions_bar',
'bbb_hide_nav_bar',
// OUTSIDE COMMANDS
'bbb_outside_toggle_self_voice',
'bbb_outside_toggle_recording',

View File

@ -323,30 +323,6 @@ WebApp.connectHandlers.use('/guestWait', (req, res) => {
res.end(guestWaitHtml);
});
// WASM endpoint to be used to fetch the .wasm models for camera effects
// (blur, virtual background).
// See: /imports/ui/services/virtual-backgrounds/
WebApp.connectHandlers.use('/wasm', (req, res) => {
const pathname = req._parsedUrl.pathname;
let file = "";
let hasError = false;
try {
file = Assets.getBinary(pathname.substr(1, pathname.length-1));
} catch (error) {
hasError = true;
Logger.warn(`Could not find WASM file: ${error}`);
}
res.setHeader('Content-Type', 'application/wasm');
if (hasError) {
res.writeHead(404);
} else {
res.writeHead(200);
}
res.end(file);
});
export const eventEmitter = Redis.emitter;
export const redisPubSub = Redis;

View File

@ -36,6 +36,7 @@ class ActionsBar extends PureComponent {
shortcuts,
layoutContextDispatch,
actionsBarStyle,
isOldMinimizeButtonEnabled,
} = this.props;
return (
@ -81,14 +82,19 @@ class ActionsBar extends PureComponent {
/>
</div>
<div className={styles.right}>
<PresentationOptionsContainer
isLayoutSwapped={isLayoutSwapped}
toggleSwapLayout={toggleSwapLayout}
layoutContextDispatch={layoutContextDispatch}
hasPresentation={isThereCurrentPresentation}
hasExternalVideo={isSharingVideo}
hasScreenshare={hasScreenshare}
/>
{!isOldMinimizeButtonEnabled ||
(isOldMinimizeButtonEnabled && isLayoutSwapped && !isPresentationDisabled)
? (
<PresentationOptionsContainer
isLayoutSwapped={isLayoutSwapped}
toggleSwapLayout={toggleSwapLayout}
layoutContextDispatch={layoutContextDispatch}
hasPresentation={isThereCurrentPresentation}
hasExternalVideo={isSharingVideo}
hasScreenshare={hasScreenshare}
/>
)
: null}
{isRaiseHandButtonEnabled
? (
<Button

View File

@ -17,6 +17,7 @@ import { isVideoBroadcasting } from '/imports/ui/components/screenshare/service'
import MediaService, {
getSwapLayout,
shouldEnableSwapLayout,
} from '../media/service';
const ActionsBarContainer = (props) => {
@ -45,13 +46,14 @@ const POLLING_ENABLED = Meteor.settings.public.poll.enabled;
const PRESENTATION_DISABLED = Meteor.settings.public.layout.hidePresentation;
const SELECT_RANDOM_USER_ENABLED = Meteor.settings.public.selectRandomUser.enabled;
const RAISE_HAND_BUTTON_ENABLED = Meteor.settings.public.app.raiseHandActionButton.enabled;
const OLD_MINIMIZE_BUTTON_ENABLED = Meteor.settings.public.presentation.oldMinimizeButton;
export default withTracker(() => ({
amIPresenter: Service.amIPresenter(),
amIModerator: Service.amIModerator(),
stopExternalVideoShare: ExternalVideoService.stopWatching,
enableVideo: getFromUserSettings('bbb_enable_video', Meteor.settings.public.kurento.enableVideo),
isLayoutSwapped: getSwapLayout(),
isLayoutSwapped: getSwapLayout()&& shouldEnableSwapLayout(),
toggleSwapLayout: MediaService.toggleSwapLayout,
handleTakePresenter: Service.takePresenterRole,
currentSlidHasContent: PresentationService.currentSlidHasContent(),
@ -64,6 +66,7 @@ export default withTracker(() => ({
isPresentationDisabled: PRESENTATION_DISABLED,
isSelectRandomUserEnabled: SELECT_RANDOM_USER_ENABLED,
isRaiseHandButtonEnabled: RAISE_HAND_BUTTON_ENABLED,
isOldMinimizeButtonEnabled: OLD_MINIMIZE_BUTTON_ENABLED,
isThereCurrentPresentation: Presentations.findOne({ meetingId: Auth.meetingID, current: true },
{ fields: {} }),
allowExternalVideo: Meteor.settings.public.externalVideoPlayer.enabled,

View File

@ -340,37 +340,6 @@ class App extends Component {
&& (isPhone || isLayeredView.matches);
}
renderNavBar() {
const { navbar, isLargeFont } = this.props;
if (!navbar) return null;
const realNavbarHeight = isLargeFont ? LARGE_NAVBAR_HEIGHT : NAVBAR_HEIGHT;
return (
<header
className={styles.navbar}
style={{
height: realNavbarHeight,
}}
>
{navbar}
</header>
);
}
renderSidebar() {
const { sidebar } = this.props;
if (!sidebar) return null;
return (
<aside className={styles.sidebar}>
{sidebar}
</aside>
);
}
renderCaptions() {
const {
captions,
@ -401,9 +370,10 @@ class App extends Component {
actionsbar,
intl,
actionsBarStyle,
hideActionsBar,
} = this.props;
if (!actionsbar) return null;
if (!actionsbar || hideActionsBar) return null;
return (
<section

View File

@ -211,6 +211,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls })
Meteor.settings.public.presentation.restoreOnUpdate,
),
hidePresentation: getFromUserSettings('bbb_hide_presentation', LAYOUT_CONFIG.hidePresentation),
hideActionsBar: getFromUserSettings('bbb_hide_actions_bar', false),
};
})(AppContainer)));

View File

@ -82,7 +82,7 @@ class AudioControls extends PureComponent {
data-test="joinAudio"
color="default"
ghost
icon="audio_off"
icon="no_audio"
size="lg"
circle
accessKey={shortcuts.joinaudio}
@ -108,12 +108,12 @@ class AudioControls extends PureComponent {
shortcuts,
} = this.props;
let joinIcon = 'audio_off';
let joinIcon = 'no_audio';
if (inAudio) {
if (listenOnly) {
joinIcon = 'listen';
} else {
joinIcon = 'audio_on';
joinIcon = 'volume_level_2';
}
}

View File

@ -293,7 +293,7 @@ class InputStreamLiveSelector extends Component {
data-test="leaveAudio"
hideLabel
color="primary"
icon={isListenOnly ? 'listen' : 'audio_on'}
icon={isListenOnly ? 'listen' : 'volume_level_2'}
size="lg"
circle
onClick={(e) => {
@ -302,6 +302,7 @@ class InputStreamLiveSelector extends Component {
}}
/>
<ButtonEmoji
className={styles.audioDropdown}
emoji="device_list_selector"
label={intl.formatMessage(intlMessages.changeAudioDevice)}
hideLabel

View File

@ -101,3 +101,12 @@
.selectedDevice {
font-weight: bold !important;
}
.audioDropdown {
span {
i {
width: 0px !important;
bottom: 1px;
}
}
}

View File

@ -186,7 +186,7 @@ export default lockContextContainer(withModalMounter(injectIntl(withTracker(({ m
if (userMic && !Service.isMuted()) {
Service.toggleMuteMicrophone();
notify(intl.formatMessage(intlMessages.reconectingAsListener), 'info', 'audio_on');
notify(intl.formatMessage(intlMessages.reconectingAsListener), 'info', 'volume_level_2');
}
}

View File

@ -23,6 +23,8 @@ const propTypes = {
tabIndex: PropTypes.number,
hideLabel: PropTypes.bool,
className: PropTypes.string,
};
const defaultProps = {
@ -33,11 +35,13 @@ const defaultProps = {
tabIndex: -1,
hideLabel: false,
onClick: null,
className: '',
};
const ButtonEmoji = (props) => {
const {
hideLabel,
className,
...newProps
} = props;
@ -62,7 +66,7 @@ const ButtonEmoji = (props) => {
type="button"
tabIndex={tabIndex}
{...newProps}
className={styles.emojiButton}
className={[styles.emojiButton, className].join(' ')}
aria-label={label}
onClick={onClick}
>

View File

@ -20,23 +20,45 @@ const isModerator = () => {
return false;
};
const getLearningDashboardAccessToken = () => ((
const isLearningDashboardEnabled = () => (((
Meetings.findOne(
{ meetingId: Auth.meetingID },
{
fields: { 'password.learningDashboardAccessToken': 1 },
fields: { 'meetingProp.learningDashboardEnabled': 1 },
},
) || {}).password || {}).learningDashboardAccessToken || null;
) || {}).meetingProp || {}).learningDashboardEnabled || false);
const getLearningDashboardAccessToken = () => ((
Meetings.findOne(
{ meetingId: Auth.meetingID, learningDashboardAccessToken: { $exists: true } },
{
fields: { learningDashboardAccessToken: 1 },
},
) || {}).learningDashboardAccessToken || null);
const setLearningDashboardCookie = () => {
const learningDashboardAccessToken = getLearningDashboardAccessToken();
if (learningDashboardAccessToken !== null) {
const cookieExpiresDate = new Date();
cookieExpiresDate.setTime(cookieExpiresDate.getTime() + (3600000 * 24 * 30)); // keep cookie 30d
document.cookie = `learningDashboardAccessToken-${Auth.meetingID}=${getLearningDashboardAccessToken()}; expires=${cookieExpiresDate.toGMTString()}; path=/`;
return true;
}
return false;
};
const openLearningDashboardUrl = (lang) => {
const cookieExpiresDate = new Date();
cookieExpiresDate.setTime(cookieExpiresDate.getTime() + (3600000 * 24 * 30)); // keep cookie 30d
document.cookie = `learningDashboardAccessToken-${Auth.meetingID}=${getLearningDashboardAccessToken()}; expires=${cookieExpiresDate.toGMTString()}; path=/`;
window.open(`/learning-dashboard/?meeting=${Auth.meetingID}&lang=${lang}`, '_blank');
if (getLearningDashboardAccessToken() && setLearningDashboardCookie()) {
window.open(`/learning-dashboard/?meeting=${Auth.meetingID}&lang=${lang}`, '_blank');
} else {
window.open(`/learning-dashboard/?meeting=${Auth.meetingID}&sessionToken=${Auth.sessionToken}&lang=${lang}`, '_blank');
}
};
export default {
isModerator,
isLearningDashboardEnabled,
getLearningDashboardAccessToken,
setLearningDashboardCookie,
openLearningDashboardUrl,
};

View File

@ -9,6 +9,7 @@ import { ACTIONS } from '../layout/enums';
const LAYOUT_CONFIG = Meteor.settings.public.layout;
const KURENTO_CONFIG = Meteor.settings.public.kurento;
const PRESENTATION_CONFIG = Meteor.settings.public.presentation;
const getPresentationInfo = () => {
const currentPresentation = Presentations.findOne({
@ -72,6 +73,13 @@ const toggleSwapLayout = (layoutContextDispatch) => {
});
};
export const shouldEnableSwapLayout = () => {
if (!PRESENTATION_CONFIG.oldMinimizeButton) {
return true;
}
return !shouldShowScreenshare() && !shouldShowExternalVideo();
}
export const getSwapLayout = () => {
swapLayout.tracker.depend();
return swapLayout.value;
@ -86,6 +94,7 @@ export default {
isUserPresenter,
isVideoBroadcasting,
toggleSwapLayout,
shouldEnableSwapLayout,
getSwapLayout,
setSwapLayout,
};

View File

@ -266,7 +266,9 @@ class MeetingEnded extends PureComponent {
<div>
{
LearningDashboardService.isModerator()
&& LearningDashboardService.getLearningDashboardAccessToken() != null
&& LearningDashboardService.isLearningDashboardEnabled() === true
// Always set cookie in case Dashboard is already opened
&& LearningDashboardService.setLearningDashboardCookie() === true
? (
<div className={styles.text}>
<Button

View File

@ -8,6 +8,7 @@
margin-right: 1.65rem;
margin-left: .5rem;
white-space: normal;
overflow-wrap: anywhere;
padding: .1rem 0;
[dir="rtl"] & {

View File

@ -54,6 +54,10 @@ const NavBarContainer = ({ children, ...props }) => {
const currentUser = users[Auth.meetingID][Auth.userID];
const amIModerator = currentUser.role === ROLE_MODERATOR;
const hideNavBar = getFromUserSettings('bbb_hide_nav_bar', false);
if (hideNavBar) return null;
return (
<NavBar
{...{

View File

@ -493,7 +493,7 @@ class Poll extends Component {
)}
</div>
<div data-test="responseTypes">
<h4>{intl.formatMessage(intlMessages.responseTypesLabel)}</h4>
<h4 className={styles.sectionHeading}>{intl.formatMessage(intlMessages.responseTypesLabel)}</h4>
<div className={styles.responseType}>
<Button
label={intl.formatMessage(intlMessages.tf)}
@ -573,11 +573,11 @@ class Poll extends Component {
{type
&& (
<div data-test="responseChoices">
<h4>{intl.formatMessage(intlMessages.responseChoices)}</h4>
<h4 className={styles.sectionHeading}>{intl.formatMessage(intlMessages.responseChoices)}</h4>
{
type === pollTypes.Response
&& (
<div>
<div className={styles.pollParagraph}>
<span>{intl.formatMessage(intlMessages.typedResponseDesc)}</span>
</div>
)
@ -607,10 +607,9 @@ class Poll extends Component {
)}
<div className={styles.row}>
<div className={styles.col} aria-hidden="true">
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
<label className={styles.label}>
<h4 className={styles.sectionHeading}>
{intl.formatMessage(intlMessages.secretPollLabel)}
</label>
</h4>
</div>
<div className={styles.col}>
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
@ -628,7 +627,7 @@ class Poll extends Component {
</div>
{secretPoll
&& (
<div>
<div className={styles.pollParagraph}>
{ intl.formatMessage(intlMessages.isSecretPollLabel) }
</div>
)}
@ -697,7 +696,7 @@ class Poll extends Component {
const { intl } = this.props;
return (
<div className={styles.noSlidePanelContainer}>
<h4>{intl.formatMessage(intlMessages.noPresentationSelected)}</h4>
<h4 className={styles.sectionHeading}>{intl.formatMessage(intlMessages.noPresentationSelected)}</h4>
<Button
label={intl.formatMessage(intlMessages.clickHereToSelect)}
color="primary"

View File

@ -403,7 +403,6 @@
position: relative;
flex-flow: column;
flex-grow: 1;
flex-basis: 0;
&:last-child {
padding-right: 0;
@ -423,3 +422,13 @@
margin: 0 0 0 var(--sm-padding-x);
}
}
.sectionHeading {
margin-top: 0;
font-weight: 600;
color: var(--color-heading);
}
.pollParagraph {
color: var(--color-text);
}

View File

@ -13,6 +13,8 @@ import PresentationOverlayContainer from './presentation-overlay/container';
import Slide from './slide/component';
import { styles } from './styles.scss';
import toastStyles from '/imports/ui/components/toast/styles';
import MediaService, { shouldEnableSwapLayout } from '../media/service';
import PresentationCloseButton from './presentation-close-button/component';
import DownloadPresentationButton from './download-presentation-button/component';
import FullscreenService from '../fullscreen-button/service';
import FullscreenButtonContainer from '../fullscreen-button/container';
@ -49,6 +51,7 @@ const intlMessages = defineMessages({
});
const ALLOW_FULLSCREEN = Meteor.settings.public.app.allowFullscreen;
const OLD_MINIMIZE_BUTTON_ENABLED = Meteor.settings.public.presentation.oldMinimizeButton;
class Presentation extends PureComponent {
constructor() {
@ -425,6 +428,31 @@ class Presentation extends PureComponent {
zoomSlide(currentSlide.num, podId, w, h, x, y);
}
renderPresentationClose() {
const { isFullscreen } = this.state;
const {
layoutType,
fullscreenContext,
layoutContextDispatch,
isIphone,
} = this.props;
if (!OLD_MINIMIZE_BUTTON_ENABLED
|| !shouldEnableSwapLayout()
|| isFullscreen
|| fullscreenContext
|| layoutType === LAYOUT_TYPE.PRESENTATION_FOCUS) {
return null;
}
return (
<PresentationCloseButton
toggleSwapLayout={MediaService.toggleSwapLayout}
layoutContextDispatch={layoutContextDispatch}
isIphone={isIphone}
/>
);
}
renderOverlays(slideObj, svgDimensions, viewBoxPosition, viewBoxDimensions, physicalDimensions) {
const {
userIsPresenter,
@ -562,6 +590,7 @@ class Presentation extends PureComponent {
}}
>
<span id="currentSlideText" className={styles.visuallyHidden}>{slideContent}</span>
{this.renderPresentationClose()}
{this.renderPresentationDownload()}
{this.renderPresentationFullscreen()}
<svg

View File

@ -1,6 +1,9 @@
import React, { useContext } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import MediaService, { getSwapLayout, } from '/imports/ui/components/media/service';
import MediaService, {
getSwapLayout,
shouldEnableSwapLayout,
} from '/imports/ui/components/media/service';
import { notify } from '/imports/ui/services/notification';
import PresentationService from './service';
import { Slides } from '/imports/api/slides';
@ -72,7 +75,7 @@ const fetchedpresentation = {};
export default withTracker(({ podId }) => {
const currentSlide = PresentationService.getCurrentSlide(podId);
const presentationIsDownloadable = PresentationService.isPresentationDownloadable(podId);
const layoutSwapped = getSwapLayout();
const layoutSwapped = getSwapLayout() && shouldEnableSwapLayout();
let slidePosition;
if (currentSlide) {

View File

@ -45,7 +45,7 @@ export default withTracker((params) => {
return {
amIPresenter: Service.amIPresenter(),
layoutSwapped: MediaService.getSwapLayout(),
layoutSwapped: MediaService.getSwapLayout() && MediaService.shouldEnableSwapLayout(),
userIsPresenter: PresentationService.isPresenter(podId),
numberOfSlides: PresentationToolbarService.getNumberOfSlides(podId, presentationId),
nextSlide: PresentationToolbarService.nextSlide,

View File

@ -2,7 +2,10 @@ import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import Users from '/imports/api/users/';
import Auth from '/imports/ui/services/auth';
import MediaService, { getSwapLayout, } from '/imports/ui/components/media/service';
import MediaService, {
getSwapLayout,
shouldEnableSwapLayout,
} from '/imports/ui/components/media/service';
import {
isVideoBroadcasting,
isGloballyBroadcasting,
@ -46,6 +49,7 @@ export default withTracker(() => {
isGloballyBroadcasting: isGloballyBroadcasting(),
isPresenter: user.presenter,
getSwapLayout,
shouldEnableSwapLayout,
toggleSwapLayout: MediaService.toggleSwapLayout,
hidePresentation: getFromUserSettings('bbb_hide_presentation', LAYOUT_CONFIG.hidePresentation),
};

View File

@ -541,7 +541,7 @@ class UserDropdown extends PureComponent {
? (<Icon iconName={normalizeEmojiName(user.emoji)} />)
: user.name.toLowerCase().slice(0, 2);
const iconVoiceOnlyUser = (<Icon iconName="audio_on" />);
const iconVoiceOnlyUser = (<Icon iconName="volume_level_2" />);
const userIcon = isVoiceOnly ? iconVoiceOnlyUser : iconUser;
return (

View File

@ -214,7 +214,7 @@ class UserOptions extends PureComponent {
hasBreakoutRoom,
isBreakoutEnabled,
getUsersNotAssigned,
learningDashboardAccessToken,
learningDashboardEnabled,
openLearningDashboardUrl,
amIModerator,
users,
@ -326,7 +326,7 @@ class UserOptions extends PureComponent {
});
}
if (amIModerator) {
if (learningDashboardAccessToken != null) {
if (learningDashboardEnabled === true) {
this.menuItems.push({
icon: 'multi_whiteboard',
iconRight: 'popout_window',
@ -336,7 +336,7 @@ class UserOptions extends PureComponent {
onClick: () => { openLearningDashboardUrl(locale); },
dividerTop: true,
});
}
}
}
}

View File

@ -92,7 +92,7 @@ const UserOptionsContainer = withTracker((props) => {
guestPolicy: WaitingUsersService.getGuestPolicy(),
isMeteorConnected: Meteor.status().connected,
meetingName: getMeetingName(),
learningDashboardAccessToken: LearningDashboardService.getLearningDashboardAccessToken(),
learningDashboardEnabled: LearningDashboardService.isLearningDashboardEnabled(),
openLearningDashboardUrl: LearningDashboardService.openLearningDashboardUrl,
dynamicGuestPolicy,
};

View File

@ -2,8 +2,7 @@ import React, { useContext } from 'react';
import { withModalMounter } from '/imports/ui/components/modal/service';
import { withTracker } from 'meteor/react-meteor-data';
import Settings from '/imports/ui/services/settings';
import MediaService, { getSwapLayout, } from '/imports/ui/components/media/service';
import MediaService, { getSwapLayout, shouldEnableSwapLayout } from '/imports/ui/components/media/service';
import Auth from '/imports/ui/services/auth';
import breakoutService from '/imports/ui/components/breakout-room/service';
import VideoService from '/imports/ui/components/video-provider/service';
@ -20,7 +19,6 @@ const WebcamContainer = ({
audioModalIsOpen,
swapLayout,
usersVideo,
disableVideo,
}) => {
const fullscreen = layoutSelect((i) => i.fullscreen);
const isRTL = layoutSelect((i) => i.isRTL);
@ -36,8 +34,7 @@ const WebcamContainer = ({
const { users } = usingUsersContext;
const currentUser = users[Auth.meetingID][Auth.userID];
return !disableVideo
&& !audioModalIsOpen
return !audioModalIsOpen
&& usersVideo.length > 0
? (
<WebcamComponent
@ -60,8 +57,6 @@ const WebcamContainer = ({
let userWasInBreakout = false;
export default withModalMounter(withTracker(() => {
const { dataSaving } = Settings;
const { viewParticipantsWebcams } = dataSaving;
const { current_presentation: hasPresentation } = MediaService.getPresentationInfo();
const data = {
audioModalIsOpen: Session.get('audioModalIsOpen'),
@ -95,8 +90,7 @@ export default withModalMounter(withTracker(() => {
const { streams: usersVideo } = VideoService.getVideoStreams();
data.usersVideo = usersVideo;
data.swapLayout = getSwapLayout() || !hasPresentation;
data.disableVideo = !viewParticipantsWebcams;
data.swapLayout = (getSwapLayout() || !hasPresentation) && shouldEnableSwapLayout();
if (data.swapLayout) {
data.floatingOverlay = true;

View File

@ -6,6 +6,7 @@ import { injectIntl, defineMessages } from 'react-intl';
import styles from './styles';
import {
getSwapLayout,
shouldEnableSwapLayout,
} from '/imports/ui/components/media/service';
const intlMessages = defineMessages({
@ -72,7 +73,7 @@ class PollDrawComponent extends Component {
}
componentDidMount() {
const isLayoutSwapped = getSwapLayout();
const isLayoutSwapped = getSwapLayout() && shouldEnableSwapLayout();
if (isLayoutSwapped) return;
this.pollInitialCalculation();

View File

@ -463,7 +463,11 @@ class AudioManager {
}
if (!this.error && !this.isEchoTest) {
this.notify(this.intl.formatMessage(this.messages.info.LEFT_AUDIO), false, 'audio_off');
this.notify(
this.intl.formatMessage(this.messages.info.LEFT_AUDIO),
false,
'no_audio'
);
}
if (!this.isEchoTest) {
this.playHangUpSound();

View File

@ -556,6 +556,7 @@ public:
allowDownloadable: true
panZoomThrottle: 32
restoreOnUpdate: false
oldMinimizeButton: false
uploadEndpoint: '/bigbluebutton/presentation/upload'
uploadValidMimeTypes:
- extension: .pdf

View File

@ -266,9 +266,9 @@
"app.poll.showRespDesc": "يعرض تكوين الاستجابة",
"app.poll.addRespDesc": "يضيف مدخلات استجابة التصويت",
"app.poll.deleteRespDesc": "يزيل الخيار {0}",
"app.poll.t": واب",
"app.poll.t": حيح",
"app.poll.f": "خطأ",
"app.poll.tf": واب / خطأ",
"app.poll.tf": حيح / خطأ",
"app.poll.y": "نعم",
"app.poll.n": "لا",
"app.poll.abstention": "امتناع",
@ -277,7 +277,7 @@
"app.poll.a3": "أ / ب / ج",
"app.poll.a4": "أ / ب / ج / د",
"app.poll.a5": "أ / ب / ج / د / هـ",
"app.poll.answer.true": واب",
"app.poll.answer.true": حيح",
"app.poll.answer.false": "خطأ",
"app.poll.answer.yes": "نعم",
"app.poll.answer.no": "لا",
@ -411,6 +411,8 @@
"app.switch.offLabel": "إيقاف",
"app.talkingIndicator.ariaMuteDesc" : "اختر لكتم صوت المستخدم",
"app.talkingIndicator.isTalking" : "{0} يتحدث",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ يتحدثون",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ كانوا يتحدثون",
"app.talkingIndicator.wasTalking" : "{0} توقف عن الكلام",
"app.actionsBar.actionsDropdown.actionsLabel": "الاجراءات",
"app.actionsBar.actionsDropdown.presentationLabel": "إدارة العروض",
@ -816,6 +818,7 @@
"app.createBreakoutRoom.title": "الغرف الجانبية",
"app.createBreakoutRoom.ariaTitle": "إخفاء الغرف الجانبية",
"app.createBreakoutRoom.breakoutRoomLabel": "غرفة جانبية {0}",
"app.createBreakoutRoom.askToJoin": "اطلب الانضمام",
"app.createBreakoutRoom.generatingURL": "إنشاء الرابط",
"app.createBreakoutRoom.generatingURLMessage": "نحن نقوم بإنشاء رابط خاص بالغرفة الجانبية المختارة. قد يستغرق الأمر بضع ثوان ...",
"app.createBreakoutRoom.duration": "المدة {0}",
@ -909,6 +912,8 @@
"playback.player.video.wrapper.aria": "مساحة الفيديو",
"app.learningDashboard.dashboardTitle": "لوحة التعلم",
"app.learningDashboard.user": "مستخدم",
"app.learningDashboard.shareButton": "شارك مع الآخرين",
"app.learningDashboard.shareLinkCopied": "تم نسخ الرابط بنجاح",
"app.learningDashboard.indicators.meetingStatusEnded": "انتهت",
"app.learningDashboard.indicators.meetingStatusActive": "فعًال",
"app.learningDashboard.indicators.usersOnline": "المستخدمين النشطين",

View File

@ -411,6 +411,8 @@
"app.switch.offLabel": "AUS",
"app.talkingIndicator.ariaMuteDesc" : "Auswählen, um Teilnehmer stummzuschalten",
"app.talkingIndicator.isTalking" : "{0} spricht",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ sprechen",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ sprachen",
"app.talkingIndicator.wasTalking" : "{0} spricht nicht mehr",
"app.actionsBar.actionsDropdown.actionsLabel": "Aktionen",
"app.actionsBar.actionsDropdown.presentationLabel": "Präsentationen verwalten",
@ -590,7 +592,7 @@
"app.guest.missingMeeting": "Konferenz existiert nicht.",
"app.guest.meetingEnded": "Konferenz beendet.",
"app.guest.guestWait": "Bitte warten Sie, bis ein Moderator Ihre Teilnahme an der Konferenz freigibt.",
"app.guest.guestDeny": "Gast wurde die Teilnahme an der Konferenz abgelehnt.",
"app.guest.guestDeny": "Der Moderator hat die Teilnahme an der Konferenz abgelehnt.",
"app.guest.seatWait": "Gast wartet auf die Teilnahme an der Konferenz.",
"app.guest.allow": "Gast zugelassen und zur Konferenz weitergeleitet.",
"app.userList.guest.waitingUsers": "Wartende Teilnehmer",
@ -601,7 +603,7 @@
"app.userList.guest.allowEveryone": "Alle erlauben",
"app.userList.guest.denyEveryone": "Alle verweigern",
"app.userList.guest.pendingUsers": "{0} unbearbeitete Teilnehmer",
"app.userList.guest.pendingGuestUsers": "{0} unbearbeitete Gäste",
"app.userList.guest.pendingGuestUsers": "{0} wartende Gäste",
"app.userList.guest.pendingGuestAlert": "Ist der Konferenz beigetreten und wartet auf Ihre Teilnahmeerlaubnis",
"app.userList.guest.rememberChoice": "Auswahl für die Zukunft speichern",
"app.userList.guest.emptyMessage": "Momentan keine Nachricht vorhanden",
@ -816,7 +818,7 @@
"app.createBreakoutRoom.title": "Gruppenräume",
"app.createBreakoutRoom.ariaTitle": "Gruppenräume verbergen",
"app.createBreakoutRoom.breakoutRoomLabel": "Gruppenräume {0}",
"app.createBreakoutRoom.askToJoin": "Beitreten auffordern",
"app.createBreakoutRoom.askToJoin": "Raum beitreten",
"app.createBreakoutRoom.generatingURL": "Erzeuge URL",
"app.createBreakoutRoom.generatingURLMessage": "Wir generieren eine Teilnahme-URL für den ausgewählten Gruppenraum. Das kann ein paar Sekunden dauern...",
"app.createBreakoutRoom.duration": "Dauer {0}",
@ -910,6 +912,8 @@
"playback.player.video.wrapper.aria": "Webcambereich",
"app.learningDashboard.dashboardTitle": "Lern-Dashboard",
"app.learningDashboard.user": "Teilnehmer",
"app.learningDashboard.shareButton": "Mit anderen teilen",
"app.learningDashboard.shareLinkCopied": "Link erfolgreich kopiert",
"app.learningDashboard.indicators.meetingStatusEnded": "Beendet",
"app.learningDashboard.indicators.meetingStatusActive": "Aktiv",
"app.learningDashboard.indicators.usersOnline": "Aktive Teilnehmer",

View File

@ -913,6 +913,8 @@
"playback.player.video.wrapper.aria": "Video area",
"app.learningDashboard.dashboardTitle": "Learning Dashboard",
"app.learningDashboard.user": "User",
"app.learningDashboard.shareButton": "Share with others",
"app.learningDashboard.shareLinkCopied": "Link successfully copied!",
"app.learningDashboard.indicators.meetingStatusEnded": "Ended",
"app.learningDashboard.indicators.meetingStatusActive": "Active",
"app.learningDashboard.indicators.usersOnline": "Active Users",

View File

@ -411,6 +411,8 @@
"app.switch.offLabel": "VÄLJAS",
"app.talkingIndicator.ariaMuteDesc" : "Vali vaigistamiseks kasutaja",
"app.talkingIndicator.isTalking" : "{0} räägib",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ räägivad",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ rääkisid",
"app.talkingIndicator.wasTalking" : "{0} lõpetas rääkimise",
"app.actionsBar.actionsDropdown.actionsLabel": "Tegevused",
"app.actionsBar.actionsDropdown.presentationLabel": "Halda esitlusi",

View File

@ -25,6 +25,8 @@
"app.chat.multi.typing": "چند کاربر در حال نوشتن هستند",
"app.chat.one.typing": "{0} در حال نوشتن است",
"app.chat.two.typing": "{0} و {1} در حال نوشتن هستند",
"app.chat.copySuccess": "محتوای گفتگو کپی شد",
"app.chat.copyErr": "کپی محتوای گفتگو با خطا مواجه شد!",
"app.captions.label": "عناوین",
"app.captions.menu.close": "بستن",
"app.captions.menu.start": "شروع",
@ -51,6 +53,7 @@
"app.captions.pad.dictationOffDesc": "غیر فعال کردن امکان تشخیص صوت",
"app.captions.pad.speechRecognitionStop": "به دلیل مشکلات مرورگر یا ایجاد وقفه، تبدیل گفتار متوقف شده است.",
"app.textInput.sendLabel": "ارسال",
"app.title.defaultViewLabel": "نمای پیش‌فرض ارائه",
"app.note.title": "یادداشت‌های اشتراکی",
"app.note.label": "یادداشت",
"app.note.hideNoteLabel": "پنهان کردن یادداشت",
@ -145,6 +148,8 @@
"app.meeting.meetingTimeRemaining": "زمان باقی مانده از جلسه: {0}",
"app.meeting.meetingTimeHasEnded": "زمان جلسه به اتمام رسید. جلسه به زودی بسته خواهد شد",
"app.meeting.endedByUserMessage": "این جلسه توسط {0} به پایان رسید",
"app.meeting.endedByNoModeratorMessageSingular": "جلسه به دلیل عدم حضور یک مدیر پس از یک دقیقه تمام شد",
"app.meeting.endedByNoModeratorMessagePlural": "جلسه به دلیل عدم حضور یک میانجی پس از {0} دقیقه تمام شد.",
"app.meeting.endedMessage": "شما در حال انتقال به صفحه اصلی هستید",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "جلسه تا یک دقیقه دیگر به پایان می‌رسد.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "جلسه تا {0} دقیقه دیگر به پایان می‌رسد.",
@ -181,6 +186,7 @@
"app.presentation.presentationToolbar.fitToWidth": "اندازه تصویر را متناسب با عرض ارائه کن",
"app.presentation.presentationToolbar.fitToPage": "اندازه تصویر را متناسب با عرض صفحه کن",
"app.presentation.presentationToolbar.goToSlide": "اسلاید {0}",
"app.presentation.placeholder": "در انتظار بارگذاری یک ارائه",
"app.presentationUploder.title": "ارائه",
"app.presentationUploder.message": "به عنوان یک ارائه دهنده شما قادرید انواع فایل های مجموعه آفیس و یا فایل PDF را بارگذاری نمایید؛ پیشنهاد ما برای رسیدن به بهترین نتایج، استفاده از فایل PDF میباشد. لطفا از انتخاب بودن یک ارائه توسط گزینه سمت راست اطمینان حاصل کنید.",
"app.presentationUploder.uploadLabel": "بارگذاری",
@ -227,6 +233,7 @@
"app.presentationUploder.itemPlural" : "آیتم‌ها",
"app.presentationUploder.clearErrors": "پاک کردن خطاها",
"app.presentationUploder.clearErrorsDesc": "پاک کردن بارگذاری‌های ناموفق ارائه",
"app.presentationUploder.uploadViewTitle": "بارگذاری ارائه ",
"app.poll.pollPaneTitle": "نظرسنجی",
"app.poll.quickPollTitle": "نظرسنجی سریع",
"app.poll.hidePollDesc": "پنهان‌سازی منوی نظرسنجی",
@ -242,6 +249,8 @@
"app.poll.customPlaceholder": "افزودن گزینه نظرسنجی",
"app.poll.noPresentationSelected": "هیچ ارائه‌ای انتخاب نشده است! لطفا یکی را انتخاب کنید.",
"app.poll.clickHereToSelect": "برای انتخاب اینجا را کلیک کن",
"app.poll.question.label" : "سوالتان را بنویسید ...",
"app.poll.optionalQuestion.label" : "سوالتان را بنویسید (اختیاری) ...",
"app.poll.userResponse.label" : "پاسخ کاربر",
"app.poll.responseTypes.label" : "نوع پاسخها",
"app.poll.optionDelete.label" : "حذف",
@ -250,7 +259,13 @@
"app.poll.addItem.label" : "اضافه کردن آیتم",
"app.poll.start.label" : "آغاز نظرسنجی",
"app.poll.secretPoll.label" : "رأی‌گیری ناشناس",
"app.poll.secretPoll.isSecretLabel": "این نظرسنجی ناشناس است - شما قادر نخواهید بود پاسخ‌های فردی را ببینید.",
"app.poll.questionErr": "ارائه یک سوال الزامی است.",
"app.poll.optionErr": "یک گزینه نظرسنجی وارد کنید",
"app.poll.startPollDesc": "آغاز رای‌گیری",
"app.poll.showRespDesc": "نمایش پاسخ پیکربندی",
"app.poll.addRespDesc": "اضافه کردن ورودی پاسخ نظر سنجی",
"app.poll.deleteRespDesc": "حذف گزینه {0}",
"app.poll.t": "درست",
"app.poll.f": "نادرست",
"app.poll.tf": "درست / نادرست",
@ -275,6 +290,8 @@
"app.poll.liveResult.usersTitle": "کاربران",
"app.poll.liveResult.responsesTitle": "پاسخ",
"app.poll.liveResult.secretLabel": "این یک نظرسنجی ناشناس است. پاسخ هر فرد نمایش داده نمی‌شود.",
"app.poll.removePollOpt": "گزینه نظرسنجی حذف شد {0}",
"app.poll.emptyPollOpt": "خالی",
"app.polling.pollingTitle": "امکانات نظرسنجی",
"app.polling.pollQuestionTitle": "سوال نظرسنجی",
"app.polling.submitLabel": "ارسال",
@ -338,6 +355,9 @@
"app.actionsBar.raiseLabel": "اجازه گرفتن از استاد",
"app.actionsBar.label": "نوار فعالیت ها",
"app.actionsBar.actionsDropdown.restorePresentationLabel": "بازیابی ارائه",
"app.actionsBar.actionsDropdown.restorePresentationDesc": "کلید برگرداندن ارائه بعد از کوچک کردن آن",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "حداقل کردن پنجره ارائه",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "کلید کوچک کردن ارائه",
"app.screenshare.screenShareLabel" : "اشتراک صفحه",
"app.submenu.application.applicationSectionTitle": "برنامه",
"app.submenu.application.animationsLabel": "انیمیشن ها",
@ -357,6 +377,7 @@
"app.submenu.notification.pushAlertLabel": "هشدارهای پاپ‌آپ",
"app.submenu.notification.messagesLabel": "پیام گفتگو",
"app.submenu.notification.userJoinLabel": "پیوستن کاربر",
"app.submenu.notification.userLeaveLabel": "کاربر ترک کرد",
"app.submenu.notification.guestWaitingLabel": "میهمان در انتظار پذیرفته شدن برای ورود به جلسه",
"app.submenu.audio.micSourceLabel": "ورودی صدای میکروفن",
"app.submenu.audio.speakerSourceLabel": "ورودی صدای بلندگو",
@ -390,6 +411,8 @@
"app.switch.offLabel": "خاموش",
"app.talkingIndicator.ariaMuteDesc" : "برای بی صدا کردن کاربر انتخاب کنید",
"app.talkingIndicator.isTalking" : "{0} در حال صحبت کردن است",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ در حال حرف زدن هستند",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ حرف می‌زدند،",
"app.talkingIndicator.wasTalking" : "{0} به صحبت خود پایان داد",
"app.actionsBar.actionsDropdown.actionsLabel": "فعالیت ها",
"app.actionsBar.actionsDropdown.presentationLabel": "مدیریت ارائه ها",
@ -465,6 +488,8 @@
"app.audioModal.ariaTitle": "ملحق شدن به مدال صدا",
"app.audioModal.microphoneLabel": "میکروفون",
"app.audioModal.listenOnlyLabel": "تنها شنونده",
"app.audioModal.microphoneDesc": "ورود به کنفرانس صوتی با میکروفن",
"app.audioModal.listenOnlyDesc": "ورود به کنفرانس صوتی به صورت شنونده",
"app.audioModal.audioChoiceLabel": "چنانچه مایل هستید تا از امکانات صوتی ذیل استفاده کنید، روی آن کلیک نمایید.",
"app.audioModal.iOSBrowser": "صدا/تصویر پیشتیبانی نمیشود",
"app.audioModal.iOSErrorDescription": "در حال حاضر صدا و تصویر در مرورگر کروم iOS پشتیبانی نمی‌شود.",
@ -490,6 +515,7 @@
"app.audioModal.playAudio.arialabel" : "پخش صدا",
"app.audioDial.tipIndicator": "نکته",
"app.audioDial.tipMessage": "برای قطع/وصل صدا کلید 0 را روی موبایل خود شماره گیری کنید",
"app.audioModal.connecting": "برقراری ارتباط صوتی",
"app.audioManager.joinedAudio": "شما به جلسه صوتی وارد شده اید",
"app.audioManager.joinedEcho": "شما به تست اکو پیوسته اید",
"app.audioManager.leftAudio": "شما جلسه صوتی را ترک کرده اید",
@ -546,6 +572,7 @@
"app.error.401": "احراز هویت نشده",
"app.error.403": "شما از جلسه حذف شدید",
"app.error.404": "پیدا نشد",
"app.error.408": "تایید هویت شکست خورد",
"app.error.410": "جلسه پایان یافت",
"app.error.500": "آخ، خطای پیش آمده است",
"app.error.userLoggedOut": "کاربر به خاطر خروج sessionToken غیر معتبر دارد",
@ -567,6 +594,7 @@
"app.guest.guestWait": "لطفا منتظر بمانید تا یک مدیر شما را برای پیوستن به جلسه تایید کند.",
"app.guest.guestDeny": "میهمان از پیوستن به اتاق سر باز زد.",
"app.guest.seatWait": "میهمان در انتظار اجازه ورود به اتاق می‌باشد.",
"app.guest.allow": "میربان تائید شد و به جلسه هدایت گردید.",
"app.userList.guest.waitingUsers": "کاربران در حال انتظار",
"app.userList.guest.waitingUsersTitle": "مدیرت کاربران",
"app.userList.guest.optionTitle": "بررسی کاربران در انتظار تایید",
@ -598,6 +626,7 @@
"app.notification.recordingPaused": "جلسه دیگر ضبط نمی‌شود",
"app.notification.recordingAriaLabel": "زمان ضبط شده",
"app.notification.userJoinPushAlert": "{0} به کلاس پیوستند",
"app.notification.userLeavePushAlert": "{0} جلسه را ترک کرد",
"app.submenu.notification.raiseHandLabel": "بالا بردن دست",
"app.shortcut-help.title": "میانبرهای صفحه کلید",
"app.shortcut-help.accessKeyNotAvailable": "کلیدهای دسترسی موجود نیست",
@ -641,14 +670,25 @@
"app.guest-policy.button.askModerator": "از مدیر تقاضا کن",
"app.guest-policy.button.alwaysAccept": "همیشه بپذیر",
"app.guest-policy.button.alwaysDeny": "همیشه رد کن",
"app.guest-policy.policyBtnDesc": "تنظیم سیاست میهمان",
"app.connection-status.ariaTitle": "کیفیت وضعیت اتصال",
"app.connection-status.title": "وضعیت اتصال",
"app.connection-status.description": "وضعیت اتصال کاربران را مشاهده کنید",
"app.connection-status.empty": "در حال حاضر هیچ مشکلی در رابطه با اتصال گزارش نشده است",
"app.connection-status.more": "بیشتر",
"app.connection-status.copy": "نسخه‌برداری از داده‌های شبکه",
"app.connection-status.copied": "کپی شد!",
"app.connection-status.jitter": "تکان دادن",
"app.connection-status.label": "وضعیت اتصال",
"app.connection-status.no": "خیر",
"app.connection-status.notification": "قطعی در اتصال شما پیدا شد",
"app.connection-status.offline": "برون خط",
"app.connection-status.lostPackets": "پکت‌های از دست رفته",
"app.connection-status.usingTurn": "استفاده از TURN",
"app.connection-status.yes": "بله",
"app.learning-dashboard.label": "داشبورد یادگیری",
"app.learning-dashboard.description": "باز کردن داشبورد با فعالیت‌های کاربران",
"app.learning-dashboard.clickHereToOpen": "نمایش داشبورد یادگیری",
"app.recording.startTitle": "شروع ضبط",
"app.recording.stopTitle": "مکث ضبط",
"app.recording.resumeTitle": "از سر گرفتن ضبط",
@ -671,6 +711,7 @@
"app.videoPreview.webcamPreviewLabel": "پیش نمایش دوربین",
"app.videoPreview.webcamSettingsTitle": "تنظیمات دوربین",
"app.videoPreview.webcamVirtualBackgroundLabel": "تنظیمات پس‌زمینه مجازی",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "این دستگاه از پس‌زمینه‌های مجازی پشتیبانی نمی‌کند",
"app.videoPreview.webcamNotFoundLabel": "دوربین یافت نشد",
"app.videoPreview.profileNotFoundLabel": "پروفایل دوربین پیشتیبانی نمیشود",
"app.video.joinVideo": "اشتراک گذاری دوربین",
@ -709,6 +750,8 @@
"app.video.virtualBackground.none": "هیچی",
"app.video.virtualBackground.blur": "محو کردن",
"app.video.virtualBackground.genericError": "افکت دوربین اعمال نشد. مجددا تلاش کنید.",
"app.video.virtualBackground.camBgAriaDesc": "تنظیم پس‌زمینه مجازی دوربین به {0}",
"app.video.dropZoneLabel": "اینجا بیندازید",
"app.fullscreenButton.label": "تغییر {0} به تمام صفحه",
"app.fullscreenUndoButton.label": "{0} تمام صفحه را واگرد کنید",
"app.switchButton.expandLabel": "گسترش اشتراک‌گذاری صفحه‌نمایش",
@ -756,6 +799,7 @@
"app.whiteboard.toolbar.palmRejectionOn": "تماس روشن",
"app.whiteboard.toolbar.palmRejectionOff": "تماس خاموش",
"app.whiteboard.toolbar.fontSize": "لیست اندازه قلم",
"app.whiteboard.toolbarAriaLabel": "ابزارهای ارائه",
"app.feedback.title": "شما از کنفرانس خارج شده اید",
"app.feedback.subtitle": "بسیار ممنون میشویم نظر خود را در خصوص استفاده از برنامه بفرمایید (اختیاری)",
"app.feedback.textarea": "چگونه می‌توانیم برنامه بیگ بلو باتن را بهبود دهیم؟",
@ -774,7 +818,9 @@
"app.createBreakoutRoom.title": "اتاق‌های زیرمجموعه",
"app.createBreakoutRoom.ariaTitle": "پنهان کردن اتاق‌های زیرمجموعه",
"app.createBreakoutRoom.breakoutRoomLabel": "اتاق‌های زیرمجموعه {0}",
"app.createBreakoutRoom.askToJoin": "درخواست برای ملحق شدن",
"app.createBreakoutRoom.generatingURL": "در حال تولید نشانی وب",
"app.createBreakoutRoom.generatingURLMessage": "ما در حال ایجاد یک نشانی اینترنتی اتصال برای اتاق زیر مجموعه انتخاب‌شده هستیم. شاید چند ثانیه طول بکشد …",
"app.createBreakoutRoom.duration": "مدت زمان {0}",
"app.createBreakoutRoom.room": "اتاق {0}",
"app.createBreakoutRoom.notAssigned": "واگذار نشده ({0})",
@ -787,6 +833,7 @@
"app.createBreakoutRoom.numberOfRooms": "تعداد اتاق‌ها",
"app.createBreakoutRoom.durationInMinutes": "مدت زمان (دقیقه)",
"app.createBreakoutRoom.randomlyAssign": "به صورت تصادفی واگذار شده",
"app.createBreakoutRoom.randomlyAssignDesc": "توزیع تصادفی کاربران به اتاق‌های زیر مجموعه",
"app.createBreakoutRoom.endAllBreakouts": "پایان تمام اتاق‌های زیرمجموعه",
"app.createBreakoutRoom.roomName": "{0} (اتاق - {1})",
"app.createBreakoutRoom.doneLabel": "انجام شد",
@ -806,6 +853,7 @@
"app.createBreakoutRoom.extendTimeLabel": "گسترش",
"app.createBreakoutRoom.extendTimeCancel": "لغو",
"app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError": "مدت زمان اتاق‌ها نمی‌تواند از زمان جلسه بیشتر باشه.",
"app.createBreakoutRoom.roomNameInputDesc": "به روز رسانی نام اتاق‌های زیر مجموعه",
"app.externalVideo.start": "به اشتراک گذاری ویدئو جدید",
"app.externalVideo.title": "اشتراک یک ویدیوی خارجی",
"app.externalVideo.input": "آدرس ویدیوی خارجی",
@ -813,6 +861,7 @@
"app.externalVideo.urlError": "آدرس این فیلم نامعتبر است",
"app.externalVideo.close": "بستن",
"app.externalVideo.autoPlayWarning": "برای به هنگام سازی ، ویدیو را پخش کنید",
"app.externalVideo.refreshLabel": "تازه سازی پخش کننده ویدئو",
"app.externalVideo.noteLabel": "نکته: ویدیوهای خارجی به اشتراک گذاشته شده در ضبط ظاهر نمی‌شوند.نشانی‌های وب یوتیوب، ویمیو، Instructure Media، توییچ، دیلی‌موشن و فایل‌های رسانه‌ای (به عنوان مثال https://example.com/xy.mp4) پشتیبانی می‌شوند.",
"app.actionsBar.actionsDropdown.shareExternalVideo": "اشتراک یک ویدیوی خارجی",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "متوقف کردن نمایش ویدیوی خارجی",
@ -831,6 +880,8 @@
"app.layout.style.smart": "چینش هوشمند",
"app.layout.style.presentationFocus": "تأکید بر نمایش",
"app.layout.style.videoFocus": "تأکید بر فیلم",
"app.layout.style.presentationFocusPush": "تمرکز روی ارائه (قالب برای همه اعمال شود)",
"app.layout.style.videoFocusPush": "تمرکز روی ویدئو (قالب برای همه اعمال شود)",
"playback.button.about.aria": "درباره",
"playback.button.clear.aria": "پاک‌سازی جستجو",
"playback.button.close.aria": "بستن مودال",
@ -858,7 +909,35 @@
"playback.player.search.modal.title": "جستجو",
"playback.player.search.modal.subtitle": "یافتن محتوای صفحات ارائه شده",
"playback.player.thumbnails.wrapper.aria": "محدوده تصاویر بندانگشتی",
"playback.player.video.wrapper.aria": "محدوده فیلم"
"playback.player.video.wrapper.aria": "محدوده فیلم",
"app.learningDashboard.dashboardTitle": "داشبورد یادگیری",
"app.learningDashboard.user": "کاربر",
"app.learningDashboard.indicators.meetingStatusEnded": "پایان یافته",
"app.learningDashboard.indicators.meetingStatusActive": "فعال",
"app.learningDashboard.indicators.usersOnline": "کاربران فعال",
"app.learningDashboard.indicators.usersTotal": "تعداد کل کاربران",
"app.learningDashboard.indicators.polls": "نظرسنجی‌ها",
"app.learningDashboard.indicators.raiseHand": "دست‌های بالا رفته",
"app.learningDashboard.indicators.activityScore": "امتیاز فعالیت",
"app.learningDashboard.indicators.duration": "مدت زمان",
"app.learningDashboard.usersTable.title": "مرور کلی",
"app.learningDashboard.usersTable.colOnline": "زمان آنلاین بودن",
"app.learningDashboard.usersTable.colTalk": "زمان صحبت کردن",
"app.learningDashboard.usersTable.colWebcam": "زمان فعالیت دوربین",
"app.learningDashboard.usersTable.colMessages": "پیام‌ها",
"app.learningDashboard.usersTable.colEmojis": "ایموجی‌ها",
"app.learningDashboard.usersTable.colRaiseHands": "دست‌های بالا برده شده",
"app.learningDashboard.usersTable.colActivityScore": "امتیاز فعالیت",
"app.learningDashboard.usersTable.colStatus": "وضعیت",
"app.learningDashboard.usersTable.userStatusOnline": "آنلاین",
"app.learningDashboard.usersTable.userStatusOffline": "آفلاین",
"app.learningDashboard.usersTable.noUsers": "کاربری نیست",
"app.learningDashboard.pollsTable.title": "نظرسنجی",
"app.learningDashboard.pollsTable.anonymousAnswer": "نظرسنجی ناشناس (پاسخ‌ها در ردیف آخر)",
"app.learningDashboard.pollsTable.anonymousRowName": "ناشناس",
"app.learningDashboard.statusTimelineTable.title": "جدول زمانی وضعیت",
"app.learningDashboard.errors.invalidToken": "توکن نشست نامعتبر است",
"app.learningDashboard.errors.dataUnavailable": "داده دیگر موجود نیست"
}

View File

@ -390,7 +390,7 @@
"app.submenu.video.participantsCamLabel": "参加者のウェブカメラを見ています",
"app.settings.applicationTab.label": "アプリケーション",
"app.settings.audioTab.label": "音声",
"app.settings.videoTab.label": "ビデオ",
"app.settings.videoTab.label": "映像",
"app.settings.usersTab.label": "参加者",
"app.settings.main.label": "設定",
"app.settings.main.cancel.label": "キャンセル",
@ -410,8 +410,10 @@
"app.switch.onLabel": "入",
"app.switch.offLabel": "切",
"app.talkingIndicator.ariaMuteDesc" : "ユーザーをミュートします",
"app.talkingIndicator.isTalking" : "{0} が話しています",
"app.talkingIndicator.wasTalking" : "{0} が話し終えました",
"app.talkingIndicator.isTalking" : "{0}人が話しています",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+人が話しています",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+人が話していました。",
"app.talkingIndicator.wasTalking" : "{0}人が話し終えました",
"app.actionsBar.actionsDropdown.actionsLabel": "アクション",
"app.actionsBar.actionsDropdown.presentationLabel": "プレゼンテーションを管理する",
"app.actionsBar.actionsDropdown.initPollLabel": "投票を初期化",
@ -671,10 +673,10 @@
"app.guest-policy.policyBtnDesc": "会議のゲストポリシーを設定",
"app.connection-status.ariaTitle": "接続状況モーダル",
"app.connection-status.title": "接続状況",
"app.connection-status.description": "ユーザの接続状況をみる",
"app.connection-status.description": "ユーザーの接続状況の閲覧",
"app.connection-status.empty": "現在のところ接続の問題は報告されていません。",
"app.connection-status.more": "更に見る",
"app.connection-status.copy": "ネットワークデータをコピーする",
"app.connection-status.copy": "ネットワークの情報をコピー",
"app.connection-status.copied": "コピーしました!",
"app.connection-status.jitter": "ジッター",
"app.connection-status.label": "接続状況",
@ -910,6 +912,8 @@
"playback.player.video.wrapper.aria": "ビデオエリア",
"app.learningDashboard.dashboardTitle": "ラーニングダッシュボード",
"app.learningDashboard.user": "ユーザー",
"app.learningDashboard.shareButton": "共有する",
"app.learningDashboard.shareLinkCopied": "リンクがコピーされました",
"app.learningDashboard.indicators.meetingStatusEnded": "終了",
"app.learningDashboard.indicators.meetingStatusActive": "会議中",
"app.learningDashboard.indicators.usersOnline": "人のアクティブなユーザー",
@ -919,7 +923,7 @@
"app.learningDashboard.indicators.activityScore": "アクティビティスコア",
"app.learningDashboard.indicators.duration": "時間",
"app.learningDashboard.usersTable.title": "概要",
"app.learningDashboard.usersTable.colOnline": "オンライン時間",
"app.learningDashboard.usersTable.colOnline": "オンライン時間",
"app.learningDashboard.usersTable.colTalk": "会話時間",
"app.learningDashboard.usersTable.colWebcam": "カメラオン時間",
"app.learningDashboard.usersTable.colMessages": "メッセージ",

View File

@ -411,6 +411,8 @@
"app.switch.offLabel": "ВЫКЛ",
"app.talkingIndicator.ariaMuteDesc" : "Нажмите, чтобы выключить микрофон пользователю",
"app.talkingIndicator.isTalking" : "{0} говорит",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ говорят",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ разговаривают",
"app.talkingIndicator.wasTalking" : "{0} прекратил говорить",
"app.actionsBar.actionsDropdown.actionsLabel": "Действия",
"app.actionsBar.actionsDropdown.presentationLabel": "Управление презентациями",
@ -816,6 +818,7 @@
"app.createBreakoutRoom.title": "Комнаты для групповой работы",
"app.createBreakoutRoom.ariaTitle": "Скрыть комнаты для групповой работы",
"app.createBreakoutRoom.breakoutRoomLabel": "Комнаты для групповой работы {0} ",
"app.createBreakoutRoom.askToJoin": "Спрашивать для подключения",
"app.createBreakoutRoom.generatingURL": "Генерация URL-адреса",
"app.createBreakoutRoom.generatingURLMessage": "Мы создаем URL-адрес для присоединения к выбранной комнате для обсуждения. Это может занять несколько секунд...",
"app.createBreakoutRoom.duration": "Продолжительность {0}",
@ -877,8 +880,8 @@
"app.layout.style.smart": "Автоматический",
"app.layout.style.presentationFocus": "Фокус на презентации",
"app.layout.style.videoFocus": "Фокус на веб-камерах",
"app.layout.style.presentationFocusPush": "Фокус на презентации (Применить компоновку для всех)",
"app.layout.style.videoFocusPush": "Фокус на веб-камерах (Применить компоновку для всех)",
"app.layout.style.presentationFocusPush": "Фокус на презентации (Применить для всех)",
"app.layout.style.videoFocusPush": "Фокус на веб-камерах (Применить для всех)",
"playback.button.about.aria": "О",
"playback.button.clear.aria": "Очистить поиск",
"playback.button.close.aria": "Закрыть модальное окно",
@ -920,7 +923,7 @@
"app.learningDashboard.usersTable.title": "Обзор",
"app.learningDashboard.usersTable.colOnline": "Время онлайна",
"app.learningDashboard.usersTable.colTalk": "Время разговора",
"app.learningDashboard.usersTable.colWebcam": "Время с вкл. веб-камерой",
"app.learningDashboard.usersTable.colWebcam": "Время с веб-камерой",
"app.learningDashboard.usersTable.colMessages": "Сообщений",
"app.learningDashboard.usersTable.colEmojis": "Смайликов",
"app.learningDashboard.usersTable.colRaiseHands": "Поднятых рук",

View File

@ -25,6 +25,8 @@
"app.chat.multi.typing": "బహుళ వినియోగదారులు టైప్ చేస్తున్నారు",
"app.chat.one.typing": "{0} టైప్ చేస్తున్నారు",
"app.chat.two.typing": "{0} , {1} టైప్ చేస్తున్నారు",
"app.chat.copySuccess": "రాయబడిన చాట్ కాపీ చేయబడింది",
"app.chat.copyErr": "చాట్ ట్రాన్స్‌క్రిప్ట్‌ని కాపీ చేయడం విఫలమైంది",
"app.captions.label": "శీర్షికలు",
"app.captions.menu.close": "మూసివేయి",
"app.captions.menu.start": "ప్రారంభించు",
@ -49,7 +51,9 @@
"app.captions.pad.dictationStop": "డిక్టేషన్ ఆపుము",
"app.captions.pad.dictationOnDesc": "మాటల గుర్తింపును ఆన్ చేయండి",
"app.captions.pad.dictationOffDesc": " మాటల గుర్తింపును ఆపివేస్తుంది",
"app.captions.pad.speechRecognitionStop": "బ్రౌజర్ అననుకూలత లేదా కొంత సమయం నిశ్శబ్దం కారణంగా మాటను గుర్తించుట నిలిపివేయబడింది",
"app.textInput.sendLabel": "పంపండి",
"app.title.defaultViewLabel": "డిఫాల్ట్ ప్రెజెంటేషన్ వ్యూ",
"app.note.title": "షేర్డ్ నోట్సు",
"app.note.label": "నోటు",
"app.note.hideNoteLabel": "నోటును దాచండి",
@ -73,7 +77,10 @@
"app.userList.moderator": "మోడరేటర్",
"app.userList.mobile": "మొబైల్",
"app.userList.guest": "అతిథి",
"app.userList.sharingWebcam": "వెబ్‌క్యామ్",
"app.userList.menuTitleContext": "అందుబాటులో ఉన్న ఎంపికలు",
"app.userList.chatListItem.unreadSingular": "ఒక కొత్త సందేశం",
"app.userList.chatListItem.unreadPlural": "{0} కొత్త సందేశాలు",
"app.userList.menu.chat.label": "ప్రైవేట్ చాట్ ప్రారంభించండి",
"app.userList.menu.clearStatus.label": "స్టేటస్ ని క్లియర్ చేయండి",
"app.userList.menu.removeUser.label": "వినియోగదారుని తొలగించండి",
@ -118,7 +125,7 @@
"app.userList.userOptions.enableNote": "షేర్డ్ నోట్సులు ఇప్పుడు ప్రారంభించబడ్డాయి",
"app.userList.userOptions.showUserList": "వినియోగదారుని జాబితా ఇప్పుడు వీక్షకులకు చూపబడింది",
"app.userList.userOptions.enableOnlyModeratorWebcam": "మీరు ఇప్పుడు మీ వెబ్‌క్యామ్‌ను ఆన్ చేయవచ్చు,అందరూ మిమ్మల్ని చూస్తారు",
"app.userList.userOptions.savedNames.title": "{1 meeting వద్ద {0 meeting ను కలవడంలో వినియోగదారుల జాబితా",
"app.userList.userOptions.savedNames.title": "{0} సమావేశంలో ఉన్న వినియోగదారుల జాబితా {1} వద్ద",
"app.userList.userOptions.sortedFirstName.heading": "మొదటి పేరుతో క్రమబద్ధీకరించబడింది:",
"app.userList.userOptions.sortedLastName.heading": "చివరి పేరుతో క్రమబద్ధీకరించబడింది:",
"app.media.label": "మీడియా",
@ -129,6 +136,9 @@
"app.media.screenshare.notSupported": "ఈ బ్రౌజర్‌లో స్క్రీన్‌షేరింగ్‌కు మద్దతు లేదు.",
"app.media.screenshare.autoplayBlockedDesc": "ప్రెజెంటర్ స్క్రీన్‌ను మీకు చూపించడానికి మాకు మీ అనుమతి అవసరం.",
"app.media.screenshare.autoplayAllowLabel": "షేర్ద్ స్క్రీన్ ‌ను చూడండి",
"app.screenshare.presenterLoadingLabel": "మీ స్క్రీన్ షేర్ లోడ్ అవుతోంది",
"app.screenshare.viewerLoadingLabel": "ప్రెజెంటర్ స్క్రీన్ లోడ్ అవుతోంది",
"app.screenshare.presenterSharingLabel": "మీరు ఇప్పుడు మీ స్క్రీన్‌ను షేర్ చేస్తున్నారు",
"app.screenshare.screenshareFinalError": "కోడ్ {0}. స్క్రీన్‌ను భాగస్వామ్యం చేయలేకపోయింది.",
"app.screenshare.screenshareRetryError": "కోడ్ {0}. స్క్రీన్‌ను మళ్లీ భాగస్వామ్యం చేయడానికి ప్రయత్నించండి.",
"app.screenshare.screenshareRetryOtherEnvError": "కోడ్ {0}. స్క్రీన్‌ను భాగస్వామ్యం చేయలేకపోయింది. వేరే బ్రౌజర్ లేదా పరికరాన్ని ఉపయోగించి మళ్లీ ప్రయత్నించండి.",
@ -137,6 +147,9 @@
"app.meeting.ended": "ఈ సెషన్ ముగిసింది",
"app.meeting.meetingTimeRemaining": "సమావేశ సమయం మిగిలి ఉంది: {0}",
"app.meeting.meetingTimeHasEnded": "సమయం ముగిసింది. సమావేశం త్వరలో ముగుస్తుంది",
"app.meeting.endedByUserMessage": "ఈ సెషన్ {0} ద్వారా ముగించబండింది",
"app.meeting.endedByNoModeratorMessageSingular": "మోడరేటర్ లేనందున ఒక నిమిషం తర్వాత సమావేశం ముగిసింది",
"app.meeting.endedByNoModeratorMessagePlural": "మోడరేటర్ లేనందున {0} నిమిషాల తర్వాత సమావేశం ముగిసింది",
"app.meeting.endedMessage": "మీరు హోమ్ స్క్రీన్‌కు తిరిగి ఫార్ వర్డ్ చేయబడతారు",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "సమావేశం ఒక నిమిషంలో ముగుస్తుంది.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "సమావేశం {0} నిమిషాల్లో ముగుస్తుంది.",
@ -173,6 +186,7 @@
"app.presentation.presentationToolbar.fitToWidth": "వెడల్పుకు సరిపెట్టు",
"app.presentation.presentationToolbar.fitToPage": "పేజీకి సరిపెట్టు",
"app.presentation.presentationToolbar.goToSlide": "స్లయిడ్ {0}",
"app.presentation.placeholder": "ప్రదర్శన అప్‌లోడ్ చేయడానికి వేచి ఉంది",
"app.presentationUploder.title": "ప్రదర్శన",
"app.presentationUploder.message": "ప్రెజెంటర్గా మీకు ఏదైనా కార్యాలయ పత్రం లేదా PDF ఫైల్‌ను అప్‌లోడ్ చేసే సామర్థ్యం ఉంది. ఉత్తమ ఫలితాల కోసం మేము PDF ఫైల్‌ను సిఫార్సు చేస్తున్నాము. దయచేసి కుడి వైపున ఉన్న సర్కిల్ చెక్‌బాక్స్ ఉపయోగించి ప్రదర్శనను ఎంచుకున్నారని నిర్ధారించుకోండి.",
"app.presentationUploder.uploadLabel": "అప్లోడ్ ",
@ -198,7 +212,7 @@
"app.presentationUploder.conversion.generatingThumbnail": "తంబ్ నైల్స్ రూపొందుతున్నాయి ...",
"app.presentationUploder.conversion.generatedSlides": "స్లయిడ్ ‌లు రూపొందాయి ...",
"app.presentationUploder.conversion.generatingSvg": "SVG చిత్రాలు రూపొందుతున్నాయి...",
"app.presentationUploder.conversion.pageCountExceeded": "పేజీల సంఖ్య గరిష్టంగా {0 మించిపోయింది",
"app.presentationUploder.conversion.pageCountExceeded": "పేజీల సంఖ్య గరిష్టంగా {0} మించిపోయింది",
"app.presentationUploder.conversion.officeDocConversionInvalid": "ఆఫీస్ డాక్యుమెంట్ ప్రాసెస్ చేయడంలో విఫలమైంది. బదులుగా ఒక PDF ని అప్‌లోడ్ చేయండి.",
"app.presentationUploder.conversion.officeDocConversionFailed": "ఆఫీస్ డాక్యుమెంట్ ప్రాసెస్ చేయడంలో విఫలమైంది. బదులుగా ఒక PDF ని అప్‌లోడ్ చేయండి.",
"app.presentationUploder.conversion.pdfHasBigPage": "మేము PDF ఫైల్‌ను మార్చలేకపోయాము, దయచేసి దాన్ని ఆప్టిమైజ్ చేయడానికి ప్రయత్నించండి. గరిష్ట పేజీ పరిమాణం {0}",
@ -219,6 +233,7 @@
"app.presentationUploder.itemPlural" : "అంశాలు",
"app.presentationUploder.clearErrors": "లోపాలను క్లియర్ చేయండి",
"app.presentationUploder.clearErrorsDesc": "విఫలమైన ప్రదర్శన అప్‌లోడ్‌లను క్లియర్ చేస్తుంది",
"app.presentationUploder.uploadViewTitle": "ప్రదర్శనను అప్‌లోడ్ చేయండి",
"app.poll.pollPaneTitle": "పోలింగ్",
"app.poll.quickPollTitle": "తక్షణ ఎన్నిక",
"app.poll.hidePollDesc": "పోల్ మెను పేన్‌ను దాచిపెడుతుంది",
@ -234,6 +249,8 @@
"app.poll.customPlaceholder": "పోల్ ఎంపికను జోడించండి",
"app.poll.noPresentationSelected": "ప్రదర్శన ఏదీ ఎంచుకోబడలేదు! దయచేసి ఒకదాన్ని ఎంచుకోండి.",
"app.poll.clickHereToSelect": "ఎంచుకోవడానికి ఇక్కడ క్లిక్ చేయండి",
"app.poll.question.label" : "మీ ప్రశ్న రాయండి ...",
"app.poll.optionalQuestion.label" : "మీ ప్రశ్న రాయండి (మీకు ఇష్టమైతే)...",
"app.poll.userResponse.label" : "వినియోగదారు ప్రతిస్పందన",
"app.poll.responseTypes.label" : "ప్రతిస్పందన రకాలు",
"app.poll.optionDelete.label" : "తొలగించు",
@ -241,14 +258,21 @@
"app.poll.typedResponse.desc" : "వినియోగదారులు వారి ప్రతిస్పందనను పూరించడానికి టెక్స్ట్ బాక్స్‌తో ప్రదర్శించబడతారు.",
"app.poll.addItem.label" : "వస్తువు జోడించు",
"app.poll.start.label" : "పోల్ ప్రారంభించండి",
"app.poll.secretPoll.label" : "అనామక పోల్",
"app.poll.secretPoll.isSecretLabel": "పోల్ అనామకంగా ఉంది - మీరు వ్యక్తిగత ప్రతిస్పందనలను చూడలేరు.",
"app.poll.questionErr": "ఒక ప్రశ్న అందించడం అవసరం.",
"app.poll.optionErr": "పోల్ ఎంపికను నమోదు చేయండి",
"app.poll.startPollDesc": "పోల్ ప్రారంభమవుతుంది\n ",
"app.poll.showRespDesc": "ప్రతిస్పందన అమరిక ప్రదర్శిస్తుంది",
"app.poll.addRespDesc": "పోల్ స్పందన ఇన్‌పుట్‌ను జతచేస్తుంది",
"app.poll.deleteRespDesc": "ఎంపికను తీసివేస్తుంది {0}",
"app.poll.t": "ఒప్పు",
"app.poll.f": "తప్పు",
"app.poll.tf": "ఒప్పు/తప్పు",
"app.poll.y": "అవును",
"app.poll.n": "కాదు",
"app.poll.abstention": "సంయమనం",
"app.poll.yna": "అవును / కాదు / సంయమనం",
"app.poll.abstention": "తిరస్కరించు",
"app.poll.yna": "అవును / కాదు / తిరస్కరించు",
"app.poll.a2": "A/B",
"app.poll.a3": "A / B / C",
"app.poll.a4": "A / B / C / D",
@ -257,7 +281,7 @@
"app.poll.answer.false": "తప్పు",
"app.poll.answer.yes": "అవును",
"app.poll.answer.no": "కాదు",
"app.poll.answer.abstention": "సంయమనం",
"app.poll.answer.abstention": "తిరస్కరించు",
"app.poll.answer.a": "A",
"app.poll.answer.b": "B",
"app.poll.answer.c": "C",
@ -265,11 +289,16 @@
"app.poll.answer.e": "E",
"app.poll.liveResult.usersTitle": "వినియోగదారులు",
"app.poll.liveResult.responsesTitle": "స్పందన",
"app.poll.liveResult.secretLabel": "ఇది అనామక పోల్. వ్యక్తిగత స్పందనలు చూపబడలేదు.",
"app.poll.removePollOpt": "తీసివేసిన పోల్ ఎంపిక {0}",
"app.poll.emptyPollOpt": "ఖాళీ",
"app.polling.pollingTitle": "పోలింగ్ ఎంపికలు",
"app.polling.pollQuestionTitle": "పోలింగ్ ప్రశ్న",
"app.polling.submitLabel": "సమర్పించండి",
"app.polling.submitAriaLabel": "పోల్ ప్రతిస్పందనను సమర్పించండి",
"app.polling.responsePlaceholder": "సమాధానం నమోదు చేయండి",
"app.polling.responseSecret": "అనామక పోల్ - ప్రెజెంటర్ మీ సమాధానం చూడలేరు.",
"app.polling.responseNotSecret": "సాధారణ పోల్ - ప్రెజెంటర్ మీ సమాధానాన్ని చూడగలరు.",
"app.polling.pollAnswerLabel": "పోల్ సమాధానం {0}",
"app.polling.pollAnswerDesc": "{0} కు ఓటు వేయడానికి ఈ ఎంపికను ఎంచుకోండి",
"app.failedMessage": "క్షమాపణలు, సర్వర్‌కు కనెక్ట్ చేయడంలో ఇబ్బంది.",
@ -326,6 +355,9 @@
"app.actionsBar.raiseLabel": "పెంచడం",
"app.actionsBar.label": "చర్యల పట్టీ",
"app.actionsBar.actionsDropdown.restorePresentationLabel": "ప్రదర్శనను పునరుద్ధరించండి",
"app.actionsBar.actionsDropdown.restorePresentationDesc": " ప్రదర్శనను తగ్గించిన తర్వాత దాన్ని పునరుద్ధరించె బటన్",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "ప్రదర్శన తగ్గించు",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "ప్రదర్శనను తగ్గించడానికి ఉపయోగించే బటన్",
"app.screenshare.screenShareLabel" : "స్క్రీన్ షేర్",
"app.submenu.application.applicationSectionTitle": "అప్లికేషన్",
"app.submenu.application.animationsLabel": "యానిమేషన్లు",
@ -337,13 +369,15 @@
"app.submenu.application.languageLabel": "అప్లికేషన్ భాష",
"app.submenu.application.languageOptionLabel": "భాషను ఎంచుకోండి",
"app.submenu.application.noLocaleOptionLabel": "చురుకైన స్థానికులు లేరు",
"app.submenu.application.paginationEnabledLabel": "వీడియో pagination",
"app.submenu.application.paginationEnabledLabel": "వీడియో పేజీజినేషన్",
"app.submenu.application.layoutOptionLabel": "లేఅవుట్ రకం",
"app.submenu.notification.SectionTitle": "నోటిఫికేషన్స్",
"app.submenu.notification.Desc": "మీకు ఎలా మరియు ఏమి తెలియజేయబడుతుందో చెప్పండి",
"app.submenu.notification.audioAlertLabel": "ఆడియో హెచ్చరికలు",
"app.submenu.notification.pushAlertLabel": "పాపప్ హెచ్చరికలు",
"app.submenu.notification.messagesLabel": "చాట్ సందేశం",
"app.submenu.notification.userJoinLabel": "వినియోగదారుడు చేరడo",
"app.submenu.notification.userLeaveLabel": "యూజర్ లీవ్",
"app.submenu.notification.guestWaitingLabel": "అతిథి నిరీక్షణ ఆమోదం",
"app.submenu.audio.micSourceLabel": "మైక్రోఫోన్ మూలం",
"app.submenu.audio.speakerSourceLabel": "స్పీకర్ మూలం",
@ -370,13 +404,15 @@
"app.settings.save-notification.label": "సెట్టింగులు సేవ్ చేయబడ్డాయి",
"app.statusNotifier.lowerHands": "చేతులను కిందకి దించారు",
"app.statusNotifier.raisedHandsTitle": "చేతులను పైకి ఎత్తారు",
"app.statusNotifier.raisedHandDesc": "{0 their వారి చేతులను పైకి లేపారు",
"app.statusNotifier.raisedHandDesc": "{0} వారి చేతులను పైకి లేపారు",
"app.statusNotifier.raisedHandDescOneUser": "{0} చేయి పైకెత్తింది",
"app.statusNotifier.and": "మరియు",
"app.switch.onLabel": "ఆన్",
"app.switch.offLabel": "ఆఫ్",
"app.talkingIndicator.ariaMuteDesc" : "వినియోగదారుని మ్యూట్ చేయడానికి ఎంచుకోండి",
"app.talkingIndicator.isTalking" : "{0} మాట్లాడుతున్నారు",
"app.talkingIndicator.moreThanMaxIndicatorsTalking" : "{0}+ మాట్లాడుతున్నారు",
"app.talkingIndicator.moreThanMaxIndicatorsWereTalking" : "{0}+ మాట్లాడుతున్నారు",
"app.talkingIndicator.wasTalking" : "{0} మాట్లాడటం మానేసారు",
"app.actionsBar.actionsDropdown.actionsLabel": "చర్యలు",
"app.actionsBar.actionsDropdown.presentationLabel": "ప్రదర్శనలను నిర్వహించండి",
@ -452,6 +488,8 @@
"app.audioModal.ariaTitle": "ఆడియో మోడల్‌లో చేరండి",
"app.audioModal.microphoneLabel": "మైక్రోఫోన్",
"app.audioModal.listenOnlyLabel": "వినడానికి మాత్రమే",
"app.audioModal.microphoneDesc": "మైక్‌తో ఆడియో కాన్ఫరెన్స్‌లో చేరండి",
"app.audioModal.listenOnlyDesc": "వినడానికి మాత్రమే ఆడియో కాన్ఫరెన్స్‌లో చేరండి",
"app.audioModal.audioChoiceLabel": "మీరు ఆడియోలో ఎలా చేరాలనుకుంటున్నారు?",
"app.audioModal.iOSBrowser": "ఆడియో / వీడియో మద్దతు లేదు",
"app.audioModal.iOSErrorDescription": "ఈ సమయంలో iOS కోసం Chrome లో ఆడియో మరియు వీడియో మద్దతు లేదు.",
@ -477,6 +515,7 @@
"app.audioModal.playAudio.arialabel" : "ఆడియో ప్లే చేయండి",
"app.audioDial.tipIndicator": "చిట్కా",
"app.audioDial.tipMessage": "మిమ్మల్ని మీరు మ్యూట్ / అన్‌మ్యూట్ చేయడానికి మీ ఫోన్‌లోని '0' కీని నొక్కండి.",
"app.audioModal.connecting": "ఆడియో కనెక్షన్‌ని ఏర్పాటు చేస్తోంది",
"app.audioManager.joinedAudio": "మీరు ఆడియో సమావేశంలో చేరారు",
"app.audioManager.joinedEcho": "మీరు ప్రతిధ్వని పరీక్షలో చేరారు",
"app.audioManager.leftAudio": "మీరు ఆడియో సమావేశం నుండి వదిలి వెళ్ళారు",
@ -488,6 +527,7 @@
"app.audioManager.mediaError": "లోపం: మీ మీడియా పరికరాలను పొందడంలో సమస్య ఉంది",
"app.audio.joinAudio": "ఆడియోలో చేరండి",
"app.audio.leaveAudio": "ఆడియోను వదిలివేయండి",
"app.audio.changeAudioDevice": "ఆడియో పరికరాన్ని మార్చండి",
"app.audio.enterSessionLabel": "సెషన్‌ను నమోదు చేయండి",
"app.audio.playSoundLabel": "ప్లే సౌండ్",
"app.audio.backLabel": "వెనక్కి",
@ -532,6 +572,7 @@
"app.error.401": "అనధికార",
"app.error.403": "మిమ్మల్ని సమావేశం నుండి తొలగించారు",
"app.error.404": "దొరకలేదు",
"app.error.408": "ధృవీకరణ విఫలమైంది",
"app.error.410": "సమావేశం ముగిసింది",
"app.error.500": "అయ్యో, ఏదో తప్పు జరిగింది",
"app.error.userLoggedOut": "లాగ్ అవుట్ కారణంగా వినియోగదారుకు చెల్లని సెషన్ టోకెన్ ఉంది",
@ -553,6 +594,7 @@
"app.guest.guestWait": "మీరు సమావేశంలో చేరడానికి మోడరేటర్ ఆమోదించడానికి దయచేసి వేచి ఉండండి.",
"app.guest.guestDeny": "సమావేశంలో పాల్గొనడానికి అతిథి నిరాకరించారు.",
"app.guest.seatWait": "సమావేశంలో సీటు కోసం వేచి ఉన్న అతిథి.",
"app.guest.allow": "అతిథి ఆమోదించబడ్డారు మరియు సమావేశానికి దారి మళ్లించబడ్డారు.",
"app.userList.guest.waitingUsers": "వినియోగదారులు వేచి ఉన్నారు",
"app.userList.guest.waitingUsersTitle": "వినియోగదారుని నిర్వహణ",
"app.userList.guest.optionTitle": "పెండింగ్ వినియోగదారులను రివ్యు చేయండి",
@ -584,6 +626,7 @@
"app.notification.recordingPaused": "ఈ సెషన్ ఇకపై రికార్డ్ చేయబడదు",
"app.notification.recordingAriaLabel": "రికార్డ్ చేసిన సమయం",
"app.notification.userJoinPushAlert": "{0 } సెషన్‌లో చేరారు",
"app.notification.userLeavePushAlert": "{0} సెషన్ నుండి వెళ్లిపోయారు",
"app.submenu.notification.raiseHandLabel": "చేయి పైకెత్తండి",
"app.shortcut-help.title": "యాక్సెస్ కీలు అందుబాటులో లేవు",
"app.shortcut-help.accessKeyNotAvailable": "యాక్సెస్ కీలు అందుబాటులో లేవు",
@ -627,14 +670,25 @@
"app.guest-policy.button.askModerator": "మోడరేటర్‌ను అడగండి",
"app.guest-policy.button.alwaysAccept": "ఎల్లప్పుడూ అంగీకరించండి",
"app.guest-policy.button.alwaysDeny": "ఎల్లప్పుడూ తిరస్కరించండి",
"app.guest-policy.policyBtnDesc": "మీటింగ్ గెస్ట్ పాలసీని సెట్ చేయండి",
"app.connection-status.ariaTitle": "కనెక్షన్ స్థితి మోడల్",
"app.connection-status.title": "కనెక్షన్ స్థితి",
"app.connection-status.description": "వినియోగదారుల కనెక్షన్ స్థితిని చూడండి",
"app.connection-status.empty": "ప్రస్తుతం నివేదించబడిన కనెక్షన్ సమస్యలు లేవు",
"app.connection-status.more": "మరిన్ని",
"app.connection-status.copy": "నెట్‌వర్క్ డేటాను కాపీ చేయండి",
"app.connection-status.copied": "కాపీ చేయబడింది!",
"app.connection-status.jitter": "గందరగోళం",
"app.connection-status.label": "కనెక్షన్ స్థితి",
"app.connection-status.no": "లేదు",
"app.connection-status.notification": "మీ కనెక్షన్‌లో నష్టం కనుగొనబడింది",
"app.connection-status.offline": "ఆఫ్‌లైన్",
"app.connection-status.lostPackets": "కోల్పోయిన ప్యాకెట్లు",
"app.connection-status.usingTurn": "TURN ని ఉపయోగిస్తోంది",
"app.connection-status.yes": "అవును",
"app.learning-dashboard.label": "లెర్నింగ్ డాష్‌బోర్డ్‌",
"app.learning-dashboard.description": "వినియోగదారుల కార్యకలాపాలతో డ్యాష్‌బోర్డ్‌ని తెరవండి",
"app.learning-dashboard.clickHereToOpen": "లెర్నింగ్ డాష్‌బోర్డ్‌ను తెరవండి",
"app.recording.startTitle": "రికార్డింగ్ ప్రారంభించు",
"app.recording.stopTitle": "రికార్డింగ్‌ను పాజ్ చేయి",
"app.recording.resumeTitle": "రికార్డింగ్‌ను తిరిగి ప్రారంభించు",
@ -656,6 +710,8 @@
"app.videoPreview.webcamOptionLabel": "వెబ్‌క్యామ్‌ను ఎంచుకోండి",
"app.videoPreview.webcamPreviewLabel": "వెబ్‌క్యామ్ ప్రివ్యూ",
"app.videoPreview.webcamSettingsTitle": "వెబ్‌క్యామ్ సెట్టింగులు",
"app.videoPreview.webcamVirtualBackgroundLabel": "వర్చువల్ బ్యాక్‌గ్రౌండ్ సెట్టింగులు",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "ఈ పరికరం వర్చువల్ బ్యాక్‌గ్రౌండ్‌లకు మద్దతు ఇవ్వదు",
"app.videoPreview.webcamNotFoundLabel": "వెబ్‌క్యామ్ కనుగొనబడలేదు",
"app.videoPreview.profileNotFoundLabel": "కెమెరా ప్రొఫైల్ కు మద్దతు లేదు",
"app.video.joinVideo": "వెబ్‌క్యామ్‌ను షేర్ చేయండి",
@ -675,6 +731,7 @@
"app.video.notReadableError": "వెబ్‌క్యామ్ వీడియో పొందలేకపోయాము. దయచేసి మరొక ప్రోగ్రామ్ ,వెబ్‌క్యామ్‌ను ఉపయోగించడం లేదని నిర్ధారించుకోండి",
"app.video.timeoutError": "బ్రౌజర్ సకాలంలో స్పందించలేదు.",
"app.video.genericError": "ഉപകരണത്തിൽ ഒരു അജ്ഞാത പിശക് സംഭവിച്ചു (പിശക് {0})",
"app.video.mediaTimedOutError": "మీ వెబ్‌క్యామ్ స్ట్రీమ్‌కు అంతరాయం ఏర్పడింది. దాన్ని మళ్లీ షేర్ చేయడానికి ప్రయత్నించండి",
"app.video.mediaFlowTimeout1020": "మీడియా సర్వర్‌కు చేరుకోలేదు (లోపం 1020)",
"app.video.suggestWebcamLock": "వీక్షకుల వెబ్‌క్యామ్‌కు లాక్ సెట్టింగ్‌ను అమలు చేయాలా?",
"app.video.suggestWebcamLockReason": "(ఇది సమావేశం యొక్క స్థిరత్వాన్ని మెరుగుపరుస్తుంది)",
@ -689,9 +746,16 @@
"app.video.videoMenuDesc": "వీడియో మెను డ్రాప్‌డౌన్ తెరవండి",
"app.video.pagination.prevPage": "മുമ്പത്തെ വീഡിയോകൾ കാണുക",
"app.video.pagination.nextPage": "അടുത്ത വീഡിയോകൾ കാണുക",
"app.video.clientDisconnected": "കണക്ഷൻ പ്രശ്‌നങ്ങൾ കാരണം വെബ്‌ക്യാം പങ്കിടാൻ കഴിയില്ല",
"app.video.clientDisconnected": "కనెక్షన్ సమస్యల కారణంగా వెబ్‌క్యామ్ షేర్ చేయబడదు",
"app.video.virtualBackground.none": "ఏదీ లేదు",
"app.video.virtualBackground.blur": "అస్పష్టత",
"app.video.virtualBackground.genericError": "కెమెరా ప్రభావాన్ని వర్తింపజేయడంలో విఫలమైంది. మళ్లీ ప్రయత్నించండి.",
"app.video.virtualBackground.camBgAriaDesc": "వెబ్‌క్యామ్ వర్చువల్ బ్యాక్ గ్రౌండ్ {0} కి సెట్ చేస్తుంది",
"app.video.dropZoneLabel": "ఇక్కడ డ్రాప్ చేయండి",
"app.fullscreenButton.label": "పూర్తి స్క్రీన్{0} చేయండి",
"app.fullscreenUndoButton.label": "Screen 0} പൂർണ്ണസ്‌ക്രീൻ പഴയപടിയാക്കുക",
"app.switchButton.expandLabel": "స్క్రీన్ షేర్ వీడియోను విస్తరించండి",
"app.switchButton.shrinkLabel": "స్క్రీన్ షేర్ వీడియోను కుదించండి",
"app.sfu.mediaServerConnectionError2000": "మీడియా సర్వర్‌కు కనెక్ట్ చేయడం సాధ్యం కాలేదు (లోపం 2000)",
"app.sfu.mediaServerOffline2001": "మీడియా సర్వర్ ఆఫ్‌లైన్‌లో ఉంది. దయచేసి తరువాత మళ్ళీ ప్రయత్నించండి (లోపం 2001)",
"app.sfu.mediaServerNoResources2002": "మీడియా సర్వర్‌కు అందుబాటులో ఉన్న వనరులు లేవు (లోపం 2002)",
@ -735,13 +799,14 @@
"app.whiteboard.toolbar.palmRejectionOn": "ഈന്തപ്പന നിരസിക്കൽ ഓണാക്കുക",
"app.whiteboard.toolbar.palmRejectionOff": "ഈന്തപ്പന നിരസിക്കൽ ഓഫാക്കുക",
"app.whiteboard.toolbar.fontSize": "ఫాంట్ పరిమాణ జాబితా",
"app.whiteboard.toolbarAriaLabel": "ప్రదర్శన సాధనాలు",
"app.feedback.title": "మీరు సమావేశం నుండి లాగ్ అవుట్ అయ్యారు",
"app.feedback.subtitle": "బిగ్‌బ్లూబటన్ తో మీ అనుభవం గురించి వినడానికి మేము ఇష్టపడతాము (మీ ఇష్ట ప్రకారం ) .",
"app.feedback.textarea": "బిగ్‌బ్లూబటన్‌ను ఎలా మెరుగుపరుస్తాము?",
"app.feedback.sendFeedback": "అభిప్రాయాన్ని పంపండి",
"app.feedback.sendFeedbackDesc": "అభిప్రాయాన్ని పంపండి మరియు సమావేశాన్ని వదిలివేయండి",
"app.videoDock.webcamMirrorLabel": "കണ്ണാടി",
"app.videoDock.webcamMirrorDesc": "തിരഞ്ഞെടുത്ത വെബ്‌ക്യാം മിറർ ചെയ്യുക",
"app.videoDock.webcamMirrorDesc": "ఎంచుకున్న వెబ్‌క్యామ్‌ను ప్రతిబింబిస్తుంది",
"app.videoDock.webcamFocusLabel": "దృష్టి",
"app.videoDock.webcamFocusDesc": "ఎంచుకున్న వెబ్‌క్యామ్‌పై దృష్టి పెట్టండి",
"app.videoDock.webcamUnfocusLabel": "దృష్టి లేని",
@ -753,7 +818,9 @@
"app.createBreakoutRoom.title": "బ్రేక్అవుట్ రూములు",
"app.createBreakoutRoom.ariaTitle": "బ్రేక్అవుట్ గదులను దాచండి",
"app.createBreakoutRoom.breakoutRoomLabel": "బ్రేక్అవుట్ రూములు {0}",
"app.createBreakoutRoom.askToJoin": "చేరమని అడగండి",
"app.createBreakoutRoom.generatingURL": "URL ను సృష్టిస్తోంది",
"app.createBreakoutRoom.generatingURLMessage": "మేము ఎంచుకున్న బ్రేక్అవుట్ రూమ్ కోసం జాయిన్ URL ని రూపొందిస్తున్నాము. ఇది కొన్ని సెకన్ల సమయం పట్టవచ్చు...",
"app.createBreakoutRoom.duration": "వ్యవధి {0}",
"app.createBreakoutRoom.room": "గది {0}",
"app.createBreakoutRoom.notAssigned": "కేటాయించబడలేదు ({0})",
@ -766,6 +833,7 @@
"app.createBreakoutRoom.numberOfRooms": "గదుల సంఖ్య",
"app.createBreakoutRoom.durationInMinutes": "వ్యవధి (నిమిషాలు)",
"app.createBreakoutRoom.randomlyAssign": "అస్తవ్యస్తంగా కేటాయించండి",
"app.createBreakoutRoom.randomlyAssignDesc": "వినియోగదారులను రేండం గా బ్రేక్అవుట్ రూమ్‌లకు కేటాయిస్తుంది",
"app.createBreakoutRoom.endAllBreakouts": "అన్ని బ్రేక్అవుట్ గదులను ముగించండి",
"app.createBreakoutRoom.roomName": "{0} (గది - {1})",
"app.createBreakoutRoom.doneLabel": "పూర్తి అయ్యింది",
@ -775,9 +843,17 @@
"app.createBreakoutRoom.addParticipantLabel": "+ పాల్గొనేవారిని జోడించండి",
"app.createBreakoutRoom.freeJoin": "వినియోగదారులు చేరడానికి ఒక బ్రేక్అవుట్ గది ఎంచుకొవడానికి అనుమతి ని ఇవ్వండి",
"app.createBreakoutRoom.leastOneWarnBreakout": "మీరు కనీసం ఒక వినియోగదారుడ్ని బ్రేక్అవుట్ గదిలో ఉంచాలి.",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "బ్రేక్అవుట్ గదికి కనీస వ్యవధి {0} నిమిషాలు.",
"app.createBreakoutRoom.modalDesc": "చిట్కా: మీరు ఒక నిర్దిష్ట బ్రేక్అవుట్ గదికి కేటాయించడానికి వినియోగదారు పేరును డ్రాగ్ మరియు డ్రాప్ చేయండి.",
"app.createBreakoutRoom.roomTime": "{0}నిమిషాలు",
"app.createBreakoutRoom.numberOfRoomsError": "గదుల సంఖ్య చెల్లదు.",
"app.createBreakoutRoom.duplicatedRoomNameError": "గది పేరు నకిలీ చేయబడదు.",
"app.createBreakoutRoom.emptyRoomNameError": "గది పేరు ఖాళీగా ఉండకూడదు.",
"app.createBreakoutRoom.extendTimeInMinutes": "పొడిగించే సమయం (నిమిషాలు)",
"app.createBreakoutRoom.extendTimeLabel": "పొడిగించు",
"app.createBreakoutRoom.extendTimeCancel": "రద్దు చేయండి",
"app.createBreakoutRoom.extendTimeHigherThanMeetingTimeError": "బ్రేక్అవుట్ గదుల వ్యవధి సమావేశం మిగిలిన సమయాన్ని మించకూడదు.",
"app.createBreakoutRoom.roomNameInputDesc": "బ్రేక్అవుట్ రూమ్ పేరును అప్‌డేట్ చేస్తుంది",
"app.externalVideo.start": "కొత్త వీడియోను షేర్ చేయండి",
"app.externalVideo.title": "బాహ్య వీడియోను షేర్ చేయండి",
"app.externalVideo.input": "బాహ్య వీడియో URL",
@ -785,6 +861,7 @@
"app.externalVideo.urlError": "ఈ వీడియో URL కి మద్దతు లేదు",
"app.externalVideo.close": "మూసివేయి",
"app.externalVideo.autoPlayWarning": "మీడియా సమకాలీకరణను ప్రారంభించడానికి వీడియోను ప్లే చేయండి",
"app.externalVideo.refreshLabel": "వీడియో ప్లేయర్‌ని రిఫ్రెష్ చేయండి",
"app.externalVideo.noteLabel": "గమనిక: షేర్ చేసిన బాహ్య వీడియోలు రికార్డింగ్‌లో కనిపించవు. యూట్యూబ్, విమియో, ఇన్‌స్ట్రక్చర్ మీడియా, ట్విచ్, డైలీమోషన్ మరియు మీడియా ఫైల్ URL లకు (ఉ.దా: https://example.com/xy.mp4) మద్దతు ఉంది.",
"app.actionsBar.actionsDropdown.shareExternalVideo": "బాహ్య వీడియోను షేర్ చేయండి",
"app.actionsBar.actionsDropdown.stopShareExternalVideo": "బాహ్య వీడియోను షేర్ చేయడం ఆపివేయండి",
@ -796,7 +873,71 @@
"app.debugWindow.form.userAgentLabel": "ഉപയോക്തൃ ഏജൻറ്",
"app.debugWindow.form.button.copy": "പകർത്തുക",
"app.debugWindow.form.enableAutoarrangeLayoutLabel": "യാന്ത്രിക ക്രമീകരണ ലേ Layout ട്ട് പ്രവർത്തനക്ഷമമാക്കുക",
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(നിങ്ങൾ വെബ്‌ക്യാം ഏരിയ വലിച്ചിടുകയോ വലുപ്പം മാറ്റുകയോ ചെയ്താൽ ഇത് പ്രവർത്തനരഹിതമാകും)"
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(మీరు వెబ్‌క్యామ్‌ల ప్రాంతాన్ని లాగడం లేదా పరిమాణం మార్చడం ద్వారా ఇది నిలిపివేయబడుతుంది)",
"app.debugWindow.form.chatLoggerLabel": "చాట్ లాగర్ లెవల్స్ ను పరీక్షించండి",
"app.debugWindow.form.button.apply": "అమలు చేయి",
"app.layout.style.custom": "వాడుక",
"app.layout.style.smart": "స్మార్ట్ లేఅవుట్",
"app.layout.style.presentationFocus": "ప్రదర్శనపై దృష్టి పెట్టండి",
"app.layout.style.videoFocus": "వీడియోపై దృష్టి పెట్టండి",
"app.layout.style.presentationFocusPush": "ప్రెజెంటేషన్‌పై దృష్టి పెట్టండి (అందరికీ లేఅవుట్‌ను నెట్టండి)",
"app.layout.style.videoFocusPush": "వీడియోపై దృష్టి పెట్టండి (అందరికీ లేఅవుట్‌ను పుష్ చేయండి)",
"playback.button.about.aria": "గురించి",
"playback.button.clear.aria": "శోధనను క్లియర్ చేయండి",
"playback.button.close.aria": "మోడల్‌ను మూసివేయండి",
"playback.button.fullscreen.aria": "పూర్తి స్క్రీన్ విషయము",
"playback.button.restore.aria": "కంటెంట్‌ను పునరుద్ధరించండి",
"playback.button.search.aria": "వెతకండి",
"playback.button.section.aria": "పక్క విభాగం",
"playback.button.swap.aria": "కంటెంట్‌ను మార్చుకోండి",
"playback.error.wrapper.aria": "లోపం ప్రాంతం",
"playback.loader.wrapper.aria": "లోడ్ చేసే ప్రాంతం",
"playback.player.wrapper.aria": "ప్లేయర్ ప్రాంతం",
"playback.player.chat.message.poll.name": "పోల్ ఫలితం",
"playback.player.chat.message.poll.question": "ప్రశ్న",
"playback.player.chat.message.poll.options": "ఎంపికలు",
"playback.player.chat.message.poll.option.yes": "అవును",
"playback.player.chat.message.poll.option.no": "కాదు",
"playback.player.chat.message.poll.option.abstention": "తిరస్కరించు",
"playback.player.chat.message.poll.option.true": "ఒప్పు",
"playback.player.chat.message.poll.option.false": "తప్పు",
"playback.player.chat.message.externalVideo.name": "బాహ్య వీడియో ",
"playback.player.chat.wrapper.aria": "కబుర్లుప్రదేశం",
"playback.player.notes.wrapper.aria": "నోట్స్ ప్రాంతం",
"playback.player.presentation.wrapper.aria": "ప్రదర్శన ప్రాంతం",
"playback.player.screenshare.wrapper.aria": "స్క్రీన్ షేర్ ప్రాంతం",
"playback.player.search.modal.title": "వెతకండి",
"playback.player.search.modal.subtitle": "ప్రదర్శన స్లయిడ్‌ల కంటెంట్‌ను కనుగొనండి",
"playback.player.thumbnails.wrapper.aria": "సూక్ష్మచిత్రాల ప్రాంతం",
"playback.player.video.wrapper.aria": "వీడియో ప్రాంతం",
"app.learningDashboard.dashboardTitle": "చాట్ ప్రదేశం",
"app.learningDashboard.user": "వినియోగదారుడు ",
"app.learningDashboard.indicators.meetingStatusEnded": "ముగిసింది",
"app.learningDashboard.indicators.meetingStatusActive": "యాక్టివ్",
"app.learningDashboard.indicators.usersOnline": "క్రియాశీల వినియోగదారులు",
"app.learningDashboard.indicators.usersTotal": "మొత్తం వినియోగదారుల సంఖ్య",
"app.learningDashboard.indicators.polls": "పోల్స్",
"app.learningDashboard.indicators.raiseHand": "చేయి పైకెత్తండి",
"app.learningDashboard.indicators.activityScore": "కార్యాచరణ స్కోరు",
"app.learningDashboard.indicators.duration": "వ్యవధి",
"app.learningDashboard.usersTable.title": "సారాంశం",
"app.learningDashboard.usersTable.colOnline": "ఆన్‌లైన్ సమయం",
"app.learningDashboard.usersTable.colTalk": "మాట్లాడు సమయం",
"app.learningDashboard.usersTable.colWebcam": "వెబ్‌క్యామ్ సమయం",
"app.learningDashboard.usersTable.colMessages": "సందేశాలు",
"app.learningDashboard.usersTable.colEmojis": "ఎమోజీలు",
"app.learningDashboard.usersTable.colRaiseHands": "చేతులు పైకెత్తండి",
"app.learningDashboard.usersTable.colActivityScore": "కార్యాచరణ స్కోరు",
"app.learningDashboard.usersTable.colStatus": "స్థితి",
"app.learningDashboard.usersTable.userStatusOnline": "ఆన్లైన్",
"app.learningDashboard.usersTable.userStatusOffline": "ఆఫ్‌లైన్",
"app.learningDashboard.usersTable.noUsers": "ఇంకా వినియోగదారులు లేరు",
"app.learningDashboard.pollsTable.title": "పోలింగ్",
"app.learningDashboard.pollsTable.anonymousAnswer": "అనామక పోల్ (చివరి వరుసలో సమాధానాలు)",
"app.learningDashboard.pollsTable.anonymousRowName": "అనామక",
"app.learningDashboard.statusTimelineTable.title": "స్థితి కాలక్రమం",
"app.learningDashboard.errors.invalidToken": "సెషన్ టోకెన్ చెల్లదు",
"app.learningDashboard.errors.dataUnavailable": "డేటా ఇకపై అందుబాటులో ఉండదు"
}

View File

@ -18,7 +18,7 @@
"app.chat.dropdown.save": "Kaydet",
"app.chat.label": "Sohbet",
"app.chat.offline": "Çevrimdışı",
"app.chat.pollResult": "Anket sonuçları",
"app.chat.pollResult": "Anket Sonuçları",
"app.chat.emptyLogLabel": "Sohbet günlüğü boş",
"app.chat.clearPublicChatMessage": "Herkese açık sohbet geçmişi sorumlu tarafından temizlendi",
"app.chat.multi.typing": "Birkaç kullanıcı yazıyor",
@ -48,6 +48,8 @@
"app.captions.pad.dictationStop": "Dikteyi durdur",
"app.captions.pad.dictationOnDesc": " Konuşma tanımayı açar",
"app.captions.pad.dictationOffDesc": " Konuşma tanımayı kapatır",
"app.textInput.sendLabel": "Gönder",
"app.title.defaultViewLabel": "Varsayılan sunum görünümü",
"app.note.title": "Paylaşılan Notlar",
"app.note.label": "Not",
"app.note.hideNoteLabel": "Notu gizle",
@ -67,8 +69,11 @@
"app.userList.byModerator": "(Sorumlu) tarafından",
"app.userList.label": "Kullanıcı listesi",
"app.userList.toggleCompactView.label": "Basit görünüm kipini aç/kapat",
"app.userList.mobile": "Mobil",
"app.userList.guest": "Konuk",
"app.userList.sharingWebcam": "Web kamerası",
"app.userList.menuTitleContext": "Kullanılabilecek seçenekler",
"app.userList.chatListItem.unreadSingular": "Bir yeni ileti",
"app.userList.menu.chat.label": "Özel sohbet başlat",
"app.userList.menu.clearStatus.label": "Durumu temizle",
"app.userList.menu.removeUser.label": "Kullanıcıyı sil",
@ -213,6 +218,7 @@
"app.poll.customPlaceholder": "Anket seçeneği ekle",
"app.poll.noPresentationSelected": "Herhangi bir sunum seçilmemiş! Lütfen bir sunum seçin.",
"app.poll.clickHereToSelect": "Seçmek için buraya tıklayın",
"app.poll.optionDelete.label" : "Sil",
"app.poll.t": "Doğru",
"app.poll.f": "Yanlış",
"app.poll.tf": "Doğru / Yanlış",
@ -293,6 +299,7 @@
"app.submenu.application.languageLabel": "Uygulama Dili",
"app.submenu.application.languageOptionLabel": "Dil seçin",
"app.submenu.application.noLocaleOptionLabel": "Etkin bir dil bulunamadı",
"app.submenu.application.paginationEnabledLabel": "Video sayfalama",
"app.submenu.notification.SectionTitle": "Bildirimler",
"app.submenu.notification.Desc": "Nasıl ve neye bildirileceğinizi tanımlayın.",
"app.submenu.notification.audioAlertLabel": "Sesli Uyarılar",

View File

@ -18,7 +18,7 @@
"app.chat.dropdown.copy": "Kopyala",
"app.chat.dropdown.save": "Kaydet",
"app.chat.label": "Sohbet",
"app.chat.offline": "Çevrimdışı",
"app.chat.offline": "Çevrim Dışı",
"app.chat.pollResult": "Anket sonuçları",
"app.chat.emptyLogLabel": "Sohbet sistem kayıtları boş",
"app.chat.clearPublicChatMessage": "Genel sohbet geçmişi moderatör tarafından temizlendi",
@ -87,7 +87,7 @@
"app.userList.menu.removeConfirmation.label": "({0}) kullanıcısını kaldır",
"app.userlist.menu.removeConfirmation.desc": "Bu kullanıcının oturuma yeniden katılması engellensin",
"app.userList.menu.muteUserAudio.label": "Kullanıcıyı sustur",
"app.userList.menu.unmuteUserAudio.label": "Kullanıcıyı konuştur",
"app.userList.menu.unmuteUserAudio.label": "Kullanıcı Sesini Aç",
"app.userList.menu.giveWhiteboardAccess.label" : "Tahta Erişimi Verin",
"app.userList.menu.removeWhiteboardAccess.label": "Tahta Erişimini Kaldırın",
"app.userList.userAriaLabel": "{0} {1} {2} Durum {3}",
@ -104,7 +104,7 @@
"app.userList.userOptions.clearAllDesc": "Tüm durum simgelerini kullanıcılardan temizler",
"app.userList.userOptions.muteAllExceptPresenterLabel": "Sunucu Hariç Tümünü Sustur",
"app.userList.userOptions.muteAllExceptPresenterDesc": "Toplantıda sunum yapan kişi dışındaki tüm kullanıcıları susturur",
"app.userList.userOptions.unmuteAllLabel": "Toplantı sesini kapatma",
"app.userList.userOptions.unmuteAllLabel": "Toplantı Sesini Aç",
"app.userList.userOptions.unmuteAllDesc": "Toplantı sesini aç",
"app.userList.userOptions.lockViewersLabel": "Katılımcıları Kilitle",
"app.userList.userOptions.lockViewersDesc": "Toplantı katılımcıları için bazı işlevleri kilitle",
@ -350,7 +350,7 @@
"app.about.dismissDesc": "Kullanıcı bilgilerini kapat",
"app.actionsBar.changeStatusLabel": "Durumu değiştir",
"app.actionsBar.muteLabel": "Sustur",
"app.actionsBar.unmuteLabel": "Konuştur",
"app.actionsBar.unmuteLabel": "Sesi Aç",
"app.actionsBar.camOffLabel": "Kamera kapalı",
"app.actionsBar.raiseLabel": "El Kaldır",
"app.actionsBar.label": "Eylemler çubuğu",
@ -404,7 +404,7 @@
"app.settings.save-notification.label": "Ayarlar kaydedildi",
"app.statusNotifier.lowerHands": "Elleri indir",
"app.statusNotifier.raisedHandsTitle": "Kalkık eller",
"app.statusNotifier.raisedHandDesc": "{0} kişi ellerini kaldırdı",
"app.statusNotifier.raisedHandDesc": "{0} kişi ellini kaldırdı",
"app.statusNotifier.raisedHandDescOneUser": "{0} el kaldırma",
"app.statusNotifier.and": "ve",
"app.switch.onLabel": "AÇIK",
@ -616,7 +616,7 @@
"app.toast.clearedEmoji.label": "Emoji durumu temizlendi",
"app.toast.setEmoji.label": "Emoji durumu {0} olarak ayarlandı",
"app.toast.meetingMuteOn.label": "Tüm kullanıcılar için ses kapatıldı",
"app.toast.meetingMuteOff.label": "Toplantı sesini kapatma kapatıldı",
"app.toast.meetingMuteOff.label": "Toplantı sesiıldı.",
"app.toast.setEmoji.raiseHand": "Elinizi kaldırdınız",
"app.toast.setEmoji.lowerHand": "Elinizi indirdiniz",
"app.notification.recordingStart": "Bu oturum şu anda kaydediliyor",
@ -634,7 +634,7 @@
"app.shortcut-help.closeDesc": "Klavye kısayolları modunu kapatır",
"app.shortcut-help.openOptions": "Seçenekleri Aç",
"app.shortcut-help.toggleUserList": "Kullanıcı Listesine Geç",
"app.shortcut-help.toggleMute": "Sustur / Konuştur",
"app.shortcut-help.toggleMute": "Sessiz / Sesi Aç",
"app.shortcut-help.togglePublicChat": "Genel Sohbeti değiştir (Kullanıcı listesi açık olmalıdır)",
"app.shortcut-help.hidePrivateChat": "Özel mesajı gizle",
"app.shortcut-help.closePrivateChat": "Özel mesajı kapat",
@ -663,7 +663,7 @@
"app.lock-viewers.locked": "Kilitli",
"app.lock-viewers.unlocked": "Açık",
"app.guest-policy.ariaTitle": "Misafir politikası ayarları modeli",
"app.guest-policy.title": "Misafir politikası",
"app.guest-policy.title": "Misafir Politikası",
"app.guest-policy.description": "Toplantı misafir politika ayarını değiştirin",
"app.guest-policy.button.askModerator": "Moderatöre sorun",
"app.guest-policy.button.alwaysAccept": "Her zaman kabul edin",
@ -680,7 +680,7 @@
"app.connection-status.label": "Bağlantı Durumu",
"app.connection-status.no": "Hayır",
"app.connection-status.notification": "Bağlantınızda kayıp tespit edildi",
"app.connection-status.offline": "çevrimdışı",
"app.connection-status.offline": "çevrim dışı",
"app.connection-status.lostPackets": "Kayıp Paketler",
"app.connection-status.usingTurn": "TURN Kullanımı",
"app.connection-status.yes": "Evet",
@ -755,7 +755,7 @@
"app.switchButton.expandLabel": "Ekran paylaşım videosunu genişlet",
"app.switchButton.shrinkLabel": "Ekran paylaşım videosunu küçült",
"app.sfu.mediaServerConnectionError2000": "Medya sunucusuna ulaşılamıyor (hata 2000)",
"app.sfu.mediaServerOffline2001": "Medya sunucusu çevrimdışı. Lütfen daha sonra tekrar deneyin (hata 2001)",
"app.sfu.mediaServerOffline2001": "Medya sunucusu çevrim dışı. Lütfen daha sonra tekrar deneyin (hata 2001)",
"app.sfu.mediaServerNoResources2002": "Medya sunucunun kullanım için uygun kaynağı yok (hata 2002)",
"app.sfu.mediaServerRequestTimeout2003": "Medya sunucu istekleri zaman aşımına uğruyor (hata 2003)",
"app.sfu.serverIceGatheringFailed2021": "Medya sunucu bağlantı parametrelerini alamıyor (ICE hatası 2021)",
@ -794,8 +794,8 @@
"app.whiteboard.toolbar.clear": "Tüm Ek Açıklamaları Temizle",
"app.whiteboard.toolbar.multiUserOn": "Çoklu kullanıcı modunu aç",
"app.whiteboard.toolbar.multiUserOff": "Çoklu kullanıcı modunu kapat",
"app.whiteboard.toolbar.palmRejectionOn": "Reddini açın",
"app.whiteboard.toolbar.palmRejectionOff": "Reddini kapatın",
"app.whiteboard.toolbar.palmRejectionOn": "Avuç içi reddetmeyi aç",
"app.whiteboard.toolbar.palmRejectionOff": "Avuç içi reddetmeyi kapat",
"app.whiteboard.toolbar.fontSize": "Yazı tipi boyutu listesi",
"app.whiteboard.toolbarAriaLabel": "Sunum araçları",
"app.feedback.title": "Konferanstan ayrıldınız",
@ -816,6 +816,7 @@
"app.createBreakoutRoom.title": "Çalışma Odaları",
"app.createBreakoutRoom.ariaTitle": "Çalışma Odalarını Gizle",
"app.createBreakoutRoom.breakoutRoomLabel": "Çalışma Odası {0}",
"app.createBreakoutRoom.askToJoin": "Katılmayı İste",
"app.createBreakoutRoom.generatingURL": "URL oluşturuluyor",
"app.createBreakoutRoom.generatingURLMessage": "Seçilen çalışma odası için bir katılım URL'si oluşturuyoruz. Birkaç saniye sürebilir...",
"app.createBreakoutRoom.duration": "Süre {0}",
@ -918,22 +919,22 @@
"app.learningDashboard.indicators.activityScore": "Etkinlik Puanı",
"app.learningDashboard.indicators.duration": "Süre",
"app.learningDashboard.usersTable.title": "Genel bakış",
"app.learningDashboard.usersTable.colOnline": "Online süresi",
"app.learningDashboard.usersTable.colTalk": "Konuşma süresi",
"app.learningDashboard.usersTable.colWebcam": "Webkamera süresi",
"app.learningDashboard.usersTable.colOnline": "Çevrim İçi Süre",
"app.learningDashboard.usersTable.colTalk": "Konuşma Süresi",
"app.learningDashboard.usersTable.colWebcam": "Web Kamera Süresi",
"app.learningDashboard.usersTable.colMessages": "Mesaj",
"app.learningDashboard.usersTable.colEmojis": "Emojiler",
"app.learningDashboard.usersTable.colRaiseHands": "El Kaldır",
"app.learningDashboard.usersTable.colActivityScore": "Etkinlik skoru",
"app.learningDashboard.usersTable.colActivityScore": "Etkinlik Puanı",
"app.learningDashboard.usersTable.colStatus": "Durum",
"app.learningDashboard.usersTable.userStatusOnline": "Çevrimiçi",
"app.learningDashboard.usersTable.userStatusOffline": "Çevrimdışı",
"app.learningDashboard.usersTable.userStatusOffline": "Çevrim Dışı",
"app.learningDashboard.usersTable.noUsers": "Henüz kullanıcı yok",
"app.learningDashboard.pollsTable.title": "Anket",
"app.learningDashboard.pollsTable.anonymousAnswer": "İsimsiz Anket (cevaplar son satırda)",
"app.learningDashboard.pollsTable.anonymousRowName": "İsimsiz",
"app.learningDashboard.statusTimelineTable.title": "Durum Zaman Çizelgesi",
"app.learningDashboard.errors.invalidToken": "Geçersiz oturum tokenı",
"app.learningDashboard.errors.invalidToken": "Geçersiz oturum anahtarı.",
"app.learningDashboard.errors.dataUnavailable": "Veri artık erişilebilir değil"
}

View File

@ -25,6 +25,8 @@
"app.chat.multi.typing": "Nhiều người dùng đang gõ",
"app.chat.one.typing": "{0} đang gõ",
"app.chat.two.typing": "{0} và {1} đang gõ",
"app.chat.copySuccess": "Bản ghi cuộc trò chuyện đã sao chép",
"app.chat.copyErr": "Sao chép bản ghi cuộc trò chuyện không thành công",
"app.captions.label": "Chú thích",
"app.captions.menu.close": "Đóng",
"app.captions.menu.start": "Mở",
@ -49,7 +51,9 @@
"app.captions.pad.dictationStop": "Dừng đọc chính tả",
"app.captions.pad.dictationOnDesc": "Bật nhận diện giọng nói",
"app.captions.pad.dictationOffDesc": "Tắt nhận diện giọng nói",
"app.captions.pad.speechRecognitionStop": "Tính năng nhận dạng giọng nói đã dừng do trình duyệt không tương thích hoặc một thời gian im lặng",
"app.textInput.sendLabel": "Gửi",
"app.title.defaultViewLabel": "Chế độ xem bản trình bày mặc định",
"app.note.title": "Ghi chú chung",
"app.note.label": "Ghi chú",
"app.note.hideNoteLabel": "Ẩn ghi chú",
@ -73,7 +77,10 @@
"app.userList.moderator": "Người điều hành",
"app.userList.mobile": "Điện thoại",
"app.userList.guest": "Khách mời",
"app.userList.sharingWebcam": "webcam",
"app.userList.menuTitleContext": "Tùy chọn có sẵn",
"app.userList.chatListItem.unreadSingular": "Một tin nhắn mới",
"app.userList.chatListItem.unreadPlural": "{0} tin nhắn mới",
"app.userList.menu.chat.label": "Chat riêng tư",
"app.userList.menu.clearStatus.label": "Xóa trạng thái",
"app.userList.menu.removeUser.label": "Loại bỏ người dùng",
@ -129,6 +136,9 @@
"app.media.screenshare.notSupported": "Chia sẻ màn hình không được hỗ trợ trong trình duyệt này.",
"app.media.screenshare.autoplayBlockedDesc": "Chúng tôi cần sự cho phép của bạn để hiển thị màn hình của người thuyết trình.",
"app.media.screenshare.autoplayAllowLabel": "Xem màn hình được chia sẻ",
"app.screenshare.presenterLoadingLabel": "Chia sẻ màn hình của bạn đang được tải",
"app.screenshare.viewerLoadingLabel": "Màn hình của người thuyết trình đang tải",
"app.screenshare.presenterSharingLabel": "Bạn hiện đang chia sẻ màn hình của mình",
"app.screenshare.screenshareFinalError": "Mã (0). Không thể chia sẻ màn hình",
"app.screenshare.screenshareRetryError": "Mã (0). Hãy thử chia sẻ lại màn hình",
"app.screenshare.screenshareRetryOtherEnvError": "Mã (0). Không thể chia sẻ màn hình, vui lòng thử trình duyệt hoặc thiết bị khác",
@ -138,6 +148,8 @@
"app.meeting.meetingTimeRemaining": "Thời gian còn lại của cuộc họp: {0}",
"app.meeting.meetingTimeHasEnded": "Thời gian đã kết thúc. Cuộc họp sẽ sớm kết thúc",
"app.meeting.endedByUserMessage": "Phòng họp này đã kết thúc bởi (0)",
"app.meeting.endedByNoModeratorMessageSingular": "Cuộc họp đã kết thúc do không có người điều hành nào có mặt sau một phút",
"app.meeting.endedByNoModeratorMessagePlural": "Cuộc họp đã kết thúc do không có người kiểm duyệt nào có mặt sau {0} phút",
"app.meeting.endedMessage": "Bạn sẽ được chuyển tiếp trở lại màn hình chính",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Cuộc họp sẽ đóng trong 1 phút.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Cuộc họp sẽ đóng {0} phút.",
@ -174,6 +186,7 @@
"app.presentation.presentationToolbar.fitToWidth": "Vừa với chiều rộng",
"app.presentation.presentationToolbar.fitToPage": "Vừa với trang",
"app.presentation.presentationToolbar.goToSlide": "Trang {0}",
"app.presentation.placeholder": "Đang đợi bản trình bày được tải lên",
"app.presentationUploder.title": "Bài thuyết trình",
"app.presentationUploder.message": "Hỗ trợ các định dạng PDF, Word, Excel, Ảnh",
"app.presentationUploder.uploadLabel": "Tải lên",
@ -218,6 +231,7 @@
"app.presentationUploder.completed": "{0} tải lên hoàn tất",
"app.presentationUploder.clearErrors": "Xóa các lỗi",
"app.presentationUploder.clearErrorsDesc": "Xóa các bài trình bày bi lỗi tải lên",
"app.presentationUploder.uploadViewTitle": "Tải lên phần trình bày",
"app.poll.pollPaneTitle": "Thăm dò ý kiến",
"app.poll.quickPollTitle": "Cuộc thăm dò ý kiến nhanh",
"app.poll.hidePollDesc": "Ẩn menu cuộc thăm dò",
@ -233,6 +247,8 @@
"app.poll.customPlaceholder": "Thêm tùy chọn cuộc thăm dò",
"app.poll.noPresentationSelected": "Không có bản trình bày nào được chọn! Vui lòng chọn một.",
"app.poll.clickHereToSelect": "Bấm vào đây để chọn",
"app.poll.question.label" : "Nhập câu hỏi của bạn",
"app.poll.optionalQuestion.label" : "Viết câu hỏi của bạn (tùy chọn) ...",
"app.poll.userResponse.label" : "Phản hồi của người dùng",
"app.poll.responseTypes.label" : "Các loại phản hồi",
"app.poll.optionDelete.label" : "Xóa bỏ",
@ -240,7 +256,14 @@
"app.poll.typedResponse.desc" : "Sẽ được hiển thị với một hộp văn bản để người dùng điền vào câu trả lời của họ.",
"app.poll.addItem.label" : "Thêm mục",
"app.poll.start.label" : "Bắt đầu khảo sát",
"app.poll.secretPoll.label" : "Cuộc thăm dò ý kiến ẩn danh",
"app.poll.secretPoll.isSecretLabel": "Cuộc thăm dò là ẩn danh - bạn sẽ không thể xem các phản hồi riêng lẻ.",
"app.poll.questionErr": "Cung cấp một câu hỏi là bắt buộc.",
"app.poll.optionErr": "Nhập tùy chọn Khảo sát",
"app.poll.startPollDesc": "Bắt đầu cuộc thăm dò",
"app.poll.showRespDesc": "Hiển thị cấu hình phản hồi",
"app.poll.addRespDesc": "Thêm đầu vào phản hồi cuộc thăm dò",
"app.poll.deleteRespDesc": "Xóa lựa chọn {0}",
"app.poll.t": "Đúng",
"app.poll.f": "Sai",
"app.poll.tf": "Đúng / Sai",
@ -264,11 +287,16 @@
"app.poll.answer.e": "E",
"app.poll.liveResult.usersTitle": "Người dùng",
"app.poll.liveResult.responsesTitle": "Phản hồi",
"app.poll.liveResult.secretLabel": "Đây là một cuộc thăm dò ẩn danh. Các câu trả lời riêng lẻ không được hiển thị.",
"app.poll.removePollOpt": "Đã xóa tùy chọn Cuộc thăm dò ý kiến {0}",
"app.poll.emptyPollOpt": "Trống",
"app.polling.pollingTitle": "Tùy chọn thăm dò",
"app.polling.pollQuestionTitle": "Câu hỏi Khảo sát",
"app.polling.submitLabel": "Gửi đi",
"app.polling.submitAriaLabel": "Gửi phản hồi khảo sát",
"app.polling.responsePlaceholder": "Nhập câu trả lời",
"app.polling.responseSecret": "Cuộc thăm dò ẩn danh - người trình bày không thể thấy câu trả lời của bạn.",
"app.polling.responseNotSecret": "Cuộc thăm dò bình thường - người thuyết trình có thể thấy câu trả lời của bạn.",
"app.polling.pollAnswerLabel": "Câu trả lời {0}",
"app.polling.pollAnswerDesc": "Chọn tùy chọn này để bỏ phiếu cho {0}",
"app.failedMessage": "Xin lỗi, sự cố khi kết nối với máy chủ.",
@ -325,6 +353,9 @@
"app.actionsBar.raiseLabel": "Giơ tay",
"app.actionsBar.label": "Thanh hành động",
"app.actionsBar.actionsDropdown.restorePresentationLabel": "Khôi phục bản trình bày",
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Nút để khôi phục bản trình bày sau khi nó đã được thu nhỏ",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Thu nhỏ phần trình bày",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Nút thu nhỏ phần trình bày",
"app.screenshare.screenShareLabel" : "Chia sẻ màn hình",
"app.submenu.application.applicationSectionTitle": "Ứng dụng",
"app.submenu.application.animationsLabel": "Đồ họa",
@ -337,12 +368,14 @@
"app.submenu.application.languageOptionLabel": "Chọn ngôn ngữ",
"app.submenu.application.noLocaleOptionLabel": "Không có ngôn ngữ",
"app.submenu.application.paginationEnabledLabel": "Phân trang video",
"app.submenu.application.layoutOptionLabel": "Loại bố cục",
"app.submenu.notification.SectionTitle": "Thông báo",
"app.submenu.notification.Desc": "Xác định cách thức và những gì bạn sẽ được thông báo.",
"app.submenu.notification.audioAlertLabel": "Cảnh báo âm thanh",
"app.submenu.notification.pushAlertLabel": "Cảnh báo bật lên Popup",
"app.submenu.notification.messagesLabel": "Tin nhắn trò chuyện",
"app.submenu.notification.userJoinLabel": "Người dùng tham gia",
"app.submenu.notification.userLeaveLabel": "Người dùng rời đi",
"app.submenu.notification.guestWaitingLabel": "Khách đang chờ phê duyệt",
"app.submenu.audio.micSourceLabel": "Nguồn micro",
"app.submenu.audio.speakerSourceLabel": "nguồn loa",
@ -451,6 +484,8 @@
"app.audioModal.ariaTitle": "Tham gia với phương thức âm thanh",
"app.audioModal.microphoneLabel": "Microphone",
"app.audioModal.listenOnlyLabel": "Chỉ nghe",
"app.audioModal.microphoneDesc": "Tham gia hội nghị âm thanh với micrô",
"app.audioModal.listenOnlyDesc": "Tham gia hội nghị âm thanh với chế độ chỉ nghe",
"app.audioModal.audioChoiceLabel": "Bạn muốn tham gia âm thanh như thế nào?",
"app.audioModal.iOSBrowser": "Âm thanh / Video không được hỗ trợ",
"app.audioModal.iOSErrorDescription": "Tại thời điểm này, âm thanh và video không được hỗ trợ trên Chrome dành cho iOS.",
@ -476,6 +511,7 @@
"app.audioModal.playAudio.arialabel" : "Phát âm thanh",
"app.audioDial.tipIndicator": "Lời khuyên",
"app.audioDial.tipMessage": "Nhấn phím '0' trên điện thoại để tắt/bật tiếng.",
"app.audioModal.connecting": "Thiết lập kết nối âm thanh",
"app.audioManager.joinedAudio": "Bạn đã tham gia hội nghị âm thanh",
"app.audioManager.joinedEcho": "Bạn đã tham gia kiểm tra tiếng vang",
"app.audioManager.leftAudio": "Bạn đã rời hội nghị âm thanh",
@ -487,6 +523,7 @@
"app.audioManager.mediaError": "Lỗi: Đã xảy ra sự cố khi tải các thiết bị phương tiện của bạn",
"app.audio.joinAudio": "Tham gia âm thanh",
"app.audio.leaveAudio": "Rời âm thanh",
"app.audio.changeAudioDevice": "Thay đổi thiết bị âm thanh",
"app.audio.enterSessionLabel": "Nhập phiên họp",
"app.audio.playSoundLabel": "Phát âm thanh",
"app.audio.backLabel": "Quay lại",
@ -531,8 +568,11 @@
"app.error.401": "Không được phép",
"app.error.403": "Bạn đã bị xóa khỏi cuộc họp",
"app.error.404": "Không tìm thấy",
"app.error.408": "Chứng thực lỗi",
"app.error.410": "Cuộc họp đã kết thúc",
"app.error.500": "Rất tiếc, đã xảy ra lỗi",
"app.error.userLoggedOut": "Người dùng có một sessionToken không hợp lệ do đăng xuất",
"app.error.ejectedUser": "Người dùng có một sessionToken không hợp lệ do bị loại bỏ",
"app.error.userBanned": "Người dùng đã bị cấm",
"app.error.leaveLabel": "Đăng nhập lại",
"app.error.fallback.presentation.title": "Đã xảy ra lỗi",
@ -541,12 +581,16 @@
"app.guest.waiting": "Đang chờ phê duyệt để tham gia",
"app.guest.errorSeeConsole": "Lỗi: xem thêm ở console",
"app.guest.noModeratorResponse": "Không có phản hồi từ Điều hành viên",
"app.guest.noSessionToken": "Không có Mã thông báo phiên nào nhận được.",
"app.guest.windowTitle": "Phòng chờ của khách",
"app.guest.missingToken": "Khách bị thiếu mã thông báo phiên.",
"app.guest.missingSession": "Khách bỏ lỡ phiên.",
"app.guest.missingMeeting": "Phòng họp này không tồn tại",
"app.guest.meetingEnded": "Cuộc họp kết thúc.",
"app.guest.guestWait": "Vui lòng đợi Người điều hành cho phép bạn vào phòng họp",
"app.guest.guestDeny": "Khách bị từ chối tham gia cuộc họp.",
"app.guest.seatWait": "Khách chờ lấy chỗ trong cuộc họp.",
"app.guest.allow": "Khách đã chấp thuận và chuyển hướng đến cuộc họp.",
"app.userList.guest.waitingUsers": "Người dùng đang chờ",
"app.userList.guest.waitingUsersTitle": "Quản lý người dùng",
"app.userList.guest.optionTitle": "Đánh giá người dùng đang chờ xử lý",
@ -559,6 +603,7 @@
"app.userList.guest.pendingGuestAlert": "Đã tham gia phiên và đang chờ sự chấp thuận của bạn.",
"app.userList.guest.rememberChoice": "Ghi nhớ lựa chọn",
"app.userList.guest.emptyMessage": "Hiện tại không có tin nhắn",
"app.userList.guest.inputPlaceholder": "Thông báo đến phòng chờ của khách",
"app.userList.guest.acceptLabel": "Chấp nhận",
"app.userList.guest.denyLabel": "Từ chối",
"app.user-info.title": "Tra cứu thư mục",
@ -577,6 +622,7 @@
"app.notification.recordingPaused": "Phiên này đã dừng ghi hình",
"app.notification.recordingAriaLabel": "Thời gian ghi hình ",
"app.notification.userJoinPushAlert": "{0} đã tham gia vào phiên",
"app.notification.userLeavePushAlert": "{0} đã rời khỏi phiên họp",
"app.submenu.notification.raiseHandLabel": "Giơ tay",
"app.shortcut-help.title": "Các phím tắt bàn phím",
"app.shortcut-help.accessKeyNotAvailable": "Các phím truy cập không khả dụng",
@ -592,6 +638,7 @@
"app.shortcut-help.closePrivateChat": "Đóng cuộc trò chuyện riêng tư",
"app.shortcut-help.openActions": "Mở menu tác vụ",
"app.shortcut-help.raiseHand": "Chuyển đổi giơ tay",
"app.shortcut-help.openDebugWindow": "Mở cửa sổ debug",
"app.shortcut-help.openStatus": "Mở menu trạng thái",
"app.shortcut-help.togglePan": "Kích hoạt công cụ Pan (Người trình bày)",
"app.shortcut-help.toggleFullscreen": "Chuyển đổi Toàn màn hình (Người trình bày)",
@ -619,14 +666,25 @@
"app.guest-policy.button.askModerator": "Hỏi người kiểm duyệt",
"app.guest-policy.button.alwaysAccept": "Luôn chấp nhận",
"app.guest-policy.button.alwaysDeny": "Luôn từ chối",
"app.guest-policy.policyBtnDesc": "Đặt chính sách phòng họp cho khách",
"app.connection-status.ariaTitle": "Phương thức trạng thái kết nối",
"app.connection-status.title": "Tình trạng kết nối",
"app.connection-status.description": "Xem trạng thái kết nối của người dùng",
"app.connection-status.empty": "Hiện không có vấn đề kết nối nào được báo cáo",
"app.connection-status.more": "thêm",
"app.connection-status.copy": "Sao chép dữ liệu mạng",
"app.connection-status.copied": "Đã sao chép",
"app.connection-status.jitter": "Nhiễu",
"app.connection-status.label": "Tình trạng kết nối",
"app.connection-status.no": "Không",
"app.connection-status.notification": "Mất kết nối của bạn đã được phát hiện",
"app.connection-status.offline": "ngoại tuyến",
"app.connection-status.lostPackets": "Mất gói",
"app.connection-status.usingTurn": "Sử dụng TURN",
"app.connection-status.yes": "Có",
"app.learning-dashboard.label": "Bảng điểu khiển phiên học",
"app.learning-dashboard.description": "Mở bảng điều khiển với các hoạt động của người dùng",
"app.learning-dashboard.clickHereToOpen": "Mở bảng điều khiển phiên học",
"app.recording.startTitle": "Bắt đầu ghi hình",
"app.recording.stopTitle": "Dừng ghi hình",
"app.recording.resumeTitle": "Tiếp tục ghi hình",
@ -648,6 +706,8 @@
"app.videoPreview.webcamOptionLabel": "Chọn webcam",
"app.videoPreview.webcamPreviewLabel": "Xem trước webcam",
"app.videoPreview.webcamSettingsTitle": "Cài đặt webcam",
"app.videoPreview.webcamVirtualBackgroundLabel": "Cài đặt nền ảo",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Thiết bị này không hỗ trợ nền ảo",
"app.videoPreview.webcamNotFoundLabel": "Không tìm thấy webcam",
"app.videoPreview.profileNotFoundLabel": "Không có cấu hình máy ảnh được hỗ trợ",
"app.video.joinVideo": "Chia sẻ webcam",
@ -657,10 +717,17 @@
"app.video.iceConnectionStateError": "Lỗi kết nối (ICE error 1107)",
"app.video.permissionError": "Lỗi chia sẻ webcam. Xin cho quyền sử dụng",
"app.video.sharingError": "Lỗi chia sẻ webcam",
"app.video.abortError": "Đã xảy ra sự cố không xác định khiến máy ảnh của bạn không được sử dụng",
"app.video.overconstrainedError": "Máy ảnh của bạn không hỗ trợ cấu hình chất lượng này",
"app.video.securityError": "Trình duyệt của bạn đã vô hiệu hóa việc sử dụng máy ảnh. Thử một trình duyệt khác",
"app.video.typeError": "Cấu hình chất lượng máy ảnh không hợp lệ. Liên hệ với quản trị viên của bạn",
"app.video.notFoundError": "Không thể tìm thấy webcam. Hãy đảm bảo rằng nó được kết nối",
"app.video.notAllowed": "Thiếu quyền chia sẻ webcam, vui lòng đảm bảo quyền trình duyệt của bạn",
"app.video.notSupportedError": "Chỉ có thể chia sẻ video webcam với các nguồn an toàn, hãy đảm bảo chứng chỉ SSL của bạn hợp lệ",
"app.video.notReadableError": "Không thể tải video webcam. Hãy đảm bảo rằng một chương trình khác không sử dụng webcam ",
"app.video.timeoutError": "Trình duyệt không phản hồi kịp.",
"app.video.genericError": "Đã xảy ra lỗi không xác định với thiết bị ({0})",
"app.video.mediaTimedOutError": "Luồng webcam của bạn đã bị gián đoạn. Hãy thử chia sẻ lại",
"app.video.mediaFlowTimeout1020": "Phương tiện không thể kết nối với máy chủ (lỗi 1020)",
"app.video.suggestWebcamLock": "Thực hiện cài đặt khóa webcam người xem?",
"app.video.suggestWebcamLockReason": "(điều này sẽ cải thiện sự ổn định của cuộc họp)",
@ -675,7 +742,16 @@
"app.video.videoMenuDesc": "Mở menu video",
"app.video.pagination.prevPage": "Xem các video trước",
"app.video.pagination.nextPage": "Xem các video tiếp theo",
"app.video.clientDisconnected": "Không thể chia sẻ webcam do sự cố kết nối",
"app.video.virtualBackground.none": "Không có",
"app.video.virtualBackground.blur": "Làm mờ",
"app.video.virtualBackground.genericError": "Không áp dụng được hiệu ứng máy ảnh. Thử lại.",
"app.video.virtualBackground.camBgAriaDesc": "Đặt nền ảo của webcam thành {0}",
"app.video.dropZoneLabel": "Thả ở đây",
"app.fullscreenButton.label": "Làm {0} toàn màn hình",
"app.fullscreenUndoButton.label": "Hoàn tác {0} toàn màn hình",
"app.switchButton.expandLabel": "Mở rộng video chia sẻ màn hình",
"app.switchButton.shrinkLabel": "Thu nhỏ video chia sẻ màn hình",
"app.sfu.mediaServerConnectionError2000": "Không thể kết nối với máy chủ (lỗi 2000)",
"app.sfu.mediaServerOffline2001": "Máy chủ phương tiện đang ngoại tuyến. Vui lòng thử lại sau (lỗi 2001)",
"app.sfu.mediaServerNoResources2002": "Máy chủ phương tiện không có sẵn nguồn (error 2002)",
@ -716,12 +792,17 @@
"app.whiteboard.toolbar.clear": "Xóa hoàn tác chú thích",
"app.whiteboard.toolbar.multiUserOn": "Bật bảng trắng nhiều người dùng",
"app.whiteboard.toolbar.multiUserOff": "Tắt bảng trắng nhiều người dùng",
"app.whiteboard.toolbar.palmRejectionOn": "Bật tính năng từ chối bằng lòng bàn tay",
"app.whiteboard.toolbar.palmRejectionOff": "Tắt tính năng từ chối lòng bàn tay",
"app.whiteboard.toolbar.fontSize": "Danh sách kích thước phông chữ",
"app.whiteboard.toolbarAriaLabel": "Các công cụ thuyết trình",
"app.feedback.title": "Bạn đã đăng xuất khỏi cuộc họp",
"app.feedback.subtitle": "Chúng tôi rất muốn nghe về trải nghiệm của bạn với hệ thống này (tùy chọn)",
"app.feedback.textarea": "Làm thế nào chúng tôi có thể cải thiện TUV NORD MEET?",
"app.feedback.sendFeedback": "Gửi thông tin phản hồi",
"app.feedback.sendFeedbackDesc": "Gửi phản hồi và rời khỏi cuộc họp",
"app.videoDock.webcamMirrorLabel": "Phản chiếu",
"app.videoDock.webcamMirrorDesc": "Phản chiếu webcam đã chọn",
"app.videoDock.webcamFocusLabel": "Tập trung",
"app.videoDock.webcamFocusDesc": "Tập trung vào webcam đã chọn",
"app.videoDock.webcamUnfocusLabel": "Bỏ tập trung",

View File

@ -1,6 +1,5 @@
const Page = require('../core/page');
const e = require('../core/elements');
const { checkElement } = require('../core/util');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
class Create {
@ -62,7 +61,7 @@ class Create {
// Check if Breakoutrooms have been created
async testCreatedBreakout(testName) {
try {
const resp = await this.modPage1.page.evaluate(checkElement, e.breakoutRoomsItem);
const resp = await this.modPage1.hasElement(e.breakoutRoomsItem);
if (resp === true) {
await this.modPage1.screenshot(`${testName}`, `05-page01-success-${testName}`);
@ -88,8 +87,7 @@ class Create {
await this.modPage2.waitAndClick(e.chatButton);
await this.modPage2.waitAndClick(e.breakoutRoomsItem);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitAndClick(e.askJoinRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected, ELEMENT_WAIT_LONGER_TIME);
const breakoutModPage2 = await this.modPage2.getLastTargetPage();
@ -107,8 +105,7 @@ class Create {
} else if (testName === 'joinBreakoutroomsWithVideo') {
await this.modPage2.init(true, true, testName, 'Moderator2', this.modPage1.meetingId);
await this.modPage2.waitAndClick(e.breakoutRoomsButton);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitAndClick(e.askJoinRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected);
const breakoutModPage2 = await this.modPage2.getLastTargetPage();
@ -116,18 +113,15 @@ class Create {
await breakoutModPage2.bringToFront();
await breakoutModPage2.closeAudioModal();
await breakoutModPage2.waitAndClick(e.joinVideo);
const parsedSettings = await this.modPage2.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
await breakoutModPage2.waitAndClick(e.videoPreview, videoPreviewTimeout);
await breakoutModPage2.waitAndClick(e.startSharingWebcam);
await breakoutModPage2.shareWebcam(true, videoPreviewTimeout);
await breakoutModPage2.screenshot(testName, '00-breakout-page03-user-joined-with-webcam-before-check');
} else if (testName === 'joinBreakoutroomsAndShareScreen') {
await this.modPage2.init(true, true, testName, 'Moderator2', this.modPage1.meetingId);
await this.modPage2.waitAndClick(e.breakoutRoomsButton);
await this.modPage2.waitAndClick(e.generateRoom1);
await this.modPage2.waitAndClick(e.joinGeneratedRoom1);
await this.modPage2.waitAndClick(e.askJoinRoom1);
await this.modPage2.waitForSelector(e.alreadyConnected);
const breakoutModPage2 = await this.modPage2.getLastTargetPage();

View File

@ -49,8 +49,7 @@ exports.alreadyConnected = 'span[class^="alreadyConnected--"]';
exports.breakoutJoin = '[data-test="breakoutJoin"]';
exports.userJoined = 'div[aria-label^="Moderator3"]';
exports.breakoutRoomsButton = 'div[aria-label="Breakout Rooms"]';
exports.generateRoom1 = 'button[aria-label="Generate URL Room 1"]';
exports.joinGeneratedRoom1 = 'button[aria-label="Generated Room 1"]';
exports.askJoinRoom1 = 'button[aria-label="Ask to join Room 1"]';
exports.joinRoom1 = 'button[aria-label="Join room Room 1"]';
exports.allowChoiceRoom = 'input[id="freeJoinCheckbox"]';
exports.labelGeneratingURL = 'span[data-test="labelGeneratingURL"]';
@ -207,6 +206,8 @@ exports.chatPanel = 'section[data-test="chatPanel"]';
exports.userListPanel = 'div[data-test="userListPanel"]';
exports.multiWhiteboardTool = 'span[data-test="multiWhiteboardTool"]'
exports.connectionStatusBtn = 'button[data-test="connectionStatusButton"]';
exports.connectionDataContainer = '[class^=networkDataContainer--]';
exports.connectionNetwordData = '[class^=networkData--]';
// Webcam
exports.joinVideo = 'button[data-test="joinVideo"]';

View File

@ -8,7 +8,7 @@ const path = require('path');
const PuppeteerVideoRecorder = require('puppeteer-video-recorder');
const helper = require('./helper');
const params = require('./params');
const { ELEMENT_WAIT_TIME } = require('./constants');
const { ELEMENT_WAIT_TIME, VIDEO_LOADING_WAIT_TIME } = require('./constants');
const { getElementLength } = require('./util');
const e = require('./elements');
const { NETWORK_PRESETS } = require('./profiles');
@ -104,6 +104,17 @@ class Page {
await this.waitForSelector(e.isTalking);
}
async shareWebcam(shouldConfirmSharing, videoPreviewTimeout = ELEMENT_WAIT_TIME) {
await this.waitAndClick(e.joinVideo);
if (shouldConfirmSharing) {
await this.waitForSelector(e.videoPreview, videoPreviewTimeout);
await this.waitAndClick(e.startSharingWebcam);
}
await this.waitForSelector(e.webcamConnecting);
await this.waitForSelector(e.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
}
// Joining audio with microphone
async joinMicrophoneWithoutEchoTest() {
await this.waitAndClick(e.joinAudio);
@ -214,16 +225,6 @@ class Page {
}
}
async isNotVisible(element, timeout = ELEMENT_WAIT_TIME) {
try {
await this.hasElement(element, false, timeout);
return true;
} catch (err) {
await this.logger(err);
return false;
}
}
// async emulateMobile(userAgent) {
// await this.page.setUserAgent(userAgent);
// }
@ -243,7 +244,7 @@ class Page {
}
}
async hasElement(element, visible = false, timeout = ELEMENT_WAIT_TIME) {
async hasElement(element, visible = true, timeout = ELEMENT_WAIT_TIME) {
try {
await this.page.waitForSelector(element, { visible, timeout });
return true;

View File

@ -3,13 +3,11 @@ exports.listenOnlyMode = 'userdata-bbb_listen_only_mode=false';
exports.forceListenOnly = 'userdata-bbb_force_listen_only=true';
exports.skipCheck = 'userdata-bbb_skip_check_audio=true';
exports.skipCheckOnFirstJoin = 'userdata-bbb_skip_check_audio_on_first_join=true';
const docTitle = 'puppeteer';
exports.docTitle = docTitle;
exports.clientTitle = `userdata-bbb_client_title=${docTitle}`;
exports.docTitle = 'puppeteer';
exports.clientTitle = `userdata-bbb_client_title=${this.docTitle}`;
exports.askForFeedbackOnLogout = 'userdata-bbb_ask_for_feedback_on_logout=true';
exports.displayBrandingArea = 'userdata-bbb_display_branding_area=true';
exports.logo = 'logo=https://bigbluebutton.org/wp-content/themes/bigbluebutton/library/images/bigbluebutton-logo.png';
exports.shortcuts = 'userdata-bbb_shortcuts=["openOptions", "toggleUserList", "toggleMute", "joinAudio", "leaveAudio", "togglePublicChat", "hidePrivateChat", "closePrivateChat", "openActions", "openStatus"]';
exports.enableScreensharing = 'userdata-bbb_enable_screen_sharing=false';
exports.enableVideo = 'userdata-bbb_enable_video=false';
exports.autoShareWebcam = 'userdata-bbb_auto_share_webcam=true';
@ -33,3 +31,35 @@ exports.skipVideoPreview = 'userdata-bbb_skip_video_preview=true';
exports.skipVideoPreviewOnFirstJoin = 'userdata-bbb_skip_video_preview_on_first_join=true';
exports.mirrorOwnWebcam = 'userdata-bbb_mirror_own_webcam=true';
exports.showParticipantsOnLogin = 'userdata-bbb_show_participants_on_login=false';
// Shortcuts
exports.shortcuts = 'userdata-bbb_shortcuts=[$]';
exports.initialShortcuts = [{
param: 'openOptions',
key: 'O'
}, {
param: 'toggleUserList',
key: 'U'
}, {
param: 'togglePublicChat',
key: 'P'
}, {
param: 'openActions',
key: 'A'
}, {
param: 'joinAudio',
key: 'J'
}];
exports.laterShortcuts = [{
param: 'toggleMute',
key: 'M'
}, {
param: 'leaveAudio',
key: 'L'
}, {
param: 'hidePrivateChat',
key: 'H'
}, {
param: 'closePrivateChat',
key: 'G'
}];

View File

@ -3,7 +3,7 @@ const e = require('../core/elements');
const c = require('./constants');
const util = require('./util');
const { VIDEO_LOADING_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
const { checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
const { checkElementLengthEqualTo, checkElement } = require('../core/util');
class CustomParameters {
constructor() {
@ -25,7 +25,7 @@ class CustomParameters {
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitForSelector(e.chatMessages);
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, e.audioModal, 0);
const resp = await this.page1.wasRemoved(e.audioModal);
if (!resp) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -96,7 +96,7 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `02-${testName}`);
await this.page1.waitForElementHandleToBeRemoved(e.connectingStatus, ELEMENT_WAIT_LONGER_TIME);
await this.page1.screenshot(`${testName}`, `03-${testName}`);
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, e.echoYesButton, 0);
const resp = await this.page1.wasRemoved(e.echoYesButton);
if (!resp) {
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -118,13 +118,13 @@ class CustomParameters {
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitAndClick(e.microphoneButton);
const firstCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.connecting, 0);
const firstCheck = await this.page1.hasElement(e.connecting);
await this.page1.screenshot(`${testName}`, `02-${testName}`);
await this.page1.leaveAudio();
await this.page1.screenshot(`${testName}`, `03-${testName}`);
await this.page1.waitAndClick(e.joinAudio);
await this.page1.waitAndClick(e.microphoneButton);
const secondCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.connectingToEchoTest, 0);
const secondCheck = await this.page1.hasElement(e.connectingToEchoTest);
if (firstCheck !== secondCheck) {
await this.page1.screenshot(`${testName}`, `04-fail-${testName}`);
@ -175,7 +175,7 @@ class CustomParameters {
await this.page1.waitForSelector(e.meetingEndedModal);
await this.page1.screenshot(`${testName}`, `04-${testName}`);
await this.page1.logger('audio modal closed');
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.rating, 0);
const resp = await this.page1.hasElement(e.rating);
if (!resp) {
await this.page1.screenshot(`${testName}`, `05-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -199,7 +199,7 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `02-${testName}`);
await this.page1.logger('audio modal closed');
await this.page1.waitForSelector(e.userListContent);
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.brandingAreaLogo, 0);
const resp = await this.page1.hasElement(e.brandingAreaLogo);
if (!resp) {
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -218,23 +218,30 @@ class CustomParameters {
async shortcuts(testName, customParameter) {
try {
await this.page1.init(true, true, testName, 'Moderator', undefined, customParameter);
await this.page2.init(false, true, testName, 'Attendee', this.page1.meetingId);
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.screenshot(`${testName}`, `02-${testName}`);
await this.page1.logger('audio modal closed');
await this.page1.waitForSelector(e.options);
await this.page1.page.keyboard.down('Alt');
await this.page1.page.keyboard.press('O');
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, e.verticalListOptions, 0);
if (!resp) {
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
await this.page1.logger(testName, ' failed');
return false;
}
await this.page1.screenshot(`${testName}`, `03-success-${testName}`);
await this.page1.logger(testName, ' passed');
await this.page1.screenshot(`${testName}`, '01-after-close-audio-modal');
return resp === true;
// Check the initial shortcuts that can be used right after joining the meeting
const check1 = await util.checkShortcutsArray(this.page1, c.initialShortcuts);
if (!check1) return false;
await this.page1.bringToFront();
// Join audio
await this.page1.waitAndClick(e.joinAudio);
await this.page1.joinMicrophone();
await this.page1.screenshot(`${testName}`, '02-after-join-audio');
// Open private chat
await this.page1.waitAndClick(e.userListItem);
await this.page1.waitAndClick(e.activeChat);
await this.page1.waitForSelector(e.hidePrivateChat);
await this.page1.screenshot(`${testName}`, '03-after-open-private-chat');
// Check the later shortcuts that can be used after joining audio and opening private chat
const check2 = await util.checkShortcutsArray(this.page1, c.laterShortcuts);
return check2 === true;
} catch (err) {
await this.page1.logger(err);
return false;
@ -246,7 +253,7 @@ class CustomParameters {
await this.page1.init(true, true, testName, 'Moderator', undefined, customParameter);
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, e.startScreenSharing, 0);
const resp = await this.page1.wasRemoved(e.startScreenSharing);
if (!resp) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -267,7 +274,7 @@ class CustomParameters {
await this.page1.init(true, true, testName, 'Moderator', undefined, customParameter);
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
const resp = await this.page1.page.evaluate(checkElementLengthEqualTo, e.joinVideo, 0);
const resp = await this.page1.wasRemoved(e.joinVideo);
if (!resp) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -450,7 +457,10 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitForSelector(e.actions);
await this.page1.screenshot(`${testName}`, `02-${testName}`);
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.defaultContent, 0);
const checkPresentationButton = await this.page1.page.evaluate(checkElement, e.restorePresentation);
const checkPresentationPlaceholder = await this.page1.page.evaluate(checkElement, e.presentationPlaceholder);
const resp = !(checkPresentationButton || checkPresentationPlaceholder);
if (!resp) {
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -473,7 +483,7 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitForSelector(e.actions);
await this.page1.screenshot(`${testName}`, `02-${testName}`);
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.notificationBar, 0);
const resp = await this.page1.hasElement(e.notificationBar);
if (!resp) {
await this.page1.screenshot(`${testName}`, `03-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -518,7 +528,7 @@ class CustomParameters {
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitForSelector(e.actions);
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.restorePresentation, 0) && await this.page1.page.evaluate(checkElementLengthDifferentTo, e.defaultContent, 0);
const resp = await this.page1.hasElement(e.restorePresentation) && await this.page1.hasElement(e.defaultContent);
if (!resp) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -585,14 +595,13 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `05-page1-${testName}`);
await this.page2.screenshot(`${testName}`, `06-page2-${testName}`);
const test = await this.page2.page.evaluate(checkElementLengthDifferentTo, e.restorePresentation, 0);
const test = await this.page2.page.evaluate(checkElement, e.restorePresentation);
const resp = (zoomInCase && zoomOutCase && pollCase && previousSlideCase && nextSlideCase && annotationCase && test);
if (resp) {
await this.page2.screenshot(`${testName}`, `07-page2-fail-${testName}`);
await this.page1.logger(testName, ' failed');
return false;
}
await this.page2.page.evaluate(checkElementLengthEqualTo, e.restorePresentation, 0);
await this.page2.screenshot(`${testName}`, `07-page2-success-${testName}`);
await this.page1.logger(testName, ' passed');
@ -617,7 +626,7 @@ class CustomParameters {
await this.page1.screenshot(`${testName}`, `02-page1-${testName}`);
await this.page2.screenshot(`${testName}`, `03-page2-${testName}`);
const test = await this.page2.page.evaluate(checkElementLengthDifferentTo, e.restorePresentation, 0);
const test = await this.page2.page.evaluate(checkElement, e.restorePresentation);
if (pollCase && test) {
await this.page2.screenshot(`${testName}`, `04-page2-fail-${testName}`);
await this.page1.logger(testName, ' failed');
@ -681,31 +690,22 @@ class CustomParameters {
await this.page1.init(true, true, testName, 'Moderator1', undefined, customParameter);
await this.page1.startRecording(testName);
await this.page1.screenshot(`${testName}`, `01-${testName}`);
await this.page1.waitAndClick(e.joinVideo);
const firstCheck = await this.page1.page.evaluate(checkElementLengthEqualTo, e.webcamSettingsModal, 0);
await this.page1.shareWebcam(false);
await this.page1.waitAndClick(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
await this.page1.waitForElementHandleToBeRemoved(e.webcamVideo, ELEMENT_WAIT_LONGER_TIME);
await this.page1.waitForElementHandleToBeRemoved(e.leaveVideo, ELEMENT_WAIT_LONGER_TIME);
await this.page1.waitAndClick(e.joinVideo);
const parsedSettings = await this.page1.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
await this.page1.waitForSelector(e.videoPreview, videoPreviewTimeout);
await this.page1.waitForSelector(e.startSharingWebcam);
const secondCheck = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.webcamSettingsModal, 0);
await this.page1.waitAndClick(e.startSharingWebcam);
await this.page1.waitForSelector(e.webcamConnecting);
await this.page1.shareWebcam(true, videoPreviewTimeout);
if (firstCheck !== secondCheck) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');
return false;
}
await this.page1.screenshot(`${testName}`, `02-success-${testName}`);
await this.page1.logger(testName, ' passed');
return true;
} catch (err) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(err);
return false;
}
@ -719,7 +719,7 @@ class CustomParameters {
await this.page1.waitAndClick(e.joinVideo);
await this.page1.waitForSelector(e.webcamMirroredVideoPreview);
await this.page1.waitAndClick(e.startSharingWebcam);
const resp = await this.page1.page.evaluate(checkElementLengthDifferentTo, e.webcamMirroredVideoContainer, 0);
const resp = await this.page1.hasElement(e.webcamMirroredVideoContainer);
if (!resp) {
await this.page1.screenshot(`${testName}`, `02-fail-${testName}`);
await this.page1.logger(testName, ' failed');

View File

@ -207,14 +207,15 @@ const customParametersTest = () => {
try {
const testName = 'shortcuts';
await page.logger('before ', testName);
response = await test.shortcuts(testName, util.encodeCustomParams(c.shortcuts));
const shortcutParam = util.getAllShortcutParams();
response = await test.shortcuts(testName, util.encodeCustomParams(shortcutParam));
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await page.logger('after ', testName);
} catch (err) {
await page.logger(err);
} finally {
await test.closePage(test.page1);
await test.close(test.page1, test.page2);
}
expect(response).toBe(true);
Page.checkRegression(0.5, screenshot);

View File

@ -1,7 +1,8 @@
const path = require('path');
const e = require('../core/elements');
const c = require('./constants');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { checkElementLengthEqualTo, checkElementLengthDifferentTo, checkElementText } = require('../core/util');
const { checkElementLengthEqualTo, checkElementLengthDifferentTo, checkElementText, checkElement } = require('../core/util');
async function autoJoinTest(test) {
try {
@ -160,6 +161,28 @@ function encodeCustomParams(param) {
}
}
function getAllShortcutParams() {
const getParams = (shortcutArray) => {
return Object.values(shortcutArray.map(e => `"${e.param}"`));
}
return c.shortcuts.replace('$', [...getParams(c.initialShortcuts), ...getParams(c.laterShortcuts)]);
}
async function checkAccesskey(test, key) {
return test.page.evaluate(checkElement, `[accesskey="${key}"]`);
}
async function checkShortcutsArray(test, shortcut) {
for (const { param, key } of shortcut) {
const resp = await checkAccesskey(test, key);
if (!resp) {
await test.logger(`${param} shortcut failed`)
return false;
}
}
return true;
}
exports.zoomIn = zoomIn;
exports.zoomOut = zoomOut;
exports.poll = poll;
@ -173,3 +196,6 @@ exports.listenOnlyMode = listenOnlyMode;
exports.forceListenOnly = forceListenOnly;
exports.skipCheck = skipCheck;
exports.encodeCustomParams = encodeCustomParams;
exports.getAllShortcutParams = getAllShortcutParams;
exports.checkAccesskey = checkAccesskey;
exports.checkShortcutsArray = checkShortcutsArray;

View File

@ -116,7 +116,7 @@ class Presentation {
await this.userPage.screenshot(testName, `3-userPage-after-allow-download-and-save-[${this.modPage.meetingId}]`);
await this.userPage.waitForSelector(e.toastDownload);
// check download button in presentation after ALLOW it - should be true
const hasPresentationDownloadBtnAfterAllow = await this.userPage.page.evaluate(checkElement, e.presentationDownloadBtn);
const hasPresentationDownloadBtnAfterAllow = await this.userPage.hasElement(e.presentationDownloadBtn);
// disallow the presentation download
await this.modPage.waitAndClick(e.actions);

View File

@ -2,7 +2,6 @@ const Page = require('../core/page');
const e = require('../core/elements');
const c = require('../core/constants');
const util = require('./util');
const { checkElementLengthEqualTo } = require('../core/util');
class Stress {
constructor() {
@ -19,7 +18,7 @@ class Stress {
await this.modPage.waitForSelector(e.userAvatar);
const hasPresenterClass = await this.modPage.page.evaluate(util.checkIncludeClass, e.userAvatar, e.presenterClassName);
await this.modPage.waitAndClick(e.actions);
const canStartPoll = await this.modPage.page.evaluate(checkElementLengthEqualTo, e.polling, 1);
const canStartPoll = await this.modPage.hasElement(e.polling);
if (!hasPresenterClass || !canStartPoll) {
failureCount++;
await this.modPage.screenshot(testName, `loop-${i}-failure-${testName}`);

View File

@ -3,7 +3,6 @@ const { exec } = require("child_process");
const { CLIENT_RECONNECTION_TIMEOUT } = require('../core/constants'); // core constants (Timeouts vars imported)
const { sleep } = require('../core/helper');
const e = require('../core/elements');
const { checkElementLengthDifferentTo } = require('../core/util');
class Trigger extends Page {
constructor() {
@ -30,7 +29,7 @@ class Trigger extends Page {
await sleep(3000);
await this.screenshot(`${testName}`, `03-after-meteor-reconnection-[${this.meetingId}]`);
const findUnauthorized = await this.page.evaluate(checkElementLengthDifferentTo, e.unauthorized, 0) === true;
const findUnauthorized = await this.hasElement(e.unauthorized);
await this.logger('Check if Unauthorized message appears => ', findUnauthorized);
return meteorStatusConfirm && getAudioButton && findUnauthorized;
} catch (err) {
@ -84,7 +83,7 @@ class Trigger extends Page {
}, e.joinAudio)
await this.logger('Check if Connections Buttons are disabled => ', getAudioButton);
await sleep(3000);
const findUnauthorized = await this.page.evaluate(checkElementLengthDifferentTo, e.unauthorized, 0) === true;
const findUnauthorized = await this.hasElement(e.unauthorized);
await this.logger('Check if Unauthorized message appears => ', findUnauthorized);
return meteorStatusConfirm && getAudioButton && findUnauthorized;
} catch (err) {

View File

@ -2,8 +2,8 @@ const Page = require('../core/page');
const util = require('../chat/util');
const utilUser = require('./util');
const e = require('../core/elements');
const { ELEMENT_WAIT_TIME } = require('../core/constants');
const { getElementLength, checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
const { ELEMENT_WAIT_TIME, ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { getElementLength, checkElementLengthEqualTo } = require('../core/util');
class MultiUsers {
constructor() {
@ -293,7 +293,7 @@ class MultiUsers {
await this.page2.close();
await utilUser.connectionStatus(this.page1);
const connectionStatusItemEmpty = await this.page1.wasRemoved(e.connectionStatusItemEmpty);
const connectionStatusOfflineUser = await this.page1.hasElement(e.connectionStatusOfflineUser, true);
const connectionStatusOfflineUser = await this.page1.hasElement(e.connectionStatusOfflineUser, true, ELEMENT_WAIT_LONGER_TIME);
return connectionStatusItemEmpty && connectionStatusOfflineUser;
} catch (err) {
@ -313,13 +313,58 @@ class MultiUsers {
}
}
async usersConnectionStatus(testName) {
try {
await this.page1.shareWebcam(true);
await this.page1.screenshot(testName, '01-page1-after-share-webcam');
await this.initUserPage(false, testName);
await this.userPage.joinMicrophone();
await this.userPage.screenshot(testName, '02-userPage-after-join-microhpone');
await this.userPage.shareWebcam(true);
await this.userPage.screenshot(testName, '03-userPage-after-share-webcam');
await this.userPage.waitAndClick(e.connectionStatusBtn);
try {
await this.userPage.page.waitForFunction(utilUser.checkNetworkStatus, { timeout: ELEMENT_WAIT_TIME },
e.connectionDataContainer, e.connectionNetwordData
);
await this.userPage.screenshot(testName, '04-connection-network-success');
return true;
} catch (err) {
await this.userPage.screenshot(testName, '04-connection-network-failed');
this.userPage.logger(err);
return false;
}
} catch (err) {
this.page1.logger(err);
return false;
}
}
async disableWebcamsFromConnectionStatus() {
try {
await this.page1.shareWebcam(true, ELEMENT_WAIT_LONGER_TIME);
await this.page2.shareWebcam(true, ELEMENT_WAIT_LONGER_TIME);
await utilUser.connectionStatus(this.page1);
await this.page1.waitAndClickElement(e.dataSavingWebcams);
await this.page1.waitAndClickElement(e.closeConnectionStatusModal);
await this.page1.waitForSelector(e.smallToastMsg);
const checkUserWhoHasDisabled = await this.page1.page.evaluate(checkElementLengthEqualTo, e.videoContainer, 1);
const checkSecondUser = await this.page2.page.evaluate(checkElementLengthEqualTo, e.videoContainer, 2);
return checkUserWhoHasDisabled && checkSecondUser;
} catch (err) {
await this.page1.logger(err);
return false;
}
}
async whiteboardNotAppearOnMobile() {
try {
await this.page1.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.chatButtonKey);
const onUserListPanel = await this.page1.isNotVisible(e.hidePresentation);
const onChatPanel = await this.page2.isNotVisible(e.hidePresentation);
const onUserListPanel = await this.page1.wasRemoved(e.hidePresentation);
const onChatPanel = await this.page2.wasRemoved(e.hidePresentation);
return onUserListPanel && onChatPanel;
} catch (err) {
@ -333,7 +378,7 @@ class MultiUsers {
await this.page2.waitAndClick(e.userListButton);
await this.page2.waitAndClick(e.chatButtonKey);
const whiteboard = await this.page1.page.evaluate(checkElementLengthEqualTo, e.chatButtonKey, 0);
const onChatPanel = await this.page2.isNotVisible(e.chatButtonKey);
const onChatPanel = await this.page2.hasElement(e.chatButtonKey, false);
return whiteboard && onChatPanel;
} catch (err) {

View File

@ -2,10 +2,9 @@ const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const Page = require('../core/page');
const e = require('../core/elements');
const util = require('./util');
const utilWebcam = require('../webcam/util');
const utilScreenshare = require('../screenshare/util');
const { sleep } = require('../core/helper');
const { checkElementLengthEqualTo, checkElementLengthDifferentTo } = require('../core/util');
const { checkElementLengthEqualTo } = require('../core/util');
class Status extends Page {
constructor() {
@ -15,12 +14,11 @@ class Status extends Page {
async test() {
try {
await util.setStatus(this, e.applaud);
const resp1 = await this.page.evaluate(checkElementLengthDifferentTo, e.applauseIcon, 0);
const resp1 = await this.hasElement(e.applauseIcon);
await sleep(1000);
await util.setStatus(this, e.away);
const resp2 = await this.page.evaluate(checkElementLengthDifferentTo, e.awayIcon, 0);
const resp2 = await this.hasElement(e.awayIcon);
await this.waitAndClick(e.firstUser);
await this.waitAndClick(e.clearStatus);
return resp1 === resp2;
} catch (err) {
await this.logger(err);
@ -33,7 +31,7 @@ class Status extends Page {
await this.waitAndClick(e.userList);
await this.waitForSelector(e.firstUser);
const response = await this.page.evaluate(checkElementLengthDifferentTo, e.mobileUser, 0);
const response = await this.hasElement(e.mobileUser);
return response === true;
} catch (err) {
await this.logger(err);
@ -44,7 +42,7 @@ class Status extends Page {
async findConnectionStatusModal() {
try {
await util.connectionStatus(this);
const resp = await this.page.evaluate(checkElementLengthDifferentTo, e.connectionStatusModal, 0);
const resp = await this.hasElement(e.connectionStatusModal);
return resp === true;
} catch (err) {
await this.logger(err);
@ -52,21 +50,6 @@ class Status extends Page {
}
}
async disableWebcamsFromConnectionStatus() {
try {
await utilWebcam.enableWebcam(this, ELEMENT_WAIT_LONGER_TIME);
await util.connectionStatus(this);
await this.waitAndClickElement(e.dataSavingWebcams);
await this.waitAndClickElement(e.closeConnectionStatusModal);
await sleep(2000);
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthDifferentTo, e.webcamsIsDisabledInDataSaving, 0);
return webcamsIsDisabledInDataSaving === true;
} catch (err) {
await this.logger(err);
return false;
}
}
async disableScreenshareFromConnectionStatus() {
try {
await utilScreenshare.startScreenshare(this);
@ -74,8 +57,8 @@ class Status extends Page {
await util.connectionStatus(this);
await this.waitAndClickElement(e.dataSavingScreenshare);
await this.waitAndClickElement(e.closeConnectionStatusModal);
await sleep(2000);
const webcamsIsDisabledInDataSaving = await this.page.evaluate(checkElementLengthEqualTo, e.screenshareLocked, 0);
const webcamsIsDisabledInDataSaving = await this.hasElement(e.screenshareLocked);
return webcamsIsDisabledInDataSaving === true;
} catch (err) {
await this.logger(err);
@ -87,13 +70,13 @@ class Status extends Page {
try {
await this.page.evaluate(() => window.dispatchEvent(new CustomEvent('socketstats', { detail: { rtt: 2000 } })));
await this.joinMicrophone();
await utilWebcam.enableWebcam(this, ELEMENT_WAIT_LONGER_TIME);
await this.shareWebcam(true, ELEMENT_WAIT_LONGER_TIME);
await utilScreenshare.startScreenshare(this);
await utilScreenshare.waitForScreenshareContainer(this);
await util.connectionStatus(this);
await sleep(5000);
const connectionStatusItemEmpty = await this.page.evaluate(checkElementLengthEqualTo, e.connectionStatusItemEmpty, 0);
const connectionStatusItemUser = await this.page.evaluate(checkElementLengthDifferentTo, e.connectionStatusItemUser, 0);
const connectionStatusItemUser = await this.hasElement(e.connectionStatusItemUser);
return connectionStatusItemUser && connectionStatusItemEmpty;
} catch (err) {
await this.logger(err);

View File

@ -112,22 +112,22 @@ const userTest = () => {
// Open Connection Status Modal, start Webcam Share, disable Webcams in
// Connection Status Modal and check if webcam sharing is still available
test('Disable Webcams From Connection Status Modal', async () => {
const test = new Status();
const test = new MultiUsers();
let response;
let screenshot;
try {
const testName = 'disableWebcamsFromConnectionStatus';
await test.logger('begin of ', testName);
await test.init(true, true, testName);
await test.startRecording(testName);
await test.page1.logger('begin of ', testName);
await test.init(testName);
await test.page1.startRecording(testName);
response = await test.disableWebcamsFromConnectionStatus();
await test.stopRecording();
screenshot = await test.page.screenshot();
await test.logger('end of ', testName);
await test.page1.stopRecording();
screenshot = await test.page1.screenshot();
await test.page1.logger('end of ', testName);
} catch (err) {
await test.logger(err);
await test.page1.logger(err);
} finally {
await test.close();
await test.close(test.page1, test.page2);
}
expect(response).toBe(true);
Page.checkRegression(2.0, screenshot);
@ -205,6 +205,29 @@ const userTest = () => {
Page.checkRegression(2.0, screenshot);
}, TEST_DURATION_TIME);
test('Show network data in Connection Status', async () => {
const test = new MultiUsers();
let response;
let screenshot;
try {
const testName = 'connectionNetworkStatus';
await test.page1.logger('begin of ', testName);
await test.initMod1(testName);
await test.page1.startRecording(testName);
response = await test.usersConnectionStatus(testName);
await test.page1.stopRecording();
screenshot = await test.page1.page.screenshot();
await test.page1.logger('end of ', testName);
} catch (err) {
await test.page1.logger(err);
} finally {
await test.close(test.page1, test.userPage);
}
expect(response).toBe(true);
Page.checkRegression(2.0, screenshot);
});
// Raise and Lower Hand and make sure that the User2 Avatar color
// and its avatar in raised hand toast are the same
test('Raise Hand Toast', async () => {

View File

@ -11,5 +11,15 @@ async function connectionStatus(test) {
await test.waitForSelector(e.connectionStatusModal);
}
function checkNetworkStatus(dataContainer, networdData) {
const values = Array.from(document.querySelectorAll(`${dataContainer} > ${networdData}`));
values.splice(4, values.length - 4);
const check = values.filter(e => e.textContent.includes(' 0 k'))[0];
if (!check) return true;
}
exports.setStatus = setStatus;
exports.connectionStatus = connectionStatus;
exports.checkNetworkStatus = checkNetworkStatus;

View File

@ -22,7 +22,7 @@ class Check extends Share {
const parsedSettings = await this.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
await util.enableWebcam(this, videoPreviewTimeout);
await this.shareWebcam(true, videoPreviewTimeout);
const respUser = await util.webcamContentCheck(this);
return respUser === true;
} catch (err) {

View File

@ -1,7 +1,5 @@
const Page = require('../core/page');
const util = require('./util');
const e = require('../core/elements');
const { checkElementLengthDifferentTo } = require('../core/util');
const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants'); // core constants (Timeouts vars imported)
class Share extends Page {
@ -13,8 +11,9 @@ class Share extends Page {
try {
const parsedSettings = await this.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
const response = await util.enableWebcam(this, videoPreviewTimeout);
return response;
await this.shareWebcam(true, videoPreviewTimeout);
return true;
} catch (err) {
await this.logger(err);
return false;
@ -26,7 +25,7 @@ class Share extends Page {
await this.joinMicrophone();
const parsedSettings = await this.getSettingsYaml();
const videoPreviewTimeout = parseInt(parsedSettings.public.kurento.gUMTimeout);
await util.enableWebcam(this, videoPreviewTimeout);
await this.shareWebcam(true, videoPreviewTimeout);
} catch (err) {
await this.logger(err);
}
@ -37,7 +36,7 @@ class Share extends Page {
await this.waitForSelector(e.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
await this.waitForSelector(e.isTalking);
const foundTestElement = await this.page.evaluate(checkElementLengthDifferentTo, e.webcamItemTalkingUser, 0);
const foundTestElement = await this.hasElement(e.webcamItemTalkingUser);
if (foundTestElement === true) {
await this.screenshot(`${testName}`, `success-${testName}`);
this.logger(testName, ' passed');

View File

@ -1,23 +1,11 @@
const e = require('../core/elements');
const { sleep } = require('../core/helper');
const { checkElement, checkElementLengthDifferentTo } = require('../core/util');
const { checkElement } = require('../core/util');
const {
LOOP_INTERVAL,
VIDEO_LOADING_WAIT_TIME,
ELEMENT_WAIT_LONGER_TIME,
} = require('../core/constants');
async function enableWebcam(test, videoPreviewTimeout) {
// Enabling webcam
await test.waitAndClick(e.joinVideo);
await test.waitForSelector(e.videoPreview, videoPreviewTimeout);
await test.waitAndClick(e.startSharingWebcam);
await test.waitForSelector(e.webcamConnecting);
await test.waitForSelector(e.webcamVideo, VIDEO_LOADING_WAIT_TIME);
await test.waitForSelector(e.leaveVideo, VIDEO_LOADING_WAIT_TIME);
return test.page.evaluate(checkElementLengthDifferentTo, e.webcamVideo, 0);
}
async function evaluateCheck(test) {
await test.waitForSelector(e.videoContainer);
return test.page.evaluate(checkElement, e.presentationFullscreenButton, 1);
@ -69,4 +57,3 @@ async function webcamContentCheck(test) {
exports.startAndCheckForWebcams = startAndCheckForWebcams;
exports.webcamContentCheck = webcamContentCheck;
exports.evaluateCheck = evaluateCheck;
exports.enableWebcam = enableWebcam;

View File

@ -19,7 +19,6 @@ const webcamTest = () => {
const testName = 'shareWebcam';
await test.logger('begin of ', testName);
await test.init(true, true, testName);
await test.closeAudioModal();
await test.startRecording(testName);
response = await test.test();
await test.stopRecording();
@ -42,7 +41,6 @@ const webcamTest = () => {
const testName = 'checkWebcamContent';
await test.logger('begin of ', testName);
await test.init(true, true, testName);
await test.closeAudioModal();
await test.startRecording(testName);
response = await test.test();
await test.stopRecording();

View File

@ -1056,6 +1056,120 @@ class ApiController {
}
}
/***********************************************
* LEARNING DASHBOARD DATA
***********************************************/
def learningDashboard = {
String API_CALL = 'learningDashboard'
log.debug CONTROLLER_NAME + "#${API_CALL}"
String respMessage = ""
boolean reject = false
String sessionToken
UserSession us
Meeting meeting
Map.Entry<String, String> validationResponse = validateRequest(
ValidationService.ApiCall.LEARNING_DASHBOARD,
request.getParameterMap(),
request.getQueryString(),
)
//Validate Session
if(!(validationResponse == null)) {
respMessage = validationResponse.getValue()
reject = true
} else {
sessionToken = sanitizeSessionToken(params.sessionToken)
if (!hasValidSession(sessionToken)) {
reject = true
respMessage = "Invalid Session"
}
}
//Validate User
if(reject == false) {
us = getUserSession(sessionToken)
if(us == null) {
reject = true;
respMessage = "Access denied"
} else if(!us.role.equals(ROLE_MODERATOR)) {
reject = true
respMessage = "Access denied"
}
}
//Validate Meeting
if(reject == false) {
meeting = meetingService.getMeeting(us.meetingID)
boolean isRunning = meeting != null && meeting.isRunning();
if(!isRunning) {
reject = true
respMessage = "Meeting not found"
}
if(meeting.getLearningDashboardEnabled() == false) {
reject = true
respMessage = "Learning Dashboard disabled for this meeting"
}
}
//Validate File
File jsonDataFile
if(reject == false) {
jsonDataFile = meetingService.learningDashboardService.getJsonDataFile(us.meetingID,meeting.getLearningDashboardAccessToken());
if (!jsonDataFile.exists()) {
reject = true
respMessage = "Learning Dashboard data not found"
}
}
if (reject) {
response.addHeader("Cache-Control", "no-cache")
withFormat {
json {
def builder = new JsonBuilder()
builder.response {
returncode RESP_CODE_FAILED
message respMessage
sessionToken
}
render(contentType: "application/json", text: builder.toPrettyString())
}
}
} else {
Map<String, Object> logData = new HashMap<String, Object>();
logData.put("meetingid", us.meetingID);
logData.put("extMeetingid", us.externMeetingID);
logData.put("name", us.fullname);
logData.put("userid", us.internalUserId);
logData.put("sessionToken", sessionToken);
logData.put("logCode", "learningDashboard");
logData.put("description", "Request Learning Dashboard data.");
Gson gson = new Gson();
String logStr = gson.toJson(logData);
log.info(" --analytics-- data=" + logStr);
response.addHeader("Cache-Control", "no-cache")
withFormat {
json {
def builder = new JsonBuilder()
builder.response {
returncode RESP_CODE_SUCCESS
data jsonDataFile.getText()
sessionToken
}
render(contentType: "application/json", text: builder.toPrettyString())
}
}
}
}
def uploadDocuments(conf) { //
log.debug("ApiController#uploadDocuments(${conf.getInternalId()})");

View File

@ -151,6 +151,30 @@
}
},
"response": []
},
{
"name": "learningDashboard",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/{{path}}/learningDashboard?{{param_session_token}}=",
"host": [
"{{base_url}}"
],
"path": [
"{{path}}",
"learningDashboard"
],
"query": [
{
"key": "{{param_session_token}}",
"value": ""
}
]
}
},
"response": []
}
]
}

View File

@ -1,3 +1,11 @@
location @html5client {
# proxy_pass http://127.0.0.1:4100; # use for development
proxy_pass http://poolhtml5servers; # use for production
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location /html5client/locales {
alias /usr/share/meteor/bundle/programs/web.browser/app/locales;
}
@ -18,10 +26,15 @@ location /html5client/fonts {
alias /usr/share/meteor/bundle/programs/web.browser/app/fonts;
}
location ~ ^/html5client/ {
# proxy_pass http://127.0.0.1:4100; # use for development
proxy_pass http://poolhtml5servers; # use for production
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
location /html5client/wasm {
types {
application/wasm wasm;
}
gzip_static on;
alias /usr/share/meteor/bundle/programs/web.browser/app/wasm;
}
location /html5client {
alias /usr/share/meteor/bundle/programs/web.browser;
try_files $uri @html5client;
}

View File

@ -91,6 +91,16 @@ if [ -f staging/usr/share/meteor/bundle/programs/web.browser/head.html ]; then
sed -i "s/VERSION/$(($BUILD))/" staging/usr/share/meteor/bundle/programs/web.browser/head.html
fi
# Compress tensorflow WASM binaries used for virtual backgrounds. Keep the
# uncompressed versions as well so it works with mismatched nginx location blocks
if [ -f staging/usr/share/meteor/bundle/programs/web.browser/app/wasm/tflite-simd.wasm ]; then
gzip -k -f -9 staging/usr/share/meteor/bundle/programs/web.browser/app/wasm/tflite-simd.wasm
fi
if [ -f staging/usr/share/meteor/bundle/programs/web.browser/app/wasm/tflite.wasm ]; then
gzip -k -f -9 staging/usr/share/meteor/bundle/programs/web.browser/app/wasm/tflite.wasm
fi
mkdir -p staging/etc/nginx/sites-available
cp bigbluebutton.nginx staging/etc/nginx/sites-available/bigbluebutton

View File

@ -143,7 +143,7 @@ module BigBlueButton
ffmpeg_filter << ",atempo=#{speed},atrim=start=#{ms_to_s(audio[:timestamp])}" if speed != 1
ffmpeg_filter << ",asetpts=PTS-STARTPTS"
ffmpeg_filter << ",asetpts=N"
else
BigBlueButton.logger.info " Generating silence"