diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/SendMessageToAllBreakoutRoomsMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/SendMessageToAllBreakoutRoomsMsgHdlr.scala index 4c9fabbc8a..7437803e8a 100644 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/SendMessageToAllBreakoutRoomsMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/breakout/SendMessageToAllBreakoutRoomsMsgHdlr.scala @@ -15,8 +15,7 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait { val outGW: OutMsgRouter - def handleSendMessageToAllBreakoutRoomsMsg(msg: SendMessageToAllBreakoutRoomsMsg, state: MeetingState2x): MeetingState2x = { - log.debug("handleSendMessageToAllBreakoutRoomsMsg {} in meeting {}", msg.body.msg, props.meetingProp.intId) + def handleSendMessageToAllBreakoutRoomsMsg(msg: SendMessageToAllBreakoutRoomsReqMsg, state: MeetingState2x): MeetingState2x = { if (permissionFailed(PermissionCheck.MOD_LEVEL, PermissionCheck.VIEWER_LEVEL, liveMeeting.users2x, msg.header.userId)) { val meetingId = liveMeeting.props.meetingProp.intId val reason = "No permission to send message to all breakout rooms for meeting." @@ -30,6 +29,10 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait { breakoutModel.rooms.values.foreach { room => eventBus.publish(BigBlueButtonEvent(room.id, SendMessageToBreakoutRoomInternalMsg(props.breakoutProps.parentId, room.id, senderUser.name, msg.body.msg))) } + + val event = buildSendMessageToAllBreakoutRoomsEvtMsg(msg.header.userId, msg.body.msg, breakoutModel.rooms.size) + outGW.send(event) + log.debug("Sending message '{}' for breakout rooms in meeting {}", msg.body.msg, props.meetingProp.intId) } @@ -37,4 +40,14 @@ trait SendMessageToAllBreakoutRoomsMsgHdlr extends RightsManagementTrait { } } + def buildSendMessageToAllBreakoutRoomsEvtMsg(senderId: String, msg: String, totalOfRooms: Int): BbbCommonEnvCoreMsg = { + val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka") + val envelope = BbbCoreEnvelope(SendMessageToAllBreakoutRoomsEvtMsg.NAME, routing) + val header = BbbClientMsgHeader(SendMessageToAllBreakoutRoomsEvtMsg.NAME, liveMeeting.props.meetingProp.intId, "not-used") + + val body = SendMessageToAllBreakoutRoomsEvtMsgBody(props.meetingProp.intId, senderId, msg, totalOfRooms) + val event = SendMessageToAllBreakoutRoomsEvtMsg(header, body) + BbbCommonEnvCoreMsg(envelope, event) + } + } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala index 6be17d71a5..056fb5859d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala @@ -201,8 +201,8 @@ class ReceivedJsonMsgHandlerActor( routeGenericMsg[TransferUserToMeetingRequestMsg](envelope, jsonNode) case ExtendBreakoutRoomsTimeReqMsg.NAME => routeGenericMsg[ExtendBreakoutRoomsTimeReqMsg](envelope, jsonNode) - case SendMessageToAllBreakoutRoomsMsg.NAME => - routeGenericMsg[SendMessageToAllBreakoutRoomsMsg](envelope, jsonNode) + case SendMessageToAllBreakoutRoomsReqMsg.NAME => + routeGenericMsg[SendMessageToAllBreakoutRoomsReqMsg](envelope, jsonNode) // Layout case GetCurrentLayoutReqMsg.NAME => diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala index af9ff39b10..1bbb0a5bd6 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala @@ -450,17 +450,17 @@ class MeetingActor( updateUserLastActivity(m.body.requesterId) // Breakout - case m: BreakoutRoomsListMsg => state = handleBreakoutRoomsListMsg(m, state) - case m: CreateBreakoutRoomsCmdMsg => state = handleCreateBreakoutRoomsCmdMsg(m, state) - case m: EndAllBreakoutRoomsMsg => state = handleEndAllBreakoutRoomsMsg(m, state) - case m: RequestBreakoutJoinURLReqMsg => state = handleRequestBreakoutJoinURLReqMsg(m, state) - case m: TransferUserToMeetingRequestMsg => state = handleTransferUserToMeetingRequestMsg(m, state) - case m: ExtendBreakoutRoomsTimeReqMsg => state = handleExtendBreakoutRoomsTimeMsg(m, state) - case m: SendMessageToAllBreakoutRoomsMsg => state = handleSendMessageToAllBreakoutRoomsMsg(m, state) + case m: BreakoutRoomsListMsg => state = handleBreakoutRoomsListMsg(m, state) + case m: CreateBreakoutRoomsCmdMsg => state = handleCreateBreakoutRoomsCmdMsg(m, state) + case m: EndAllBreakoutRoomsMsg => state = handleEndAllBreakoutRoomsMsg(m, state) + case m: RequestBreakoutJoinURLReqMsg => state = handleRequestBreakoutJoinURLReqMsg(m, state) + case m: TransferUserToMeetingRequestMsg => state = handleTransferUserToMeetingRequestMsg(m, state) + case m: ExtendBreakoutRoomsTimeReqMsg => state = handleExtendBreakoutRoomsTimeMsg(m, state) + case m: SendMessageToAllBreakoutRoomsReqMsg => state = handleSendMessageToAllBreakoutRoomsMsg(m, state) // Voice - case m: UserLeftVoiceConfEvtMsg => handleUserLeftVoiceConfEvtMsg(m) - case m: UserMutedInVoiceConfEvtMsg => handleUserMutedInVoiceConfEvtMsg(m) + case m: UserLeftVoiceConfEvtMsg => handleUserLeftVoiceConfEvtMsg(m) + case m: UserMutedInVoiceConfEvtMsg => handleUserMutedInVoiceConfEvtMsg(m) case m: UserTalkingInVoiceConfEvtMsg => updateVoiceUserLastActivity(m.body.voiceUserId) handleUserTalkingInVoiceConfEvtMsg(m) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala index ef80780001..2fe8ba0ed4 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/AnalyticsActor.scala @@ -61,7 +61,7 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging { case m: EndAllBreakoutRoomsMsg => logMessage(msg) case m: TransferUserToMeetingRequestMsg => logMessage(msg) case m: ExtendBreakoutRoomsTimeReqMsg => logMessage(msg) - case m: SendMessageToAllBreakoutRoomsMsg => logMessage(msg) + case m: SendMessageToAllBreakoutRoomsReqMsg => logMessage(msg) case m: UserLeftVoiceConfToClientEvtMsg => logMessage(msg) case m: UserLeftVoiceConfEvtMsg => logMessage(msg) case m: RecordingStartedVoiceConfEvtMsg => logMessage(msg) diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/BreakoutMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/BreakoutMsgs.scala index 2a821359ef..d21a3f3cfa 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/BreakoutMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/BreakoutMsgs.scala @@ -102,9 +102,13 @@ object ExtendBreakoutRoomsTimeEvtMsg { val NAME = "ExtendBreakoutRoomsTimeEvtMsg case class ExtendBreakoutRoomsTimeEvtMsg(header: BbbClientMsgHeader, body: ExtendBreakoutRoomsTimeEvtMsgBody) extends BbbCoreMsg case class ExtendBreakoutRoomsTimeEvtMsgBody(meetingId: String, extendTimeInMinutes: Int) -object SendMessageToAllBreakoutRoomsMsg { val NAME = "SendMessageToAllBreakoutRoomsMsg" } -case class SendMessageToAllBreakoutRoomsMsg(header: BbbClientMsgHeader, body: SendMessageToAllBreakoutRoomsMsgBody) extends StandardMsg -case class SendMessageToAllBreakoutRoomsMsgBody(meetingId: String, msg: String) +object SendMessageToAllBreakoutRoomsReqMsg { val NAME = "SendMessageToAllBreakoutRoomsReqMsg" } +case class SendMessageToAllBreakoutRoomsReqMsg(header: BbbClientMsgHeader, body: SendMessageToAllBreakoutRoomsReqMsgBody) extends StandardMsg +case class SendMessageToAllBreakoutRoomsReqMsgBody(meetingId: String, msg: String) + +object SendMessageToAllBreakoutRoomsEvtMsg { val NAME = "SendMessageToAllBreakoutRoomsEvtMsg" } +case class SendMessageToAllBreakoutRoomsEvtMsg(header: BbbClientMsgHeader, body: SendMessageToAllBreakoutRoomsEvtMsgBody) extends BbbCoreMsg +case class SendMessageToAllBreakoutRoomsEvtMsgBody(meetingId: String, senderId: String, msg: String, totalOfRooms: Int) // Common Value objects case class BreakoutUserVO(id: String, name: String) diff --git a/bigbluebutton-html5/imports/api/breakouts-history/server/eventHandlers.js b/bigbluebutton-html5/imports/api/breakouts-history/server/eventHandlers.js index 9418f5f1fe..4cbdc27381 100644 --- a/bigbluebutton-html5/imports/api/breakouts-history/server/eventHandlers.js +++ b/bigbluebutton-html5/imports/api/breakouts-history/server/eventHandlers.js @@ -1,4 +1,6 @@ import RedisPubSub from '/imports/startup/server/redis'; import handleBreakoutRoomsList from './handlers/breakoutRoomsList'; +import messageToAllSent from '/imports/api/breakouts-history/server/handlers/messageToAllSent'; RedisPubSub.on('BreakoutRoomsListEvtMsg', handleBreakoutRoomsList); +RedisPubSub.on('SendMessageToAllBreakoutRoomsEvtMsg', messageToAllSent); diff --git a/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/breakoutRoomsList.js b/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/breakoutRoomsList.js index 0b26a79310..4d123334c0 100644 --- a/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/breakoutRoomsList.js +++ b/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/breakoutRoomsList.js @@ -30,6 +30,6 @@ export default function handleBreakoutRoomsList({ body }) { Logger.info(`Upserted rooms to breakout-history Data: meeting=${meetingId}`); } } catch (err) { - Logger.error(`Adding note to the collection breakout-history: ${err}`); + Logger.error(`Adding rooms to the collection breakout-history: ${err}`); } } diff --git a/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/messageToAllSent.js b/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/messageToAllSent.js new file mode 100644 index 0000000000..43ced532c8 --- /dev/null +++ b/bigbluebutton-html5/imports/api/breakouts-history/server/handlers/messageToAllSent.js @@ -0,0 +1,43 @@ +import Logger from '/imports/startup/server/logger'; +import { check } from 'meteor/check'; +import BreakoutsHistory from '/imports/api/breakouts-history'; + +export default function handleSendMessageToAllBreakoutRoomsEvtMsg({ body }, meetingId) { + + const { + senderId, + msg, + totalOfRooms, + } = body; + + check(meetingId, String); + check(senderId, String); + check(msg, String); + check(totalOfRooms, Number); + + const selector = { + meetingId, + }; + + const modifier = { + $push: { + broadcastMsgs: { + senderId, + msg, + totalOfRooms, + }, + }, + }; + + try { + const { insertedId } = BreakoutsHistory.upsert(selector, modifier); + + if (insertedId) { + Logger.info(`Added broadCastMsg to breakout-history Data: meeting=${meetingId}`); + } else { + Logger.info(`Upserted broadCastMsg to breakout-history Data: meeting=${meetingId}`); + } + } catch (err) { + Logger.error(`Adding broadCastMsg to the collection breakout-history: ${err}`); + } +} diff --git a/bigbluebutton-html5/imports/api/breakouts/server/methods/sendMessageToAllBreakouts.js b/bigbluebutton-html5/imports/api/breakouts/server/methods/sendMessageToAllBreakouts.js index f5b794dbc9..3aa9fe3afd 100644 --- a/bigbluebutton-html5/imports/api/breakouts/server/methods/sendMessageToAllBreakouts.js +++ b/bigbluebutton-html5/imports/api/breakouts/server/methods/sendMessageToAllBreakouts.js @@ -7,7 +7,7 @@ import Logger from '/imports/startup/server/logger'; export default function sendMessageToAllBreakouts({ msg }) { const REDIS_CONFIG = Meteor.settings.private.redis; const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; - const EVENT_NAME = 'SendMessageToAllBreakoutRoomsMsg'; + const EVENT_NAME = 'SendMessageToAllBreakoutRoomsReqMsg'; try { const { meetingId, requesterUserId } = extractCredentials(this.userId); diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx index 1c3c279aa2..2c7eb75165 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/component.jsx @@ -482,19 +482,6 @@ class BreakoutRoom extends PureComponent { /> ) : null} - {amIModerator - ? ( - - ) : null } + {amIModerator + ? ( + + ) : null } + {amIModerator ? : null } {this.renderBreakoutRooms()} {this.renderDuration()} { diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/component.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/component.jsx index 5535bd2a1a..ab87a9068d 100755 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/component.jsx @@ -3,9 +3,12 @@ import { defineMessages, injectIntl } from 'react-intl'; import deviceInfo from '/imports/utils/deviceInfo'; import PropTypes from 'prop-types'; import Styled from './styles'; +import { notify } from '/imports/ui/services/notification'; const propTypes = { - intl: PropTypes.object.isRequired, + intl: PropTypes.shape({ + formatMessage: PropTypes.func.isRequired, + }).isRequired, chatId: PropTypes.string.isRequired, disabled: PropTypes.bool.isRequired, minMessageLength: PropTypes.number.isRequired, @@ -39,6 +42,10 @@ const messages = defineMessages({ errorChatLocked: { id: 'app.chat.locked', }, + msgToBreakoutsSent: { + id: 'app.createBreakoutRoom.msgToBreakoutsSent', + description: 'Message for chat sent successfully', + }, }); const CHAT_CONFIG = Meteor.settings.public.chat; @@ -74,16 +81,23 @@ class MessageForm extends PureComponent { const { connected, locked, + userMessagesTooAllBreakouts, + intl, } = this.props; const { message } = this.state; + // Check for new messages sent and notify user + if (prevProps.userMessagesTooAllBreakouts.length < userMessagesTooAllBreakouts.length) { + for (let i = prevProps.userMessagesTooAllBreakouts.length; + i < userMessagesTooAllBreakouts.length; + i += 1) { + notify( + intl.formatMessage(messages.msgToBreakoutsSent, { 0: userMessagesTooAllBreakouts[i].totalOfRooms }), 'info', 'group_chat', + ); + } + } + this.updateUnsentMessagesCollection(prevProps.chatId, message); - this.setState( - { - error: null, - hasErrors: false, - }, this.setMessageState(), - ); if ( connected !== prevProps.connected @@ -100,47 +114,6 @@ class MessageForm extends PureComponent { this.setMessageState(); } - setMessageHint() { - const { - connected, - disabled, - intl, - locked, - } = this.props; - - let chatDisabledHint = null; - - if (disabled) { - if (connected) { - if (locked) { - chatDisabledHint = messages.errorChatLocked; - } - } else { - chatDisabledHint = messages.errorServerDisconnected; - } - } - - this.setState({ - hasErrors: disabled, - error: chatDisabledHint ? intl.formatMessage(chatDisabledHint) : null, - }); - } - - setMessageState() { - const { chatId, UnsentMessagesCollection } = this.props; - const unsentMessageByChat = UnsentMessagesCollection.findOne({ chatId }, - { fields: { message: 1 } }); - this.setState({ message: unsentMessageByChat ? unsentMessageByChat.message : '' }); - } - - updateUnsentMessagesCollection(chatId, message) { - const { UnsentMessagesCollection } = this.props; - UnsentMessagesCollection.upsert( - { chatId }, - { $set: { message } }, - ); - } - handleMessageKeyDown(e) { // TODO Prevent send message pressing enter on mobile and/or virtual keyboard if (e.keyCode === 13 && !e.shiftKey) { @@ -192,7 +165,7 @@ class MessageForm extends PureComponent { if (msg.length < minMessageLength) return; if (disabled - || msg.length > maxMessageLength) { + || msg.length > maxMessageLength) { this.setState({ hasErrors: true }); return; } @@ -207,6 +180,47 @@ class MessageForm extends PureComponent { this.setState({ message: '', hasErrors: false }); } + setMessageHint() { + const { + connected, + disabled, + intl, + locked, + } = this.props; + + let chatDisabledHint = null; + + if (disabled) { + if (connected) { + if (locked) { + chatDisabledHint = messages.errorChatLocked; + } + } else { + chatDisabledHint = messages.errorServerDisconnected; + } + } + + this.setState({ + hasErrors: disabled, + error: chatDisabledHint ? intl.formatMessage(chatDisabledHint) : null, + }); + } + + setMessageState() { + const { chatId, UnsentMessagesCollection } = this.props; + const unsentMessageByChat = UnsentMessagesCollection.findOne({ chatId }, + { fields: { message: 1 } }); + this.setState({ message: unsentMessageByChat ? unsentMessageByChat.message : '' }); + } + + updateUnsentMessagesCollection(chatId, message) { + const { UnsentMessagesCollection } = this.props; + UnsentMessagesCollection.upsert( + { chatId }, + { $set: { message } }, + ); + } + render() { const { intl, diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/container.jsx b/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/container.jsx index 8880362073..bc372e4ae3 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/message-form/container.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { withTracker } from 'meteor/react-meteor-data'; import MessageForm from './component'; import BreakoutService from '/imports/ui/components/breakout-room/service'; import ChatService from '/imports/ui/components/chat/service'; @@ -20,4 +21,12 @@ const MessageFormContainer = (props) => { ); }; -export default MessageFormContainer; +export default withTracker((props) => { + const userMessagesTooAllBreakouts = BreakoutService.getUserMessagesToAllBreakouts(); + + return { + ...props, + userMessagesTooAllBreakouts, + }; +})(MessageFormContainer); +// export default MessageFormContainer; diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/service.js b/bigbluebutton-html5/imports/ui/components/breakout-room/service.js index d3ff081d24..ac9c0ea4c6 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/service.js +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/service.js @@ -6,6 +6,7 @@ import Users from '/imports/api/users'; import UserListService from '/imports/ui/components/user-list/service'; import fp from 'lodash/fp'; import UsersPersistentData from '/imports/api/users-persistent-data'; +import BreakoutsHistory from '/imports/api/breakouts-history'; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; @@ -88,6 +89,15 @@ const sendMessageToAllBreakouts = (msg) => { return true; }; +const getUserMessagesToAllBreakouts = () => { + const breakoutHistory = BreakoutsHistory.findOne( + { meetingId: Auth.meetingID }, + { fields: { broadcastMsgs: 1 } }, + ) || {}; + + return (breakoutHistory.broadcastMsgs || []).filter((msg) => msg.senderId === Auth.userID); +}; + const transferUserToMeeting = (fromMeetingId, toMeetingId) => makeCall('transferUser', fromMeetingId, toMeetingId); @@ -201,6 +211,7 @@ export default { endAllBreakouts, extendBreakoutsTime, sendMessageToAllBreakouts, + getUserMessagesToAllBreakouts, isExtendTimeHigherThanMeetingRemaining, requestJoinURL, getBreakoutRoomUrl, diff --git a/bigbluebutton-html5/imports/ui/components/breakout-room/styles.js b/bigbluebutton-html5/imports/ui/components/breakout-room/styles.js index 2ad96a1005..2e53d84707 100644 --- a/bigbluebutton-html5/imports/ui/components/breakout-room/styles.js +++ b/bigbluebutton-html5/imports/ui/components/breakout-room/styles.js @@ -3,7 +3,7 @@ import { systemMessageBorderColor, mdPaddingX, borderSize, - listItemBgHover, + listItemBgHover, borderSizeSmall, } from '/imports/ui/stylesheets/styled-components/general'; import { colorPrimary, @@ -11,7 +11,7 @@ import { colorDanger, colorGrayDark, userListBg, - colorWhite, + colorWhite, colorGrayLighter, } from '/imports/ui/stylesheets/styled-components/palette'; import { headingsFontWeight, @@ -230,6 +230,15 @@ const HeaderButton = styled(Button)` } }`; +const Separator = styled.div` + position: relative; + width: 100%; + height: 10px; + height: ${borderSizeSmall}; + background-color: ${colorGrayLighter}; + margin: 30px 0px; +`; + export default { BreakoutActions, AlreadyConnected, @@ -251,4 +260,5 @@ export default { Duration, Panel, HeaderButton, + Separator, }; diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx index 3360c15ec9..4c2710ac41 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/component.jsx @@ -130,6 +130,7 @@ class TimeWindowChatItem extends PureComponent { isModerator, avatar, isOnline, + isSystemSender, } = this.props; const dateTime = new Date(timestamp); @@ -140,7 +141,7 @@ class TimeWindowChatItem extends PureComponent { return ( - + { name: senderName, color: '#01579b', avatar: '', - role: '', + role: ROLE_MODERATOR, loggedOut: false, } : users[Auth.meetingID][sender]; const messageKey = key; @@ -42,6 +42,7 @@ const TimeWindowChatItemContainer = (props) => { ...{ color: user?.color, isModerator: user?.role === ROLE_MODERATOR, + isSystemSender: sender === 'SYSTEM', isOnline: !user?.loggedOut, avatar: user?.avatar, name: user?.name, diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js index 8640169102..6b8d2019d0 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js +++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/styles.js @@ -9,6 +9,8 @@ import { systemMessageBackgroundColor, systemMessageBorderColor, systemMessageFontColor, + highlightedMessageBackgroundColor, + highlightedMessageBorderColor, colorHeading, colorGrayLight, palettePlaceholderText, @@ -63,6 +65,13 @@ const Wrapper = styled.div` position: relative; margin: ${borderSize} 0 0 ${borderSize}; + ${({ isSystemSender }) => isSystemSender && ` + background-color: ${highlightedMessageBackgroundColor}; + border-left: 2px solid ${highlightedMessageBorderColor}; + border-radius: 0px 3px 3px 0px; + padding: 8px 2px; + `} + [dir="rtl"] & { margin: ${borderSize} ${borderSize} 0 0; } diff --git a/bigbluebutton-html5/imports/ui/stylesheets/styled-components/palette.js b/bigbluebutton-html5/imports/ui/stylesheets/styled-components/palette.js index cf0cf25811..3cb7cc4891 100644 --- a/bigbluebutton-html5/imports/ui/stylesheets/styled-components/palette.js +++ b/bigbluebutton-html5/imports/ui/stylesheets/styled-components/palette.js @@ -75,6 +75,8 @@ const loaderBullet = `var(--loader-bullet, ${colorWhite})`; const systemMessageBackgroundColor = 'var(--system-message-background-color, #F9FBFC)'; const systemMessageBorderColor = 'var(--system-message-border-color, #C5CDD4)'; const systemMessageFontColor = `var(--system-message-font-color, ${colorGrayDark})`; +const highlightedMessageBackgroundColor = 'var(--system-message-background-color, #fef9f1)'; +const highlightedMessageBorderColor = 'var(--system-message-border-color, #f5c67f)'; const colorHeading = `var(--color-heading, ${colorGrayDark})`; const palettePlaceholderText = 'var(--palette-placeholder-text, #787675)'; const pollAnnotationGray = 'var(--poll-annotation-gray, #333333)'; @@ -164,6 +166,8 @@ export { systemMessageBackgroundColor, systemMessageBorderColor, systemMessageFontColor, + highlightedMessageBackgroundColor, + highlightedMessageBorderColor, colorHeading, palettePlaceholderText, pollAnnotationGray, diff --git a/bigbluebutton-html5/public/locales/en.json b/bigbluebutton-html5/public/locales/en.json index 441b470155..6e4050f1a0 100755 --- a/bigbluebutton-html5/public/locales/en.json +++ b/bigbluebutton-html5/public/locales/en.json @@ -867,7 +867,8 @@ "app.createBreakoutRoom.resetAssignments": "Reset assignments", "app.createBreakoutRoom.resetAssignmentsDesc": "Reset all user room assignments", "app.createBreakoutRoom.endAllBreakouts": "End all breakout rooms", - "app.createBreakoutRoom.chatTitleMsgAllRooms": "all rooms TODAs", + "app.createBreakoutRoom.chatTitleMsgAllRooms": "all rooms", + "app.createBreakoutRoom.msgToBreakoutsSent": "Message was sent to {0} breakout rooms", "app.createBreakoutRoom.roomName": "{0} (Room - {1})", "app.createBreakoutRoom.doneLabel": "Done", "app.createBreakoutRoom.nextLabel": "Next",