Skip to content

Commit b5c37c4

Browse files
glunardirppt
authored andcommitted
LPC2022 new Matrix to BBB integration component
1 parent 440ea61 commit b5c37c4

15 files changed

Lines changed: 399 additions & 1 deletion

File tree

bigbluebutton-html5/imports/api/pads/server/helpers.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import RedisPubSub from '/imports/startup/server/redis';
22
import { Meteor } from 'meteor/meteor';
33
import Logger from '/imports/startup/server/logger';
44

5+
const MATRIX_CONFIG = Meteor.settings.public.matrix;
56
const NOTES_CONFIG = Meteor.settings.public.notes;
67
const CAPTIONS_CONFIG = Meteor.settings.public.captions;
78
const REDIS_CONFIG = Meteor.settings.private.redis;
@@ -11,6 +12,7 @@ const TOKEN = '$';
1112
const models = {
1213
CAPTIONS: CAPTIONS_CONFIG.id,
1314
NOTES: NOTES_CONFIG.id,
15+
MATRIX: MATRIX_CONFIG.id,
1416
};
1517

1618
const getDataFromChangeset = (changeset) => {

bigbluebutton-html5/imports/ui/components/layout/enums.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const PANELS = {
105105
POLL: 'poll',
106106
CAPTIONS: 'captions',
107107
BREAKOUT: 'breakoutroom',
108+
MATRIX: 'matrix',
108109
SHARED_NOTES: 'shared-notes',
109110
TIMER: 'timer',
110111
WAITING_USERS: 'waiting-users',
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { defineMessages, injectIntl } from 'react-intl';
4+
import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component';
5+
import Styled from './styles';
6+
import Auth from '/imports/ui/services/auth';
7+
import getFromUserSettings from '/imports/ui/services/users-settings';
8+
import Meetings from '/imports/api/meetings';
9+
import { PANELS, ACTIONS } from '../layout/enums';
10+
import Header from '/imports/ui/components/common/control-header/component';
11+
import browserInfo from '/imports/utils/browserInfo';
12+
13+
const intlMessages = defineMessages({
14+
hide: {
15+
id: 'app.matrix.hide',
16+
description: 'Label for hiding matrix button',
17+
},
18+
title: {
19+
id: 'app.matrix.title',
20+
description: 'Title for Matrix',
21+
},
22+
tipLabel: {
23+
id: 'app.matrix.tipLabel',
24+
description: 'Label for tip on how to escape iframe',
25+
},
26+
});
27+
28+
const propTypes = {
29+
intl: PropTypes.shape({
30+
formatMessage: PropTypes.func.isRequired,
31+
}).isRequired,
32+
isResizing: PropTypes.bool.isRequired,
33+
layoutContextDispatch: PropTypes.func.isRequired,
34+
};
35+
36+
const Matrix = ({
37+
intl,
38+
layoutContextDispatch,
39+
isResizing,
40+
}) => {
41+
const { isChrome } = browserInfo;
42+
43+
const prop = Meetings.findOne(
44+
{ meetingId: Auth.meetingID },
45+
{ fields: { metadataProp: 1 } },
46+
).metadataProp;
47+
48+
const matrixRoomID = prop.metadata ? prop.metadata.matrixroomid : null;
49+
const urlemail = getFromUserSettings('mail', 'failed-to-retrieve-mail');
50+
const urlregcode = getFromUserSettings('regcode', 'failed-to-retrieve-regcode');
51+
const matrixtitle = `Matrix integration for ${Auth.confname}`;
52+
const matrixurl = `/riot-embedded/index.html?urlroomid=${matrixRoomID}&urlemail=${urlemail}&urlregcode=${urlregcode}`;
53+
54+
return (
55+
<Styled.Matrix data-test="matrix" isChrome={isChrome}>
56+
<Header
57+
leftButtonProps={{
58+
onClick: () => {
59+
layoutContextDispatch({
60+
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
61+
value: false,
62+
});
63+
layoutContextDispatch({
64+
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
65+
value: PANELS.NONE,
66+
});
67+
},
68+
'data-test': 'hide',
69+
'aria-label': intl.formatMessage(intlMessages.hide),
70+
label: intl.formatMessage(intlMessages.title),
71+
}}
72+
/>
73+
<Styled.IFrame
74+
title={matrixtitle}
75+
src={matrixurl}
76+
aria-describedby="MatrixEscapeHint"
77+
style={{
78+
pointerEvents: isResizing ? 'none' : 'inherit',
79+
}}
80+
/>
81+
<Styled.Hint
82+
id="MatrixEscapeHint"
83+
aria-hidden
84+
>
85+
{intl.formatMessage(intlMessages.tipLabel)}
86+
</Styled.Hint>
87+
</Styled.Matrix>
88+
);
89+
};
90+
91+
Matrix.propTypes = propTypes;
92+
93+
export default injectWbResizeEvent(injectIntl(Matrix));
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import { withTracker } from 'meteor/react-meteor-data';
3+
import Matrix from './component';
4+
import Service from './service';
5+
import { layoutSelectInput, layoutDispatch } from '../layout/context';
6+
7+
const MatrixContainer = ({ ...props }) => {
8+
const cameraDock = layoutSelectInput((i) => i.cameraDock);
9+
const { isResizing } = cameraDock;
10+
const layoutContextDispatch = layoutDispatch();
11+
12+
return <Matrix {...{ layoutContextDispatch, isResizing, ...props }} />;
13+
};
14+
15+
export default withTracker(() => {
16+
const isLocked = Service.isLocked();
17+
const isRTL = document.documentElement.getAttribute('dir') === 'rtl';
18+
19+
return {
20+
isLocked,
21+
isRTL,
22+
};
23+
})(MatrixContainer);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Users from '/imports/api/users';
2+
import Meetings from '/imports/api/meetings';
3+
import Auth from '/imports/ui/services/auth';
4+
import { ACTIONS, PANELS } from '/imports/ui/components/layout/enums';
5+
import { isMatrixEnabled } from '/imports/ui/services/features';
6+
7+
const MATRIX_CONFIG = Meteor.settings.public.matrix;
8+
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
9+
10+
const isLocked = () => {
11+
const meeting = Meetings.findOne({ meetingId: Auth.meetingID }, { fields: { 'lockSettingsProps.disableMatrix': 1 } });
12+
const user = Users.findOne({ userId: Auth.userID }, { fields: { locked: 1, role: 1 } });
13+
14+
if (meeting.lockSettingsProps && user.role !== ROLE_MODERATOR && user.locked) {
15+
return meeting.lockSettingsProps.disableMatrix;
16+
}
17+
return false;
18+
};
19+
20+
const isEnabled = () => isMatrixEnabled();
21+
22+
const toggleMatrixPanel = (sidebarContentPanel, layoutContextDispatch) => {
23+
layoutContextDispatch({
24+
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
25+
value: sidebarContentPanel !== PANELS.MATRIX,
26+
});
27+
layoutContextDispatch({
28+
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
29+
value:
30+
sidebarContentPanel === PANELS.MATRIX
31+
? PANELS.NONE
32+
: PANELS.MATRIX,
33+
});
34+
};
35+
36+
export default {
37+
ID: MATRIX_CONFIG.id,
38+
toggleMatrixPanel,
39+
isLocked,
40+
isEnabled,
41+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import styled from 'styled-components';
2+
import {
3+
mdPaddingX,
4+
mdPaddingY,
5+
smPaddingX,
6+
lgPaddingY,
7+
} from '/imports/ui/stylesheets/styled-components/general';
8+
import {
9+
colorWhite,
10+
colorGray,
11+
colorGrayLightest,
12+
} from '/imports/ui/stylesheets/styled-components/palette';
13+
import { smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints';
14+
import { fontSizeSmall } from '/imports/ui/stylesheets/styled-components/typography';
15+
16+
const Matrix = styled.div`
17+
background-color: ${colorWhite};
18+
padding: ${mdPaddingX} ${mdPaddingY} ${mdPaddingX} ${mdPaddingX};
19+
display: flex;
20+
flex-grow: 1;
21+
flex-direction: column;
22+
overflow: hidden;
23+
height: 100%;
24+
25+
${({ isChrome }) => isChrome && `
26+
transform: translateZ(0);
27+
`}
28+
29+
@media ${smallOnly} {
30+
transform: none !important;
31+
}
32+
`;
33+
34+
const Hint = styled.span`
35+
visibility: hidden;
36+
position: absolute;
37+
@media (pointer: none) {
38+
visibility: visible;
39+
position: relative;
40+
color: ${colorGray};
41+
font-size: ${fontSizeSmall};
42+
font-style: italic;
43+
padding: ${smPaddingX} 0 0 ${smPaddingX};
44+
text-align: left;
45+
[dir="rtl"] & {
46+
padding-right: ${lgPaddingY} ${lgPaddingY} 0 0;
47+
text-align: right;
48+
}
49+
}
50+
`;
51+
52+
const IFrame = styled.iframe`
53+
width: 100%;
54+
height: 100%;
55+
overflow: hidden;
56+
border-style: none;
57+
border-bottom: 1px solid ${colorGrayLightest};
58+
padding-bottom: 5px;
59+
`;
60+
61+
export default {
62+
Matrix,
63+
Hint,
64+
IFrame,
65+
};

bigbluebutton-html5/imports/ui/components/sidebar-content/component.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import Resizable from 're-resizable';
44
import { ACTIONS, PANELS } from '../layout/enums';
55
import ChatContainer from '/imports/ui/components/chat/container';
6+
import MatrixContainer from '/imports/ui/components/matrix/container';
67
import NotesContainer from '/imports/ui/components/notes/container';
78
import PollContainer from '/imports/ui/components/poll/container';
89
import CaptionsContainer from '/imports/ui/components/captions/container';
@@ -141,6 +142,8 @@ const SidebarContent = (props) => {
141142
isToSharedNotesBeShow={sidebarContentPanel === PANELS.SHARED_NOTES}
142143
/>
143144
)}
145+
{sidebarContentPanel === PANELS.MATRIX && <MatrixContainer />}
146+
{sidebarContentPanel === PANELS.SHARED_NOTES && <NotesContainer />}
144147
{sidebarContentPanel === PANELS.CAPTIONS && <CaptionsContainer />}
145148
{sidebarContentPanel === PANELS.BREAKOUT && <BreakoutRoomContainer />}
146149
{sidebarContentPanel === PANELS.TIMER && <TimerContainer />}

bigbluebutton-html5/imports/ui/components/user-list/service.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ const isMeetingLocked = (id) => {
381381
|| lockSettings.disableMic
382382
|| lockSettings.disablePrivateChat
383383
|| lockSettings.disablePublicChat
384+
|| lockSettings.disableMatrix
384385
|| lockSettings.disableNotes
385386
|| lockSettings.hideUserList
386387
|| lockSettings.hideViewersCursor

bigbluebutton-html5/imports/ui/components/user-list/user-list-content/component.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import Styled from './styles';
44
import UserParticipantsContainer from './user-participants/container';
55
import UserMessagesContainer from './user-messages/container';
6+
import UserMatrixContainer from './user-matrix/container';
67
import UserNotesContainer from './user-notes/container';
78
import TimerContainer from './timer/container';
89
import UserCaptionsContainer from './user-captions/container';
@@ -37,6 +38,7 @@ class UserContent extends PureComponent {
3738
<Styled.Content data-test="userListContent">
3839
{isChatEnabled() ? <UserMessagesContainer /> : null}
3940
<UserCaptionsContainer />
41+
<UserMatrixContainer />
4042
<UserNotesContainer />
4143
{ isTimerActive && (
4244
<TimerContainer
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { defineMessages, injectIntl } from 'react-intl';
4+
import Icon from '/imports/ui/components/common/icon/component';
5+
import Styled from './styles';
6+
import { ACTIONS, PANELS } from '../../../layout/enums';
7+
8+
const intlMessages = defineMessages({
9+
title: {
10+
id: 'app.userList.matrixTitle',
11+
description: 'Title for the Matrix chat',
12+
},
13+
Matrix: {
14+
id: 'app.matrix.title',
15+
description: 'Title for the LPC 2022 chat',
16+
},
17+
locked: {
18+
id: 'app.matrix.locked',
19+
description: '',
20+
},
21+
});
22+
23+
const UserMatrix = ({
24+
intl,
25+
disableMatrix,
26+
sidebarContentPanel,
27+
layoutContextDispatch,
28+
}) => {
29+
if (disableMatrix) return null;
30+
31+
const handleClickToggleMatrix = () => {
32+
layoutContextDispatch({
33+
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
34+
value: sidebarContentPanel !== PANELS.MATRIX,
35+
});
36+
layoutContextDispatch({
37+
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
38+
value: sidebarContentPanel === PANELS.MATRIX
39+
? PANELS.NONE
40+
: PANELS.MATRIX,
41+
});
42+
};
43+
44+
return (
45+
<Styled.Messages>
46+
<Styled.Container>
47+
<Styled.SmallTitle>
48+
{intl.formatMessage(intlMessages.title)}
49+
</Styled.SmallTitle>
50+
</Styled.Container>
51+
<Styled.List>
52+
<Styled.ScrollableList>
53+
<Styled.ListItem
54+
role="button"
55+
tabIndex={0}
56+
data-test="matrixMenuButton"
57+
onClick={handleClickToggleMatrix}
58+
onKeyPress={() => {}}
59+
>
60+
<Icon iconName="group_chat" />
61+
<span>{intl.formatMessage(intlMessages.Matrix)}</span>
62+
</Styled.ListItem>
63+
</Styled.ScrollableList>
64+
</Styled.List>
65+
</Styled.Messages>
66+
);
67+
};
68+
69+
export default injectIntl(UserMatrix);
70+
71+
UserMatrix.propTypes = {
72+
intl: PropTypes.shape({
73+
formatMessage: PropTypes.func.isRequired,
74+
}).isRequired,
75+
disableMatrix: PropTypes.bool.isRequired,
76+
layoutContextDispatch: PropTypes.func.isRequired,
77+
sidebarContentPanel: PropTypes.string.isRequired,
78+
};

0 commit comments

Comments
 (0)