Skip to content
Snippets Groups Projects
Unverified Commit fc8df881 authored by Ahmad Farhat's avatar Ahmad Farhat Committed by GitHub
Browse files

Various improvements throughout the app (#5325)

* Various improvements

* Invalidate right queries

* Improve recording visibility dropdown

* Fix min width

* Fix dropdown overflow

* small styling
parent 4b5f0dea
No related branches found
No related tags found
No related merge requests found
......@@ -441,6 +441,43 @@ input.search-bar {
}
}
.simple-select {
button {
background: white !important;
color: black !important;
border-color: gainsboro !important;
text-align: left;
width: 220px;
&:hover, &:focus, &:active {
background: white !important;
color: black !important;
border-color: gainsboro !important;
}
&:focus {
box-shadow: 0 0 0 0.25rem var(--brand-color-light) !important;
}
&::after {
display: none;
}
}
.dropdown-menu {
min-width: 220px;
}
}
@media (max-width: 767px) {
.table-responsive .dropdown-menu {
position: static !important;
}
}
@media (min-width: 768px) {
.table-responsive {
overflow: visible;
}
}
input[type='text']:focus {
border-color: whitesmoke !important;
box-shadow: 0 0 0 2px var(--brand-color-light) !important;
......
......@@ -15,11 +15,13 @@
// with Greenlight; if not, see <http://www.gnu.org/licenses/>.
#user-recordings, #room-recordings {
min-height: 400px;
table {
border-top-right-radius: $border-radius-lg;
border-top-left-radius: $border-radius-lg;
border-spacing: 0;
overflow: hidden;
border-top-width: 0 !important;
}
tr {
......
......@@ -17,7 +17,6 @@
import {
VideoCameraIcon, TrashIcon, PencilSquareIcon, ClipboardDocumentIcon, EllipsisVerticalIcon,
} from '@heroicons/react/24/outline';
import Form from 'react-bootstrap/Form';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import {
......@@ -32,6 +31,7 @@ import Modal from '../shared_components/modals/Modal';
import { localizeDateTimeString } from '../../helpers/DateTimeHelper';
import useRedirectRecordingUrl from '../../hooks/mutations/recordings/useRedirectRecordingUrl';
import useCopyRecordingUrl from '../../hooks/mutations/recordings/useCopyRecordingUrl';
import SimpleSelect from '../shared_components/utilities/SimpleSelect';
// TODO: Amir - Refactor this.
export default function RecordingRow({
......@@ -102,29 +102,48 @@ export default function RecordingRow({
<td className="border-0"> {t('recording.length_in_minutes', { recording })} </td>
<td className="border-0"> {recording.participants} </td>
<td className="border-0">
{/* TODO: Refactor this. */}
<Form.Select
className="visibility-dropdown"
onChange={(event) => {
visibilityAPI.mutate({ visibility: event.target.value, id: recording.record_id });
}}
<SimpleSelect
defaultValue={recording.visibility}
disabled={visibilityAPI.isLoading}
>
<option value="Published">{t('recording.published')}</option>
<option value="Unpublished">{t('recording.unpublished')}</option>
{recording?.protectable === true
&& (
<>
<option value="Protected">{t('recording.protected')}</option>
<option value="Public/Protected">{t('recording.public_protected')}</option>
</>
)}
<option value="Public">{t('recording.public')}</option>
</Form.Select>
<Dropdown.Item
key="Public/Protected"
value="Public/Protected"
onClick={() => visibilityAPI.mutate({ visibility: 'Public/Protected', id: recording.record_id })}
>
{t('recording.public_protected')}
</Dropdown.Item>
<Dropdown.Item
key="Public"
value="Public"
onClick={() => visibilityAPI.mutate({ visibility: 'Public', id: recording.record_id })}
>
{t('recording.public')}
</Dropdown.Item>
<Dropdown.Item
key="Protected"
value="Protected"
onClick={() => visibilityAPI.mutate({ visibility: 'Protected', id: recording.record_id })}
>
{t('recording.protected')}
</Dropdown.Item>
<Dropdown.Item
key="Published"
value="Published"
onClick={() => visibilityAPI.mutate({ visibility: 'Published', id: recording.record_id })}
>
{t('recording.published')}
</Dropdown.Item>
<Dropdown.Item
key="Unpublished"
value="Unpublished"
onClick={() => visibilityAPI.mutate({ visibility: 'Unpublished', id: recording.record_id })}
>
{t('recording.unpublished')}
</Dropdown.Item>
</SimpleSelect>
</td>
<td className="border-0">
{formats.map((format) => (
{recording?.visibility !== 'Unpublished' && formats.map((format) => (
<Button
onClick={() => redirectRecordingUrl.mutate({ record_id: recording.record_id, format: format.recording_type })}
className={`btn-sm rounded-pill me-1 mt-1 border-0 btn-format-${format.recording_type.toLowerCase()}`}
......@@ -158,6 +177,7 @@ export default function RecordingRow({
)
: (
<Stack direction="horizontal" className="float-end recordings-icons">
{ recording?.visibility !== 'Unpublished' && (
<Button
variant="icon"
className="mt-1 me-3"
......@@ -165,6 +185,7 @@ export default function RecordingRow({
>
<ClipboardDocumentIcon className="hi-s text-muted" />
</Button>
)}
<Modal
modalButton={<Dropdown.Item className="btn btn-icon"><TrashIcon className="hi-s me-2" /></Dropdown.Item>}
body={(
......
// BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
//
// Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
//
// This program is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation; either version 3.0 of the License, or (at your option) any later
// version.
//
// Greenlight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along
// with Greenlight; if not, see <http://www.gnu.org/licenses/>.
import { Dropdown } from 'react-bootstrap';
import React from 'react';
import PropTypes from 'prop-types';
import { ChevronDownIcon } from '@heroicons/react/20/solid';
export default function SimpleSelect({ defaultValue, children }) {
// Get the currently selected option and set the dropdown toggle to that value
const defaultString = children?.filter((item) => item.props.value === defaultValue)[0];
return (
<Dropdown className="simple-select">
<Dropdown.Toggle>
{ defaultString?.props?.children }
<ChevronDownIcon className="hi-s float-end" />
</Dropdown.Toggle>
<Dropdown.Menu>
{children}
</Dropdown.Menu>
</Dropdown>
);
}
SimpleSelect.defaultProps = {
defaultValue: '',
children: undefined,
};
SimpleSelect.propTypes = {
defaultValue: PropTypes.string,
children: PropTypes.arrayOf(PropTypes.element),
};
......@@ -28,6 +28,8 @@ export default function useUpdateRecordingVisibility() {
{
onSuccess: () => {
queryClient.invalidateQueries(['getRecordings']);
queryClient.invalidateQueries(['getRoomRecordings']);
queryClient.invalidateQueries(['getServerRecordings']);
toast.success(t('toast.success.recording.recording_visibility_updated'));
},
onError: () => {
......
......@@ -20,4 +20,8 @@ class PublicRecordingSerializer < ApplicationSerializer
attributes :id, :record_id, :name, :length, :recorded_at
has_many :formats
def formats
object.formats.filter { |format| format.recording_type != 'statistics' }
end
end
......@@ -37,7 +37,7 @@ namespace :admin do
task :super_admin, %i[name email password] => :environment do |_task, args|
super_admin_email = "superadmin-#{args[:email]}"
user = User.create(
user = User.new(
name: args[:name],
email: super_admin_email,
password: args[:password],
......@@ -48,11 +48,16 @@ namespace :admin do
language: I18n.default_locale
)
if user.save
success 'User account was created successfully!'
info " Name: #{user.name}"
info " Email: #{user.email}"
info " Password: #{user.password}"
info " Role: #{user.role.name}"
else
warning 'There was an error creating this user'
err " Error: #{user.errors.full_messages}"
end
exit 0
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment