Compare commits

...

4 Commits

Author SHA1 Message Date
damencho
029ca1753f Fixes renewing let's encrypt certificates when using jetty.
Uses webroot for obtaining certificate, avoids stopping jitsi-videobridge before obtaining certificate.
Adds a renew hook, where we reload apache or nginx and try to graceful shutdown jvb and restart it.
Before merging this we need to make sure graceful shutdown is enabled by default and also pubsub is enabled by default so after restarting jvb, jicofo will discover it.
2017-03-30 13:57:47 -05:00
virtuacoplenny
2301732e2d style: catalog all z-indexes and move toolbar down
All z-indexes found in css files have been moved into css
variables. If the z-index is used only once, the variable
name will be the same as the selector it is used in. If
the z-index is used multiple times, then the plain name
of $zindex# was used. This allowed a more confident
moving down of the toolbar so that the new modal dialog,
with z-index 500, could display on top of it.

#1436
2017-03-30 18:13:00 +01:00
virtuacoplenny
24ee8eb16a electron: add desktop picker
#1411
2017-03-30 17:58:31 +01:00
Lyubo Marinov
57065bb274 Update NPM dependencies/packages 2017-03-30 09:11:02 -05:00
28 changed files with 784 additions and 59 deletions

View File

@@ -39,6 +39,9 @@ import {
participantLeft,
participantRoleChanged
} from './react/features/base/participants';
import {
showDesktopPicker
} from './react/features/desktop-picker';
import {
mediaPermissionPromptVisibilityChanged,
suspendDetected
@@ -66,6 +69,16 @@ let DSExternalInstallationInProgress = false;
import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/VideoContainer";
/*
* Logic to open a desktop picker put on the window global for
* lib-jitsi-meet to detect and invoke
*/
window.JitsiMeetScreenObtainer = {
openDesktopPicker(onSourceChoose) {
APP.store.dispatch(showDesktopPicker(onSourceChoose));
}
};
/**
* Known custom conference commands.
*/

View File

@@ -84,7 +84,7 @@ form {
height: 74px;
background-size: contain;
background-repeat: no-repeat;
z-index: 2;
z-index: $zindex2;
}
.leftwatermark {
@@ -106,7 +106,7 @@ form {
font-size: 11pt;
color: rgba(255,255,255,.50);
text-decoration: none;
z-index: 100;
z-index: $poweredByZ;
}
.connected {

View File

@@ -212,24 +212,24 @@
line-height: 30px;
}
::-webkit-scrollbar {
:not(.default-scrollbar)::-webkit-scrollbar {
background: #06a5df;
width: 7px;
}
::-webkit-scrollbar-button {
:not(.default-scrollbar)::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-track {
:not(.default-scrollbar)::-webkit-scrollbar-track {
background: black;
}
::-webkit-scrollbar-track-piece {
:not(.default-scrollbar)::-webkit-scrollbar-track-piece {
background: black;
}
::-webkit-scrollbar-thumb {
:not(.default-scrollbar)::-webkit-scrollbar-thumb {
background: #06a5df;
border-radius: 4px;
}

View File

@@ -17,7 +17,7 @@
flex-direction: column-reverse;
flex-wrap: nowrap;
position: relative;
z-index: 1; // Set z-index to make element visible
z-index: $zindex1; // Set z-index to make element visible
width: $hideFilmstripButtonWidth;
button {
@@ -55,7 +55,7 @@
bottom: 0;
width:auto;
border: $thumbnailsBorder solid transparent;
z-index: 5;
z-index: $filmstripVideosZ;
transition: bottom 2s;
overflow: visible !important;
/*!!!Removes the gap between the local video container and the remote

View File

@@ -2,7 +2,7 @@
position: absolute;
top: 0;
left: 0;
z-index: 1010;
z-index: $jitsipopoverZ;
display: none;
max-width: 300px;
min-width: 100px;

View File

@@ -143,7 +143,7 @@
position: absolute;
top: 50%;
right: 8px;
z-index: 1;
z-index: $zindex1;
width: 0;
height: 0;
content: '';

View File

@@ -6,7 +6,7 @@
overflow: hidden;
padding: 20px;
margin-left: 10px;
z-index: 10;
z-index: $zindex10;
border-radius: $borderRadius;
background-attachment: scroll;
background-size: auto auto;

View File

@@ -1,6 +1,6 @@
.notice {
position: relative;
z-index: 3;
z-index: $zindex3;
margin-top: 6px;
&__message {

View File

@@ -2,7 +2,7 @@
position: absolute;
top: 0;
left: 0;
z-index: 1015;
z-index: $popoverZ;
display: none;
max-width: 300px;
min-width: 100px;

View File

@@ -10,7 +10,7 @@
position: absolute;
top: 0;
width: 0;
z-index: 800;
z-index: $sideToolbarContainerZ;
/**
* Labels inside the side panel.

View File

@@ -33,7 +33,7 @@
#subject {
position: relative;
z-index: 3;
z-index: $zindex3;
width: auto;
padding: 5px;
margin-left: 40%;
@@ -106,7 +106,7 @@
height: 50px;
cursor: pointer;
text-align: center;
z-index: 1;
z-index: $zindex1;
font-size: $toolbarFontSize !important;
line-height: 50px !important;
vertical-align: middle;

View File

@@ -104,13 +104,26 @@ $happySoftwareBackground: transparent;
/**
* Z-indexes. TODO: Replace this by a function.
*/
$tooltipsZ: 901;
$toolbarZ: 900;
$overlayZ: 902;
$notificationZ: 1012;
$ringingZ: 800;
$dropdownZ: 901;
$zindex0: 0;
$zindex1: 1;
$zindex2: 2;
$zindex3: 3;
$filmstripVideosZ: 5;
$zindex10: 10;
$reloadZ: 20;
$poweredByZ: 100;
$ringingZ: 300;
$sideToolbarContainerZ: 300;
$toolbarZ: 400;
$tooltipsZ: 401;
$dropdownMaskZ: 900;
$dropdownZ: 901;
$overlayZ: 902;
$jitsipopoverZ: 1010;
$centeredVideoLabelZ: 1011;
$notificationZ: 1012;
$popoverZ: 1015;
/**
* Font Colors

View File

@@ -31,7 +31,7 @@
&__toptoolbar {
position: absolute;
left: 0;
z-index: 3;
z-index: $zindex3;
width: 100%;
box-sizing: border-box; // Includes the padding in the 100% width.
}
@@ -59,7 +59,7 @@
float: left;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
z-index: 3;
z-index: $zindex3;
background: $dominantSpeakerBg;
color: $thumbnailPictogramColor;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
@@ -113,7 +113,7 @@
width: 100%;
height: 100%;
visibility: hidden;
z-index: 2;
z-index: $zindex2;
}
}
@@ -161,7 +161,7 @@
position: absolute;
left: 0;
top: 0;
z-index: 1;
z-index: $zindex1;
width: 100%;
height: 100%;
}
@@ -171,7 +171,7 @@
}
#etherpad {
z-index: 0;
z-index: $zindex0;
}
/**
@@ -193,7 +193,7 @@
overflow: hidden;
white-space: nowrap;
line-height: $thumbnailToolbarHeight;
z-index: 2;
z-index: $zindex2;
}
/**
@@ -233,7 +233,7 @@
padding: 3px 5px;
font-size: 9pt;
cursor: pointer;
z-index: 2;
z-index: $zindex2;
}
/**
@@ -283,7 +283,7 @@
top: 0px;
right: 0;
margin: 7px;
z-index: 3;
z-index: $zindex3;
width: 18px;
height: 13px;
color: #FFF;
@@ -301,7 +301,7 @@
margin-top: -17px;
width: 6px;
height: 35px;
z-index: 2;
z-index: $zindex2;
border: none;
.audiodot-top,
@@ -344,13 +344,13 @@
background-clip: padding-box;
-webkit-border-radius: 5px;
-webkit-background-clip: padding-box;
z-index: 20; /*The reload button should appear on top of the header!*/
z-index: $reloadZ; /*The reload button should appear on top of the header!*/
}
.audiolevel {
display: inline-block;
position: absolute;
z-index: 0;
z-index: $zindex0;
border-radius:1px;
pointer-events: none;
}
@@ -408,7 +408,7 @@
.noMic {
position: absolute;
border-radius: 8px;
z-index: 1;
z-index: $zindex1;
width: 100%;
height: 100%;
background-image: url("../images/noMic.png");
@@ -420,7 +420,7 @@
.noVideo {
position: absolute;
border-radius: 8px;
z-index: 1;
z-index: $zindex1;
width: 100%;
height: 100%;
background-image: url("../images/noVideo.png");
@@ -453,7 +453,7 @@
display: none;
position: absolute;
width: auto;
z-index: 2;
z-index: $zindex2;
font-weight: 600;
font-size: 14px;
text-align: center;
@@ -477,7 +477,7 @@
left: 0;
width: 100%;
top:50%;
z-index: 2;
z-index: $zindex2;
font-weight: 600;
font-size: 14px;
text-align: center;
@@ -506,7 +506,7 @@
#videoResolutionLabel,
.centeredVideoLabel {
display: none;
z-index: 1011;
z-index: $centeredVideoLabelZ;
}
.centeredVideoLabel {

View File

@@ -22,7 +22,7 @@
font-weight: 500;
font-size: 16px;
color: #acacac;
z-index: 2;
z-index: $zindex2;
}
#disable_welcome:checked + label
@@ -35,7 +35,7 @@
font-weight: 500;
font-size: 16px;
color: #acacac;
z-index: 2;
z-index: $zindex2;
}
#enter_room_form {
@@ -74,7 +74,7 @@
float: left;
background-color: #FFFFFF;
position: relative;
z-index: 2;
z-index: $zindex2;
}
&__reload {
@@ -83,7 +83,7 @@
color: #acacac;
font-size: 1.9em;
line-height: 55px;
z-index: 3;
z-index: $zindex3;
float: left;
cursor: pointer;
text-align: center;
@@ -104,7 +104,7 @@
outline: none;
float:left;
position: relative;
z-index: 2;
z-index: $zindex2;
}
}

View File

@@ -37,6 +37,7 @@
@import 'overlay/overlay';
@import 'inlay';
@import 'reload_overlay/reload_overlay';
@import 'modals/desktop-picker/desktop-picker';
@import 'modals/dialog';
@import 'modals/feedback/feedback';
@import 'modals/speaker_stats/speaker_stats';

View File

@@ -0,0 +1,59 @@
.desktop-picker-pane {
height: 320px;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
&.source-type-screen {
.desktop-picker-source {
margin-left: auto;
margin-right: auto;
width: 50%;
}
.desktop-source-preview-thumbnail {
width: 100%;
}
.desktop-source-preview-label {
display: none;
}
}
&.source-type-window {
.desktop-picker-source {
display: inline-block;
width: 30%;
}
}
}
.desktop-picker-source {
color: $defaultDarkFontColor;
margin-top: 10px;
text-align: center;
&.is-selected {
.desktop-source-preview-image-container {
background: rgba(0, 0, 0, 0.1);
border-radius: $borderRadius;
}
}
}
.desktop-source-preview-label {
margin-top: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desktop-source-preview-thumbnail {
box-shadow: 5px 5px 5px grey;
height: auto;
max-width: 100%;
}
.desktop-source-preview-image-container {
padding: 10px;
}

View File

@@ -339,7 +339,10 @@
"remoteControlAllowedMessage": "__user__ accepted your remote control request!",
"remoteControlErrorMessage": "An error occurred while trying to request remote control permissions from __user__!",
"remoteControlStopMessage": "The remote control session ended!",
"close": "Close"
"close": "Close",
"shareYourScreen": "Share your screen",
"yourEntireScreen": "Your entire screen",
"applicationWindow": "Application window"
},
"email":
{

View File

@@ -20,14 +20,15 @@
"@atlaskit/button": "1.0.3",
"@atlaskit/button-group": "1.0.0",
"@atlaskit/modal-dialog": "1.2.4",
"@atlaskit/tabs": "1.2.5",
"async": "0.9.0",
"autosize": "1.18.13",
"bootstrap": "3.1.1",
"es6-iterator": "2.0.1",
"es6-symbol": "3.1.1",
"i18next": "7.1.2",
"i18next": "7.1.3",
"i18next-browser-languagedetector": "1.0.1",
"i18next-xhr-backend": "1.4.0",
"i18next-xhr-backend": "1.4.1",
"jitsi-meet-logger": "jitsi/jitsi-meet-logger",
"jquery": "2.1.4",
"jquery-contextmenu": "2.4.3",
@@ -40,7 +41,7 @@
"postis": "2.2.0",
"react": "15.4.2",
"react-dom": "15.4.2",
"react-i18next": "2.2.0",
"react-i18next": "2.2.3",
"react-native": "0.42.3",
"react-native-background-timer": "1.0.0",
"react-native-immersive": "0.0.4",
@@ -61,16 +62,16 @@
},
"devDependencies": {
"babel-core": "6.24.0",
"babel-eslint": "7.2.0",
"babel-eslint": "7.2.1",
"babel-loader": "6.4.1",
"babel-polyfill": "6.23.0",
"babel-preset-es2015": "6.24.0",
"babel-preset-react": "6.23.0",
"babel-preset-stage-1": "6.22.0",
"clean-css": "3.4.25",
"css-loader": "0.26.2",
"css-loader": "0.28.0",
"eslint": "3.18.0",
"eslint-plugin-flowtype": "2.30.3",
"eslint-plugin-flowtype": "2.30.4",
"eslint-plugin-import": "2.2.0",
"eslint-plugin-jsdoc": "3.0.0",
"eslint-plugin-react": "6.10.3",
@@ -84,8 +85,8 @@
"json-loader": "0.5.4",
"node-sass": "3.13.1",
"precommit-hook": "3.0.0",
"string-replace-loader": "1.0.5",
"style-loader": "0.15.0",
"string-replace-loader": "1.1.0",
"style-loader": "0.16.1",
"webpack": "1.14.0",
"webpack-dev-server": "1.16.3"
},

View File

@@ -0,0 +1,20 @@
import { Symbol } from '../base/react';
/**
* Action to remove known DesktopCapturerSources.
*
* {
* type: RESET_DESKTOP_SOURCES,
* }
*/
export const RESET_DESKTOP_SOURCES = Symbol('RESET_DESKTOP_SOURCES');
/**
* Action to replace stored DesktopCapturerSources with new sources.
*
* {
* type: UPDATE_DESKTOP_SOURCES,
* sources: {Array}
* }
*/
export const UPDATE_DESKTOP_SOURCES = Symbol('UPDATE_DESKTOP_SOURCES');

View File

@@ -0,0 +1,87 @@
import { getLogger } from 'jitsi-meet-logger';
import { openDialog } from '../base/dialog';
import {
RESET_DESKTOP_SOURCES,
UPDATE_DESKTOP_SOURCES
} from './actionTypes';
import { DesktopPicker } from './components';
const logger = getLogger(__filename);
/**
* Signals to remove all stored DesktopCapturerSources.
*
* @returns {{
* type: RESET_DESKTOP_SOURCES
* }}
*/
export function resetDesktopSources() {
return {
type: RESET_DESKTOP_SOURCES
};
}
/**
* Begins a request to get available DesktopCapturerSources.
*
* @param {Array} types - An array with DesktopCapturerSource type strings.
* @param {Object} options - Additional configuration for getting a list
* of sources.
* @param {Object} options.thumbnailSize - The desired height and width
* of the return native image object used for the preview image of the source.
* @returns {Function}
*/
export function obtainDesktopSources(types, options = {}) {
const capturerOptions = {
types
};
if (options.thumbnailSize) {
capturerOptions.thumbnailSize = options.thumbnailSize;
}
return dispatch => {
if (window.JitsiMeetElectron
&& window.JitsiMeetElectron.obtainDesktopStreams) {
window.JitsiMeetElectron.obtainDesktopStreams(
sources => dispatch(updateDesktopSources(sources)),
error => logger.error(
`Error while obtaining desktop sources: ${error}`),
capturerOptions
);
} else {
logger.error('Called JitsiMeetElectron.obtainDesktopStreams '
+ 'but it is not defined');
}
};
}
/**
* Signals to open a dialog with the DesktopPicker component.
*
* @param {Function} onSourceChoose - The callback to invoke when
* a DesktopCapturerSource has been chosen.
* @returns {Object}
*/
export function showDesktopPicker(onSourceChoose) {
return openDialog(DesktopPicker, {
onSourceChoose
});
}
/**
* Signals new DesktopCapturerSources have been received.
*
* @param {Object} sources - Arrays with DesktopCapturerSources.
* @returns {{
* type: UPDATE_DESKTOP_SOURCES,
* sources: Array
* }}
*/
export function updateDesktopSources(sources) {
return {
type: UPDATE_DESKTOP_SOURCES,
sources
};
}

View File

@@ -0,0 +1,264 @@
/* global config */
import Tabs from '@atlaskit/tabs';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Dialog, hideDialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import {
resetDesktopSources,
obtainDesktopSources
} from '../actions';
import DesktopPickerPane from './DesktopPickerPane';
const updateInterval = 1000;
const thumbnailSize = {
height: 300,
width: 300
};
const tabConfigurations = [
{
label: 'dialog.yourEntireScreen',
type: 'screen',
isDefault: true
},
{
label: 'dialog.applicationWindow',
type: 'window'
}
];
const validTypes = tabConfigurations.map(configuration => configuration.type);
const configuredTypes = config.desktopSharingChromeSources || [];
const tabsToPopulate = tabConfigurations.filter(configuration =>
configuredTypes.includes(configuration.type)
&& validTypes.includes(configuration.type)
);
const typesToFetch = tabsToPopulate.map(configuration => configuration.type);
/**
* React component for DesktopPicker.
*
* @extends Component
*/
class DesktopPicker extends Component {
/**
* DesktopPicker component's property types.
*
* @static
*/
static propTypes = {
/**
* Used to request DesktopCapturerSources.
*/
dispatch: React.PropTypes.func,
/**
* The callback to be invoked when the component is closed or
* when a DesktopCapturerSource has been chosen.
*/
onSourceChoose: React.PropTypes.func,
/**
* An object with arrays of DesktopCapturerSources. The key
* should be the source type.
*/
sources: React.PropTypes.object,
/**
* Used to obtain translations.
*/
t: React.PropTypes.func
}
/**
* Initializes a new DesktopPicker instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
super(props);
this.state = {
selectedSourceId: ''
};
this._poller = null;
this._onCloseModal = this._onCloseModal.bind(this);
this._onPreviewClick = this._onPreviewClick.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._updateSources = this._updateSources.bind(this);
}
/**
* Perform an immediate update request for DesktopCapturerSources and
* begin requesting updates at an interval.
*
* @inheritdoc
*/
componentWillMount() {
this._updateSources();
this._startPolling();
}
/**
* Clean up component and DesktopCapturerSource store state.
*
* @inheritdoc
*/
componentWillUnmount() {
this._stopPolling();
this.props.dispatch(resetDesktopSources());
}
/**
* Notifies this mounted React Component that it will receive new props.
* Sets a default selected source if one is not already set.
*
* @inheritdoc
* @param {Object} nextProps - The read-only React Component props that this
* instance will receive.
* @returns {void}
*/
componentWillReceiveProps(nextProps) {
if (!this.state.selectedSourceId
&& nextProps.sources.screen.length) {
this.setState({ selectedSourceId: nextProps.sources.screen[0].id });
}
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
*/
render() {
return (
<Dialog
isModal = { false }
okTitleKey = 'dialog.Share'
onCancel = { this._onCloseModal }
onSubmit = { this._onSubmit }
titleKey = 'dialog.shareYourScreen'
width = 'medium' >
{ this._renderTabs() }
</Dialog>);
}
/**
* Dispatches an action to get currently available DesktopCapturerSources.
*
* @private
* @returns {void}
*/
_updateSources() {
this.props.dispatch(obtainDesktopSources(
typesToFetch,
{
thumbnailSize
}
));
}
/**
* Create an interval to update knwon available DesktopCapturerSources.
*
* @private
* @returns {void}
*/
_startPolling() {
this._stopPolling();
this._poller = window.setInterval(this._updateSources,
updateInterval);
}
/**
* Cancels the interval to update DesktopCapturerSources.
*
* @private
* @returns {void}
*/
_stopPolling() {
window.clearInterval(this._poller);
this._poller = null;
}
/**
* Sets the currently selected DesktopCapturerSource.
*
* @param {string} id - The id of DesktopCapturerSource.
* @returns {void}
*/
_onPreviewClick(id) {
this.setState({ selectedSourceId: id });
}
/**
* Request to close the modal and execute callbacks
* with the selected source id.
*
* @returns {void}
*/
_onSubmit() {
this._onCloseModal(this.state.selectedSourceId);
}
/**
* Dispatches an action to hide the DesktopPicker and invokes
* the passed in callback with a selectedSourceId, if any.
*
* @param {string} id - The id of the DesktopCapturerSource to pass into
* the onSourceChoose callback.
* @returns {void}
*/
_onCloseModal(id = '') {
this.props.onSourceChoose(id);
this.props.dispatch(hideDialog());
}
/**
* Configures and renders the tabs for display.
*
* @returns {ReactElement}
* @private
*/
_renderTabs() {
const tabs = tabsToPopulate.map(tabConfig => {
const type = tabConfig.type;
return {
label: this.props.t(tabConfig.label),
defaultSelected: tabConfig.isDefault,
content: <DesktopPickerPane
key = { type }
onClick = { this._onPreviewClick }
onDoubleClick = { this._onCloseModal }
selectedSourceId = { this.state.selectedSourceId }
sources = { this.props.sources[type] || [] }
type = { type } />
};
});
return <Tabs tabs = { tabs } />;
}
}
/**
* Maps (parts of) the Redux state to the associated DesktopPicker's props.
*
* @param {Object} state - Redux state.
* @protected
* @returns {{
* sources: Object
* }}
*/
function mapStateToProps(state) {
return {
sources: state['features/desktop-picker/sources']
};
}
export default translate(connect(mapStateToProps)(DesktopPicker));

View File

@@ -0,0 +1,69 @@
import React, { Component } from 'react';
import DesktopSourcePreview from './DesktopSourcePreview';
/**
* React component for showing a grid of DesktopSourcePreviews.
*
* @extends Component
*/
class DesktopPickerPane extends Component {
/**
* DesktopPickerPane component's property types.
*
* @static
*/
static propTypes = {
/**
* The handler to be invoked when a DesktopSourcePreview is clicked.
*/
onClick: React.PropTypes.func,
/**
* The handler to be invoked when a DesktopSourcePreview is
* double clicked.
*/
onDoubleClick: React.PropTypes.func,
/**
* The id of the DesktopCapturerSource that is currently selected.
*/
selectedSourceId: React.PropTypes.string,
/**
* An array of DesktopCapturerSources.
*/
sources: React.PropTypes.array,
/**
* The source type of the DesktopCapturerSources to display.
*/
type: React.PropTypes.string
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const previews = this.props.sources.map(source =>
<DesktopSourcePreview
isSelected = { source.id === this.props.selectedSourceId }
key = { source.id }
onClick = { this.props.onClick }
onDoubleClick = { this.props.onDoubleClick }
source = { source } />
);
const classnames = 'desktop-picker-pane default-scrollbar '
+ `source-type-${this.props.type}`;
return (
<div className = { classnames }>
{ previews }
</div>
);
}
}
export default DesktopPickerPane;

View File

@@ -0,0 +1,97 @@
import React, { Component } from 'react';
/**
* React component for displaying a preview of a DesktopCapturerSource.
*
* @extends Component
*/
class DesktopSourcePreview extends Component {
/**
* DesktopSourcePreview component's property types.
*
* @static
*/
static propTypes = {
/**
* If true the 'is-selected' class will be added to the component.
*/
isSelected: React.PropTypes.bool,
/**
* The callback to invoke when the component is clicked.
* The id of the DesktopCapturerSource will be passed in.
*/
onClick: React.PropTypes.func,
/**
* The callback to invoke when the component is double clicked.
* The id of the DesktopCapturerSource will be passed in.
*/
onDoubleClick: React.PropTypes.func,
/**
* The DesktopCapturerSource to display.
*/
source: React.PropTypes.object
}
/**
* Initializes a new DesktopSourcePreview instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
super(props);
this._onClick = this._onClick.bind(this);
this._onDoubleClick = this._onDoubleClick.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const isSelectedClass = this.props.isSelected ? 'is-selected' : '';
const displayClasses = `desktop-picker-source ${isSelectedClass}`;
return (
<div
className = { displayClasses }
onClick = { this._onClick }
onDoubleClick = { this._onDoubleClick }>
<div className = 'desktop-source-preview-image-container'>
<img
className = 'desktop-source-preview-thumbnail'
src = { this.props.source.thumbnail.toDataURL() } />
</div>
<div className = 'desktop-source-preview-label'>
{ this.props.source.name }
</div>
</div>
);
}
/**
* Invokes the passed in onClick callback.
*
* @returns {void}
*/
_onClick() {
this.props.onClick(this.props.source.id);
}
/**
* Invokes the passed in onDoubleClick callback.
*
* @returns {void}
*/
_onDoubleClick() {
this.props.onDoubleClick(this.props.source.id);
}
}
export default DesktopSourcePreview;

View File

@@ -0,0 +1 @@
export { default as DesktopPicker } from './DesktopPicker';

View File

@@ -0,0 +1,5 @@
export * from './actionTypes';
export * from './actions';
export * from './components';
import './reducer';

View File

@@ -0,0 +1,59 @@
import { ReducerRegistry } from '../base/redux';
import {
RESET_DESKTOP_SOURCES,
UPDATE_DESKTOP_SOURCES
} from './actionTypes';
const defaultState = {
screen: [],
window: []
};
/**
* Listen for actions that mutate the known available DesktopCapturerSources.
*
* @param {Object[]} state - Current state.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @param {Array} action.sources - DesktopCapturerSources.
* @returns {Object}
*/
ReducerRegistry.register(
'features/desktop-picker/sources',
(state = defaultState, action) => {
switch (action.type) {
case RESET_DESKTOP_SOURCES:
return { ...defaultState };
case UPDATE_DESKTOP_SOURCES:
return seperateSourcesByType(action.sources);
default:
return state;
}
});
/**
* Converts an array of DesktopCapturerSources to an object with types
* for keys and values being an array with sources of the key's type.
*
* @param {Array} sources - DesktopCapturerSources.
* @returns {Object} An object with the sources split into seperate arrays
* based on source type.
* @private
*/
function seperateSourcesByType(sources = []) {
const sourcesByType = {
screen: [],
window: []
};
sources.forEach(source => {
const sourceIdParts = source.id.split(':');
const sourceType = sourceIdParts[0];
if (sourcesByType[sourceType]) {
sourcesByType[sourceType].push(source);
}
});
return sourcesByType;
}

View File

@@ -30,7 +30,7 @@ fi
CRON_FILE="/etc/cron.weekly/letsencrypt-renew"
echo "#!/bin/bash" > $CRON_FILE
echo "/usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log" >> $CRON_FILE
echo "/usr/local/sbin/certbot-auto --renew-hook '/usr/share/jitsi-meet/scripts/renew-letsencrypt-cert.sh' renew >> /var/log/le-renew.log" >> $CRON_FILE
CERT_KEY="/etc/letsencrypt/live/$DOMAIN/privkey.pem"
CERT_CRT="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
@@ -54,7 +54,6 @@ if [ -f /etc/nginx/sites-enabled/$DOMAIN.conf ] ; then
sed -i "s/ssl_certificate\ \/etc\/jitsi\/meet\/.*crt/ssl_certificate\ $CERT_CRT_ESC/g" \
$CONF_FILE
echo "service nginx reload" >> $CRON_FILE
service nginx reload
elif [ -f /etc/apache2/sites-enabled/$DOMAIN.conf ] ; then
@@ -76,13 +75,11 @@ elif [ -f /etc/apache2/sites-enabled/$DOMAIN.conf ] ; then
sed -i "s/SSLCertificateFile\ \/etc\/jitsi\/meet\/.*crt/SSLCertificateFile\ $CERT_CRT_ESC/g" \
$CONF_FILE
echo "service apache2 reload" >> $CRON_FILE
service apache2 reload
else
service jitsi-videobridge stop
./certbot-auto certonly --noninteractive \
--standalone \
--webroot --webroot-path /usr/share/jitsi-meet \
-d $DOMAIN \
--agree-tos --email $EMAIL
@@ -97,7 +94,14 @@ else
-srckeystore $CERT_P12 -srcstoretype pkcs12 \
-noprompt -storepass changeit -srcstorepass changeit
service jitsi-videobridge start
PIDFILE=/var/run/jitsi-videobridge.pid
if [ -f $PIDFILE ]; then
PID=$(cat $PIDFILE)
/usr/share/jitsi-videobridge/graceful_shutdown.sh $PID || true
fi
service jitsi-videobridge restart
fi

View File

@@ -0,0 +1,29 @@
#!/bin/bash
set -e
#
# This script is executed once a Lets Encrypt certificate had been renewed
# we reload web servers or in case of jetty we restart jvb
# In future we need to implement reloading jvb, which will reload the jetty
#
DEB_CONF_RESULT=`debconf-show jitsi-meet-web-config | grep jvb-hostname`
DOMAIN="${DEB_CONF_RESULT##*:}"
# remove whitespace
DOMAIN="$(echo -e "${DOMAIN}" | tr -d '[:space:]')"
if [ -f /etc/nginx/sites-enabled/$DOMAIN.conf ] ; then
service nginx reload
elif [ -f /etc/apache2/sites-enabled/$DOMAIN.conf ] ; then
service apache2 reload
else
PIDFILE=/var/run/jitsi-videobridge.pid
if [ -f $PIDFILE ]; then
PID=$(cat $PIDFILE)
/usr/share/jitsi-videobridge/graceful_shutdown.sh $PID || true
fi
service jitsi-videobridge restart
fi