Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 6 additions & 7 deletions app/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,13 @@
"protected": "Protected",
"public": "Public",
"public_protected": "Public/Protected",
"formats_help": "Shows the available playback types (for example, Presentation or Video). Clicking a format opens the BigBlueButton recording in a new tab.",
"formats_help": "Displays the available playback formats. Selecting a format opens the BigBlueButton Recording in a new tab",
"visibility_help": {
"title": "Recording visibility options",
"public_protected": "Public/Protected - The recording is available on the Public Recordings page that can be reached from the Room Join page. The link can only be viewed from within Greenlight",
"public": "Public - The recording is available on the Public Recordings page that can be reached from the Room Join page. The link can be shared with anyone",
"protected": "Protected - The recording must be viewed from within Greenlight",
"published": "Published - The recording is accessible to anyone with the link",
"unpublished": "Unpublished - The recording is not accessible to anyone"
"public_protected": "The recording is available on the Public Recordings page, accessible from the Room Join page. It can also be shared with others using a one-time access link",
"public": "The recording is available on the Public Recordings page, accessible from the Room Join page, and its link can be shared with anyone",
"protected": "The recording is accessible only to the room owner and can be shared with others using a one-time access link",
"published": "The recording is accessible to anyone who has the link",
"unpublished": "The recording is not accessible to anyone"
},
"length_in_minutes": "{{recording.length}} min.",
"processing_recording": "Processing recording, this may take several minutes...",
Expand Down
21 changes: 20 additions & 1 deletion app/assets/stylesheets/recordings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,23 @@
svg:hover {
color: var(--brand-color) !important;
}
}
}

.simple-select {
.recording-info {
display: inline-flex;
align-items: center;
}

.dropdown-toggle .recording-info {
visibility: hidden;
pointer-events: none;
min-width: 1.25rem;
justify-content: center;
}

.dropdown-menu .recording-info {
visibility: visible;
pointer-events: auto;
}
}
64 changes: 58 additions & 6 deletions app/javascript/components/recordings/RecordingRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// with Greenlight; if not, see <http://www.gnu.org/licenses/>.

