diff --git a/enterprise/frontend/src/metabase-enterprise/application_permissions/selectors.ts b/enterprise/frontend/src/metabase-enterprise/application_permissions/selectors.ts index c6b9d8b8fa2584a326f7ad07bdd92a339be9e1bb..a73d70533f0fbcf6b3b7ceaa4c60fd6b95911a75 100644 --- a/enterprise/frontend/src/metabase-enterprise/application_permissions/selectors.ts +++ b/enterprise/frontend/src/metabase-enterprise/application_permissions/selectors.ts @@ -1,6 +1,6 @@ import _ from "underscore"; import { t } from "ttag"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getIn } from "icepick"; import { Group } from "metabase-types/api"; import { isAdminGroup } from "metabase/lib/groups"; @@ -42,7 +42,7 @@ const getApplicationPermission = ( export const getIsDirty = createSelector( (state: ApplicationPermissionsState) => state.plugins.applicationPermissionsPlugin?.applicationPermissions, - state => + (state: ApplicationPermissionsState) => state.plugins.applicationPermissionsPlugin?.originalApplicationPermissions, (permissions, originalPermissions) => !_.isEqual(permissions, originalPermissions), diff --git a/enterprise/frontend/src/metabase-enterprise/sandboxes/selectors.ts b/enterprise/frontend/src/metabase-enterprise/sandboxes/selectors.ts index 69f434e6893afc29268adff426a26a9dbb6fbaf4..bddd6a20b53f7aded192454ee06b1730b268ac1b 100644 --- a/enterprise/frontend/src/metabase-enterprise/sandboxes/selectors.ts +++ b/enterprise/frontend/src/metabase-enterprise/sandboxes/selectors.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { GroupTableAccessPolicyParams, SandboxesState } from "./types"; import { getPolicyKeyFromParams } from "./utils"; diff --git a/frontend/src/metabase/account/notifications/selectors.js b/frontend/src/metabase/account/notifications/selectors.js index 5558b68e79e6a947f636c7b3df8cd4e9f94bb0bd..8fb751164958d97923f6957d96db59f251f7eafb 100644 --- a/frontend/src/metabase/account/notifications/selectors.js +++ b/frontend/src/metabase/account/notifications/selectors.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { parseTimestamp } from "metabase/lib/time"; export const getAlertId = ({ params: { alertId } }) => { diff --git a/frontend/src/metabase/account/profile/selectors.ts b/frontend/src/metabase/account/profile/selectors.ts index bff59f25a30d2629f6f3dfc543dd213f9d3e34c9..724efb4341c54fc3082b6ff5f2aa5476f0b80544 100644 --- a/frontend/src/metabase/account/profile/selectors.ts +++ b/frontend/src/metabase/account/profile/selectors.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getUser } from "metabase/selectors/user"; import { getSettings } from "metabase/selectors/settings"; diff --git a/frontend/src/metabase/admin/people/selectors.js b/frontend/src/metabase/admin/people/selectors.js index 09ab1ac33bc0b72f7288874235176d53ec12350c..3c5da4591729c2107f2d6fd5b32d86a2ef8b14a7 100644 --- a/frontend/src/metabase/admin/people/selectors.js +++ b/frontend/src/metabase/admin/people/selectors.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; export const getMemberships = state => state.admin.people.memberships; diff --git a/frontend/src/metabase/admin/permissions/selectors/collection-permissions.js b/frontend/src/metabase/admin/permissions/selectors/collection-permissions.js index 2c19391602ed9101bb77047d2be562f1c98cfde0..ffb36916b903ab27eee1ab645949cdb822d4d74a 100644 --- a/frontend/src/metabase/admin/permissions/selectors/collection-permissions.js +++ b/frontend/src/metabase/admin/permissions/selectors/collection-permissions.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { t } from "ttag"; import { getIn } from "icepick"; import _ from "underscore"; diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/breadcrumbs.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/breadcrumbs.ts index 08d2872b820554f78dda34f90341935db8a72109..f30e87fb0fad51f0904998ea835acb81bc2e1da9 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/breadcrumbs.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/breadcrumbs.ts @@ -1,5 +1,5 @@ import { Group } from "metabase-types/api"; -import { isNotNull } from "metabase/core/utils/types"; +import { isNotFalsy } from "metabase/core/utils/types"; import type Metadata from "metabase-lib/metadata/Metadata"; import type Schema from "metabase-lib/metadata/Schema"; import type Table from "metabase-lib/metadata/Table"; @@ -15,11 +15,17 @@ import { } from "../../utils/urls"; import { DataRouteParams, GroupRouteParams } from "../../types"; +export type EditorBreadcrumb = { + id?: number | string; + text: string; + url?: string; +}; + export const getDatabasesEditorBreadcrumbs = ( params: GroupRouteParams, metadata: Metadata, group: Group, -) => { +): EditorBreadcrumb[] | null => { const { groupId, databaseId, schemaName } = params; if (groupId == null) { @@ -59,7 +65,7 @@ export const getDatabasesEditorBreadcrumbs = ( export const getGroupsDataEditorBreadcrumbs = ( params: DataRouteParams, metadata: Metadata, -) => { +): EditorBreadcrumb[] | null => { const { databaseId, schemaName, tableId } = params; if (databaseId == null) { @@ -91,7 +97,7 @@ export const getGroupsDataEditorBreadcrumbs = ( const hasMultipleSchemas = database.schemasCount() > 1; if (tableId == null) { - return [databaseItem, hasMultipleSchemas && schemaItem].filter(isNotNull); + return [databaseItem, hasMultipleSchemas && schemaItem].filter(isNotFalsy); } const table = metadata.table(tableId) as Table; @@ -102,6 +108,6 @@ export const getGroupsDataEditorBreadcrumbs = ( }; return [databaseItem, hasMultipleSchemas && schemaItem, tableItem].filter( - Boolean, + isNotFalsy, ); }; diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.ts index 41e5a21d63169991afff235ce50ee72ce5ab85f8..b4b6fe1c00c0c488b151a6d2d753489295036032 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.ts @@ -1,11 +1,13 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; +import type { Selector } from "@reduxjs/toolkit"; import { t } from "ttag"; import { getMetadataWithHiddenTables } from "metabase/selectors/metadata"; -import { State } from "metabase-types/store"; import { ITreeNodeItem } from "metabase/components/tree/types"; import { isNotNull } from "metabase/core/utils/types"; + +import { State } from "metabase-types/store"; import Database from "metabase-lib/metadata/Database"; import Metadata from "metabase-lib/metadata/Metadata"; import { EntityId, RawDataRouteParams } from "../../types"; @@ -17,6 +19,20 @@ import { import { getDatabase } from "../../utils/metadata"; import { getIsLoadingDatabaseTables } from "./permission-editor"; +type DataTreeNodeItem = { + entityId: EntityId; + children?: DataTreeNodeItem[]; +} & ITreeNodeItem; + +type DataSidebarProps = { + title?: string; + description?: string; + entityGroups: DataTreeNodeItem[][]; + entityViewFocus?: "database"; + selectedId?: string | null; + filterPlaceholder?: string; +}; + const getRouteParams = ( _state: State, props: { params: RawDataRouteParams }, @@ -32,7 +48,7 @@ const getRouteParams = ( const getSchemaId = (name: string) => `schema:${name}`; const getTableId = (id: string | number) => `table:${id}`; -const getDatabasesSidebar = (metadata: Metadata) => { +const getDatabasesSidebar = (metadata: Metadata): DataSidebarProps => { const entities = metadata .databasesList({ savedQuestions: false }) .map(database => ({ @@ -49,16 +65,11 @@ const getDatabasesSidebar = (metadata: Metadata) => { }; }; -type DataTreeNodeItem = { - entityId: EntityId; - children?: DataTreeNodeItem[]; -} & ITreeNodeItem; - const getTablesSidebar = ( database: Database, schemaName?: string, tableId?: string, -) => { +): DataSidebarProps => { let selectedId = null; if (tableId != null) { @@ -102,23 +113,24 @@ const getTablesSidebar = ( }; }; -export const getDataFocusSidebar = createSelector( - getMetadataWithHiddenTables, - getRouteParams, - getIsLoadingDatabaseTables, - (metadata, params, isLoading) => { - if (isLoading) { - return null; - } +export const getDataFocusSidebar: Selector<State, DataSidebarProps | null> = + createSelector( + getMetadataWithHiddenTables, + getRouteParams, + getIsLoadingDatabaseTables, + (metadata, params, isLoading) => { + if (isLoading) { + return null; + } - const { databaseId, schemaName, tableId } = params; + const { databaseId, schemaName, tableId } = params; - if (databaseId == null) { - return getDatabasesSidebar(metadata); - } + if (databaseId == null) { + return getDatabasesSidebar(metadata); + } - const database = getDatabase(metadata, databaseId); + const database = getDatabase(metadata, databaseId); - return getTablesSidebar(database, schemaName, tableId); - }, -); + return getTablesSidebar(database, schemaName, tableId); + }, + ); diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.unit.spec.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.unit.spec.ts index 62456455d1e4059bb3bed1f8f234dc649dcb2361..7428854a152456ad6cc429872e9a2307737d9489 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.unit.spec.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/data-sidebar.unit.spec.ts @@ -1,7 +1,10 @@ +import type { State } from "metabase-types/store"; import { RawDataRouteParams } from "../../types"; -import { state } from "./data-permissions.unit.spec.fixtures"; +import { state as mockState } from "./data-permissions.unit.spec.fixtures"; import { getDataFocusSidebar } from "."; +const state = mockState as unknown as State; + const getRouteProps = ({ databaseId, schemaName, @@ -18,7 +21,7 @@ describe("getDataFocusSidebar", () => { describe("when database is not selected", () => { it("returns a correct placeholder for databases list search", () => { const sidebarData = getDataFocusSidebar( - state as any, + state, getRouteProps({ databaseId: undefined }), ); @@ -26,7 +29,7 @@ describe("getDataFocusSidebar", () => { }); it("returns list of databases", () => { - const sidebarData = getDataFocusSidebar(state as any, getRouteProps({})); + const sidebarData = getDataFocusSidebar(state, getRouteProps({})); expect(sidebarData?.entityGroups).toEqual([ [ @@ -54,7 +57,7 @@ describe("getDataFocusSidebar", () => { describe("when a database is selected", () => { it("returns a correct placeholder for databases list search", () => { const sidebarData = getDataFocusSidebar( - state as any, + state, getRouteProps({ databaseId: "2" }), ); @@ -63,7 +66,7 @@ describe("getDataFocusSidebar", () => { it("returns tree of schemas and tables for a database with schemas", () => { const sidebarData = getDataFocusSidebar( - state as any, + state, getRouteProps({ databaseId: "2" }), ); diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/diff.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/diff.ts index d2f682ef57027384ce7631529ec470ad700f8263..35c4f47bf483ec68547bafc313309a334dda6821 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/diff.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/diff.ts @@ -1,13 +1,16 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; +import type { Selector } from "@reduxjs/toolkit"; import _ from "underscore"; -import { State } from "metabase-types/store"; -import Groups from "metabase/entities/groups"; + import { diffDataPermissions } from "metabase/admin/permissions/utils/graph"; -import { Group } from "metabase-types/api"; +import Groups from "metabase/entities/groups"; import { PLUGIN_DATA_PERMISSIONS } from "metabase/plugins"; + +import { Database } from "metabase-types/api"; +import { State } from "metabase-types/store"; import { isVirtualCardId } from "metabase-lib/metadata/utils/saved-questions"; -const getDatabasesWithTables = createSelector( +const getDatabasesWithTables: Selector<State, Database[]> = createSelector( (state: State) => state.entities.databases, (state: State) => state.entities.tables, (databases, tables) => { @@ -23,8 +26,7 @@ const getDatabasesWithTables = createSelector( ); return { - id: database.id, - name: database.name, + ...database, tables: databaseTables, }; }); @@ -42,13 +44,8 @@ export const getIsDirty = createSelector( export const getDiff = createSelector( getDatabasesWithTables, Groups.selectors.getList, - state => state.admin.permissions.dataPermissions, - state => state.admin.permissions.originalDataPermissions, + (state: State) => state.admin.permissions.dataPermissions, + (state: State) => state.admin.permissions.originalDataPermissions, (databases, groups, permissions, originalPermissions) => - diffDataPermissions( - permissions, - originalPermissions, - groups as Group[], - databases as any, - ), + diffDataPermissions(permissions, originalPermissions, groups, databases), ); diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/fields.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/fields.ts index 6b63c8357fd7494b564f9142e54e6d23410e02ea..340a049fe28591e118fbd0e7823d59099b9bd92e 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/fields.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/fields.ts @@ -22,7 +22,7 @@ import { UNABLE_TO_CHANGE_ADMIN_PERMISSIONS, } from "../../constants/messages"; import { DATA_PERMISSION_OPTIONS } from "../../constants/data-permissions"; -import { TableEntityId } from "../../types"; +import { TableEntityId, PermissionSectionConfig } from "../../types"; const buildAccessPermission = ( entityId: TableEntityId, @@ -114,7 +114,7 @@ export const buildFieldsPermissions = ( permissions: GroupsPermissions, defaultGroup: Group, database: Database, -) => { +): PermissionSectionConfig[] => { const accessPermission = buildAccessPermission( entityId, groupId, diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.ts index 15fc5f53000241f6999d07dcd5035389aeecac46..06aac8b0f3dddfcb64ab5112714b808958374c60 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { t } from "ttag"; import { State } from "metabase-types/store"; diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.unit.spec.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.unit.spec.ts index 2540c7241b70f66a10dc1a2a5ad1968bd8455f47..836d615b6bbbdc0c41f8192ca0b2fff71d93cd7a 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.unit.spec.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/group-sidebar.unit.spec.ts @@ -1,9 +1,12 @@ -import { state } from "./data-permissions.unit.spec.fixtures"; +import type { State } from "metabase-types/store"; +import { state as mockState } from "./data-permissions.unit.spec.fixtures"; import { getGroupsDataPermissionEditor } from "."; +const state = mockState as unknown as State; + describe("getGroupsDataPermissionEditor", () => { it("returns data for permission editor header", () => { - const permissionEditorData = getGroupsDataPermissionEditor(state as any, { + const permissionEditorData = getGroupsDataPermissionEditor(state, { params: { databaseId: 3, }, @@ -23,7 +26,7 @@ describe("getGroupsDataPermissionEditor", () => { }); it("returns entities list for permissions editor", () => { - const entities = getGroupsDataPermissionEditor(state as any, { + const entities = getGroupsDataPermissionEditor(state, { params: { databaseId: 3, }, diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/groups.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/groups.ts index 4156bea63b478dcb801228df5632e87788e42ec2..423da677e2b8bb0b503b773ed445dcefd9f0fb85 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/groups.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/groups.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; import Groups from "metabase/entities/groups"; diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/permission-editor.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/permission-editor.ts index ce8b09f6828696bc654fe81ed8c5e79e989b89e7..041a94fa69600644f37a83f9bdb9db10db218006 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/permission-editor.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/permission-editor.ts @@ -1,4 +1,5 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; +import type { Selector } from "@reduxjs/toolkit"; import { msgid, ngettext, t } from "ttag"; import _ from "underscore"; @@ -8,7 +9,7 @@ import Groups from "metabase/entities/groups"; import Tables from "metabase/entities/tables"; import { isAdminGroup, isDefaultGroup } from "metabase/lib/groups"; -import { Group, GroupsPermissions } from "metabase-types/api"; +import { Database, Group, GroupsPermissions, Table } from "metabase-types/api"; import { State } from "metabase-types/store"; import { PLUGIN_FEATURE_LEVEL_PERMISSIONS } from "metabase/plugins"; import Schema from "metabase-lib/metadata/Schema"; @@ -19,13 +20,18 @@ import { getPermissionSubject, } from "../../utils/data-entity-id"; -import { DataRouteParams, RawGroupRouteParams } from "../../types"; +import { + DataRouteParams, + RawGroupRouteParams, + PermissionSectionConfig, +} from "../../types"; import { buildFieldsPermissions } from "./fields"; import { buildTablesPermissions } from "./tables"; import { buildSchemasPermissions } from "./schemas"; import { getDatabasesEditorBreadcrumbs, getGroupsDataEditorBreadcrumbs, + EditorBreadcrumb, } from "./breadcrumbs"; import { getOrderedGroups } from "./groups"; @@ -52,7 +58,14 @@ export const getLoadingDatabaseTablesError = ( }); }; -const getRouteParams = (_state: State, props: { params: DataRouteParams }) => { +type RouteParamsSelectorParameters = { + params: DataRouteParams; +}; + +const getRouteParams = ( + _state: State, + props: RouteParamsSelectorParameters, +) => { const { databaseId, schemaName, tableId } = props.params; return { databaseId, @@ -248,92 +261,124 @@ export const getDatabasesPermissionEditor = createSelector( }, ); -export const getGroupsDataPermissionEditor = createSelector( - getMetadataWithHiddenTables, - getRouteParams, - getDataPermissions, - getOrderedGroups, - (metadata, params, permissions, groups: Group[][]) => { - const { databaseId, schemaName, tableId } = params; - const database = metadata?.database(databaseId); +type DataPermissionEditorEntity = { + id: Group["id"]; + name: Group["name"]; + hint: string | null; + entityId: { + databaseId?: Database["id"]; + schemaName?: Schema["name"]; + tableId?: Table["id"]; + }; + permissions?: PermissionSectionConfig[]; +}; - if (!permissions || databaseId == null || !database) { - return null; - } +type DataPermissionEditorProps = { + title: string; + filterPlaceholder: string; + breadcrumbs: EditorBreadcrumb[] | null; + columns: { name: string }[]; + entities: DataPermissionEditorEntity[]; +}; - const sortedGroups = groups.flat(); +type GetGroupsDataPermissionEditorSelectorParameters = + RouteParamsSelectorParameters & { + includeHiddenTables?: boolean; + }; - const defaultGroup = _.find(sortedGroups, isDefaultGroup); +type GetGroupsDataPermissionEditorSelector = Selector< + State, + DataPermissionEditorProps | null, + GetGroupsDataPermissionEditorSelectorParameters[] +>; + +export const getGroupsDataPermissionEditor: GetGroupsDataPermissionEditorSelector = + createSelector( + getMetadataWithHiddenTables, + getRouteParams, + getDataPermissions, + getOrderedGroups, + (metadata, params, permissions, groups) => { + const { databaseId, schemaName, tableId } = params; + const database = metadata?.database(databaseId); + + if (!permissions || databaseId == null || !database) { + return null; + } - if (!defaultGroup) { - throw new Error("No default group found"); - } + const sortedGroups = groups.flat(); - const permissionSubject = getPermissionSubject(params); - const columns = [ - { name: t`Group name` }, - { name: t`Data access` }, - { name: t`Native query editing` }, - ...PLUGIN_FEATURE_LEVEL_PERMISSIONS.getDataColumns(permissionSubject), - ]; + const defaultGroup = _.find(sortedGroups, isDefaultGroup); - const entities = sortedGroups.map(group => { - const isAdmin = isAdminGroup(group); - let groupPermissions; - - if (tableId != null) { - groupPermissions = buildFieldsPermissions( - { - databaseId, - schemaName, - tableId, - }, - group.id, - isAdmin, - permissions, - defaultGroup, - database, - ); - } else if (schemaName != null) { - groupPermissions = buildTablesPermissions( - { - databaseId, - schemaName, - }, - group.id, - isAdmin, - permissions, - defaultGroup, - ); - } else if (databaseId != null) { - groupPermissions = buildSchemasPermissions( - { - databaseId, - }, - group.id, - isAdmin, - permissions, - defaultGroup, - ); + if (!defaultGroup) { + throw new Error("No default group found"); } + const permissionSubject = getPermissionSubject(params); + const columns = [ + { name: t`Group name` }, + { name: t`Data access` }, + { name: t`Native query editing` }, + ...PLUGIN_FEATURE_LEVEL_PERMISSIONS.getDataColumns(permissionSubject), + ]; + + const entities = sortedGroups.map(group => { + const isAdmin = isAdminGroup(group); + let groupPermissions; + + if (tableId != null) { + groupPermissions = buildFieldsPermissions( + { + databaseId, + schemaName, + tableId, + }, + group.id, + isAdmin, + permissions, + defaultGroup, + database, + ); + } else if (schemaName != null) { + groupPermissions = buildTablesPermissions( + { + databaseId, + schemaName, + }, + group.id, + isAdmin, + permissions, + defaultGroup, + ); + } else if (databaseId != null) { + groupPermissions = buildSchemasPermissions( + { + databaseId, + }, + group.id, + isAdmin, + permissions, + defaultGroup, + ); + } + + return { + id: group.id, + name: group.name, + hint: isAdmin + ? t`The Administrators group is special, and always has Unrestricted access.` + : null, + entityId: params, + permissions: groupPermissions, + }; + }); + return { - id: group.id, - name: group.name, - hint: isAdmin - ? t`The Administrators group is special, and always has Unrestricted access.` - : null, - entityId: params, - permissions: groupPermissions, + title: t`Permissions for`, + filterPlaceholder: t`Search for a group`, + breadcrumbs: getGroupsDataEditorBreadcrumbs(params, metadata), + columns, + entities, }; - }); - - return { - title: t`Permissions for`, - filterPlaceholder: t`Search for a group`, - breadcrumbs: getGroupsDataEditorBreadcrumbs(params, metadata), - columns, - entities, - }; - }, -); + }, + ); diff --git a/frontend/src/metabase/admin/permissions/selectors/data-permissions/tables.ts b/frontend/src/metabase/admin/permissions/selectors/data-permissions/tables.ts index e031d46ccacc6b66089fda773d0a0bd270e03a72..905e9245777d74807d0be6f95c7705666ac09a47 100644 --- a/frontend/src/metabase/admin/permissions/selectors/data-permissions/tables.ts +++ b/frontend/src/metabase/admin/permissions/selectors/data-permissions/tables.ts @@ -19,7 +19,7 @@ import { getPermissionWarningModal, getControlledDatabaseWarningModal, } from "../confirmations"; -import { SchemaEntityId } from "../../types"; +import { SchemaEntityId, PermissionSectionConfig } from "../../types"; import { getGroupFocusPermissionsUrl } from "../../utils/urls"; const buildAccessPermission = ( @@ -104,7 +104,7 @@ export const buildTablesPermissions = ( isAdmin: boolean, permissions: GroupsPermissions, defaultGroup: Group, -) => { +): PermissionSectionConfig[] => { const accessPermission = buildAccessPermission( entityId, groupId, diff --git a/frontend/src/metabase/admin/permissions/types.ts b/frontend/src/metabase/admin/permissions/types.ts index 405ac8d7f822ad3364b76270c5b1a6a941bcfbfc..8d283414a3a3ebddc1b6b9218db26313a85a1916 100644 --- a/frontend/src/metabase/admin/permissions/types.ts +++ b/frontend/src/metabase/admin/permissions/types.ts @@ -40,3 +40,31 @@ export type EntityId = DatabaseEntityId & export type DataPermission = "data" | "download" | "data-model" | "details"; export type PermissionSubject = "schemas" | "tables" | "fields"; + +export type PermissionSectionConfig = { + permission: string; + type: string; + isDisabled: boolean; + disabledTooltip: string | null; + isHighlighted: boolean; + value: string; + warning: string | null; + options: { + label: string; + value: string; + icon: string; + iconColor: string; + }[]; + actions: { + controlled: { + label: string; + icon: string; + iconColor: string; + actionCreator: (...args: unknown[]) => void; + }[]; + }; + postActions: { + controlled: null | ((...args: unknown[]) => void); + }; + confirmations: unknown[]; +}; diff --git a/frontend/src/metabase/admin/permissions/utils/graph/permissions-diff.ts b/frontend/src/metabase/admin/permissions/utils/graph/permissions-diff.ts index 163bfad2f21a8037cb8fc75281e5d1b8739618de..d1e943aa4221eb7db35fa394fa0777cb2ac454f0 100644 --- a/frontend/src/metabase/admin/permissions/utils/graph/permissions-diff.ts +++ b/frontend/src/metabase/admin/permissions/utils/graph/permissions-diff.ts @@ -1,9 +1,9 @@ import type { + ConcreteTableId, + Database, Group, GroupsPermissions, - ConcreteTableId, } from "metabase-types/api"; -import type Database from "metabase-lib/metadata/Database"; import { getFieldsPermission, getNativePermission, @@ -41,7 +41,7 @@ function diffDatabasePermissions( databaseDiff.native = newNativePerm; } // check each table in this db - for (const table of database.tables) { + for (const table of database.tables ?? []) { const oldFieldsPerm = getFieldsPermission( oldPerms, groupId, diff --git a/frontend/src/metabase/admin/settings/selectors.js b/frontend/src/metabase/admin/settings/selectors.js index a3dec68ba0f850425531a41d7fb942ae6353182a..4b74d2c14dc85cd53d01034102ffb401d36ff237 100644 --- a/frontend/src/metabase/admin/settings/selectors.js +++ b/frontend/src/metabase/admin/settings/selectors.js @@ -1,7 +1,7 @@ /* eslint-disable react/display-name */ import React from "react"; import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { t, jt } from "ttag"; import ExternalLink from "metabase/core/components/ExternalLink"; import MetabaseSettings from "metabase/lib/settings"; diff --git a/frontend/src/metabase/auth/selectors.ts b/frontend/src/metabase/auth/selectors.ts index 2bff3bbdee297a5e0311f84465606de98509ce95..3e591d6347a3096c6cbcdcf2a0180e585adb6fbe 100644 --- a/frontend/src/metabase/auth/selectors.ts +++ b/frontend/src/metabase/auth/selectors.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getSettings } from "metabase/selectors/settings"; import { PLUGIN_AUTH_PROVIDERS } from "metabase/plugins"; diff --git a/frontend/src/metabase/core/components/Select/Select.tsx b/frontend/src/metabase/core/components/Select/Select.tsx index 845f8ebd6ea2a87a132c98c1d00a276191073e44..5ff24052e08b1a819ae4b6a0627a4d0a6228061f 100644 --- a/frontend/src/metabase/core/components/Select/Select.tsx +++ b/frontend/src/metabase/core/components/Select/Select.tsx @@ -9,7 +9,7 @@ import React, { import _ from "underscore"; import cx from "classnames"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import Icon from "metabase/components/Icon"; import PopoverWithTrigger from "metabase/components/PopoverWithTrigger"; import SelectButton, { diff --git a/frontend/src/metabase/core/utils/types/index.ts b/frontend/src/metabase/core/utils/types/index.ts index 10b604b77046b0b47ba6e2ba11bc468402e643c1..eea524d655708d7561b53642ce62e241627eece6 100644 --- a/frontend/src/metabase/core/utils/types/index.ts +++ b/frontend/src/metabase/core/utils/types/index.ts @@ -1 +1 @@ -export { isNotNull, checkNotNull } from "./types"; +export * from "./types"; diff --git a/frontend/src/metabase/core/utils/types/types.ts b/frontend/src/metabase/core/utils/types/types.ts index db53810a336cb210d4152fc76d5def58e9191509..d5329923776027abcccaafbacc85b80cf476a759 100644 --- a/frontend/src/metabase/core/utils/types/types.ts +++ b/frontend/src/metabase/core/utils/types/types.ts @@ -2,6 +2,12 @@ export const isNotNull = <T>(value: T | null | undefined): value is T => { return value != null; }; +export const isNotFalsy = <T>( + value: T | null | undefined | false, +): value is T => { + return value != null; +}; + export const checkNotNull = <T>(value: T | null | undefined): T => { if (value != null) { return value; diff --git a/frontend/src/metabase/dashboard/components/AddSeriesModal/AddSeriesModal.jsx b/frontend/src/metabase/dashboard/components/AddSeriesModal/AddSeriesModal.jsx index ecc34ea3acc42008eaa6df1170591fa80602b27d..619bf81dcc18a8ac61eb783d4aab9f572d73b55f 100644 --- a/frontend/src/metabase/dashboard/components/AddSeriesModal/AddSeriesModal.jsx +++ b/frontend/src/metabase/dashboard/components/AddSeriesModal/AddSeriesModal.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { t } from "ttag"; import { getIn } from "icepick"; import { connect } from "react-redux"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; import Visualization from "metabase/visualizations/components/Visualization"; diff --git a/frontend/src/metabase/dashboard/selectors.js b/frontend/src/metabase/dashboard/selectors.js index 4654af7f3b71b23be31477ba85265f1b9f3a0782..4e6262e81135f7ec4ef9dee944f20624e0d418ae 100644 --- a/frontend/src/metabase/dashboard/selectors.js +++ b/frontend/src/metabase/dashboard/selectors.js @@ -1,6 +1,6 @@ import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getMetadata } from "metabase/selectors/metadata"; import { LOAD_COMPLETE_FAVICON } from "metabase/hoc/Favicon"; diff --git a/frontend/src/metabase/databases/containers/DatabaseSyncModal/DatabaseSyncModal.tsx b/frontend/src/metabase/databases/containers/DatabaseSyncModal/DatabaseSyncModal.tsx index b45b7d04e982548310340c3567dfa4842af7ca3a..820038f74c6048ba30cf778d6e03b9d0288c276e 100644 --- a/frontend/src/metabase/databases/containers/DatabaseSyncModal/DatabaseSyncModal.tsx +++ b/frontend/src/metabase/databases/containers/DatabaseSyncModal/DatabaseSyncModal.tsx @@ -1,5 +1,5 @@ import { connect } from "react-redux"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; import Databases from "metabase/entities/databases"; import DatabaseCandidates from "metabase/entities/database-candidates"; diff --git a/frontend/src/metabase/entities/bookmarks.js b/frontend/src/metabase/entities/bookmarks.js index d9e8c9ea021cbac1ec4d7e46627236e5b49dc25c..006d2099c0263fea683465fd7255ed8257815c88 100644 --- a/frontend/src/metabase/entities/bookmarks.js +++ b/frontend/src/metabase/entities/bookmarks.js @@ -1,6 +1,6 @@ import { assoc, updateIn, dissoc } from "icepick"; import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { createEntity } from "metabase/lib/entities"; import Collections from "metabase/entities/collections"; import Dashboards from "metabase/entities/dashboards"; diff --git a/frontend/src/metabase/entities/collections/collections.ts b/frontend/src/metabase/entities/collections/collections.ts index 3925687002e4906cefe8e024af15644e237ff3a6..a32837b4c824538a061182258847d8b841d1f82b 100644 --- a/frontend/src/metabase/entities/collections/collections.ts +++ b/frontend/src/metabase/entities/collections/collections.ts @@ -1,5 +1,5 @@ import { t } from "ttag"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { GET } from "metabase/lib/api"; import { createEntity, undo } from "metabase/lib/entities"; diff --git a/frontend/src/metabase/entities/collections/getInitialCollectionId.ts b/frontend/src/metabase/entities/collections/getInitialCollectionId.ts index 642903704d753917a5f0c9695bea427e397e0b18..4762ce1eadf10ef21be468c0715a98bb10adf85a 100644 --- a/frontend/src/metabase/entities/collections/getInitialCollectionId.ts +++ b/frontend/src/metabase/entities/collections/getInitialCollectionId.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import type { Location } from "history"; import * as Urls from "metabase/lib/urls"; diff --git a/frontend/src/metabase/entities/containers/EntityListLoader.jsx b/frontend/src/metabase/entities/containers/EntityListLoader.jsx index 4f528c029c7a07daf59d6922c0da93fe67e72783..9a935794d26e14283c40d961a0be0358844351e0 100644 --- a/frontend/src/metabase/entities/containers/EntityListLoader.jsx +++ b/frontend/src/metabase/entities/containers/EntityListLoader.jsx @@ -2,9 +2,8 @@ import React from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; -import { createSelector } from "reselect"; -import { createMemoizedSelector } from "metabase/lib/redux"; import paginationState from "metabase/hoc/PaginationState"; import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper"; @@ -72,13 +71,12 @@ const getEntityQuery = (state, props) => ? props.entityQuery(state, props) : props.entityQuery; -// NOTE: Memoize entityQuery so we don't re-render even if a new but identical -// object is created. This works because entityQuery must be JSON serializable -// NOTE: Technically leaks a small amount of memory because it uses an unbounded -// memoization cache, but that's probably ok. -const getMemoizedEntityQuery = createMemoizedSelector( - [getEntityQuery], +const getMemoizedEntityQuery = createSelector( + getEntityQuery, entityQuery => entityQuery, + { + equalityFn: _.isEqual, + }, ); class EntityListLoaderInner extends React.Component { diff --git a/frontend/src/metabase/entities/containers/EntityObjectLoader.jsx b/frontend/src/metabase/entities/containers/EntityObjectLoader.jsx index 70ea3456de16f3ffd6e850ddb48ac814e0a75f55..86103ac87e3a81a06fce9743f49f4d524b7ffc56 100644 --- a/frontend/src/metabase/entities/containers/EntityObjectLoader.jsx +++ b/frontend/src/metabase/entities/containers/EntityObjectLoader.jsx @@ -1,10 +1,9 @@ /* eslint-disable react/prop-types */ import React from "react"; import { connect } from "react-redux"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; -import { createMemoizedSelector } from "metabase/lib/redux"; import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper"; import entityType from "./EntityType"; @@ -23,11 +22,12 @@ const CONSUMED_PROPS = [ "requestType", ]; -// NOTE: Memoize entityQuery so we don't re-render even if a new but identical -// object is created. This works because entityQuery must be JSON serializable -const getMemoizedEntityQuery = createMemoizedSelector( +const getMemoizedEntityQuery = createSelector( (state, entityQuery) => entityQuery, entityQuery => entityQuery, + { + equalityFn: _.isEqual, + }, ); class EntityObjectLoaderInner extends React.Component { diff --git a/frontend/src/metabase/entities/databases.js b/frontend/src/metabase/entities/databases.js index 6925a42ef7161146a009812058ca0e73b0d84735..ba94a37f000e1a9575262574ff5bbfcb6596633c 100644 --- a/frontend/src/metabase/entities/databases.js +++ b/frontend/src/metabase/entities/databases.js @@ -1,7 +1,7 @@ import { normalize } from "normalizr"; import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { createEntity } from "metabase/lib/entities"; import * as Urls from "metabase/lib/urls"; import { color } from "metabase/lib/colors"; diff --git a/frontend/src/metabase/entities/persisted-models.js b/frontend/src/metabase/entities/persisted-models.js index f2267f339c9786ac63b1a9acea3352a9bbcb938a..934e0e2bd5f737ee8d9296154f7bcf0680d9ebeb 100644 --- a/frontend/src/metabase/entities/persisted-models.js +++ b/frontend/src/metabase/entities/persisted-models.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { PersistedModelSchema } from "metabase/schema"; import { createEntity } from "metabase/lib/entities"; import { CardApi, PersistedModelsApi } from "metabase/services"; diff --git a/frontend/src/metabase/entities/snippet-collections.js b/frontend/src/metabase/entities/snippet-collections.js index b6acb049577044aedceab982a59702406a553ad9..20c38df717a07e998a25524186382bf339526ba7 100644 --- a/frontend/src/metabase/entities/snippet-collections.js +++ b/frontend/src/metabase/entities/snippet-collections.js @@ -1,6 +1,6 @@ import _ from "underscore"; import { t } from "ttag"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { createEntity, undo } from "metabase/lib/entities"; import { SnippetCollectionSchema } from "metabase/schema"; diff --git a/frontend/src/metabase/entities/tables.js b/frontend/src/metabase/entities/tables.js index a198fd8f8805d94bda32df0f53e04979d0d02835..2d3cb73f33b8e693ebe7e310a1181be7cf926535 100644 --- a/frontend/src/metabase/entities/tables.js +++ b/frontend/src/metabase/entities/tables.js @@ -1,6 +1,6 @@ import { t } from "ttag"; import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { updateIn } from "icepick"; import { createEntity, notify } from "metabase/lib/entities"; import { diff --git a/frontend/src/metabase/lib/entities.js b/frontend/src/metabase/lib/entities.js index c4338c3ad92fc4df42b7521fbca10d3aeda3a9fa..2610d56e66878b0af936913f7a2231ed276d9eaa 100644 --- a/frontend/src/metabase/lib/entities.js +++ b/frontend/src/metabase/lib/entities.js @@ -73,7 +73,7 @@ import createCachedSelector from "re-reselect"; // NOTE: need to use inflection directly here due to circular dependency import inflection from "inflection"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { normalize, denormalize, schema } from "normalizr"; import { getIn, merge } from "icepick"; import _ from "underscore"; diff --git a/frontend/src/metabase/lib/redux/utils.js b/frontend/src/metabase/lib/redux/utils.js index 164934ff5e055c85c1e489ed60783a47c6b2eb3c..26efd9649c7d7234519a19b15e33cfb2d09f7e2f 100644 --- a/frontend/src/metabase/lib/redux/utils.js +++ b/frontend/src/metabase/lib/redux/utils.js @@ -3,7 +3,6 @@ import _ from "underscore"; import { getIn } from "icepick"; import { normalize } from "normalizr"; import { compose } from "@reduxjs/toolkit"; -import { createSelectorCreator } from "reselect"; import * as MetabaseAnalytics from "metabase/lib/analytics"; import { @@ -183,11 +182,6 @@ export const formDomOnlyProps = ({ ...domProps }) => domProps; -export const createMemoizedSelector = createSelectorCreator( - _.memoize, - (...args) => JSON.stringify(args), -); - // THUNK DECORATORS /** diff --git a/frontend/src/metabase/metabot/selectors.ts b/frontend/src/metabase/metabot/selectors.ts index 663f78e52c5cb32724dc35b2a9b5455f25d968c1..f7b3ac01b8754aa618f572fbd338237f6080b41a 100644 --- a/frontend/src/metabase/metabot/selectors.ts +++ b/frontend/src/metabase/metabot/selectors.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getMetadata } from "metabase/selectors/metadata"; import { State } from "metabase-types/store"; import Question from "metabase-lib/Question"; diff --git a/frontend/src/metabase/pulse/selectors.js b/frontend/src/metabase/pulse/selectors.js index ee8b4ef454434df889d14e62e7dc04e84c1fcfac..cd8e82e56596d2253cc8bc2f7d6df8f9bdba532e 100644 --- a/frontend/src/metabase/pulse/selectors.js +++ b/frontend/src/metabase/pulse/selectors.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; export const getEditingPulse = state => state.pulse.editingPulse; diff --git a/frontend/src/metabase/query_builder/selectors.js b/frontend/src/metabase/query_builder/selectors.js index dcd28e0426a56220936c9b9e8701a183ee212257..14606d86870d7ae4a6559be394f6ec04080e3414 100644 --- a/frontend/src/metabase/query_builder/selectors.js +++ b/frontend/src/metabase/query_builder/selectors.js @@ -1,7 +1,7 @@ /*eslint no-use-before-define: "error"*/ import d3 from "d3"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import createCachedSelector from "re-reselect"; import _ from "underscore"; import { getIn, merge, updateIn } from "icepick"; diff --git a/frontend/src/metabase/reference/selectors.js b/frontend/src/metabase/reference/selectors.js index 5251045e56734bc18ef0cbbba3dd46a72e9136ce..4cea36d1454e5c1c778a334035fc293ba6b5ec3a 100644 --- a/frontend/src/metabase/reference/selectors.js +++ b/frontend/src/metabase/reference/selectors.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { assoc, getIn } from "icepick"; import Dashboards from "metabase/entities/dashboards"; diff --git a/frontend/src/metabase/selectors/app.ts b/frontend/src/metabase/selectors/app.ts index e2809f5f9f06b073d48f5eba924cc5112123fee3..0339272faed6d6d1af18d1dc8dcd63dc57f8f48e 100644 --- a/frontend/src/metabase/selectors/app.ts +++ b/frontend/src/metabase/selectors/app.ts @@ -1,5 +1,5 @@ import { Location } from "history"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getUser } from "metabase/selectors/user"; import { getIsEditing as getIsEditingDashboard, diff --git a/frontend/src/metabase/selectors/embed.ts b/frontend/src/metabase/selectors/embed.ts index 5410680ce428ec131e3761026db81dcd72c44442..b01d1135071b52daaf3d3bb7ca38446e99ba8907 100644 --- a/frontend/src/metabase/selectors/embed.ts +++ b/frontend/src/metabase/selectors/embed.ts @@ -1,7 +1,7 @@ import { isWithinIframe } from "metabase/lib/dom"; import { State } from "metabase-types/store"; -export const getIsEmbedded = () => { +export const getIsEmbedded = (state: State) => { return isWithinIframe(); }; diff --git a/frontend/src/metabase/selectors/metadata.js b/frontend/src/metabase/selectors/metadata.js index 85f58fd6f875432578b8a0b949223fbced199a36..4ad05ca3b49eebdb6a4da28e7bcfd2100587d78d 100644 --- a/frontend/src/metabase/selectors/metadata.js +++ b/frontend/src/metabase/selectors/metadata.js @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import _ from "underscore"; import { isVirtualCardId } from "metabase-lib/metadata/utils/saved-questions"; diff --git a/frontend/src/metabase/selectors/settings.ts b/frontend/src/metabase/selectors/settings.ts index a1231370fac88edc3abf46df37260a124124de99..f85de9746506e6cfbff671f37d93493030737648 100644 --- a/frontend/src/metabase/selectors/settings.ts +++ b/frontend/src/metabase/selectors/settings.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import type { Settings, SettingKey, TokenFeatures } from "metabase-types/api"; import type { State } from "metabase-types/store"; diff --git a/frontend/src/metabase/selectors/user.ts b/frontend/src/metabase/selectors/user.ts index 0f46fdf65521df2e550ba5a6aaa077ed681a0df7..0f82edad0ed20baf6f4d2cfb299ae849dc3acf34 100644 --- a/frontend/src/metabase/selectors/user.ts +++ b/frontend/src/metabase/selectors/user.ts @@ -1,4 +1,4 @@ -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { PLUGIN_APPLICATION_PERMISSIONS } from "metabase/plugins"; import type { State } from "metabase-types/store"; diff --git a/frontend/src/metabase/styled-components/selectors.ts b/frontend/src/metabase/styled-components/selectors.ts index 944b2540038b53fb0b16f5eb3f8ca0b4558bcff2..fdfb3e09b6ff85da1d8b2ab42478259ea1ddc964 100644 --- a/frontend/src/metabase/styled-components/selectors.ts +++ b/frontend/src/metabase/styled-components/selectors.ts @@ -1,5 +1,5 @@ import _ from "underscore"; -import { createSelector } from "reselect"; +import { createSelector } from "@reduxjs/toolkit"; import { getSettings } from "metabase/selectors/settings"; import { getEmbedOptions } from "metabase/selectors/embed"; diff --git a/package.json b/package.json index de020bd58c7d685dfcdb2107452c4570f7f91af6..371be6246902375b8ecfdeed8f9619b9eaa200e0 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "number-to-locale-string": "^1.0.1", "password-generator": "^2.0.1", "prop-types": "^15.5.7", - "re-reselect": "^3.4.0", + "re-reselect": "^4.0.1", "react": "~16.14.0", "react-ace": "^9.5.0", "react-ansi-style": "^1.0.0", @@ -97,7 +97,6 @@ "regenerator": "^0.14.1", "rehype-external-links": "^2.0.1", "remark-gfm": "1.0.0", - "reselect": "^3.0.0", "screenfull": "^4.2.1", "server-text-width": "^1.0.2", "simple-statistics": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index 1e79338f76a46c2cee900dfec565e774d93d2a7a..022818f1d9b839db44c96a02bc2603cb45b4ba55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18382,10 +18382,10 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -re-reselect@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/re-reselect/-/re-reselect-3.4.0.tgz#0f2303f3c84394f57f0cd31fea08a1ca4840a7cd" - integrity sha512-JsecfN+JlckncVXTWFWjn0Vk6uInl8GSf4eEd9tTk5qXHlgqkPdILpnYpgZcISXNYAzvfvsCZviaDk8AxyS5sg== +re-reselect@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/re-reselect/-/re-reselect-4.0.1.tgz#21a2306d11bbf377ac78687aa46e1a8848974194" + integrity sha512-xVTNGQy/dAxOolunBLmVMGZ49VUUR1s8jZUiJQb+g1sI63GAv9+a5Jas9yHvdxeUgiZkU9r3gDExDorxHzOgRA== react-ace@^9.5.0: version "9.5.0" @@ -19358,11 +19358,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= -reselect@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" - integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= - reselect@^4.1.7: version "4.1.7" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.7.tgz#56480d9ff3d3188970ee2b76527bd94a95567a42"