diff --git a/package-lock.json b/package-lock.json index 15dba9ac8dd..1057972f5fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "js-sha512": "0.8.0", "jwt-decode": "2.2.0", "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1847.0.0+03eef6de/lib-jitsi-meet.tgz", - "lodash": "4.17.21", + "lodash-es": "4.17.21", "moment": "2.29.4", "moment-duration-format": "2.2.2", "null-loader": "4.0.1", @@ -132,7 +132,7 @@ "@types/audioworklet": "0.0.29", "@types/dom-screen-wake-lock": "1.0.1", "@types/js-md5": "0.4.3", - "@types/lodash": "4.14.182", + "@types/lodash-es": "4.17.12", "@types/moment-duration-format": "2.2.6", "@types/offscreencanvas": "2019.7.2", "@types/pixelmatch": "5.2.5", @@ -6254,6 +6254,15 @@ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", "dev": true }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", @@ -12824,7 +12833,13 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", @@ -23404,6 +23419,15 @@ "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", "dev": true }, + "@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", @@ -28254,7 +28278,13 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "lodash.clonedeep": { "version": "4.5.0", diff --git a/package.json b/package.json index 0a3313df323..d2e9d3c32e0 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "js-sha512": "0.8.0", "jwt-decode": "2.2.0", "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1847.0.0+03eef6de/lib-jitsi-meet.tgz", - "lodash": "4.17.21", + "lodash-es": "4.17.21", "moment": "2.29.4", "moment-duration-format": "2.2.2", "null-loader": "4.0.1", @@ -138,7 +138,7 @@ "@types/audioworklet": "0.0.29", "@types/dom-screen-wake-lock": "1.0.1", "@types/js-md5": "0.4.3", - "@types/lodash": "4.14.182", + "@types/lodash-es": "4.17.12", "@types/moment-duration-format": "2.2.6", "@types/offscreencanvas": "2019.7.2", "@types/pixelmatch": "5.2.5", diff --git a/react/features/base/app/components/BaseApp.tsx b/react/features/base/app/components/BaseApp.tsx index e26107b9218..47a15207765 100644 --- a/react/features/base/app/components/BaseApp.tsx +++ b/react/features/base/app/components/BaseApp.tsx @@ -1,6 +1,6 @@ // @ts-expect-error import { jitsiLocalStorage } from '@jitsi/js-utils'; -import _ from 'lodash'; +import { isEqual } from 'lodash-es'; import React, { Component, ComponentType, Fragment } from 'react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; @@ -254,7 +254,7 @@ export default class BaseApp

