From 1dc3bccb0d8708b0227b97676ada6eae1faed20a Mon Sep 17 00:00:00 2001 From: Oswaldo Acauan Date: Wed, 3 May 2017 17:51:17 -0300 Subject: [PATCH] Add presenter upload capabilities --- .../server/methods/removePresentation.js | 2 +- .../server/methods/sharePresentation.js | 2 +- .../actions-dropdown/component.jsx | 25 +++++----- .../ui/components/actions-bar/component.jsx | 4 -- .../ui/components/checkbox/component.jsx | 13 +++-- .../ui/components/checkbox/styles.scss | 5 ++ .../ui/components/dropdown/list/component.jsx | 23 +++++---- .../presentation-uploader/component.jsx | 47 ++++++++++++------- .../presentation-uploader/service.js | 30 +++++++----- .../presentation-uploader/styles.scss | 11 +++++ 10 files changed, 102 insertions(+), 60 deletions(-) mode change 100644 => 100755 bigbluebutton-html5/imports/ui/components/checkbox/styles.scss diff --git a/bigbluebutton-html5/imports/api/presentations/server/methods/removePresentation.js b/bigbluebutton-html5/imports/api/presentations/server/methods/removePresentation.js index 00e1f4af72..98ca84900f 100755 --- a/bigbluebutton-html5/imports/api/presentations/server/methods/removePresentation.js +++ b/bigbluebutton-html5/imports/api/presentations/server/methods/removePresentation.js @@ -29,7 +29,7 @@ export default function removePresentation(credentials, presentationId) { } let payload = { - meeting_id: currentPoll.meetingId, + meeting_id: meetingId, presentation_id: presentationId, }; diff --git a/bigbluebutton-html5/imports/api/presentations/server/methods/sharePresentation.js b/bigbluebutton-html5/imports/api/presentations/server/methods/sharePresentation.js index 44c30f6dd9..0906f2fd96 100755 --- a/bigbluebutton-html5/imports/api/presentations/server/methods/sharePresentation.js +++ b/bigbluebutton-html5/imports/api/presentations/server/methods/sharePresentation.js @@ -19,7 +19,7 @@ export default function sharePresentation(credentials, presentationId, shouldSha check(shouldShare, Boolean); let payload = { - meeting_id: currentPoll.meetingId, + meeting_id: meetingId, presentation_id: presentationId, share: shouldShare, }; diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx index cb2efe4f75..f979d9851d 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/actions-dropdown/component.jsx @@ -1,5 +1,6 @@ import React, { Component, PropTypes } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; +import { withModalMounter } from '/imports/ui/components/modal/service'; import Button from '/imports/ui/components/button/component'; import Dropdown from '/imports/ui/components/dropdown/component'; @@ -8,6 +9,8 @@ import DropdownContent from '/imports/ui/components/dropdown/content/component'; import DropdownList from '/imports/ui/components/dropdown/list/component'; import DropdownListItem from '/imports/ui/components/dropdown/list/item/component'; +import PresentationUploderContainer from '/imports/ui/components/presentation/presentation-uploader/container'; + const intlMessages = defineMessages({ actionsLabel: { id: 'app.actionsBar.actionsDropdown.actionsLabel', @@ -39,22 +42,20 @@ const intlMessages = defineMessages({ }, }); -const presentation = () => {console.log('Should show the uploader component');}; - -const polling = () => {console.log('Should initiate a polling');}; - -const shareScreen = () => {console.log('Should start screen sharing');}; - class ActionsDropdown extends Component { constructor(props) { super(props); + this.handlePresentationClick = this.handlePresentationClick.bind(this); + } + + handlePresentationClick() { + this.props.mountModal(); } render() { const { intl, isUserPresenter } = this.props; - // if (!isUserPresenter) return null; - return null; // temporarily disabling the functionality + if (!isUserPresenter) return null; return ( @@ -74,12 +75,12 @@ class ActionsDropdown extends Component { icon="presentation" label={intl.formatMessage(intlMessages.presentationLabel)} description={intl.formatMessage(intlMessages.presentationDesc)} - onClick={presentation.bind(this)} + onClick={this.handlePresentationClick} /> {/* These icons are unaligned because of the font issue Check it later */} - + /> */} @@ -98,4 +99,4 @@ class ActionsDropdown extends Component { } } -export default injectIntl(ActionsDropdown); +export default withModalMounter(injectIntl(ActionsDropdown)); diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx index 3ddb8eef2e..02643917d2 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/component.jsx @@ -5,9 +5,6 @@ import ActionsDropdown from './actions-dropdown/component'; import JoinAudioOptionsContainer from '../audio/audio-menu/container'; import MuteAudioContainer from './mute-button/container'; -import { showModal } from '../app/service'; -import PresentationUploderContainer from '../presentation/presentation-uploader/container' - export default class ActionsBar extends Component { constructor(props) { super(props); @@ -20,7 +17,6 @@ export default class ActionsBar extends Component {
-
diff --git a/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx b/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx index a801b18e19..74443730d8 100755 --- a/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/checkbox/component.jsx @@ -13,22 +13,25 @@ export default class Checkbox extends Component { } handleChange() { - this.onChange(); + if (!this.props.disabled) + this.onChange(); } render() { - - const { ariaLabel, ariaLabelledBy, ariaDesc, ariaDescribedBy, } = this.props; + const { className, ariaLabel, ariaLabelledBy, ariaDesc, ariaDescribedBy, disabled } = this.props; return ( -
+
+ aria-describedby={ariaDescribedBy} + disabled={disabled} />
{ this.props.checked ? : diff --git a/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss b/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss old mode 100644 new mode 100755 index c1fe34b315..3ff3b79333 --- a/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/checkbox/styles.scss @@ -11,6 +11,11 @@ width: 1px; } +.disabled .icon { + opacity: .5; + cursor: not-allowed; +} + .icon { cursor: pointer; font-size: 1.35rem; diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx index c355a4fc27..be1890810d 100755 --- a/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/dropdown/list/component.jsx @@ -9,16 +9,19 @@ import ListSeparator from './separator/component'; import ListTitle from './title/component'; const propTypes = { - children: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => { - if (propValue[key].type !== ListItem && - propValue[key].type !== ListSeparator && - propValue[key].type !== ListTitle) { - return new Error( - 'Invalid prop `' + propFullName + '` supplied to' + - ' `' + componentName + '`. Validation failed.' - ); - } - }), + children: PropTypes.oneOfType([ + PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => { + if (propValue[key].type !== ListItem && + propValue[key].type !== ListSeparator && + propValue[key].type !== ListTitle) { + return new Error( + 'Invalid prop `' + propFullName + '` supplied to' + + ' `' + componentName + '`. Validation failed.' + ); + } + }), + PropTypes.element, + ]).isRequired, }; export default class DropdownList extends Component { diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx index d7445e71b2..6ce83b31a1 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { defineMessages, injectIntl, FormattedDate } from 'react-intl'; import update from 'immutability-helper'; -import ModalFullscreen from '/imports/ui/components/modal/component'; +import ModalFullscreen from '/imports/ui/components/modal/fullscreen/component'; import Icon from '/imports/ui/components/icon/component'; import ButtonBase from '/imports/ui/components/button/base/component'; import Checkbox from '/imports/ui/components/checkbox/component'; @@ -83,13 +83,18 @@ class PresentationUploder extends Component { file: file, filename: file.name, uploadedAt: new Date(), - isCurrent: false, + isCurrent: true, isUploaded: false, isProcessed: false, })); this.setState(({ presentations }) => ({ - presentations: presentations.concat(presentationsToUpload), + presentations: presentations + .map(p => { + p.isCurrent = false; + return p; + }) + .concat(presentationsToUpload), })); } @@ -174,7 +179,7 @@ class PresentationUploder extends Component { } renderPresentationItem(item) { - const { isProcessing } = this.state; + const { isProcessing, presentations } = this.state; let itemClassName = {}; @@ -182,6 +187,8 @@ class PresentationUploder extends Component { itemClassName[styles.tableItemUploading] = item.isUploading; itemClassName[styles.tableItemProcessing] = item.isProcessing; + const hideActions = isProcessing || presentations.some(_ => !_.isUploaded); + return ( - - this.handleCurrentChange(item)} - /> - this.handleRemove(item)}> - - - + {hideActions ? null : ( + + this.handleCurrentChange(item)} + /> + this.handleRemove(item)}> + + + + )} ); } @@ -234,8 +246,11 @@ class PresentationUploder extends Component { fileValidMimeTypes, } = this.props; + // TODO: Change the multiple prop when the endpoint supports multiple files + return ( Presentations @@ -32,20 +32,28 @@ const uploadPresentation = (file, meetingID, endpoint) => { }); }; -const removePresentation = (presentationID) => { - return makeCall('removePresentation'); -}; +const uploadPresentations = (presentationsToUpload, meetingID, uploadEndpoint) => + Promise.all( + presentationsToUpload + .map(p => uploadPresentation(p.file, meetingID, uploadEndpoint)) + ); + +const removePresentation = presentationID => call('removePresentation', presentationID); + +const removePresentations = presentationsToRemove => + Promise.all(presentationsToRemove.map(p => removePresentation(p.id))); const persistPresentationChanges = (oldState, newState, uploadEndpoint) => { const presentationsToUpload = newState.filter(_ => !oldState.includes(_)); - const presentationsToDelete = oldState.filter(_ => !newState.includes(_)); + const presentationsToRemove = oldState.filter(_ => !newState.includes(_)); + const currentPresentation = newState.find(_ => _.isCurrent); + return new Promise((resolve, reject) => - Promise.resolve().then( - Promise.all(presentationsToUpload.map(p => - uploadPresentation(p.file, Auth.meetingID, uploadEndpoint))) - ).then( - Promise.all(presentationsToDelete.map(p => removePresentation(p.filename))) - ).then(() => makeCall('sharePresentation')) + uploadPresentations(presentationsToUpload, Auth.meetingID, uploadEndpoint) + .then(removePresentations.bind(null, presentationsToRemove)) + .then(call.bind(null, 'sharePresentation', currentPresentation.id, true)) + .then(resolve) + .catch(reject) ); }; diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/styles.scss b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/styles.scss index 2515568b59..23222ffae3 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/styles.scss @@ -3,6 +3,7 @@ .fileList { @include scrollbox-vertical(); + max-height: 50vh; } .table { @@ -75,6 +76,16 @@ background-color: transparentize($color-primary, .95); } +.itemAction { + display: inline-block; + border: none; + background: transparent; + cursor: pointer; + font-size: 1.35rem; + color: $color-gray-light; + padding: 0; +} + .dropzone { width: 100%; display: block;