Flow, coding style

This commit is contained in:
Lyubo Marinov 2017-10-06 15:15:51 -05:00
parent d4d2cb4aad
commit 2eb36c4053
8 changed files with 179 additions and 165 deletions

View File

@ -8,16 +8,6 @@
*/ */
export const CANCEL_LOGIN = Symbol('CANCEL_LOGIN'); export const CANCEL_LOGIN = Symbol('CANCEL_LOGIN');
/**
* The type of (redux) action which signals that the {@link WaitForOwnerDialog}
* has been canceled.
*
* {
* type: CANCEL_WAIT_FOR_OWNER
* }
*/
export const CANCEL_WAIT_FOR_OWNER = Symbol('CANCEL_WAIT_FOR_OWNER');
/** /**
* The type of (redux) action which signals that the cyclic operation of waiting * The type of (redux) action which signals that the cyclic operation of waiting
* for conference owner has been aborted. * for conference owner has been aborted.

View File

@ -1,11 +1,11 @@
/* @flow */ // @flow
import { appNavigate } from '../app';
import { checkIfCanJoin } from '../base/conference'; import { checkIfCanJoin } from '../base/conference';
import { openDialog } from '../base/dialog'; import { openDialog } from '../base/dialog';
import { import {
CANCEL_LOGIN, CANCEL_LOGIN,
CANCEL_WAIT_FOR_OWNER,
STOP_WAIT_FOR_OWNER, STOP_WAIT_FOR_OWNER,
UPGRADE_ROLE_FINISHED, UPGRADE_ROLE_FINISHED,
UPGRADE_ROLE_STARTED, UPGRADE_ROLE_STARTED,
@ -25,7 +25,7 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
* @param {string} password - The XMPP user's password. * @param {string} password - The XMPP user's password.
* @param {JitsiConference} conference - The conference for which the local * @param {JitsiConference} conference - The conference for which the local
* participant's role will be upgraded. * participant's role will be upgraded.
* @returns {function({ dispatch: Dispatch, getState: Function })} * @returns {Function}
*/ */
export function authenticateAndUpgradeRole( export function authenticateAndUpgradeRole(
id: string, id: string,
@ -79,13 +79,12 @@ export function cancelLogin() {
/** /**
* Cancels {@link WaitForOwnerDialog}. Will navigate back to the welcome page. * Cancels {@link WaitForOwnerDialog}. Will navigate back to the welcome page.
* *
* @returns {{ * @returns {Function}
* type: CANCEL_WAIT_FOR_OWNER
* }}
*/ */
export function cancelWaitForOwner() { export function cancelWaitForOwner() {
return { return (dispatch: Dispatch<*>) => {
type: CANCEL_WAIT_FOR_OWNER dispatch(stopWaitForOwner());
dispatch(appNavigate(undefined));
}; };
} }
@ -197,7 +196,7 @@ function _upgradeRoleStarted(thenableWithCancel) {
* start the process of "waiting for the owner" by periodically trying to join * start the process of "waiting for the owner" by periodically trying to join
* the room every five seconds. * the room every five seconds.
* *
* @returns {function({ dispatch: Dispatch })} * @returns {Function}
*/ */
export function waitForOwner() { export function waitForOwner() {
return (dispatch: Dispatch) => return (dispatch: Dispatch) =>

View File

@ -22,7 +22,6 @@ import {
} from './actions'; } from './actions';
import { import {
CANCEL_LOGIN, CANCEL_LOGIN,
CANCEL_WAIT_FOR_OWNER,
STOP_WAIT_FOR_OWNER, STOP_WAIT_FOR_OWNER,
WAIT_FOR_OWNER WAIT_FOR_OWNER
} from './actionTypes'; } from './actionTypes';
@ -40,8 +39,8 @@ import { LoginDialog, WaitForOwnerDialog } from './components';
MiddlewareRegistry.register(store => next => action => { MiddlewareRegistry.register(store => next => action => {
switch (action.type) { switch (action.type) {
case CANCEL_LOGIN: { case CANCEL_LOGIN: {
const { thenableWithCancel } const { dispatch, getState } = store;
= store.getState()['features/authentication']; const { thenableWithCancel } = getState()['features/authentication'];
thenableWithCancel && thenableWithCancel.cancel(); thenableWithCancel && thenableWithCancel.cancel();
@ -53,27 +52,18 @@ MiddlewareRegistry.register(store => next => action => {
// Instead of hiding show the new one. // Instead of hiding show the new one.
const result = next(action); const result = next(action);
store.dispatch(_openWaitForOwnerDialog()); dispatch(_openWaitForOwnerDialog());
return result; return result;
} }
// Go back to the app's entry point. // Go back to the app's entry point.
_hideLoginDialog(store); _hideLoginDialog(store);
store.dispatch(appNavigate(undefined)); dispatch(appNavigate(undefined));
} }
break; break;
} }
case CANCEL_WAIT_FOR_OWNER: {
const result = next(action);
store.dispatch(stopWaitForOwner());
store.dispatch(appNavigate(undefined));
return result;
}
case CONFERENCE_FAILED: case CONFERENCE_FAILED:
if (action.error.name if (action.error.name
=== JitsiConferenceErrors.AUTHENTICATION_REQUIRED) { === JitsiConferenceErrors.AUTHENTICATION_REQUIRED) {

View File

@ -71,6 +71,15 @@ export default class AbstractDialog extends Component {
this._mounted = false; this._mounted = false;
} }
/**
* Dispatches a redux action to hide this dialog.
*
* @returns {*} The return value of {@link hideDialog}.
*/
_hide() {
return this.props.dispatch(hideDialog());
}
_onCancel: () => void; _onCancel: () => void;
/** /**
@ -84,7 +93,7 @@ export default class AbstractDialog extends Component {
if ((typeof cancelDisabled === 'undefined' || !cancelDisabled) if ((typeof cancelDisabled === 'undefined' || !cancelDisabled)
&& (!onCancel || onCancel())) { && (!onCancel || onCancel())) {
this.props.dispatch(hideDialog()); this._hide();
} }
} }
@ -147,7 +156,7 @@ export default class AbstractDialog extends Component {
_onSubmitFulfilled() { _onSubmitFulfilled() {
this._mounted && this.setState({ submitting: false }); this._mounted && this.setState({ submitting: false });
this.props.dispatch(hideDialog()); this._hide();
} }
_onSubmitRejected: () => void; _onSubmitRejected: () => void;

View File

@ -1,4 +1,4 @@
export { default as Container } from './Container'; export { default as Container } from './Container';
export { default as MultiSelectAutocomplete } from './MultiSelectAutocomplete';
export { default as Text } from './Text'; export { default as Text } from './Text';
export { default as Watermarks } from './Watermarks'; export { default as Watermarks } from './Watermarks';
export { default as MultiSelectAutocomplete } from './MultiSelectAutocomplete';

View File

@ -1,3 +1,5 @@
// @flow
import Tabs from '@atlaskit/tabs'; import Tabs from '@atlaskit/tabs';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
@ -15,7 +17,12 @@ const THUMBNAIL_SIZE = {
}; };
const UPDATE_INTERVAL = 1000; const UPDATE_INTERVAL = 1000;
const TAB_CONFIGURATIONS = [ type TabConfiguration = {
defaultSelected?: boolean,
label: string,
type: string
};
const TAB_CONFIGURATIONS: Array<TabConfiguration> = [
{ {
/** /**
* The indicator which determines whether this tab configuration is * The indicator which determines whether this tab configuration is
@ -83,6 +90,14 @@ class DesktopPicker extends Component {
t: PropTypes.func t: PropTypes.func
}; };
_poller = null;
state = {
selectedSource: {},
tabsToPopulate: [],
typesToFetch: []
};
/** /**
* Initializes a new DesktopPicker instance. * Initializes a new DesktopPicker instance.
* *
@ -92,13 +107,7 @@ class DesktopPicker extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { // Bind event handlers so they are only bound once per instance.
selectedSource: {},
tabsToPopulate: [],
typesToFetch: []
};
this._poller = null;
this._onCloseModal = this._onCloseModal.bind(this); this._onCloseModal = this._onCloseModal.bind(this);
this._onPreviewClick = this._onPreviewClick.bind(this); this._onPreviewClick = this._onPreviewClick.bind(this);
this._onSubmit = this._onSubmit.bind(this); this._onSubmit = this._onSubmit.bind(this);
@ -175,12 +184,14 @@ class DesktopPicker extends Component {
); );
} }
_onCloseModal: (?string, string) => void;
/** /**
* Dispatches an action to hide the DesktopPicker and invokes the passed in * Dispatches an action to hide the DesktopPicker and invokes the passed in
* callback with a selectedSource, if any. * callback with a selectedSource, if any.
* *
* @param {string} id - The id of the DesktopCapturerSource to pass into the * @param {string} [id] - The id of the DesktopCapturerSource to pass into
* onSourceChoose callback. * the onSourceChoose callback.
* @param {string} type - The type of the DesktopCapturerSource to pass into * @param {string} type - The type of the DesktopCapturerSource to pass into
* the onSourceChoose callback. * the onSourceChoose callback.
* @returns {void} * @returns {void}
@ -190,6 +201,8 @@ class DesktopPicker extends Component {
this.props.dispatch(hideDialog()); this.props.dispatch(hideDialog());
} }
_onPreviewClick: (string, string) => void;
/** /**
* Sets the currently selected DesktopCapturerSource. * Sets the currently selected DesktopCapturerSource.
* *
@ -206,6 +219,27 @@ class DesktopPicker extends Component {
}); });
} }
/**
* Handles changing of allowed desktop sharing source types.
*
* @param {Array<string>} desktopSharingSourceTypes - The types that will be
* fetched and displayed.
* @returns {void}
*/
_onSourceTypesConfigChanged(desktopSharingSourceTypes = []) {
const tabsToPopulate
= TAB_CONFIGURATIONS.filter(({ type }) =>
desktopSharingSourceTypes.includes(type)
&& VALID_TYPES.includes(type));
this.setState({
tabsToPopulate,
typesToFetch: tabsToPopulate.map(c => c.type)
});
}
_onSubmit: () => void;
/** /**
* Request to close the modal and execute callbacks with the selected source * Request to close the modal and execute callbacks with the selected source
* id. * id.
@ -268,24 +302,7 @@ class DesktopPicker extends Component {
this._poller = null; this._poller = null;
} }
/** _updateSources: () => void;
* Handles changing of allowed desktop sharing source types.
*
* @param {Array<string>} desktopSharingSourceTypes - The types that will be
* fetched and displayed.
* @returns {void}
*/
_onSourceTypesConfigChanged(desktopSharingSourceTypes = []) {
const tabsToPopulate = TAB_CONFIGURATIONS.filter(
c => desktopSharingSourceTypes.includes(c.type)
&& VALID_TYPES.includes(c.type)
);
this.setState({
tabsToPopulate,
typesToFetch: tabsToPopulate.map(c => c.type)
});
}
/** /**
* Dispatches an action to get currently available DesktopCapturerSources. * Dispatches an action to get currently available DesktopCapturerSources.

View File

@ -1,3 +1,5 @@
// @flow
import Avatar from '@atlaskit/avatar'; import Avatar from '@atlaskit/avatar';
import InlineMessage from '@atlaskit/inline-message'; import InlineMessage from '@atlaskit/inline-message';
import { Immutable } from 'nuclear-js'; import { Immutable } from 'nuclear-js';
@ -8,8 +10,7 @@ import { connect } from 'react-redux';
import { getInviteURL } from '../../base/connection'; import { getInviteURL } from '../../base/connection';
import { Dialog, hideDialog } from '../../base/dialog'; import { Dialog, hideDialog } from '../../base/dialog';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import MultiSelectAutocomplete import { MultiSelectAutocomplete } from '../../base/react';
from '../../base/react/components/web/MultiSelectAutocomplete';
import { invitePeople, inviteRooms, searchPeople } from '../functions'; import { invitePeople, inviteRooms, searchPeople } from '../functions';
@ -67,6 +68,54 @@ class AddPeopleDialog extends Component {
t: PropTypes.func t: PropTypes.func
}; };
_multiselect = null;
_resourceClient = {
makeQuery: text => {
const {
_jwt,
_peopleSearchQueryTypes,
_peopleSearchUrl
} = this.props; // eslint-disable-line no-invalid-this
return (
searchPeople(
_peopleSearchUrl,
_jwt,
text,
_peopleSearchQueryTypes));
},
parseResults: response => response.map(user => {
return {
content: user.name,
elemBefore: <Avatar
size = 'medium'
src = { user.avatar } />,
item: user,
value: user.id
};
})
};
state = {
/**
* Indicating that an error occurred when adding people to the call.
*/
addToCallError: false,
/**
* Indicating that we're currently adding the new people to the
* call.
*/
addToCallInProgress: false,
/**
* The list of invite items.
*/
inviteItems: new Immutable.List()
};
/** /**
* Initializes a new {@code AddPeopleDialog} instance. * Initializes a new {@code AddPeopleDialog} instance.
* *
@ -76,56 +125,7 @@ class AddPeopleDialog extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { // Bind event handlers so they are only bound once per instance.
/**
* Indicating that an error occurred when adding people to the call.
*/
addToCallError: false,
/**
* Indicating that we're currently adding the new people to the
* call.
*/
addToCallInProgress: false,
/**
* The list of invite items.
*/
inviteItems: new Immutable.List()
};
this._multiselect = null;
this._resourceClient = {
makeQuery: text => {
const {
_jwt,
_peopleSearchQueryTypes,
_peopleSearchUrl
} = this.props;
return searchPeople(
_peopleSearchUrl,
_jwt,
text,
_peopleSearchQueryTypes
);
},
parseResults: response => response.map(user => {
const avatar = ( // eslint-disable-line no-extra-parens
<Avatar
size = 'medium'
src = { user.avatar } />
);
return {
content: user.name,
value: user.id,
elemBefore: avatar,
item: user
};
})
};
this._isAddDisabled = this._isAddDisabled.bind(this); this._isAddDisabled = this._isAddDisabled.bind(this);
this._onSelectionChange = this._onSelectionChange.bind(this); this._onSelectionChange = this._onSelectionChange.bind(this);
this._onSubmit = this._onSubmit.bind(this); this._onSubmit = this._onSubmit.bind(this);
@ -144,9 +144,9 @@ class AddPeopleDialog extends Component {
* invite. * invite.
*/ */
if (prevState.addToCallError if (prevState.addToCallError
&& !this.state.addToCallInProgress && !this.state.addToCallInProgress
&& !this.state.addToCallError && !this.state.addToCallError
&& this._multiselect) { && this._multiselect) {
this._multiselect.clear(); this._multiselect.clear();
} }
} }
@ -169,44 +169,22 @@ class AddPeopleDialog extends Component {
); );
} }
/** _isAddDisabled: () => boolean;
* Renders the input form.
*
* @returns {ReactElement}
* @private
*/
_renderUserInputForm() {
const { t } = this.props;
return (
<div className = 'add-people-form-wrap'>
{ this._renderErrorMessage() }
<MultiSelectAutocomplete
isDisabled
= { this.state.addToCallInProgress || false }
noMatchesFound = { t('addPeople.noResults') }
onSelectionChange = { this._onSelectionChange }
placeholder = { t('addPeople.searchPlaceholder') }
ref = { this._setMultiSelectElement }
resourceClient = { this._resourceClient }
shouldFitContainer = { true }
shouldFocus = { true } />
</div>
);
}
/** /**
* Indicates if the Add button should be disabled. * Indicates if the Add button should be disabled.
* *
* @private
* @returns {boolean} - True to indicate that the Add button should * @returns {boolean} - True to indicate that the Add button should
* be disabled, false otherwise. * be disabled, false otherwise.
* @private
*/ */
_isAddDisabled() { _isAddDisabled() {
return !this.state.inviteItems.length return !this.state.inviteItems.length
|| this.state.addToCallInProgress; || this.state.addToCallInProgress;
} }
_onSelectionChange: (Map<*, *>) => void;
/** /**
* Handles a selection change. * Handles a selection change.
* *
@ -222,6 +200,8 @@ class AddPeopleDialog extends Component {
}); });
} }
_onSubmit: () => void;
/** /**
* Handles the submit button action. * Handles the submit button action.
* *
@ -245,27 +225,28 @@ class AddPeopleDialog extends Component {
this.props._inviteUrl, this.props._inviteUrl,
this.props._jwt, this.props._jwt,
this.state.inviteItems.filter(i => i.type === 'user')) this.state.inviteItems.filter(i => i.type === 'user'))
.then(() => { .then(
this.setState({ /* onFulfilled */ () => {
addToCallInProgress: false this.setState({
}); addToCallInProgress: false
});
this.props.hideDialog(); this.props.hideDialog();
}) },
.catch(() => { /* onRejected */ () => {
this.setState({ this.setState({
addToCallInProgress: false, addToCallInProgress: false,
addToCallError: true addToCallError: true
});
}); });
});
} }
} }
/** /**
* Renders the error message if the add doesn't succeed. * Renders the error message if the add doesn't succeed.
* *
* @returns {ReactElement|null}
* @private * @private
* @returns {ReactElement|null}
*/ */
_renderErrorMessage() { _renderErrorMessage() {
if (!this.state.addToCallError) { if (!this.state.addToCallError) {
@ -304,6 +285,34 @@ class AddPeopleDialog extends Component {
); );
} }
/**
* Renders the input form.
*
* @private
* @returns {ReactElement}
*/
_renderUserInputForm() {
const { t } = this.props;
return (
<div className = 'add-people-form-wrap'>
{ this._renderErrorMessage() }
<MultiSelectAutocomplete
isDisabled
= { this.state.addToCallInProgress || false }
noMatchesFound = { t('addPeople.noResults') }
onSelectionChange = { this._onSelectionChange }
placeholder = { t('addPeople.searchPlaceholder') }
ref = { this._setMultiSelectElement }
resourceClient = { this._resourceClient }
shouldFitContainer = { true }
shouldFocus = { true } />
</div>
);
}
_setMultiSelectElement: (Object) => void;
/** /**
* Sets the instance variable for the multi select component * Sets the instance variable for the multi select component
* element so it can be accessed directly. * element so it can be accessed directly.
@ -338,13 +347,13 @@ function _mapStateToProps(state) {
return { return {
_conference: conference, _conference: conference,
_jwt: state['features/jwt'].jwt,
_inviteUrl: getInviteURL(state),
_inviteServiceUrl: inviteServiceUrl, _inviteServiceUrl: inviteServiceUrl,
_inviteUrl: getInviteURL(state),
_jwt: state['features/jwt'].jwt,
_peopleSearchQueryTypes: peopleSearchQueryTypes, _peopleSearchQueryTypes: peopleSearchQueryTypes,
_peopleSearchUrl: peopleSearchUrl _peopleSearchUrl: peopleSearchUrl
}; };
} }
export default translate( export default translate(connect(_mapStateToProps, { hideDialog })(
connect(_mapStateToProps, { hideDialog })(AddPeopleDialog)); AddPeopleDialog));

View File

@ -1,4 +1,4 @@
/* @flow */ // @flow
import { NativeModules } from 'react-native'; import { NativeModules } from 'react-native';
import uuid from 'uuid'; import uuid from 'uuid';
@ -238,9 +238,9 @@ function _onPerformEndCallAction({ callUUID }) {
const conference = getCurrentConference(getState); const conference = getCurrentConference(getState);
if (conference && conference.callUUID === callUUID) { if (conference && conference.callUUID === callUUID) {
// We arrive here when a call is ended by the system, for // We arrive here when a call is ended by the system, for example, when
// example when another incoming call is received and the user // another incoming call is received and the user selects "End &
// selects "End & Accept". // Accept".
delete conference.callUUID; delete conference.callUUID;
dispatch(appNavigate(undefined)); dispatch(appNavigate(undefined));
} }