Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement of Room Sharing capabilities (followup to #5068 static SIP pins) #5102

Open
wants to merge 54 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
71dd8f8
st
Mar 21, 2023
2b915ba
Static SIP
Mar 24, 2023
d55c30f
revert locale dev change
Mar 24, 2023
7fab7af
revert locale dev change
Mar 24, 2023
af1c240
sample.env update with VoiceBrige config
Mar 24, 2023
ebc4a87
Update room.rb, mistake in comment
SebastianAppDev Mar 27, 2023
7940467
Improved room sharing
Mar 28, 2023
741c482
merge SIP into ics
Mar 28, 2023
96df717
Voice Brige database migration for existing rooms
Mar 29, 2023
fb5f20d
Merge branch 'SIP' of https://github.com/SebastianAppDev/greenlight i…
Mar 29, 2023
6419f8e
Merge branch 'SIP' into ics
Mar 29, 2023
be32835
Merge branch 'ics' into master
SebastianAppDev Mar 29, 2023
8be708d
Merge pull request #1 from SebastianAppDev/master
SebastianAppDev Mar 29, 2023
7b9cd7b
update
Mar 29, 2023
32efa91
Improved data migration
Mar 29, 2023
e70fe86
Merge branch 'SIP' into ics
Mar 29, 2023
daef372
undefind frindly_id fix
Mar 29, 2023
3596405
improved database voice_brige population
Mar 29, 2023
6f975d9
Merge branch 'SIP' into ics
Mar 29, 2023
3a64741
bug fix
Mar 29, 2023
fa090b7
Merge branch 'master' into ics
SebastianAppDev Mar 29, 2023
8470182
Merge branch 'master' into SIP
SebastianAppDev Mar 29, 2023
54b52aa
Typo
Mar 30, 2023
a91eb30
Merge branch 'master' of https://github.com/bigbluebutton/greenlight …
May 30, 2023
84ee009
Merge branch 'master' of https://github.com/bigbluebutton/greenlight …
Sep 25, 2023
97a4cfc
Merge branch 'bigbluebutton-master'
Sep 25, 2023
b3660ee
Merge branch 'master' of https://github.com/SebastianAppDev/greenlight
Sep 25, 2023
161933d
Merge branch 'ics' into master
SebastianAppDev Sep 25, 2023
714a699
Merge pull request #5 from SebastianAppDev/master
SebastianAppDev Sep 25, 2023
4697389
Merge branch 'master' of https://github.com/bigbluebutton/greenlight …
SebastianAppDev Oct 23, 2023
fc6fcfa
ICS: fix design inconsistency
SebastianAppDev Dec 20, 2023
ea0b85c
FIX: code issues
SebastianAppDev Dec 20, 2023
7982446
FIX: code issues
SebastianAppDev Dec 20, 2023
33cc493
Fix undefined ics file content
SebastianAppDev Jan 8, 2024
f31fae5
ics file update
SebastianAppDev Jan 8, 2024
8ac70fc
Fix typo
SebastianAppDev Apr 2, 2024
c889458
ENV setting to chose ics html or txt format
SebastianAppDev May 13, 2024
bb31c61
ShareRoomForm switched to relative root join urls
SebastianAppDev May 13, 2024
b3c0ad4
FIX defaultProp "room" defined for isRequired propType
SebastianAppDev May 13, 2024
baab248
FIX room.friendly_id undefined on room page
SebastianAppDev May 17, 2024
245f76c
Clean seperation of pr #5068 (in backend)
SebastianAppDev Jun 14, 2024
4a77fef
Merge master
SebastianAppDev Jun 14, 2024
6fed1f1
Clean seperation of pr #5068 (in backend)
SebastianAppDev Jun 14, 2024
a49d670
New ics Version
SebastianAppDev Jun 14, 2024
4755184
Fix err thrown without err
SebastianAppDev Jun 14, 2024
c9fd855
Access code integration
SebastianAppDev Jun 14, 2024
3ff3667
Fix code issues
SebastianAppDev Jun 14, 2024
c3b50ed
Removed changes to unrelated files
SebastianAppDev Jun 14, 2024
df7ef12
Removed changes to unrelated files
SebastianAppDev Jun 14, 2024
99503b0
Merge branch 'master' into ics
SebastianAppDev Jun 28, 2024
a17e905
Merge branch 'master' into ics
SebastianAppDev Jul 12, 2024
51f2ee2
Merge branch 'master' into ics
SebastianAppDev Sep 18, 2024
b9e484f
eslint
SebastianAppDev Sep 18, 2024
314102a
Merge branch 'ics' of github.com:SebastianAppDev/greenlight into ics
SebastianAppDev Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion app/assets/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"close": "Schließen",
"delete": "Löschen",
"copy": "Einladungslink kopieren",
"copy_voice_bridge": "Telefoneinwahl kopieren",
"copy_viewer_code": "Zugangscode für Zuhörerende kopieren",
"copy_moderator_code": "Zugangscode für Moderation kopieren",
"or": "oder",
Expand Down Expand Up @@ -125,7 +126,14 @@
"meeting_invitation": "Du wurdest zur Teilnahme eingeladen",
"meeting_not_started": "Die Konferenz hat noch nicht begonnen",
"join_meeting_automatically": "Beitritt erfolgt automatisch, sobald die Konferenz beginnt",
"recording_consent": "Ich nehme zur Kenntnis, dass die Sitzung aufgezeichnet werden kann. Dies wird meine Stimme und mein Bild einschließen, wenn dies aktiviert ist."
"recording_consent": "Ich nehme zur Kenntnis, dass die Sitzung aufgezeichnet werden kann. Dies wird meine Stimme und mein Bild einschließen, wenn dies aktiviert ist.",
"invite_to_meeting": "{{ name }} lädt Sie ein, an einem Meeting teilzunehmen.",
"join_by_url": "An Besprechung per URL teilnehmen",
"alternative_options": "Alternative Optionen zur Teilnahme",
"download_ics": ".ics-Kalenderdatei herunterladen",
"share_meeting": "Raum teilen",
"join_by_phone": "Mit Telefoneinwahl beitreten",
"location": "Videokonferenz, siehe Details im Termin"
},
"presentation": {
"presentation": "Präsentation",
Expand Down Expand Up @@ -403,6 +411,8 @@
"access_code_generated": "Zugangscode generiert.",
"access_code_deleted": "Zugriffcode wurde gelöscht.",
"copied_meeting_url": "Die URL der Konferenz wurde kopiert. Der Link kann verwendet werden, um an der Konferenz teilzunehmen.",
"download_ics": "Die .ics-Datei wurde erstellt. Öffnen Sie sie, um sie zu bearbeiten und zu versenden, um Personen zu Ihrem Meeting einzuladen.",
"copied_voice_bridge": "Die Telefonnummer und der Pin wurden kopiert. Diese können genutzt werden um an der Konferenz teilzunehmen.",
"copied_viewer_code": "Zugangscode für Zuhörende wurde in die Zwischenablage kopiert.",
"copied_moderator_code": "Zugangscode für Moderation wurde in die Zwischenablage kopiert."
},
Expand Down
12 changes: 11 additions & 1 deletion app/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"close": "Close",
"delete": "Delete",
"copy": "Copy Join Link",
"copy_voice_bridge": "Copy Phone Dialup",
"copy_viewer_code": "Copy Viewer Code",
"copy_moderator_code": "Copy Moderator Code",
"or": "Or",
Expand Down Expand Up @@ -126,7 +127,14 @@
"meeting_invitation": "You have been invited to join",
"meeting_not_started": "The meeting has not started yet",
"join_meeting_automatically": "You will automatically join when the meeting starts",
"recording_consent": "I acknowledge that this session may be recorded. This may include my voice and video if enabled."
"recording_consent": "I acknowledge that this session may be recorded. This may include my voice and video if enabled.",
"invite_to_meeting": "{{ name }} invites you to join a meeting.",
"join_by_url": "Join room by URL",
"alternative_options": "Alternative options to join",
"download_ics": "Download .ics calender file",
"share_meeting": "Share Room",
"join_by_phone": "Connect via telephone dial-up",
"location": "Video conference - Further details are provided below"
},
"presentation": {
"presentation": "Presentation",
Expand Down Expand Up @@ -412,6 +420,8 @@
"access_code_generated": "A new access code has been generated.",
"access_code_deleted": "The access code has been deleted.",
"copied_meeting_url": "The meeting URL has been copied. The link can be used to join the meeting.",
"download_ics": "The .ics file has been created. Open it to edit and send it, to invite people to your Meeting.",
"copied_voice_bridge": "The phone number and pin have been copied. They can be used to join the conference.",
"copied_viewer_code": "The viewer access code has been copied.",
"copied_moderator_code": "The moderator access code has been copied."
},
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/api/v1/env_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def index
HCAPTCHA_KEY: ENV.fetch('HCAPTCHA_SITE_KEY', nil),
VERSION_TAG: ENV.fetch('VERSION_TAG', ''),
CURRENT_PROVIDER: current_provider,
SMTP_ENABLED: ENV.fetch('SMTP_SERVER', nil)
SMTP_ENABLED: ENV.fetch('SMTP_SERVER', nil),
ICS_USE_HTML: ENV.fetch('ICS_USE_HTML', false)
}, status: :ok
end
end
Expand Down
57 changes: 29 additions & 28 deletions app/javascript/components/rooms/RoomCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ import React, { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Button, Card, Stack } from 'react-bootstrap';
import PropTypes from 'prop-types';
import { DocumentDuplicateIcon, LinkIcon } from '@heroicons/react/24/outline';
import { toast } from 'react-toastify';
import { ShareIcon, LinkIcon } from '@heroicons/react/24/outline';
import { useTranslation } from 'react-i18next';
import { useAuth } from '../../contexts/auth/AuthProvider';
import { localizeDateTimeString } from '../../helpers/DateTimeHelper';
import Spinner from '../shared_components/utilities/Spinner';
import useStartMeeting from '../../hooks/mutations/rooms/useStartMeeting';
import MeetingBadges from './MeetingBadges';
import UserBoardIcon from './UserBoardIcon';
import Modal from '../shared_components/modals/Modal';
import ShareRoomForm from './room/forms/ShareRoomForm';
import useRoomSettings from '../../hooks/queries/rooms/useRoomSettings';

