ref(TS) Convert some features to TS (#12546)

This commit is contained in:
Robert Pintilii 2022-11-11 10:20:33 +02:00 committed by GitHub
parent a884a6b232
commit 7a9f51b01b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 141 additions and 137 deletions

1
globals.native.d.ts vendored
View File

@ -27,6 +27,7 @@ interface IWindow {
clearTimeout: typeof clearTimeout; clearTimeout: typeof clearTimeout;
setImmediate: typeof setImmediate; setImmediate: typeof setImmediate;
clearImmediate: typeof clearImmediate; clearImmediate: typeof clearImmediate;
addEventListener: Function;
} }
interface INavigator { interface INavigator {

View File

@ -58,6 +58,7 @@ export interface IJitsiConference {
isCallstatsEnabled: Function; isCallstatsEnabled: Function;
isEndConferenceSupported: Function; isEndConferenceSupported: Function;
isLobbySupported: Function; isLobbySupported: Function;
isSIPCallingSupported: Function;
isStartAudioMuted: Function; isStartAudioMuted: Function;
isStartVideoMuted: Function; isStartVideoMuted: Function;
join: Function; join: Function;

View File

@ -342,6 +342,7 @@ export interface IConfig {
iAmRecorder?: boolean; iAmRecorder?: boolean;
iAmSipGateway?: boolean; iAmSipGateway?: boolean;
inviteAppName?: string | null; inviteAppName?: string | null;
jaasActuatorUrl?: string;
jaasFeedbackMetadataURL?: string; jaasFeedbackMetadataURL?: string;
jaasTokenUrl?: string; jaasTokenUrl?: string;
lastNLimits?: { lastNLimits?: {
@ -391,6 +392,7 @@ export interface IConfig {
hideMuteAllButton?: boolean; hideMuteAllButton?: boolean;
}; };
pcStatsInterval?: number; pcStatsInterval?: number;
peopleSearchUrl?: string;
preferH264?: boolean; preferH264?: boolean;
preferredTranscribeLanguage?: string; preferredTranscribeLanguage?: string;
prejoinConfig?: { prejoinConfig?: {
@ -427,6 +429,7 @@ export interface IConfig {
mode?: 'always' | 'recording'; mode?: 'always' | 'recording';
}; };
serviceUrl?: string; serviceUrl?: string;
sipInviteUrl?: string;
speakerStats?: { speakerStats?: {
disableSearch?: boolean; disableSearch?: boolean;
disabled?: boolean; disabled?: boolean;

View File

@ -1,13 +1,12 @@
// @flow // @ts-expect-error
import { getJitsiMeetTransport } from '../../../modules/transport'; import { getJitsiMeetTransport } from '../../../modules/transport';
import { import {
CONFERENCE_FAILED, CONFERENCE_FAILED,
CONFERENCE_JOINED, CONFERENCE_JOINED,
DATA_CHANNEL_OPENED, DATA_CHANNEL_OPENED,
KICKED_OUT KICKED_OUT
} from '../base/conference'; } from '../base/conference/actionTypes';
import { SET_CONFIG } from '../base/config'; import { SET_CONFIG } from '../base/config/actionTypes';
import { NOTIFY_CAMERA_ERROR, NOTIFY_MIC_ERROR } from '../base/devices/actionTypes'; import { NOTIFY_CAMERA_ERROR, NOTIFY_MIC_ERROR } from '../base/devices/actionTypes';
import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; import { JitsiConferenceErrors } from '../base/lib-jitsi-meet';
import { import {
@ -16,21 +15,21 @@ import {
PARTICIPANT_KICKED, PARTICIPANT_KICKED,
PARTICIPANT_LEFT, PARTICIPANT_LEFT,
PARTICIPANT_ROLE_CHANGED, PARTICIPANT_ROLE_CHANGED,
SET_LOADABLE_AVATAR_URL, SET_LOADABLE_AVATAR_URL
} from '../base/participants/actionTypes';
import {
getDominantSpeakerParticipant, getDominantSpeakerParticipant,
getLocalParticipant, getLocalParticipant,
getParticipantById getParticipantById
} from '../base/participants'; } from '../base/participants/functions';
import { MiddlewareRegistry } from '../base/redux'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { getBaseUrl } from '../base/util'; import { getBaseUrl } from '../base/util/helpers';
import { appendSuffix } from '../display-name'; import { appendSuffix } from '../display-name/functions';
import { SUBMIT_FEEDBACK_ERROR, SUBMIT_FEEDBACK_SUCCESS } from '../feedback'; import { SUBMIT_FEEDBACK_ERROR, SUBMIT_FEEDBACK_SUCCESS } from '../feedback/actionTypes';
import { SET_FILMSTRIP_VISIBLE } from '../filmstrip'; import { SET_FILMSTRIP_VISIBLE } from '../filmstrip/actionTypes';
import './subscriber'; import './subscriber';
declare var APP: Object;
/** /**
* The middleware of the feature {@code external-api}. * The middleware of the feature {@code external-api}.
* *
@ -103,8 +102,8 @@ MiddlewareRegistry.register(store => next => action => {
const state = store.getState(); const state = store.getState();
const { defaultLocalDisplayName } = state['features/base/config']; const { defaultLocalDisplayName } = state['features/base/config'];
const { room } = state['features/base/conference']; const { room } = state['features/base/conference'];
const { loadableAvatarUrl, name, id, email } = getLocalParticipant(state); const { loadableAvatarUrl, name, id, email } = getLocalParticipant(state) ?? {};
const breakoutRoom = APP.conference.roomName.toString() !== room.toLowerCase(); const breakoutRoom = APP.conference.roomName.toString() !== room?.toLowerCase();
// we use APP.conference.roomName as we do not update state['features/base/conference'].room when // we use APP.conference.roomName as we do not update state['features/base/conference'].room when
// moving between rooms in case of breakout rooms and it stays always with the name of the main room // moving between rooms in case of breakout rooms and it stays always with the name of the main room
@ -114,7 +113,7 @@ MiddlewareRegistry.register(store => next => action => {
{ {
displayName: name, displayName: name,
formattedDisplayName: appendSuffix( formattedDisplayName: appendSuffix(
name, name ?? '',
defaultLocalDisplayName defaultLocalDisplayName
), ),
avatarURL: loadableAvatarUrl, avatarURL: loadableAvatarUrl,
@ -132,7 +131,7 @@ MiddlewareRegistry.register(store => next => action => {
case KICKED_OUT: case KICKED_OUT:
APP.API.notifyKickedOut( APP.API.notifyKickedOut(
{ {
id: getLocalParticipant(store.getState()).id, id: getLocalParticipant(store.getState())?.id,
local: true local: true
}, },
{ id: action.participant ? action.participant.getId() : undefined } { id: action.participant ? action.participant.getId() : undefined }
@ -142,7 +141,7 @@ MiddlewareRegistry.register(store => next => action => {
case NOTIFY_CAMERA_ERROR: case NOTIFY_CAMERA_ERROR:
if (action.error) { if (action.error) {
APP.API.notifyOnCameraError( APP.API.notifyOnCameraError(
action.error.name, action.error.message); action.error.name, action.error.message);
} }
break; break;

View File

@ -1,11 +1,7 @@
// @flow import { getLocalParticipant } from '../base/participants/functions';
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
import { getLocalParticipant } from '../base/participants'; import { appendSuffix } from '../display-name/functions';
import { StateListenerRegistry } from '../base/redux'; import { shouldDisplayTileView } from '../video-layout/functions';
import { appendSuffix } from '../display-name';
import { shouldDisplayTileView } from '../video-layout';
declare var APP: Object;
/** /**
* StateListenerRegistry provides a reliable way of detecting changes to * StateListenerRegistry provides a reliable way of detecting changes to

View File

@ -1,4 +1,4 @@
// @flow import { IStore } from '../app/types';
import { SET_DETAILS } from './actionTypes'; import { SET_DETAILS } from './actionTypes';
import { getVpaasTenant, sendGetDetailsRequest } from './functions'; import { getVpaasTenant, sendGetDetailsRequest } from './functions';
@ -10,7 +10,7 @@ import logger from './logger';
* @param {Object} details - The customer details object. * @param {Object} details - The customer details object.
* @returns {Object} * @returns {Object}
*/ */
function setCustomerDetails(details) { function setCustomerDetails(details: Object) {
return { return {
type: SET_DETAILS, type: SET_DETAILS,
payload: details payload: details
@ -23,7 +23,7 @@ function setCustomerDetails(details) {
* @returns {Function} * @returns {Function}
*/ */
export function getCustomerDetails() { export function getCustomerDetails() {
return async function(dispatch: Function, getState: Function) { return async function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
const state = getState(); const state = getState();
const baseUrl = state['features/base/config'].jaasActuatorUrl || 'https://api-vo-pilot.jitsi.net/jaas-actuator'; const baseUrl = state['features/base/config'].jaasActuatorUrl || 'https://api-vo-pilot.jitsi.net/jaas-actuator';
const appId = getVpaasTenant(state); const appId = getVpaasTenant(state);

View File

@ -1,8 +1,7 @@
// @flow import { IStore } from '../app/types';
import { openDialog } from '../base/dialog/actions';
import { openDialog } from '../base/dialog'; import PremiumFeatureDialog from './components/web/PremiumFeatureDialog';
import { PremiumFeatureDialog } from './components';
import { isFeatureDisabled } from './functions'; import { isFeatureDisabled } from './functions';
/** /**
@ -13,7 +12,7 @@ import { isFeatureDisabled } from './functions';
* @returns {Function} * @returns {Function}
*/ */
export function maybeShowPremiumFeatureDialog(feature: string) { export function maybeShowPremiumFeatureDialog(feature: string) {
return function(dispatch: Function, getState: Function) { return function(dispatch: IStore['dispatch'], getState: IStore['getState']) {
if (isFeatureDisabled(getState(), feature)) { if (isFeatureDisabled(getState(), feature)) {
dispatch(openDialog(PremiumFeatureDialog)); dispatch(openDialog(PremiumFeatureDialog));

View File

@ -1,6 +1,8 @@
import { createVpaasConferenceJoinedEvent, sendAnalytics } from '../analytics'; import { createVpaasConferenceJoinedEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IReduxState } from '../app/types';
import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
import { MiddlewareRegistry } from '../base/redux'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { getVpaasTenant, isVpaasMeeting } from './functions'; import { getVpaasTenant, isVpaasMeeting } from './functions';
@ -29,7 +31,7 @@ MiddlewareRegistry.register(store => next => async action => {
* @param {Store} state - The app state. * @param {Store} state - The app state.
* @returns {Function} * @returns {Function}
*/ */
function _maybeTrackVpaasConferenceJoin(state) { function _maybeTrackVpaasConferenceJoin(state: IReduxState) {
if (isVpaasMeeting(state)) { if (isVpaasMeeting(state)) {
sendAnalytics(createVpaasConferenceJoinedEvent( sendAnalytics(createVpaasConferenceJoinedEvent(
getVpaasTenant(state))); getVpaasTenant(state)));

View File

@ -1,10 +1,10 @@
import { redirectToStaticPage } from '../app/actions'; import { redirectToStaticPage } from '../app/actions.web';
import { CONFERENCE_JOINED } from '../base/conference/actionTypes'; import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
import { import {
JitsiConferenceErrors, JitsiConferenceErrors,
JitsiConferenceEvents JitsiConferenceEvents
} from '../base/lib-jitsi-meet'; } from '../base/lib-jitsi-meet';
import { MiddlewareRegistry } from '../base/redux'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { SET_DETAILS } from './actionTypes'; import { SET_DETAILS } from './actionTypes';
import { STATUSES } from './constants'; import { STATUSES } from './constants';
@ -27,7 +27,7 @@ MiddlewareRegistry.register(store => next => async action => {
} }
conference.on( conference.on(
JitsiConferenceEvents.CONFERENCE_ERROR, (errorType, errorMsg) => { JitsiConferenceEvents.CONFERENCE_ERROR, (errorType: string, errorMsg: string) => {
errorType === JitsiConferenceErrors.SETTINGS_ERROR && logger.error(errorMsg); errorType === JitsiConferenceErrors.SETTINGS_ERROR && logger.error(errorMsg);
}); });
break; break;

View File

@ -1,17 +1,17 @@
// @flow import { IStore } from '../app/types';
import { getMeetingRegion, getRecordingSharingUrl } from '../base/config/functions';
import { getMeetingRegion, getRecordingSharingUrl } from '../base/config';
import JitsiMeetJS, { JitsiRecordingConstants } from '../base/lib-jitsi-meet'; import JitsiMeetJS, { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
import { getLocalParticipant, getParticipantDisplayName } from '../base/participants'; import { getLocalParticipant, getParticipantDisplayName } from '../base/participants/functions';
import { copyText } from '../base/util/copyText'; import { copyText } from '../base/util/copyText';
import { getVpaasTenant, isVpaasMeeting } from '../jaas/functions'; import { getVpaasTenant, isVpaasMeeting } from '../jaas/functions';
import { import {
NOTIFICATION_TIMEOUT_TYPE,
hideNotification, hideNotification,
showErrorNotification, showErrorNotification,
showNotification, showNotification,
showWarningNotification showWarningNotification
} from '../notifications'; } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { INotificationProps } from '../notifications/types';
import { import {
CLEAR_RECORDING_SESSIONS, CLEAR_RECORDING_SESSIONS,
@ -31,8 +31,6 @@ import {
} from './functions'; } from './functions';
import logger from './logger'; import logger from './logger';
declare var APP: Object;
/** /**
* Clears the data of every recording sessions. * Clears the data of every recording sessions.
* *
@ -70,7 +68,7 @@ export function setHighlightMomentButtonState(disabled: boolean) {
* @returns {Function} * @returns {Function}
*/ */
export function hidePendingRecordingNotification(streamType: string) { export function hidePendingRecordingNotification(streamType: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { pendingNotificationUids } = getState()['features/recording']; const { pendingNotificationUids } = getState()['features/recording'];
const pendingNotificationUid = pendingNotificationUids[streamType]; const pendingNotificationUid = pendingNotificationUids[streamType];
@ -108,7 +106,7 @@ export function setLiveStreamKey(streamKey: string) {
* @returns {Function} * @returns {Function}
*/ */
export function showPendingRecordingNotification(streamType: string) { export function showPendingRecordingNotification(streamType: string) {
return async (dispatch: Function) => { return async (dispatch: IStore['dispatch']) => {
const isLiveStreaming const isLiveStreaming
= streamType === JitsiMeetJS.constants.recording.mode.STREAM; = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
const dialogProps = isLiveStreaming ? { const dialogProps = isLiveStreaming ? {
@ -209,13 +207,13 @@ export function showStoppedRecordingNotification(streamType: string, participant
*/ */
export function showStartedRecordingNotification( export function showStartedRecordingNotification(
mode: string, mode: string,
initiator: Object | string, initiator: { getId: Function; } | string,
sessionId: string) { sessionId: string) {
return async (dispatch: Function, getState: Function) => { return async (dispatch: Function, getState: Function) => {
const state = getState(); const state = getState();
const initiatorId = getResourceId(initiator); const initiatorId = getResourceId(initiator);
const participantName = getParticipantDisplayName(state, initiatorId); const participantName = getParticipantDisplayName(state, initiatorId);
let dialogProps = { let dialogProps: INotificationProps = {
descriptionKey: participantName ? 'liveStreaming.onBy' : 'liveStreaming.on', descriptionKey: participantName ? 'liveStreaming.onBy' : 'liveStreaming.on',
descriptionArguments: { name: participantName }, descriptionArguments: { name: participantName },
titleKey: 'dialog.liveStreaming' titleKey: 'dialog.liveStreaming'
@ -223,7 +221,7 @@ export function showStartedRecordingNotification(
if (mode !== JitsiMeetJS.constants.recording.mode.STREAM) { if (mode !== JitsiMeetJS.constants.recording.mode.STREAM) {
const recordingSharingUrl = getRecordingSharingUrl(state); const recordingSharingUrl = getRecordingSharingUrl(state);
const iAmRecordingInitiator = getLocalParticipant(state).id === initiatorId; const iAmRecordingInitiator = getLocalParticipant(state)?.id === initiatorId;
dialogProps = { dialogProps = {
customActionHandler: undefined, customActionHandler: undefined,
@ -278,7 +276,7 @@ export function showStartedRecordingNotification(
* sessionData: Object * sessionData: Object
* }} * }}
*/ */
export function updateRecordingSessionData(session: Object) { export function updateRecordingSessionData(session: any) {
const status = session.getStatus(); const status = session.getStatus();
const timestamp const timestamp
= status === JitsiRecordingConstants.status.ON = status === JitsiRecordingConstants.status.ON
@ -327,7 +325,7 @@ export function setSelectedRecordingService(selectedRecordingService: string) {
* uid: number * uid: number
* }} * }}
*/ */
function _setPendingRecordingNotificationUid(uid: ?number, streamType: string) { function _setPendingRecordingNotificationUid(uid: string | undefined, streamType: string) {
return { return {
type: SET_PENDING_RECORDING_NOTIFICATION_UID, type: SET_PENDING_RECORDING_NOTIFICATION_UID,
streamType, streamType,
@ -341,7 +339,7 @@ function _setPendingRecordingNotificationUid(uid: ?number, streamType: string) {
* @param {boolean} onlySelf - Whether to only record the local streams. * @param {boolean} onlySelf - Whether to only record the local streams.
* @returns {Object} * @returns {Object}
*/ */
export function startLocalVideoRecording(onlySelf) { export function startLocalVideoRecording(onlySelf: boolean) {
return { return {
type: START_LOCAL_RECORDING, type: START_LOCAL_RECORDING,
onlySelf onlySelf

View File

@ -1,7 +1,10 @@
import { openSheet } from '../base/dialog'; import { IStore } from '../app/types';
import { openSheet } from '../base/dialog/actions';
import JitsiMeetJS from '../base/lib-jitsi-meet'; import JitsiMeetJS from '../base/lib-jitsi-meet';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
// @ts-ignore
import HighlightDialog from './components/Recording/native/HighlightDialog'; import HighlightDialog from './components/Recording/native/HighlightDialog';
export * from './actions.any'; export * from './actions.any';
@ -12,7 +15,7 @@ export * from './actions.any';
* @returns {Function} * @returns {Function}
*/ */
export function openHighlightDialog() { export function openHighlightDialog() {
return (dispatch: Function) => { return (dispatch: IStore['dispatch']) => {
dispatch(openSheet(HighlightDialog)); dispatch(openSheet(HighlightDialog));
}; };
} }
@ -26,7 +29,7 @@ export function openHighlightDialog() {
* @returns {showNotification} * @returns {showNotification}
*/ */
export function showRecordingLimitNotification(streamType: string) { export function showRecordingLimitNotification(streamType: string) {
return (dispatch: Function, getState: Function) => { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const isLiveStreaming = streamType === JitsiMeetJS.constants.recording.mode.STREAM; const isLiveStreaming = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
let descriptionKey, titleKey; let descriptionKey, titleKey;

View File

@ -1,10 +1,10 @@
// @flow
import React from 'react'; import React from 'react';
import JitsiMeetJS from '../base/lib-jitsi-meet'; import JitsiMeetJS from '../base/lib-jitsi-meet';
import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
// @ts-ignore
import { RecordingLimitNotificationDescription } from './components'; import { RecordingLimitNotificationDescription } from './components';
export * from './actions.any'; export * from './actions.any';

View File

@ -1,13 +1,11 @@
// @flow
import { Component } from 'react'; import { Component } from 'react';
import { import { createRecordingDialogEvent } from '../../../analytics/AnalyticsEvents';
createRecordingDialogEvent, import { sendAnalytics } from '../../../analytics/functions';
sendAnalytics import { IReduxState } from '../../../app/types';
} from '../../../analytics'; import { IJitsiConference } from '../../../base/conference/reducer';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet'; import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { setVideoMuted } from '../../../base/media'; import { setVideoMuted } from '../../../base/media/actions';
import { stopLocalVideoRecording } from '../../actions'; import { stopLocalVideoRecording } from '../../actions';
import { getActiveSession } from '../../functions'; import { getActiveSession } from '../../functions';
@ -17,38 +15,38 @@ import LocalRecordingManager from './LocalRecordingManager';
* The type of the React {@code Component} props of * The type of the React {@code Component} props of
* {@link AbstractStopRecordingDialog}. * {@link AbstractStopRecordingDialog}.
*/ */
export type Props = { export interface IProps {
/** /**
* The {@code JitsiConference} for the current conference. * The {@code JitsiConference} for the current conference.
*/ */
_conference: Object, _conference: IJitsiConference;
/** /**
* The redux representation of the recording session to be stopped. * The redux representation of the recording session to be stopped.
*/ */
_fileRecordingSession: Object, _fileRecordingSession: Object;
/** /**
* Whether the recording is a local recording or not. * Whether the recording is a local recording or not.
*/ */
_localRecording: boolean, _localRecording: boolean;
/** /**
* The redux dispatch function. * The redux dispatch function.
*/ */
dispatch: Function, dispatch: Function;
/** /**
* The user trying to stop the video while local recording is running. * The user trying to stop the video while local recording is running.
*/ */
localRecordingVideoStop?: boolean, localRecordingVideoStop?: boolean;
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
*/ */
t: Function t: Function;
}; }
/** /**
* Abstract React Component for getting confirmation to stop a file recording * Abstract React Component for getting confirmation to stop a file recording
@ -56,7 +54,7 @@ export type Props = {
* *
* @augments Component * @augments Component
*/ */
export default class AbstractStopRecordingDialog<P: Props> export default class AbstractStopRecordingDialog<P extends IProps>
extends Component<P> { extends Component<P> {
/** /**
* Initializes a new {@code AbstrStopRecordingDialog} instance. * Initializes a new {@code AbstrStopRecordingDialog} instance.
@ -71,8 +69,6 @@ export default class AbstractStopRecordingDialog<P: Props>
this._toggleScreenshotCapture = this._toggleScreenshotCapture.bind(this); this._toggleScreenshotCapture = this._toggleScreenshotCapture.bind(this);
} }
_onSubmit: () => boolean;
/** /**
* Stops the recording session. * Stops the recording session.
* *
@ -90,7 +86,7 @@ export default class AbstractStopRecordingDialog<P: Props>
} else { } else {
const { _fileRecordingSession } = this.props; const { _fileRecordingSession } = this.props;
if (_fileRecordingSession) { if (_fileRecordingSession) { // @ts-ignore
this.props._conference.stopRecording(_fileRecordingSession.id); this.props._conference.stopRecording(_fileRecordingSession.id);
this._toggleScreenshotCapture(); this._toggleScreenshotCapture();
} }
@ -99,8 +95,6 @@ export default class AbstractStopRecordingDialog<P: Props>
return true; return true;
} }
_toggleScreenshotCapture: () => void;
/** /**
* Toggles screenshot capture feature. * Toggles screenshot capture feature.
* *
@ -122,7 +116,7 @@ export default class AbstractStopRecordingDialog<P: Props>
* _fileRecordingSession: Object * _fileRecordingSession: Object
* }} * }}
*/ */
export function _mapStateToProps(state: Object) { export function _mapStateToProps(state: IReduxState) {
return { return {
_conference: state['features/base/conference'].conference, _conference: state['features/base/conference'].conference,
_fileRecordingSession: _fileRecordingSession:

View File

@ -3,11 +3,20 @@ import { IStore } from '../../../app/types';
interface ILocalRecordingManager { interface ILocalRecordingManager {
addAudioTrackToLocalRecording: (track: any) => void; addAudioTrackToLocalRecording: (track: any) => void;
isRecordingLocally: () => boolean; isRecordingLocally: () => boolean;
startLocalRecording: (store: IStore) => void; selfRecording: {
on: boolean;
withVideo: boolean;
};
startLocalRecording: (store: IStore, onlySelf: boolean) => void;
stopLocalRecording: () => void; stopLocalRecording: () => void;
} }
const LocalRecordingManager: ILocalRecordingManager = { const LocalRecordingManager: ILocalRecordingManager = {
selfRecording: {
on: false,
withVideo: false
},
/** /**
* Adds audio track to the recording stream. * Adds audio track to the recording stream.
* *

View File

@ -1,11 +1,14 @@
// @flow import { IReduxState } from '../app/types';
import { isMobileBrowser } from '../base/environment/utils'; import { isMobileBrowser } from '../base/environment/utils';
import { isJwtFeatureEnabled } from '../base/jwt/functions'; import { isJwtFeatureEnabled } from '../base/jwt/functions';
import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet'; import { JitsiRecordingConstants, browser } from '../base/lib-jitsi-meet';
import { getLocalParticipant, getRemoteParticipants, isLocalParticipantModerator } from '../base/participants'; import {
getLocalParticipant,
getRemoteParticipants,
isLocalParticipantModerator
} from '../base/participants/functions';
import { isInBreakoutRoom } from '../breakout-rooms/functions'; import { isInBreakoutRoom } from '../breakout-rooms/functions';
import { isEnabled as isDropboxEnabled } from '../dropbox'; import { isEnabled as isDropboxEnabled } from '../dropbox/functions';
import { extractFqnFromPath } from '../dynamic-branding/functions.any'; import { extractFqnFromPath } from '../dynamic-branding/functions.any';
import LocalRecordingManager from './components/Recording/LocalRecordingManager'; import LocalRecordingManager from './components/Recording/LocalRecordingManager';
@ -20,7 +23,7 @@ import logger from './logger';
* @param {string} mode - Find an active recording session of the given mode. * @param {string} mode - Find an active recording session of the given mode.
* @returns {Object|undefined} * @returns {Object|undefined}
*/ */
export function getActiveSession(state: Object, mode: string) { export function getActiveSession(state: IReduxState, mode: string) {
const { sessionDatas } = state['features/recording']; const { sessionDatas } = state['features/recording'];
const { status: statusConstants } = JitsiRecordingConstants; const { status: statusConstants } = JitsiRecordingConstants;
@ -37,7 +40,7 @@ export function getActiveSession(state: Object, mode: string) {
* @param {number} size - The size in MB of the recorded video. * @param {number} size - The size in MB of the recorded video.
* @returns {number} - The estimated duration in minutes. * @returns {number} - The estimated duration in minutes.
*/ */
export function getRecordingDurationEstimation(size: ?number) { export function getRecordingDurationEstimation(size?: number | null) {
return Math.floor((size || 0) / 10); return Math.floor((size || 0) / 10);
} }
@ -49,7 +52,7 @@ export function getRecordingDurationEstimation(size: ?number) {
* @param {string} id - The ID of the recording session to find. * @param {string} id - The ID of the recording session to find.
* @returns {Object|undefined} * @returns {Object|undefined}
*/ */
export function getSessionById(state: Object, id: string) { export function getSessionById(state: IReduxState, id: string) {
return state['features/recording'].sessionDatas.find( return state['features/recording'].sessionDatas.find(
sessionData => sessionData.id === id); sessionData => sessionData.id === id);
} }
@ -81,7 +84,7 @@ export async function getRecordingLink(url: string, recordingSessionId: string,
* @param {Object} state - The redux state to search in. * @param {Object} state - The redux state to search in.
* @returns {string} * @returns {string}
*/ */
export function isSavingRecordingOnDropbox(state: Object) { export function isSavingRecordingOnDropbox(state: IReduxState) {
return isDropboxEnabled(state) return isDropboxEnabled(state)
&& state['features/recording'].selectedRecordingService === RECORDING_TYPES.DROPBOX; && state['features/recording'].selectedRecordingService === RECORDING_TYPES.DROPBOX;
} }
@ -92,7 +95,7 @@ export function isSavingRecordingOnDropbox(state: Object) {
* @param {Object} state - The redux state to search in. * @param {Object} state - The redux state to search in.
* @returns {string} * @returns {string}
*/ */
export function isHighlightMeetingMomentDisabled(state: Object) { export function isHighlightMeetingMomentDisabled(state: IReduxState) {
return state['features/recording'].disableHighlightMeetingMoment; return state['features/recording'].disableHighlightMeetingMoment;
} }
@ -105,7 +108,7 @@ export function isHighlightMeetingMomentDisabled(state: Object) {
* @param {string} mode - The recording mode to get status for. * @param {string} mode - The recording mode to get status for.
* @returns {string|undefined} * @returns {string|undefined}
*/ */
export function getSessionStatusToShow(state: Object, mode: string): ?string { export function getSessionStatusToShow(state: IReduxState, mode: string): string | undefined {
const recordingSessions = state['features/recording'].sessionDatas; const recordingSessions = state['features/recording'].sessionDatas;
let status; let status;
@ -149,7 +152,7 @@ export function supportsLocalRecording() {
* visible: boolean * visible: boolean
* }} * }}
*/ */
export function getRecordButtonProps(state: Object): ?string { export function getRecordButtonProps(state: IReduxState) {
let visible; let visible;
// a button can be disabled/enabled if enableFeaturesBasedOnToken // a button can be disabled/enabled if enableFeaturesBasedOnToken
@ -197,7 +200,7 @@ export function getRecordButtonProps(state: Object): ?string {
* @param {Object | string} recorder - A participant or it's resource. * @param {Object | string} recorder - A participant or it's resource.
* @returns {string|undefined} * @returns {string|undefined}
*/ */
export function getResourceId(recorder: string | Object) { export function getResourceId(recorder: string | { getId: Function; }) {
if (recorder) { if (recorder) {
return typeof recorder === 'string' return typeof recorder === 'string'
? recorder ? recorder
@ -211,12 +214,12 @@ export function getResourceId(recorder: string | Object) {
* @param {Object} state - Redux state. * @param {Object} state - Redux state.
* @returns {boolean} - True if sent, false otherwise. * @returns {boolean} - True if sent, false otherwise.
*/ */
export async function sendMeetingHighlight(state: Object) { export async function sendMeetingHighlight(state: IReduxState) {
const { webhookProxyUrl: url } = state['features/base/config']; const { webhookProxyUrl: url } = state['features/base/config'];
const { conference } = state['features/base/conference']; const { conference } = state['features/base/conference'];
const { jwt } = state['features/base/jwt']; const { jwt } = state['features/base/jwt'];
const { connection } = state['features/base/connection']; const { connection } = state['features/base/connection'];
const jid = connection.getJid(); const jid = connection?.getJid();
const localParticipant = getLocalParticipant(state); const localParticipant = getLocalParticipant(state);
const headers = { const headers = {
@ -226,10 +229,10 @@ export async function sendMeetingHighlight(state: Object) {
const reqBody = { const reqBody = {
meetingFqn: extractFqnFromPath(state), meetingFqn: extractFqnFromPath(state),
sessionId: conference.getMeetingUniqueId(), sessionId: conference?.getMeetingUniqueId(),
submitted: Date.now(), submitted: Date.now(),
participantId: localParticipant.jwtId, participantId: localParticipant?.jwtId,
participantName: localParticipant.name, participantName: localParticipant?.name,
participantJid: jid participantJid: jid
}; };
@ -259,7 +262,7 @@ export async function sendMeetingHighlight(state: Object) {
* @param {Object} state - Redux state. * @param {Object} state - Redux state.
* @returns {boolean} * @returns {boolean}
*/ */
function isRemoteParticipantRecordingLocally(state) { function isRemoteParticipantRecordingLocally(state: IReduxState) {
const participants = getRemoteParticipants(state); const participants = getRemoteParticipants(state);
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const

View File

@ -1,5 +1,3 @@
// @flow
import { getLogger } from '../base/logging/functions'; import { getLogger } from '../base/logging/functions';
export default getLogger('features/recording'); export default getLogger('features/recording');

View File

@ -1,27 +1,27 @@
/* @flow */ import { createRecordingEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IStore } from '../app/types';
import { import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes';
createRecordingEvent, import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
sendAnalytics import { getCurrentConference } from '../base/conference/functions';
} from '../analytics';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
import { CONFERENCE_JOIN_IN_PROGRESS, getCurrentConference } from '../base/conference';
import JitsiMeetJS, { import JitsiMeetJS, {
JitsiConferenceEvents, JitsiConferenceEvents,
JitsiRecordingConstants JitsiRecordingConstants
} from '../base/lib-jitsi-meet'; } from '../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../base/media'; import { MEDIA_TYPE } from '../base/media/constants';
import { getParticipantDisplayName, updateLocalRecordingStatus } from '../base/participants'; import { updateLocalRecordingStatus } from '../base/participants/actions';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; import { getParticipantDisplayName } from '../base/participants/functions';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
import { import {
playSound, playSound,
registerSound, registerSound,
stopSound, stopSound,
unregisterSound unregisterSound
} from '../base/sounds'; } from '../base/sounds/actions';
import { TRACK_ADDED } from '../base/tracks'; import { TRACK_ADDED } from '../base/tracks/actionTypes';
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../notifications'; import { showErrorNotification, showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { RECORDING_SESSION_UPDATED, START_LOCAL_RECORDING, STOP_LOCAL_RECORDING } from './actionTypes'; import { RECORDING_SESSION_UPDATED, START_LOCAL_RECORDING, STOP_LOCAL_RECORDING } from './actionTypes';
import { import {
@ -54,9 +54,6 @@ import {
RECORDING_ON_SOUND_FILE RECORDING_ON_SOUND_FILE
} from './sounds'; } from './sounds';
declare var APP: Object;
declare var interfaceConfig: Object;
/** /**
* StateListenerRegistry provides a reliable way to detect the leaving of a * StateListenerRegistry provides a reliable way to detect the leaving of a
* conference, where we need to clean up the recording sessions. * conference, where we need to clean up the recording sessions.
@ -119,7 +116,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
conference.on( conference.on(
JitsiConferenceEvents.RECORDER_STATE_CHANGED, JitsiConferenceEvents.RECORDER_STATE_CHANGED,
recorderSession => { (recorderSession: any) => {
if (recorderSession) { if (recorderSession) {
recorderSession.getID() && dispatch(updateRecordingSessionData(recorderSession)); recorderSession.getID() && dispatch(updateRecordingSessionData(recorderSession));
recorderSession.getError() && _showRecordingErrorNotification(recorderSession, dispatch); recorderSession.getError() && _showRecordingErrorNotification(recorderSession, dispatch);
@ -156,7 +153,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
if (typeof APP !== 'undefined') { if (typeof APP !== 'undefined') {
APP.API.notifyRecordingStatusChanged(true, 'local'); APP.API.notifyRecordingStatusChanged(true, 'local');
} }
} catch (err) { } catch (err: any) {
logger.error('Capture failed', err); logger.error('Capture failed', err);
let descriptionKey = 'recording.error'; let descriptionKey = 'recording.error';
@ -213,16 +210,16 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
const updatedSessionData const updatedSessionData
= getSessionById(getState(), action.sessionData.id); = getSessionById(getState(), action.sessionData.id);
const { initiator, mode, terminator } = updatedSessionData; const { initiator, mode = '', terminator } = updatedSessionData ?? {};
const { PENDING, OFF, ON } = JitsiRecordingConstants.status; const { PENDING, OFF, ON } = JitsiRecordingConstants.status;
if (updatedSessionData.status === PENDING if (updatedSessionData?.status === PENDING
&& (!oldSessionData || oldSessionData.status !== PENDING)) { && (!oldSessionData || oldSessionData.status !== PENDING)) {
dispatch(showPendingRecordingNotification(mode)); dispatch(showPendingRecordingNotification(mode));
} else if (updatedSessionData.status !== PENDING) { } else if (updatedSessionData?.status !== PENDING) {
dispatch(hidePendingRecordingNotification(mode)); dispatch(hidePendingRecordingNotification(mode));
if (updatedSessionData.status === ON) { if (updatedSessionData?.status === ON) {
// We receive 2 updates of the session status ON. The first one is from jibri when it joins. // We receive 2 updates of the session status ON. The first one is from jibri when it joins.
// The second one is from jicofo which will deliever the initiator value. Since the start // The second one is from jicofo which will deliever the initiator value. Since the start
@ -256,7 +253,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
APP.API.notifyRecordingStatusChanged(true, mode); APP.API.notifyRecordingStatusChanged(true, mode);
} }
} }
} else if (updatedSessionData.status === OFF } else if (updatedSessionData?.status === OFF
&& (!oldSessionData || oldSessionData.status !== OFF)) { && (!oldSessionData || oldSessionData.status !== OFF)) {
if (terminator) { if (terminator) {
dispatch( dispatch(
@ -266,7 +263,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
let duration = 0, soundOff, soundOn; let duration = 0, soundOff, soundOn;
if (oldSessionData && oldSessionData.timestamp) { if (oldSessionData?.timestamp) {
duration duration
= (Date.now() / 1000) - oldSessionData.timestamp; = (Date.now() / 1000) - oldSessionData.timestamp;
} }
@ -319,7 +316,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
* @param {Dispatch} dispatch - The Redux Dispatch function. * @param {Dispatch} dispatch - The Redux Dispatch function.
* @returns {void} * @returns {void}
*/ */
function _showRecordingErrorNotification(recorderSession, dispatch) { function _showRecordingErrorNotification(recorderSession: any, dispatch: IStore['dispatch']) {
const mode = recorderSession.getMode(); const mode = recorderSession.getMode();
const error = recorderSession.getError(); const error = recorderSession.getError();
const isStreamMode = mode === JitsiMeetJS.constants.recording.mode.STREAM; const isStreamMode = mode === JitsiMeetJS.constants.recording.mode.STREAM;

View File

@ -19,18 +19,18 @@ const DEFAULT_STATE = {
interface ISessionData { interface ISessionData {
error?: Error; error?: Error;
id?: string; id?: string;
initiator?: Object; initiator?: { getId: Function; };
liveStreamViewURL?: string; liveStreamViewURL?: string;
mode?: string; mode?: string;
status?: string; status?: string;
terminator?: Object; terminator?: { getId: Function; };
timestamp?: number; timestamp?: number;
} }
export interface IRecordingState { export interface IRecordingState {
disableHighlightMeetingMoment: boolean; disableHighlightMeetingMoment: boolean;
pendingNotificationUids: { pendingNotificationUids: {
[key: string]: number | undefined; [key: string]: string | undefined;
}; };
selectedRecordingService: string; selectedRecordingService: string;
sessionDatas: Array<ISessionData>; sessionDatas: Array<ISessionData>;

View File

@ -3,7 +3,7 @@
import React from 'react'; import React from 'react';
import { IconCalendar, IconGear, IconRestore } from '../base/icons/svg'; import { IconCalendar, IconGear, IconRestore } from '../base/icons/svg';
import BaseTheme from '../base/ui/components/BaseTheme.native'; import BaseTheme from '../base/ui/components/BaseTheme';
// @ts-ignore // @ts-ignore
import TabIcon from './components/TabIcon'; import TabIcon from './components/TabIcon';

View File

@ -217,6 +217,7 @@ function getConfig(options = {}) {
extensions: [ extensions: [
'.web.js', '.web.js',
'.web.ts', '.web.ts',
'.web.tsx',
// Typescript: // Typescript:
'.tsx', '.tsx',