ref(TS) Convert some components to TS (#13137)

*Remove unnecessary @ts-ignores
This commit is contained in:
Robert Pintilii
2023-03-30 15:30:15 +03:00
committed by GitHub
parent 206a4afd76
commit 46c91b7566
68 changed files with 318 additions and 405 deletions

7
globals.d.ts vendored
View File

@@ -25,6 +25,13 @@ declare global {
interfaceConfig?: any;
JitsiMeetJS?: any;
JitsiMeetElectron?: any;
// selenium tests handler
_sharedVideoPlayer: any;
}
interface Document {
mozCancelFullScreen?: Function;
webkitExitFullscreen?: Function;
}
const config: IConfig;

13
package-lock.json generated
View File

@@ -143,6 +143,7 @@
"@types/react-native": "0.68.9",
"@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/resemblejs": "^4.1.0",
"@types/unorm": "1.3.28",
"@types/uuid": "8.3.4",
"@types/zxcvbn": "4.4.1",
@@ -6398,6 +6399,12 @@
"@types/react": "*"
}
},
"node_modules/@types/resemblejs": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@types/resemblejs/-/resemblejs-4.1.0.tgz",
"integrity": "sha512-+MIkKy/UngDfhTnvn2yK/KSzlbtLeB5BU73qqZrzIF24+e2r8enJ4cW3UbtkstByYSDV8pbheGAqg7zT8ZZ2pA==",
"dev": true
},
"node_modules/@types/retry": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
@@ -24951,6 +24958,12 @@
"@types/react": "*"
}
},
"@types/resemblejs": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@types/resemblejs/-/resemblejs-4.1.0.tgz",
"integrity": "sha512-+MIkKy/UngDfhTnvn2yK/KSzlbtLeB5BU73qqZrzIF24+e2r8enJ4cW3UbtkstByYSDV8pbheGAqg7zT8ZZ2pA==",
"dev": true
},
"@types/retry": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",

View File

@@ -148,6 +148,7 @@
"@types/react-native": "0.68.9",
"@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/resemblejs": "^4.1.0",
"@types/unorm": "1.3.28",
"@types/uuid": "8.3.4",
"@types/zxcvbn": "4.4.1",

View File