extends Component { href?: string; props?: Object; }): Promise { - if (_.isEqual(route, this.state.route)) { + if (isEqual(route, this.state.route)) { return Promise.resolve(); } diff --git a/react/features/base/avatar/functions.ts b/react/features/base/avatar/functions.ts index da3a7493d35..52121815b09 100644 --- a/react/features/base/avatar/functions.ts +++ b/react/features/base/avatar/functions.ts @@ -1,5 +1,5 @@ import GraphemeSplitter from 'grapheme-splitter'; -import _ from 'lodash'; +import { split } from 'lodash-es'; const AVATAR_COLORS = [ '#6A50D3', @@ -63,7 +63,7 @@ function getFirstGraphemeUpper(word: string) { */ export function getInitials(s?: string) { // We don't want to use the domain part of an email address, if it is one - const initialsBasis = _.split(s, '@')[0]; + const initialsBasis = split(s, '@')[0]; const [ firstWord, secondWord ] = initialsBasis.split(wordSplitRegex).filter(Boolean); return getFirstGraphemeUpper(firstWord) + getFirstGraphemeUpper(secondWord); diff --git a/react/features/base/conference/functions.ts b/react/features/base/conference/functions.ts index 6ebe335ec83..f08224d1182 100644 --- a/react/features/base/conference/functions.ts +++ b/react/features/base/conference/functions.ts @@ -1,5 +1,5 @@ import { sha512_256 as sha512 } from 'js-sha512'; -import _ from 'lodash'; +import { upperFirst, words } from 'lodash-es'; import { getName } from '../../app/functions'; import { IReduxState, IStore } from '../../app/types'; @@ -571,7 +571,7 @@ export function sendLocalParticipant( * @returns {string} */ function safeStartCase(s = '') { - return _.words(`${s}`.replace(/['\u2019]/g, '')).reduce( - (result, word, index) => result + (index ? ' ' : '') + _.upperFirst(word) + return words(`${s}`.replace(/['\u2019]/g, '')).reduce( + (result, word, index) => result + (index ? ' ' : '') + upperFirst(word) , ''); } diff --git a/react/features/base/config/functions.any.ts b/react/features/base/config/functions.any.ts index 8393a2d0a08..3cf706b3b00 100644 --- a/react/features/base/config/functions.any.ts +++ b/react/features/base/config/functions.any.ts @@ -3,7 +3,7 @@ import { jitsiLocalStorage } from '@jitsi/js-utils'; // eslint-disable-next-line lines-around-comment // @ts-ignore import { safeJsonParse } from '@jitsi/js-utils/json'; -import _ from 'lodash'; +import { isEmpty, mergeWith, pick } from 'lodash-es'; import { IReduxState } from '../../app/types'; import { getLocalParticipant } from '../participants/functions'; @@ -136,13 +136,11 @@ export function overrideConfigJSON(config: IConfig, interfaceConfig: any, json: const configJSON = getWhitelistedJSON(configName as 'interfaceConfig' | 'config', json[configName]); - if (!_.isEmpty(configJSON)) { - logger.info( - `Extending ${configName} with: ${ - JSON.stringify(configJSON)}`); + if (!isEmpty(configJSON)) { + logger.info(`Extending ${configName} with: ${JSON.stringify(configJSON)}`); // eslint-disable-next-line arrow-body-style - _.mergeWith(configObj, configJSON, (oldValue, newValue) => { + mergeWith(configObj, configJSON, (oldValue, newValue) => { // XXX We don't want to merge the arrays, we want to // overwrite them. @@ -166,9 +164,9 @@ export function overrideConfigJSON(config: IConfig, interfaceConfig: any, json: */ export function getWhitelistedJSON(configName: 'interfaceConfig' | 'config', configJSON: any): Object { if (configName === 'interfaceConfig') { - return _.pick(configJSON, INTERFACE_CONFIG_WHITELIST); + return pick(configJSON, INTERFACE_CONFIG_WHITELIST); } else if (configName === 'config') { - return _.pick(configJSON, CONFIG_WHITELIST); + return pick(configJSON, CONFIG_WHITELIST); } return configJSON; diff --git a/react/features/base/config/reducer.ts b/react/features/base/config/reducer.ts index 00812289cd4..b7f8a217875 100644 --- a/react/features/base/config/reducer.ts +++ b/react/features/base/config/reducer.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { merge, union } from 'lodash-es'; import { CONFERENCE_INFO } from '../../conference/components/constants'; import { TOOLBAR_BUTTONS } from '../../toolbox/constants'; @@ -194,7 +194,7 @@ function _setConfig(state: IConfig, { config }: { config: IConfig; }) { }); } - const newState = _.merge( + const newState = merge( {}, config, hdAudioOptions, @@ -397,7 +397,7 @@ function _translateLegacyConfig(oldValue: IConfig) { = (newValue.conferenceInfo?.alwaysVisible ?? []) .filter(c => !CONFERENCE_HEADER_MAPPING[key].includes(c)); newValue.conferenceInfo.autoHide - = _.union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]); + = union(newValue.conferenceInfo.autoHide, CONFERENCE_HEADER_MAPPING[key]); } else { newValue.conferenceInfo.alwaysVisible = (newValue.conferenceInfo.alwaysVisible ?? []) @@ -593,7 +593,7 @@ function _translateLegacyConfig(oldValue: IConfig) { * @returns {Object} The new state after the reduction of the specified action. */ function _updateConfig(state: IConfig, { config }: { config: IConfig; }) { - const newState = _.merge({}, state, config); + const newState = merge({}, state, config); _cleanupConfig(newState); diff --git a/react/features/base/connection/actions.any.ts b/react/features/base/connection/actions.any.ts index 6abd593e281..534f9c9d3ef 100644 --- a/react/features/base/connection/actions.any.ts +++ b/react/features/base/connection/actions.any.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { cloneDeep } from 'lodash-es'; import { IReduxState, IStore } from '../../app/types'; import { conferenceLeft, conferenceWillLeave, redirect } from '../conference/actions'; @@ -113,7 +113,7 @@ export function connectionFailed( export function constructOptions(state: IReduxState) { // Deep clone the options to make sure we don't modify the object in the // redux store. - const options: IOptions = _.cloneDeep(state['features/base/config']); + const options: IOptions = cloneDeep(state['features/base/config']); const { locationURL, preferVisitor } = state['features/base/connection']; const params = parseURLParams(locationURL || ''); diff --git a/react/features/base/flags/reducer.ts b/react/features/base/flags/reducer.ts index 3bb10f41670..961576ecf59 100644 --- a/react/features/base/flags/reducer.ts +++ b/react/features/base/flags/reducer.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { isEqual, merge } from 'lodash-es'; import ReducerRegistry from '../redux/ReducerRegistry'; @@ -25,9 +25,9 @@ export interface IFlagsState { ReducerRegistry.register('features/base/flags', (state = DEFAULT_STATE, action): IFlagsState => { switch (action.type) { case UPDATE_FLAGS: { - const newState = _.merge({}, state, action.flags); + const newState = merge({}, state, action.flags); - return _.isEqual(state, newState) ? state : newState; + return isEqual(state, newState) ? state : newState; } } diff --git a/react/features/base/i18n/i18next.ts b/react/features/base/i18n/i18next.ts index c352f32f267..2d266ee27e0 100644 --- a/react/features/base/i18n/i18next.ts +++ b/react/features/base/i18n/i18next.ts @@ -1,7 +1,7 @@ import COUNTRIES_RESOURCES from 'i18n-iso-countries/langs/en.json'; import i18next from 'i18next'; import I18nextXHRBackend, { HttpBackendOptions } from 'i18next-http-backend'; -import _ from 'lodash'; +import { merge } from 'lodash-es'; import LANGUAGES_RESOURCES from '../../../../lang/languages.json'; import MAIN_RESOURCES from '../../../../lang/main.json'; @@ -22,7 +22,7 @@ const COUNTRIES_RESOURCES_OVERRIDES = { /** * Merged country names. */ -const COUNTRIES = _.merge({}, COUNTRIES_RESOURCES, COUNTRIES_RESOURCES_OVERRIDES); +const COUNTRIES = merge({}, COUNTRIES_RESOURCES, COUNTRIES_RESOURCES_OVERRIDES); /** * The available/supported languages. diff --git a/react/features/base/logging/functions.ts b/react/features/base/logging/functions.ts index 99a640806ea..a2a455b1d0c 100644 --- a/react/features/base/logging/functions.ts +++ b/react/features/base/logging/functions.ts @@ -1,6 +1,6 @@ // @ts-expect-error import Logger, { getLogger as _getLogger } from '@jitsi/logger'; -import _ from 'lodash'; +import { once } from 'lodash-es'; import LogTransport from './LogTransport'; @@ -26,7 +26,7 @@ export function getLogger(id: string) { /** * Initializes native logging. This operations must be done as early as possible. */ -export const _initLogging = _.once(() => { +export const _initLogging = once(() => { if (navigator.product !== 'ReactNative') { return; } diff --git a/react/features/base/logging/reducer.ts b/react/features/base/logging/reducer.ts index b3c01b6ad5f..fe9e99659cd 100644 --- a/react/features/base/logging/reducer.ts +++ b/react/features/base/logging/reducer.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { merge } from 'lodash-es'; import { AnyAction } from 'redux'; import ReducerRegistry from '../redux/ReducerRegistry'; @@ -95,7 +95,7 @@ ReducerRegistry.register( * reduction of the specified action. */ function _setLoggingConfig(state: ILoggingState, action: AnyAction) { - const newConfig = _.merge({}, DEFAULT_STATE.config, action.config); + const newConfig = merge({}, DEFAULT_STATE.config, action.config); if (equals(state.config, newConfig)) { return state; diff --git a/react/features/base/participants/subscriber.ts b/react/features/base/participants/subscriber.ts index 89750c0f1db..b7a143b5fc2 100644 --- a/react/features/base/participants/subscriber.ts +++ b/react/features/base/participants/subscriber.ts @@ -1,5 +1,5 @@ -import _ from 'lodash'; +import { difference } from 'lodash-es'; import { batch } from 'react-redux'; import { IStore } from '../../app/types'; @@ -57,8 +57,8 @@ function _createOrRemoveVirtualParticipants( store: IStore): void { const { dispatch, getState } = store; const conference = getCurrentConference(getState()); - const removedScreenshareSourceNames = _.difference(oldScreenshareSourceNames, newScreenshareSourceNames); - const addedScreenshareSourceNames = _.difference(newScreenshareSourceNames, oldScreenshareSourceNames); + const removedScreenshareSourceNames = difference(oldScreenshareSourceNames, newScreenshareSourceNames); + const addedScreenshareSourceNames = difference(newScreenshareSourceNames, oldScreenshareSourceNames); if (removedScreenshareSourceNames.length) { removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference, { diff --git a/react/features/base/redux/functions.ts b/react/features/base/redux/functions.ts index f40240bc853..289b9187221 100644 --- a/react/features/base/redux/functions.ts +++ b/react/features/base/redux/functions.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { isEqual } from 'lodash-es'; import { IReduxState, IStore } from '../../app/types'; import { IStateful } from '../app/types'; @@ -36,7 +36,7 @@ export function assign(target: T, source: Partial): T { * comparison); false, otherwise. */ export function equals(a: any, b: any) { - return _.isEqual(a, b); + return isEqual(a, b); } /** diff --git a/react/features/base/redux/middleware.ts b/react/features/base/redux/middleware.ts index 2dbb8f760c8..e0d20eaf22e 100644 --- a/react/features/base/redux/middleware.ts +++ b/react/features/base/redux/middleware.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { throttle } from 'lodash-es'; import MiddlewareRegistry from './MiddlewareRegistry'; import PersistenceRegistry from './PersistenceRegistry'; @@ -13,10 +13,7 @@ const PERSIST_STATE_DELAY = 2000; /** * A throttled function to avoid repetitive state persisting. */ -const throttledPersistState - = _.throttle( - state => PersistenceRegistry.persistState(state), - PERSIST_STATE_DELAY); +const throttledPersistState = throttle(state => PersistenceRegistry.persistState(state), PERSIST_STATE_DELAY); // Web only code. // We need the if because it appears that on mobile the polyfill is not diff --git a/react/features/base/settings/middleware.any.ts b/react/features/base/settings/middleware.any.ts index 3583772ed31..a9daa06b036 100644 --- a/react/features/base/settings/middleware.any.ts +++ b/react/features/base/settings/middleware.any.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { escape } from 'lodash-es'; import { AnyAction } from 'redux'; import { IStore } from '../../app/types'; @@ -100,8 +100,8 @@ function _updateLocalParticipantFromUrl({ dispatch, getState }: IStore) { const localParticipant = getLocalParticipant(getState()); if (localParticipant) { - const displayName = _.escape(urlDisplayName); - const email = _.escape(urlEmail); + const displayName = escape(urlDisplayName); + const email = escape(urlEmail); dispatch(participantUpdated({ ...localParticipant, diff --git a/react/features/base/settings/reducer.ts b/react/features/base/settings/reducer.ts index 17d75433619..8aa50f90713 100644 --- a/react/features/base/settings/reducer.ts +++ b/react/features/base/settings/reducer.ts @@ -1,6 +1,6 @@ // @ts-expect-error import { jitsiLocalStorage } from '@jitsi/js-utils'; -import _ from 'lodash'; +import { escape } from 'lodash-es'; import { APP_WILL_MOUNT } from '../app/actionTypes'; import PersistenceRegistry from '../redux/PersistenceRegistry'; @@ -154,8 +154,8 @@ function _initSettings(featureState: ISettingsState) { // is a defined value, it will override any value found in local storage. // The workaround is sidestepping _.escape when the value is not set in // local storage. - const displayName = savedDisplayName === null ? undefined : _.escape(savedDisplayName); - const email = savedEmail === null ? undefined : _.escape(savedEmail); + const displayName = savedDisplayName === null ? undefined : escape(savedDisplayName); + const email = savedEmail === null ? undefined : escape(savedEmail); settings = assignIfDefined({ displayName, diff --git a/react/features/base/tracks/subscriber.ts b/react/features/base/tracks/subscriber.ts index 68c8bdb11c8..e646697c316 100644 --- a/react/features/base/tracks/subscriber.ts +++ b/react/features/base/tracks/subscriber.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { isEqual, sortBy } from 'lodash-es'; import { MEDIA_TYPE } from '../media/constants'; import { getScreenshareParticipantIds } from '../participants/functions'; @@ -16,7 +16,7 @@ StateListenerRegistry.register( return; } - if (!_.isEqual(_.sortBy(participantIDs), _.sortBy(previousParticipantIDs))) { + if (!isEqual(sortBy(participantIDs), sortBy(previousParticipantIDs))) { APP.API.notifySharingParticipantsChanged(participantIDs); } } diff --git a/react/features/base/util/isInsecureRoomName.ts b/react/features/base/util/isInsecureRoomName.ts index cec71f4dd56..e0feb27f116 100644 --- a/react/features/base/util/isInsecureRoomName.ts +++ b/react/features/base/util/isInsecureRoomName.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { isEqual } from 'lodash-es'; import { NIL, parse as parseUUID } from 'uuid'; import zxcvbn from 'zxcvbn'; @@ -22,7 +22,7 @@ function isValidUUID(str: string) { return false; } - return !_.isEqual(uuid, NIL_UUID); + return !isEqual(uuid, NIL_UUID); } /** diff --git a/react/features/breakout-rooms/actions.ts b/react/features/breakout-rooms/actions.ts index b8975f616cc..69f91923db3 100644 --- a/react/features/breakout-rooms/actions.ts +++ b/react/features/breakout-rooms/actions.ts @@ -1,5 +1,5 @@ import i18next from 'i18next'; -import _ from 'lodash'; +import { chunk, filter, shuffle } from 'lodash-es'; import { createBreakoutRoomsEvent } from '../analytics/AnalyticsEvents'; import { sendAnalytics } from '../analytics/functions'; @@ -129,14 +129,14 @@ export function removeBreakoutRoom(breakoutRoomJid: string) { export function autoAssignToBreakoutRooms() { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const rooms = getBreakoutRooms(getState); - const breakoutRooms = _.filter(rooms, room => !room.isMainRoom); + const breakoutRooms = filter(rooms, room => !room.isMainRoom); if (breakoutRooms) { sendAnalytics(createBreakoutRoomsEvent('auto.assign')); const participantIds = Array.from(getRemoteParticipants(getState).keys()); const length = Math.ceil(participantIds.length / breakoutRooms.length); - _.chunk(_.shuffle(participantIds), length).forEach((group, index) => + chunk(shuffle(participantIds), length).forEach((group, index) => group.forEach(participantId => { dispatch(sendParticipantToRoom(participantId, breakoutRooms[index].id)); }) diff --git a/react/features/breakout-rooms/functions.ts b/react/features/breakout-rooms/functions.ts index eac11f48ffb..23429fe6ece 100644 --- a/react/features/breakout-rooms/functions.ts +++ b/react/features/breakout-rooms/functions.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { find } from 'lodash-es'; import { IStateful } from '../base/app/types'; import { getCurrentConference } from '../base/conference/functions'; @@ -33,7 +33,7 @@ export const getBreakoutRooms = (stateful: IStateful): IRooms => toState(statefu export const getMainRoom = (stateful: IStateful) => { const rooms = getBreakoutRooms(stateful); - return _.find(rooms, room => Boolean(room.isMainRoom)); + return find(rooms, room => Boolean(room.isMainRoom)); }; /** @@ -135,7 +135,7 @@ export const getRoomsInfo = (stateful: IStateful) => { export const getRoomByJid = (stateful: IStateful, roomJid: string) => { const rooms = getBreakoutRooms(stateful); - return _.find(rooms, (room: IRoom) => room.jid === roomJid); + return find(rooms, (room: IRoom) => room.jid === roomJid); }; /** diff --git a/react/features/conference/components/web/Conference.tsx b/react/features/conference/components/web/Conference.tsx index e430aadad18..da5abb683c6 100644 --- a/react/features/conference/components/web/Conference.tsx +++ b/react/features/conference/components/web/Conference.tsx @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { throttle } from 'lodash-es'; import React from 'react'; import { WithTranslation } from 'react-i18next'; import { connect as reactReduxConnect } from 'react-redux'; @@ -133,7 +133,7 @@ class Conference extends AbstractConference { this._originalOnShowToolbar = this._onShowToolbar; this._originalOnMouseMove = this._onMouseMove; - this._onShowToolbar = _.throttle( + this._onShowToolbar = throttle( () => this._originalOnShowToolbar(), 100, { @@ -141,7 +141,7 @@ class Conference extends AbstractConference { trailing: false }); - this._onMouseMove = _.throttle( + this._onMouseMove = throttle( event => this._originalOnMouseMove(event), _mouseMoveCallbackInterval, { diff --git a/react/features/connection-indicator/statsEmitter.ts b/react/features/connection-indicator/statsEmitter.ts index 64d654ae1c7..5292373922f 100644 --- a/react/features/connection-indicator/statsEmitter.ts +++ b/react/features/connection-indicator/statsEmitter.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { union } from 'lodash-es'; import { IJitsiConference } from '../base/conference/reducer'; import { @@ -143,7 +143,7 @@ const statsEmitter = { const resolutionUserIds = Object.keys(allUserResolutions); const codecUserIds = Object.keys(allUserCodecs); - _.union(framerateUserIds, resolutionUserIds, codecUserIds) + union(framerateUserIds, resolutionUserIds, codecUserIds) .filter(id => id !== localUserId) .forEach(id => { const remoteUserStats: IStats = {}; diff --git a/react/features/filmstrip/components/web/Filmstrip.tsx b/react/features/filmstrip/components/web/Filmstrip.tsx index 6b7ea3a3aa2..940a273b581 100644 --- a/react/features/filmstrip/components/web/Filmstrip.tsx +++ b/react/features/filmstrip/components/web/Filmstrip.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import _ from 'lodash'; +import { throttle } from 'lodash-es'; import React, { PureComponent } from 'react'; import { WithTranslation } from 'react-i18next'; import { connect } from 'react-redux'; @@ -286,7 +286,7 @@ class Filmstrip extends PureComponent { this._onDragMouseUp = this._onDragMouseUp.bind(this); this._onFilmstripResize = this._onFilmstripResize.bind(this); - this._throttledResize = _.throttle( + this._throttledResize = throttle( this._onFilmstripResize, 50, { diff --git a/react/features/follow-me/middleware.ts b/react/features/follow-me/middleware.ts index ad3351912c0..76adfee5345 100644 --- a/react/features/follow-me/middleware.ts +++ b/react/features/follow-me/middleware.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { differenceWith, isEqual } from 'lodash-es'; import { IStore } from '../app/types'; import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes'; @@ -184,9 +184,9 @@ function _onFollowMeCommand(attributes: any = {}, id: string, store: IStore) { oldStageParticipants = JSON.parse(oldState.pinnedStageParticipants); } - if (!_.isEqual(stageParticipants, oldStageParticipants)) { - const toRemove = _.differenceWith(oldStageParticipants, stageParticipants, _.isEqual); - const toAdd = _.differenceWith(stageParticipants, oldStageParticipants, _.isEqual); + if (!isEqual(stageParticipants, oldStageParticipants)) { + const toRemove = differenceWith(oldStageParticipants, stageParticipants, isEqual); + const toAdd = differenceWith(stageParticipants, oldStageParticipants, isEqual); toRemove.forEach((p: { participantId: string; }) => store.dispatch(removeStageParticipant(p.participantId))); diff --git a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.tsx b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.tsx index 6a88365a4f3..c3b8972facb 100644 --- a/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.tsx +++ b/react/features/invite/components/add-people-dialog/native/AddPeopleDialog.tsx @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { matchesProperty, sortBy } from 'lodash-es'; import React, { ReactElement } from 'react'; import { WithTranslation } from 'react-i18next'; import { @@ -331,7 +331,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { const finderKey = item.type === INVITE_TYPES.PHONE ? 'number' : 'user_id'; if (inviteItems.find( - _.matchesProperty(finderKey, item[finderKey as keyof typeof item]))) { + matchesProperty(finderKey, item[finderKey as keyof typeof item]))) { // Item is already selected, need to unselect it. this.setState({ inviteItems: inviteItems.filter( @@ -343,7 +343,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { const items = inviteItems.concat(item); this.setState({ - inviteItems: _.sortBy(items, [ 'name', 'number' ]) + inviteItems: sortBy(items, [ 'name', 'number' ]) }); } }; @@ -394,7 +394,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { _performSearch(query: string) { this._query(query).then(results => { this.setState({ - selectableItems: _.sortBy(results, [ 'name', 'number' ]) + selectableItems: sortBy(results, [ 'name', 'number' ]) }); }) .finally(() => { @@ -459,13 +459,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog { switch (item.type) { case INVITE_TYPES.PHONE: - selected = inviteItems.find(_.matchesProperty('number', item.number)); + selected = inviteItems.find(matchesProperty('number', item.number)); break; case INVITE_TYPES.USER: case INVITE_TYPES.EMAIL: selected = item.id - ? inviteItems.find(_.matchesProperty('id', item.id)) - : inviteItems.find(_.matchesProperty('user_id', item.user_id)); + ? inviteItems.find(matchesProperty('id', item.id)) + : inviteItems.find(matchesProperty('user_id', item.user_id)); break; default: return null; diff --git a/react/features/mobile/audio-mode/components/AudioRoutePickerDialog.tsx b/react/features/mobile/audio-mode/components/AudioRoutePickerDialog.tsx index bb2078c1ef6..0ac21391248 100644 --- a/react/features/mobile/audio-mode/components/AudioRoutePickerDialog.tsx +++ b/react/features/mobile/audio-mode/components/AudioRoutePickerDialog.tsx @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { sortBy } from 'lodash-es'; import React, { Component } from 'react'; import { NativeModules, Text, TextStyle, TouchableHighlight, View, ViewStyle } from 'react-native'; import { connect } from 'react-redux'; @@ -201,7 +201,7 @@ class AudioRoutePickerDialog extends Component { // Make sure devices is alphabetically sorted. return { - devices: _.sortBy(audioDevices, 'text') + devices: sortBy(audioDevices, 'text') }; } diff --git a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts index 392a82ec424..091a0058903 100644 --- a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts +++ b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts @@ -1,5 +1,5 @@ -import { DebouncedFunc } from 'lodash'; -import debounce from 'lodash/debounce'; +import { debounce } from 'lodash-es'; +import type { DebouncedFunc } from 'lodash-es'; import { Component } from 'react'; import { WithTranslation } from 'react-i18next'; diff --git a/react/features/speaker-stats/functions.ts b/react/features/speaker-stats/functions.ts index 26f784bd388..1804d870739 100644 --- a/react/features/speaker-stats/functions.ts +++ b/react/features/speaker-stats/functions.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { cloneDeep } from 'lodash-es'; import { IReduxState } from '../app/types'; import { getConferenceTimestamp } from '../base/conference/functions'; @@ -175,7 +175,7 @@ function getEnhancedStatsForOrdering(state: IReduxState, stats: ISpeakerStats, o * @public */ export function filterBySearchCriteria(state: IReduxState, stats?: ISpeakerStats) { - const filteredStats = _.cloneDeep(stats ?? getSpeakerStats(state)); + const filteredStats = cloneDeep(stats ?? getSpeakerStats(state)); const criteria = getSearchCriteria(state); if (criteria !== null) { @@ -203,7 +203,7 @@ export function filterBySearchCriteria(state: IReduxState, stats?: ISpeakerStats * @public */ export function resetHiddenStats(state: IReduxState, stats?: ISpeakerStats) { - const resetStats = _.cloneDeep(stats ?? getSpeakerStats(state)); + const resetStats = cloneDeep(stats ?? getSpeakerStats(state)); for (const id in resetStats) { if (resetStats[id].hidden) { diff --git a/react/features/speaker-stats/reducer.ts b/react/features/speaker-stats/reducer.ts index 870a7045b56..887055cbf35 100644 --- a/react/features/speaker-stats/reducer.ts +++ b/react/features/speaker-stats/reducer.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { assign } from 'lodash-es'; import ReducerRegistry from '../base/redux/ReducerRegistry'; import { FaceLandmarks } from '../face-landmarks/types'; @@ -141,11 +141,7 @@ ReducerRegistry.register('features/speaker-stats', * @returns {Object} The new state after the reduction of the specified action. */ function _updateCriteria(state: ISpeakerStatsState, { criteria }: { criteria: string | null; }) { - return _.assign( - {}, - state, - { criteria } - ); + return assign({}, state, { criteria }); } /** @@ -188,9 +184,5 @@ function _updateSortedSpeakerStats(state: ISpeakerStatsState, { participantIds } * @returns {Object} The new state after the reduction of the specified action. */ function _initReorderStats(state: ISpeakerStatsState) { - return _.assign( - {}, - state, - { pendingReorder: true } - ); + return assign({}, state, { pendingReorder: true }); } diff --git a/react/features/toolbox/components/HangupButton.ts b/react/features/toolbox/components/HangupButton.ts index db0c09f9a64..ebe17c3f858 100644 --- a/react/features/toolbox/components/HangupButton.ts +++ b/react/features/toolbox/components/HangupButton.ts @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { once } from 'lodash-es'; import { connect } from 'react-redux'; import { createToolbarEvent } from '../../analytics/AnalyticsEvents'; @@ -29,7 +29,7 @@ class HangupButton extends AbstractHangupButton { constructor(props: AbstractButtonProps) { super(props); - this._hangup = _.once(() => { + this._hangup = once(() => { sendAnalytics(createToolbarEvent('hangup')); this.props.dispatch(leaveConference()); }); diff --git a/react/features/toolbox/subscriber.web.ts b/react/features/toolbox/subscriber.web.ts index ce365abc6c1..fa12e6b45cd 100644 --- a/react/features/toolbox/subscriber.web.ts +++ b/react/features/toolbox/subscriber.web.ts @@ -1,4 +1,4 @@ -import { throttle } from 'lodash'; +import { throttle } from 'lodash-es'; import { IReduxState, IStore } from '../app/types'; import { getParticipantCount } from '../base/participants/functions'; diff --git a/react/features/video-menu/components/native/VolumeSlider.tsx b/react/features/video-menu/components/native/VolumeSlider.tsx index 4f78c78ac06..84a3ac01f42 100644 --- a/react/features/video-menu/components/native/VolumeSlider.tsx +++ b/react/features/video-menu/components/native/VolumeSlider.tsx @@ -1,7 +1,7 @@ /* eslint-disable lines-around-comment*/ import Slider from '@react-native-community/slider'; -import _ from 'lodash'; +import { throttle } from 'lodash-es'; import React, { PureComponent } from 'react'; import { View, ViewStyle } from 'react-native'; import { connect } from 'react-redux'; @@ -88,7 +88,7 @@ class VolumeSlider extends PureComponent { this._originalVolumeChange = this._onVolumeChange; - this._onVolumeChange = _.throttle( + this._onVolumeChange = throttle( volumeLevel => this._originalVolumeChange(volumeLevel), 500 ); } diff --git a/react/features/visitors/components/web/JoinMeetingDialog.tsx b/react/features/visitors/components/web/JoinMeetingDialog.tsx index 3017e8272af..385b1903baa 100644 --- a/react/features/visitors/components/web/JoinMeetingDialog.tsx +++ b/react/features/visitors/components/web/JoinMeetingDialog.tsx @@ -1,4 +1,4 @@ -import { noop } from 'lodash'; +import { noop } from 'lodash-es'; import React from 'react'; import { useTranslation } from 'react-i18next'; import { makeStyles } from 'tss-react/mui';