From b9224862deb84b0252b9f55ea8249034b0334f2d Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Wed, 2 Feb 2022 11:33:57 +0100 Subject: [PATCH] Replace Lodash with it's ESM variant (#1990) --- .eslintrc.js | 2 + .../pages/admin_console/SidebarPage.ts | 2 +- cypress/support/util/AdminClient.ts | 2 +- jest.config.ts | 3 +- package-lock.json | 57 ++++++++++++++++++- package.json | 5 +- .../components/DraggableTable.tsx | 2 +- src/clients/ClientDetails.tsx | 4 +- .../advanced/AuthenticationOverrides.tsx | 4 +- .../attribute-input/AttributeInput.tsx | 2 +- .../bread-crumb/PageBreadCrumbs.tsx | 4 +- .../dynamic/MultivaluedRoleComponent.tsx | 2 +- .../role-mapping/AddRoleMappingModal.tsx | 4 +- .../table-toolbar/KeycloakDataTable.tsx | 12 ++-- src/context/RealmsContext.tsx | 2 +- src/dashboard/Dashboard.tsx | 2 +- src/events/AdminEvents.tsx | 2 +- src/events/EventsSection.tsx | 2 +- src/groups/Members.tsx | 4 +- src/groups/MembersModal.tsx | 4 +- .../IdentityProvidersSection.tsx | 46 +++++++-------- src/identity-providers/ManageOrderDialog.tsx | 4 +- src/realm-roles/AssociatedRolesModal.tsx | 2 +- src/realm-roles/RealmRoleTabs.tsx | 2 +- src/realm-settings/LocalizationTab.tsx | 2 +- .../NewClientPolicyCondition.tsx | 2 +- src/realm-settings/ProfilesTab.tsx | 2 +- .../kerberos/KerberosSettingsRequired.tsx | 4 +- .../ldap/LdapSettingsConnection.tsx | 6 +- src/user-federation/shared/SettingsCache.tsx | 10 ++-- src/user/UserConsents.tsx | 4 +- src/user/UserGroups.tsx | 2 +- src/user/UserIdPModal.tsx | 6 +- src/user/UserIdentityProviderLinks.tsx | 8 +-- src/util.ts | 2 +- src/utils/useRequiredContext.test.ts | 2 +- 36 files changed, 139 insertions(+), 86 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 180c147048..7e743a923c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,7 @@ module.exports = { env: { node: true, }, + plugins: ["lodash"], extends: [ "eslint:recommended", "plugin:react/recommended", @@ -30,6 +31,7 @@ module.exports = { "@typescript-eslint/no-empty-function": "error", "@typescript-eslint/no-unnecessary-condition": "warn", "@typescript-eslint/no-unused-vars": "error", + "lodash/import-scope": ["error", "member"], // react/prop-types cannot handle generic props, so we need to disable it. // https://github.com/yannickcr/eslint-plugin-react/issues/2777#issuecomment-814968432 "react/prop-types": "off", diff --git a/cypress/support/pages/admin_console/SidebarPage.ts b/cypress/support/pages/admin_console/SidebarPage.ts index e9a70f1e65..02236f6fea 100644 --- a/cypress/support/pages/admin_console/SidebarPage.ts +++ b/cypress/support/pages/admin_console/SidebarPage.ts @@ -1,4 +1,4 @@ -import { capitalize } from "lodash"; +import { capitalize } from "lodash-es"; export default class SidebarPage { private realmsDrpDwn = "realmSelectorToggle"; diff --git a/cypress/support/util/AdminClient.ts b/cypress/support/util/AdminClient.ts index a6c9bf1b39..c25f08b900 100644 --- a/cypress/support/util/AdminClient.ts +++ b/cypress/support/util/AdminClient.ts @@ -4,7 +4,7 @@ import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/ import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig"; -import { merge } from "lodash"; +import { merge } from "lodash-es"; export default class AdminClient { private client: KeycloakAdminClient; diff --git a/jest.config.ts b/jest.config.ts index b21db1a531..d48a3a2e56 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,4 @@ -import type { InitialOptionsTsJest } from "ts-jest/dist/types"; +import type { InitialOptionsTsJest } from "ts-jest"; const config: InitialOptionsTsJest = { preset: "ts-jest", @@ -11,6 +11,7 @@ const config: InitialOptionsTsJest = { setupFilesAfterEnv: ["/jest.setup.ts"], moduleNameMapper: { "\\.css$": "/mocks/fileMock.ts", + "lodash-es": "lodash", }, }; diff --git a/package-lock.json b/package-lock.json index 8b5e16f0c8..b445e5b818 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "file-saver": "^2.0.5", "flat": "^5.0.2", "i18next": "^21.6.10", - "lodash": "^4.17.20", + "lodash-es": "^4.17.21", "moment": "^2.29.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -43,7 +43,7 @@ "@types/dagre": "^0.7.47", "@types/file-saver": "^2.0.5", "@types/flat": "^5.0.2", - "@types/lodash": "^4.14.178", + "@types/lodash-es": "^4.17.5", "@types/node": "^17.0.13", "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", @@ -57,6 +57,7 @@ "eslint": "^8.8.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-lodash": "^7.3.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.28.0", "fork-ts-checker-webpack-plugin": "^7.0.0", @@ -4755,6 +4756,15 @@ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", "dev": true }, + "node_modules/@types/lodash-es": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.5.tgz", + "integrity": "sha512-SHBoI8/0aoMQWAgUHMQ599VM6ZiSKg8sh/0cFqqlQQMyY9uEplc0ULU5yQNzcvdR4ZKa0ey8+vFmahuRbOCT1A==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.13.tgz", @@ -9318,6 +9328,21 @@ "eslint": ">= 3.2.1" } }, + "node_modules/eslint-plugin-lodash": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-7.3.0.tgz", + "integrity": "sha512-FQM8HklruJzulPawX3uZqWbeyN3bQT4hjVCpFYMrWo0Hdz1qDCwp1v3JS4zjhdssAXdwCxdnyrNMCZJK70GeUQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": ">=2" + } + }, "node_modules/eslint-plugin-prettier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", @@ -14604,6 +14629,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "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.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -25042,6 +25072,15 @@ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", "dev": true }, + "@types/lodash-es": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.5.tgz", + "integrity": "sha512-SHBoI8/0aoMQWAgUHMQ599VM6ZiSKg8sh/0cFqqlQQMyY9uEplc0ULU5yQNzcvdR4ZKa0ey8+vFmahuRbOCT1A==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/node": { "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.13.tgz", @@ -28805,6 +28844,15 @@ "globals": "^11.12.0" } }, + "eslint-plugin-lodash": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-lodash/-/eslint-plugin-lodash-7.3.0.tgz", + "integrity": "sha512-FQM8HklruJzulPawX3uZqWbeyN3bQT4hjVCpFYMrWo0Hdz1qDCwp1v3JS4zjhdssAXdwCxdnyrNMCZJK70GeUQ==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, "eslint-plugin-prettier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", @@ -32647,6 +32695,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "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.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", diff --git a/package.json b/package.json index b17d4879ae..2657b7ab5a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "file-saver": "^2.0.5", "flat": "^5.0.2", "i18next": "^21.6.10", - "lodash": "^4.17.20", + "lodash-es": "^4.17.21", "moment": "^2.29.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -59,7 +59,7 @@ "@types/dagre": "^0.7.47", "@types/file-saver": "^2.0.5", "@types/flat": "^5.0.2", - "@types/lodash": "^4.14.178", + "@types/lodash-es": "^4.17.5", "@types/node": "^17.0.13", "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", @@ -73,6 +73,7 @@ "eslint": "^8.8.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-lodash": "^7.3.0", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.28.0", "fork-ts-checker-webpack-plugin": "^7.0.0", diff --git a/src/authentication/components/DraggableTable.tsx b/src/authentication/components/DraggableTable.tsx index e245a5e1c3..e9d8c1357d 100644 --- a/src/authentication/components/DraggableTable.tsx +++ b/src/authentication/components/DraggableTable.tsx @@ -1,6 +1,6 @@ import React, { ReactNode, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { get } from "lodash"; +import { get } from "lodash-es"; import { TableComposable, Tbody, diff --git a/src/clients/ClientDetails.tsx b/src/clients/ClientDetails.tsx index 87409cd6f8..cc3767c0c7 100644 --- a/src/clients/ClientDetails.tsx +++ b/src/clients/ClientDetails.tsx @@ -12,7 +12,7 @@ import { } from "@patternfly/react-core"; import { InfoCircleIcon } from "@patternfly/react-icons"; import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation"; -import _, { cloneDeep } from "lodash"; +import { cloneDeep, sortBy } from "lodash-es"; import React, { useMemo, useState } from "react"; import { Controller, FormProvider, useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; @@ -224,7 +224,7 @@ export default function ClientDetails() { const loader = async () => { const roles = await adminClient.clients.listRoles({ id: clientId }); - return _.sortBy(roles, (role) => role.name?.toUpperCase()); + return sortBy(roles, (role) => role.name?.toUpperCase()); }; const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ diff --git a/src/clients/advanced/AuthenticationOverrides.tsx b/src/clients/advanced/AuthenticationOverrides.tsx index 5174e84208..86ed27ef51 100644 --- a/src/clients/advanced/AuthenticationOverrides.tsx +++ b/src/clients/advanced/AuthenticationOverrides.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Control, Controller } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { sortBy } from "lodash-es"; import { ActionGroup, Button, @@ -40,7 +40,7 @@ export const AuthenticationOverrides = ({ let filteredFlows = [ ...flows.filter((flow) => flow.providerId !== "client-flow"), ]; - filteredFlows = _.sortBy(filteredFlows, [(f) => f.alias]); + filteredFlows = sortBy(filteredFlows, [(f) => f.alias]); setFlows([ {t("common:choose")} diff --git a/src/components/attribute-input/AttributeInput.tsx b/src/components/attribute-input/AttributeInput.tsx index ea7e1b0945..653991a91c 100644 --- a/src/components/attribute-input/AttributeInput.tsx +++ b/src/components/attribute-input/AttributeInput.tsx @@ -20,7 +20,7 @@ import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons"; import "../attribute-form/attribute-form.css"; import { defaultContextAttributes } from "../../clients/utils"; -import { camelCase } from "lodash"; +import { camelCase } from "lodash-es"; import type ResourceRepresentation from "@keycloak/keycloak-admin-client/lib/defs/resourceRepresentation"; export type AttributeType = { diff --git a/src/components/bread-crumb/PageBreadCrumbs.tsx b/src/components/bread-crumb/PageBreadCrumbs.tsx index 54f33a59b6..fa7bb08fc8 100644 --- a/src/components/bread-crumb/PageBreadCrumbs.tsx +++ b/src/components/bread-crumb/PageBreadCrumbs.tsx @@ -5,7 +5,7 @@ import useBreadcrumbs, { BreadcrumbsRoute, } from "use-react-router-breadcrumbs"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { uniqBy } from "lodash-es"; import { Breadcrumb, BreadcrumbItem } from "@patternfly/react-core"; import { useRealm } from "../../context/realm-context/RealmContext"; @@ -23,7 +23,7 @@ export const PageBreadCrumbs = () => { breadcrumb: route.breadcrumb?.(t), })); - const crumbs = _.uniqBy( + const crumbs = uniqBy( useBreadcrumbs(routesWithCrumbs, { disableDefaults: true, excludePaths: ["/", `/${realm}`], diff --git a/src/components/dynamic/MultivaluedRoleComponent.tsx b/src/components/dynamic/MultivaluedRoleComponent.tsx index 52958e1b62..de44fbeabe 100644 --- a/src/components/dynamic/MultivaluedRoleComponent.tsx +++ b/src/components/dynamic/MultivaluedRoleComponent.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; -import { sortedUniq } from "lodash"; +import { sortedUniq } from "lodash-es"; import { FormGroup, Select, diff --git a/src/components/role-mapping/AddRoleMappingModal.tsx b/src/components/role-mapping/AddRoleMappingModal.tsx index 8a1e3c549a..6a5e1377d6 100644 --- a/src/components/role-mapping/AddRoleMappingModal.tsx +++ b/src/components/role-mapping/AddRoleMappingModal.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { findIndex } from "lodash-es"; import { Badge, Button, @@ -127,7 +127,7 @@ export const AddRoleMappingModal = ({ }; const loader = async () => { - const realmRolesSelected = _.findIndex( + const realmRolesSelected = findIndex( selectedClients, (client) => client.name === "realmRoles" ); diff --git a/src/components/table-toolbar/KeycloakDataTable.tsx b/src/components/table-toolbar/KeycloakDataTable.tsx index e155b49881..dd1fe6ee52 100644 --- a/src/components/table-toolbar/KeycloakDataTable.tsx +++ b/src/components/table-toolbar/KeycloakDataTable.tsx @@ -18,7 +18,7 @@ import { TableProps, TableVariant, } from "@patternfly/react-table"; -import _ from "lodash"; +import { get, cloneDeep, differenceBy } from "lodash-es"; import { PaginatingTableToolbar } from "./PaginatingTableToolbar"; import { ListEmptyState } from "../list-empty-state/ListEmptyState"; @@ -208,7 +208,7 @@ export function KeycloakDataTable({ if (col.cellRenderer) { return { title: col.cellRenderer(value) }; } - return _.get(value, col.name); + return get(value, col.name); }); }; @@ -223,9 +223,7 @@ export function KeycloakDataTable({ data: value, disableSelection: disabledRow, disableActions: disabledRow, - selected: !!selected.find( - (v) => _.get(v, "id") === _.get(value, "id") - ), + selected: !!selected.find((v) => get(v, "id") === get(value, "id")), isOpen: isDetailColumnsEnabled(value) ? false : undefined, cells: renderCell(columns, value), }, @@ -308,7 +306,7 @@ export function KeycloakDataTable({ const convertAction = () => actions && - _.cloneDeep(actions).map((action: Action, index: number) => { + cloneDeep(actions).map((action: Action, index: number) => { delete action.onRowClick; action.onClick = async (_, rowIndex) => { const result = await actions[index].onRowClick!( @@ -342,7 +340,7 @@ export function KeycloakDataTable({ } // Keeps selected items when paginating - const difference = _.differenceBy( + const difference = differenceBy( selected, data!.map((row) => row.data), "id" diff --git a/src/context/RealmsContext.tsx b/src/context/RealmsContext.tsx index 8005af7824..ee9f11f781 100644 --- a/src/context/RealmsContext.tsx +++ b/src/context/RealmsContext.tsx @@ -1,5 +1,5 @@ import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; -import { sortBy } from "lodash"; +import { sortBy } from "lodash-es"; import React, { createContext, FunctionComponent, diff --git a/src/dashboard/Dashboard.tsx b/src/dashboard/Dashboard.tsx index 455efc14a6..cec5794525 100644 --- a/src/dashboard/Dashboard.tsx +++ b/src/dashboard/Dashboard.tsx @@ -22,7 +22,7 @@ import { } from "@patternfly/react-core"; import React from "react"; import { Trans, useTranslation } from "react-i18next"; -import { xor } from "lodash"; +import { xor } from "lodash-es"; import { useRealm } from "../context/realm-context/RealmContext"; import { useServerInfo } from "../context/server-info/ServerInfoProvider"; diff --git a/src/events/AdminEvents.tsx b/src/events/AdminEvents.tsx index fbb72eb395..2cc62c0e9e 100644 --- a/src/events/AdminEvents.tsx +++ b/src/events/AdminEvents.tsx @@ -31,7 +31,7 @@ import React, { FunctionComponent, useMemo, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; -import { pickBy } from "lodash"; +import { pickBy } from "lodash-es"; import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { useAdminClient } from "../context/auth/AdminClient"; diff --git a/src/events/EventsSection.tsx b/src/events/EventsSection.tsx index 4e4839c4b9..8afbd1acf0 100644 --- a/src/events/EventsSection.tsx +++ b/src/events/EventsSection.tsx @@ -27,7 +27,7 @@ import { cellWidth, expandable } from "@patternfly/react-table"; import type EventRepresentation from "@keycloak/keycloak-admin-client/lib/defs/eventRepresentation"; import type EventType from "@keycloak/keycloak-admin-client/lib/defs/eventTypes"; import type { RealmEventsConfigRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/realmEventsConfigRepresentation"; -import { pickBy } from "lodash"; +import { pickBy } from "lodash-es"; import moment from "moment"; import React, { useState } from "react"; import { Controller, useForm } from "react-hook-form"; diff --git a/src/groups/Members.tsx b/src/groups/Members.tsx index 87c8c40c58..b7873e5ee1 100644 --- a/src/groups/Members.tsx +++ b/src/groups/Members.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { uniqBy } from "lodash-es"; import { AlertVariant, Button, @@ -74,7 +74,7 @@ export const Members = () => { await adminClient.groups.listMembers({ id: group.id! }) ); } - members = _.uniqBy(members, (member) => member.username); + members = uniqBy(members, (member) => member.username); } const memberOfPromises = await Promise.all( diff --git a/src/groups/MembersModal.tsx b/src/groups/MembersModal.tsx index 98f5acf673..07d30b02ef 100644 --- a/src/groups/MembersModal.tsx +++ b/src/groups/MembersModal.tsx @@ -16,7 +16,7 @@ import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; import { emptyFormatter } from "../util"; import { toAddUser } from "../user/routes/AddUser"; -import _ from "lodash"; +import { differenceBy } from "lodash-es"; type MemberModalProps = { groupId: string; @@ -43,7 +43,7 @@ export const MemberModal = ({ groupId, onClose }: MemberModalProps) => { try { const users = await adminClient.users.find({ ...params }); - return _.differenceBy(users, members, "id").slice(0, max); + return differenceBy(users, members, "id").slice(0, max); } catch (error) { addError("groups:noUsersFoundError", error); return []; diff --git a/src/identity-providers/IdentityProvidersSection.tsx b/src/identity-providers/IdentityProvidersSection.tsx index 3463a1063e..f070eb7d3c 100644 --- a/src/identity-providers/IdentityProvidersSection.tsx +++ b/src/identity-providers/IdentityProvidersSection.tsx @@ -1,7 +1,7 @@ import React, { Fragment, useState } from "react"; import { Link, useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { sortBy, groupBy } from "lodash-es"; import { AlertVariant, Badge, @@ -41,7 +41,7 @@ import helpUrls from "../help-urls"; export default function IdentityProvidersSection() { const { t } = useTranslation("identity-providers"); - const identityProviders = _.groupBy( + const identityProviders = groupBy( useServerInfo().identityProviders, "groupName" ); @@ -74,7 +74,7 @@ export default function IdentityProvidersSection() { [] ); - const loader = () => Promise.resolve(_.sortBy(providers, "alias")); + const loader = () => Promise.resolve(sortBy(providers, "alias")); const DetailLink = (identityProvider: IdentityProviderRepresentation) => ( Object.keys(identityProviders).map((group) => ( - {_.sortBy(identityProviders[group], "name").map((provider) => ( + {sortBy(identityProviders[group], "name").map((provider) => (
- {_.sortBy(identityProviders[group], "name").map( - (provider) => ( - navigateToCreate(provider.id)} - > - - - - - - {provider.name} - - - - ) - )} + {sortBy(identityProviders[group], "name").map((provider) => ( + navigateToCreate(provider.id)} + > + + + + + + {provider.name} + + + + ))} ))} diff --git a/src/identity-providers/ManageOrderDialog.tsx b/src/identity-providers/ManageOrderDialog.tsx index bbdda1a9d9..ae1345db05 100644 --- a/src/identity-providers/ManageOrderDialog.tsx +++ b/src/identity-providers/ManageOrderDialog.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import _ from "lodash"; +import { sortBy } from "lodash-es"; import { AlertVariant, Button, @@ -109,7 +109,7 @@ export const ManageOderDialog = ({ onDragCancel={onDragCancel} itemOrder={order} > - {_.sortBy(providers, "config.guiOrder").map((provider) => ( + {sortBy(providers, "config.guiOrder").map((provider) => ( - {_.isEqual(allowPassAuth, ["true"]) ? ( + {isEqual(allowPassAuth, ["true"]) ? ( { const settings: TestLdapConnectionRepresentation = {}; testLdapProperties.forEach((key) => { - const value = _.get(form.getValues(), `config.${key}`); + const value = get(form.getValues(), `config.${key}`); settings[key] = Array.isArray(value) ? value[0] : ""; }); @@ -285,7 +285,7 @@ export const LdapSettingsConnection = ({ > - {_.isEqual(ldapBindType, ["simple"]) && ( + {isEqual(ldapBindType, ["simple"]) && ( <> { )} /> - {_.isEqual(cachePolicyType, ["EVICT_WEEKLY"]) ? ( + {isEqual(cachePolicyType, ["EVICT_WEEKLY"]) ? ( { /> ) : null} - {_.isEqual(cachePolicyType, ["EVICT_DAILY"]) || - _.isEqual(cachePolicyType, ["EVICT_WEEKLY"]) ? ( + {isEqual(cachePolicyType, ["EVICT_DAILY"]) || + isEqual(cachePolicyType, ["EVICT_WEEKLY"]) ? ( <> { ) : null} - {_.isEqual(cachePolicyType, ["MAX_LIFESPAN"]) ? ( + {isEqual(cachePolicyType, ["MAX_LIFESPAN"]) ? ( { const adminClient = useAdminClient(); const { id } = useParams<{ id: string }>(); const alphabetize = (consentsList: UserConsentRepresentation[]) => { - return _.sortBy(consentsList, (client) => client.clientId?.toUpperCase()); + return sortBy(consentsList, (client) => client.clientId?.toUpperCase()); }; const refresh = () => setKey(new Date().getTime()); diff --git a/src/user/UserGroups.tsx b/src/user/UserGroups.tsx index d5a4847189..2426ce530b 100644 --- a/src/user/UserGroups.tsx +++ b/src/user/UserGroups.tsx @@ -9,7 +9,7 @@ import { QuestionCircleIcon } from "@patternfly/react-icons"; import { cellWidth } from "@patternfly/react-table"; import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; -import { intersectionBy, sortBy } from "lodash"; +import { intersectionBy, sortBy } from "lodash-es"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useAlerts } from "../components/alert/Alerts"; diff --git a/src/user/UserIdPModal.tsx b/src/user/UserIdPModal.tsx index 5d851cf825..440fffb6c3 100644 --- a/src/user/UserIdPModal.tsx +++ b/src/user/UserIdPModal.tsx @@ -16,7 +16,7 @@ import { useForm } from "react-hook-form"; import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; import { useAdminClient } from "../context/auth/AdminClient"; import { useAlerts } from "../components/alert/Alerts"; -import _ from "lodash"; +import { capitalize } from "lodash-es"; import { useParams } from "react-router-dom"; import type FederatedIdentityRepresentation from "@keycloak/keycloak-admin-client/lib/defs/federatedIdentityRepresentation"; import type { UserParams } from "./routes/User"; @@ -60,7 +60,7 @@ export const UserIdpModal = ({ { const [toggleUnlinkDialog, UnlinkConfirm] = useConfirmDialog({ titleKey: t("users:unlinkAccountTitle", { - provider: _.capitalize(federatedId), + provider: capitalize(federatedId), }), messageKey: t("users:unlinkAccountConfirm", { - provider: _.capitalize(federatedId), + provider: capitalize(federatedId), }), continueButtonLabel: "users:unlink", continueButtonVariant: ButtonVariant.primary, @@ -114,7 +114,7 @@ export const UserIdentityProviderLinks = () => { tab: "settings", })} > - {_.capitalize(idp.identityProvider)} + {capitalize(idp.identityProvider)} ); }; diff --git a/src/util.ts b/src/util.ts index e7fd7a9c77..e370604970 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,4 @@ -import { cloneDeep } from "lodash"; +import { cloneDeep } from "lodash-es"; import { useTranslation } from "react-i18next"; import FileSaver from "file-saver"; import type { IFormatter, IFormatterValueType } from "@patternfly/react-table"; diff --git a/src/utils/useRequiredContext.test.ts b/src/utils/useRequiredContext.test.ts index cbe0de6958..58da654e33 100644 --- a/src/utils/useRequiredContext.test.ts +++ b/src/utils/useRequiredContext.test.ts @@ -1,6 +1,6 @@ import type { Context } from "react"; import { useContext } from "react"; -import { mocked } from "ts-jest/utils"; +import { mocked } from "jest-mock"; import useRequiredContext from "./useRequiredContext"; jest.mock("react");