export default function RoomCard({ room }) {
const { t } = useTranslation();
Expand All @@ -35,47 +37,50 @@ export default function RoomCard({ room }) {
const startMeeting = useStartMeeting(room.friendly_id);
const currentUser = useAuth();
const localizedTime = localizeDateTimeString(room?.last_session, currentUser?.language);

function copyInvite(friendlyId) {
navigator.clipboard.writeText(`${window.location}/${friendlyId}/join`);
toast.success(t('toast.success.room.copied_meeting_url'));
}
const roomSettings = useRoomSettings(room.friendly_id);

return (
<Card id="room-card" className="h-100 card-shadow border-0">
<Card.Body className="pb-0" onClick={handleClick}>
<Stack direction="horizontal">
<div className="room-icon rounded">
{ room?.shared_owner
{room?.shared_owner
? <LinkIcon className="hi-m text-brand pt-4 d-block mx-auto" />
: <UserBoardIcon className="hi-m text-brand pt-4 d-block mx-auto" />}
</div>
{ room?.online
{room?.online
&& <MeetingBadges count={room?.participants} />}
</Stack>

<Stack className="my-4">
<Card.Title className="mb-0"> { room.name } </Card.Title>
{ room.shared_owner && (
<span className="text-muted">{ t('room.shared_by') } {' '} <strong>{ room.shared_owner }</strong></span>
<Card.Title className="mb-0"> {room.name} </Card.Title>
{room.shared_owner && (
<span className="text-muted">{t('room.shared_by')} {' '} <strong>{room.shared_owner}</strong></span>
)}
{ room.last_session ? (
<span className="text-muted"> { t('room.last_session', { localizedTime }) } </span>
{room.last_session ? (
<span className="text-muted"> {t('room.last_session', { localizedTime })} </span>
) : (
<span className="text-muted mt-2"> { t('room.no_last_session') } </span>
<span className="text-muted mt-2"> {t('room.no_last_session')} </span>
)}
</Stack>
</Card.Body>
<Card.Footer className="bg-white">
<Button
variant="icon"
onClick={() => copyInvite(room.friendly_id)}
>
<DocumentDuplicateIcon className="hi-m mt-1 text-muted" />
</Button>
<Modal
size="lg"
modalButton={(
<Button
variant="icon"
>
<ShareIcon className="hi-m mt-1 text-muted" />
</Button>
)}
title={t('room.meeting.share_meeting')}
body={<ShareRoomForm room={room} friendly_id={room.friendly_id} roomSettings={roomSettings} />}
/>

<Button variant="brand-outline" className="btn btn-md float-end" onClick={startMeeting.mutate} disabled={startMeeting.isLoading}>
{startMeeting.isLoading && <Spinner className="me-2" />}
{ room.online ? (
{room.online ? (
t('join')
) : (
t('start')
Expand All @@ -86,12 +91,6 @@ export default function RoomCard({ room }) {
);
}

RoomCard.defaulProps = {
room: PropTypes.shape({
last_session: '',
}),
};

RoomCard.propTypes = {
room: PropTypes.shape({
id: PropTypes.string.isRequired,
Expand All @@ -101,5 +100,7 @@ RoomCard.propTypes = {
shared_owner: PropTypes.string,
online: PropTypes.bool,
participants: PropTypes.number,
voice_bridge: PropTypes.string,
voice_bridge_phone_number: PropTypes.string,
}).isRequired,
};
98 changes: 37 additions & 61 deletions app/javascript/components/rooms/room/Room.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@

import React from 'react';
import {
Stack, Button, Col, Row, Dropdown,
Stack, Button, Col, Row,
} from 'react-bootstrap';
import { Link, useParams } from 'react-router-dom';
import { HomeIcon, Square2StackIcon } from '@heroicons/react/24/outline';
import { toast } from 'react-toastify';
import { HomeIcon, ShareIcon } from '@heroicons/react/24/outline';
import { useTranslation } from 'react-i18next';
import { useAuth } from '../../../contexts/auth/AuthProvider';
import { localizeDayDateTimeString } from '../../../helpers/DateTimeHelper';
Expand All @@ -31,6 +30,8 @@ import useStartMeeting from '../../../hooks/mutations/rooms/useStartMeeting';
import MeetingBadges from '../MeetingBadges';
import SharedBadge from './SharedBadge';
import RoomNamePlaceHolder from './RoomNamePlaceHolder';
import Modal from '../../shared_components/modals/Modal';
import ShareRoomForm from './forms/ShareRoomForm';
import Title from '../../shared_components/utilities/Title';
import useRoomSettings from '../../../hooks/queries/rooms/useRoomSettings';

Expand All @@ -45,19 +46,6 @@ export default function Room() {
const localizedTime = localizeDayDateTimeString(room?.last_session, currentUser?.language);
const roomSettings = useRoomSettings(friendlyId);

function copyInvite(role) {
if (role === 'viewer') {
navigator.clipboard.writeText(roomSettings?.data?.glViewerAccessCode);
toast.success(t('toast.success.room.copied_viewer_code'));
} else if (role === 'moderator') {
navigator.clipboard.writeText(roomSettings?.data?.glModeratorAccessCode);
toast.success(t('toast.success.room.copied_moderator_code'));
} else {
navigator.clipboard.writeText(`${window.location}/join`);
toast.success(t('toast.success.room.copied_meeting_url'));
}
}

return (
<>
<Title>{room?.name}</Title>
Expand All @@ -72,27 +60,27 @@ export default function Room() {
<Row className="py-5">
<Col className="col-4">
{
isRoomLoading
? (
<RoomNamePlaceHolder />
) : (
<Stack className="room-header-wrapper">
<Stack direction="horizontal" gap={2}>
<h1>{room?.name}</h1>
<Stack direction="horizontal" className="mb-1">
{ room?.online
&& <MeetingBadges count={room?.participants} />}
{ room?.shared && <SharedBadge ownerName={room?.owner_name} /> }
</Stack>
isRoomLoading
? (
<RoomNamePlaceHolder />
) : (
<Stack className="room-header-wrapper">
<Stack direction="horizontal" gap={2}>
<h1>{room?.name}</h1>
<Stack direction="horizontal" className="mb-1">
{room?.online
&& <MeetingBadges count={room?.participants} />}
{room?.shared && <SharedBadge ownerName={room?.owner_name} />}
</Stack>
{ room?.last_session ? (
<span className="text-muted"> { t('room.last_session', { localizedTime }) } </span>
) : (
<span className="text-muted"> { t('room.no_last_session') } </span>
)}
</Stack>
)
}
{room?.last_session ? (
<span className="text-muted"> {t('room.last_session', { localizedTime })} </span>
) : (
<span className="text-muted"> {t('room.no_last_session')} </span>
)}
</Stack>
)
}
</Col>
<Col>
<Row>
Expand All @@ -104,39 +92,27 @@ export default function Room() {
disabled={startMeeting.isLoading}
>
{startMeeting.isLoading && <Spinner className="me-2" />}
{ room?.online ? (
{room?.online ? (
t('room.meeting.join_meeting')
) : (
t('room.meeting.start_meeting')
)}
</Button>

<Dropdown className="btn-group mt-1 mx-2 float-end pb-5">
<Button variant="brand-outline" type="button" className="btn dropdown-main" onClick={() => copyInvite()}>
<Square2StackIcon className="hi-s me-1" />
{ t('copy') }
</Button>
{ (roomSettings?.data?.glModeratorAccessCode || roomSettings?.data?.glViewerAccessCode) && (
<Dropdown.Toggle
<Modal
size="lg"
modalButton={(
<Button
variant="brand-outline"
className="btn dropdown-toggle dropdown-toggle-split"
id="dropdown-toggle"
/>
className="mt-1 mx-2 float-end"
type="button"
>
<ShareIcon className="hi-s me-1" />
{t('room.meeting.share_meeting')}
</Button>
)}

<Dropdown.Menu className="dropdown-menu">
{ roomSettings?.data?.glModeratorAccessCode && (
<Dropdown.Item onClick={() => copyInvite('moderator')}>
{ t('copy_moderator_code') }
</Dropdown.Item>
)}
{ roomSettings?.data?.glViewerAccessCode && (
<Dropdown.Item onClick={() => copyInvite('viewer')}>
{ t('copy_viewer_code') }
</Dropdown.Item>
)}
</Dropdown.Menu>
</Dropdown>
title={t('room.meeting.share_meeting')}
body={<ShareRoomForm room={room} roomSettings={roomSettings} />}
/>
</Col>
</Row>
</Col>
Expand Down
Loading
Loading