Chore: Upgrade redux (#86877)

* update packages

* fix type errors

* upgrade redux toolkit as well

* don't need eslint-disable command

* remove comment

* fix unit tests

* call rtk query selector directly

* remove unnecessary checks
This commit is contained in:
Ashley Harrison 2024-05-10 14:28:51 +01:00 committed by GitHub
parent 926ee0f62e
commit 670960f70c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 119 additions and 157 deletions

View File

@ -5104,8 +5104,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
],
"public/test/core/thunk/thunkTester.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],

View File

@ -282,7 +282,7 @@
"@react-aria/overlays": "3.22.0",
"@react-aria/utils": "3.24.0",
"@react-awesome-query-builder/ui": "6.4.2",
"@reduxjs/toolkit": "1.9.5",
"@reduxjs/toolkit": "2.2.3",
"@testing-library/react-hooks": "^8.0.1",
"@visx/event": "3.3.0",
"@visx/gradient": "3.3.0",
@ -362,7 +362,7 @@
"react-inlinesvg": "3.0.2",
"react-loading-skeleton": "3.4.0",
"react-moveable": "0.56.0",
"react-redux": "8.1.3",
"react-redux": "9.1.1",
"react-resizable": "3.0.5",
"react-responsive-carousel": "^3.2.23",
"react-router": "5.3.3",
@ -378,10 +378,10 @@
"react-window": "1.8.10",
"react-window-infinite-loader": "1.0.9",
"react-zoom-pan-pinch": "^3.3.0",
"redux": "4.2.1",
"redux-thunk": "2.4.2",
"redux": "5.0.1",
"redux-thunk": "3.1.0",
"regenerator-runtime": "0.14.1",
"reselect": "4.1.8",
"reselect": "5.1.0",
"rxjs": "7.8.1",
"selecto": "1.26.3",
"semver": "7.6.1",
@ -413,7 +413,8 @@
"react-split-pane@0.1.92": "patch:react-split-pane@npm:0.1.92#.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch",
"@storybook/blocks@7.4.5": "patch:@storybook/blocks@npm%3A7.4.5#./.yarn/patches/@storybook-blocks-npm-7.4.5-5a2374564a.patch",
"history@4.10.1": "patch:history@npm%3A4.10.1#./.yarn/patches/history-npm-4.10.1-ee217563ae.patch",
"history@^4.9.0": "patch:history@npm%3A4.10.1#./.yarn/patches/history-npm-4.10.1-ee217563ae.patch"
"history@^4.9.0": "patch:history@npm%3A4.10.1#./.yarn/patches/history-npm-4.10.1-ee217563ae.patch",
"redux": "^5.0.0"
},
"workspaces": {
"packages": [

View File

@ -49,7 +49,7 @@
"@lezer/highlight": "1.2.0",
"@lezer/lr": "1.4.0",
"@prometheus-io/lezer-promql": "0.52.0",
"@reduxjs/toolkit": "1.9.5",
"@reduxjs/toolkit": "2.2.3",
"d3": "7.9.0",
"date-fns": "3.6.0",
"debounce-promise": "3.1.2",

View File

@ -250,8 +250,8 @@ describe('NestedFolderPicker', () => {
await userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowRight}');
// Folder A's children are visible
expect(screen.getByLabelText(folderA_folderA.item.title)).toBeInTheDocument();
expect(screen.getByLabelText(folderA_folderB.item.title)).toBeInTheDocument();
expect(await screen.findByLabelText(folderA_folderA.item.title)).toBeInTheDocument();
expect(await screen.findByLabelText(folderA_folderB.item.title)).toBeInTheDocument();
// Collapse Folder A
await userEvent.keyboard('{ArrowLeft}');

View File

@ -23,18 +23,6 @@ type ListFoldersRequest = QueryActionCreatorResult<
>
>;
const listFoldersSelector = createSelector(
(state: RootState) => state,
(
state: RootState,
parentUid: ListFolderQueryArgs['parentUid'],
page: ListFolderQueryArgs['page'],
limit: ListFolderQueryArgs['limit'],
permission: ListFolderQueryArgs['permission']
) => browseDashboardsAPI.endpoints.listFolders.select({ parentUid, page, limit, permission }),
(state, selectFolderList) => selectFolderList(state)
);
const listAllFoldersSelector = createSelector(
[(state: RootState) => state, (state: RootState, requests: ListFoldersRequest[]) => requests],
(state: RootState, requests: ListFoldersRequest[]) => {
@ -49,7 +37,13 @@ const listAllFoldersSelector = createSelector(
continue;
}
const page = listFoldersSelector(state, req.arg.parentUid, req.arg.page, req.arg.limit, req.arg.permission);
const page = browseDashboardsAPI.endpoints.listFolders.select({
parentUid: req.arg.parentUid,
page: req.arg.page,
limit: req.arg.limit,
permission: req.arg.permission,
})(state);
if (page.status === 'pending') {
isLoading = true;
}

View File

@ -203,14 +203,7 @@ describe('NotificationPreview', () => {
});
await userEvent.click(ui.previewButton.get());
await waitFor(() => {
expect(ui.loadingIndicator.query()).not.toBeInTheDocument();
});
//open details modal
await waitFor(() => {
expect(ui.loadingIndicator.query()).not.toBeInTheDocument();
});
await userEvent.click(ui.seeDetails.get());
await userEvent.click(await ui.seeDetails.find());
expect(ui.details.title.query()).toBeInTheDocument();
//we expect seeing the default policy
expect(screen.getByText(/default policy/i)).toBeInTheDocument();
@ -234,14 +227,7 @@ describe('NotificationPreview', () => {
});
await userEvent.click(ui.previewButton.get());
await waitFor(() => {
expect(ui.loadingIndicator.query()).not.toBeInTheDocument();
});
//open details modal
await waitFor(() => {
expect(ui.loadingIndicator.query()).not.toBeInTheDocument();
});
await userEvent.click(ui.seeDetails.get());
await userEvent.click(await ui.seeDetails.find());
expect(ui.details.title.query()).toBeInTheDocument();
//we expect seeing the default policy
expect(screen.getByText(/default policy/i)).toBeInTheDocument();

View File

@ -48,7 +48,7 @@ const expressionQuery: AlertQuery = {
describe('Query and expressions reducer', () => {
it('should return initial state', () => {
expect(queriesAndExpressionsReducer(undefined, { type: undefined })).toEqual({
expect(queriesAndExpressionsReducer(undefined, { type: '' })).toEqual({
queries: [],
});
});

View File

@ -1,5 +1,5 @@
import configureMockStore, { MockStore } from 'redux-mock-store';
import thunk from 'redux-thunk';
import { thunk } from 'redux-thunk';
import { Subject } from 'rxjs';
import { BackendSrv, FetchError, locationService, setEchoSrv } from '@grafana/runtime';

View File

@ -125,7 +125,7 @@ describe('thresholdReducer', () => {
};
it('should return initial state', () => {
expect(thresholdReducer(undefined, { type: undefined })).toEqual({
expect(thresholdReducer(undefined, { type: '' })).toEqual({
type: ExpressionQueryType.threshold,
conditions: [],
refId: '',

View File

@ -6,7 +6,7 @@ import { selectors } from './reducers';
export const { selectAll, selectById, selectTotal } = selectors;
const selectQuery = (_state: EntityState<Invitee>, query: string) => query;
const selectQuery = (_state: EntityState<Invitee, string>, query: string) => query;
export const selectInvitesMatchingQuery = createSelector([selectAll, selectQuery], (invites, searchQuery) => {
const regex = new RegExp(searchQuery, 'i');
const matches = invites.filter((invite) => regex.test(invite.name) || regex.test(invite.email));

View File

@ -155,9 +155,9 @@ export const fetchRemotePlugins = createAsyncThunk<RemotePlugin[], void, { rejec
}
);
export const fetchDetails = createAsyncThunk<Update<CatalogPlugin>, string>(
export const fetchDetails = createAsyncThunk<Update<CatalogPlugin, string>, string>(
`${STATE_PREFIX}/fetchDetails`,
async (id: string, thunkApi) => {
async (id, thunkApi) => {
try {
const details = await getPluginDetails(id);
@ -191,7 +191,7 @@ export const addLocalAndRemotePlugins = createAction<{ local: LocalPlugin[]; rem
// We are also using the install API endpoint to update the plugin
export const install = createAsyncThunk<
Update<CatalogPlugin>,
Update<CatalogPlugin, string>,
{
id: string;
version?: string;
@ -222,7 +222,7 @@ export const install = createAsyncThunk<
export const unsetInstall = createAsyncThunk(`${STATE_PREFIX}/install`, async () => ({}));
export const uninstall = createAsyncThunk<Update<CatalogPlugin>, string>(
export const uninstall = createAsyncThunk<Update<CatalogPlugin, string>, string>(
`${STATE_PREFIX}/uninstall`,
async (id, thunkApi) => {
try {

View File

@ -105,7 +105,7 @@ const slice = createSlice({
status: RequestStatus.Fulfilled,
};
})
.addMatcher(isRejectedRequest, (state, action) => {
.addMatcher(isRejectedRequest, (state, action: PayloadAction) => {
state.requests[getOriginalActionType(action.type)] = {
status: RequestStatus.Rejected,
error: action.payload,

View File

@ -288,7 +288,7 @@ export type PluginDetailsTab = {
// TODO<remove `PluginsState &` when the "plugin_admin_enabled" feature flag is removed>
export type ReducerState = PluginsState & {
items: EntityState<CatalogPlugin>;
items: EntityState<CatalogPlugin, string>;
requests: Record<string, RequestInfo>;
settings: {
displayMode: PluginListDisplayMode;

View File

@ -1,4 +1,4 @@
import { CombinedState, combineReducers, Reducer } from 'redux';
import { AnyAction, combineReducers, Reducer } from 'redux';
import { initialVariableEditorState, variableEditorReducer, VariableEditorState } from '../editor/reducer';
import { initialVariableInspectState, variableInspectReducer, VariableInspectState } from '../inspect/reducer';
@ -16,7 +16,7 @@ export interface TemplatingState {
inspect: VariableInspectState;
}
let templatingReducers: Reducer<CombinedState<TemplatingState>>;
let templatingReducers: Reducer<TemplatingState, AnyAction, Partial<TemplatingState>>;
export function getTemplatingReducers() {
if (!templatingReducers) {

View File

@ -1,21 +1,12 @@
import {
AnyAction,
configureStore,
EnhancedStore,
Reducer,
getDefaultMiddleware,
CombinedState,
PreloadedState,
} from '@reduxjs/toolkit';
import { NoInfer } from '@reduxjs/toolkit/dist/tsHelpers';
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
import thunk, { ThunkMiddleware } from 'redux-thunk';
import { AnyAction, configureStore, EnhancedStore, Reducer, Tuple } from '@reduxjs/toolkit';
import { Middleware, StoreEnhancer, UnknownAction } from 'redux';
import { thunk, ThunkDispatch, ThunkMiddleware } from 'redux-thunk';
import { setStore } from '../../../app/store/store';
import { StoreState } from '../../../app/types';
export interface ReduxTesterGiven<State> {
givenRootReducer: (rootReducer: Reducer<State>) => ReduxTesterWhen<State>;
givenRootReducer: (rootReducer: Reducer<State, UnknownAction, Partial<NoInfer<State>>>) => ReduxTesterWhen<State>;
}
export interface ReduxTesterWhen<State> {
@ -38,36 +29,53 @@ export interface ReduxTesterThen<State> {
}
export interface ReduxTesterArguments<State> {
preloadedState?: PreloadedState<CombinedState<NoInfer<State>>>;
preloadedState?: Partial<NoInfer<State>>;
debug?: boolean;
}
export const reduxTester = <State>(args?: ReduxTesterArguments<State>): ReduxTesterGiven<State> => {
const dispatchedActions: AnyAction[] = [];
const logActionsMiddleWare: Middleware<{}, Partial<StoreState>> =
(store: MiddlewareAPI<Dispatch, Partial<StoreState>>) => (next: Dispatch) => (action: AnyAction) => {
// filter out thunk actions
if (action && typeof action !== 'function') {
dispatchedActions.push(action);
}
const logActionsMiddleWare: Middleware<{}, Partial<StoreState>> = (store) => (next) => (action) => {
// filter out thunk actions
if (action && typeof action !== 'function') {
dispatchedActions.push(action as AnyAction);
}
return next(action);
};
return next(action);
};
const preloadedState = args?.preloadedState ?? ({} as unknown as PreloadedState<CombinedState<NoInfer<State>>>);
const preloadedState = args?.preloadedState ?? ({} as unknown as Partial<NoInfer<State>>);
const debug = args?.debug ?? false;
let store: EnhancedStore<State, AnyAction, []> | null = null;
const defaultMiddleware = getDefaultMiddleware<State>({
thunk: false,
serializableCheck: false,
immutableCheck: false,
} as any);
const givenRootReducer = (rootReducer: Reducer<State>): ReduxTesterWhen<State> => {
store = configureStore<State, AnyAction, Array<Middleware<State>>>({
const givenRootReducer = (
rootReducer: Reducer<State, UnknownAction, Partial<NoInfer<State>>>
): ReduxTesterWhen<State> => {
store = configureStore<
State,
UnknownAction,
Tuple<[ThunkMiddleware<State>]>,
Tuple<
[
StoreEnhancer<{
dispatch: ThunkDispatch<State, undefined, AnyAction>;
}>,
StoreEnhancer,
]
>,
Partial<NoInfer<State>>
>({
reducer: rootReducer,
middleware: [...defaultMiddleware, logActionsMiddleWare, thunk] as unknown as [ThunkMiddleware<State>],
middleware: (getDefaultMiddleware) =>
[
...getDefaultMiddleware({
thunk: false,
serializableCheck: false,
immutableCheck: false,
}),
logActionsMiddleWare,
thunk,
] as unknown as Tuple<[ThunkMiddleware<State>]>,
preloadedState,
});

View File

@ -1,6 +1,6 @@
import { PayloadAction } from '@reduxjs/toolkit';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { thunk } from 'redux-thunk';
const mockStore = configureMockStore([thunk]);

View File

@ -1,4 +1,4 @@
import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import { Store } from '@reduxjs/toolkit';
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
@ -13,7 +13,7 @@ import { StoreState } from 'app/types/store';
export interface Props {
storeState?: Partial<StoreState>;
store?: ToolkitStore;
store?: Store<StoreState>;
children: React.ReactNode;
grafanaContext?: GrafanaContextType;
}

View File

@ -1,5 +1,4 @@
import { AnyAction, configureStore } from '@reduxjs/toolkit';
import { ThunkMiddlewareFor } from '@reduxjs/toolkit/dist/getDefaultMiddleware';
import { configureStore } from '@reduxjs/toolkit';
import { render as rtlRender } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
@ -13,11 +12,7 @@ function render(
ui: React.ReactElement,
{
preloadedState = { navIndex: mockNavModel },
store = configureStore<
StoreState,
AnyAction,
ReadonlyArray<ThunkMiddlewareFor<StoreState, { thunk: true; serializableCheck: false; immutableCheck: false }>>
>({
store = configureStore({
reducer: createRootReducer(),
preloadedState,
middleware: (getDefaultMiddleware) =>

View File

@ -1,11 +1,10 @@
import { ToolkitStore } from '@reduxjs/toolkit/dist/configureStore';
import { Store } from '@reduxjs/toolkit';
import { render, RenderOptions } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createMemoryHistory, MemoryHistoryBuildOptions } from 'history';
import React, { Fragment, PropsWithChildren } from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { PreloadedState } from 'redux';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
import { HistoryWrapper, setLocationService } from '@grafana/runtime';
@ -19,11 +18,11 @@ interface ExtendedRenderOptions extends RenderOptions {
* Optional store to use for rendering. If not provided, a fresh store will be generated
* via `configureStore` method
*/
store?: ToolkitStore;
store?: Store<StoreState>;
/**
* Partial state to use for preloading store when rendering tests
*/
preloadedState?: PreloadedState<StoreState>;
preloadedState?: Partial<StoreState>;
/**
* Should the wrapper be generated with a wrapping Router component?
* Useful if you're testing something that needs more nuanced routing behaviour
@ -91,8 +90,7 @@ const customRender = (
ui: React.ReactElement,
{ renderWithRouter = true, ...renderOptions }: ExtendedRenderOptions = {}
) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const store = renderOptions.preloadedState ? configureStore(renderOptions?.preloadedState as any) : undefined;
const store = renderOptions.preloadedState ? configureStore(renderOptions?.preloadedState) : undefined;
const AllTheProviders = renderOptions.wrapper || getWrapper({ store, renderWithRouter, ...renderOptions });
return {

View File

@ -3769,7 +3769,7 @@ __metadata:
"@lezer/highlight": "npm:1.2.0"
"@lezer/lr": "npm:1.4.0"
"@prometheus-io/lezer-promql": "npm:0.52.0"
"@reduxjs/toolkit": "npm:1.9.5"
"@reduxjs/toolkit": "npm:2.2.3"
"@rollup/plugin-image": "npm:3.0.3"
"@rollup/plugin-node-resolve": "npm:15.2.3"
"@swc/core": "npm:1.4.2"
@ -6876,23 +6876,23 @@ __metadata:
languageName: node
linkType: hard
"@reduxjs/toolkit@npm:1.9.5":
version: 1.9.5
resolution: "@reduxjs/toolkit@npm:1.9.5"
"@reduxjs/toolkit@npm:2.2.3":
version: 2.2.3
resolution: "@reduxjs/toolkit@npm:2.2.3"
dependencies:
immer: "npm:^9.0.21"
redux: "npm:^4.2.1"
redux-thunk: "npm:^2.4.2"
reselect: "npm:^4.1.8"
immer: "npm:^10.0.3"
redux: "npm:^5.0.1"
redux-thunk: "npm:^3.1.0"
reselect: "npm:^5.0.1"
peerDependencies:
react: ^16.9.0 || ^17.0.0 || ^18
react-redux: ^7.2.1 || ^8.0.2
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
peerDependenciesMeta:
react:
optional: true
react-redux:
optional: true
checksum: 10/ac24173de599b830232da5e040ea2b898c34cc803cb219e537ce15c5b914c85dfdb97f8f7015ea4e8cc9110430e2a081766b0dcbc1e71f99639b8bec136d3499
checksum: 10/7054747462f8b6a0739b76e227fde8a08143c9deef663f31c2f6f72352e0d1d49a400c8e56c68f320e0e88029412d7f452d88dd2b2a5d6dce7b65c9be646e894
languageName: node
linkType: hard
@ -9559,7 +9559,7 @@ __metadata:
languageName: node
linkType: hard
"@types/hoist-non-react-statics@npm:3.3.5, @types/hoist-non-react-statics@npm:^3.3.0, @types/hoist-non-react-statics@npm:^3.3.1":
"@types/hoist-non-react-statics@npm:3.3.5, @types/hoist-non-react-statics@npm:^3.3.0":
version: 3.3.5
resolution: "@types/hoist-non-react-statics@npm:3.3.5"
dependencies:
@ -18179,7 +18179,7 @@ __metadata:
"@react-types/menu": "npm:3.9.8"
"@react-types/overlays": "npm:3.8.6"
"@react-types/shared": "npm:3.22.1"
"@reduxjs/toolkit": "npm:1.9.5"
"@reduxjs/toolkit": "npm:2.2.3"
"@rtk-query/codegen-openapi": "npm:^1.2.0"
"@rtsao/plugin-proposal-class-properties": "npm:7.0.1-patch.1"
"@swc/core": "npm:1.4.2"
@ -18383,7 +18383,7 @@ __metadata:
react-inlinesvg: "npm:3.0.2"
react-loading-skeleton: "npm:3.4.0"
react-moveable: "npm:0.56.0"
react-redux: "npm:8.1.3"
react-redux: "npm:9.1.1"
react-refresh: "npm:0.14.0"
react-resizable: "npm:3.0.5"
react-responsive-carousel: "npm:^3.2.23"
@ -18402,11 +18402,11 @@ __metadata:
react-window: "npm:1.8.10"
react-window-infinite-loader: "npm:1.0.9"
react-zoom-pan-pinch: "npm:^3.3.0"
redux: "npm:4.2.1"
redux: "npm:5.0.1"
redux-mock-store: "npm:1.5.4"
redux-thunk: "npm:2.4.2"
redux-thunk: "npm:3.1.0"
regenerator-runtime: "npm:0.14.1"
reselect: "npm:4.1.8"
reselect: "npm:5.1.0"
rimraf: "npm:5.0.5"
rudder-sdk-js: "npm:2.48.7"
rxjs: "npm:7.8.1"
@ -19268,20 +19268,13 @@ __metadata:
languageName: node
linkType: hard
"immer@npm:10.0.4":
"immer@npm:10.0.4, immer@npm:^10.0.3":
version: 10.0.4
resolution: "immer@npm:10.0.4"
checksum: 10/c1196783cf18e836527f970e45dc88e5472756401831e94d494ca5fd00ab7b39de3156f50505908207e7efe59ac23244d2cde0bd0cff791de7e23709771757e6
languageName: node
linkType: hard
"immer@npm:^9.0.21":
version: 9.0.21
resolution: "immer@npm:9.0.21"
checksum: 10/8455d6b4dc8abfe40f06eeec9bcc944d147c81279424c0f927a4d4905ae34e5af19ab6da60bcc700c14f51c452867d7089b3b9236f5a9a2248e39b4a09ee89de
languageName: node
linkType: hard
"immutable@npm:4.3.5, immutable@npm:^4.0.0":
version: 4.3.5
resolution: "immutable@npm:4.3.5"
@ -26162,35 +26155,25 @@ __metadata:
languageName: node
linkType: hard
"react-redux@npm:8.1.3":
version: 8.1.3
resolution: "react-redux@npm:8.1.3"
"react-redux@npm:9.1.1":
version: 9.1.1
resolution: "react-redux@npm:9.1.1"
dependencies:
"@babel/runtime": "npm:^7.12.1"
"@types/hoist-non-react-statics": "npm:^3.3.1"
"@types/use-sync-external-store": "npm:^0.0.3"
hoist-non-react-statics: "npm:^3.3.2"
react-is: "npm:^18.0.0"
use-sync-external-store: "npm:^1.0.0"
peerDependencies:
"@types/react": ^16.8 || ^17.0 || ^18.0
"@types/react-dom": ^16.8 || ^17.0 || ^18.0
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
react-native: ">=0.59"
redux: ^4 || ^5.0.0-beta.0
"@types/react": ^18.2.25
react: ^18.0
react-native: ">=0.69"
redux: ^5.0.0
peerDependenciesMeta:
"@types/react":
optional: true
"@types/react-dom":
optional: true
react-dom:
optional: true
react-native:
optional: true
redux:
optional: true
checksum: 10/c4c7586cff3abeb784e73598d330f5301116a4e9942fd36895f2bccd8990001709c6c3ea1817edb75ee477470d6c67c9113e05a7f86b2b68a3950c9c29fe20cb
checksum: 10/eecc5cf0d9f9dec30634b23c912535eb1314d135f426a6108cd1532d52f14f699834f7cb07bcccffa1369ee26f7b43020dc9b41c4486c09bd6f98d7279be07bc
languageName: node
linkType: hard
@ -26856,21 +26839,19 @@ __metadata:
languageName: node
linkType: hard
"redux-thunk@npm:2.4.2, redux-thunk@npm:^2.4.2":
version: 2.4.2
resolution: "redux-thunk@npm:2.4.2"
"redux-thunk@npm:3.1.0, redux-thunk@npm:^3.1.0":
version: 3.1.0
resolution: "redux-thunk@npm:3.1.0"
peerDependencies:
redux: ^4
checksum: 10/9bcb1193835128ecebf1e1a1b1a37bc15e8dfbdf6b6ee1b5566dd4c8e4ca05a81175f0c6dda34ab47f87053cd13b74d9f881d59446691d7b192831852b5d7a72
redux: ^5.0.0
checksum: 10/38c563db5f0bbec90d2e65cc27f3c870c1b6102e0c071258734fac41cb0e51d31d894125815c2f4133b20aff231f51f028ad99bccc05a7e3249f1a5d5a959ed3
languageName: node
linkType: hard
"redux@npm:4.2.1, redux@npm:^4.0.0, redux@npm:^4.0.4, redux@npm:^4.0.5, redux@npm:^4.2.0, redux@npm:^4.2.1":
version: 4.2.1
resolution: "redux@npm:4.2.1"
dependencies:
"@babel/runtime": "npm:^7.9.2"
checksum: 10/371e4833b671193303a7dea7803c8fdc8e0d566740c78f580e0a3b77b4161da25037626900a2205a5d616117fa6ad09a4232e5a110bd437186b5c6355a041750
"redux@npm:^5.0.0":
version: 5.0.1
resolution: "redux@npm:5.0.1"
checksum: 10/a373f9ed65693ead58bea5ef61c1d6bef39da9f2706db3be6f84815f3a1283230ecd1184efb1b3daa7f807d8211b0181564ca8f336fc6ee0b1e2fa0ba06737c2
languageName: node
linkType: hard
@ -27098,10 +27079,10 @@ __metadata:
languageName: node
linkType: hard
"reselect@npm:4.1.8, reselect@npm:^4.1.8":
version: 4.1.8
resolution: "reselect@npm:4.1.8"
checksum: 10/199984d9872f71cd207f4aa6e6fd2bd48d95154f7aa9b3aee3398335f39f5491059e732f28c12e9031d5d434adab2c458dc8af5afb6564d0ad37e1644445e09c
"reselect@npm:5.1.0, reselect@npm:^5.0.1":
version: 5.1.0
resolution: "reselect@npm:5.1.0"
checksum: 10/657c379d9461781b7cb5f0a32133e23b4266886660c94fcc77c102bec8abe484b32bf43a911b99b747ecf7439f157696561d744d40dc920024611beb1a0d921f
languageName: node
linkType: hard