Merge pull request #20734 from danielpetri1/pass-breakout-pres
feat: Pass a different presentation to each breakout
This commit is contained in:
commit
b248143cae
@ -18,8 +18,11 @@ object BreakoutModel {
|
|||||||
captureSlides: Boolean,
|
captureSlides: Boolean,
|
||||||
captureNotesFilename: String,
|
captureNotesFilename: String,
|
||||||
captureSlidesFilename: String,
|
captureSlidesFilename: String,
|
||||||
|
allPages: Boolean,
|
||||||
|
presId: String,
|
||||||
): BreakoutRoom2x = {
|
): BreakoutRoom2x = {
|
||||||
new BreakoutRoom2x(id, externalId, name, parentId, sequence, shortName, isDefaultName, freeJoin, voiceConf, assignedUsers, Vector(), Vector(), None, false, captureNotes, captureSlides, captureNotesFilename, captureSlidesFilename)
|
new BreakoutRoom2x(id, externalId, name, parentId, sequence, shortName, isDefaultName, freeJoin, voiceConf, assignedUsers, Vector(), Vector(), None, false,
|
||||||
|
captureNotes, captureSlides, captureNotesFilename, captureSlidesFilename, allPages, presId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,26 +40,30 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def processRequest(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
|
def processRequest(msg: CreateBreakoutRoomsCmdMsg, state: MeetingState2x): MeetingState2x = {
|
||||||
|
val presId = getPresentationId(state) // The current presentation
|
||||||
val presId = getPresentationId(state)
|
val presSlide = getPresentationSlide(state) // The current slide
|
||||||
val presSlide = getPresentationSlide(state)
|
|
||||||
val parentId = liveMeeting.props.meetingProp.intId
|
val parentId = liveMeeting.props.meetingProp.intId
|
||||||
var rooms = new collection.immutable.HashMap[String, BreakoutRoom2x]
|
var rooms = new collection.immutable.HashMap[String, BreakoutRoom2x]
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
for (room <- msg.body.rooms) {
|
for (room <- msg.body.rooms) {
|
||||||
|
val roomPresId = if (room.presId.isEmpty) presId else room.presId;
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
val (internalId, externalId) = BreakoutRoomsUtil.createMeetingIds(liveMeeting.props.meetingProp.intId, i)
|
val (internalId, externalId) = BreakoutRoomsUtil.createMeetingIds(liveMeeting.props.meetingProp.intId, i)
|
||||||
val voiceConf = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i)
|
val voiceConf = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i)
|
||||||
|
|
||||||
val breakout = BreakoutModel.create(parentId, internalId, externalId, room.name, room.sequence, room.shortName,
|
val breakout = BreakoutModel.create(parentId, internalId, externalId, room.name, room.sequence, room.shortName,
|
||||||
room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes,
|
room.isDefaultName, room.freeJoin, voiceConf, room.users, msg.body.captureNotes,
|
||||||
msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename)
|
msg.body.captureSlides, room.captureNotesFilename, room.captureSlidesFilename,
|
||||||
|
room.allPages, roomPresId)
|
||||||
|
|
||||||
rooms = rooms + (breakout.id -> breakout)
|
rooms = rooms + (breakout.id -> breakout)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (breakout <- rooms.values.toVector) {
|
for (breakout <- rooms.values.toVector) {
|
||||||
|
val roomSlides = if (breakout.allPages) -1 else presSlide;
|
||||||
|
|
||||||
val roomDetail = new BreakoutRoomDetail(
|
val roomDetail = new BreakoutRoomDetail(
|
||||||
breakout.id, breakout.name,
|
breakout.id, breakout.name,
|
||||||
liveMeeting.props.meetingProp.intId,
|
liveMeeting.props.meetingProp.intId,
|
||||||
@ -72,7 +76,9 @@ trait CreateBreakoutRoomsCmdMsgHdlr extends RightsManagementTrait {
|
|||||||
msg.body.durationInMinutes * 60,
|
msg.body.durationInMinutes * 60,
|
||||||
liveMeeting.props.password.moderatorPass,
|
liveMeeting.props.password.moderatorPass,
|
||||||
liveMeeting.props.password.viewerPass,
|
liveMeeting.props.password.viewerPass,
|
||||||
presId, presSlide, msg.body.record,
|
breakout.presId,
|
||||||
|
roomSlides,
|
||||||
|
msg.body.record,
|
||||||
liveMeeting.props.breakoutProps.privateChatEnabled,
|
liveMeeting.props.breakoutProps.privateChatEnabled,
|
||||||
breakout.captureNotes,
|
breakout.captureNotes,
|
||||||
breakout.captureSlides,
|
breakout.captureSlides,
|
||||||
|
@ -19,6 +19,8 @@ case class BreakoutRoom2x(
|
|||||||
captureSlides: Boolean,
|
captureSlides: Boolean,
|
||||||
captureNotesFilename: String,
|
captureNotesFilename: String,
|
||||||
captureSlidesFilename: String,
|
captureSlidesFilename: String,
|
||||||
|
allPages: Boolean,
|
||||||
|
presId: String,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ case class BreakoutRoomDetail(
|
|||||||
object CreateBreakoutRoomsCmdMsg { val NAME = "CreateBreakoutRoomsCmdMsg" }
|
object CreateBreakoutRoomsCmdMsg { val NAME = "CreateBreakoutRoomsCmdMsg" }
|
||||||
case class CreateBreakoutRoomsCmdMsg(header: BbbClientMsgHeader, body: CreateBreakoutRoomsCmdMsgBody) extends StandardMsg
|
case class CreateBreakoutRoomsCmdMsg(header: BbbClientMsgHeader, body: CreateBreakoutRoomsCmdMsgBody) extends StandardMsg
|
||||||
case class CreateBreakoutRoomsCmdMsgBody(meetingId: String, durationInMinutes: Int, record: Boolean, captureNotes: Boolean, captureSlides: Boolean, rooms: Vector[BreakoutRoomMsgBody], sendInviteToModerators: Boolean)
|
case class CreateBreakoutRoomsCmdMsgBody(meetingId: String, durationInMinutes: Int, record: Boolean, captureNotes: Boolean, captureSlides: Boolean, rooms: Vector[BreakoutRoomMsgBody], sendInviteToModerators: Boolean)
|
||||||
case class BreakoutRoomMsgBody(name: String, sequence: Int, shortName: String, captureNotesFilename: String, captureSlidesFilename: String, isDefaultName: Boolean, freeJoin: Boolean, users: Vector[String])
|
case class BreakoutRoomMsgBody(name: String, sequence: Int, shortName: String, captureNotesFilename: String, captureSlidesFilename: String, isDefaultName: Boolean, freeJoin: Boolean, users: Vector[String], allPages: Boolean, presId: String)
|
||||||
|
|
||||||
// Sent by user to request ending all the breakout rooms
|
// Sent by user to request ending all the breakout rooms
|
||||||
object EndAllBreakoutRoomsMsg { val NAME = "EndAllBreakoutRoomsMsg" }
|
object EndAllBreakoutRoomsMsg { val NAME = "EndAllBreakoutRoomsMsg" }
|
||||||
|
@ -94,6 +94,7 @@ public class PresentationUrlDownloadService {
|
|||||||
}, 5, TimeUnit.SECONDS);
|
}, 5, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A negative presentationSlide indicates the entire presentation deck should be used.
|
||||||
private void extractPage(final String sourceMeetingId, final String presentationId,
|
private void extractPage(final String sourceMeetingId, final String presentationId,
|
||||||
final Integer presentationSlide, final String destinationMeetingId) {
|
final Integer presentationSlide, final String destinationMeetingId) {
|
||||||
|
|
||||||
@ -146,7 +147,7 @@ public class PresentationUrlDownloadService {
|
|||||||
+ newFilename;
|
+ newFilename;
|
||||||
File newPresentation = new File(newFilePath);
|
File newPresentation = new File(newFilePath);
|
||||||
|
|
||||||
if (sourcePresentationFile.getName().toLowerCase().endsWith("pdf")) {
|
if (sourcePresentationFile.getName().toLowerCase().endsWith("pdf") && presentationSlide >= 0) {
|
||||||
pageExtractor.extractPage(sourcePresentationFile, new File(
|
pageExtractor.extractPage(sourcePresentationFile, new File(
|
||||||
newFilePath), presentationSlide);
|
newFilePath), presentationSlide);
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,12 +181,17 @@ const intlMessages = defineMessages({
|
|||||||
id: 'app.createBreakoutRoom.sendInvitationToMods',
|
id: 'app.createBreakoutRoom.sendInvitationToMods',
|
||||||
description: 'label for checkbox send invitation to moderators',
|
description: 'label for checkbox send invitation to moderators',
|
||||||
},
|
},
|
||||||
|
currentSlide: {
|
||||||
|
id: 'app.createBreakoutRoom.currentSlideLabel',
|
||||||
|
description: 'label for current slide',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const BREAKOUT_LIM = Meteor.settings.public.app.breakouts.breakoutRoomLimit;
|
const BREAKOUT_LIM = Meteor.settings.public.app.breakouts.breakoutRoomLimit;
|
||||||
const MIN_BREAKOUT_ROOMS = 2;
|
const MIN_BREAKOUT_ROOMS = 2;
|
||||||
const MAX_BREAKOUT_ROOMS = BREAKOUT_LIM > MIN_BREAKOUT_ROOMS ? BREAKOUT_LIM : MIN_BREAKOUT_ROOMS;
|
const MAX_BREAKOUT_ROOMS = BREAKOUT_LIM > MIN_BREAKOUT_ROOMS ? BREAKOUT_LIM : MIN_BREAKOUT_ROOMS;
|
||||||
const MIN_BREAKOUT_TIME = 5;
|
const MIN_BREAKOUT_TIME = 5;
|
||||||
|
const CURRENT_SLIDE_PREFIX = 'current-';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
intl: PropTypes.shape({
|
intl: PropTypes.shape({
|
||||||
@ -244,6 +249,7 @@ class BreakoutRoom extends PureComponent {
|
|||||||
this.removeRoomUsers = this.removeRoomUsers.bind(this);
|
this.removeRoomUsers = this.removeRoomUsers.bind(this);
|
||||||
this.renderErrorMessages = this.renderErrorMessages.bind(this);
|
this.renderErrorMessages = this.renderErrorMessages.bind(this);
|
||||||
this.onUpdateBreakouts = this.onUpdateBreakouts.bind(this);
|
this.onUpdateBreakouts = this.onUpdateBreakouts.bind(this);
|
||||||
|
this.getRoomPresentation = this.getRoomPresentation.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
numberOfRooms: MIN_BREAKOUT_ROOMS,
|
numberOfRooms: MIN_BREAKOUT_ROOMS,
|
||||||
@ -266,6 +272,7 @@ class BreakoutRoom extends PureComponent {
|
|||||||
durationIsValid: true,
|
durationIsValid: true,
|
||||||
breakoutJoinedUsers: null,
|
breakoutJoinedUsers: null,
|
||||||
enableUnassingUsers: null,
|
enableUnassingUsers: null,
|
||||||
|
roomPresentations: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.btnLevelId = uniqueId('btn-set-level-');
|
this.btnLevelId = uniqueId('btn-set-level-');
|
||||||
@ -503,6 +510,8 @@ class BreakoutRoom extends PureComponent {
|
|||||||
isDefaultName: !this.hasNameChanged(seq),
|
isDefaultName: !this.hasNameChanged(seq),
|
||||||
freeJoin,
|
freeJoin,
|
||||||
sequence: seq,
|
sequence: seq,
|
||||||
|
allPages: !this.getRoomPresentation(seq).startsWith(CURRENT_SLIDE_PREFIX),
|
||||||
|
presId: this.getRoomPresentation(seq).replace(CURRENT_SLIDE_PREFIX, ''),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
createBreakoutRoom(rooms, durationTime, record, captureNotes, captureSlides, inviteMods);
|
createBreakoutRoom(rooms, durationTime, record, captureNotes, captureSlides, inviteMods);
|
||||||
@ -688,6 +697,15 @@ class BreakoutRoom extends PureComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRoomPresentation(position) {
|
||||||
|
const { roomPresentations } = this.state;
|
||||||
|
const { presentations } = this.props;
|
||||||
|
|
||||||
|
const currentPresentation = presentations.find((presentation) => presentation.current);
|
||||||
|
|
||||||
|
return roomPresentations[position] || `${CURRENT_SLIDE_PREFIX}${currentPresentation?.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
getFullName(position) {
|
getFullName(position) {
|
||||||
const { meetingName } = this.props;
|
const { meetingName } = this.props;
|
||||||
|
|
||||||
@ -909,11 +927,12 @@ class BreakoutRoom extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderRoomsGrid() {
|
renderRoomsGrid() {
|
||||||
const { intl, isUpdate } = this.props;
|
const { intl, isUpdate, presentations } = this.props;
|
||||||
const {
|
const {
|
||||||
leastOneUserIsValid,
|
leastOneUserIsValid,
|
||||||
numberOfRooms,
|
numberOfRooms,
|
||||||
roomNamesChanged,
|
roomNamesChanged,
|
||||||
|
roomPresentations,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const rooms = (numberOfRooms > MAX_BREAKOUT_ROOMS
|
const rooms = (numberOfRooms > MAX_BREAKOUT_ROOMS
|
||||||
@ -941,6 +960,17 @@ class BreakoutRoom extends PureComponent {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeRoomPresentation = (position) => (ev) => {
|
||||||
|
const newRoomsPresentations = [...roomPresentations];
|
||||||
|
newRoomsPresentations[position] = ev.target.value;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
roomPresentations: newRoomsPresentations,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentPresentation = presentations.find((presentation) => presentation.current);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styled.BoxContainer key="rooms-grid-" ref={(r) => { this.listOfUsers = r; }} data-test="roomGrid">
|
<Styled.BoxContainer key="rooms-grid-" ref={(r) => { this.listOfUsers = r; }} data-test="roomGrid">
|
||||||
{
|
{
|
||||||
@ -963,6 +993,31 @@ class BreakoutRoom extends PureComponent {
|
|||||||
{intl.formatMessage(intlMessages.roomNameInputDesc)}
|
{intl.formatMessage(intlMessages.roomNameInputDesc)}
|
||||||
</div>
|
</div>
|
||||||
</Styled.FreeJoinLabel>
|
</Styled.FreeJoinLabel>
|
||||||
|
{ presentations.length > 0 ? (
|
||||||
|
<Styled.BreakoutSlideLabel>
|
||||||
|
<Styled.InputRooms
|
||||||
|
value={this.getRoomPresentation(value)}
|
||||||
|
onChange={changeRoomPresentation(value)}
|
||||||
|
valid
|
||||||
|
>
|
||||||
|
{ currentPresentation?.id ? (
|
||||||
|
<option key="current-slide" value={`${CURRENT_SLIDE_PREFIX}${currentPresentation.id}`}>
|
||||||
|
{intl.formatMessage(intlMessages.currentSlide)}
|
||||||
|
</option>
|
||||||
|
) : null }
|
||||||
|
{
|
||||||
|
presentations.map((presentation) => (
|
||||||
|
<option
|
||||||
|
key={presentation.id}
|
||||||
|
value={presentation.id}
|
||||||
|
>
|
||||||
|
{presentation.name}
|
||||||
|
</option>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Styled.InputRooms>
|
||||||
|
</Styled.BreakoutSlideLabel>
|
||||||
|
) : null }
|
||||||
<Styled.BreakoutBox id={`breakoutBox-${value}`} onDrop={drop(value)} onDragOver={allowDrop} tabIndex={0}>
|
<Styled.BreakoutBox id={`breakoutBox-${value}`} onDrop={drop(value)} onDragOver={allowDrop} tabIndex={0}>
|
||||||
{this.renderUserItemByRoom(value)}
|
{this.renderUserItemByRoom(value)}
|
||||||
</Styled.BreakoutBox>
|
</Styled.BreakoutBox>
|
||||||
|
@ -3,6 +3,7 @@ import { withTracker } from 'meteor/react-meteor-data';
|
|||||||
import ActionsBarService from '/imports/ui/components/actions-bar/service';
|
import ActionsBarService from '/imports/ui/components/actions-bar/service';
|
||||||
import BreakoutRoomService from '/imports/ui/components/breakout-room/service';
|
import BreakoutRoomService from '/imports/ui/components/breakout-room/service';
|
||||||
import CreateBreakoutRoomModal from './component';
|
import CreateBreakoutRoomModal from './component';
|
||||||
|
import Presentations from '/imports/api/presentations';
|
||||||
import { isImportSharedNotesFromBreakoutRoomsEnabled, isImportPresentationWithAnnotationsFromBreakoutRoomsEnabled } from '/imports/ui/services/features';
|
import { isImportSharedNotesFromBreakoutRoomsEnabled, isImportPresentationWithAnnotationsFromBreakoutRoomsEnabled } from '/imports/ui/services/features';
|
||||||
|
|
||||||
const METEOR_SETTINGS_APP = Meteor.settings.public.app;
|
const METEOR_SETTINGS_APP = Meteor.settings.public.app;
|
||||||
@ -46,4 +47,5 @@ export default withTracker(() => ({
|
|||||||
meetingName: ActionsBarService.meetingName(),
|
meetingName: ActionsBarService.meetingName(),
|
||||||
amIModerator: ActionsBarService.amIModerator(),
|
amIModerator: ActionsBarService.amIModerator(),
|
||||||
moveUser: ActionsBarService.moveUser,
|
moveUser: ActionsBarService.moveUser,
|
||||||
|
presentations: Presentations.find({ 'conversion.done': true }).fetch(),
|
||||||
}))(CreateBreakoutRoomContainer);
|
}))(CreateBreakoutRoomContainer);
|
||||||
|
@ -68,6 +68,15 @@ const FreeJoinLabel = styled.label`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const BreakoutSlideLabel = styled.label`
|
||||||
|
font-size: ${fontSizeSmall};
|
||||||
|
font-weight: bolder;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: ${fontSizeSmall};
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
`
|
||||||
|
|
||||||
const BreakoutNameInput = styled.input`
|
const BreakoutNameInput = styled.input`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -377,4 +386,5 @@ export default {
|
|||||||
SubTitle,
|
SubTitle,
|
||||||
Content,
|
Content,
|
||||||
ContentContainer,
|
ContentContainer,
|
||||||
|
BreakoutSlideLabel,
|
||||||
};
|
};
|
||||||
|
@ -1249,6 +1249,7 @@
|
|||||||
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "The breakout rooms duration can't exceed the meeting remaining time.",
|
"app.createBreakoutRoom.setTimeHigherThanMeetingTimeError": "The breakout rooms duration can't exceed the meeting remaining time.",
|
||||||
"app.createBreakoutRoom.roomNameInputDesc": "Updates breakout room name",
|
"app.createBreakoutRoom.roomNameInputDesc": "Updates breakout room name",
|
||||||
"app.createBreakoutRoom.movedUserLabel": "Moved {0} to room {1}",
|
"app.createBreakoutRoom.movedUserLabel": "Moved {0} to room {1}",
|
||||||
|
"app.createBreakoutRoom.currentSlideLabel": "Current slide",
|
||||||
"app.updateBreakoutRoom.modalDesc": "To update or invite a user, simply drag them into the desired room.",
|
"app.updateBreakoutRoom.modalDesc": "To update or invite a user, simply drag them into the desired room.",
|
||||||
"app.updateBreakoutRoom.cancelLabel": "Cancel",
|
"app.updateBreakoutRoom.cancelLabel": "Cancel",
|
||||||
"app.updateBreakoutRoom.title": "Update Breakout Rooms",
|
"app.updateBreakoutRoom.title": "Update Breakout Rooms",
|
||||||
|
Loading…
Reference in New Issue
Block a user