import {
VideoCameraIcon, TrashIcon, PencilSquareIcon, ClipboardDocumentIcon,
VideoCameraIcon, TrashIcon, PencilSquareIcon, ClipboardDocumentIcon, QuestionMarkCircleIcon,
} from '@heroicons/react/24/outline';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
Expand All @@ -24,6 +24,7 @@ import {
} from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Popover from 'react-bootstrap/Popover';
import { useAuth } from '../../contexts/auth/AuthProvider';
import Spinner from '../shared_components/utilities/Spinner';
import UpdateRecordingForm from './forms/UpdateRecordingForm';
Expand Down Expand Up @@ -55,6 +56,22 @@ export default function RecordingRow({
(a, b) => (a.recording_type.toLowerCase() > b.recording_type.toLowerCase() ? 1 : -1),
);

const visibilityHelpText = {
'Public/Protected': t('recording.visibility_help.public_protected'),
Public: t('recording.visibility_help.public'),
Protected: t('recording.visibility_help.protected'),
Published: t('recording.visibility_help.published'),
Unpublished: t('recording.visibility_help.unpublished'),
};

const visibilityPopover = (visibilityKey) => (
<Popover className="ms-3">
<Popover.Body>
<p className="mb-0">{visibilityHelpText[visibilityKey]}</p>
</Popover.Body>
</Popover>
);

return (
<tr
key={recording.id}
Expand Down Expand Up @@ -114,7 +131,14 @@ export default function RecordingRow({
value="Public/Protected"
onClick={() => visibilityAPI.mutate({ visibility: 'Public/Protected', id: recording.record_id })}
>
{t('recording.public_protected')}
<Stack direction="horizontal" className="justify-content-between">
<span>{t('recording.public_protected')}</span>
<span className="recording-info">
<OverlayTrigger placement="right" trigger={['hover', 'focus']} overlay={visibilityPopover('Public/Protected')}>
<QuestionMarkCircleIcon className="hi-xs" />
</OverlayTrigger>
</span>
</Stack>
</Dropdown.Item>
)}

Expand All @@ -124,7 +148,14 @@ export default function RecordingRow({
value="Public"
onClick={() => visibilityAPI.mutate({ visibility: 'Public', id: recording.record_id })}
>
{t('recording.public')}
<Stack direction="horizontal" className="justify-content-between">
<span>{t('recording.public')}</span>
<span className="recording-info">
<OverlayTrigger placement="right" trigger={['hover', 'focus']} overlay={visibilityPopover('Public')}>
<QuestionMarkCircleIcon className="hi-xs" />
</OverlayTrigger>
</span>
</Stack>
</Dropdown.Item>
)}

Expand All @@ -134,7 +165,14 @@ export default function RecordingRow({
value="Protected"
onClick={() => visibilityAPI.mutate({ visibility: 'Protected', id: recording.record_id })}
>
{t('recording.protected')}
<Stack direction="horizontal" className="justify-content-between">
<span>{t('recording.protected')}</span>
<span className="recording-info">
<OverlayTrigger placement="right" trigger={['hover', 'focus']} overlay={visibilityPopover('Protected')}>
<QuestionMarkCircleIcon className="hi-xs" />
</OverlayTrigger>
</span>
</Stack>
</Dropdown.Item>
)}

Expand All @@ -144,7 +182,14 @@ export default function RecordingRow({
value="Published"
onClick={() => visibilityAPI.mutate({ visibility: 'Published', id: recording.record_id })}
>
{t('recording.published')}
<Stack direction="horizontal" className="justify-content-between">
<span>{t('recording.published')}</span>
<span className="recording-info">
<OverlayTrigger placement="right" trigger={['hover', 'focus']} overlay={visibilityPopover('Published')}>
<QuestionMarkCircleIcon className="hi-xs" />
</OverlayTrigger>
</span>
</Stack>
</Dropdown.Item>
)}

Expand All @@ -154,7 +199,14 @@ export default function RecordingRow({
value="Unpublished"
onClick={() => visibilityAPI.mutate({ visibility: 'Unpublished', id: recording.record_id })}
>
{t('recording.unpublished')}
<Stack direction="horizontal" className="justify-content-between">
<span>{t('recording.unpublished')}</span>
<span className="recording-info">
<OverlayTrigger placement="right" trigger={['hover', 'focus']} overlay={visibilityPopover('Unpublished')}>
<QuestionMarkCircleIcon className="hi-xs" />
</OverlayTrigger>
</span>
</Stack>
</Dropdown.Item>
)}
</SimpleSelect>
Expand Down
39 changes: 7 additions & 32 deletions app/javascript/components/recordings/RecordingsList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import {
Badge, Card, Stack, Table,
} from 'react-bootstrap';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';
import { useTranslation } from 'react-i18next';
import { QuestionMarkCircleIcon } from '@heroicons/react/24/outline';
import Popover from 'react-bootstrap/Popover';
import SortBy from '../shared_components/search/SortBy';
import RecordingsListRowPlaceHolder from './RecordingsListRowPlaceHolder';
import NoSearchResults from '../shared_components/search/NoSearchResults';
Expand All @@ -36,23 +36,12 @@ export default function RecordingsList({
}) {
const { t } = useTranslation();

const visibilityTooltip = (
<Tooltip id="recordings-visibility-tooltip" className="text-start">
<div className="fw-semibold mb-1">{t('recording.visibility_help.title')}</div>
<ul className="mb-0 ps-3">
<li>{t('recording.visibility_help.public_protected')}</li>
<li>{t('recording.visibility_help.public')}</li>
<li>{t('recording.visibility_help.protected')}</li>
<li>{t('recording.visibility_help.published')}</li>
<li>{t('recording.visibility_help.unpublished')}</li>
</ul>
</Tooltip>
);

const formatsTooltip = (
<Tooltip id="recordings-formats-tooltip" className="text-start">
{t('recording.formats_help')}
</Tooltip>
<Popover>
<Popover.Body>
<p className="mb-0">{t('recording.formats_help')}</p>
</Popover.Body>
</Popover>
);

if (!isLoading && recordings?.data?.length === 0 && !searchInput && recordingsProcessing === 0) {
Expand Down Expand Up @@ -90,21 +79,7 @@ export default function RecordingsList({
<th className="fw-normal border-end-0">{t('recording.name')}<SortBy fieldName="name" /></th>
<th className="fw-normal border-0">{t('recording.length')}<SortBy fieldName="length" /></th>
<th className="fw-normal border-0">{t('recording.users')}</th>
<th className="fw-normal border-0">
<Stack direction="horizontal" gap={1} className="align-items-center">
<span>{t('recording.visibility')}</span>
<SortBy fieldName="visibility" />
<OverlayTrigger
placement="top"
trigger={['hover', 'focus']}
overlay={visibilityTooltip}
>
<button type="button" className="btn btn-link p-0 border-0 d-inline-flex text-muted cursor-pointer">
<QuestionMarkCircleIcon className="hi-xs" />
</button>
</OverlayTrigger>
</Stack>
</th>
<th className="fw-normal border-0">{t('recording.visibility')}<SortBy fieldName="visibility" /></th>
<th className="fw-normal border-0">
<Stack direction="horizontal" gap={1} className="align-items-center">
<span>{t('recording.formats')}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export default function SimpleSelect({ defaultValue, dropUp, children }) {

return (
<Dropdown className="simple-select" drop={dropUp ? 'up' : undefined}>
<Dropdown.Toggle>
{ defaultString?.props?.children }
<ChevronDownIcon className="hi-s float-end" />
<Dropdown.Toggle className="d-inline-flex justify-content-between">
<span className="d-inline-flex">
{ defaultString?.props?.children }
</span>
<ChevronDownIcon className="hi-s" />
</Dropdown.Toggle>
<Dropdown.Menu>
{children}
Expand Down
Loading