Merge pull request #16354 from antobinary/26-into-27

chore: Merging 2.6.0-beta.4 into develop
This commit is contained in:
Anton Georgiev 2022-12-28 14:50:28 -05:00 committed by GitHub
commit f9a0debb11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 1225 additions and 552 deletions

View File

@ -13,7 +13,7 @@ jobs:
build-install-and-test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- run: ./build/get_external_dependencies.sh
- run: ./build/setup.sh bbb-apps-akka
- run: ./build/setup.sh bbb-config

View File

@ -6,8 +6,13 @@ on:
- opened
- synchronize
permissions:
contents: read
jobs:
main:
permissions:
pull-requests: write # for eps1lon/actions-label-merge-conflict to label PRs
runs-on: ubuntu-latest
steps:
- name: Check for dirty pull requests

View File

@ -18,7 +18,7 @@ val compileSettings = Seq(
"-Xlint",
"-Ywarn-dead-code",
"-language:_",
"-target:jvm-1.11",
"-target:11",
"-encoding", "UTF-8"
),
javacOptions ++= List(
@ -48,7 +48,7 @@ lazy val bbbAppsAkka = (project in file(".")).settings(name := "bbb-apps-akka",
// Config file is in ./.scalariform.conf
scalariformAutoformat := true
scalaVersion := "2.13.4"
scalaVersion := "2.13.9"
//-----------
// Packaging
//

View File

@ -7,7 +7,7 @@ object Dependencies {
object Versions {
// Scala
val scala = "2.13.4"
val scala = "2.13.9"
val junit = "4.12"
val junitInterface = "0.11"
val scalactic = "3.0.8"
@ -26,7 +26,7 @@ object Dependencies {
val codec = "1.15"
// BigBlueButton
val bbbCommons = "0.0.21-SNAPSHOT"
val bbbCommons = "0.0.22-SNAPSHOT"
// Test
val scalaTest = "3.2.11"

View File

@ -13,6 +13,12 @@ import java.io.File
trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
this: PresentationPodHdlrs =>
object JobTypes {
val DOWNLOAD = "PresentationWithAnnotationDownloadJob"
val CAPTURE_PRESENTATION = "PresentationWithAnnotationExportJob"
val CAPTURE_NOTES = "PadCaptureJob"
}
def buildStoreAnnotationsInRedisSysMsg(annotations: StoredAnnotations, liveMeeting: LiveMeeting): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(StoreAnnotationsInRedisSysMsg.NAME, routing)
@ -111,7 +117,6 @@ trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
log.error(s"Presentation ${presId} not found in meeting ${meetingId}")
} else {
val jobType: String = "PresentationWithAnnotationDownloadJob"
val jobId: String = RandomStringGenerator.randomAlphanumericString(16);
val allPages: Boolean = m.body.allPages
val pageCount = currentPres.get.pages.size
@ -120,7 +125,7 @@ trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
val pages: List[Int] = m.body.pages // Desired presentation pages for export
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages
val exportJob: ExportJob = new ExportJob(jobId, jobType, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
// Send Export Job to Redis
@ -147,7 +152,6 @@ trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
} else {
val jobId: String = RandomStringGenerator.randomAlphanumericString(16);
val jobType = "PresentationWithAnnotationExportJob"
val allPages: Boolean = m.allPages
val pageCount = currentPres.get.pages.size
@ -172,7 +176,7 @@ trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
// Informs bbb-web about the token so that when we use it to upload the presentation, it is able to look it up in the list of tokens
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(parentMeetingId, userId, presentationUploadToken, filename))
val exportJob: ExportJob = new ExportJob(jobId, jobType, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);
// Send Export Job to Redis
@ -210,13 +214,12 @@ trait PresentationWithAnnotationsMsgHdlr extends RightsManagementTrait {
val userId: String = "system"
val jobId: String = s"${m.body.breakoutId}-notes" // Used as the temporaryPresentationId upon upload
val jobType = "PadCaptureJob"
val filename = m.body.filename
val presentationUploadToken: String = PresentationPodsApp.generateToken("DEFAULT_PRESENTATION_POD", userId)
bus.outGW.send(buildPresentationUploadTokenSysPubMsg(m.body.parentMeetingId, userId, presentationUploadToken, filename))
val exportJob = new ExportJob(jobId, jobType, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)
bus.outGW.send(job)

View File

@ -42,6 +42,17 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
MeetingStatus2x.setPermissions(liveMeeting.status, settings)
// Dial-in
def buildLockMessage(meetingId: String, userId: String, lockedBy: String, locked: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(UserLockedInMeetingEvtMsg.NAME, routing)
val body = UserLockedInMeetingEvtMsgBody(userId, locked, lockedBy)
val header = BbbClientMsgHeader(UserLockedInMeetingEvtMsg.NAME, meetingId, userId)
val event = UserLockedInMeetingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
if (oldPermissions.disableCam != settings.disableCam) {
if (settings.disableCam) {
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
@ -55,24 +66,6 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
outGW.send(notifyEvent)
LockSettingsUtil.enforceCamLockSettingsForAllUsers(liveMeeting, outGW)
// Dial-in
def buildLockMessage(meetingId: String, userId: String, lockedBy: String, locked: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(UserLockedInMeetingEvtMsg.NAME, routing)
val body = UserLockedInMeetingEvtMsgBody(userId, locked, lockedBy)
val header = BbbClientMsgHeader(UserLockedInMeetingEvtMsg.NAME, meetingId, userId)
val event = UserLockedInMeetingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (vu.intId.startsWith(IntIdPrefixType.DIAL_IN)) { // only Dial-in users need this
val eventExplicitLock = buildLockMessage(liveMeeting.props.meetingProp.intId, vu.intId, msg.body.setBy, settings.disableMic)
outGW.send(eventExplicitLock)
}
}
} else {
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(
liveMeeting.props.meetingProp.intId,
@ -97,8 +90,12 @@ trait ChangeLockSettingsInMeetingCmdMsgHdlr extends RightsManagementTrait {
Vector()
)
outGW.send(notifyEvent)
// Apply lock settings when disableMic from false to true.
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (vu.intId.startsWith(IntIdPrefixType.DIAL_IN)) { // only Dial-in users need this
val eventExplicitLock = buildLockMessage(liveMeeting.props.meetingProp.intId, vu.intId, msg.body.setBy, settings.disableMic)
outGW.send(eventExplicitLock)
}
}
LockSettingsUtil.enforceLockSettingsForAllVoiceUsers(liveMeeting, outGW)
} else {
val notifyEvent = MsgBuilder.buildNotifyAllInMeetingEvtMsg(

View File

@ -18,7 +18,7 @@ val compileSettings = Seq(
"-Xlint",
"-Ywarn-dead-code",
"-language:_",
"-target:jvm-1.11",
"-target:11",
"-encoding", "UTF-8"
),
javacOptions ++= List(
@ -27,7 +27,7 @@ val compileSettings = Seq(
)
)
scalaVersion := "2.13.4"
scalaVersion := "2.13.9"
resolvers += Resolver.sonatypeRepo("releases")

View File

@ -7,7 +7,7 @@ object Dependencies {
object Versions {
// Scala
val scala = "2.13.4"
val scala = "2.13.9"
val junitInterface = "0.11"
val scalactic = "3.0.8"
@ -21,8 +21,8 @@ object Dependencies {
val codec = "1.15"
// BigBlueButton
val bbbCommons = "0.0.21-SNAPSHOT"
val bbbFsesl = "0.0.8-SNAPSHOT"
val bbbCommons = "0.0.22-SNAPSHOT"
val bbbFsesl = "0.0.9-SNAPSHOT"
// Test
val scalaTest = "3.2.11"

View File

@ -1,7 +1,7 @@
import org.bigbluebutton.build._
version := "0.0.21-SNAPSHOT"
version := "0.0.22-SNAPSHOT"
val compileSettings = Seq(
organization := "org.bigbluebutton",
@ -12,7 +12,7 @@ val compileSettings = Seq(
"-Xlint",
"-Ywarn-dead-code",
"-language:_",
"-target:jvm-1.11",
"-target:11",
"-encoding", "UTF-8"
),
javacOptions ++= List(
@ -55,7 +55,7 @@ scalariformAutoformat := true
// Do not append Scala versions to the generated artifacts
//crossPaths := false
scalaVersion := "2.13.4"
scalaVersion := "2.13.9"
// This forbids including Scala related libraries into the dependency
//autoScalaLibrary := false

View File

@ -7,7 +7,7 @@ object Dependencies {
object Versions {
// Scala
val scala = "2.13.4"
val scala = "2.13.9"
val junit = "4.12"
val junitInterface = "0.11"
val scalactic = "3.0.8"

View File

@ -9,16 +9,16 @@ case class DurationProps(duration: Int, createdTime: Long, createdDate: String,
endWhenNoModerator: Boolean, endWhenNoModeratorDelayInMinutes: Int)
case class MeetingProp(
name: String,
extId: String,
intId: String,
meetingCameraCap: Int,
maxPinnedCameras: Int,
isBreakout: Boolean,
disabledFeatures: Vector[String],
notifyRecordingIsOn: Boolean,
uploadExternalDescription: String,
uploadExternalUrl: String,
name: String,
extId: String,
intId: String,
meetingCameraCap: Int,
maxPinnedCameras: Int,
isBreakout: Boolean,
disabledFeatures: Vector[String],
notifyRecordingIsOn: Boolean,
presentationUploadExternalDescription: String,
presentationUploadExternalUrl: String,
)
case class BreakoutProps(

View File

@ -11,7 +11,7 @@ val compileSettings = Seq(
"-Xlint",
"-Ywarn-dead-code",
"-language:_",
"-target:jvm-1.11",
"-target:11",
"-encoding", "UTF-8"
),
javacOptions ++= List(
@ -40,7 +40,7 @@ lazy val commonWeb = (project in file(".")).settings(name := "bbb-common-web", l
// Config file is in ./.scalariform.conf
scalariformAutoformat := true
scalaVersion := "2.13.4"
scalaVersion := "2.13.9"
//-----------
// Packaging
//

View File

@ -7,7 +7,7 @@ object Dependencies {
object Versions {
// Scala
val scala = "2.13.4"
val scala = "2.13.9"
val junit = "4.12"
val junitInterface = "0.11"
val scalactic = "3.0.8"
@ -34,7 +34,7 @@ object Dependencies {
val text = "1.10.0"
// BigBlueButton
val bbbCommons = "0.0.21-SNAPSHOT"
val bbbCommons = "0.0.22-SNAPSHOT"
// Test
val scalaTest = "3.2.11"

View File

@ -73,8 +73,8 @@ public class ApiParams {
public static final String DISABLED_FEATURES = "disabledFeatures";
public static final String NOTIFY_RECORDING_IS_ON = "notifyRecordingIsOn";
public static final String UPLOAD_EXTERNAL_DESCRIPTION = "uploadExternalDescription";
public static final String UPLOAD_EXTERNAL_URL = "uploadExternalUrl";
public static final String PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION = "presentationUploadExternalDescription";
public static final String PRESENTATION_UPLOAD_EXTERNAL_URL = "presentationUploadExternalUrl";
public static final String BREAKOUT_ROOMS_CAPTURE_SLIDES = "breakoutRoomsCaptureSlides";
public static final String BREAKOUT_ROOMS_CAPTURE_NOTES = "breakoutRoomsCaptureNotes";

View File

@ -419,7 +419,7 @@ public class MeetingService implements MessageListener {
m.getMuteOnStart(), m.getAllowModsToUnmuteUsers(), m.getAllowModsToEjectCameras(), m.getMeetingKeepEvents(),
m.breakoutRoomsParams, m.lockSettingsParams, m.getHtml5InstanceId(),
m.getGroups(), m.getDisabledFeatures(), m.getNotifyRecordingIsOn(),
m.getUploadExternalDescription(), m.getUploadExternalUrl());
m.getPresentationUploadExternalDescription(), m.getPresentationUploadExternalUrl());
}
private String formatPrettyDate(Long timestamp) {

View File

@ -81,6 +81,7 @@ public class ParamsProcessorUtil {
private String defaultHTML5ClientUrl;
private String defaultGuestWaitURL;
private Boolean allowRequestsWithoutSession = false;
private Integer defaultHttpSessionTimeout = 14400;
private Boolean useDefaultAvatar = false;
private String defaultAvatarURL;
private String defaultGuestPolicy;
@ -104,8 +105,8 @@ public class ParamsProcessorUtil {
private boolean defaultKeepEvents = false;
private Boolean useDefaultLogo;
private String defaultLogoURL;
private String defaultUploadExternalDescription = "";
private String defaultUploadExternalUrl = "";
private String defaultPresentationUploadExternalDescription = "";
private String defaultPresentationUploadExternalUrl = "";
private boolean defaultBreakoutRoomsEnabled = true;
private boolean defaultBreakoutRoomsRecord;
@ -639,14 +640,14 @@ public class ParamsProcessorUtil {
guestPolicy = params.get(ApiParams.GUEST_POLICY);
}
String uploadExternalDescription = defaultUploadExternalDescription;
if (!StringUtils.isEmpty(params.get(ApiParams.UPLOAD_EXTERNAL_DESCRIPTION))) {
uploadExternalDescription = params.get(ApiParams.UPLOAD_EXTERNAL_DESCRIPTION);
String presentationUploadExternalDescription = defaultPresentationUploadExternalDescription;
if (!StringUtils.isEmpty(params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION))) {
presentationUploadExternalDescription = params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_DESCRIPTION);
}
String uploadExternalUrl = defaultUploadExternalUrl;
if (!StringUtils.isEmpty(params.get(ApiParams.UPLOAD_EXTERNAL_URL))) {
uploadExternalUrl = params.get(ApiParams.UPLOAD_EXTERNAL_URL);
String presentationUploadExternalUrl = defaultPresentationUploadExternalUrl;
if (!StringUtils.isEmpty(params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_URL))) {
presentationUploadExternalUrl = params.get(ApiParams.PRESENTATION_UPLOAD_EXTERNAL_URL);
}
String meetingLayout = defaultMeetingLayout;
@ -737,8 +738,8 @@ public class ParamsProcessorUtil {
.withGroups(groups)
.withDisabledFeatures(listOfDisabledFeatures)
.withNotifyRecordingIsOn(notifyRecordingIsOn)
.withUploadExternalDescription(uploadExternalDescription)
.withUploadExternalUrl(uploadExternalUrl)
.withPresentationUploadExternalDescription(presentationUploadExternalDescription)
.withPresentationUploadExternalUrl(presentationUploadExternalUrl)
.build();
if (!StringUtils.isEmpty(params.get(ApiParams.MODERATOR_ONLY_MESSAGE))) {
@ -846,6 +847,14 @@ public class ParamsProcessorUtil {
return allowRequestsWithoutSession;
}
public Integer getDefaultHttpSessionTimeout() {
return defaultHttpSessionTimeout;
}
public void setDefaultHttpSessionTimeout(Integer value) {
this.defaultHttpSessionTimeout = value;
}
public String getDefaultLogoutUrl() {
if ((StringUtils.isEmpty(defaultLogoutUrl)) || "default".equalsIgnoreCase(defaultLogoutUrl)) {
return defaultServerUrl;
@ -1445,12 +1454,12 @@ public class ParamsProcessorUtil {
this.defaultNotifyRecordingIsOn = notifyRecordingIsOn;
}
public void setUploadExternalDescription(String uploadExternalDescription) {
this.defaultUploadExternalDescription = uploadExternalDescription;
public void setPresentationUploadExternalDescription(String presentationUploadExternalDescription) {
this.defaultPresentationUploadExternalDescription = presentationUploadExternalDescription;
}
public void setUploadExternalUrl(String uploadExternalUrl) {
this.defaultUploadExternalUrl = uploadExternalUrl;
public void setPresentationUploadExternalUrl(String presentationUploadExternalUrl) {
this.defaultPresentationUploadExternalUrl = presentationUploadExternalUrl;
}
public void setBbbVersion(String version) {

View File

@ -97,8 +97,8 @@ public class Meeting {
private Boolean allowRequestsWithoutSession = false;
private Boolean allowModsToEjectCameras = false;
private Boolean meetingKeepEvents;
private String uploadExternalDescription;
private String uploadExternalUrl;
private String presentationUploadExternalDescription;
private String presentationUploadExternalUrl;
private Integer meetingExpireIfNoUserJoinedInMinutes = 5;
private Integer meetingExpireWhenLastUserLeftInMinutes = 1;
@ -123,8 +123,8 @@ public class Meeting {
intMeetingId = builder.internalId;
disabledFeatures = builder.disabledFeatures;
notifyRecordingIsOn = builder.notifyRecordingIsOn;
uploadExternalDescription = builder.uploadExternalDescription;
uploadExternalUrl = builder.uploadExternalUrl;
presentationUploadExternalDescription = builder.presentationUploadExternalDescription;
presentationUploadExternalUrl = builder.presentationUploadExternalUrl;
if (builder.viewerPass == null){
viewerPass = "";
} else {
@ -424,11 +424,11 @@ public class Meeting {
return notifyRecordingIsOn;
}
public String getUploadExternalDescription() {
return uploadExternalDescription;
public String getPresentationUploadExternalDescription() {
return presentationUploadExternalDescription;
}
public String getUploadExternalUrl() {
return uploadExternalUrl;
public String getPresentationUploadExternalUrl() {
return presentationUploadExternalUrl;
}
public String getWelcomeMessageTemplate() {
@ -863,8 +863,8 @@ public class Meeting {
private String learningDashboardAccessToken;
private ArrayList<String> disabledFeatures;
private Boolean notifyRecordingIsOn;
private String uploadExternalDescription;
private String uploadExternalUrl;
private String presentationUploadExternalDescription;
private String presentationUploadExternalUrl;
private int duration;
private String webVoice;
private String telVoice;
@ -993,13 +993,13 @@ public class Meeting {
return this;
}
public Builder withUploadExternalDescription(String d) {
this.uploadExternalDescription = d;
public Builder withPresentationUploadExternalDescription(String d) {
this.presentationUploadExternalDescription = d;
return this;
}
public Builder withUploadExternalUrl(String u) {
this.uploadExternalUrl = u;
public Builder withPresentationUploadExternalUrl(String u) {
this.presentationUploadExternalUrl = u;
return this;
}

View File

@ -25,8 +25,8 @@ public class CreateMeetingMessage {
public final String learningDashboardAccessToken;
public final ArrayList<String> disabledFeatures;
public final Boolean notifyRecordingIsOn;
public final String uploadExternalDescription;
public final String uploadExternalUrl;
public final String presentationUploadExternalDescription;
public final String presentationUploadExternalUrl;
public final Long createTime;
public final String createDate;
public final Map<String, String> metadata;
@ -38,8 +38,8 @@ public class CreateMeetingMessage {
String viewerPass, String learningDashboardAccessToken,
ArrayList<String> disabledFeatures,
Boolean notifyRecordingIsOn,
String uploadExternalDescription,
String uploadExternalUrl,
String presentationUploadExternalDescription,
String presentationUploadExternalUrl,
Long createTime, String createDate, Map<String, String> metadata) {
this.id = id;
this.externalId = externalId;
@ -58,8 +58,8 @@ public class CreateMeetingMessage {
this.learningDashboardAccessToken = learningDashboardAccessToken;
this.disabledFeatures = disabledFeatures;
this.notifyRecordingIsOn = notifyRecordingIsOn;
this.uploadExternalDescription = uploadExternalDescription;
this.uploadExternalUrl = uploadExternalUrl;
this.presentationUploadExternalDescription = presentationUploadExternalDescription;
this.presentationUploadExternalUrl = presentationUploadExternalUrl;
this.createTime = createTime;
this.createDate = createDate;
this.metadata = metadata;

View File

@ -18,7 +18,7 @@ public class ParamsUtil {
public static final String INVALID_CHARS = ",";
public static String stripControlChars(String text) {
return text.replaceAll("\\p{Cc}", "");
return text.replaceAll("\\p{Cc}", "").trim();
}
public static String escapeHTMLTags(String value) {

View File

@ -43,8 +43,8 @@ public interface IBbbWebApiGWApp {
ArrayList<Group> groups,
ArrayList<String> disabledFeatures,
Boolean notifyRecordingIsOn,
String uploadExternalDescription,
String uploadExternalUrl);
String presentationUploadExternalDescription,
String presentationUploadExternalUrl);
void registerUser(String meetingID, String internalUserId, String fullname, String role,
String externUserID, String authToken, String avatarURL,

View File

@ -150,8 +150,8 @@ class BbbWebApiGWApp(
groups: java.util.ArrayList[Group],
disabledFeatures: java.util.ArrayList[String],
notifyRecordingIsOn: java.lang.Boolean,
uploadExternalDescription: String,
uploadExternalUrl: String): Unit = {
presentationUploadExternalDescription: String,
presentationUploadExternalUrl: String): Unit = {
val disabledFeaturesAsVector: Vector[String] = disabledFeatures.asScala.toVector
@ -164,8 +164,8 @@ class BbbWebApiGWApp(
isBreakout = isBreakout.booleanValue(),
disabledFeaturesAsVector,
notifyRecordingIsOn,
uploadExternalDescription,
uploadExternalUrl
presentationUploadExternalDescription,
presentationUploadExternalUrl
)
val durationProps = DurationProps(

View File

@ -0,0 +1 @@
engine-strict=true

View File

@ -1,13 +1,13 @@
const config = require('../../config');
const { level } = config.log;
const {level} = config.log;
const trace = level.toLowerCase() === 'trace';
const debug = trace || level.toLowerCase() === 'debug';
const date = () => new Date().toISOString();
const parse = (messages) => {
return messages.map(message => {
return messages.map((message) => {
if (typeof message === 'object') return JSON.stringify(message);
return message;

View File

@ -0,0 +1,88 @@
const config = require('../../config');
const EXPORT_STATUSES = Object.freeze({
COLLECTING: 'COLLECTING',
PROCESSING: 'PROCESSING',
});
class PresAnnStatusMsg {
constructor(exportJob, status = EXPORT_STATUSES.COLLECTING) {
this.message = {
envelope: {
name: config.log.msgName,
routing: {
sender: exportJob.module,
},
timestamp: (new Date()).getTime(),
},
core: {
header: {
name: config.log.msgName,
meetingId: exportJob.parentMeetingId,
userId: '',
},
body: {
presId: exportJob.presId,
pageNumber: 1,
totalPages: JSON.parse(exportJob.pages).length,
status,
error: false,
},
},
};
}
build = (pageNumber = 1) => {
this.message.core.body.pageNumber = pageNumber;
this.message.envelope.timestamp = (new Date()).getTime();
const event = JSON.stringify(this.message);
this.message.core.body.error = false;
return event;
};
setError = (error = true) => {
this.message.core.body.error = error;
};
setStatus = (status) => {
this.message.core.body.status = status;
};
static get EXPORT_STATUSES() {
return EXPORT_STATUSES;
}
};
class NewPresAnnFileAvailableMsg {
constructor(exportJob, link) {
this.message = {
envelope: {
name: config.notifier.msgName,
routing: {
sender: exportJob.module,
},
timestamp: (new Date()).getTime(),
},
core: {
header: {
name: config.notifier.msgName,
meetingId: exportJob.parentMeetingId,
userId: '',
},
body: {
fileURI: link,
presId: exportJob.presId,
},
},
};
}
build = () => {
return JSON.stringify(this.message);
};
};
module.exports = {
PresAnnStatusMsg,
NewPresAnnFileAvailableMsg,
};

View File

@ -10,6 +10,7 @@
"dependencies": {
"axios": "^0.26.0",
"form-data": "^4.0.0",
"lodash": "^4.17.21",
"perfect-freehand": "^1.0.16",
"probe-image-size": "^7.2.3",
"redis": "^4.0.3",
@ -19,6 +20,10 @@
"devDependencies": {
"eslint": "^8.20.0",
"eslint-config-google": "^0.14.0"
},
"engines": {
"node": "^16.16.0",
"npm": "^8.5.0"
}
},
"node_modules/@eslint/eslintrc": {
@ -920,6 +925,11 @@
"node": ">= 0.8.0"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -2044,6 +2054,11 @@
"type-check": "~0.4.0"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",

View File

@ -19,5 +19,9 @@
"devDependencies": {
"eslint": "^8.20.0",
"eslint-config-google": "^0.14.0"
},
"engines": {
"node": "^16.16.0",
"npm": "^8.5.0"
}
}

View File

@ -8,6 +8,7 @@ const redis = require('redis');
const sanitize = require('sanitize-filename');
const stream = require('stream');
const WorkerStarter = require('../lib/utils/worker-starter');
const {PresAnnStatusMsg} = require('../lib/utils/message-builder');
const {workerData} = require('worker_threads');
const {promisify} = require('util');
@ -55,29 +56,7 @@ async function collectAnnotationsFromRedis() {
const pdfFile = `${presFile}.pdf`;
// Message to display conversion progress toast
const statusUpdate = {
envelope: {
name: config.log.msgName,
routing: {
sender: exportJob.module,
},
timestamp: (new Date()).getTime(),
},
core: {
header: {
name: config.log.msgName,
meetingId: exportJob.parentMeetingId,
userId: '',
},
body: {
presId: exportJob.presId,
pageNumber: 1,
totalPages: pages.length,
status: 'COLLECTING',
error: false,
},
},
};
const statusUpdate = new PresAnnStatusMsg(exportJob);
if (fs.existsSync(pdfFile)) {
for (const p of pages) {
@ -103,35 +82,32 @@ async function collectAnnotationsFromRedis() {
try {
cp.spawnSync(config.shared.pdftocairo, extract_png_from_pdf, {shell: false});
} catch (error) {
const error_reason = `PDFtoCairo failed extracting slide ${pageNumber}`;
logger.error(`${error_reason} in job ${jobId}: ${error.message}`);
statusUpdate.core.body.status = error_reason;
statusUpdate.core.body.error = true;
logger.error(`PDFtoCairo failed extracting slide ${pageNumber} in job ${jobId}: ${error.message}`);
statusUpdate.setError();
}
statusUpdate.core.body.pageNumber = pageNumber;
statusUpdate.envelope.timestamp = (new Date()).getTime();
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
statusUpdate.core.body.error = false;
await client.publish(config.redis.channels.publish, statusUpdate.build(pageNumber));
}
// If PNG file already available
} else if (fs.existsSync(`${presFile}.png`)) {
fs.copyFileSync(`${presFile}.png`, path.join(dropbox, 'slide1.png'));
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
// If JPEG file available
} else if (fs.existsSync(`${presFile}.jpeg`)) {
fs.copyFileSync(`${presFile}.jpeg`, path.join(dropbox, 'slide1.jpeg'));
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
} else {
statusUpdate.core.body.error = true;
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
client.disconnect();
return logger.error(`Presentation file missing for job ${exportJob.jobId}`);
if (fs.existsSync(`${presFile}.png`)) {
// PNG file available
fs.copyFileSync(`${presFile}.png`, path.join(dropbox, 'slide1.png'));
} else if (fs.existsSync(`${presFile}.jpeg`)) {
// JPEG file available
fs.copyFileSync(`${presFile}.jpeg`, path.join(dropbox, 'slide1.jpeg'));
await client.publish(config.redis.channels.publish, statusUpdate.build());
} else {
await client.publish(config.redis.channels.publish, statusUpdate.build());
client.disconnect();
return logger.error(`No PDF, PNG or JPEG file available for job ${jobId}`);
}
await client.publish(config.redis.channels.publish, statusUpdate.build());
}
client.disconnect();
const process = new WorkerStarter({jobId, statusUpdate});
const process = new WorkerStarter({jobId});
process.process();
}

View File

@ -5,6 +5,7 @@ const FormData = require('form-data');
const redis = require('redis');
const axios = require('axios').default;
const path = require('path');
const {NewPresAnnFileAvailableMsg} = require('../lib/utils/message-builder');
const {workerData} = require('worker_threads');
const [jobType, jobId, filename] = [workerData.jobType, workerData.jobId, workerData.filename];
@ -31,30 +32,10 @@ async function notifyMeetingActor() {
exportJob.parentMeetingId, exportJob.parentMeetingId,
exportJob.presId, 'pdf', jobId, filename);
const notification = {
envelope: {
name: config.notifier.msgName,
routing: {
sender: exportJob.module,
},
timestamp: (new Date()).getTime(),
},
core: {
header: {
name: config.notifier.msgName,
meetingId: exportJob.parentMeetingId,
userId: '',
},
body: {
fileURI: link,
presId: exportJob.presId,
},
},
};
const notification = new NewPresAnnFileAvailableMsg(exportJob, link);
logger.info(`Annotated PDF available at ${link}`);
await client.publish(config.redis.channels.publish,
JSON.stringify(notification));
await client.publish(config.redis.channels.publish, notification.build());
client.disconnect();
}

View File

@ -10,14 +10,16 @@ const sanitize = require('sanitize-filename');
const {getStrokePoints, getStrokeOutlinePoints} = require('perfect-freehand');
const probe = require('probe-image-size');
const redis = require('redis');
const {PresAnnStatusMsg} = require('../lib/utils/message-builder');
const [jobId, statusUpdate] = [workerData.jobId, workerData.statusUpdate];
const jobId = workerData.jobId;
const logger = new Logger('presAnn Process Worker');
logger.info('Processing PDF for job ' + jobId);
statusUpdate.core.body.status = 'PROCESSING';
const dropbox = path.join(config.shared.presAnnDropboxDir, jobId);
const job = fs.readFileSync(path.join(dropbox, 'job'));
const exportJob = JSON.parse(job);
const statusUpdate = new PresAnnStatusMsg(exportJob, PresAnnStatusMsg.EXPORT_STATUSES.PROCESSING);
// General utilities for rendering SVGs resembling Tldraw as much as possible
function align_to_pango(alignment) {
@ -157,10 +159,8 @@ function render_textbox(textColor, font, fontSize, textAlign, text, id, textBoxW
try {
cp.spawnSync(config.shared.imagemagick, commands, {shell: false});
} catch (error) {
const error_reason = 'ImageMagick failed to render textbox';
logger.error(`${error_reason} in job ${jobId}: ${error.message}`);
statusUpdate.core.body.status = error_reason;
statusUpdate.core.body.error = true;
logger.error(`ImageMagick failed to render textbox in job ${jobId}: ${error.message}`);
statusUpdate.setError();
}
}
@ -596,7 +596,7 @@ function overlay_shape_label(svg, annotation) {
const fontSize = text_size_to_px(annotation.style.size, annotation.style.scale);
const textAlign = 'center';
const text = annotation.label;
const id = annotation.id;
const id = sanitize(annotation.id);
const rotation = rad_to_degree(annotation.rotation);
const [shape_width, shape_height] = annotation.size;
@ -641,7 +641,7 @@ function overlay_sticky(svg, annotation) {
const textColor = '#0d0d0d'; // For sticky notes
const text = annotation.text;
const id = annotation.id;
const id = sanitize(annotation.id);
render_textbox(textColor, font, fontSize, textAlign, text, id, textBoxWidth);
@ -701,7 +701,7 @@ function overlay_text(svg, annotation) {
const fontSize = text_size_to_px(annotation.style.size, annotation.style.scale);
const textAlign = align_to_pango(annotation.style.textAlign);
const text = annotation.text;
const id = annotation.id;
const id = sanitize(annotation.id);
const rotation = rad_to_degree(annotation.rotation);
const [textBox_x, textBox_y] = annotation.point;
@ -787,17 +787,13 @@ async function process_presentation_annotations() {
client.on('error', (err) => logger.info('Redis Client Error', err));
// 1. Get the job
const job = fs.readFileSync(path.join(dropbox, 'job'));
const exportJob = JSON.parse(job);
// 2. Get the annotations
// Get the annotations
const annotations = fs.readFileSync(path.join(dropbox, 'whiteboard'));
const whiteboard = JSON.parse(annotations);
const pages = JSON.parse(whiteboard.pages);
const ghostScriptInput = [];
// 3. Convert annotations to SVG
// Convert annotations to SVG
for (const currentSlide of pages) {
const bgImagePath = path.join(dropbox, `slide${currentSlide.page}`);
const svgBackgroundSlide = path.join(exportJob.presLocation,
@ -854,14 +850,7 @@ async function process_presentation_annotations() {
}
});
// Dimensions converted to a pixel size which,
// when converted to points, will yield the desired
// dimension in pixels when read without conversion
// e.g. say the background SVG dimensions are set to 1920x1080 pt
// Resize output to 2560x1440 px so that the SVG
// generates with the original size in pt.
// Scale slide back to its original size
const convertAnnotatedSlide = [
SVGfile,
'--output-width', to_px(slideWidth),
@ -873,15 +862,11 @@ async function process_presentation_annotations() {
cp.spawnSync(config.shared.cairosvg, convertAnnotatedSlide, {shell: false});
} catch (error) {
logger.error(`Processing slide ${currentSlide.page} failed for job ${jobId}: ${error.message}`);
statusUpdate.core.body.error = true;
statusUpdate.setError();
}
statusUpdate.core.body.pageNumber = currentSlide.page;
statusUpdate.envelope.timestamp = (new Date()).getTime();
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
await client.publish(config.redis.channels.publish, statusUpdate.build(currentSlide.page));
ghostScriptInput.push(PDFfile);
statusUpdate.core.body.error = false;
}
// Create PDF output directory if it doesn't exist
@ -903,11 +888,7 @@ async function process_presentation_annotations() {
try {
cp.spawnSync(config.shared.ghostscript, mergePDFs, {shell: false});
} catch (error) {
const error_reason = 'GhostScript failed to merge PDFs';
logger.error(`${error_reason} in job ${jobId}: ${error.message}`);
statusUpdate.core.body.status = error_reason;
statusUpdate.core.body.error = true;
await client.publish(config.redis.channels.publish, JSON.stringify(statusUpdate));
return logger.error(`GhostScript failed to merge PDFs in job ${jobId}: ${error.message}`);
}
// Launch Notifier Worker depending on job type

View File

@ -2,7 +2,7 @@ import org.bigbluebutton.build._
description := "BigBlueButton custom FS-ESL client built on top of FS-ESL Java library."
version := "0.0.8-SNAPSHOT"
version := "0.0.9-SNAPSHOT"
val compileSettings = Seq(
organization := "org.bigbluebutton",
@ -13,7 +13,7 @@ val compileSettings = Seq(
"-Xlint",
"-Ywarn-dead-code",
"-language:_",
"-target:jvm-1.11",
"-target:11",
"-encoding", "UTF-8"
),
javacOptions ++= List(
@ -52,7 +52,7 @@ crossPaths := false
// This forbids including Scala related libraries into the dependency
autoScalaLibrary := false
scalaVersion := "2.13.4"
scalaVersion := "2.13.9"
publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath + "/.m2/repository")))

View File

@ -7,7 +7,7 @@ object Dependencies {
object Versions {
// Scala
val scala = "2.13.4"
val scala = "2.13.9"
// Libraries
val netty = "3.2.10.Final"

View File

@ -1 +1 @@
BIGBLUEBUTTON_RELEASE=2.6.0-beta.3
BIGBLUEBUTTON_RELEASE=2.6.0-beta.4

View File

@ -109,6 +109,15 @@ enableUFWRules() {
ufw allow OpenSSH
ufw allow "Nginx Full"
ufw allow 16384:32768/udp
# Check if coturn is running on this server and, if so, open firewall port
if systemctl status coturn > /dev/null; then
echo " - Local turnserver detected -- opening port 3478"
ufw allow 3478
# echo " - Forcing FireFox to use turn server"
# yq w -i $HTML5_CONFIG public.kurento.forceRelayOnFirefox true
fi
ufw --force enable
}

View File

@ -1686,8 +1686,7 @@ if [ -n "$HOST" ]; then
echo "Restarting BigBlueButton $BIGBLUEBUTTON_RELEASE ..."
stop_bigbluebutton
start_bigbluebutton
systemctl restart bigbluebutton.target
exit 0
fi
@ -1699,8 +1698,7 @@ if [ $RESTART ]; then
echo "Restarting BigBlueButton $BIGBLUEBUTTON_RELEASE ..."
stop_bigbluebutton
start_bigbluebutton
systemctl restart bigbluebutton.target
check_state
fi

View File

@ -127,7 +127,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</head>
<body style="background-color: #06172A">
<div id="aria-polite-alert" aria-live="polite" aria-atomic="false" class="sr-only"></div>
<div id="app" role="document">
<main>
<div id="app" role="document">
</main>
</div>
<span id="destination"></span>
<audio id="remote-media" autoplay>

View File

@ -1296,6 +1296,8 @@ export default class SIPBridge extends BaseAudioBridge {
}
exitAudio() {
if (this.activeSession == null) return Promise.resolve();
return this.activeSession.exitAudio();
}

View File

@ -2,6 +2,7 @@ import Breakouts from '/imports/api/breakouts';
import updateUserBreakoutRoom from '/imports/api/users-persistent-data/server/modifiers/updateUserBreakoutRoom';
import Logger from '/imports/startup/server/logger';
import { check } from 'meteor/check';
import { lowercaseTrim } from '/imports/utils/string-utils';
export default function joinedUsersChanged({ body }) {
check(body, Object);
@ -21,7 +22,7 @@ export default function joinedUsersChanged({ body }) {
breakoutId,
};
const usersMapped = users.map(user => ({ userId: user.id, name: user.name }));
const usersMapped = users.map(user => ({ userId: user.id, name: user.name, sortName: lowercaseTrim(user.name) }));
const modifier = {
$set: {
joinedUsers: usersMapped,

View File

@ -86,8 +86,8 @@ export default function addMeeting(meeting) {
name: String,
disabledFeatures: Array,
notifyRecordingIsOn: Boolean,
uploadExternalDescription: String,
uploadExternalUrl: String,
presentationUploadExternalDescription: String,
presentationUploadExternalUrl: String,
},
usersProp: {
maxUsers: Number,

View File

@ -6,6 +6,7 @@ import VoiceUsers from '/imports/api/voice-users/';
import addUserPsersistentData from '/imports/api/users-persistent-data/server/modifiers/addUserPersistentData';
import stringHash from 'string-hash';
import flat from 'flat';
import { lowercaseTrim } from '/imports/utils/string-utils';
import addVoiceUser from '/imports/api/voice-users/server/modifiers/addVoiceUser';
@ -51,7 +52,7 @@ export default function addUser(meetingId, userData) {
const userInfos = {
meetingId,
sortName: user.name.trim().toLowerCase(),
sortName: lowercaseTrim(user.name),
color,
speechLocale: '',
mobile: false,

View File

@ -7,6 +7,7 @@ import {
} from '/imports/api/video-streams/server/helpers';
import VoiceUsers from '/imports/api/voice-users/';
import Users from '/imports/api/users/';
import { lowercaseTrim } from '/imports/utils/string-utils';
const BASE_FLOOR_TIME = "0";
@ -40,6 +41,7 @@ export default function sharedWebcam(meetingId, userId, stream) {
$set: {
stream,
name,
sortName: lowercaseTrim(name),
lastFloorTime,
floor,
pin,

View File

@ -723,8 +723,7 @@ class BreakoutRoom extends PureComponent {
}
populateWithLastBreakouts(lastBreakouts) {
const { getBreakoutUserWasIn, intl } = this.props;
const { users } = this.state;
const { getBreakoutUserWasIn, users, intl } = this.props;
const changedNames = [];
lastBreakouts.forEach((breakout) => {

View File

@ -74,11 +74,7 @@ class LiveCaptions extends PureComponent {
<div style={captionStyles}>
{clear ? '' : data}
</div>
<div
style={visuallyHidden}
aria-atomic
aria-live="polite"
>
<div style={visuallyHidden}>
{clear ? '' : data}
</div>
</div>

View File

@ -46,7 +46,7 @@ class LocalesDropdown extends PureComponent {
render() {
const {
value, handleChange, elementId, selectMessage,
value, handleChange, elementId, selectMessage, ariaLabel,
} = this.props;
const defaultLocale = value || DEFAULT_VALUE;
@ -57,6 +57,7 @@ class LocalesDropdown extends PureComponent {
id={elementId}
onChange={handleChange}
value={defaultLocale}
aria-label={ariaLabel||''}
>
<option disabled key={DEFAULT_KEY} value={DEFAULT_VALUE}>
{selectMessage}

View File

@ -19,6 +19,7 @@ import Checkbox from '/imports/ui/components/common/checkbox/component';
const { isMobile } = deviceInfo;
const propTypes = {
allowDownloadable: PropTypes.bool.isRequired,
intl: PropTypes.object.isRequired,
fileUploadConstraintsHint: PropTypes.bool.isRequired,
fileSizeMax: PropTypes.number.isRequired,
@ -954,6 +955,18 @@ class PresentationUploader extends Component {
}
}
renderDownloadableWithAnnotationsHint() {
const {
intl,
allowDownloadable
} = this.props;
return allowDownloadable ? (
<Styled.ExportHint>
{intl.formatMessage(intlMessages.exportHint)}
</Styled.ExportHint>)
: null;
}
renderPresentationItem(item) {
const { disableActions } = this.state;
const {
@ -1108,9 +1121,9 @@ class PresentationUploader extends Component {
renderExternalUpload() {
const { externalUploadData, intl } = this.props;
const { uploadExternalDescription, uploadExternalUrl } = externalUploadData;
const { presentationUploadExternalDescription, presentationUploadExternalUrl } = externalUploadData;
if (!uploadExternalDescription || !uploadExternalUrl) return null;
if (!presentationUploadExternalDescription || !presentationUploadExternalUrl) return null;
return (
<Styled.ExternalUpload>
@ -1119,11 +1132,11 @@ class PresentationUploader extends Component {
{intl.formatMessage(intlMessages.externalUploadTitle)}
</Styled.ExternalUploadTitle>
<p>{uploadExternalDescription}</p>
<p>{presentationUploadExternalDescription}</p>
</div>
<Styled.ExternalUploadButton
color="default"
onClick={() => window.open(`${uploadExternalUrl}`)}
onClick={() => window.open(`${presentationUploadExternalUrl}`)}
label={intl.formatMessage(intlMessages.externalUploadLabel)}
aria-describedby={intl.formatMessage(intlMessages.externalUploadLabel)}
/>
@ -1218,10 +1231,8 @@ class PresentationUploader extends Component {
{`${intl.formatMessage(intlMessages.message)}`}
{fileUploadConstraintsHint ? this.renderExtraHint() : null}
</Styled.ModalHint>
{this.renderPresentationList()}
<Styled.ExportHint>
{intl.formatMessage(intlMessages.exportHint)}
</Styled.ExportHint>
{this.renderPresentationList()}
{this.renderDownloadableWithAnnotationsHint()}
{isMobile ? this.renderPicDropzone() : null}
{this.renderDropzone()}
{this.renderExternalUpload()}

View File

@ -342,17 +342,17 @@ const getExternalUploadData = () => {
{ meetingId: Auth.meetingID },
{
fields: {
'meetingProp.uploadExternalDescription': 1,
'meetingProp.uploadExternalUrl': 1
'meetingProp.presentationUploadExternalDescription': 1,
'meetingProp.presentationUploadExternalUrl': 1
},
},
);
const { uploadExternalDescription, uploadExternalUrl } = meetingProp;
const { presentationUploadExternalDescription, presentationUploadExternalUrl } = meetingProp;
return {
uploadExternalDescription,
uploadExternalUrl,
presentationUploadExternalDescription,
presentationUploadExternalUrl,
}
};

View File

@ -150,11 +150,14 @@ class Settings extends Component {
});
}
displaySettingsStatus(status) {
displaySettingsStatus(status, textOnly = false) {
const { intl } = this.props;
if (textOnly) {
return status ? intl.formatMessage(intlMessages.on)
: intl.formatMessage(intlMessages.off)
}
return (
<Styled.ToggleLabel>
<Styled.ToggleLabel aria-hidden>
{status ? intl.formatMessage(intlMessages.on)
: intl.formatMessage(intlMessages.off)}
</Styled.ToggleLabel>

View File

@ -283,7 +283,7 @@ class ApplicationMenu extends BaseMenu {
icons={false}
defaultChecked={this.state.audioFilterEnabled}
onChange={() => this.handleAudioFilterChange()}
ariaLabel={intl.formatMessage(intlMessages.audioFilterLabel)}
ariaLabel={`${intl.formatMessage(intlMessages.audioFilterLabel)} - ${displaySettingsStatus(audioFilterStatus, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
@ -319,7 +319,7 @@ class ApplicationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.paginationEnabled}
onChange={() => this.handleToggle('paginationEnabled')}
ariaLabel={intl.formatMessage(intlMessages.paginationEnabledLabel)}
ariaLabel={`${intl.formatMessage(intlMessages.paginationEnabledLabel)} - ${displaySettingsStatus(settings.paginationEnabled, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
@ -353,6 +353,7 @@ class ApplicationMenu extends BaseMenu {
defaultChecked={settings.darkTheme}
onChange={() => this.handleToggle('darkTheme')}
showToggleLabel={showToggleLabel}
ariaLabel={`${intl.formatMessage(intlMessages.darkThemeLabel)} - ${displaySettingsStatus(settings.darkTheme, true)}`}
data-test="darkModeToggleBtn"
/>
</Styled.FormElementRight>
@ -408,7 +409,7 @@ class ApplicationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.animations}
onChange={() => this.handleToggle('animations')}
ariaLabel={intl.formatMessage(intlMessages.animationsLabel)}
ariaLabel={`${intl.formatMessage(intlMessages.animationsLabel)} - ${displaySettingsStatus(settings.animations, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
@ -422,10 +423,7 @@ class ApplicationMenu extends BaseMenu {
<Styled.Row>
<Styled.Col>
<Styled.FormElement>
<Styled.Label
htmlFor="langSelector"
aria-label={intl.formatMessage(intlMessages.languageLabel)}
>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.languageLabel)}
</Styled.Label>
</Styled.FormElement>
@ -439,6 +437,7 @@ class ApplicationMenu extends BaseMenu {
handleChange={(e) => this.handleSelectChange('locale', e)}
value={settings.locale}
elementId="langSelector"
ariaLabel={intl.formatMessage(intlMessages.languageLabel)}
selectMessage={intl.formatMessage(intlMessages.languageOptionLabel)}
/>
</Styled.LocalesDropdownSelect>

View File

@ -54,7 +54,7 @@ class DataSaving extends BaseMenu {
{isVideoEnabled
? (
<Styled.Row>
<Styled.Col aria-hidden="true">
<Styled.Col aria-hidden>
<Styled.FormElement>
<Styled.Label>
{intl.formatMessage(intlMessages.webcamLabel)}
@ -69,7 +69,7 @@ class DataSaving extends BaseMenu {
defaultChecked={viewParticipantsWebcams}
onChange={() => this.handleToggle('viewParticipantsWebcams')}
ariaLabelledBy="webcamToggle"
ariaLabel={intl.formatMessage(intlMessages.webcamLabel)}
ariaLabel={`${intl.formatMessage(intlMessages.webcamLabel)} - ${displaySettingsStatus(viewParticipantsWebcams, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>
@ -80,7 +80,7 @@ class DataSaving extends BaseMenu {
{isScreenSharingEnabled
? (
<Styled.Row>
<Styled.Col aria-hidden="true">
<Styled.Col aria-hidden>
<Styled.FormElement>
<Styled.Label>
{intl.formatMessage(intlMessages.screenShareLabel)}
@ -95,7 +95,7 @@ class DataSaving extends BaseMenu {
defaultChecked={viewScreenshare}
onChange={() => this.handleToggle('viewScreenshare')}
ariaLabelledBy="screenShare"
ariaLabel={intl.formatMessage(intlMessages.screenShareLabel)}
ariaLabel={`${intl.formatMessage(intlMessages.screenShareLabel)} - ${displaySettingsStatus(viewScreenshare, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementRight>

View File

@ -77,7 +77,7 @@ class NotificationMenu extends BaseMenu {
</div>
<Styled.Form>
<Styled.Row>
<Styled.Row aria-hidden>
<Styled.Col />
<Styled.ColHeading>
{intl.formatMessage(intlMessages.audioAlertLabel)}
@ -90,7 +90,7 @@ class NotificationMenu extends BaseMenu {
{isChatEnabled() ? (
<Styled.Row>
<Styled.Col>
<Styled.Label>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.messagesLabel)}
</Styled.Label>
</Styled.Col>
@ -101,7 +101,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.chatAudioAlerts}
onChange={() => this.handleToggle('chatAudioAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.messagesLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.messagesLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)} - ${displaySettingsStatus(settings.chatAudioAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -113,7 +113,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.chatPushAlerts}
onChange={() => this.handleToggle('chatPushAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.messagesLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.messagesLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)} - ${displaySettingsStatus(settings.chatPushAlerts, true)}`}
showToggleLabel={showToggleLabel}
data-test="chatPopupAlertsBtn"
/>
@ -124,7 +124,7 @@ class NotificationMenu extends BaseMenu {
<Styled.Row>
<Styled.Col>
<Styled.Label>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.userJoinLabel)}
</Styled.Label>
</Styled.Col>
@ -135,7 +135,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.userJoinAudioAlerts}
onChange={() => this.handleToggle('userJoinAudioAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.userJoinLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.userJoinLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)} - ${displaySettingsStatus(settings.userJoinAudioAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -147,7 +147,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.userJoinPushAlerts}
onChange={() => this.handleToggle('userJoinPushAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.userJoinLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.userJoinLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)} - ${displaySettingsStatus(settings.userJoinPushAlerts, true)}`}
showToggleLabel={showToggleLabel}
data-test="userJoinPopupAlerts"
/>
@ -157,7 +157,7 @@ class NotificationMenu extends BaseMenu {
<Styled.Row>
<Styled.Col>
<Styled.Label>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.userLeaveLabel)}
</Styled.Label>
</Styled.Col>
@ -168,7 +168,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.userLeaveAudioAlerts}
onChange={() => this.handleToggle('userLeaveAudioAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.userLeaveLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.userLeaveLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)} - ${displaySettingsStatus(settings.userLeaveAudioAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -180,7 +180,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.userLeavePushAlerts}
onChange={() => this.handleToggle('userLeavePushAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.userLeaveLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.userLeaveLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)} - ${displaySettingsStatus(settings.userLeavePushAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -190,7 +190,7 @@ class NotificationMenu extends BaseMenu {
{isModerator && showGuestNotification ? (
<Styled.Row>
<Styled.Col>
<Styled.Label>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.guestWaitingLabel)}
</Styled.Label>
</Styled.Col>
@ -201,7 +201,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.guestWaitingAudioAlerts}
onChange={() => this.handleToggle('guestWaitingAudioAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.guestWaitingLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.guestWaitingLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)} - ${displaySettingsStatus(settings.guestWaitingAudioAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -213,7 +213,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.guestWaitingPushAlerts}
onChange={() => this.handleToggle('guestWaitingPushAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.guestWaitingLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.guestWaitingLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)} - ${displaySettingsStatus(settings.guestWaitingPushAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -224,7 +224,7 @@ class NotificationMenu extends BaseMenu {
{isModerator ? (
<Styled.Row>
<Styled.Col>
<Styled.Label>
<Styled.Label aria-hidden>
{intl.formatMessage(intlMessages.raiseHandLabel)}
</Styled.Label>
</Styled.Col>
@ -235,7 +235,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.raiseHandAudioAlerts}
onChange={() => this.handleToggle('raiseHandAudioAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.raiseHandLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.raiseHandLabel)} ${intl.formatMessage(intlMessages.audioAlertLabel)} - ${displaySettingsStatus(settings.raiseHandAudioAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>
@ -247,7 +247,7 @@ class NotificationMenu extends BaseMenu {
icons={false}
defaultChecked={settings.raiseHandPushAlerts}
onChange={() => this.handleToggle('raiseHandPushAlerts')}
ariaLabel={`${intl.formatMessage(intlMessages.raiseHandLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)}`}
ariaLabel={`${intl.formatMessage(intlMessages.raiseHandLabel)} ${intl.formatMessage(intlMessages.pushAlertLabel)} - ${displaySettingsStatus(settings.raiseHandPushAlerts, true)}`}
showToggleLabel={showToggleLabel}
/>
</Styled.FormElementCenter>

View File

@ -60,8 +60,8 @@ const sortUsersByUserId = (a, b) => {
};
const sortUsersByName = (a, b) => {
const aName = a.name ? a.name.toLowerCase() : '';
const bName = b.name ? b.name.toLowerCase() : '';
const aName = a.sortName || '';
const bName = b.sortName || '';
// Extending for sorting strings with non-ASCII characters
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#sorting_non-ascii_characters

View File

@ -235,6 +235,7 @@ class UserOptions extends PureComponent {
description: intl.formatMessage(intlMessages[isMeetingMuted ? 'unmuteAllDesc' : 'muteAllDesc']),
onClick: toggleMuteAllUsers,
icon: isMeetingMuted ? 'unmute' : 'mute',
dataTest: 'muteAll',
});
if (!isMeetingMuted) {
@ -244,6 +245,7 @@ class UserOptions extends PureComponent {
description: intl.formatMessage(intlMessages.muteAllExceptPresenterDesc),
onClick: toggleMuteAllUsersExceptPresenter,
icon: 'mute',
dataTest: 'muteAllExceptPresenter',
});
}

View File

@ -533,6 +533,7 @@ class VideoProvider extends Component {
}
const peer = new WebRtcPeer('sendonly', peerOptions);
peer.bbbVideoStream = bbbVideoStream;
this.webRtcPeers[stream] = peer;
peer.stream = stream;
peer.started = false;
@ -546,7 +547,7 @@ class VideoProvider extends Component {
peer.generateOffer().then((offer) => {
// Store the media stream if necessary. The scenario here is one where
// there is no preloaded stream stored.
if (bbbVideoStream == null) {
if (peer.bbbVideoStream == null) {
bbbVideoStream = new BBBVideoStream(peer.getLocalStream());
VideoPreviewService.storeStream(
MediaStreamUtils.extractDeviceIdFromStream(
@ -928,6 +929,11 @@ class VideoProvider extends Component {
peer.attached = true;
if (isLocal) {
if (peer.bbbVideoStream == null) {
this.handleVirtualBgError(new TypeError('Undefined media stream'));
return;
}
const deviceId = MediaStreamUtils.extractDeviceIdFromStream(
peer.bbbVideoStream.mediaStream,
'video',
@ -994,7 +1000,7 @@ class VideoProvider extends Component {
},
}, `Failed to restore virtual background after reentering the room: ${error.message}`);
notify(intl.formatMessage(intlMessages.virtualBgGenericError), 'error', 'video');
notify(intl.formatMessage(intlClientErrors.virtualBgGenericError), 'error', 'video');
}
createVideoTag(stream, video) {

View File

@ -86,7 +86,7 @@ export const sortLocalPresenterAlphabetical = (s1, s2) => mandatorySorting(s1, s
// 2 - add an entry to SORTING_METHODS, the key being the name to be used
// in settings.yml and the value object like the aforementioned
const MANDATORY_DATA_TYPES = {
userId: 1, stream: 1, name: 1, deviceId: 1, floor: 1, pin: 1,
userId: 1, stream: 1, name: 1, sortName: 1, deviceId: 1, floor: 1, pin: 1,
};
const SORTING_METHODS = Object.freeze({
// Default
@ -132,6 +132,7 @@ export const sortVideoStreams = (streams, mode) => {
stream: videoStream.stream,
userId: videoStream.userId,
name: videoStream.name,
sortName: videoStream.sortName,
floor: videoStream.floor,
pin: videoStream.pin,
}));

View File

@ -452,6 +452,14 @@ export default function Whiteboard(props) {
tldrawAPI?.setSetting('language', language);
}, [language]);
// Reset zoom to default when current presentation changes.
React.useEffect(() => {
if (isPresenter && slidePosition && tldrawAPI) {
const zoom = calculateZoom(slidePosition.width, slidePosition.height);
tldrawAPI.zoomTo(zoom);
}
}, [curPres?.id]);
const onMount = (app) => {
const menu = document.getElementById("TD-Styles")?.parentElement;
if (menu) {
@ -696,30 +704,44 @@ export default function Whiteboard(props) {
}
};
const onPaste = (e) => {
// disable file pasting
const clipboardData = e.clipboardData || window.clipboardData;
const { types } = clipboardData;
const hasFiles = types && types.indexOf && types.indexOf('Files') !== -1;
if (hasFiles) {
e.preventDefault();
e.stopPropagation();
}
};
const webcams = document.getElementById('cameraDock');
const dockPos = webcams?.getAttribute("data-position");
const editableWB = (
<Tldraw
key={`wb-${isRTL}-${dockPos}-${forcePanning}`}
document={doc}
// disable the ability to drag and drop files onto the whiteboard
// until we handle saving of assets in akka.
disableAssets={true}
// Disable automatic focus. Users were losing focus on shared notes
// and chat on presentation mount.
autofocus={false}
onMount={onMount}
showPages={false}
showZoom={false}
showUI={curPres ? (isPresenter || hasWBAccess) : true}
showMenu={curPres ? false : true}
showMultiplayerMenu={false}
readOnly={false}
onPatch={onPatch}
onUndo={onUndo}
onRedo={onRedo}
onCommand={onCommand}
/>
<div onPaste={onPaste}>
<Tldraw
key={`wb-${isRTL}-${dockPos}-${forcePanning}`}
document={doc}
// disable the ability to drag and drop files onto the whiteboard
// until we handle saving of assets in akka.
disableAssets={true}
// Disable automatic focus. Users were losing focus on shared notes
// and chat on presentation mount.
autofocus={false}
onMount={onMount}
showPages={false}
showZoom={false}
showUI={curPres ? (isPresenter || hasWBAccess) : true}
showMenu={curPres ? false : true}
showMultiplayerMenu={false}
readOnly={false}
onPatch={onPatch}
onUndo={onUndo}
onRedo={onRedo}
onCommand={onCommand}
/>
</div>
);
const readOnlyWB = (

View File

@ -47,6 +47,10 @@ export const safeMatch = (regex, content, defaultValue) => {
return content.match(regex) || defaultValue;
};
export const lowercaseTrim = (text) => {
return text.trim().toLowerCase();
}
export default {
capitalizeFirstLetter,
getDateString,
@ -55,4 +59,5 @@ export default {
unescapeHtml,
formatLocaleCode,
safeMatch,
lowercaseTrim,
};

View File

@ -2592,9 +2592,9 @@
}
},
"dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
@ -2602,22 +2602,22 @@
}
},
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
},
"domhandler": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz",
"integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
"requires": {
"domelementtype": "^2.2.0"
}
},
"domutils": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz",
"integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
@ -4140,11 +4140,6 @@
"object.assign": "^4.1.2"
}
},
"klona": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
"integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA=="
},
"kuler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
@ -5271,9 +5266,9 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nanoid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w=="
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
},
"natural-compare": {
"version": "1.4.0",
@ -5751,7 +5746,7 @@
"parse-srcset": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
"integrity": "sha1-8r0iH2zJcKk42IVWq8WJyqqiveE="
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
},
"path-exists": {
"version": "3.0.0",
@ -5820,11 +5815,11 @@
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
},
"postcss": {
"version": "8.4.12",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz",
"integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==",
"version": "8.4.20",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz",
"integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==",
"requires": {
"nanoid": "^3.3.1",
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
@ -6313,17 +6308,16 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sanitize-html": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.3.3.tgz",
"integrity": "sha512-DCFXPt7Di0c6JUnlT90eIgrjs6TsJl/8HYU3KLdmrVclFN4O0heTcVbJiMa23OKVr6aR051XYtsgd8EWwEBwUA==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.7.1.tgz",
"integrity": "sha512-oOpe8l4J8CaBk++2haoN5yNI5beekjuHv3JRPKUx/7h40Rdr85pemn4NkvUB3TcBP7yjat574sPlcMAyv4UQig==",
"requires": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"htmlparser2": "^6.0.0",
"is-plain-object": "^5.0.0",
"klona": "^2.0.3",
"parse-srcset": "^1.0.2",
"postcss": "^8.0.2"
"postcss": "^8.3.11"
},
"dependencies": {
"escape-string-regexp": {

2
bigbluebutton-html5/package.json Executable file → Normal file
View File

@ -79,7 +79,7 @@
"react-virtualized": "^9.22.3",
"reconnecting-websocket": "~v4.4.0",
"redis": "^3.1.2",
"sanitize-html": "2.3.3",
"sanitize-html": "2.7.1",
"scheduler": "^0.20.2",
"sdp-transform": "2.7.0",
"smile2emoji": "^2.8.0",

View File

@ -2,10 +2,11 @@
"app.home.greeting": "Ihre Präsentation beginnt in Kürze...",
"app.chat.submitLabel": "Nachricht senden",
"app.chat.loading": "Chatnachrichten geladen: {0}%",
"app.chat.errorMaxMessageLength": "Die Nachricht ist {0} Buchstabe(n) zu lang",
"app.chat.errorMaxMessageLength": "Die Nachricht ist zu lang. Sie darf maximal {0} Zeichen haben.",
"app.chat.disconnected": "Nicht verbunden, es können keine Nachrichten gesendet werden",
"app.chat.locked": "Der Chat ist gesperrt. Es können keine Nachrichten gesendet werden.",
"app.chat.inputLabel": "Chatnachricht eingeben für {0}",
"app.chat.emojiButtonLabel": "Emoji-Auswahl",
"app.chat.inputPlaceholder": "Nachricht {0}",
"app.chat.titlePublic": "Öffentlicher Chat",
"app.chat.titlePrivate": "Privater Chat mit {0}",
@ -21,6 +22,7 @@
"app.chat.offline": "Offline",
"app.chat.pollResult": "Umfrageergebnisse",
"app.chat.breakoutDurationUpdated": "Gruppenzeit beträgt jetzt {0} Minuten",
"app.chat.breakoutDurationUpdatedModerator": "Gruppenraumzeit beträgt nun {0} und eine Benachrichtigung wurde versendet.",
"app.chat.emptyLogLabel": "Chatprotokoll ist leer",
"app.chat.clearPublicChatMessage": "Der öffentliche Chatverlauf wurde durch einen Moderator gelöscht",
"app.chat.multi.typing": "Mehrere Teilnehmer tippen",
@ -28,6 +30,27 @@
"app.chat.two.typing": "{0} und {1} tippen",
"app.chat.copySuccess": "Chatprotokoll kopiert",
"app.chat.copyErr": "Kopieren des Chatprotokolls fehlgeschlagen",
"app.emojiPicker.search": "Suche",
"app.emojiPicker.notFound": "Kein Emoji gefunden",
"app.emojiPicker.skintext": "Wähle die standardmäßige Hautfarbe",
"app.emojiPicker.clear": "Leeren",
"app.emojiPicker.categories.label": "Emoji-Kategorien",
"app.emojiPicker.categories.people": "Menschen & Körper",
"app.emojiPicker.categories.nature": "Tiere & Natur",
"app.emojiPicker.categories.foods": "Essen & Trinken",
"app.emojiPicker.categories.places": "Reisen & Orte",
"app.emojiPicker.categories.activity": "Aktivitäten",
"app.emojiPicker.categories.objects": "Objekte",
"app.emojiPicker.categories.symbols": "Symbole",
"app.emojiPicker.categories.flags": "Flaggen",
"app.emojiPicker.categories.recent": "Häufig genutzt",
"app.emojiPicker.categories.search": "Suchergebnisse",
"app.emojiPicker.skintones.1": "Standardmäßige Hautfarbe",
"app.emojiPicker.skintones.2": "Heller Hautton",
"app.emojiPicker.skintones.3": "Mittelheller Hautton",
"app.emojiPicker.skintones.4": "Mittlerer Hautton",
"app.emojiPicker.skintones.5": "Mitteldunkler Hautton",
"app.emojiPicker.skintones.6": "Dunkler Hautton",
"app.captions.label": "Untertitel",
"app.captions.menu.close": "Schließen",
"app.captions.menu.start": "Start",
@ -53,12 +76,21 @@
"app.captions.speech.start": "Spracherkennung gestartet",
"app.captions.speech.stop": "Spracherkennung gestoppt",
"app.captions.speech.error": "Spracherkennung wurde aufgrund der Inkompatibilität des Browsers oder einer längeren Zeit der Stille angehalten",
"app.confirmation.skipConfirm": "Nicht nochmal fragen",
"app.confirmation.virtualBackground.title": "Neuen virtuellen Hintergrund starten",
"app.confirmation.virtualBackground.description": "{0} wird als virtueller Hintergrund hinzufügt. Frotzsetzen?",
"app.confirmationModal.yesLabel": "Ja",
"app.textInput.sendLabel": "Absenden",
"app.title.defaultViewLabel": "Standardpräsentation",
"app.notes.title": "Geteilte Notizen",
"app.notes.label": "Notizen",
"app.notes.hide": "Notizen verbergen",
"app.notes.locked": "Gesperrt",
"app.notes.disabled": "Im Medienbereich angeheftet",
"app.notes.notesDropdown.covertAndUpload": "Notizen in Präsentation umwandeln",
"app.notes.notesDropdown.pinNotes": "Notizen an das Whiteboard heften",
"app.notes.notesDropdown.unpinNotes": "Notizen loslösen",
"app.notes.notesDropdown.notesOptions": "Notizoptionen",
"app.pads.hint": "Esc drücken, um die Symbolleiste des Pads auszuwählen",
"app.user.activityCheck": "Teilnehmeraktivitätsprüfung",
"app.user.activityCheck.label": "Prüfen, ob der Teilnehmer noch in der Konferenz ist ({0})",
@ -170,7 +202,7 @@
"app.presentation.endSlideContent": "Ende des Folieninhalts",
"app.presentation.changedSlideContent": "Präsentation gewechselt zur Folie: {0}",
"app.presentation.emptySlideContent": "Kein Inhalt für aktuelle Folie",
"app.presentation.options.fullscreen": "Vollbild",
"app.presentation.options.fullscreen": "Vollbild-Präsentation",
"app.presentation.options.exitFullscreen": "Vollbilddarstellung beenden",
"app.presentation.options.minimize": "Minimieren",
"app.presentation.options.snapshot": "Aktuelle Folie herunterladen",
@ -203,7 +235,18 @@
"app.presentation.presentationToolbar.goToSlide": "Folie {0}",
"app.presentation.placeholder": "Es gibt derzeit keine aktive Präsentation",
"app.presentationUploder.title": "Präsentation",
"app.presentationUploder.message": "Als Präsentator können Präsentationen als Office-Dokumente oder PDF-Dateien hochgeladen werden. PDF-Dateien haben dabei die bessere Qualität. Bitte achten Sie darauf, dass eine Präsentation über das runde Auswahlfeld auf der rechten Seite ausgewählt ist.",
"app.presentationUploder.message": "Es können Office-Dokumente oder PDFs als Präsentation hochgeladen werden. Wir empfehlen PDF für beste Ergebnisse. Bitte sicherstellen, dass die richtige Präsentation mit runden Auswahlfeld auf der linken Seite ausgewählt ist.",
"app.presentationUploader.exportHint": "Wenn Sie \"An den Chat senden\" wählen, erhalten die Nutzer einen herunterladbaren Link mit Kommentaren im öffentlichen Chat.",
"app.presentationUploader.exportToastHeader": "Sende an Chat ({0} Element)",
"app.presentationUploader.exportToastHeaderPlural": "Sende an Chat ({0} Elemente)",
"app.presentationUploader.exporting": "Sende an Chat…",
"app.presentationUploader.sending": "Sende…",
"app.presentationUploader.collecting": "Extrahiere Folie {0} von {1}…",
"app.presentationUploader.processing": "Annotiere Folie {0} von {1}...",
"app.presentationUploader.sent": "Gesendet",
"app.presentationUploader.exportingTimeout": "Der Export dauert zu lange…",
"app.presentationUploader.export": "An Chat senden",
"app.presentationUploader.currentPresentationLabel": "Aktuelle Präsentation",
"app.presentationUploder.extraHint": "WICHTIG: Jede Datei darf {0} MB und {1} Seiten nicht überschreiten.",
"app.presentationUploder.uploadLabel": "Hochladen",
"app.presentationUploder.confirmLabel": "Bestätigen",
@ -214,6 +257,8 @@
"app.presentationUploder.dropzoneImagesLabel": "Bilder zum Hochladen hierhin ziehen",
"app.presentationUploder.browseFilesLabel": "oder nach Dateien suchen",
"app.presentationUploder.browseImagesLabel": "oder nach Bildern suchen/aufnehmen",
"app.presentationUploder.externalUploadTitle": "Füge Inhalte aus anderen Apps hinzu",
"app.presentationUploder.externalUploadLabel": "Dateien durchsuchen",
"app.presentationUploder.fileToUpload": "Bereit zum Hochladen...",
"app.presentationUploder.currentBadge": "Aktuell",
"app.presentationUploder.rejectedError": "Die ausgewählten Dateien wurden zurückgewiesen. Bitte die zulässigen Dateitypen prüfen.",
@ -230,14 +275,14 @@
"app.presentationUploder.conversion.generatedSlides": "Folien wurden generiert...",
"app.presentationUploder.conversion.generatingSvg": "SVG-Bilder werden generiert...",
"app.presentationUploder.conversion.pageCountExceeded": "Maximale Seitenanzahl von {0} Seiten wurde überschritten",
"app.presentationUploder.conversion.invalidMimeType": "Ungültiges Format entdeckt (Dateiendung={0}, Content-Type={1})",
"app.presentationUploder.conversion.conversionTimeout": "Folie {0} konnte nicht innerhalb von {1} Versuchen konvertiert werden.",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte eine PDF-Datei hochladen versuchen.",
"app.presentationUploder.conversion.officeDocConversionFailed": "Die Verarbeitung des Office-Dokuments ist fehlgeschlagen, bitte eine PDF-Datei hochladen.",
"app.presentationUploder.conversion.pdfHasBigPage": "Die PDF-Datei konnte nicht konvertiert werden, bitte versuchen Sie die Datei zu optimieren. Die maximale Seitenzahl beträgt {0} Seiten.",
"app.presentationUploder.conversion.timeout": "Ups, die Konvertierung hat zu lange gedauert",
"app.presentationUploder.conversion.pageCountFailed": "Die Seitenanzahl konnte nicht ermittelt werden.",
"app.presentationUploder.conversion.unsupportedDocument": "Dateityp wird nicht unterstützt",
"app.presentationUploder.isDownloadableLabel": "Das Herunterladen der Präsentation ist nicht zugelassen - hier das Herunterladen der Präsentation erlauben",
"app.presentationUploder.isNotDownloadableLabel": "Das Herunterladen der Präsentation ist zugelassen - hier das Herunterladen der Präsentation verbieten",
"app.presentationUploder.removePresentationLabel": "Präsentation entfernen",
"app.presentationUploder.setAsCurrentPresentation": "Diese Präsentation auswählen",
"app.presentationUploder.tableHeading.filename": "Dateiname",
@ -251,6 +296,10 @@
"app.presentationUploder.clearErrors": "Fehler löschen",
"app.presentationUploder.clearErrorsDesc": "Löscht fehlgeschlagene Präsentationsuploads",
"app.presentationUploder.uploadViewTitle": "Präsentation hochladen",
"app.poll.questionAndoptions.label" : "Zu zeigender Fragetext.\nA. Umfrageoption *\nB. Umfrageoption (optional)\nC. Abfrageoption (optional)\nD. Abfrageoption (optional)\nE. Abfrageoption (optional)",
"app.poll.customInput.label": "benutzerdefinierte Eingabe",
"app.poll.customInputInstructions.label": "Custom input is enabled write poll question and option(s) in given format or drag and drop a text file in same format.",
"app.poll.maxOptionsWarning.label": "Nur die ersten fünf Optionen können genutzt werden!",
"app.poll.pollPaneTitle": "Umfrage",
"app.poll.enableMultipleResponseLabel": "Mehrere Antworten pro Befragten zulassen?",
"app.poll.quickPollTitle": "Schnellumfrage",
@ -270,7 +319,7 @@
"app.poll.clickHereToSelect": "Zum Auswählen hier klicken",
"app.poll.question.label" : "Eine Frage stellen...",
"app.poll.optionalQuestion.label" : "Eine Frage stellen (optional)...",
"app.poll.userResponse.label" : "Teilnehmerantwort",
"app.poll.userResponse.label" : "Typed Response",
"app.poll.responseTypes.label" : "Antworttypen",
"app.poll.optionDelete.label" : "Löschen",
"app.poll.responseChoices.label" : "Antwortmöglichkeiten",
@ -311,8 +360,8 @@
"app.poll.liveResult.secretLabel": "Dies ist eine anonyme Umfrage. Individuelle Antworten werden nicht angezeigt.",
"app.poll.removePollOpt": "Entfernt die Option {0}",
"app.poll.emptyPollOpt": "Leer",
"app.polling.pollingTitle": "Umfrageoptionen",
"app.polling.pollQuestionTitle": "Frage der Umfrage",
"app.polling.pollingTitle": "Antworten",
"app.polling.pollQuestionTitle": "Umfrage",
"app.polling.submitLabel": "Absenden",
"app.polling.submitAriaLabel": "Umfrageantwort absenden",
"app.polling.responsePlaceholder": "Antwort eingeben",
@ -329,11 +378,11 @@
"app.muteWarning.disableMessage": "Hinweis auf Stummschaltung deaktiviert, bis die Stummschaltung aufgehoben wird",
"app.muteWarning.tooltip": "Klicken, um den Hinweis bis zur nächsten Aufhebung der Stummschaltung zu schließen",
"app.navBar.settingsDropdown.optionsLabel": "Optionen",
"app.navBar.settingsDropdown.fullscreenLabel": "Als Vollbild darstellen",
"app.navBar.settingsDropdown.fullscreenLabel": "Vollbild-Anwendung",
"app.navBar.settingsDropdown.settingsLabel": "Einstellungen öffnen",
"app.navBar.settingsDropdown.aboutLabel": "Versionsinfo",
"app.navBar.settingsDropdown.leaveSessionLabel": "Konferenz verlassen",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Vollbilddarstellung beenden",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Vollbild beenden",
"app.navBar.settingsDropdown.fullscreenDesc": "Einstellungsmenü als Vollbild darstellen",
"app.navBar.settingsDropdown.settingsDesc": "Basiseinstellungen ändern",
"app.navBar.settingsDropdown.aboutDesc": "Informationen über den Client anzeigen",
@ -342,6 +391,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "Tastenkombinationen",
"app.navBar.settingsDropdown.hotkeysDesc": "Liste verfügbarer Tastenkombinationen",
"app.navBar.settingsDropdown.helpLabel": "Hilfe",
"app.navBar.settingsDropdown.openAppLabel": "In \"BigBlueButton Tablet\"-App öffnen",
"app.navBar.settingsDropdown.helpDesc": "Link zu Videoanleitungen (öffnet neuen Browsertab)",
"app.navBar.settingsDropdown.endMeetingDesc": "Beendet die aktuelle Konferenz",
"app.navBar.settingsDropdown.endMeetingLabel": "Konferenz beenden",
@ -359,7 +409,7 @@
"app.endMeeting.description": "Mit dieser Aktion wird die Konferenz für {0} aktive(n) Teilnehmer beendet. Sind Sie sicher, dass Sie diese Konferenz beenden möchten?",
"app.endMeeting.noUserDescription": "Sind Sie sicher, dass Sie die Konferenz beenden wollen?",
"app.endMeeting.contentWarning": "Chatnachrichten, geteilte Notizen, Whiteboard-Inhalte und geteilte Dokumente dieser Konferenz sind nicht mehr direkt zugänglich",
"app.endMeeting.yesLabel": "Ja",
"app.endMeeting.yesLabel": "Sitzung für alle beenden",
"app.endMeeting.noLabel": "Nein",
"app.about.title": "Versionsinfo",
"app.about.version": "Clientversion:",
@ -369,6 +419,15 @@
"app.about.confirmDesc": "OK",
"app.about.dismissLabel": "Abbrechen",
"app.about.dismissDesc": "Informationen über Client schließen",
"app.mobileAppModal.title": "\"BigBlueButton Tablet\"-App öffnen",
"app.mobileAppModal.description": "Ist die \"BigBlueButton Tablet\"-App auf diesem Gerät installiert?",
"app.mobileAppModal.openApp": "Ja, App jetzt öffnen.",
"app.mobileAppModal.obtainUrlMsg": "Hole Meeting URL",
"app.mobileAppModal.obtainUrlErrorMsg": "Error trying to obtain meeting URL",
"app.mobileAppModal.openStore": "Nein, App-Store öffnen",
"app.mobileAppModal.dismissLabel": "Abbrechen",
"app.mobileAppModal.dismissDesc": "Schließen",
"app.mobileAppModal.userConnectedWithSameId": "The user {0} just connected using the same ID as you.",
"app.actionsBar.changeStatusLabel": "Status ändern",
"app.actionsBar.muteLabel": "Stummschalten",
"app.actionsBar.unmuteLabel": "Freischalten",
@ -379,10 +438,12 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "Schaltfläche zum Wiederherstellen der Präsentation, nachdem sie minimiert wurde",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "Präsentation minimieren",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "Schaltfläche zum Minimieren der Präsentation",
"app.actionsBar.actionsDropdown.layoutModal": "Layout Settings Modal",
"app.screenshare.screenShareLabel" : "Bildschirmfreigabe",
"app.submenu.application.applicationSectionTitle": "Anwendung",
"app.submenu.application.animationsLabel": "Animationen",
"app.submenu.application.audioFilterLabel": "Audiofilter für das Mikrofon",
"app.submenu.application.darkThemeLabel": "Dark-Mode",
"app.submenu.application.fontSizeControlLabel": "Schriftgröße",
"app.submenu.application.increaseFontBtnLabel": "Schriftgröße erhöhen",
"app.submenu.application.decreaseFontBtnLabel": "Schriftgröße verringern",
@ -392,6 +453,7 @@
"app.submenu.application.noLocaleOptionLabel": "Keine Sprachschemata verfügbar",
"app.submenu.application.paginationEnabledLabel": "Seitenweises Anzeigen von Webcams",
"app.submenu.application.layoutOptionLabel": "Layout-Modus",
"app.submenu.application.pushLayoutLabel": "Push layout",
"app.submenu.notification.SectionTitle": "Benachrichtigungen",
"app.submenu.notification.Desc": "Bitte definieren, wie und was mitgeteilt werden soll.",
"app.submenu.notification.audioAlertLabel": "Audio-Hinweise",
@ -420,7 +482,7 @@
"app.settings.main.save.label.description": "Speichert die Einstellungen und schließt das Einstellungsmenü",
"app.settings.dataSavingTab.label": "Datensparmodus",
"app.settings.dataSavingTab.webcam": "Webcams aktiviert",
"app.settings.dataSavingTab.screenShare": "Bildschirmfreigabe aktiviert",
"app.settings.dataSavingTab.screenShare": "Enable other participants desktop sharing",
"app.settings.dataSavingTab.description": "Um Datentransfervolumen zu sparen, können hier eingestellt werden, was angezeigt wird.",
"app.settings.save-notification.label": "Einstellungen wurden gespeichert",
"app.statusNotifier.lowerHands": "Hände senken",
@ -440,7 +502,6 @@
"app.actionsBar.actionsDropdown.presentationLabel": "Präsentationen verwalten",
"app.actionsBar.actionsDropdown.initPollLabel": "Eine Umfrage starten",
"app.actionsBar.actionsDropdown.desktopShareLabel": "Bildschirm freigeben",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "Bildschirmfreigabe gesperrt",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "Bildschirmfreigabe beenden",
"app.actionsBar.actionsDropdown.presentationDesc": "Präsentation hochladen",
"app.actionsBar.actionsDropdown.initPollDesc": "Eine Umfrage starten",
@ -457,6 +518,7 @@
"app.actionsBar.actionsDropdown.takePresenterDesc": "Sich selbst zum neuen Präsentator machen",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "Zufälligen Teilnehmer auswählen",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "Wählt einen Teilnehmer nach dem Zufallsprinzip aus",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "Layout verbreiten",
"app.actionsBar.emojiMenu.statusTriggerLabel": "Status setzen",
"app.actionsBar.emojiMenu.awayLabel": "Abwesend",
"app.actionsBar.emojiMenu.awayDesc": "Ihren Status auf abwesend setzen",
@ -496,6 +558,7 @@
"app.audioNotification.audioFailedError1012": "Verbindung beendet (Fehler 1012)",
"app.audioNotification.audioFailedMessage": "Audioverbindung konnte nicht hergestellt werden",
"app.audioNotification.mediaFailedMessage": "getUserMicMedia fehlgeschlagen, weil nur sichere Quellen erlaubt sind",
"app.audioNotification.deviceChangeFailed": "Wechsel des Audiogeräts gescheitert. Bite prüfen, ob das gewählte Gerät korrekt eingerichtet und verfügbar ist.",
"app.audioNotification.closeLabel": "Schließen",
"app.audioNotificaion.reconnectingAsListenOnly": "Mikrofone sind für Teilnehmer:innen gesperrt, in dieser Konferenz ist nur Zuhören möglich",
"app.breakoutJoinConfirmation.title": "Gruppenraum beitreten",
@ -509,6 +572,7 @@
"app.breakout.dropdown.manageDuration": "Dauer ändern",
"app.breakout.dropdown.destroyAll": "Gruppenräume beenden",
"app.breakout.dropdown.options": "Gruppenraumoptionen",
"app.breakout.dropdown.manageUsers": "Benutzer verwalten",
"app.calculatingBreakoutTimeRemaining": "Berechne verbleibende Zeit...",
"app.audioModal.ariaTitle": "Audioteilnahmedialog",
"app.audioModal.microphoneLabel": "Mit Mikrofon",
@ -555,6 +619,7 @@
"app.audio.changeAudioDevice": "Audiogerät wechseln",
"app.audio.enterSessionLabel": "An Konferenz teilnehmen",
"app.audio.playSoundLabel": "Testton abspielen",
"app.audio.stopAudioFeedback": "Audio Feedback stoppen",
"app.audio.backLabel": "Zurück",
"app.audio.loading": "Laden",
"app.audio.microphones": "Mikrofone",
@ -567,10 +632,32 @@
"app.audio.audioSettings.testSpeakerLabel": "Lautsprecher testen",
"app.audio.audioSettings.microphoneStreamLabel": "Lautstärke des Audiosignals",
"app.audio.audioSettings.retryLabel": "Erneut versuchen",
"app.audio.audioSettings.fallbackInputLabel": "Audioeingabe {0}",
"app.audio.audioSettings.fallbackOutputLabel": "Audioausgabe {0}",
"app.audio.audioSettings.defaultOutputDeviceLabel": "Standard",
"app.audio.audioSettings.findingDevicesLabel": "Suche Geräte…",
"app.audio.listenOnly.backLabel": "Zurück",
"app.audio.listenOnly.closeLabel": "Schließen",
"app.audio.permissionsOverlay.title": "Zugriff auf das Mikrofon erlauben",
"app.audio.permissionsOverlay.hint": "Zugriff auf die Mediengeräte muss im Browser erlaubt werden, um an einer Audiokonferenz teilnehmen zu können.",
"app.audio.captions.button.start": "Untertitel anzeigen",
"app.audio.captions.button.stop": "Untertitel verbergen",
"app.audio.captions.button.language": "Sprache",
"app.audio.captions.button.transcription": "Transkription",
"app.audio.captions.button.transcriptionSettings": "Transkriptions-Einstellungen",
"app.audio.captions.speech.title": "automatische Transkription",
"app.audio.captions.speech.disabled": "Deaktiviert",
"app.audio.captions.speech.unsupported": "Dieser Browser unterstützt keine Spracherkennung. Ihr Audio wird nicht untertitelt.",
"app.audio.captions.select.de-DE": "Deutsch",
"app.audio.captions.select.en-US": "Englisch",
"app.audio.captions.select.es-ES": "Spanisch",
"app.audio.captions.select.fr-FR": "Französisch",
"app.audio.captions.select.hi-ID": "Hindi",
"app.audio.captions.select.it-IT": "Italienisch",
"app.audio.captions.select.ja-JP": "Japanisch",
"app.audio.captions.select.pt-BR": "Portugiesisch",
"app.audio.captions.select.ru-RU": "Russisch",
"app.audio.captions.select.zh-CN": "Chinesisch/Mandarin",
"app.error.removed": "Sie wurden aus der Konferenz entfernt",
"app.error.meeting.ended": "Sie haben die Konferenz verlassen",
"app.meeting.logout.duplicateUserEjectReason": "Bereits anwesender Teilnehmer versucht erneut der Konferenz beizutreten",
@ -578,6 +665,7 @@
"app.meeting.logout.ejectedFromMeeting": "Sie wurden aus der Konferenz entfernt",
"app.meeting.logout.validateTokenFailedEjectReason": "Verifikation des Autorisierungsmerkmals fehlgeschlagen",
"app.meeting.logout.userInactivityEjectReason": "Teilnehmer war zu lange inaktiv",
"app.meeting.logout.maxParticipantsReached": "Die maximal zulässige Teilnehmerzahl für dieses Meeting ist erreicht",
"app.meeting-ended.rating.legendLabel": "Feedbackbewertung",
"app.meeting-ended.rating.starLabel": "Stern",
"app.modal.close": "Schließen",
@ -599,8 +687,11 @@
"app.error.403": "Sie wurden aus der Konferenz entfernt",
"app.error.404": "Nicht gefunden",
"app.error.408": "Authentifizierung fehlgeschlagen",
"app.error.409": "Konflikt",
"app.error.410": "Die Konferenz ist zu Ende",
"app.error.500": "Ups, irgendwas ist schiefgelaufen",
"app.error.503": "Verbindung wurde getrennt",
"app.error.disconnected.rejoin": "Bitte Seite neu laden um wieder beizutreten.",
"app.error.userLoggedOut": "Teilnehmer hat einen ungültigen Konferenz-Token, weil er sich ausgeloggt hat",
"app.error.ejectedUser": "Teilnehmer hat einen ungültigen Konferenz-Token, weil er gesperrt wurde",
"app.error.joinedAnotherWindow": "Diese Konferenz scheint in einem anderen Browserfenster geöffnet zu sein.",
@ -644,14 +735,18 @@
"app.userList.guest.privateMessageLabel": "Nachricht",
"app.userList.guest.acceptLabel": "Akzeptieren",
"app.userList.guest.denyLabel": "Ablehnen",
"app.userList.guest.feedbackMessage": "Action applied: ",
"app.user-info.title": "Verzeichnissuche",
"app.toast.breakoutRoomEnded": "Gruppenraum wurde geschlossen. Bitte treten der Audiokonferenz erneut beitreten.",
"app.toast.chat.public": "Neue öffentliche Chatnachricht",
"app.toast.chat.private": "Neue private Chatnachricht",
"app.toast.chat.system": "System",
"app.toast.chat.poll": "Umfrageergebnisse",
"app.toast.chat.pollClick": "Umfrageergebnisse wurden veröffentlicht. Hier klicken, um sie anzusehen.",
"app.toast.clearedEmoji.label": "Emojistatus zurückgesetzt",
"app.toast.setEmoji.label": "Emojistatus auf {0} gesetzt",
"app.toast.meetingMuteOn.label": "Alle Teilnehmer wurden stummgeschaltet",
"app.toast.meetingMuteOnViewers.label": "Alle Teilnehmer wurden stummgeschaltet",
"app.toast.meetingMuteOff.label": "Konferenz-Stummschaltung ausgeschaltet",
"app.toast.setEmoji.raiseHand": "Sie haben Ihre Hand gehoben",
"app.toast.setEmoji.lowerHand": "Ihre Hand wurde gesenkt",
@ -688,6 +783,38 @@
"app.shortcut-help.toggleFullscreenKey": "Enter",
"app.shortcut-help.nextSlideKey": "Pfeil rechts",
"app.shortcut-help.previousSlideKey": "Pfeil links",
"app.shortcut-help.select": "Werkzeug auswählen",
"app.shortcut-help.pencil": "Stift",
"app.shortcut-help.eraser": "Radierer",
"app.shortcut-help.rectangle": "Rechteck",
"app.shortcut-help.elipse": "Ellipse",
"app.shortcut-help.triangle": "Dreieck",
"app.shortcut-help.line": "Linie",
"app.shortcut-help.arrow": "Pfeil",
"app.shortcut-help.text": "Text",
"app.shortcut-help.note": "Haftnotiz",
"app.shortcut-help.general": "Allgemein",
"app.shortcut-help.presentation": "Präsentation",
"app.shortcut-help.whiteboard": "Whiteboard",
"app.shortcut-help.zoomIn": "Vergrößern",
"app.shortcut-help.zoomOut": "Verkleinern",
"app.shortcut-help.zoomFit": "Auf Bereich anpassen",
"app.shortcut-help.zoomSelect": "Zoom to Selection",
"app.shortcut-help.flipH": "Horizontal wenden",
"app.shortcut-help.flipV": "Vertikal spiegeln",
"app.shortcut-help.lock": "Sperren / Entsperren",
"app.shortcut-help.moveToFront": "Nach vone bringen",
"app.shortcut-help.moveToBack": "Nach hinten schieben",
"app.shortcut-help.moveForward": "Move Forward",
"app.shortcut-help.moveBackward": "Move Backward",
"app.shortcut-help.undo": "Rückgängig",
"app.shortcut-help.redo": "Wiederherstellen",
"app.shortcut-help.cut": "Ausschneiden",
"app.shortcut-help.copy": "Kopieren",
"app.shortcut-help.paste": "Einfügen",
"app.shortcut-help.selectAll": "Alles auswählen",
"app.shortcut-help.delete": "Löschen",
"app.shortcut-help.duplicate": "Duplizieren",
"app.lock-viewers.title": "Teilnehmerrechte einschränken",
"app.lock-viewers.description": "Diese Optionen ermöglichen es, bestimmte Funktionen für Teilnehmer einzuschränken.",
"app.lock-viewers.featuresLable": "Funktion",
@ -737,13 +864,19 @@
"app.connection-status.next": "Nächste Seite",
"app.connection-status.prev": "Vorherige Seite",
"app.learning-dashboard.label": "Lernanalyse-Dashboard",
"app.learning-dashboard.description": "Übersichtsseite mit Benutzeraktivitäten öffnen",
"app.learning-dashboard.description": "Dashboard mit Nutzeraktivitäten",
"app.learning-dashboard.clickHereToOpen": "Lernanalyse-Dashboard öffnen",
"app.recording.startTitle": "Aufzeichnung starten",
"app.recording.stopTitle": "Aufzeichnung pausieren",
"app.recording.resumeTitle": "Aufzeichnung fortsetzen",
"app.recording.startDescription": "Durch erneutes Drücken des Aufnahmeknopfs Aufnahme pausieren.",
"app.recording.stopDescription": "Aufnahme pausieren? Diese kann durch erneutes Drücken des Aufnahmeknopfs jederzeit fortgesetzt werden.",
"app.recording.notify.title": "Aufzeichnung hat begonnen",
"app.recording.notify.description": "A recording will be available based on the remainder of this session",
"app.recording.notify.continue": "Fortsetzen",
"app.recording.notify.leave": "Konferenz verlassen",
"app.recording.notify.continueLabel" : "Aufzeichnung akzeptieren und fortsetzen",
"app.recording.notify.leaveLabel" : "Aufzeichnung nicht akzeptieren und Konferenz verlassen",
"app.videoPreview.cameraLabel": "Kamera",
"app.videoPreview.profileLabel": "Qualität",
"app.videoPreview.quality.low": "Niedrige",
@ -760,13 +893,20 @@
"app.videoPreview.webcamOptionLabel": "Webcam auswählen",
"app.videoPreview.webcamPreviewLabel": "Webcamvorschau",
"app.videoPreview.webcamSettingsTitle": "Webcameinstellungen",
"app.videoPreview.webcamEffectsTitle": "Grafische Effekte für Webcam",
"app.videoPreview.webcamVirtualBackgroundLabel": "Einstellungen zum virtuellen Hintergrund",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "Dieses Gerät unterstützt keine virtuellen Hintergründe",
"app.videoPreview.webcamNotFoundLabel": "Keine Webcam gefunden",
"app.videoPreview.profileNotFoundLabel": "Keine unterstützten Kameraprofile",
"app.videoPreview.brightness": "Helligkeit",
"app.videoPreview.wholeImageBrightnessLabel": "Ganzes Bild",
"app.videoPreview.wholeImageBrightnessDesc": "Applies brightness to stream and background image",
"app.videoPreview.sliderDesc": "Helligkeitsstufen regeln",
"app.video.joinVideo": "Webcam freigeben",
"app.video.connecting": "Webcamfreigabe wird gestartet ...",
"app.video.leaveVideo": "Webcamfreigabe beenden",
"app.video.videoSettings": "Videoeinstellungen",
"app.video.visualEffects": "Grafische Effekte",
"app.video.advancedVideo": "Erweiterte Einstellungen öffnen",
"app.video.iceCandidateError": "Fehler beim Hinzufügen vom ice candidate",
"app.video.iceConnectionStateError": "Verbindungsfehler (Fehler 1107)",
@ -782,6 +922,7 @@
"app.video.notReadableError": "Konnte nicht auf die Webcam zugreifen. Bitte prüfen, dass kein anderes Programm auf die Webcam zugreift",
"app.video.timeoutError": "Der Browser hat nicht rechtzeitig reagiert.",
"app.video.genericError": "Ein unbekannter Fehler ist mit der Kamera aufgetreten (Fehler {0})",
"app.video.inactiveError": "Die Webcam stoppte unerwartet. Bitte die Browserbrechtigungen prüfen.",
"app.video.mediaTimedOutError": "Ihre Webcam-Freigabe wurde unterbrochen. Bitte erneut starten.",
"app.video.mediaFlowTimeout1020": "Verbindung zum Server konnte nicht hergestellt werden (Fehler 1020)",
"app.video.suggestWebcamLock": "Sperrung der Teilnehmerwebcams aktivieren?",
@ -804,8 +945,17 @@
"app.video.virtualBackground.board": "Tafel",
"app.video.virtualBackground.coffeeshop": "Café",
"app.video.virtualBackground.background": "Hintergrund",
"app.video.virtualBackground.backgroundWithIndex": "Hintergrund {0}",
"app.video.virtualBackground.custom": "Vom Gerät hochladen",
"app.video.virtualBackground.remove": "Hinzugefügtes Bild entfernen",
"app.video.virtualBackground.genericError": "Virtueller Hintergrund konnte nicht angewendet werden. Bitte erneut versuchen.",
"app.video.virtualBackground.camBgAriaDesc": "Setzt den virtuellen Hintergrund der Webcam auf {0}",
"app.video.virtualBackground.maximumFileSizeExceeded": "Maximale Dateigröße von {0} MB überschritten.",
"app.video.virtualBackground.typeNotAllowed": "Dateityp nicht erlaubt.",
"app.video.virtualBackground.errorOnRead": "Etwas ist beim Verarbeitung der Datei schiefgelaufen.",
"app.video.virtualBackground.uploaded": "Hochgeladen",
"app.video.virtualBackground.uploading": "Lade hoch…",
"app.video.virtualBackground.button.customDesc": "Fügt ein neues virtuelles Hintergrundbild hinzu.",
"app.video.camCapReached": "Sie können keine weiteren Kameras freigeben",
"app.video.meetingCamCapReached": "Konferenz hat die maximale Anzahl gleichzeitiger Kameras erreicht",
"app.video.dropZoneLabel": "Hier loslassen",
@ -826,6 +976,7 @@
"app.whiteboard.annotations.poll": "Umfrageergebnisse wurden veröffentlicht",
"app.whiteboard.annotations.pollResult": "Umfrageergebnis",
"app.whiteboard.annotations.noResponses": "Keine Antworten",
"app.whiteboard.annotations.notAllowed": "Keine Berechtigung für diese Änderung",
"app.whiteboard.toolbar.tools": "Werkzeuge",
"app.whiteboard.toolbar.tools.hand": "Verschieben",
"app.whiteboard.toolbar.tools.pencil": "Stift",
@ -852,6 +1003,7 @@
"app.whiteboard.toolbar.color.silver": "Silber",
"app.whiteboard.toolbar.undo": "Anmerkung zurücknehmen",
"app.whiteboard.toolbar.clear": "Alle Anmerkungen löschen",
"app.whiteboard.toolbar.clearConfirmation": "Sollen sämtliche Anmerkungen wirklich gelöscht werden?",
"app.whiteboard.toolbar.multiUserOn": "Mehrbenutzermodus starten",
"app.whiteboard.toolbar.multiUserOff": "Mehrbenutzermodus beenden",
"app.whiteboard.toolbar.palmRejectionOn": "Handballenerkennung einschalten",
@ -871,13 +1023,13 @@
"app.videoDock.webcamUnfocusDesc": "Ausgewählte Webcam auf Normalgröße verkleinern",
"app.videoDock.webcamPinLabel": "Anheften",
"app.videoDock.webcamPinDesc": "Ausgewählte Webcam anheften",
"app.videoDock.webcamFullscreenLabel": "Webcam als Vollbild",
"app.videoDock.webcamSqueezedButtonLabel": "Webcameinstellungen",
"app.videoDock.webcamUnpinLabel": "Lösen",
"app.videoDock.webcamUnpinLabelDisabled": "Nur Moderatoren können Teilnehmer lösen",
"app.videoDock.webcamUnpinDesc": "Ausgewählte Webcam lösen",
"app.videoDock.autoplayBlockedDesc": "Wir benötigen Ihre Zustimmung, um Ihnen die Webcams anderer Teilnehmer zu zeigen.",
"app.videoDock.autoplayAllowLabel": "Webcams zeigen",
"app.invitation.title": "Gruppenraumeinladung",
"app.invitation.confirm": "Einladen",
"app.createBreakoutRoom.title": "Gruppenräume",
"app.createBreakoutRoom.ariaTitle": "Gruppenräume verbergen",
"app.createBreakoutRoom.breakoutRoomLabel": "Gruppenräume {0}",
@ -909,6 +1061,8 @@
"app.createBreakoutRoom.addRoomTime": "Gruppenraumzeit erhöhen auf",
"app.createBreakoutRoom.addParticipantLabel": "+ Teilnehmer hinzufügen",
"app.createBreakoutRoom.freeJoin": "Den Teilnehmern erlauben, sich selbst einen Gruppenraum auszusuchen.",
"app.createBreakoutRoom.captureNotes": "Übertragen der gemeinsamen Notizen nach Beendigung der Arbeitsgruppenräume",
"app.createBreakoutRoom.captureSlides": "Whiteboard erfassen, wenn Breakout-Räume enden",
"app.createBreakoutRoom.leastOneWarnBreakout": "Jedem Gruppenraum muss wenigstens ein Teilnehmer zugeordnet sein.",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "Die Mindestdauer für einen Gruppenraum beträgt {0} Minuten.",
"app.createBreakoutRoom.modalDesc": "Tipp: Sie können die Teilnehmer per Drag-and-Drop einem bestimmten Gruppenraum zuweisen.",
@ -921,6 +1075,14 @@
"app.createBreakoutRoom.setTimeCancel": "Abbrechen",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "Die Dauer der Gruppenräume darf die verbleibende Zeit der Konferenz nicht überschreiten.",
"app.createBreakoutRoom.roomNameInputDesc": "Gruppenraumname ändern",
"app.createBreakoutRoom.movedUserLabel": "{0} in Raum {1} verschoben.",
"app.updateBreakoutRoom.modalDesc": "To update or invite a user, simply drag them into the desired room.",
"app.updateBreakoutRoom.cancelLabel": "Abbrechen",
"app.updateBreakoutRoom.title": "Gruppenräume aktualisieren",
"app.updateBreakoutRoom.confirm": "Anwenden",
"app.updateBreakoutRoom.userChangeRoomNotification": "Du wurdest in Raum {0} verschoben.",
"app.smartMediaShare.externalVideo": "Externe Video(s)",
"app.update.resetRoom": "Reset user room",
"app.externalVideo.start": "Neues Video teilen",
"app.externalVideo.title": "Externes Video teilen",
"app.externalVideo.input": "Externe Video-URL",
@ -946,6 +1108,15 @@
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(es wird deaktiviert, wenn der Webcambereich gezogen oder in der Größe verändert wird)",
"app.debugWindow.form.chatLoggerLabel": "Test der Chatprotokollierungsstufen",
"app.debugWindow.form.button.apply": "Anwenden",
"app.layout.modal.title": "Layouts",
"app.layout.modal.confirm": "Bestätigen",
"app.layout.modal.cancel": "Abbrechen",
"app.layout.modal.layoutLabel": "Layout auswählen",
"app.layout.modal.keepPushingLayoutLabel": "Layout bei allen anwenden",
"app.layout.modal.pushLayoutLabel": "An alle verteilen",
"app.layout.modal.layoutToastLabel": "Layouteinstellungen geändert",
"app.layout.modal.layoutSingular": "Layout",
"app.layout.modal.layoutBtnDesc": "Sets layout as selected option",
"app.layout.style.custom": "Benutzerdefiniertes Layout",
"app.layout.style.smart": "Automatisches Layout",
"app.layout.style.presentationFocus": "Präsentation im Zentrum",
@ -995,6 +1166,7 @@
"playback.player.thumbnails.wrapper.aria": "Vorschaubildbereich",
"playback.player.webcams.wrapper.aria": "Webcambereich",
"app.learningDashboard.dashboardTitle": "Lernanalyse-Dashboard",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "Konferenzdaten herunterladen",
"app.learningDashboard.lastUpdatedLabel": "Zuletzt aktualisiert um",
"app.learningDashboard.sessionDataDownloadedLabel": "Heruntergeladen!",
@ -1019,6 +1191,12 @@
"app.learningDashboard.userDetails.response": "Antwort",
"app.learningDashboard.userDetails.mostCommonAnswer": "Häufigste Antwort",
"app.learningDashboard.userDetails.anonymousAnswer": "Anonyme Umfrage",
"app.learningDashboard.userDetails.talkTime": "Sprechzeit",
"app.learningDashboard.userDetails.messages": "Nachrichten",
"app.learningDashboard.userDetails.emojis": "Emojis",
"app.learningDashboard.userDetails.raiseHands": "Hand heben",
"app.learningDashboard.userDetails.pollVotes": "Abstimmungen",
"app.learningDashboard.userDetails.onlineIndicator": "{0} online time",
"app.learningDashboard.usersTable.title": "Übersicht",
"app.learningDashboard.usersTable.colOnline": "Onlinezeit",
"app.learningDashboard.usersTable.colTalk": "Redezeit",
@ -1042,8 +1220,13 @@
"app.learningDashboard.pollsTable.anonymousRowName": "Anonym",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "Es wurden keine Umfragen erstellt",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "Sobald eine Umfrage an die Teilnehmer gesendet wurde, werden die Ergebnisse in dieser Liste angezeigt.",
"app.learningDashboard.pollsTable.answerTotal": "Insgesamt",
"app.learningDashboard.pollsTable.userLabel": "Nutzer:in",
"app.learningDashboard.statusTimelineTable.title": "Zeitverlauf",
"app.learningDashboard.statusTimelineTable.thumbnail": "Vorschaubild der Präsentation",
"app.learningDashboard.statusTimelineTable.presentation": "Präsentation",
"app.learningDashboard.statusTimelineTable.pageNumber": "Seite",
"app.learningDashboard.statusTimelineTable.setAt": "Set at",
"app.learningDashboard.errors.invalidToken": "Ungültiger Konferenz-Token",
"app.learningDashboard.errors.dataUnavailable": "Die Daten sind nicht mehr verfügbar",
"mobileApp.portals.list.empty.addFirstPortal.label": "Fügen Sie Ihr erstes Portal über die Schaltfläche oben hinzu,",
@ -1057,6 +1240,4 @@
"mobileApp.portals.addPortalPopup.validation.emptyFields": "Benötigte Felder",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "Name existiert bereits",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "Fehler beim Laden der Seite - URL und Netzwerkverbindung prüfen"
}

View File

@ -800,7 +800,7 @@
"app.shortcut-help.zoomOut": "Zoom Out",
"app.shortcut-help.zoomFit": "Zoom to Fit",
"app.shortcut-help.zoomSelect": "Zoom to Selection",
"app.shortcut-help.flipH": "Flip Horozontal",
"app.shortcut-help.flipH": "Flip Horizontal",
"app.shortcut-help.flipV": "Flip Vertical",
"app.shortcut-help.lock": "Lock / Unlock",
"app.shortcut-help.moveToFront": "Move to Front",
@ -900,7 +900,7 @@
"app.videoPreview.profileNotFoundLabel": "No supported camera profile",
"app.videoPreview.brightness": "Brightness",
"app.videoPreview.wholeImageBrightnessLabel": "Whole image",
"app.videoPreview.wholeImageBrightnessDesc": "Applies brighteness to stream and background image",
"app.videoPreview.wholeImageBrightnessDesc": "Applies brightness to stream and background image",
"app.videoPreview.sliderDesc": "Increase or decrease levels of brightness",
"app.video.joinVideo": "Share webcam",
"app.video.connecting": "Webcam sharing is starting ...",

View File

@ -2,10 +2,11 @@
"app.home.greeting": "プレゼンテーションはまもなく始まります…",
"app.chat.submitLabel": "メッセージを送信",
"app.chat.loading": "チャットメッセージをロードしています: {0}%",
"app.chat.errorMaxMessageLength": "このメッセージは文字数制限を {0} 文字超えています",
"app.chat.errorMaxMessageLength": "メッセージが長すぎます。最大の{0}文字を超えています",
"app.chat.disconnected": "通信が切断されたため、メッセージを送れません",
"app.chat.locked": "チャットがロック状態のため、メッセージを送れません",
"app.chat.inputLabel": "チャット {0} へメッセージ入力",
"app.chat.emojiButtonLabel": "絵文字選択",
"app.chat.inputPlaceholder": "メッセージ{0}",
"app.chat.titlePublic": "グループチャット",
"app.chat.titlePrivate": "{0} との非公開チャット",
@ -21,13 +22,35 @@
"app.chat.offline": "オフライン",
"app.chat.pollResult": "投票結果",
"app.chat.breakoutDurationUpdated": "小会議の時間は現在{0}分です",
"app.chat.breakoutDurationUpdatedModerator": "小会議の時間は現在{0}分です。通知が送られました。",
"app.chat.emptyLogLabel": "チャットログは空です",
"app.chat.clearPublicChatMessage": "チャット履歴はモデレーターにより消去されました",
"app.chat.clearPublicChatMessage": "チャット履歴は司会者により消去されました",
"app.chat.multi.typing": "複数の人が入力中",
"app.chat.one.typing": "{0}が入力中",
"app.chat.two.typing": "{0}と{1}が入力中",
"app.chat.copySuccess": "チャットの記録がコピーされました",
"app.chat.copyErr": "チャット記録のコピーに失敗しました",
"app.emojiPicker.search": "検索",
"app.emojiPicker.notFound": "絵文字が見つかりません",
"app.emojiPicker.skintext": "標準の肌の色を選択",
"app.emojiPicker.clear": "消す",
"app.emojiPicker.categories.label": "絵文字カテゴリー",
"app.emojiPicker.categories.people": "人物&からだ",
"app.emojiPicker.categories.nature": "動物&自然",
"app.emojiPicker.categories.foods": "食べ物&飲み物",
"app.emojiPicker.categories.places": "旅行&場所",
"app.emojiPicker.categories.activity": "活動",
"app.emojiPicker.categories.objects": "物体",
"app.emojiPicker.categories.symbols": "記号",
"app.emojiPicker.categories.flags": "旗",
"app.emojiPicker.categories.recent": "よく使われるもの",
"app.emojiPicker.categories.search": "検索結果",
"app.emojiPicker.skintones.1": "通常の肌の色",
"app.emojiPicker.skintones.2": "淡い肌色",
"app.emojiPicker.skintones.3": "少し淡い肌色",
"app.emojiPicker.skintones.4": "中間の肌色",
"app.emojiPicker.skintones.5": "少し濃い肌色",
"app.emojiPicker.skintones.6": "濃い肌色",
"app.captions.label": "字幕",
"app.captions.menu.close": "閉じる",
"app.captions.menu.start": "開始",
@ -53,12 +76,21 @@
"app.captions.speech.start": "音声認識を開始しました",
"app.captions.speech.stop": "音声認識が停止しました",
"app.captions.speech.error": "ブラウザが対応していないため、もしくは音声が一定時間停止したため、音声認識が停止しました",
"app.confirmation.skipConfirm": "次回から尋ねない",
"app.confirmation.virtualBackground.title": "新しいバーチャル背景を設定",
"app.confirmation.virtualBackground.description": "{0}個がバーチャル背景として追加されます。続けますか?",
"app.confirmationModal.yesLabel": "はい",
"app.textInput.sendLabel": "送る",
"app.title.defaultViewLabel": "既定のプレゼンテーションビュー",
"app.notes.title": "共有ノート",
"app.notes.label": "ノート",
"app.notes.hide": "ノートを隠す",
"app.notes.locked": "ロック",
"app.notes.disabled": "メディアエリアに固定",
"app.notes.notesDropdown.covertAndUpload": "ノートをプレゼンファイルに変換",
"app.notes.notesDropdown.pinNotes": "ホワイトボードにノートの内容を固定",
"app.notes.notesDropdown.unpinNotes": "ノートを外す",
"app.notes.notesDropdown.notesOptions": "ノートの操作",
"app.pads.hint": "パッドのツールバーにフォーカスするにはEscを押してください",
"app.user.activityCheck": "ユーザーアクティビティ確認",
"app.user.activityCheck.label": "会議({0})にユーザーがまだ参加しているか確認する",
@ -69,13 +101,13 @@
"app.userList.notesTitle": "メモ",
"app.userList.notesListItem.unreadContent": "共有ノートに新しいコンテンツがあります",
"app.userList.captionsTitle": "字幕",
"app.userList.presenter": "プレゼンター",
"app.userList.presenter": "発表者",
"app.userList.you": "自分",
"app.userList.locked": "ロック",
"app.userList.byModerator": "(Moderator)による",
"app.userList.label": "ユーザーリスト",
"app.userList.toggleCompactView.label": "コンパクトモードに切り替え",
"app.userList.moderator": "モデレーター",
"app.userList.moderator": "司会者",
"app.userList.mobile": "モバイル端末",
"app.userList.guest": "ゲスト",
"app.userList.sharingWebcam": "ウェブカメラ",
@ -95,35 +127,35 @@
"app.userList.menu.removeWhiteboardAccess.label": "ホワイトボードへの書き込み許可を取り消す",
"app.userList.menu.ejectUserCameras.label": "カメラを閉じる",
"app.userList.userAriaLabel": "{0} {1} {2} ステータス {3}",
"app.userList.menu.promoteUser.label": "モデレーターにする",
"app.userList.menu.demoteUser.label": "ビューアーに戻す",
"app.userList.menu.promoteUser.label": "司会者にする",
"app.userList.menu.demoteUser.label": "視聴者に戻す",
"app.userList.menu.unlockUser.label": "{0}を有効にする",
"app.userList.menu.lockUser.label": "{0}を無効にする",
"app.userList.menu.directoryLookup.label": "ディレクトリ検索",
"app.userList.menu.makePresenter.label": "プレゼンターにする",
"app.userList.menu.makePresenter.label": "発表者にする",
"app.userList.userOptions.manageUsersLabel": "ユーザー管理",
"app.userList.userOptions.muteAllLabel": "全ユーザーをミュート",
"app.userList.userOptions.muteAllDesc": "会議の全ユーザーをミュートする",
"app.userList.userOptions.clearAllLabel": "全てのステータスを消す",
"app.userList.userOptions.clearAllDesc": "ユーザーの全ステータスアイコンを消去する",
"app.userList.userOptions.muteAllExceptPresenterLabel": "プレゼンター以外全員ミュート",
"app.userList.userOptions.muteAllExceptPresenterDesc": "この会議のプレゼンター以外の全ユーザーをミュートにする",
"app.userList.userOptions.muteAllExceptPresenterLabel": "発表者以外全員ミュート",
"app.userList.userOptions.muteAllExceptPresenterDesc": "この会議の発表者以外の全ユーザーをミュートにする",
"app.userList.userOptions.unmuteAllLabel": "会議のミュートを解除",
"app.userList.userOptions.unmuteAllDesc": "会議のミュートを解除する",
"app.userList.userOptions.lockViewersLabel": "参加者の行動を制限",
"app.userList.userOptions.lockViewersLabel": "視聴者の行動を制限",
"app.userList.userOptions.lockViewersDesc": "会議の参加者が使用可能な特定の機能を無効にする",
"app.userList.userOptions.guestPolicyLabel": "ゲストポリシー",
"app.userList.userOptions.guestPolicyDesc": "会議のゲストポリシー設定を変更する",
"app.userList.userOptions.disableCam": "ビューアーのウェブカメラは利用できません",
"app.userList.userOptions.disableMic": "ビューアーのマイクは利用できません",
"app.userList.userOptions.disableCam": "視聴者のウェブカメラは利用できません",
"app.userList.userOptions.disableMic": "視聴者のマイクは利用できません",
"app.userList.userOptions.disablePrivChat": "非公開チャットは利用できません",
"app.userList.userOptions.disablePubChat": "グループチャットは利用できません",
"app.userList.userOptions.disableNotes": "共有ノートがロックされています",
"app.userList.userOptions.hideUserList": "ユーザーリストは視聴者に表示されません",
"app.userList.userOptions.webcamsOnlyForModerator": "モデレーターのみがビューアーのウェブカメラを見ることができます(ロック設定による)",
"app.userList.userOptions.webcamsOnlyForModerator": "司会者のみが視聴者のウェブカメラを見ることができます(ロック設定による)",
"app.userList.content.participants.options.clearedStatus": "全てのユーザーのステータスをクリアしました",
"app.userList.userOptions.enableCam": "ビューアーのウェブカメラが利用可能です",
"app.userList.userOptions.enableMic": "ビューアーのマイクが利用可能です",
"app.userList.userOptions.enableCam": "視聴者のウェブカメラが利用可能です",
"app.userList.userOptions.enableMic": "視聴者のマイクが利用可能です",
"app.userList.userOptions.enablePrivChat": "非公開チャットが利用可能です",
"app.userList.userOptions.enablePubChat": "グループチャットが利用可能です",
"app.userList.userOptions.enableNotes": "共有ノートが使用可能です",
@ -132,8 +164,8 @@
"app.userList.userOptions.savedNames.title": "{0}の会議の{1}のユーザーリスト",
"app.userList.userOptions.sortedFirstName.heading": "第一語でソート",
"app.userList.userOptions.sortedLastName.heading": "第二語でソート",
"app.userList.userOptions.hideViewersCursor": "ビューアーのカーソルがロックされました",
"app.userList.userOptions.showViewersCursor": "ビューアーのカーソルロックが解除されました",
"app.userList.userOptions.hideViewersCursor": "視聴者のカーソルがロックされました",
"app.userList.userOptions.showViewersCursor": "視聴者のカーソルロックが解除されました",
"app.media.label": "メディア",
"app.media.autoplayAlertDesc": "アクセス許可",
"app.media.screenshare.start": "画面共有を開始しました",
@ -141,10 +173,10 @@
"app.media.screenshare.endDueToDataSaving": "通信量抑制のため、画面共有を停止しました",
"app.media.screenshare.unavailable": "画面共有は利用できません",
"app.media.screenshare.notSupported": "画面共有はこのブラウザではサポートされていません。",
"app.media.screenshare.autoplayBlockedDesc": "プレゼンターの画面の共有を許可してください",
"app.media.screenshare.autoplayBlockedDesc": "発表者の画面の共有を許可してください",
"app.media.screenshare.autoplayAllowLabel": "共有画面を見る",
"app.screenshare.presenterLoadingLabel": "あなたの画面を共有しようとしています",
"app.screenshare.viewerLoadingLabel": "プレゼンターの画面を共有しようとしています",
"app.screenshare.viewerLoadingLabel": "発表者の画面を共有しようとしています",
"app.screenshare.presenterSharingLabel": "現在あなたの画面を共有中です",
"app.screenshare.screenshareFinalError": "コード{0} 画面をシェアできませんでした。",
"app.screenshare.screenshareRetryError": "コード{0} 画面シェアをもう一度試してください。",
@ -170,7 +202,7 @@
"app.presentation.endSlideContent": "スライドコンテンツ終了",
"app.presentation.changedSlideContent": "プレゼンテーションがスライド{0}に移動",
"app.presentation.emptySlideContent": "現在のスライドにはコンテンツはありません",
"app.presentation.options.fullscreen": "全画面表示",
"app.presentation.options.fullscreen": "プレゼンを全画面表示にする",
"app.presentation.options.exitFullscreen": "全画面表示解除",
"app.presentation.options.minimize": "最小化",
"app.presentation.options.snapshot": "現在のスライドのスナップショット",
@ -203,7 +235,18 @@
"app.presentation.presentationToolbar.goToSlide": "スライド {0}",
"app.presentation.placeholder": "現在アクティブなプレゼンテーションはありません",
"app.presentationUploder.title": "プレゼンテーション",
"app.presentationUploder.message": "プレゼンターはドキュメントをアップロードすることができます。お勧めのファイル形式はPDFです。右側のチェックボックスをクリックし、プレゼンテーションが選択されていることを確認してください。",
"app.presentationUploder.message": "発表者になるとオフィスドキュメントやPDFファイルをアップロードできるようになります。PDFファイルの使用がおすすめです。左側の丸いチェックボックスによってプレゼンファイルが選択されていることを確認してください。",
"app.presentationUploader.exportHint": "「チャットへ送信」を選ぶと、ホワイトボードへの書き込みをダウンロードするためのリンクが、公開チャットを通じてユーザーに提供されます。",
"app.presentationUploader.exportToastHeader": "チャットへ送信中 ({0} 個)",
"app.presentationUploader.exportToastHeaderPlural": "チャットへ送信中 ({0} 個)",
"app.presentationUploader.exporting": "チャットへ送信中",
"app.presentationUploader.sending": "送信中...",
"app.presentationUploader.collecting": "{1}枚のスライドのうち{0}番目を抽出中...",
"app.presentationUploader.processing": "{1}枚のスライドのうち{0}番目に書き込み中...",
"app.presentationUploader.sent": "送信終了",
"app.presentationUploader.exportingTimeout": "エクスポートに時間がかかりすぎています...",
"app.presentationUploader.export": "チャットへ送信",
"app.presentationUploader.currentPresentationLabel": "プレゼンテーションファイル",
"app.presentationUploder.extraHint": "重要:それぞれのファイルが{0}MB、{1}ページを超えないようにしてください。",
"app.presentationUploder.uploadLabel": "アップロード",
"app.presentationUploder.confirmLabel": "確認",
@ -214,8 +257,10 @@
"app.presentationUploder.dropzoneImagesLabel": "画像をここにドラッグしてアップロードする",
"app.presentationUploder.browseFilesLabel": "またはファイルを探す",
"app.presentationUploder.browseImagesLabel": "または画像を探す/キャプチャする",
"app.presentationUploder.externalUploadTitle": "外部アプリからプレゼン内容を追加",
"app.presentationUploder.externalUploadLabel": "ファイルを閲覧",
"app.presentationUploder.fileToUpload": "アップロード前...",
"app.presentationUploder.currentBadge": "現在",
"app.presentationUploder.currentBadge": "現在のプレゼンファイル",
"app.presentationUploder.rejectedError": "選択されたファイルはアップロードできません。ファイル形式を確認してください。",
"app.presentationUploder.connectionClosedError": "接続に問題があったため中断されました。もう一度試してみてください。",
"app.presentationUploder.upload.progress": "アップロード中({0}%)",
@ -230,14 +275,14 @@
"app.presentationUploder.conversion.generatedSlides": "スライド作成中…",
"app.presentationUploder.conversion.generatingSvg": "SVG画像作成中…",
"app.presentationUploder.conversion.pageCountExceeded": "ページ数の制限を超えました。最大は{0}ページです。",
"app.presentationUploder.conversion.invalidMimeType": "無効な形式です (拡張子={0}, タイプ={1})",
"app.presentationUploder.conversion.conversionTimeout": "スライド{0}は{1}回の試行で処理できませんでした。",
"app.presentationUploder.conversion.officeDocConversionInvalid": "Officeドキュメントが変換できませんでした。代わりにPDFをアップロードしてください。",
"app.presentationUploder.conversion.officeDocConversionFailed": "Officeドキュメントが変換できませんでした。代わりにPDFをアップロードしてください。",
"app.presentationUploder.conversion.pdfHasBigPage": "PDFファイルを変換できませんでした。最適化してみてください。最大は{0}ページです。",
"app.presentationUploder.conversion.timeout": "エラー:変換に時間がかかりすぎました",
"app.presentationUploder.conversion.pageCountFailed": "ページ数の判定に失敗しました。",
"app.presentationUploder.conversion.unsupportedDocument": "この拡張子のファイルはサポートされていません",
"app.presentationUploder.isDownloadableLabel": "プレゼン資料のダウンロードは現在許可されていません ー クリックすると許可されます",
"app.presentationUploder.isNotDownloadableLabel": "プレゼン資料のダウンロードが可能となっています ー クリックするとこれを禁止します",
"app.presentationUploder.removePresentationLabel": "プレゼンテーション削除",
"app.presentationUploder.setAsCurrentPresentation": "現在のプレゼンテーションを表示する",
"app.presentationUploder.tableHeading.filename": "ファイル名",
@ -251,6 +296,10 @@
"app.presentationUploder.clearErrors": "エラー消去",
"app.presentationUploder.clearErrorsDesc": "アップロードに失敗したプレゼン資料を消去します",
"app.presentationUploder.uploadViewTitle": "プレゼンテーションのアップロード",
"app.poll.questionAndoptions.label" : "表示される質問文\nA. 選択肢 *\nB. 選択肢 (オプション)\nC. 選択肢 (オプション)\nD. 選択肢 (オプション)\nE. 選択肢 (オプション)",
"app.poll.customInput.label": "自作の投票を入力",
"app.poll.customInputInstructions.label": "自作の投票を入力できます 質問文と選択肢を指定の形式で記述するか、同じ形式のテキストファイルをドラッグ&ドロップしてください。",
"app.poll.maxOptionsWarning.label": "最初の5つの選択肢しか使用されません!",
"app.poll.pollPaneTitle": "投票",
"app.poll.enableMultipleResponseLabel": "複数回答を許可しますか?",
"app.poll.quickPollTitle": "簡易投票",
@ -316,7 +365,7 @@
"app.polling.submitLabel": "送る",
"app.polling.submitAriaLabel": "回答を送る",
"app.polling.responsePlaceholder": "答えを入力",
"app.polling.responseSecret": "無記名投票 ー プレゼンターはあなたの答えを見ることができません。",
"app.polling.responseSecret": "無記名投票 ー 発表者はあなたの答えを見ることができません。",
"app.polling.responseNotSecret": "記名投票 ー プレゼンターはあなたの答えを見ることができます。",
"app.polling.pollAnswerLabel": "投票結果{0}",
"app.polling.pollAnswerDesc": "この選択肢で「{0}」に投票する",
@ -324,12 +373,12 @@
"app.downloadPresentationButton.label": "元のプレゼンテーションをダウンロード",
"app.connectingMessage": "接続中...",
"app.waitingMessage": "接続が切れました。 {0} 秒で再接続します ...",
"app.retryNow": "リトライ",
"app.retryNow": "すぐに再接続",
"app.muteWarning.label": "自分のミュートを解除するため{0}をクリック",
"app.muteWarning.disableMessage": "ミュートの警告は、次にアンミュートするまで無効になります",
"app.muteWarning.tooltip": "クリックすると閉じます。次にアンミュートするまで警告は無効になります。",
"app.navBar.settingsDropdown.optionsLabel": "オプション",
"app.navBar.settingsDropdown.fullscreenLabel": "全画面表示に切替",
"app.navBar.settingsDropdown.fullscreenLabel": "全画面表示",
"app.navBar.settingsDropdown.settingsLabel": "設定を開く",
"app.navBar.settingsDropdown.aboutLabel": "このソフトウェアについて",
"app.navBar.settingsDropdown.leaveSessionLabel": "退室する",
@ -342,6 +391,7 @@
"app.navBar.settingsDropdown.hotkeysLabel": "キーボードショートカット",
"app.navBar.settingsDropdown.hotkeysDesc": "利用可能なキーボードショートカット一覧",
"app.navBar.settingsDropdown.helpLabel": "ヘルプ",
"app.navBar.settingsDropdown.openAppLabel": "BigBlueButtonタブレットアプリを開く",
"app.navBar.settingsDropdown.helpDesc": "ユーザーをビデオチュートリアルへリンクする(新しいタブを開く)",
"app.navBar.settingsDropdown.endMeetingDesc": "現在の会議を終了する",
"app.navBar.settingsDropdown.endMeetingLabel": "会議を終了する",
@ -355,11 +405,11 @@
"app.navBar.emptyAudioBrdige": "アクティブなマイクがありません。この録画に音声を追加するには、マイクを使用してください。",
"app.leaveConfirmation.confirmLabel": "退室",
"app.leaveConfirmation.confirmDesc": "自分を会議からログアウトさせる",
"app.endMeeting.title": "終了 {0}",
"app.endMeeting.title": "終了します... {0}",
"app.endMeeting.description": "この操作により、セッションを終了します。まだ{0}人が参加していますが本当に構いませんか?",
"app.endMeeting.noUserDescription": "本当にこのセッションを終了しますか?",
"app.endMeeting.contentWarning": "このセッションのチャットメッセージ、共有メモ、ホワイトボードの書き込み、そして共有ドキュメントにはもうアクセスできなくなります",
"app.endMeeting.yesLabel": "はい",
"app.endMeeting.yesLabel": "ユーザー全員を退室させる",
"app.endMeeting.noLabel": "いいえ",
"app.about.title": "このソフトウェアについて",
"app.about.version": "ビルド番号:",
@ -369,6 +419,15 @@
"app.about.confirmDesc": "OK",
"app.about.dismissLabel": "キャンセル",
"app.about.dismissDesc": "クライアント情報を閉じる",
"app.mobileAppModal.title": "BigBlueButtonタブレットアプリを開く",
"app.mobileAppModal.description": "BigBlueButtonタブレットアプリはデバイスにインストールされていますか",
"app.mobileAppModal.openApp": "はい、すぐにアプリを開きます",
"app.mobileAppModal.obtainUrlMsg": "会議URLを取得しています",
"app.mobileAppModal.obtainUrlErrorMsg": "会議URLの取得エラー",
"app.mobileAppModal.openStore": "いいえ、アプリストアを開いてダウンロードします",
"app.mobileAppModal.dismissLabel": "キャンセル",
"app.mobileAppModal.dismissDesc": "閉じる",
"app.mobileAppModal.userConnectedWithSameId": "ユーザー{0}があなたと同じIDを使用して接続しました。",
"app.actionsBar.changeStatusLabel": "ステータス変更",
"app.actionsBar.muteLabel": "ミュート",
"app.actionsBar.unmuteLabel": "ミュート解除",
@ -379,19 +438,22 @@
"app.actionsBar.actionsDropdown.restorePresentationDesc": "最小化したプレゼンパネルを復活させるボタン",
"app.actionsBar.actionsDropdown.minimizePresentationLabel": "プレゼンパネルを最小化",
"app.actionsBar.actionsDropdown.minimizePresentationDesc": "プレゼンパネルを最小化するボタン",
"app.actionsBar.actionsDropdown.layoutModal": "レイアウト設定モーダル",
"app.screenshare.screenShareLabel" : "画面共有",
"app.submenu.application.applicationSectionTitle": "アプリケーション",
"app.submenu.application.animationsLabel": "アニメーション効果",
"app.submenu.application.audioFilterLabel": "マイク音声の自動補正",
"app.submenu.application.darkThemeLabel": "ダークモード",
"app.submenu.application.fontSizeControlLabel": "フォントサイズ",
"app.submenu.application.increaseFontBtnLabel": "アプリケーションのフォントサイズを大きくする",
"app.submenu.application.decreaseFontBtnLabel": "アプリケーションのフォントサイズを小さくする",
"app.submenu.application.currentSize": "現在{0}",
"app.submenu.application.currentSize": "現在 {0}",
"app.submenu.application.languageLabel": "使用言語",
"app.submenu.application.languageOptionLabel": "言語を選択",
"app.submenu.application.noLocaleOptionLabel": "アクティブなロケールがありません",
"app.submenu.application.paginationEnabledLabel": "ビデオのページ付け",
"app.submenu.application.layoutOptionLabel": "レイアウトのタイプ",
"app.submenu.application.pushLayoutLabel": "レイアウトを強制",
"app.submenu.notification.SectionTitle": "通知",
"app.submenu.notification.Desc": "何をどのように通知するかを設定できます。",
"app.submenu.notification.audioAlertLabel": "音声通知",
@ -402,7 +464,7 @@
"app.submenu.notification.guestWaitingLabel": "承認待ちのゲスト",
"app.submenu.audio.micSourceLabel": "マイクのソース",
"app.submenu.audio.speakerSourceLabel": "スピーカーのソース",
"app.submenu.audio.streamVolumeLabel": "音声ストリームの音量",
"app.submenu.audio.streamVolumeLabel": "入力音量",
"app.submenu.video.title": "ビデオ",
"app.submenu.video.videoSourceLabel": "ソースを表示",
"app.submenu.video.videoOptionLabel": "ソース表示を選択",
@ -419,8 +481,8 @@
"app.settings.main.save.label": "保存",
"app.settings.main.save.label.description": "変更を保存し設定メニューを閉じる",
"app.settings.dataSavingTab.label": "通信量抑制",
"app.settings.dataSavingTab.webcam": "ウェブカメラを有効にする",
"app.settings.dataSavingTab.screenShare": "デスクトップ共有を有効にする",
"app.settings.dataSavingTab.webcam": "参加者のウェブカメラを有効にする",
"app.settings.dataSavingTab.screenShare": "参加者の画面共有を有効にする",
"app.settings.dataSavingTab.description": "これらの設定により通信量を抑制できます。",
"app.settings.save-notification.label": "設定が保存されました",
"app.statusNotifier.lowerHands": "手をおろす",
@ -440,7 +502,6 @@
"app.actionsBar.actionsDropdown.presentationLabel": "プレゼン用ファイルの管理",
"app.actionsBar.actionsDropdown.initPollLabel": "投票を初期化",
"app.actionsBar.actionsDropdown.desktopShareLabel": "画面を共有",
"app.actionsBar.actionsDropdown.lockedDesktopShareLabel": "画面共有ロック",
"app.actionsBar.actionsDropdown.stopDesktopShareLabel": "画面共有をやめる",
"app.actionsBar.actionsDropdown.presentationDesc": "プレゼンテーションをアップロード",
"app.actionsBar.actionsDropdown.initPollDesc": "投票を初期化",
@ -453,10 +514,11 @@
"app.actionsBar.actionsDropdown.createBreakoutRoomDesc": "現在の会議を分割し、小会議を作成する",
"app.actionsBar.actionsDropdown.captionsLabel": "字幕を作成する",
"app.actionsBar.actionsDropdown.captionsDesc": "字幕を切り替える",
"app.actionsBar.actionsDropdown.takePresenter": "プレゼンターになる",
"app.actionsBar.actionsDropdown.takePresenterDesc": "自分を新しいプレゼンターとして割り当てる",
"app.actionsBar.actionsDropdown.takePresenter": "発表者になる",
"app.actionsBar.actionsDropdown.takePresenterDesc": "自分を新しい発表者として割り当てる",
"app.actionsBar.actionsDropdown.selectRandUserLabel": "参加者を無作為に指名",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "現参加者の中からランダムに一人あてます",
"app.actionsBar.actionsDropdown.selectRandUserDesc": "現視聴者の中からランダムに一人あてます",
"app.actionsBar.actionsDropdown.propagateLayoutLabel": "レイアウトを全体で統一",
"app.actionsBar.emojiMenu.statusTriggerLabel": "ステータス設定",
"app.actionsBar.emojiMenu.awayLabel": "不在",
"app.actionsBar.emojiMenu.awayDesc": "スタータスを「不在」にする",
@ -484,7 +546,7 @@
"app.actionsBar.captions.stop": "字幕を非表示",
"app.audioNotification.audioFailedError1001": "WebSocketが切断されました (error 1001)",
"app.audioNotification.audioFailedError1002": "WebSocket接続に失敗しました (error 1002)",
"app.audioNotification.audioFailedError1003": "このバージョンのブラウザはサポートされていません (error 1003)",
"app.audioNotification.audioFailedError1003": "このブラウザのバージョンはサポートされていません (error 1003)",
"app.audioNotification.audioFailedError1004": "呼び出しに失敗しました (理由={0}) (error 1004)",
"app.audioNotification.audioFailedError1005": "通話が予期せず終了しました (error 1005)",
"app.audioNotification.audioFailedError1006": "呼び出しがタイムアウトしました (error 1006)",
@ -496,8 +558,9 @@
"app.audioNotification.audioFailedError1012": "接続が閉じました (ICE error 1012)",
"app.audioNotification.audioFailedMessage": "音声接続に失敗しました",
"app.audioNotification.mediaFailedMessage": "getUserMicMediaは失敗しました。許可されているのは安全な発行元のみです。",
"app.audioNotification.deviceChangeFailed": "オーディオデバイスの変更に失敗しました。選択したデバイスが正しく設定されていて、使用可能であるかどうか確認してください。",
"app.audioNotification.closeLabel": "閉じる",
"app.audioNotificaion.reconnectingAsListenOnly": "参加者のマイクはロックされています。「聴講のみ」の接続を行います。",
"app.audioNotificaion.reconnectingAsListenOnly": "視聴者のマイクはロックされています。「聴講のみ」の接続を行います。",
"app.breakoutJoinConfirmation.title": "小会議室に参加",
"app.breakoutJoinConfirmation.message": "この部屋に入室しますか:",
"app.breakoutJoinConfirmation.confirmDesc": "小会議室に参加します",
@ -509,6 +572,7 @@
"app.breakout.dropdown.manageDuration": "利用時間を変更",
"app.breakout.dropdown.destroyAll": "小会議室を閉じる",
"app.breakout.dropdown.options": "小会議室の設定",
"app.breakout.dropdown.manageUsers": "ユーザーの管理",
"app.calculatingBreakoutTimeRemaining": "残り時間を計算中...",
"app.audioModal.ariaTitle": "音声参加モーダル",
"app.audioModal.microphoneLabel": "マイクをオン",
@ -517,7 +581,7 @@
"app.audioModal.listenOnlyDesc": "音声付きの会議に聴講のみで参加",
"app.audioModal.audioChoiceLabel": "音声参加の方法を選んでください",
"app.audioModal.iOSBrowser": "サポートされていない音声/ビデオ",
"app.audioModal.iOSErrorDescription": "iOSのChromeでは、音声、 ビデオは現在サポートされていません",
"app.audioModal.iOSErrorDescription": "iOSのChromeでは、音声、 ビデオは今のところサポートされていません",
"app.audioModal.iOSErrorRecommendation": "Safari iOSをお使いください",
"app.audioModal.audioChoiceDesc": "音声はどうしますか?",
"app.audioModal.unsupportedBrowserLabel": "サポート対象外のブラウザを使用している可能性があります。サポート対象の {0} または {1} をお使いください。",
@ -555,22 +619,45 @@
"app.audio.changeAudioDevice": "オーディオデバイスを変更",
"app.audio.enterSessionLabel": "セッションに参加",
"app.audio.playSoundLabel": "音声を再生",
"app.audio.stopAudioFeedback": "エコー再生を停止",
"app.audio.backLabel": "戻る",
"app.audio.loading": "ロード中",
"app.audio.microphones": "マイク",
"app.audio.speakers": "スピーカー",
"app.audio.noDeviceFound": "デバイスが見つかりません",
"app.audio.audioSettings.titleLabel": "音声設定を選択",
"app.audio.audioSettings.descriptionLabel": "マイク共有の許可を求めるダイアログがブラウザ内に現われますのでご了承ください。",
"app.audio.audioSettings.descriptionLabel": "マイク共有の許可を求めるダイアログがブラウザ内にあらわれますのでご注意ください。",
"app.audio.audioSettings.microphoneSourceLabel": "マイクのソース",
"app.audio.audioSettings.speakerSourceLabel": "スピーカーのソース",
"app.audio.audioSettings.testSpeakerLabel": "スピーカーをテストする",
"app.audio.audioSettings.microphoneStreamLabel": "音声ストリームの音量",
"app.audio.audioSettings.microphoneStreamLabel": "音声ストリームのボリューム",
"app.audio.audioSettings.retryLabel": "再試行",
"app.audio.audioSettings.fallbackInputLabel": "音声入力{0}",
"app.audio.audioSettings.fallbackOutputLabel": "音声出力{0}",
"app.audio.audioSettings.defaultOutputDeviceLabel": "標準",
"app.audio.audioSettings.findingDevicesLabel": "デバイスを探しています...",
"app.audio.listenOnly.backLabel": "戻る",
"app.audio.listenOnly.closeLabel": "閉じる",
"app.audio.permissionsOverlay.title": "デバイスのアクセスを許可する",
"app.audio.permissionsOverlay.hint": "会議に音声で参加するには、メディアデバイスの使用を許可する必要があります。",
"app.audio.permissionsOverlay.hint": "会議に音声で参加するには、メディアデバイスの使用を許可してもらう必要があります。",
"app.audio.captions.button.start": "字幕を開始",
"app.audio.captions.button.stop": "字幕を停止",
"app.audio.captions.button.language": "言語",
"app.audio.captions.button.transcription": "文字起こし",
"app.audio.captions.button.transcriptionSettings": "文字起こし設定",
"app.audio.captions.speech.title": "自動文字起こし",
"app.audio.captions.speech.disabled": "無効",
"app.audio.captions.speech.unsupported": "お使いのブラウザは音声認識をサポートしていません。音声は書き起こされません。",
"app.audio.captions.select.de-DE": "ドイツ語",
"app.audio.captions.select.en-US": "英語",
"app.audio.captions.select.es-ES": "スペイン語",
"app.audio.captions.select.fr-FR": "フランス語",
"app.audio.captions.select.hi-ID": "ヒンズー語",
"app.audio.captions.select.it-IT": "イタリア語",
"app.audio.captions.select.ja-JP": "日本語",
"app.audio.captions.select.pt-BR": "ポルトガル語",
"app.audio.captions.select.ru-RU": "ロシア語",
"app.audio.captions.select.zh-CN": "中国語",
"app.error.removed": "会議から退席しました",
"app.error.meeting.ended": "会議からログアウトしました",
"app.meeting.logout.duplicateUserEjectReason": "重複したユーザーが会議に参加しようとしています",
@ -578,6 +665,7 @@
"app.meeting.logout.ejectedFromMeeting": "会議から退室させられました",
"app.meeting.logout.validateTokenFailedEjectReason": "認証トークンが確認できませんでした",
"app.meeting.logout.userInactivityEjectReason": "一定時間操作がなかったため、接続が中断されました",
"app.meeting.logout.maxParticipantsReached": "この会議に参加可能な最大人数に達しました",
"app.meeting-ended.rating.legendLabel": "評価のフィードバック",
"app.meeting-ended.rating.starLabel": "スター",
"app.modal.close": "閉じる",
@ -585,7 +673,7 @@
"app.modal.confirm": "完了",
"app.modal.newTab": "(新しいタブを開く)",
"app.modal.confirm.description": "変更を保存してウィンドウを閉じる",
"app.modal.randomUser.noViewers.description": "指名する参加者がいません",
"app.modal.randomUser.noViewers.description": "指名する視聴者がいません",
"app.modal.randomUser.selected.description": "あなたが選ばれました",
"app.modal.randomUser.title": "選ばれた人",
"app.modal.randomUser.who": "誰が選ばれるでしょう..?",
@ -599,8 +687,11 @@
"app.error.403": "会議から退室させられました",
"app.error.404": "見つかりません",
"app.error.408": "認証に失敗しました",
"app.error.409": "競合",
"app.error.410": "会議は終了しました",
"app.error.500": "問題が起こりました",
"app.error.503": "接続が切断されました",
"app.error.disconnected.rejoin": "ページを再読み込みすると再び参加できます",
"app.error.userLoggedOut": "ログアウトしたため、セッショントークンが無効になっています",
"app.error.ejectedUser": "強制退出のため、セッショントークンが無効になっています",
"app.error.joinedAnotherWindow": "このセッションはブラウザの別ウィンドウで既に開かれているようです。",
@ -611,14 +702,14 @@
"app.error.fallback.presentation.reloadButton": "再読み込み",
"app.guest.waiting": "主催者の承認待ち",
"app.guest.errorSeeConsole": "エラー:詳細はコンソールに表示。",
"app.guest.noModeratorResponse": "モデレーターからの反応がありません。",
"app.guest.noModeratorResponse": "司会者からの反応がありません。",
"app.guest.noSessionToken": "セッションのトークンを受け取っていません。",
"app.guest.windowTitle": "BigBlueButton - ゲストロビー",
"app.guest.missingToken": "セッショントークンのないゲスト。",
"app.guest.missingSession": "セッションが不明のゲスト。",
"app.guest.missingMeeting": "会議は開かれていません。",
"app.guest.meetingEnded": "会議は終わりました。",
"app.guest.guestWait": "モデレーターが参加を許可するまでお待ちください。",
"app.guest.guestWait": "司会者が参加を許可するまでお待ちください。",
"app.guest.guestDeny": "会議への参加を拒否されたゲスト。",
"app.guest.seatWait": "会議への参加許可を待っているゲスト。",
"app.guest.allow": "参加を許可され会議へ向かうゲスト。",
@ -634,29 +725,33 @@
"app.userList.guest.allowEveryone": "全員を許可する",
"app.userList.guest.denyEveryone": "全員を拒否する",
"app.userList.guest.pendingUsers": "{0} 保留中のユーザー",
"app.userList.guest.noPendingUsers": "現在保留中のユーザーはいません",
"app.userList.guest.noPendingUsers": "今のところ保留中のユーザーはいません",
"app.userList.guest.pendingGuestUsers": "{0} 保留中のゲストユーザー",
"app.userList.guest.pendingGuestAlert": "はセッションに参加し、許可を待っています。",
"app.userList.guest.rememberChoice": "選択を記憶させる",
"app.userList.guest.emptyMessage": "現在のところメッセージはありません",
"app.userList.guest.emptyMessage": "のところメッセージはありません",
"app.userList.guest.inputPlaceholder": "ゲストロビーへのメッセージ",
"app.userList.guest.privateInputPlaceholder": "{0}へのメッセージ",
"app.userList.guest.privateMessageLabel": "メッセージ",
"app.userList.guest.acceptLabel": "承認",
"app.userList.guest.denyLabel": "却下",
"app.userList.guest.feedbackMessage": "操作完了",
"app.user-info.title": "ディレクトリ検索",
"app.toast.breakoutRoomEnded": "小会議が終了しました。もう一度音声参加を行ってください。",
"app.toast.chat.public": "新しいグループチャットメッセージ",
"app.toast.chat.private": "新しい非公開チャットメッセージ",
"app.toast.chat.system": "システム",
"app.toast.chat.poll": "投票結果",
"app.toast.chat.pollClick": "投票結果が公開されました。閲覧するにはここをクリックしてください。",
"app.toast.clearedEmoji.label": "絵文字ステータスがクリアされました",
"app.toast.setEmoji.label": "絵文字ステータスが {0} になりました",
"app.toast.meetingMuteOn.label": "全てのユーザーがミュートされました",
"app.toast.meetingMuteOnViewers.label": "すべての視聴者はミュートされました",
"app.toast.meetingMuteOff.label": "会議のミュートを解除しました",
"app.toast.setEmoji.raiseHand": "手を挙げました",
"app.toast.setEmoji.lowerHand": "手を下ろしました",
"app.toast.promotedLabel": "あなたはモデレーターになりました",
"app.toast.demotedLabel": "あなたはビューアーになりました",
"app.toast.promotedLabel": "あなたは司会者になりました",
"app.toast.demotedLabel": "あなたは視聴者になりました",
"app.notification.recordingStart": "録画が開始しました",
"app.notification.recordingStop": "このセッションは録画されていません",
"app.notification.recordingPaused": "このセッションはもう録画されていません",
@ -666,7 +761,7 @@
"app.submenu.notification.raiseHandLabel": "挙手",
"app.shortcut-help.title": "キーボードショートカット",
"app.shortcut-help.accessKeyNotAvailable": "使用できないアクセスキー",
"app.shortcut-help.comboLabel": "コンボ",
"app.shortcut-help.comboLabel": "キー",
"app.shortcut-help.functionLabel": "機能",
"app.shortcut-help.closeLabel": "閉じる",
"app.shortcut-help.closeDesc": "キーボードショートカットウィンドウを閉じる",
@ -680,30 +775,62 @@
"app.shortcut-help.raiseHand": "挙手状態の切り替え",
"app.shortcut-help.openDebugWindow": "デバッグウィンドウを開く",
"app.shortcut-help.openStatus": "ステータスメニューを開く",
"app.shortcut-help.togglePan": "パンツールを有効にする(プレゼンターのみ)",
"app.shortcut-help.toggleFullscreen": "フルスクリーン切り替え(プレゼンターのみ)",
"app.shortcut-help.nextSlideDesc": "次のスライド(プレゼンターのみ)",
"app.shortcut-help.previousSlideDesc": "前のスライド(プレゼンターのみ)",
"app.shortcut-help.togglePan": "パンツールを有効にする(発表者のみ)",
"app.shortcut-help.toggleFullscreen": "全画面表示切り替え(発表者のみ)",
"app.shortcut-help.nextSlideDesc": "次のスライド(発表者のみ)",
"app.shortcut-help.previousSlideDesc": "前のスライド(発表者のみ)",
"app.shortcut-help.togglePanKey": "スペース",
"app.shortcut-help.toggleFullscreenKey": "エンター",
"app.shortcut-help.nextSlideKey": "右矢印",
"app.shortcut-help.previousSlideKey": "左矢印",
"app.lock-viewers.title": "参加者の行動を制限",
"app.lock-viewers.description": "こちらの設定で参加者が使える機能を制限できます",
"app.shortcut-help.select": "ツールを選択",
"app.shortcut-help.pencil": "ペン",
"app.shortcut-help.eraser": "消しゴム",
"app.shortcut-help.rectangle": "四角",
"app.shortcut-help.elipse": "丸",
"app.shortcut-help.triangle": "三角",
"app.shortcut-help.line": "直線",
"app.shortcut-help.arrow": "矢印",
"app.shortcut-help.text": "文字ツール",
"app.shortcut-help.note": "ポストイット",
"app.shortcut-help.general": "一般",
"app.shortcut-help.presentation": "プレゼン",
"app.shortcut-help.whiteboard": "ホワイトボード",
"app.shortcut-help.zoomIn": "ズームイン",
"app.shortcut-help.zoomOut": "ズームアウト",
"app.shortcut-help.zoomFit": "ズーム解除",
"app.shortcut-help.zoomSelect": "選択領域をズーム",
"app.shortcut-help.flipH": "水平反転",
"app.shortcut-help.flipV": "垂直反転",
"app.shortcut-help.lock": "ロック / ロック解除",
"app.shortcut-help.moveToFront": "最前面に移動",
"app.shortcut-help.moveToBack": "最後面に移動",
"app.shortcut-help.moveForward": "前に移動",
"app.shortcut-help.moveBackward": "後ろに移動",
"app.shortcut-help.undo": "取り消し",
"app.shortcut-help.redo": "やり直し",
"app.shortcut-help.cut": "カット",
"app.shortcut-help.copy": "コピー",
"app.shortcut-help.paste": "ペースト",
"app.shortcut-help.selectAll": "全て選択",
"app.shortcut-help.delete": "削除",
"app.shortcut-help.duplicate": "複製",
"app.lock-viewers.title": "視聴者の行動を制限",
"app.lock-viewers.description": "こちらの設定で視聴者が使える機能を制限できます",
"app.lock-viewers.featuresLable": "機能",
"app.lock-viewers.lockStatusLabel": "ステータス",
"app.lock-viewers.webcamLabel": "ウェブカメラを共有する",
"app.lock-viewers.otherViewersWebcamLabel": "他ビューアーのウェブカメラを見る",
"app.lock-viewers.otherViewersWebcamLabel": "他の視聴者のウェブカメラを見る",
"app.lock-viewers.microphoneLable": "マイクを共有する",
"app.lock-viewers.PublicChatLabel": "公開チャットにメッセージを送信する",
"app.lock-viewers.PrivateChatLable": "プライベートチャットにメッセージを送信する",
"app.lock-viewers.notesLabel": "共有ノートを編集する",
"app.lock-viewers.userListLabel": "他の視聴者をユーザーリストに表示する",
"app.lock-viewers.ariaTitle": "参加者の行動制限設定モーダル",
"app.lock-viewers.ariaTitle": "視聴者の行動制限設定モーダル",
"app.lock-viewers.button.apply": "適用",
"app.lock-viewers.button.cancel": "キャンセル",
"app.lock-viewers.locked": "禁止",
"app.lock-viewers.hideViewersCursor": "他のビューアーのカーソルを表示する",
"app.lock-viewers.hideViewersCursor": "他の視聴者のカーソルを表示する",
"app.guest-policy.ariaTitle": "入室許可設定モーダル",
"app.guest-policy.title": "入室許可設定",
"app.guest-policy.description": "会議室の入室許可設定を変更する",
@ -714,7 +841,7 @@
"app.connection-status.ariaTitle": "接続状況モーダル",
"app.connection-status.title": "接続状況",
"app.connection-status.description": "ユーザーの接続状況の閲覧",
"app.connection-status.empty": "現在のところ接続の問題は報告されていません。",
"app.connection-status.empty": "のところ接続の問題は報告されていません。",
"app.connection-status.more": "更に見る",
"app.connection-status.copy": "データをコピー",
"app.connection-status.copied": "コピーしました!",
@ -737,13 +864,19 @@
"app.connection-status.next": "次のページ",
"app.connection-status.prev": "前のページ",
"app.learning-dashboard.label": "参加状況分析ボード",
"app.learning-dashboard.description": "ダッシュボードを開いてユーザーのアクティビティを見る",
"app.learning-dashboard.description": "ユーザーの活動状況を一覧",
"app.learning-dashboard.clickHereToOpen": "参加状況分析ボードを開く",
"app.recording.startTitle": "録画開始",
"app.recording.stopTitle": "録画一時停止",
"app.recording.resumeTitle": "録画再開",
"app.recording.startDescription": "録画ボタンをもう一度クリックすると録画が止まります。",
"app.recording.stopDescription": "録画を止めますか?再開するには、もう一度ボタンをクリックします。",
"app.recording.notify.title": "録画がスタートしました",
"app.recording.notify.description": "これ以降の会議の内容が録画され、視聴可能となります",
"app.recording.notify.continue": "続ける",
"app.recording.notify.leave": "セッションから退出",
"app.recording.notify.continueLabel" : "録画を認めて続ける",
"app.recording.notify.leaveLabel" : "録画を受け入れず会議を退出",
"app.videoPreview.cameraLabel": "カメラ",
"app.videoPreview.profileLabel": "画像品質",
"app.videoPreview.quality.low": "低",
@ -760,13 +893,20 @@
"app.videoPreview.webcamOptionLabel": "ウェブカメラを選択",
"app.videoPreview.webcamPreviewLabel": "ウェブカメラのプレビュー",
"app.videoPreview.webcamSettingsTitle": "ウェブカメラ設定",
"app.videoPreview.webcamEffectsTitle": "ウェブカメラの視覚効果",
"app.videoPreview.webcamVirtualBackgroundLabel": "バーチャル背景の設定",
"app.videoPreview.webcamVirtualBackgroundDisabledLabel": "このデバイスはバーチャル背景をサポートしていません",
"app.videoPreview.webcamNotFoundLabel": "ウェブカメラが見つかりません",
"app.videoPreview.profileNotFoundLabel": "利用可能なカメラプロフィールがありません",
"app.videoPreview.brightness": "明るさ",
"app.videoPreview.wholeImageBrightnessLabel": "画像全体",
"app.videoPreview.wholeImageBrightnessDesc": "背景を含めて画像全体に明るさ調整を適用",
"app.videoPreview.sliderDesc": "明るさのレベルを増減させる",
"app.video.joinVideo": "ウェブカメラを共有",
"app.video.connecting": "ウェブカメラの共有を始めます...",
"app.video.leaveVideo": "ウェブカメラの共有を終了",
"app.video.videoSettings": "ビデオの設定",
"app.video.visualEffects": "視覚効果",
"app.video.advancedVideo": "詳細設定を開く",
"app.video.iceCandidateError": "ICE候補の追加に失敗しました",
"app.video.iceConnectionStateError": "接続失敗 (ICE error 1107)",
@ -782,6 +922,7 @@
"app.video.notReadableError": "ウェブカメラの映像を取得できませんでした。他のプログラムがカメラを使ってないことを確認してください",
"app.video.timeoutError": "ブラウザが時間内に反応しませんでした",
"app.video.genericError": "デバイスに不明なエラーが起きました (Error {0})",
"app.video.inactiveError": "ウェブカメラが予期せず停止しました。ブラウザのカメラ使用許可を調べてください。",
"app.video.mediaTimedOutError": "ウェブカメラのストリームが中断しました。もう一度共有しなおしてください",
"app.video.mediaFlowTimeout1020": "映像がサーバに届いていません (error 1020)",
"app.video.suggestWebcamLock": "視聴者のカメラをロックしますか?",
@ -804,13 +945,22 @@
"app.video.virtualBackground.board": "ボード",
"app.video.virtualBackground.coffeeshop": "喫茶店",
"app.video.virtualBackground.background": "背景",
"app.video.virtualBackground.backgroundWithIndex": "背景 {0}",
"app.video.virtualBackground.custom": "コンピューターからアップロード",
"app.video.virtualBackground.remove": "追加した画像を削除",
"app.video.virtualBackground.genericError": "カメラエフェクトの適用に失敗しました。もう一度やってみてください。",
"app.video.virtualBackground.camBgAriaDesc": "ウェブカムのバーチャル背景を{0}に設定する",
"app.video.virtualBackground.maximumFileSizeExceeded": "ファイルサイズの上限 ({0}MB) を超えました",
"app.video.virtualBackground.typeNotAllowed": "ファイルのタイプが不適当です。",
"app.video.virtualBackground.errorOnRead": "ファイルの読み込みで不具合が発生しました。",
"app.video.virtualBackground.uploaded": "アップロード完了",
"app.video.virtualBackground.uploading": "アップロードしています...",
"app.video.virtualBackground.button.customDesc": "新しいバーチャル背景の画像を追加",
"app.video.camCapReached": "ウェブカメラはこれ以上シェアできません",
"app.video.meetingCamCapReached": "カメラの数が最大に達しています",
"app.video.dropZoneLabel": "ここにドロップ",
"app.fullscreenButton.label": "{0}を全画面に切り替える",
"app.fullscreenUndoButton.label": "{0}のフルスクリーン表示を解除",
"app.fullscreenUndoButton.label": "{0}の全画面表示を解除",
"app.switchButton.expandLabel": "画面共有のビデオを拡大",
"app.switchButton.shrinkLabel": "画面共有のビデオを縮小",
"app.sfu.mediaServerConnectionError2000": "メディアサーバーに接続できません (error 2000)",
@ -826,6 +976,7 @@
"app.whiteboard.annotations.poll": "投票結果が公開されました",
"app.whiteboard.annotations.pollResult": "投票結果",
"app.whiteboard.annotations.noResponses": "無回答",
"app.whiteboard.annotations.notAllowed": "この変更は許可されていません",
"app.whiteboard.toolbar.tools": "ツール",
"app.whiteboard.toolbar.tools.hand": "パン",
"app.whiteboard.toolbar.tools.pencil": "ペン",
@ -852,6 +1003,7 @@
"app.whiteboard.toolbar.color.silver": "グレー",
"app.whiteboard.toolbar.undo": "取り消す",
"app.whiteboard.toolbar.clear": "全て取り消す",
"app.whiteboard.toolbar.clearConfirmation": "本当に全ての書き込みを削除しますか?",
"app.whiteboard.toolbar.multiUserOn": "マルチユーザーモードにする",
"app.whiteboard.toolbar.multiUserOff": "マルチユーザーモードを解除",
"app.whiteboard.toolbar.palmRejectionOn": "手のひらの接触感知をオン",
@ -871,13 +1023,13 @@
"app.videoDock.webcamUnfocusDesc": "選択したウェブカメラのフォーカスを外す",
"app.videoDock.webcamPinLabel": "ピン止め",
"app.videoDock.webcamPinDesc": "選択したウェブカメラをピン止めする",
"app.videoDock.webcamFullscreenLabel": "ウェブカメラを全画面表示にする",
"app.videoDock.webcamSqueezedButtonLabel": "ウェブカメラの設定",
"app.videoDock.webcamUnpinLabel": "ピン止めを外す",
"app.videoDock.webcamUnpinLabelDisabled": "モデレーターだけがピン止めを外すことができます",
"app.videoDock.webcamUnpinLabelDisabled": "司会者だけがピン止めを外すことができます",
"app.videoDock.webcamUnpinDesc": "選択したウェブカメラのピン止めを外す",
"app.videoDock.autoplayBlockedDesc": "他の人のウェブカメラを表示するため、許可してください",
"app.videoDock.autoplayAllowLabel": "ウェブカメラ表示",
"app.invitation.title": "小会議室への招待",
"app.invitation.confirm": "招待",
"app.createBreakoutRoom.title": "小会議室",
"app.createBreakoutRoom.ariaTitle": "小会議室を隠す",
"app.createBreakoutRoom.breakoutRoomLabel": "小会議室 {0}",
@ -909,6 +1061,8 @@
"app.createBreakoutRoom.addRoomTime": "小会議室の制限時間を増やす",
"app.createBreakoutRoom.addParticipantLabel": "+参加者を追加",
"app.createBreakoutRoom.freeJoin": "ユーザーに参加する小会議室を選択させる",
"app.createBreakoutRoom.captureNotes": "小会議室終了時に共有ノートを保存",
"app.createBreakoutRoom.captureSlides": "小会議室終了時にホワイトボードを保存",
"app.createBreakoutRoom.leastOneWarnBreakout": "小会議室には最低1人のユーザーが必要です。",
"app.createBreakoutRoom.minimumDurationWarnBreakout": "小会議室の最小利用時間は{0}分です。",
"app.createBreakoutRoom.modalDesc": "ヒント:ユーザーの名前をドラッグ&ドロップして、特定の小会議室に割り当てることができます。",
@ -921,6 +1075,14 @@
"app.createBreakoutRoom.setTimeCancel": "キャンセル",
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "小会議室の会議時間は、親会議の残り時間を超えて設定できません",
"app.createBreakoutRoom.roomNameInputDesc": "小会議室の名前をアップデート",
"app.createBreakoutRoom.movedUserLabel": "{0}が会議室{1}に移されました",
"app.updateBreakoutRoom.modalDesc": "顔ぶれを新しくしたり新たなユーザーを招待したりするには、単純に名前を希望の会議室にドラッグしてください。",
"app.updateBreakoutRoom.cancelLabel": "キャンセル",
"app.updateBreakoutRoom.title": "小会議室を更新",
"app.updateBreakoutRoom.confirm": "適用",
"app.updateBreakoutRoom.userChangeRoomNotification": "会議室{0}に移されました。",
"app.smartMediaShare.externalVideo": "ネット動画",
"app.update.resetRoom": "会議室を元に戻す",
"app.externalVideo.start": "新しいビデオを共有",
"app.externalVideo.title": "インターネット上の動画を共有する",
"app.externalVideo.input": "動画のURL",
@ -946,6 +1108,15 @@
"app.debugWindow.form.enableAutoarrangeLayoutDescription": "(ウェブカメラエリアをドラッグしたりリサイズしたりすると無効となります)",
"app.debugWindow.form.chatLoggerLabel": "チャットロガーレベルをテストする",
"app.debugWindow.form.button.apply": "設定",
"app.layout.modal.title": "レイアウト",
"app.layout.modal.confirm": "確認",
"app.layout.modal.cancel": "キャンセル",
"app.layout.modal.layoutLabel": "レイアウトを選択してください",
"app.layout.modal.keepPushingLayoutLabel": "レイアウトを全体に強制する",
"app.layout.modal.pushLayoutLabel": "全員に強制",
"app.layout.modal.layoutToastLabel": "レイアウトの設定が変更されました",
"app.layout.modal.layoutSingular": "レイアウト",
"app.layout.modal.layoutBtnDesc": "レイアウトを選択したものに設定",
"app.layout.style.custom": "カスタム",
"app.layout.style.smart": "スマートレイアウト",
"app.layout.style.presentationFocus": "プレゼンにフォーカス",
@ -969,7 +1140,7 @@
"playback.player.about.modal.shortcuts.title": "ショートカット",
"playback.player.about.modal.shortcuts.alt": "Alt",
"playback.player.about.modal.shortcuts.shift": "Shift",
"playback.player.about.modal.shortcuts.fullscreen": "フルスクリーン切り替え",
"playback.player.about.modal.shortcuts.fullscreen": "全画面表示切り替え",
"playback.player.about.modal.shortcuts.play": "再生/ポーズ",
"playback.player.about.modal.shortcuts.section": "サイドパネル表示の切り替え",
"playback.player.about.modal.shortcuts.seek.backward": "前を検索",
@ -995,6 +1166,7 @@
"playback.player.thumbnails.wrapper.aria": "サムネイルエリア",
"playback.player.webcams.wrapper.aria": "ウェブカムエリア",
"app.learningDashboard.dashboardTitle": "参加状況分析ボード",
"app.learningDashboard.bigbluebuttonTitle": "BigBlueButton",
"app.learningDashboard.downloadSessionDataLabel": "セッションのデータをダウンロード",
"app.learningDashboard.lastUpdatedLabel": "最後のアップデート",
"app.learningDashboard.sessionDataDownloadedLabel": "ダウンロードされました!",
@ -1019,6 +1191,12 @@
"app.learningDashboard.userDetails.response": "回答",
"app.learningDashboard.userDetails.mostCommonAnswer": "最も多かった回答",
"app.learningDashboard.userDetails.anonymousAnswer": "匿名投票",
"app.learningDashboard.userDetails.talkTime": "会話時間",
"app.learningDashboard.userDetails.messages": "メッセージ",
"app.learningDashboard.userDetails.emojis": "絵文字",
"app.learningDashboard.userDetails.raiseHands": "挙手",
"app.learningDashboard.userDetails.pollVotes": "投票",
"app.learningDashboard.userDetails.onlineIndicator": "{0} のオンライン時間",
"app.learningDashboard.usersTable.title": "概要",
"app.learningDashboard.usersTable.colOnline": "オンライン時間",
"app.learningDashboard.usersTable.colTalk": "会話時間",
@ -1032,7 +1210,7 @@
"app.learningDashboard.usersTable.userStatusOffline": "オフライン",
"app.learningDashboard.usersTable.noUsers": "まだユーザーはいません",
"app.learningDashboard.usersTable.name": "名前",
"app.learningDashboard.usersTable.moderator": "モデレーター",
"app.learningDashboard.usersTable.moderator": "司会者",
"app.learningDashboard.usersTable.pollVotes": "得票",
"app.learningDashboard.usersTable.join": "参加",
"app.learningDashboard.usersTable.left": "退室",
@ -1041,9 +1219,14 @@
"app.learningDashboard.pollsTable.anonymousAnswer": "匿名投票(回答は最終行)",
"app.learningDashboard.pollsTable.anonymousRowName": "匿名",
"app.learningDashboard.pollsTable.noPollsCreatedHeading": "投票は行われていません",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "投票が行われれば、ここに結果が表示されます",
"app.learningDashboard.pollsTable.noPollsCreatedMessage": "投票が行われると、ここに結果が表示されます",
"app.learningDashboard.pollsTable.answerTotal": "計",
"app.learningDashboard.pollsTable.userLabel": "ユーザー",
"app.learningDashboard.statusTimelineTable.title": "タイムライン",
"app.learningDashboard.statusTimelineTable.thumbnail": "プレゼンのサムネール",
"app.learningDashboard.statusTimelineTable.presentation": "プレゼン",
"app.learningDashboard.statusTimelineTable.pageNumber": "ページ",
"app.learningDashboard.statusTimelineTable.setAt": "セット時刻",
"app.learningDashboard.errors.invalidToken": "セッショントークンが無効です",
"app.learningDashboard.errors.dataUnavailable": "データはもう閲覧できません",
"mobileApp.portals.list.empty.addFirstPortal.label": "上のボタンで自分のポータルサイトを追加するか、",
@ -1057,6 +1240,4 @@
"mobileApp.portals.addPortalPopup.validation.emptyFields": "必須項目",
"mobileApp.portals.addPortalPopup.validation.portalNameAlreadyExists": "名前が既に使用されています",
"mobileApp.portals.addPortalPopup.validation.urlInvalid": "ウェブページのアクセスに失敗しましたーURLとネットワーク接続を確認してください"
}

View File

@ -12,7 +12,8 @@ class Audio extends Page {
const { autoJoinAudioModal, listenOnlyCallTimeout } = this.settings;
if (!autoJoinAudioModal) await this.waitAndClick(e.joinAudio);
await this.waitAndClick(e.listenOnlyButton);
await this.wasRemoved(e.establishingAudioLabel);
await this.waitForSelector(e.establishingAudioLabel);
await this.wasRemoved(e.establishingAudioLabel, ELEMENT_WAIT_LONGER_TIME);
await this.waitForSelector(e.leaveListenOnly, listenOnlyCallTimeout);
await this.waitAndClick(e.audioDropdownMenu);
await this.hasElement(e.leaveAudio);

View File

@ -3,7 +3,6 @@ const { Create } = require('./create');
const { Join } = require('./join');
test.describe.parallel('Breakout', () => {
test.describe.parallel('Creating', () => {
test('Create Breakout room @ci', async ({ browser, context, page }) => {
const create = new Create(browser, context);
@ -39,7 +38,7 @@ test.describe.parallel('Breakout', () => {
const create = new Create(browser, context);
await create.initPages(page);
await create.dragDropUserInRoom();
});
});
});
test.describe.parallel('After creating', () => {

View File

@ -50,7 +50,7 @@ class Create extends MultiUsers {
await this.modPage.waitAndClick(e.increaseBreakoutTime);
await this.modPage.waitAndClick(e.modalConfirmButton, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.breakoutRoomsItem);
await this.modPage.hasText(e.breakoutRemainingTime, /15:[0-5][0-9]/);
await this.modPage.hasText(e.breakoutRemainingTime, /15:[0-5][0-9]/, ELEMENT_WAIT_LONGER_TIME);
}
async changeRoomsName() {
@ -87,7 +87,7 @@ class Create extends MultiUsers {
//testing no user assigned
await this.modPage.waitAndClick(e.modalConfirmButton);
await this.modPage.hasElement(e.warningNoUserAssigned);
//await this.modPage.hasElementDisabled(e.modalConfirmButton);
const modalConfirmButton = await this.modPage.getLocator(e.modalConfirmButton);
await expect(modalConfirmButton, 'Getting error when trying to create a breakout room without designating any user.').toBeDisabled();

View File

@ -1,9 +1,10 @@
const { Create } = require('./create');
const utilScreenShare = require('../screenshare/util');
const e = require('../core/elements');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_TIME } = require('../core/constants');
const { getSettings } = require('../core/settings');
const { expect } = require('@playwright/test');
const { sleep } = require('../core/helpers');
class Join extends Create {
constructor(browser, context) {
@ -109,7 +110,7 @@ class Join extends Create {
await this.modPage.waitAndClick(e.sendButtonDurationTime);
await this.modPage.hasText(e.breakoutRemainingTime, /[11-12]:[0-5][0-9]/);
await breakoutUserPage.hasText(e.timeRemaining,/[11-12]:[0-5][0-9]/);
await breakoutUserPage.hasText(e.timeRemaining, /[11-12]:[0-5][0-9]/);
}
async endAllBreakoutRooms() {
@ -133,8 +134,8 @@ class Join extends Create {
await this.modPage.waitAndClick(e.modalConfirmButton);
await this.userPage.waitForSelector(e.modalConfirmButton);
await expect(breakoutUserPage.page.isClosed(), "Previous breakout room page did not close!").toBeTruthy();
await breakoutUserPage.hasElement(e.errorScreenMessage);
await breakoutUserPage.hasText(e.errorScreenMessage, e.error403removedLabel);
await this.userPage.waitAndClick(e.modalConfirmButton);
await this.modPage.hasText(e.userNameBreakoutRoom2, /Attendee/);

View File

@ -201,7 +201,8 @@ exports.pollingContainer = 'div[data-test="pollingContainer"]';
exports.pollLetterAlternatives = 'button[data-test="pollLetterAlternatives"]';
exports.pollOptionItem = 'input[data-test="pollOptionItem"]';
exports.anonymousPoll = 'input[data-test="anonymousPollBtn"]';
exports.publishPollingLabel = 'button[data-test="publishPollingLabel"]';
const pollAnswerOptionBtn = 'button[data-test="publishPollingLabel"]';
exports.publishPollingLabel = pollAnswerOptionBtn;
exports.pollAnswerOptionBtn = 'button[data-test="pollAnswerOption"]';
exports.receivedAnswer = 'td[data-test="receivedAnswer"]';
exports.quickPoll = 'button[data-test="quickPollBtn"]';
@ -228,8 +229,8 @@ exports.answer2 = 'div[data-test="numberOfVotes"]>>nth=1';
exports.errorNoValueInput = 'div[data-test="errorNoValueInput"]';
exports.smartSlides1 = 'smartSlidesPresentation.pdf';
exports.responsePollQuestion = 'div[data-test="pollQuestion"]';
exports.pollAnswerOptionBtn = 'button[data-test="pollAnswerOption"]>>nth=0';
exports.checkboxInput = 'div[data-test="optionsAnswers"] > div';
exports.firstPollAnswerOptionBtn = `${pollAnswerOptionBtn}>>nth=0`;
exports.checkboxInput = `${pollAnswerOptionBtn} > div`;
// Presentation
exports.currentSlideImg = 'img[id="slide-background-shape_image"]';
exports.uploadPresentationFileName = 'uploadTest.png';
@ -254,7 +255,6 @@ exports.presentationContainer = 'div[data-test="presentationContainer"]';
exports.minimizePresentation = 'button[data-test="minimizePresentation"]';
exports.restorePresentation = 'button[data-test="restorePresentation"]';
exports.shareExternalVideoBtn = 'li[data-test="shareExternalVideo"]';
exports.externalVideoModalHeader = 'header[data-test="videoModalHeader"]';
exports.videoModalInput = 'input[id="video-modal-input"]';
exports.startShareVideoBtn = 'button[data-test="startNewVideo"]';
exports.videoPlayer = 'div[data-test="videoPlayer"]';
@ -307,7 +307,7 @@ exports.copyStats = 'span[data-test="copyStats"]';
exports.dataSavingScreenshare = 'input[data-test="dataSavingScreenshare"]';
exports.screenshareLocked = 'button[data-test="screenshareLocked"]';
exports.connectionStatusItemEmpty = 'div[data-test="connectionStatusItemEmpty"]';
exports.connectionStatusTab2 = 'div[data-tab="2"]';
exports.connectionStatusTab2 = 'li[id="react-tabs-2"]';
exports.connectionStatusItemUser = 'div[data-test="connectionStatusItemUser"]';
exports.connectionStatusLinkToSettings = `${networkDataContainer} span[role="button"]`;
exports.dataSavingWebcams = 'input[data-test="dataSavingWebcams"]';
@ -329,10 +329,14 @@ exports.promoteToModerator = 'li[data-test="promoteToModerator"]';
exports.demoteToViewer = 'li[data-test="demoteToViewer"]';
exports.makePresenter = 'li[data-test="makePresenter"]';
exports.takePresenter = 'li[data-test="takePresenter"]';
exports.muteAll = 'li[data-test="muteAll"]';
exports.muteAllExceptPresenter = 'li[data-test="muteAllExceptPresenter"]';
exports.error403removedLabel = 'You have been removed from the meeting';
// Lock Viewers
exports.lockViewersButton = 'li[data-test="lockViewersButton"]';
exports.unlockUserButton = 'li[data-test="unlockUserButton"]';
exports.applyLockSettings ='button[data-test="applyLockSettings"]';
exports.applyLockSettings = 'button[data-test="applyLockSettings"]';
exports.lockShareWebcam = 'input[data-test="lockShareWebcam"]';
exports.lockSeeOtherViewersWebcam = 'input[data-test="lockSeeOtherViewersWebcam"]';
exports.lockShareMicrophone = 'input[data-test="lockShareMicrophone"]';

View File

@ -1,6 +1,5 @@
require('dotenv').config();
const sha1 = require('sha1');
const path = require('path');
const axios = require('axios');
const { test } = require('@playwright/test');
const xml2js = require('xml2js');
@ -9,9 +8,6 @@ const { expect } = require("@playwright/test");
const parameters = require('./parameters');
const httpPath = path.join(path.dirname(require.resolve('axios')), 'lib/adapters/http');
const http = require(httpPath);
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
@ -28,7 +24,7 @@ function apiCallUrl(name, callParams) {
function apiCall(name, callParams) {
const url = apiCallUrl(name, callParams);
return axios.get(url, { adapter: http }).then(response => xml2js.parseStringPromise(response.data));
return axios.get(url, { adapter: 'http' }).then(response => xml2js.parseStringPromise(response.data));
}
function createMeetingUrl(params, customParameter) {
@ -47,7 +43,7 @@ function createMeetingUrl(params, customParameter) {
function createMeetingPromise(params, customParameter) {
const url = createMeetingUrl(params, customParameter);
return axios.get(url, { adapter: http });
return axios.get(url, { adapter: 'http' });
}
async function createMeeting(params, customParameter) {

View File

@ -83,7 +83,7 @@ test.describe.parallel('Notifications', () => {
test('Screenshare notification', async ({ browser, browserName, context, page }) => {
test.skip(browserName === 'firefox' && process.env.DISPLAY === undefined,
"Screenshare tests not able in Firefox browser without desktop");
"Screenshare tests not able in Firefox browser without desktop");
const presenterNotifications = new PresenterNotifications(browser, context);
await presenterNotifications.initModPage(page);
await presenterNotifications.screenshareToast();

View File

@ -54,7 +54,7 @@ async function waitAndClearNotification(testPage) {
}
async function waitAndClearDefaultPresentationNotification(testPage) {
await testPage.waitForSelector(e.whiteboard,ELEMENT_WAIT_LONGER_TIME);
await testPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
const hasCurrentPresentationToast = await testPage.checkElement(e.currentPresentationToast);
if (hasCurrentPresentationToast) {
await waitAndClearNotification(testPage);

View File

@ -1,26 +1,26 @@
{
"name": "npm-proj-1662355536800-0.49467469802579256kg5mNL",
"name": "playwright",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@playwright/test": "^1.25.0",
"axios": "^0.26.1",
"@playwright/test": "^1.28.1",
"axios": "^1.2.0",
"chalk": "^4.1.2",
"dotenv": "^16.0.0",
"playwright": "^1.19.2",
"playwright": "^1.28.1",
"sha1": "^1.1.1",
"xml2js": "^0.4.23"
}
},
"node_modules/@playwright/test": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.25.0.tgz",
"integrity": "sha512-j4EZhTTQI3dBeWblE21EV//swwmBtOpIrLdOIJIRv4uqsLdHgBg1z+JtTg+AeC5o2bAXIE26kDNW5A0TimG8Bg==",
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.1.tgz",
"integrity": "sha512-xN6spdqrNlwSn9KabIhqfZR7IWjPpFK1835tFNgjrlysaSezuX8PYUwaz38V/yI8TJLG9PkAMEXoHRXYXlpTPQ==",
"dependencies": {
"@types/node": "*",
"playwright-core": "1.25.0"
"playwright-core": "1.28.1"
},
"bin": {
"playwright": "cli.js"
@ -29,21 +29,10 @@
"node": ">=14"
}
},
"node_modules/@playwright/test/node_modules/playwright-core": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.25.0.tgz",
"integrity": "sha512-kZ3Jwaf3wlu0GgU0nB8UMQ+mXFTqBIFz9h1svTlNduNKjnbPXFxw7mJanLVjqxHJRn62uBfmgBj93YHidk2N5Q==",
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@types/node": {
"version": "17.0.40",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.40.tgz",
"integrity": "sha512-UXdBxNGqTMtm7hCwh9HtncFVLrXoqA3oJW30j6XWp5BH/wu3mVeaxo7cq5benFdBw34HB3XDT2TRPI7rXZ+mDg=="
"version": "18.11.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz",
"integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw=="
},
"node_modules/ansi-styles": {
"version": "4.3.0",
@ -59,12 +48,19 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
"dependencies": {
"follow-redirects": "^1.14.8"
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/chalk": {
@ -106,6 +102,17 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
@ -114,18 +121,26 @@
"node": "*"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dotenv": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==",
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
@ -141,6 +156,19 @@
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -149,13 +177,32 @@
"node": ">=8"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/playwright": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.22.2.tgz",
"integrity": "sha512-hUTpg7LytIl3/O4t0AQJS1V6hWsaSY5uZ7w1oCC8r3a1AQN5d6otIdCkiB3cbzgQkcMaRxisinjMFMVqZkybdQ==",
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.28.1.tgz",
"integrity": "sha512-92Sz6XBlfHlb9tK5UCDzIFAuIkHHpemA9zwUaqvo+w7sFMSmVMGmvKcbptof/eJObq63PGnMhM75x7qxhTR78Q==",
"hasInstallScript": true,
"dependencies": {
"playwright-core": "1.22.2"
"playwright-core": "1.28.1"
},
"bin": {
"playwright": "cli.js"
@ -165,9 +212,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.2.tgz",
"integrity": "sha512-w/hc/Ld0RM4pmsNeE6aL/fPNWw8BWit2tg+TfqJ3+p59c6s3B6C8mXvXrIPmfQEobkcFDc+4KirNzOQ+uBSP1Q==",
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.1.tgz",
"integrity": "sha512-3PixLnGPno0E8rSBJjtwqTwJe3Yw72QwBBBxNoukIj3lEeBNXwbNiKrNuB1oyQgTBw5QHUhNO3SteEtHaMK6ag==",
"bin": {
"playwright": "cli.js"
},
@ -175,6 +222,11 @@
"node": ">=14"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@ -183,7 +235,7 @@
"node_modules/sha1": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
"integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
"integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==",
"dependencies": {
"charenc": ">= 0.0.1",
"crypt": ">= 0.0.1"
@ -226,25 +278,18 @@
},
"dependencies": {
"@playwright/test": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.25.0.tgz",
"integrity": "sha512-j4EZhTTQI3dBeWblE21EV//swwmBtOpIrLdOIJIRv4uqsLdHgBg1z+JtTg+AeC5o2bAXIE26kDNW5A0TimG8Bg==",
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.1.tgz",
"integrity": "sha512-xN6spdqrNlwSn9KabIhqfZR7IWjPpFK1835tFNgjrlysaSezuX8PYUwaz38V/yI8TJLG9PkAMEXoHRXYXlpTPQ==",
"requires": {
"@types/node": "*",
"playwright-core": "1.25.0"
},
"dependencies": {
"playwright-core": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.25.0.tgz",
"integrity": "sha512-kZ3Jwaf3wlu0GgU0nB8UMQ+mXFTqBIFz9h1svTlNduNKjnbPXFxw7mJanLVjqxHJRn62uBfmgBj93YHidk2N5Q=="
}
"playwright-core": "1.28.1"
}
},
"@types/node": {
"version": "17.0.40",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.40.tgz",
"integrity": "sha512-UXdBxNGqTMtm7hCwh9HtncFVLrXoqA3oJW30j6XWp5BH/wu3mVeaxo7cq5benFdBw34HB3XDT2TRPI7rXZ+mDg=="
"version": "18.11.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz",
"integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw=="
},
"ansi-styles": {
"version": "4.3.0",
@ -254,12 +299,19 @@
"color-convert": "^2.0.1"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
"requires": {
"follow-redirects": "^1.14.8"
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"chalk": {
@ -289,38 +341,79 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"dotenv": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ=="
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
},
"follow-redirects": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"playwright": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.22.2.tgz",
"integrity": "sha512-hUTpg7LytIl3/O4t0AQJS1V6hWsaSY5uZ7w1oCC8r3a1AQN5d6otIdCkiB3cbzgQkcMaRxisinjMFMVqZkybdQ==",
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"playwright-core": "1.22.2"
"mime-db": "1.52.0"
}
},
"playwright": {
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.28.1.tgz",
"integrity": "sha512-92Sz6XBlfHlb9tK5UCDzIFAuIkHHpemA9zwUaqvo+w7sFMSmVMGmvKcbptof/eJObq63PGnMhM75x7qxhTR78Q==",
"requires": {
"playwright-core": "1.28.1"
}
},
"playwright-core": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.2.tgz",
"integrity": "sha512-w/hc/Ld0RM4pmsNeE6aL/fPNWw8BWit2tg+TfqJ3+p59c6s3B6C8mXvXrIPmfQEobkcFDc+4KirNzOQ+uBSP1Q=="
"version": "1.28.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.1.tgz",
"integrity": "sha512-3PixLnGPno0E8rSBJjtwqTwJe3Yw72QwBBBxNoukIj3lEeBNXwbNiKrNuB1oyQgTBw5QHUhNO3SteEtHaMK6ag=="
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"sax": {
"version": "1.2.4",
@ -330,7 +423,7 @@
"sha1": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
"integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
"integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==",
"requires": {
"charenc": ">= 0.0.1",
"crypt": ">= 0.0.1"

View File

@ -8,11 +8,11 @@
"test-firefox-ci": "export CI='true' && npx playwright test --project=firefox --grep @ci"
},
"dependencies": {
"@playwright/test": "^1.25.0",
"playwright": "^1.19.2",
"axios": "^0.26.1",
"chalk": "^4.1.2",
"@playwright/test": "^1.28.1",
"axios": "^1.2.0",
"dotenv": "^16.0.0",
"playwright": "^1.28.1",
"chalk": "^4.1.2",
"sha1": "^1.1.1",
"xml2js": "^0.4.23"
}

View File

@ -4,7 +4,7 @@ const CI = process.env.CI === 'true';
const DEBUG_MODE = process.env.DEBUG_MODE === 'true';
const config = {
workers: 2,
workers: CI ? 1 : 2,
timeout: 3 * 60 * 1000,
reporter: [
[CI ? 'github' : 'list'],
@ -15,7 +15,7 @@ const config = {
headless: true,
trace: DEBUG_MODE ? 'on'
: CI ? 'retain-on-failure'
: 'off',
: 'off',
screenshot: 'on',
video: 'on',
},

View File

@ -6,6 +6,7 @@ const utilPresentation = require('../presentation/util');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
const { getSettings } = require('../core/settings');
const { waitAndClearDefaultPresentationNotification } = require('../notifications/util');
const { sleep } = require('../core/helpers');
class Polling extends MultiUsers {
constructor(browser, context) {
@ -206,7 +207,7 @@ class Polling extends MultiUsers {
async smartSlidesQuestions() {
await utilPresentation.uploadSinglePresentation(this.modPage, e.smartSlides1, ELEMENT_WAIT_LONGER_TIME);
await this.userPage.hasElement(e.presentationTitle);
await this.modPage.waitAndClick(e.quickPoll);
await this.userPage.hasElement(e.responsePollQuestion);
await this.userPage.type(e.pollAnswerOptionInput, 'test');
@ -221,11 +222,11 @@ class Polling extends MultiUsers {
await this.userPage.waitAndClick(e.submitAnswersMultiple);
await this.modPage.hasText(e.answer1, '1');
await this.modPage.waitAndClick(e.publishPollingLabel);
await this.modPage.waitAndClick(e.nextSlide);
await this.modPage.waitAndClick(e.quickPoll);
await this.userPage.waitAndClick(e.pollAnswerOptionBtn);
await this.userPage.waitAndClick(e.pollAnswerDescTest1);
await this.modPage.hasText(e.answer1, '1');
await this.modPage.hasElementDisabled(e.nextSlide);

View File

@ -50,7 +50,7 @@ class Presentation extends MultiUsers {
await this.modPage.waitForSelector(e.whiteboard);
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.shareExternalVideoBtn);
await this.modPage.waitForSelector(e.externalVideoModalHeader);
await this.modPage.waitForSelector(e.closeModal);
await this.modPage.type(e.videoModalInput, e.youtubeLink);
await this.modPage.waitAndClick(e.startShareVideoBtn);
@ -62,6 +62,7 @@ class Presentation extends MultiUsers {
}
async uploadSinglePresentationTest() {
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitForSelector(e.skipSlide);
const modSlides0 = await getSlideOuterHtml(this.modPage);
@ -81,14 +82,14 @@ class Presentation extends MultiUsers {
async uploadMultiplePresentationsTest() {
await this.modPage.waitForSelector(e.skipSlide);
const modSlides0 = await this.modPage.page.evaluate(getSvgOuterHtml);
const userSlides0 = await this.userPage.page.evaluate(getSvgOuterHtml);
const modSlides0 = await getSlideOuterHtml(this.modPage);
const userSlides0 = await getSlideOuterHtml(this.userPage);
await expect(modSlides0).toEqual(userSlides0);
await uploadMultiplePresentations(this.modPage, [e.uploadPresentationFileName, e.questionSlideFileName]);
const modSlides1 = await this.userPage.page.evaluate(async () => document.querySelector('svg g g g').outerHTML);
const userSlides1 = await this.modPage.page.evaluate(async () => document.querySelector('svg g g g').outerHTML);
const modSlides1 = await getSlideOuterHtml(this.modPage);
const userSlides1 = await getSlideOuterHtml(this.userPage);
await expect(modSlides1).toEqual(userSlides1);
await expect(modSlides0).not.toEqual(modSlides1);
@ -100,9 +101,9 @@ class Presentation extends MultiUsers {
await this.modPage.waitForSelector(e.skipSlide);
await this.modPage.waitAndClick(e.userListToggleBtn);
await uploadSinglePresentation(this.modPage, e.uploadPresentationFileName);
const width1 = await this.modPage.page.locator(e.whiteboard).getAttribute("width");
const width1 = (await this.modPage.page.locator(e.whiteboard).boundingBox()).width;
await this.modPage.waitAndClick(e.fitToWidthButton);
const width2 = await this.modPage.page.locator(e.whiteboard).getAttribute("width");
const width2 = (await this.modPage.page.locator(e.whiteboard).boundingBox()).width;
await expect(Number(width2) > Number(width1)).toBeTruthy();
}
@ -136,11 +137,11 @@ class Presentation extends MultiUsers {
async uploadAndRemoveAllPresentations() {
await waitAndClearDefaultPresentationNotification(this.modPage);
await uploadSinglePresentation(this.modPage, e.uploadPresentationFileName);
const modSlides1 = await getSlideOuterHtml(this.modPage);
const userSlides1 = await getSlideOuterHtml(this.userPage);
await expect(modSlides1).toEqual(userSlides1);
// Remove
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.actions);
@ -148,44 +149,44 @@ class Presentation extends MultiUsers {
await this.modPage.waitAndClick(e.removePresentation);
await this.modPage.waitAndClick(e.removePresentation);
await this.modPage.waitAndClick(e.confirmManagePresentation);
await this.modPage.wasRemoved(e.whiteboard);
await this.modPage.hasElementDisabled(e.minimizePresentation);
await this.userPage.wasRemoved(e.whiteboard);
await this.userPage.hasElementDisabled(e.minimizePresentation);
// Check removed presentations inside the Manage Presentations
await this.modPage.waitAndClick(e.actions);
await this.modPage.waitAndClick(e.managePresentations);
await this.modPage.wasRemoved(e.presentationsList);
await this.modPage.waitAndClick(e.confirmManagePresentation);
// Making viewer a presenter
await this.modPage.waitAndClick(e.userListItem);
await this.modPage.waitAndClick(e.makePresenter);
await this.userPage.waitAndClick(e.actions);
await this.userPage.waitAndClick(e.managePresentations);
await this.userPage.wasRemoved(e.presentationsList);
}
async removePreviousPresentationFromPreviousPresenter() {
await waitAndClearDefaultPresentationNotification(this.modPage);
await uploadSinglePresentation(this.modPage, e.uploadPresentationFileName);
const modSlides1 = await getSlideOuterHtml(this.modPage);
const userSlides1 = await getSlideOuterHtml(this.userPage);
await expect(modSlides1).toEqual(userSlides1);
await this.modPage.waitAndClick(e.userListItem);
await this.modPage.waitAndClick(e.makePresenter);
await this.userPage.waitAndClick(e.actions);
await this.userPage.waitAndClick(e.managePresentations);
await this.userPage.waitAndClick(e.removePresentation);
await this.userPage.waitAndClick(e.removePresentation);
await this.userPage.waitAndClick(e.confirmManagePresentation);
await this.userPage.wasRemoved(e.whiteboard);
await this.userPage.waitAndClick(e.actions);
await this.userPage.waitAndClick(e.managePresentations);

View File

@ -76,7 +76,7 @@ test.describe.parallel('Presentation', () => {
await presentation.initPages(page);
await presentation.uploadAndRemoveAllPresentations();
});
test('Remove previous presentation from previous presenter', async ({ browser, context, page }) => {
const presentation = new Presentation(browser, context);
await presentation.initPages(page);

View File

@ -4,7 +4,7 @@ const Page = require('../core/page');
const e = require('../core/elements');
const { waitAndClearDefaultPresentationNotification } = require('../notifications/util');
const { sleep } = require('../core/helpers');
const { checkAvatarIcon, checkIsPresenter } = require('./util');
const { checkAvatarIcon, checkIsPresenter, checkMutedUsers } = require('./util');
const { checkTextContent } = require('../core/util');
const { getSettings } = require('../core/settings');
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
@ -231,6 +231,40 @@ class MultiUsers {
}, e.multiUsersWhiteboardOff);
await expect(resp).toBeTruthy();
}
async muteAllUsers() {
await this.modPage.joinMicrophone();
await this.modPage2.joinMicrophone();
await this.userPage.joinMicrophone();
await this.modPage.waitAndClick(e.manageUsers);
await this.modPage.waitAndClick(e.muteAll);
await checkMutedUsers(this.modPage);
await checkMutedUsers(this.modPage2);
await checkMutedUsers(this.userPage);
}
async muteAllUsersExceptPresenter(){
await this.modPage.joinMicrophone();
await this.modPage2.joinMicrophone();
await this.userPage.joinMicrophone();
await this.modPage.waitAndClick(e.manageUsers);
await this.modPage.waitAndClick(e.muteAllExceptPresenter);
await this.modPage.hasElement(e.isTalking);
await checkMutedUsers(this.modPage2);
await checkMutedUsers(this.userPage);
}
async giveAndRemoveWhiteboardAccess() {
await this.whiteboardAccess();
await this.modPage.waitForSelector(e.whiteboard);
await this.modPage.waitAndClick(e.userListItem);
await this.modPage.waitAndClick(e.changeWhiteboardAccess);
await this.modPage.hasElement(e.multiUsersWhiteboardOn);
}
}
exports.MultiUsers = MultiUsers;

View File

@ -64,11 +64,18 @@ test.describe.parallel('User', () => {
await multiusers.initModPage2();
await multiusers.demoteToViewer();
});
test('Give and remove whiteboard access', async ({ browser, context, page }) => {
const multiusers = new MultiUsers(browser, context);
await multiusers.initModPage(page);
await multiusers.initModPage2();
await multiusers.giveAndRemoveWhiteboardAccess();
});
});
test.describe.parallel('Manage', () => {
test.describe.parallel('Guest policy', () => {
test.describe.parallel('ASK_MODERATOR', () => {
test.describe.parallel('ASK_MODERATOR', () => {
// https://docs.bigbluebutton.org/2.6/release-tests.html#ask-moderator
test('Message to guest lobby', async ({ browser, context, page }) => {
const guestPolicy = new GuestPolicy(browser, context);
@ -85,7 +92,7 @@ test.describe.parallel('User', () => {
await guestPolicy.initModPage(page);
await guestPolicy.denyEveryone();
});
test('Remember choice', async ({ browser, context, page }) => {
const guestPolicy = new GuestPolicy(browser, context);
await guestPolicy.initModPage(page);
@ -98,13 +105,13 @@ test.describe.parallel('User', () => {
await guestPolicy.initModPage(page);
await guestPolicy.messageToSpecificUser();
});
test('Accept', async ({ browser, context, page }) => {
const guestPolicy = new GuestPolicy(browser, context);
await guestPolicy.initModPage(page);
await guestPolicy.acceptSpecificUser();
});
test('Deny', async ({ browser, context, page }) => {
const guestPolicy = new GuestPolicy(browser, context);
await guestPolicy.initModPage(page);
@ -203,6 +210,22 @@ test.describe.parallel('User', () => {
await multiusers.initModPage(page);
await multiusers.selectRandomUser();
});
test('Mute all users', async ({ browser, context, page }) => {
const multiusers = new MultiUsers(browser, context);
await multiusers.initModPage(page, false);
await multiusers.initModPage2(false);
await multiusers.initUserPage(false);
await multiusers.muteAllUsers();
});
test('Mute all users except presenter', async ({ browser, context, page }) => {
const multiusers = new MultiUsers(browser, context);
await multiusers.initModPage(page, false);
await multiusers.initModPage2(false);
await multiusers.initUserPage(false);
await multiusers.muteAllUsersExceptPresenter();
});
});
test.describe.parallel('Mobile devices', () => {

View File

@ -27,8 +27,14 @@ async function checkIsPresenter(test) {
}, [e.currentUser, e.userAvatar])
}
async function checkMutedUsers(test) {
await test.wasRemoved(e.muteMicButton);
await test.hasElement(e.unmuteMicButton);
}
exports.setStatus = setStatus;
exports.openLockViewers = openLockViewers;
exports.setGuestPolicyOption = setGuestPolicyOption;
exports.checkAvatarIcon = checkAvatarIcon;
exports.checkIsPresenter = checkIsPresenter;
exports.checkMutedUsers = checkMutedUsers;

View File

@ -30,28 +30,28 @@ test.describe.parallel('Drawing - visual regression', () => {
test('Draw rectangle', async ({ browser, context, page }) => {
const drawRectangle = new DrawRectangle(browser, context);
await drawRectangle.initModPage(page, true, { customMeetingId : 'draw_rectangle_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawRectangle.initModPage(page, true, { customMeetingId: 'draw_rectangle_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawRectangle.initModPage2(true, context, { customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawRectangle.test();
});
test('Draw ellipse', async ({ browser, context, page }) => {
const drawEllipse = new DrawEllipse(browser, context);
await drawEllipse.initModPage(page, true, { customMeetingId : 'draw_ellipse_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawEllipse.initModPage(page, true, { customMeetingId: 'draw_ellipse_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawEllipse.initModPage2(true, context, { customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawEllipse.test();
});
test('Draw triangle', async ({ browser, context, page }) => {
const drawTriangle = new DrawTriangle(browser, context);
await drawTriangle.initModPage(page, true, { customMeetingId : 'draw_triangle_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawTriangle.initModPage(page, true, { customMeetingId: 'draw_triangle_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawTriangle.initModPage2(true, context, { customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawTriangle.test();
});
test('Draw line', async ({ browser, context, page }) => {
const drawLine= new DrawLine(browser, context);
await drawLine.initModPage(page, true, { customMeetingId : 'draw_line_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
const drawLine = new DrawLine(browser, context);
await drawLine.initModPage(page, true, { customMeetingId: 'draw_line_meeting', customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawLine.initModPage2(true, context, { customParameter: encodeCustomParams(`userdata-bbb_custom_style=.presentationUploaderToast{display: none;}.currentPresentationToast{display:none;}`) });
await drawLine.test();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -300,6 +300,11 @@ defaultLogoURL=${bigbluebutton.web.serverURL}/images/logo.png
# Allow requests without JSESSIONID to be handled (default = false)
allowRequestsWithoutSession=false
# Timeout (seconds) to invalidate inactive HTTP sessions.
# Default: 4 hours.
# For more info, refer to javax.servlet.http.HttpSession#setMaxInactiveInterval 's spec
defaultHttpSessionTimeout=14400
# The url for where the guest will poll if approved to join or not.
defaultGuestWaitURL=${bigbluebutton.web.serverURL}/html5client/guestWait

View File

@ -152,6 +152,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="defaultLogoURL" value="${defaultLogoURL}"/>
<property name="defaultGuestWaitURL" value="${defaultGuestWaitURL}"/>
<property name="allowRequestsWithoutSession" value="${allowRequestsWithoutSession}"/>
<property name="defaultHttpSessionTimeout" value="${defaultHttpSessionTimeout}"/>
<property name="defaultMeetingDuration" value="${defaultMeetingDuration}"/>
<property name="disableRecordingDefault" value="${disableRecordingDefault}"/>
<property name="autoStartRecording" value="${autoStartRecording}"/>

View File

@ -47,7 +47,6 @@ import org.json.JSONArray
import javax.servlet.ServletRequest
class ApiController {
private static final Integer SESSION_TIMEOUT = 14400 // 4 hours
private static final String CONTROLLER_NAME = 'ApiController'
protected static final String RESP_CODE_SUCCESS = 'SUCCESS'
protected static final String RESP_CODE_FAILED = 'FAILED'
@ -408,7 +407,7 @@ class ApiController {
us.leftGuestLobby
)
session.setMaxInactiveInterval(SESSION_TIMEOUT);
session.setMaxInactiveInterval(paramsProcessorUtil.getDefaultHttpSessionTimeout())
//check if exists the param redirect
boolean redirectClient = true;

View File

@ -27,7 +27,7 @@ dependencies {
implementation 'org.apache.commons:commons-lang3:3.9'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'org.apache.xmlbeans:xmlbeans:3.0.2'
implementation 'org.apache.commons:commons-compress:1.20'
implementation 'org.apache.commons:commons-compress:1.21'
}
jar {

View File

@ -597,7 +597,40 @@
"loglevel": "INFO",
/* Override any strings found in locale directories */
"customLocaleStrings": {},
"customLocaleStrings": {
"de": {
"pad.importExport.import_export": "Export",
"pad.toolbar.import_export.title": "Export zu verschiedenen Dateiformaten"
},
"en-gb": {
"pad.importExport.import_export": "Export",
"pad.toolbar.import_export.title": "Export to different file formats"
},
"en": {
"pad.importExport.import_export": "Export",
"pad.toolbar.import_export.title": "Export to different file formats"
},
"es": {
"pad.importExport.import_export": "Exportar",
"pad.toolbar.import_export.title": "Exportar a diferentes formatos de archivos"
},
"fr": {
"pad.importExport.import_export": "Exporter",
"pad.toolbar.import_export.title": "Exporter vers un format de fichier différent"
},
"it": {
"pad.importExport.import_export": "Esportazione",
"pad.toolbar.import_export.title": "Esporta a diversi formati di file"
},
"pt-br": {
"pad.importExport.import_export": "Exportar",
"pad.toolbar.import_export.title": "Exportar para diferentes formatos de arquivo"
},
"pt": {
"pad.importExport.import_export": "Exportar",
"pad.toolbar.import_export.title": "Exportar para diferentes formatos de ficheiro"
}
},
/* Disable Admin UI tests */
"enableAdminUITests": false