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';