@@ -164,10 +164,10 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
* If we have a close page enabled, redirect to it without
* showing any other dialog.
*
* @param {Object} options - Ignored.
* @param {Object} _options - Ignored.
* @returns {Function}
*/
export function maybeRedirectToWelcomePage(options: any) { // eslint-disable-line @typescript-eslint/no-unused-vars
export function maybeRedirectToWelcomePage(_options?: any): any {
// Dummy.
}

View File

@@ -127,6 +127,7 @@ export interface INoiseSuppressionConfig {
export interface IConfig {
_desktopSharingSourceDevice?: string;
_screenshotHistoryRegionUrl?: string;
analytics?: {
amplitudeAPPKey?: string;
disabled?: boolean;

View File

@@ -1,79 +1,75 @@
// @flow
import React from 'react';
import { Icon } from '../../../icons';
import Icon from '../../../icons/components/Icon';
import Popover from '../../../popover/components/Popover.web';
type Props = {
/**
* Whether the element popup is expanded.
*/
ariaExpanded?: boolean,
interface IProps {
/**
* The id of the element this button icon controls.
*/
ariaControls?: string,
ariaControls?: string;
/**
* Whether the element popup is expanded.
*/
ariaExpanded?: boolean;
/**
* Whether the element has a popup.
*/
ariaHasPopup?: boolean,
ariaHasPopup?: boolean;
/**
* Aria label for the Icon.
*/
ariaLabel?: string,
ariaLabel?: string;
/**
* The decorated component (ToolboxButton).
*/
children: React$Node,
children: React.ReactNode;
/**
* Icon of the button.
*/
icon: Function,
icon: Function;
/**
* Flag used for disabling the small icon.
*/
iconDisabled: boolean,
iconDisabled: boolean;
/**
* The ID of the icon button.
*/
iconId: string,
iconId: string;
/**
* Popover close callback.
*/
onPopoverClose: Function,
onPopoverClose: Function;
/**
* Popover open callback.
*/
onPopoverOpen: Function,
onPopoverOpen: Function;
/**
* The content that will be displayed inside the popover.
*/
popoverContent: React$Node,
popoverContent: React.ReactNode;
/**
* Additional styles.
*/
styles?: Object,
styles?: Object;
/**
* Whether or not the popover is visible.
*/
visible: boolean
};
declare var APP: Object;
visible: boolean;
}
/**
* Displays the `ToolboxButtonWithIcon` component.
@@ -81,7 +77,7 @@ declare var APP: Object;
* @param {Object} props - Component's props.
* @returns {ReactElement}
*/
export default function ToolboxButtonWithIconPopup(props: Props) {
export default function ToolboxButtonWithIconPopup(props: IProps) {
const {
ariaControls,
ariaExpanded,
@@ -98,7 +94,7 @@ export default function ToolboxButtonWithIconPopup(props: Props) {
visible
} = props;
const iconProps = {};
const iconProps: any = {};
if (iconDisabled) {
iconProps.className
@@ -116,7 +112,7 @@ export default function ToolboxButtonWithIconPopup(props: Props) {
return (
<div
className = 'settings-button-container'
styles = { styles }>
style = { styles }>
{children}
<div className = 'settings-button-small-icon-container'>
<Popover

View File

@@ -44,6 +44,7 @@ export interface ITrackOptions {
* any.
*/
export interface ITrack {
getOriginalStream: Function;
isReceivingData: boolean;
jitsiTrack: any;
local: boolean;

View File

@@ -83,7 +83,7 @@ interface IProps {
/**
* Target elements against which positioning calculations are made.
*/
offsetTarget?: HTMLElement;
offsetTarget?: HTMLElement | null;
/**
* Callback for click on an item in the menu.

View File

@@ -3,12 +3,12 @@ import { useCallback, useRef, useState } from 'react';
import { findAncestorByClass } from '../functions.web';
type RaiseContext = {
type RaiseContext<T> = {
/**
* The entity for which the menu is context menu is raised.
*/
entity?: string | Object;
entity?: T;
/**
* Target elements against which positioning calculations are made.
@@ -18,13 +18,13 @@ type RaiseContext = {
const initialState = Object.freeze({});
const useContextMenu = (): [(force?: boolean | Object) => void,
(entity: string | Object, target: HTMLElement | null) => void,
(entity: string | Object) => (e: MouseEvent) => void,
const useContextMenu = <T>(): [(force?: boolean | Object) => void,
(entity: T, target: HTMLElement | null) => void,
(entity: T) => (e?: MouseEvent) => void,
() => void,
() => void,
RaiseContext] => {
const [ raiseContext, setRaiseContext ] = useState < RaiseContext >(initialState);
RaiseContext<T>] => {
const [ raiseContext, setRaiseContext ] = useState < RaiseContext<T> >(initialState);
const isMouseOverMenu = useRef(false);
const lowerMenu = useCallback((force: boolean | Object = false) => {
@@ -45,21 +45,21 @@ const useContextMenu = (): [(force?: boolean | Object) => void,
});
}, [ raiseContext ]);
const raiseMenu = useCallback((entity: string | Object, target: HTMLElement | null) => {
const raiseMenu = useCallback((entity: T, target: HTMLElement | null) => {
setRaiseContext({
entity,
offsetTarget: findAncestorByClass(target, 'list-item-container')
});
}, [ raiseContext ]);
const toggleMenu = useCallback((entity: string | Object) => (e: MouseEvent) => {
e.stopPropagation();
const toggleMenu = useCallback((entity: T) => (e?: MouseEvent) => {
e?.stopPropagation();
const { entity: raisedEntity } = raiseContext;
if (raisedEntity && raisedEntity === entity) {
lowerMenu();
} else {
raiseMenu(entity, e.target as HTMLElement);
raiseMenu(entity, e?.target as HTMLElement);
}
}, [ raiseContext ]);

View File

@@ -1,38 +1,31 @@
// @flow
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../base/i18n';
import { translate } from '../../base/i18n/functions';
/**
* The type of the React {@code Component} props of
* {@link MicrosoftSignInButton}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* The callback to invoke when {@code MicrosoftSignInButton} is clicked.
*/
onClick: Function,
onClick: (e?: React.MouseEvent) => void;
/**
* The text to display within {@code MicrosoftSignInButton}.
*/
text: string,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
text: string;
}
/**
* A React Component showing a button to sign in with Microsoft.
*
* @augments Component
*/
class MicrosoftSignInButton extends Component<Props> {
class MicrosoftSignInButton extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*

View File

@@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
import ReactionButton from '../../../reactions/components/web/ReactionButton';
import { showOverflowDrawer } from '../../../toolbox/functions.web';
import { setGifDrawerVisibility, setGifMenuVisibility } from '../../actions';
import { isGifsMenuOpen } from '../../functions';
import { isGifsMenuOpen } from '../../functions.web';
const GifsMenuButton = () => {
const menuOpen = useSelector(isGifsMenuOpen);

View File

@@ -1,4 +1,4 @@
import { Component } from 'react';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
/**
@@ -9,13 +9,18 @@ interface IProps extends WithTranslation {
/**
* The callback to invoke when the button is clicked.
*/
onClick: Function;
onClick: (e?: React.MouseEvent) => void;
/**
* True if the user is signed in, so it needs to render a different label
* and maybe different style (for the future).
*/
signedIn?: boolean;
/**
* The text to display within {@code GoogleSignInButton}.
*/
text?: string;
}
/**

View File

@@ -1,8 +1,6 @@
// @flow
import React from 'react';
import { translate } from '../../base/i18n';
import { translate } from '../../base/i18n/functions';
import AbstractGoogleSignInButton from './AbstractGoogleSignInButton';

View File

@@ -1,4 +1,4 @@
import React, { ReactElement, useCallback, useState } from 'react';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
@@ -9,6 +9,7 @@ import Icon from '../../../../../base/icons/components/Icon';
import { IconArrowDown, IconArrowUp } from '../../../../../base/icons/svg';
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
import { withPixelLineHeight } from '../../../../../base/styles/functions.web';
import { IRoom } from '../../../../../breakout-rooms/types';
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
import { ACTION_TRIGGER } from '../../../../constants';
import { participantMatchesSearch } from '../../../../functions';
@@ -25,7 +26,7 @@ interface IProps {
/**
* React children.
*/
children: ReactElement;
children: React.ReactNode;
/**
* Is this item highlighted/raised.
@@ -47,6 +48,8 @@ interface IProps {
*/
participantContextEntity?: {
jid: string;
participantName: string;
room: IRoom;
};
/**

View File

@@ -1,47 +1,44 @@
// @flow
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { createBreakoutRoomsEvent, sendAnalytics } from '../../../../../analytics';
import {
IconCloseLarge,
IconRingGroup
} from '../../../../../base/icons';
import { isLocalParticipantModerator } from '../../../../../base/participants';
import { createBreakoutRoomsEvent } from '../../../../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../../../../analytics/functions';
import { IconCloseLarge, IconRingGroup } from '../../../../../base/icons/svg';
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
import ContextMenu from '../../../../../base/ui/components/web/ContextMenu';
import ContextMenuItemGroup from '../../../../../base/ui/components/web/ContextMenuItemGroup';
import { closeBreakoutRoom, moveToRoom, removeBreakoutRoom } from '../../../../../breakout-rooms/actions';
import { showOverflowDrawer } from '../../../../../toolbox/functions';
import { IRoom } from '../../../../../breakout-rooms/types';
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
type Props = {
interface IProps {
/**
* Room reference.
*/
entity: Object,
entity?: IRoom;
/**
* Target elements against which positioning calculations are made.
*/
offsetTarget: ?HTMLElement,
offsetTarget?: HTMLElement | null;
/**
* Callback for the mouse entering the component.
*/
onEnter: Function,
onEnter: (e?: React.MouseEvent) => void;
/**
* Callback for the mouse leaving the component.
*/
onLeave: Function,
onLeave: (e?: React.MouseEvent) => void;
/**
* Callback for making a selection in the menu.
*/
onSelect: Function
};
onSelect: (e?: React.MouseEvent | boolean) => void;
}
export const RoomContextMenu = ({
entity: room,
@@ -49,7 +46,7 @@ export const RoomContextMenu = ({
onEnter,
onLeave,
onSelect
}: Props) => {
}: IProps) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const isLocalModerator = useSelector(isLocalParticipantModerator);
@@ -57,15 +54,15 @@ export const RoomContextMenu = ({
const onJoinRoom = useCallback(() => {
sendAnalytics(createBreakoutRoomsEvent('join'));
dispatch(moveToRoom(room.jid));
dispatch(moveToRoom(room?.jid));
}, [ dispatch, room ]);
const onRemoveBreakoutRoom = useCallback(() => {
dispatch(removeBreakoutRoom(room.jid));
dispatch(removeBreakoutRoom(room?.jid ?? ''));
}, [ dispatch, room ]);
const onCloseBreakoutRoom = useCallback(() => {
dispatch(closeBreakoutRoom(room.id));
dispatch(closeBreakoutRoom(room?.id ?? ''));
}, [ dispatch, room ]);
const isRoomEmpty = !(room?.participants && Object.keys(room.participants).length > 0);
@@ -86,17 +83,18 @@ export const RoomContextMenu = ({
} : null
].filter(Boolean);
const lowerMenu = useCallback(() => onSelect(true));
const lowerMenu = useCallback(() => onSelect(true), []);
return (
<ContextMenu
entity = { room }
isDrawerOpen = { room }
isDrawerOpen = { Boolean(room) }
offsetTarget = { offsetTarget }
onClick = { lowerMenu }
onDrawerClose = { onSelect }
onMouseEnter = { onEnter }
onMouseLeave = { onLeave }>
{/* @ts-ignore */}
<ContextMenuItemGroup actions = { actions } />
</ContextMenu>
);

View File

@@ -1,11 +1,9 @@
// @flow
import React, { useCallback } from 'react';
import { useSelector } from 'react-redux';
import { isMobileBrowser } from '../../../../../base/environment/utils';
import { isLocalParticipantModerator } from '../../../../../base/participants';
import { equals } from '../../../../../base/redux';
import { isLocalParticipantModerator } from '../../../../../base/participants/functions';
import { equals } from '../../../../../base/redux/functions';
import useContextMenu from '../../../../../base/ui/hooks/useContextMenu.web';
import {
getBreakoutRooms,
@@ -14,7 +12,8 @@ import {
isAutoAssignParticipantsVisible,
isInBreakoutRoom
} from '../../../../../breakout-rooms/functions';
import { showOverflowDrawer } from '../../../../../toolbox/functions';
import { IRoom } from '../../../../../breakout-rooms/types';
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
import { AutoAssignButton } from './AutoAssignButton';
import { CollapsibleRoom } from './CollapsibleRoom';
@@ -24,36 +23,40 @@ import RoomActionEllipsis from './RoomActionEllipsis';
import { RoomContextMenu } from './RoomContextMenu';
import { RoomParticipantContextMenu } from './RoomParticipantContextMenu';
type Props = {
interface IProps {
/**
* Participants search string.
*/
searchString: string
searchString: string;
}
export const RoomList = ({ searchString }: Props) => {
export const RoomList = ({ searchString }: IProps) => {
const currentRoomId = useSelector(getCurrentRoomId);
const rooms = Object.values(useSelector(getBreakoutRooms, equals))
.filter((room: Object) => room.id !== currentRoomId)
.sort((p1: Object, p2: Object) => (p1?.name || '').localeCompare(p2?.name || ''));
.filter((room: IRoom) => room.id !== currentRoomId)
.sort((p1?: IRoom, p2?: IRoom) => (p1?.name || '').localeCompare(p2?.name || ''));
const inBreakoutRoom = useSelector(isInBreakoutRoom);
const isLocalModerator = useSelector(isLocalParticipantModerator);
const showAutoAssign = useSelector(isAutoAssignParticipantsVisible);
const { hideJoinRoomButton } = useSelector(getBreakoutRoomsConfig);
const overflowDrawer = useSelector(showOverflowDrawer);
const [ lowerMenu, raiseMenu, toggleMenu, menuEnter, menuLeave, raiseContext ] = useContextMenu();
const [ lowerMenu, raiseMenu, toggleMenu, menuEnter, menuLeave, raiseContext ] = useContextMenu<IRoom>();
const [ lowerParticipantMenu, raiseParticipantMenu, toggleParticipantMenu,
participantMenuEnter, participantMenuLeave, raiseParticipantContext ] = useContextMenu();
participantMenuEnter, participantMenuLeave, raiseParticipantContext ] = useContextMenu<{
jid: string;
participantName: string;
room: IRoom;
}>();
const hideMenu = useCallback(() => !overflowDrawer && lowerMenu(), [ overflowDrawer, lowerMenu ]);
const onRaiseMenu = useCallback(room => target => raiseMenu(room, target), [ raiseMenu ]);
const onRaiseMenu = useCallback(room => (target: HTMLElement) => raiseMenu(room, target), [ raiseMenu ]);
return (
<>
{inBreakoutRoom && <LeaveButton />}
{showAutoAssign && <AutoAssignButton />}
<div id = 'breakout-rooms-list'>
{rooms.map((room: Object) => (
{rooms.map(room => (
<React.Fragment key = { room.id }>
<CollapsibleRoom
isHighlighted = { raiseContext.entity === room }

View File

@@ -9,8 +9,6 @@ import ContextMenu from '../../../../../base/ui/components/web/ContextMenu';
import ContextMenuItemGroup from '../../../../../base/ui/components/web/ContextMenuItemGroup';
import { getBreakoutRooms } from '../../../../../breakout-rooms/functions';
import { showOverflowDrawer } from '../../../../../toolbox/functions.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import SendToRoomButton from '../../../../../video-menu/components/web/SendToRoomButton';
import { AVATAR_SIZE } from '../../../../constants';
@@ -20,7 +18,7 @@ interface IProps {
/**
* Room and participant jid reference.
*/
entity: {
entity?: {
jid: string;
participantName: string;
room: any;
@@ -29,7 +27,7 @@ interface IProps {
/**
* Target elements against which positioning calculations are made.
*/
offsetTarget: HTMLElement | undefined;
offsetTarget?: HTMLElement | null;
/**
* Callback for the mouse entering the component.
@@ -80,15 +78,15 @@ export const RoomParticipantContextMenu = ({
return (<SendToRoomButton
key = { room.id }
onClick = { lowerMenu }
participantID = { entity?.jid }
participantID = { entity?.jid ?? '' }
room = { room } />);
}
return null;
})
.filter(Boolean), [ entity, rooms ]);
.filter(Boolean), [ entity, rooms ]);
return isLocalModerator && (
return isLocalModerator ? (
<ContextMenu
entity = { entity }
isDrawerOpen = { Boolean(entity) }
@@ -112,5 +110,5 @@ export const RoomParticipantContextMenu = ({
{breakoutRoomsButtons}
</ContextMenuItemGroup>
</ContextMenu>
);
) : null;
};

View File

@@ -83,7 +83,7 @@ function MeetingParticipants({
const dispatch = useDispatch();
const { t } = useTranslation();
const [ lowerMenu, , toggleMenu, menuEnter, menuLeave, raiseContext ] = useContextMenu();
const [ lowerMenu, , toggleMenu, menuEnter, menuLeave, raiseContext ] = useContextMenu<string>();
const muteAudio = useCallback(id => () => {
dispatch(muteRemote(id, MEDIA_TYPE.AUDIO));
dispatch(rejectParticipantAudio(id));

View File

@@ -21,8 +21,6 @@ import {
isMuteAllVisible
} from '../../functions';
import { AddBreakoutRoomButton } from '../breakout-rooms/components/web/AddBreakoutRoomButton';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { RoomList } from '../breakout-rooms/components/web/RoomList';
import { FooterContextMenu } from './FooterContextMenu';

View File

@@ -1,36 +1,34 @@
// @flow
import React from 'react';
type Props = {
interface IProps {
/**
* The text for the Label.
*/
children: React$Node,
children: React.ReactElement;
/**
* The CSS class of the label.
*/
className?: string,
className?: string;
/**
* The (round) number prefix for the Label.
*/
number?: string | number,
number?: string | number;
/**
* The click handler.
*/
onClick?: Function,
};
onClick?: (e?: React.MouseEvent) => void;
}
/**
* Label for the dialogs.
*
* @returns {ReactElement}
*/
function Label({ children, className, number, onClick }: Props) {
function Label({ children, className, number, onClick }: IProps) {
const containerClass = className
? `prejoin-dialog-label ${className}`
: 'prejoin-dialog-label';

View File

@@ -6,8 +6,6 @@ import Avatar from '../../../../base/avatar/components/Avatar';
import { translate } from '../../../../base/i18n/functions';
import Icon from '../../../../base/icons/components/Icon';
import { IconCloseLarge } from '../../../../base/icons/svg';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Label from '../Label';
interface IProps extends WithTranslation {

View File

@@ -7,8 +7,6 @@ import Icon from '../../../../base/icons/components/Icon';
import { IconArrowLeft } from '../../../../base/icons/svg';
import Button from '../../../../base/ui/components/web/Button';
import { getCountryCodeFromPhone } from '../../../utils';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Label from '../Label';
interface IProps extends WithTranslation {

View File

@@ -6,8 +6,6 @@ import { translate } from '../../../../base/i18n/functions';
import Icon from '../../../../base/icons/components/Icon';
import { IconCloseLarge } from '../../../../base/icons/svg';
import Button from '../../../../base/ui/components/web/Button';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import Label from '../Label';
import CountryPicker from '../country-picker/CountryPicker';

View File

@@ -1,26 +1,27 @@
import { connect } from 'react-redux';
import { translate } from '../../../base/i18n';
import { IconRaiseHand } from '../../../base/icons';
import { getLocalParticipant, hasRaisedHand } from '../../../base/participants';
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
import { IReduxState } from '../../../app/types';
import { translate } from '../../../base/i18n/functions';
import { IconRaiseHand } from '../../../base/icons/svg';
import { getLocalParticipant, hasRaisedHand } from '../../../base/participants/functions';
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
/**
* The type of the React {@code Component} props of {@link RaiseHandButton}.
*/
type Props = AbstractButtonProps & {
interface IProps extends AbstractButtonProps {
/**
* Whether or not the hand is raised.
*/
raisedHand: boolean,
};
raisedHand: boolean;
}
/**
* Implementation of a button for raising hand.
*/
class RaiseHandButton extends AbstractButton<Props, *> {
class RaiseHandButton extends AbstractButton<IProps> {
accessibilityLabel = 'toolbar.accessibilityLabel.raiseHand';
toggledAccessibilityLabel = 'toolbar.accessibilityLabel.lowerHand';
icon = IconRaiseHand;
@@ -48,7 +49,7 @@ class RaiseHandButton extends AbstractButton<Props, *> {
* @param {Object} state - Redux state.
* @returns {Object}
*/
const mapStateToProps = state => {
const mapStateToProps = (state: IReduxState) => {
const localParticipant = getLocalParticipant(state);
return {

View File

@@ -1,47 +1,46 @@
/* @flow */
import React from 'react';
import Tooltip from '../../../base/tooltip/components/Tooltip';
import AbstractToolbarButton from '../../../toolbox/components/AbstractToolbarButton';
import type { Props as AbstractToolbarButtonProps } from '../../../toolbox/components/AbstractToolbarButton';
import AbstractToolbarButton, {
IProps as AbstractToolbarButtonProps
} from '../../../toolbox/components/AbstractToolbarButton';
/**
* The type of the React {@code Component} props of {@link ReactionButton}.
*/
type Props = AbstractToolbarButtonProps & {
interface IProps extends AbstractToolbarButtonProps {
/**
* Optional label for the button.
*/
label?: string;
/**
* Optional text to display in the tooltip.
*/
tooltip?: string,
tooltip?: string;
/**
* From which direction the tooltip should appear, relative to the
* button.
*/
tooltipPosition: string,
/**
* Optional label for the button.
*/
label?: string
};
tooltipPosition: 'top' | 'bottom' | 'left' | 'right';
}
/**
* The type of the React {@code Component} state of {@link ReactionButton}.
*/
type State = {
interface IState {
/**
* Used to determine zoom level on reaction burst.
*/
increaseLevel: number,
increaseLevel: number;
/**
* Timeout ID to reset reaction burst.
*/
increaseTimeout: TimeoutID | null
increaseTimeout: number | null;
}
/**
@@ -49,7 +48,7 @@ type State = {
*
* @augments AbstractToolbarButton
*/
class ReactionButton extends AbstractToolbarButton<Props, State> {
class ReactionButton extends AbstractToolbarButton<IProps, IState> {
/**
* Default values for {@code ReactionButton} component's properties.
*
@@ -64,7 +63,7 @@ class ReactionButton extends AbstractToolbarButton<Props, State> {
*
* @inheritdoc
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this._onKeyDown = this._onKeyDown.bind(this);
@@ -76,10 +75,6 @@ class ReactionButton extends AbstractToolbarButton<Props, State> {
};
}
_onKeyDown: (Object) => void;
_onClickHandler: () => void;
/**
* Handles 'Enter' key on the button to trigger onClick for accessibility.
* We should be handling Space onKeyUp but it conflicts with PTT.
@@ -88,7 +83,7 @@ class ReactionButton extends AbstractToolbarButton<Props, State> {
* @private
* @returns {void}
*/
_onKeyDown(event) {
_onKeyDown(event: React.KeyboardEvent) {
// If the event coming to the dialog has been subject to preventDefault
// we don't handle it here.
if (event.defaultPrevented) {
@@ -109,8 +104,8 @@ class ReactionButton extends AbstractToolbarButton<Props, State> {
*/
_onClickHandler() {
this.props.onClick();
clearTimeout(this.state.increaseTimeout);
const timeout = setTimeout(() => {
clearTimeout(this.state.increaseTimeout ?? 0);
const timeout = window.setTimeout(() => {
this.setState({
increaseLevel: 0
});
@@ -132,7 +127,7 @@ class ReactionButton extends AbstractToolbarButton<Props, State> {
* @protected
* @returns {ReactElement} The button of this {@code ReactionButton}.
*/
_renderButton(children) {
_renderButton(children: React.ReactElement) {
return (
<div
aria-label = { this.props.accessibilityLabel }

View File

@@ -10,8 +10,6 @@ import { isMobileBrowser } from '../../../base/environment/utils';
import { raiseHand } from '../../../base/participants/actions';
import { getLocalParticipant, hasRaisedHand } from '../../../base/participants/functions';
import GifsMenu from '../../../gifs/components/web/GifsMenu';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import GifsMenuButton from '../../../gifs/components/web/GifsMenuButton';
import { isGifEnabled, isGifsMenuOpen } from '../../../gifs/functions';
import { dockToolbox } from '../../../toolbox/actions.web';
@@ -19,7 +17,6 @@ import { addReactionToBuffer } from '../../actions.any';
import { toggleReactionsMenuVisibility } from '../../actions.web';
import { REACTIONS, REACTIONS_MENU_HEIGHT } from '../../constants';
// @ts-ignore
import ReactionButton from './ReactionButton';
interface IProps {

View File

@@ -6,15 +6,12 @@ import { IReduxState } from '../../../app/types';
import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n/functions';
import { IconArrowUp } from '../../../base/icons/svg';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import ToolboxButtonWithIconPopup from '../../../base/toolbox/components/web/ToolboxButtonWithIconPopup';
import { toggleReactionsMenuVisibility } from '../../actions.web';
import { IReactionEmojiProps } from '../../constants';
import { getReactionsQueue, isReactionsEnabled } from '../../functions.any';
import { getReactionsMenuVisibility } from '../../functions.web';
// @ts-ignore
import RaiseHandButton from './RaiseHandButton';
import ReactionEmoji from './ReactionEmoji';
import ReactionsMenu from './ReactionsMenu';

View File

@@ -4,8 +4,7 @@ import JitsiMeetJS from '../base/lib-jitsi-meet';
import { showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
// @ts-ignore
import { RecordingLimitNotificationDescription } from './components';
import RecordingLimitNotificationDescription from './components/web/RecordingLimitNotificationDescription';
export * from './actions.any';

View File

@@ -196,7 +196,7 @@ export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
const { mode } = ownProps;
return {
_iAmRecorder: state['features/base/config'].iAmRecorder,
_iAmRecorder: Boolean(state['features/base/config'].iAmRecorder),
_status: getSessionStatusToShow(state, mode)
};
}

View File

@@ -15,7 +15,7 @@ export interface IProps {
/**
* The {@code JitsiConference} for the current conference.
*/
_conference: IJitsiConference;
_conference?: IJitsiConference;
/**
* The current state of interactions with the Google API. Determines what
@@ -32,7 +32,7 @@ export interface IProps {
/**
* The live stream key that was used before.
*/
_streamKey: string;
_streamKey?: string;
/**
* The Redux dispatch function.
@@ -72,7 +72,7 @@ export interface IState {
/**
* The selected or entered stream key to use for YouTube live streaming.
*/
streamKey: string;
streamKey?: string;
}
/**
@@ -159,7 +159,9 @@ export default class AbstractStartLiveStreamDialog<P extends IProps>
* @private
* @returns {Promise}
*/
_onGetYouTubeBroadcasts: () => Promise<any>;
_onGetYouTubeBroadcasts(): Promise<any> | void {
// to be overwritten by child classes.
}
/**
* Callback invoked to update the {@code StartLiveStreamDialog} component's
@@ -205,7 +207,7 @@ export default class AbstractStartLiveStreamDialog<P extends IProps>
sendAnalytics(
createLiveStreamingDialogEvent('start', 'confirm.button'));
this.props._conference.startRecording({
this.props._conference?.startRecording({
broadcastId: selectedBroadcastID,
mode: JitsiRecordingConstants.mode.STREAM,
streamId: key

View File

@@ -7,6 +7,7 @@ import { IReduxState } from '../../../app/types';
import { IJitsiConference } from '../../../base/conference/reducer';
import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { getActiveSession } from '../../functions';
import { ISessionData } from '../../reducer';
/**
* The type of the React {@code Component} props of
@@ -17,12 +18,12 @@ interface IProps extends WithTranslation {
/**
* The {@code JitsiConference} for the current conference.
*/
_conference: IJitsiConference;
_conference?: IJitsiConference;
/**
* The redux representation of the live streaming to be stopped.
*/
_session: { id: string; };
_session?: ISessionData;
}
/**
@@ -57,7 +58,7 @@ export default class AbstractStopLiveStreamDialog extends Component<IProps> {
const { _session } = this.props;
if (_session) {
this.props._conference.stopRecording(_session.id);
this.props._conference?.stopRecording(_session.id);
}
return true;

View File

@@ -9,12 +9,8 @@ import AbstractLiveStreamButton, {
_mapStateToProps as _abstractMapStateToProps
} from '../AbstractLiveStreamButton';
import {
StartLiveStreamDialog,
StopLiveStreamDialog
// @ts-ignore
} from './index';
import StartLiveStreamDialog from './StartLiveStreamDialog';
import StopLiveStreamDialog from './StopLiveStreamDialog';
/**

View File

@@ -1,9 +1,8 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../../base/i18n';
import { IReduxState } from '../../../../app/types';
import { translate } from '../../../../base/i18n/functions';
import Dialog from '../../../../base/ui/components/web/Dialog';
import Spinner from '../../../../base/ui/components/web/Spinner';
import {
@@ -15,22 +14,24 @@ import {
showAccountSelection,
signIn,
updateProfile
// @ts-ignore
} from '../../../../google-api';
import AbstractStartLiveStreamDialog, {
type Props as AbstractProps,
IProps as AbstractProps,
_mapStateToProps as _abstractMapStateToProps
} from '../AbstractStartLiveStreamDialog';
import StreamKeyForm from './StreamKeyForm';
import StreamKeyPicker from './StreamKeyPicker';
type Props = AbstractProps & {
interface IProps extends AbstractProps {
/**
* The ID for the Google client application used for making stream key
* related requests.
*/
_googleApiApplicationClientID: string
_googleApiApplicationClientID?: string;
}
/**
@@ -40,15 +41,15 @@ type Props = AbstractProps & {
* @augments Component
*/
class StartLiveStreamDialog
extends AbstractStartLiveStreamDialog<Props> {
extends AbstractStartLiveStreamDialog<IProps> {
/**
* Initializes a new {@code StartLiveStreamDialog} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* @param {IProps} props - The React {@code Component} props to initialize
* the new {@code StartLiveStreamDialog} instance with.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once per instance.
@@ -95,19 +96,13 @@ class StartLiveStreamDialog
<StreamKeyForm
onChange = { this._onStreamKeyChange }
value = {
this.state.streamKey || this.props._streamKey
this.state.streamKey || this.props._streamKey || ''
} />
</div>
</Dialog>
);
}
_onCancel: () => boolean;
_onSubmit: () => boolean;
_onInitializeGoogleApi: () => void;
/**
* Loads the Google web client application used for fetching stream keys.
* If the user is already logged in, then a request for available YouTube
@@ -118,7 +113,7 @@ class StartLiveStreamDialog
*/
_onInitializeGoogleApi() {
this.props.dispatch(loadGoogleAPI())
.catch(response => this._parseErrorFromResponse(response));
.catch((response: any) => this._parseErrorFromResponse(response));
}
/**
@@ -128,15 +123,13 @@ class StartLiveStreamDialog
* @inheritdoc
* @returns {void}
*/
componentDidUpdate(previousProps) {
componentDidUpdate(previousProps: IProps) {
if (previousProps._googleAPIState === GOOGLE_API_STATES.LOADED
&& this.props._googleAPIState === GOOGLE_API_STATES.SIGNED_IN) {
this._onGetYouTubeBroadcasts();
}
}
_onGetYouTubeBroadcasts: () => void;
/**
* Asks the user to sign in, if not already signed in, and then requests a
* list of the user's YouTube broadcasts.
@@ -146,10 +139,10 @@ class StartLiveStreamDialog
*/
_onGetYouTubeBroadcasts() {
this.props.dispatch(updateProfile())
.catch(response => this._parseErrorFromResponse(response));
.catch((response: any) => this._parseErrorFromResponse(response));
this.props.dispatch(requestAvailableYouTubeBroadcasts())
.then(broadcasts => {
.then((broadcasts: { boundStreamID: string; }[]) => {
this._setStateIfMounted({
broadcasts
});
@@ -160,11 +153,9 @@ class StartLiveStreamDialog
this._onYouTubeBroadcastIDSelected(broadcast.boundStreamID);
}
})
.catch(response => this._parseErrorFromResponse(response));
.catch((response: any) => this._parseErrorFromResponse(response));
}
_onGoogleSignIn: () => Object;
/**
* Forces the Google web client application to prompt for a sign in, such as
* when changing account, and will then fetch available YouTube broadcasts.
@@ -174,11 +165,9 @@ class StartLiveStreamDialog
*/
_onGoogleSignIn() {
this.props.dispatch(signIn())
.catch(response => this._parseErrorFromResponse(response));
.catch((response: any) => this._parseErrorFromResponse(response));
}
_onRequestGoogleSignIn: () => Object;
/**
* Forces the Google web client application to prompt for a sign in, such as
* when changing account, and will then fetch available YouTube broadcasts.
@@ -198,10 +187,6 @@ class StartLiveStreamDialog
.then(() => this._onGetYouTubeBroadcasts());
}
_onStreamKeyChange: string => void;
_onYouTubeBroadcastIDSelected: (string) => Object;
/**
* Fetches the stream key for a YouTube broadcast and updates the internal
* state to display the associated stream key as being entered.
@@ -211,10 +196,10 @@ class StartLiveStreamDialog
* @private
* @returns {Promise}
*/
_onYouTubeBroadcastIDSelected(boundStreamID) {
_onYouTubeBroadcastIDSelected(boundStreamID: string) {
this.props.dispatch(
requestLiveStreamsForYouTubeBroadcast(boundStreamID))
.then(({ streamKey, selectedBoundStreamID }) =>
.then(({ streamKey, selectedBoundStreamID }: { selectedBoundStreamID: string; streamKey: string; }) =>
this._setStateIfMounted({
streamKey,
selectedBoundStreamID
@@ -232,7 +217,7 @@ class StartLiveStreamDialog
* @private
* @returns {string|null}
*/
_parseErrorFromResponse(response) {
_parseErrorFromResponse(response: any) {
if (!response || !response.result) {
return;
@@ -240,11 +225,11 @@ class StartLiveStreamDialog
const result = response.result;
const error = result.error;
const errors = error && error.errors;
const firstError = errors && errors[0];
const errors = error?.errors;
const firstError = errors?.[0];
this._setStateIfMounted({
errorType: (firstError && firstError.reason) || null
errorType: firstError?.reason || null
});
}
@@ -335,8 +320,6 @@ class StartLiveStreamDialog
);
}
_setStateIfMounted: Object => void;
/**
* Returns the error message to display for the current error state.
*
@@ -369,7 +352,7 @@ class StartLiveStreamDialog
* _googleApiApplicationClientID: string
* }}
*/
function _mapStateToProps(state: Object) {
function _mapStateToProps(state: IReduxState) {
return {
..._abstractMapStateToProps(state),
_googleApiApplicationClientID:

View File

@@ -1,9 +1,7 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../../base/i18n';
import { translate } from '../../../../base/i18n/functions';
import Dialog from '../../../../base/ui/components/web/Dialog';
import AbstractStopLiveStreamDialog, {
_mapStateToProps
@@ -33,8 +31,6 @@ class StopLiveStreamDialog extends AbstractStopLiveStreamDialog {
</Dialog>
);
}
_onSubmit: () => boolean;
}
export default translate(connect(_mapStateToProps)(StopLiveStreamDialog));

View File

@@ -1,12 +1,10 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../../base/i18n';
import { translate } from '../../../../base/i18n/functions';
import Input from '../../../../base/ui/components/web/Input';
import AbstractStreamKeyForm, {
type Props, _mapStateToProps
IProps, _mapStateToProps
} from '../AbstractStreamKeyForm';
/**
@@ -14,15 +12,15 @@ import AbstractStreamKeyForm, {
*
* @augments Component
*/
class StreamKeyForm extends AbstractStreamKeyForm<Props> {
class StreamKeyForm extends AbstractStreamKeyForm<IProps> {
/**
* Initializes a new {@code StreamKeyForm} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* @param {IProps} props - The React {@code Component} props to initialize
* the new {@code StreamKeyForm} instance with.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once per instance.
@@ -90,10 +88,6 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
);
}
_onInputChange: Object => void;
_onOpenHelp: () => void;
/**
* Opens a new tab with information on how to manually locate a YouTube
* broadcast stream key.
@@ -105,8 +99,6 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
window.open(this.props._liveStreaming.helpURL, '_blank', 'noopener');
}
_onOpenHelpKeyPress: () => void;
/**
* Opens a new tab with information on how to manually locate a YouTube
* broadcast stream key.
@@ -116,7 +108,7 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
* @private
* @returns {void}
*/
_onOpenHelpKeyPress(e) {
_onOpenHelpKeyPress(e: React.KeyboardEvent) {
if (e.key === ' ') {
e.preventDefault();
this._onOpenHelp();

View File

@@ -30,7 +30,7 @@ interface IProps extends WithTranslation {
* The boundStreamID of the broadcast that should display as selected in the
* dropdown.
*/
selectedBoundStreamID: string;
selectedBoundStreamID?: string;
}
/**
@@ -103,7 +103,7 @@ class StreamKeyPicker extends PureComponent<IProps> {
label = { t('liveStreaming.choose') }
onChange = { this._onSelect }
options = { dropdownItems }
value = { selectedBoundStreamID } />
value = { selectedBoundStreamID ?? '' } />
</div>
);
}

View File

@@ -113,7 +113,7 @@ export function _abstractMapStateToProps(state: IReduxState) {
} = getRecordButtonProps(state);
const canStartRecording = isRecordButtonVisible && !isRecordButtonDisabled;
const _visible = (canStartRecording || isRecordingRunning) && Boolean(webhookProxyUrl);
const _visible = Boolean((canStartRecording || isRecordingRunning) && Boolean(webhookProxyUrl));
return {
_disabled: !isRecordingRunning,

View File

@@ -30,7 +30,7 @@ export interface IProps extends WithTranslation {
/**
* The {@code JitsiConference} for the current conference.
*/
_conference: IJitsiConference;
_conference?: IJitsiConference;
/**
* Whether to show file recordings service, even if integrations
@@ -100,12 +100,12 @@ interface IState {
/**
* Whether the local recording should record just the local user streams.
*/
localRecordingOnlySelf?: boolean;
localRecordingOnlySelf: boolean;
/**
* The currently selected recording service of type: RECORDING_TYPES.
*/
selectedRecordingService?: string;
selectedRecordingService: string;
/**
* True if the user requested the service to share the recording with others.
@@ -143,7 +143,7 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
this._toggleScreenshotCapture = this._toggleScreenshotCapture.bind(this);
this._onLocalRecordingSelfChange = this._onLocalRecordingSelfChange.bind(this);
let selectedRecordingService;
let selectedRecordingService = '';
// TODO: Potentially check if we need to handle changes of
// _fileRecordingsServiceEnabled and _areIntegrationsEnabled()
@@ -351,7 +351,7 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
);
this._toggleScreenshotCapture();
_conference.startRecording({
_conference?.startRecording({
mode: JitsiRecordingConstants.mode.FILE,
appData
});
@@ -408,16 +408,16 @@ export function mapStateToProps(state: IReduxState) {
} = state['features/base/config'];
return {
_appKey: dropbox.appKey,
_appKey: dropbox.appKey ?? '',
_autoCaptionOnRecord: transcription?.autoCaptionOnRecord ?? false,
_conference: state['features/base/conference'].conference,
_fileRecordingsServiceEnabled: recordingService?.enabled ?? false,
_fileRecordingsServiceSharingEnabled: recordingService?.sharingEnabled ?? false,
_isDropboxEnabled: isDropboxEnabled(state),
_localRecordingEnabled: !localRecording?.disable,
_rToken: state['features/dropbox'].rToken,
_rToken: state['features/dropbox'].rToken ?? '',
_tokenExpireDate: state['features/dropbox'].expireDate,
_token: state['features/dropbox'].token
_token: state['features/dropbox'].token ?? ''
};
}

View File

@@ -126,12 +126,12 @@ export interface IProps extends WithTranslation {
/**
* Number of MiB of available space in user's Dropbox account.
*/
spaceLeft: number | null;
spaceLeft?: number;
/**
* The display name of the user's Dropbox account.
*/
userName: string | null;
userName?: string;
}
/**

View File

@@ -83,8 +83,8 @@ export default class AbstractStopRecordingDialog<P extends IProps>
} else {
const { _fileRecordingSession } = this.props;
if (_fileRecordingSession) { // @ts-ignore
this.props._conference.stopRecording(_fileRecordingSession.id);
if (_fileRecordingSession) {
this.props._conference?.stopRecording(_fileRecordingSession.id);
this._toggleScreenshotCapture();
}
}

View File

@@ -3,8 +3,6 @@ import { withStyles } from '@mui/styles';
import React from 'react';
import { connect } from 'react-redux';
// @ts-ignore
import { StartRecordingDialog } from '../..';
import { openDialog } from '../../../../base/dialog/actions';
import { translate } from '../../../../base/i18n/functions';
import { IconHighlight } from '../../../../base/icons/svg';
@@ -13,12 +11,13 @@ import Label from '../../../../base/label/components/web/Label';
import Tooltip from '../../../../base/tooltip/components/Tooltip';
import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
import StartRecordingDialog from '../../Recording/web/StartRecordingDialog';
import AbstractHighlightButton, {
IProps as AbstractProps,
_abstractMapStateToProps
} from '../AbstractHighlightButton';
type Props = AbstractProps & {
interface IProps extends AbstractProps {
_disabled: boolean;
/**
@@ -32,7 +31,7 @@ type Props = AbstractProps & {
_visible: boolean;
classes: any;
};
}
/**
* The type of the React {@code Component} state of {@link HighlightButton}.
@@ -90,17 +89,16 @@ const styles = (theme: Theme) => {
* React {@code Component} responsible for displaying an action that
* allows users to highlight a meeting moment.
*/
export class HighlightButton extends AbstractHighlightButton<Props, IState> {
export class HighlightButton extends AbstractHighlightButton<IProps, IState> {
/**
* Initializes a new HighlightButton instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// @ts-ignore
this.state = {
isNotificationOpen: false
};
@@ -133,7 +131,6 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
* @returns {void}
*/
async _onOpenDialog() {
// @ts-ignore
const { dispatch } = this.props;
const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
@@ -152,11 +149,9 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
_onClick(e?: React.MouseEvent) {
e?.stopPropagation();
// @ts-ignore
const { _disabled } = this.props;
if (_disabled) {
// @ts-ignore
this.setState({
isNotificationOpen: true
});
@@ -171,7 +166,6 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
* @returns {void}
*/
_onWindowClickListener() {
// @ts-ignore
this.setState({
isNotificationOpen: false
});
@@ -189,8 +183,6 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
_visible,
classes,
t
// @ts-ignore
} = this.props;
if (!_visible) {
@@ -212,7 +204,6 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
id = 'highlightMeetingLabel'
onClick = { this._onClick } />
</Tooltip>
{/* @ts-ignore */}
{this.state.isNotificationOpen && (
<div className = { classes.highlightNotification }>
{t('recording.highlightMomentDisabled')}
@@ -228,5 +219,4 @@ export class HighlightButton extends AbstractHighlightButton<Props, IState> {
}
}
// @ts-ignore
export default withStyles(styles)(translate(connect(_abstractMapStateToProps)(HighlightButton)));

View File

@@ -9,8 +9,8 @@ import AbstractRecordButton, {
_mapStateToProps as _abstractMapStateToProps
} from '../AbstractRecordButton';
// @ts-ignore
import { StartRecordingDialog, StopRecordingDialog } from './index';
import StartRecordingDialog from './StartRecordingDialog';
import StopRecordingDialog from './StopRecordingDialog';
/**

View File

@@ -1,9 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../../base/i18n';
import { IReduxState } from '../../../../app/types';
import { translate } from '../../../../base/i18n/functions';
import Dialog from '../../../../base/ui/components/web/Dialog';
import { toggleScreenshotCaptureSummary } from '../../../../screenshot-capture';
import { toggleScreenshotCaptureSummary } from '../../../../screenshot-capture/actions';
import { isScreenshotCaptureEnabled } from '../../../../screenshot-capture/functions';
import { RECORDING_TYPES } from '../../../constants';
import AbstractStartRecordingDialog, {
@@ -21,8 +22,6 @@ import StartRecordingDialogContent from './StartRecordingDialogContent';
*/
class StartRecordingDialog extends AbstractStartRecordingDialog {
isStartRecordingDisabled: () => boolean;
/**
* Disables start recording button.
*
@@ -104,12 +103,6 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
dispatch(toggleScreenshotCaptureSummary(true));
}
}
_areIntegrationsEnabled: () => boolean;
_onSubmit: () => boolean;
_onSelectedRecordingServiceChanged: (string) => void;
_onSharingSettingChanged: () => void;
_onLocalRecordingSelfChange: () => void;
}
/**
@@ -118,7 +111,7 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
* @param {Object} state - Redux state.
* @returns {Object}
*/
function mapStateToProps(state) {
function mapStateToProps(state: IReduxState) {
return {
...abstractMapStateToProps(state),
_screenshotCaptureEnabled: isScreenshotCaptureEnabled(state, true, false)

View File

@@ -25,7 +25,6 @@ import {
ICON_INFO,
ICON_USERS,
LOCAL_RECORDING
// @ts-ignore
} from '../styles.web';
@@ -122,7 +121,6 @@ class StartRecordingDialogContent extends AbstractStartRecordingDialogContent<IP
onSharingSettingChanged,
sharingSetting,
t
// @ts-ignore
} = this.props;
return (

View File

@@ -3,9 +3,7 @@ import { connect } from 'react-redux';
import { translate } from '../../../../base/i18n/functions';
import Dialog from '../../../../base/ui/components/web/Dialog';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { toggleScreenshotCaptureSummary } from '../../../../screenshot-capture';
import { toggleScreenshotCaptureSummary } from '../../../../screenshot-capture/actions';
import AbstractStopRecordingDialog, {
IProps,
_mapStateToProps

View File

@@ -38,14 +38,12 @@ class RecordingLabel extends AbstractRecordingLabel {
* @inheritdoc
*/
_renderLabel() {
// @ts-ignore
if (this.props._status !== JitsiRecordingConstants.status.ON) {
// Since there are no expanded labels on web, we only render this
// label when the recording status is ON.
return null;
}
// @ts-ignore
const { classes, mode, t } = this.props;
const isRecording = mode === JitsiRecordingConstants.mode.FILE;
const icon = isRecording ? IconRecord : IconSites;
@@ -63,5 +61,4 @@ class RecordingLabel extends AbstractRecordingLabel {
}
}
// @ts-ignore
export default withStyles(styles)(translate(connect(_mapStateToProps)(RecordingLabel)));

View File

@@ -1,48 +1,43 @@
// @flow
import React from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { translate, translateToHTML } from '../../../base/i18n';
import { IReduxState } from '../../../app/types';
import { translate, translateToHTML } from '../../../base/i18n/functions';
/**
* The type of the React {@code Component} props of {@link RecordingLimitNotificationDescription}.
*/
type Props = {
/**
* The limit of time in minutes for the recording.
*/
_limit: number,
interface IProps extends WithTranslation {
/**
* The name of the app with unlimited recordings.
*/
_appName: string,
_appName?: string;
/**
* The URL to the app with unlimited recordings.
*/
_appURL: string,
_appURL?: string;
/**
* The limit of time in minutes for the recording.
*/
_limit?: number;
/**
* True if the notification is related to the livestreaming and false if not.
*/
isLiveStreaming: Boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
isLiveStreaming: Boolean;
}
/**
* A component that renders the description of the notification for the recording initiator.
*
* @param {Props} props - The props of the component.
* @param {IProps} props - The props of the component.
* @returns {Component}
*/
function RecordingLimitNotificationDescription(props: Props) {
function RecordingLimitNotificationDescription(props: IProps) {
const { _limit, _appName, _appURL, isLiveStreaming, t } = props;
return (
@@ -65,9 +60,9 @@ function RecordingLimitNotificationDescription(props: Props) {
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state): $Shape<Props> {
function _mapStateToProps(state: IReduxState) {
const { recordingLimit = {} } = state['features/base/config'];
const { limit: _limit, appName: _appName, appURL: _appURL } = recordingLimit;

View File

@@ -210,9 +210,7 @@ export function processPermissionRequestReply(participantId: string, event: any)
const virtualScreenshareParticipant = getVirtualScreenshareParticipantByOwnerId(state, participantId);
const pinnedId = pinnedParticipant?.id;
// @ts-ignore
if (virtualScreenshareParticipant?.id && pinnedId !== virtualScreenshareParticipant?.id) {
// @ts-ignore
dispatch(pinParticipant(virtualScreenshareParticipant?.id));
} else if (!virtualScreenshareParticipant?.id && pinnedId !== participantId) {
dispatch(pinParticipant(participantId));
@@ -563,7 +561,7 @@ export function grant(participantId: string) {
true,
false,
{ desktopSharingSources: [ 'screen' ] }
)) // @ts-ignore
))
.then(() => dispatch(sendStartRequest()));
}

View File

@@ -154,8 +154,7 @@ const keyCodeToKey = {
* Generate codes for digit keys (0-9).
*/
for (let i = 0; i < 10; i++) {
// @ts-ignore
keyCodeToKey[i + 48] = `${i}`;
keyCodeToKey[(i + 48) as keyof typeof keyCodeToKey] = `${i}`;
}
/**

View File

@@ -30,7 +30,6 @@ export function _cancelPasswordRequiredPrompt(conference: any) {
// unload and clean of the connection.
APP.API.notifyReadyToClose();
// @ts-ignore
dispatch(maybeRedirectToWelcomePage());
return;

View File

@@ -12,22 +12,22 @@ interface IProps {
/**
* The id of the record.
*/
id: string;
id?: string;
/**
* The name of the record.
*/
name: string;
name?: string;
/**
* The handler for the click event.
*/
onClick: (e?: React.MouseEvent) => void;
onClick?: (e?: React.MouseEvent) => void;
/**
* The type of the record.
*/
type: string;
type?: string;
}
const useStyles = makeStyles()(theme => {
@@ -99,7 +99,7 @@ export const RecordItem = ({
<div
className = { classes.recordType }
key = { type }>
{t(RECORD_TYPE[type].label)}
{t(RECORD_TYPE[type ?? ''].label)}
</div>
</div>
</li>

View File

@@ -176,9 +176,7 @@ function SalesforceLinkDialog() {
const renderSelection = () => (
<div>
<div className = { classes.recordInfo }>
{/* @ts-ignore */}
<RecordItem { ...selectedRecord } />
{/* @ts-ignore */}
{selectedRecordOwner && <RecordItem { ...selectedRecordOwner } />}
{hasDetailsErrors && renderDetailsErrors()}
</div>

View File

@@ -18,11 +18,17 @@ import {
searchSessionRecords
} from './functions';
interface ISelectedRecord {
id: string;
name: string;
onClick: (e?: React.MouseEvent) => void;
type: string;
}
export const useSalesforceLinkDialog = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const [ selectedRecord, setSelectedRecord ] = useState<{
id: string; name: string; onClick: Function; type: string; } | null>(null);
const [ selectedRecord, setSelectedRecord ] = useState<ISelectedRecord | null>(null);
const [ selectedRecordOwner, setSelectedRecordOwner ] = useState<{
id: string; name: string; type: string; } | null>(null);
const [ records, setRecords ] = useState([]);

View File

@@ -58,7 +58,7 @@ export function startAudioScreenShareFlow() {
const audioOnlySharing = isAudioOnlySharing(state);
// If we're already in a normal screen sharing session, warn the user.
if (isScreenVideoShared(state)) { // @ts-ignore
if (isScreenVideoShared(state)) {
dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: true }));
return;
@@ -76,7 +76,6 @@ export function startAudioScreenShareFlow() {
return;
}
// @ts-ignore
dispatch(openDialog(ShareAudioDialog));
};
}
@@ -94,7 +93,7 @@ export function startScreenShareFlow(enabled: boolean) {
const audioOnlySharing = isAudioOnlySharing(state);
// If we're in an audio screen sharing session, warn the user.
if (audioOnlySharing) { // @ts-ignore
if (audioOnlySharing) {
dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: false }));
return;

View File

@@ -1,12 +1,13 @@
// @flow
import resemble from 'resemblejs';
import 'image-capture';
import './createImageBitmap';
import { createScreensharingCaptureTakenEvent, sendAnalytics } from '../analytics';
import { getCurrentConference } from '../base/conference';
import { getLocalParticipant, getRemoteParticipants } from '../base/participants';
import { createScreensharingCaptureTakenEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IReduxState } from '../app/types';
import { getCurrentConference } from '../base/conference/functions';
import { getLocalParticipant, getRemoteParticipants } from '../base/participants/functions';
import { ITrack } from '../base/tracks/types';
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
import {
@@ -16,35 +17,34 @@ import {
POLL_INTERVAL,
SET_INTERVAL
} from './constants';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { processScreenshot } from './processScreenshot';
import { timerWorkerScript } from './worker';
declare var interfaceConfig: Object;
declare var ImageCapture: any;
declare let ImageCapture: any;
/**
* Effect that wraps {@code MediaStream} adding periodic screenshot captures.
* Manipulates the original desktop stream and performs custom processing operations, if implemented.
*/
export default class ScreenshotCaptureSummary {
_state: Object;
_state: IReduxState;
_currentCanvas: HTMLCanvasElement;
_currentCanvasContext: CanvasRenderingContext2D;
_handleWorkerAction: Function;
_initScreenshotCapture: Function;
_currentCanvasContext: CanvasRenderingContext2D | null;
_initializedRegion: boolean;
_imageCapture: any;
_streamWorker: Worker;
_streamHeight: any;
_streamWidth: any;
_storedImageData: ImageData;
_storedImageData?: ImageData;
/**
* Initializes a new {@code ScreenshotCaptureEffect} instance.
*
* @param {Object} state - The redux state.
*/
constructor(state: Object) {
constructor(state: IReduxState) {
this._state = state;
this._currentCanvas = document.createElement('canvas');
this._currentCanvasContext = this._currentCanvas.getContext('2d');
@@ -66,7 +66,7 @@ export default class ScreenshotCaptureSummary {
async _initRegionSelection() {
const { _screenshotHistoryRegionUrl } = this._state['features/base/config'];
const conference = getCurrentConference(this._state);
const sessionId = conference.getMeetingUniqueId();
const sessionId = conference?.getMeetingUniqueId();
const { jwt } = this._state['features/base/jwt'];
if (!_screenshotHistoryRegionUrl) {
@@ -92,7 +92,7 @@ export default class ScreenshotCaptureSummary {
* @returns {Promise} - Promise that resolves once effect has started or rejects if the
* videoType parameter is not desktop.
*/
async start(track: Object) {
async start(track: ITrack) {
const { videoType } = track;
const stream = track.getOriginalStream();
@@ -136,8 +136,8 @@ export default class ScreenshotCaptureSummary {
async _initScreenshotCapture() {
const imageBitmap = await this._imageCapture.grabFrame();
this._currentCanvasContext.drawImage(imageBitmap, 0, 0, this._streamWidth, this._streamHeight);
const imageData = this._currentCanvasContext.getImageData(0, 0, this._streamWidth, this._streamHeight);
this._currentCanvasContext?.drawImage(imageBitmap, 0, 0, this._streamWidth, this._streamHeight);
const imageData = this._currentCanvasContext?.getImageData(0, 0, this._streamWidth, this._streamHeight);
this._storedImageData = imageData;
this._streamWorker.postMessage({
@@ -153,7 +153,7 @@ export default class ScreenshotCaptureSummary {
* @param {EventHandler} message - Message received from the Worker.
* @returns {void}
*/
_handleWorkerAction(message: Object) {
_handleWorkerAction(message: { data: { id: number; }; }) {
return message.data.id === INTERVAL_TIMEOUT && this._handleScreenshot();
}
@@ -164,20 +164,20 @@ export default class ScreenshotCaptureSummary {
* @param {ImageData} imageData - The image data of the new screenshot.
* @returns {void}
*/
_doProcessScreenshot(imageData) {
_doProcessScreenshot(imageData?: ImageData) {
sendAnalytics(createScreensharingCaptureTakenEvent());
const conference = getCurrentConference(this._state);
const sessionId = conference.getMeetingUniqueId();
const sessionId = conference?.getMeetingUniqueId();
const { connection } = this._state['features/base/connection'];
const jid = connection.getJid();
const jid = connection?.getJid();
const timestamp = Date.now();
const { jwt } = this._state['features/base/jwt'];
const meetingFqn = extractFqnFromPath();
const remoteParticipants = getRemoteParticipants(this._state);
const participants = [];
participants.push(getLocalParticipant(this._state).id);
participants.push(getLocalParticipant(this._state)?.id);
remoteParticipants.forEach(p => participants.push(p.id));
this._storedImageData = imageData;
@@ -200,11 +200,11 @@ export default class ScreenshotCaptureSummary {
async _handleScreenshot() {
const imageBitmap = await this._imageCapture.grabFrame();
this._currentCanvasContext.drawImage(imageBitmap, 0, 0, this._streamWidth, this._streamHeight);
const imageData = this._currentCanvasContext.getImageData(0, 0, this._streamWidth, this._streamHeight);
this._currentCanvasContext?.drawImage(imageBitmap, 0, 0, this._streamWidth, this._streamHeight);
const imageData = this._currentCanvasContext?.getImageData(0, 0, this._streamWidth, this._streamHeight);
resemble(imageData)
.compareTo(this._storedImageData)
resemble(imageData ?? '')
.compareTo(this._storedImageData ?? '')
.setReturnEarlyThreshold(PERCENTAGE_LOWER_BOUND)
.onComplete(resultData => {
if (resultData.rawMisMatchPercentage > PERCENTAGE_LOWER_BOUND) {

View File

@@ -3,8 +3,6 @@ import { getMultipleVideoSendingSupportFeatureFlag } from '../base/config/functi
import { getLocalJitsiDesktopTrack, getLocalJitsiVideoTrack } from '../base/tracks/functions';
import { SET_SCREENSHOT_CAPTURE } from './actionTypes';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { createScreenshotCaptureSummary } from './functions';
import logger from './logger';

View File

@@ -1,7 +1,7 @@
// @flow
import { IReduxState } from '../app/types';
import { IStateful } from '../base/app/types';
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
import { toState } from '../base/redux';
import { toState } from '../base/redux/functions';
import { getActiveSession } from '../recording/functions';
import { isScreenVideoShared } from '../screen-share/functions';
@@ -14,7 +14,7 @@ import ScreenshotCaptureSummary from './ScreenshotCaptureSummary';
* {@code getState} function.
* @returns {Promise<ScreenshotCapture>}
*/
export function createScreenshotCaptureSummary(stateful: Object | Function) {
export function createScreenshotCaptureSummary(stateful: IStateful) {
if (!MediaStreamTrack.prototype.getSettings && !MediaStreamTrack.prototype.getConstraints) {
return Promise.reject(new Error('ScreenshotCaptureSummary not supported!'));
}
@@ -30,7 +30,7 @@ export function createScreenshotCaptureSummary(stateful: Object | Function) {
* @param {boolean} checkRecording - Whether to check is recording is on.
* @returns {boolean}
*/
export function isScreenshotCaptureEnabled(state: Object, checkSharing, checkRecording) {
export function isScreenshotCaptureEnabled(state: IReduxState, checkSharing?: boolean, checkRecording?: boolean) {
const { screenshotCapture } = state['features/base/config'];
if (!screenshotCapture?.enabled) {

View File

@@ -1,5 +1,3 @@
// @flow
import {
CLEAR_INTERVAL,
INTERVAL_TIMEOUT,
@@ -27,4 +25,5 @@ const code = `
};
`;
// @ts-ignore
export const timerWorkerScript = URL.createObjectURL(new Blob([ code ], { type: 'application/javascript' }));

View File

@@ -1,4 +1,3 @@
/* eslint-disable lines-around-comment */
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
@@ -8,13 +7,10 @@ import { IJitsiConference } from '../../../../base/conference/reducer';
import { getSecurityUiConfig } from '../../../../base/config/functions.any';
import { isLocalParticipantModerator } from '../../../../base/participants/functions';
import Dialog from '../../../../base/ui/components/web/Dialog';
// @ts-ignore
import { E2EESection } from '../../../../e2ee/components';
// @ts-ignore
import { LobbySection } from '../../../../lobby';
import E2EESection from '../../../../e2ee/components/E2EESection';
import LobbySection from '../../../../lobby/components/web/LobbySection';
import PasswordSection from './PasswordSection';
/* eslint-enable lines-around-comment */
export interface INotifyClick {
key: string;

View File

@@ -9,19 +9,11 @@ import { translate } from '../../../base/i18n/functions';
import { withPixelLineHeight } from '../../../base/styles/functions.web';
import Button from '../../../base/ui/components/web/Button';
import Spinner from '../../../base/ui/components/web/Spinner';
import {
CALENDAR_TYPE,
MicrosoftSignInButton,
bootstrapCalendarIntegration,
clearCalendarIntegration,
isCalendarEnabled,
signIn
// @ts-ignore
} from '../../../calendar-sync';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { GoogleSignInButton } from '../../../google-api';
import { bootstrapCalendarIntegration, clearCalendarIntegration, signIn } from '../../../calendar-sync/actions';
import MicrosoftSignInButton from '../../../calendar-sync/components/MicrosoftSignInButton';
import { CALENDAR_TYPE } from '../../../calendar-sync/constants';
import { isCalendarEnabled } from '../../../calendar-sync/functions';
import GoogleSignInButton from '../../../google-api/components/GoogleSignInButton';
import logger from '../../logger';
/**

View File

@@ -129,7 +129,6 @@ class AbstractVideoManager extends PureComponent<IProps> {
this.throttledFireUpdateSharedVideoEvent = throttle(this.fireUpdateSharedVideoEvent.bind(this), 5000);
// selenium tests handler
// @ts-ignore
window._sharedVideoPlayer = this;
}

View File

@@ -219,8 +219,9 @@ const SpeakerStats = () => {
showFaceExpressions && !displaySwitch && dispatch(toggleFaceExpressions());
}, [ clientWidth ]);
// @ts-ignore
useEffect(() => () => dispatch(resetSearchCriteria()), []);
useEffect(() => () => {
dispatch(resetSearchCriteria());
}, []);
return (
<Dialog

View File

@@ -5,10 +5,8 @@ import { connect, useDispatch } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { IReduxState } from '../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { TRANSLATION_LANGUAGES, TRANSLATION_LANGUAGES_HEAD } from '../../base/i18n';
import { translate, translateToHTML } from '../../base/i18n/functions';
import { TRANSLATION_LANGUAGES, TRANSLATION_LANGUAGES_HEAD } from '../../base/i18n/i18next';
import Dialog from '../../base/ui/components/web/Dialog';
import { openSettingsDialog } from '../../settings/actions';
import { SETTINGS_TABS } from '../../settings/constants';

View File

@@ -6,9 +6,7 @@ import { openDialog } from '../../../base/dialog/actions';
import { translate } from '../../../base/i18n/functions';
import { IconCloudUpload } from '../../../base/icons/svg';
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { SalesforceLinkDialog } from '../../../salesforce/components';
import SalesforceLinkDialog from '../../../salesforce/components/web/SalesforceLinkDialog';
/**
* Implementation of a button for opening the Salesforce link dialog.

View File

@@ -5,9 +5,8 @@ import { makeStyles } from 'tss-react/mui';
import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../../analytics/functions';
import Popover from '../../../base/popover/components/Popover.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { ReactionEmoji, ReactionsMenu } from '../../../reactions/components';
import ReactionEmoji from '../../../reactions/components/web/ReactionEmoji';
import ReactionsMenu from '../../../reactions/components/web/ReactionsMenu';
import { REACTIONS_MENU_HEIGHT } from '../../../reactions/constants';
import { getReactionsQueue } from '../../../reactions/functions.any';
import { DRAWER_MAX_HEIGHT } from '../../constants';

View File

@@ -86,14 +86,9 @@ function _setFullScreen(next: Function, action: AnyAction) {
if (typeof document.exitFullscreen === 'function') {
document.exitFullscreen();
// @ts-ignore
} else if (typeof document.mozCancelFullScreen === 'function') {
// @ts-ignore
document.mozCancelFullScreen();
// @ts-ignore
} else if (typeof document.webkitExitFullscreen === 'function') {
// @ts-ignore
document.webkitExitFullscreen();
}
}

View File

@@ -28,7 +28,9 @@
"react/features/no-audio-signal",
"react/features/noise-suppression",
"react/features/old-client-notification",
"react/features/remote-control",
"react/features/screen-share",
"react/features/screenshot-capture",
"react/features/stream-effects/noise-suppression",
"react/features/stream-effects/rnnoise",
"react/features/virtual-background",