Chore: Bumps Immer, Redux Toolkit, Redux and React Redux (#38872)

* Chore: Bumps immer and redux/toolkit

* WIP: transpile errors

* Chore: bumps redux and react redux

* Chore: removes unused dispatch

* make alerting compile with updated redux toolkit

* Test: Fixes broken test

* Chore: fixes strict errors

Co-authored-by: Domas <domasx2@gmail.com>
This commit is contained in:
Hugo Häggmark
2021-09-07 10:44:47 +02:00
committed by GitHub
parent 3f0f448201
commit 058ac6becf
12 changed files with 127 additions and 132 deletions

View File

@ -121,7 +121,7 @@
"@types/react-grid-layout": "1.1.1",
"@types/react-highlight-words": "^0.16.2",
"@types/react-loadable": "5.5.2",
"@types/react-redux": "7.1.7",
"@types/react-redux": "7.1.18",
"@types/react-router-dom": "^5.1.7",
"@types/react-select": "4.0.13",
"@types/react-test-renderer": "17.0.1",
@ -232,7 +232,7 @@
"@opentelemetry/exporter-collector": "0.23.0",
"@opentelemetry/semantic-conventions": "0.23.0",
"@popperjs/core": "2.5.4",
"@reduxjs/toolkit": "1.5.0",
"@reduxjs/toolkit": "1.6.1",
"@sentry/browser": "5.25.0",
"@sentry/types": "5.24.2",
"@sentry/utils": "5.24.2",
@ -268,7 +268,7 @@
"file-saver": "2.0.2",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",
"immer": "8.0.1",
"immer": "9.0.6",
"jquery": "3.5.1",
"json-source-map": "0.6.1",
"jsurl": "^0.1.5",
@ -299,7 +299,7 @@
"react-highlight-words": "0.17.0",
"react-loadable": "5.5.0",
"react-popper": "2.2.4",
"react-redux": "7.2.0",
"react-redux": "7.2.5",
"react-reverse-portal": "^2.0.1",
"react-router-dom": "^5.2.0",
"react-select": "4.3.0",
@ -308,7 +308,7 @@
"react-use": "17.2.4",
"react-virtualized-auto-sizer": "1.0.2",
"react-window": "1.8.5",
"redux": "4.0.5",
"redux": "4.1.1",
"redux-thunk": "2.3.0",
"regenerator-runtime": "0.13.3",
"reselect": "4.0.0",

View File

@ -563,7 +563,7 @@ export const fetchAlertGroupsAction = createAsyncThunk(
}
);
export const checkIfLotexSupportsEditingRulesAction = createAsyncThunk(
export const checkIfLotexSupportsEditingRulesAction = createAsyncThunk<boolean, string>(
'unifiedalerting/checkIfLotexRuleEditingSupported',
async (rulesSourceName: string): Promise<boolean> =>
withAppEvents(

View File

@ -1,8 +1,10 @@
import { AnyAction, AsyncThunk, createSlice, Draft, isAsyncThunkAction, SerializedError } from '@reduxjs/toolkit';
import { FetchError } from '@grafana/runtime';
import { isArray } from 'angular';
import { appEvents } from 'app/core/core';
import { AsyncThunk, createSlice, Draft, isAsyncThunkAction, PayloadAction, SerializedError } from '@reduxjs/toolkit';
import { FetchError } from '@grafana/runtime';
import { AppEvents } from '@grafana/data';
import { appEvents } from 'app/core/core';
export interface AsyncRequestState<T> {
result?: T;
loading: boolean;
@ -18,10 +20,12 @@ export const initialAsyncRequestState: AsyncRequestState<any> = Object.freeze({
export type AsyncRequestMapSlice<T> = Record<string, AsyncRequestState<T>>;
export type AsyncRequestAction<T> = PayloadAction<Draft<T>, string, any, any>;
function requestStateReducer<T, ThunkArg = void, ThunkApiConfig = {}>(
asyncThunk: AsyncThunk<T, ThunkArg, ThunkApiConfig>,
state: Draft<AsyncRequestState<T>> = initialAsyncRequestState,
action: AnyAction
action: AsyncRequestAction<T>
): Draft<AsyncRequestState<T>> {
if (asyncThunk.pending.match(action)) {
return {
@ -35,7 +39,7 @@ function requestStateReducer<T, ThunkArg = void, ThunkApiConfig = {}>(
if (state.requestId === undefined || state.requestId === action.meta.requestId) {
return {
...state,
result: action.payload as Draft<T>,
result: action.payload,
loading: false,
error: undefined,
};
@ -45,7 +49,7 @@ function requestStateReducer<T, ThunkArg = void, ThunkApiConfig = {}>(
return {
...state,
loading: false,
error: (action as any).error,
error: action.error,
};
}
}
@ -65,7 +69,9 @@ export function createAsyncSlice<T, ThunkArg = void, ThunkApiConfig = {}>(
initialState: initialAsyncRequestState as AsyncRequestState<T>,
reducers: {},
extraReducers: (builder) =>
builder.addDefaultCase((state, action) => requestStateReducer(asyncThunk, state, action)),
builder.addDefaultCase((state, action) =>
requestStateReducer(asyncThunk, state, (action as unknown) as AsyncRequestAction<T>)
),
});
}
@ -86,10 +92,11 @@ export function createAsyncMapSlice<T, ThunkArg = void, ThunkApiConfig = {}>(
extraReducers: (builder) =>
builder.addDefaultCase((state, action) => {
if (isAsyncThunkAction(asyncThunk)(action)) {
const entityId = getEntityId(action.meta.arg);
const asyncAction = (action as unknown) as AsyncRequestAction<T>;
const entityId = getEntityId(asyncAction.meta.arg);
return {
...state,
[entityId]: requestStateReducer(asyncThunk, state[entityId], action),
[entityId]: requestStateReducer(asyncThunk, state[entityId], asyncAction),
};
}
return state;

View File

@ -2,24 +2,13 @@ import { locationService } from '@grafana/runtime';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { Provider } from 'react-redux';
import createMockStore from 'redux-mock-store';
import { PanelNotSupported, Props } from './PanelNotSupported';
import { PanelEditorTabId } from './types';
const setupTestContext = (options: Partial<Props>) => {
const defaults: Props = {
message: '',
dispatch: jest.fn(),
};
const store = createMockStore();
const defaults: Props = { message: '' };
const props = { ...defaults, ...options };
render(
<Provider store={store()}>
<PanelNotSupported {...props} />
</Provider>
);
render(<PanelNotSupported {...props} />);
return { props };
};

View File

@ -1,6 +1,4 @@
import React, { FC, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { Dispatch } from 'redux';
import React, { useCallback } from 'react';
import { Button, VerticalGroup } from '@grafana/ui';
import { Layout } from '@grafana/ui/src/components/Layout/Layout';
@ -9,12 +7,9 @@ import { locationService } from '@grafana/runtime';
export interface Props {
message: string;
dispatch?: Dispatch;
}
export const PanelNotSupported: FC<Props> = ({ message, dispatch: propsDispatch }) => {
let dispatch = useDispatch();
dispatch = propsDispatch ?? dispatch;
export function PanelNotSupported({ message }: Props): JSX.Element {
const onBackToQueries = useCallback(() => {
locationService.partial({ tab: PanelEditorTabId.Query });
}, []);
@ -31,4 +26,4 @@ export const PanelNotSupported: FC<Props> = ({ message, dispatch: propsDispatch
</VerticalGroup>
</Layout>
);
};
}

View File

@ -1,5 +1,5 @@
import { DataQuery, DefaultTimeZone, EventBusExtended, serializeStateToUrlParam, toUtc } from '@grafana/data';
import { ExploreId } from 'app/types';
import { ExploreId, StoreState, ThunkDispatch } from 'app/types';
import { refreshExplore } from './explorePane';
import { setDataSourceSrv } from '@grafana/runtime';
import { configureStore } from '../../../store/configureStore';
@ -92,37 +92,38 @@ function setup(state?: any) {
},
} as any);
const store = setupStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = setupStore({
datasourceInstance: datasources.someDs,
...(state || {}),
});
return {
store,
dispatch,
getState,
datasources,
};
}
describe('refreshExplore', () => {
it('should change data source when datasource in url changes', async () => {
const { store } = setup();
await store.dispatch(
const { dispatch, getState } = setup();
await dispatch(
refreshExplore(ExploreId.left, serializeStateToUrlParam({ datasource: 'newDs', queries: [], range: testRange }))
);
expect(store.getState().explore[ExploreId.left].datasourceInstance?.name).toBe('newDs');
expect(getState().explore[ExploreId.left].datasourceInstance?.name).toBe('newDs');
});
it('should change and run new queries from the URL', async () => {
const { store, datasources } = setup();
const { dispatch, getState, datasources } = setup();
datasources.someDs.query.mockReturnValueOnce(of({}));
await store.dispatch(
await dispatch(
refreshExplore(
ExploreId.left,
serializeStateToUrlParam({ datasource: 'someDs', queries: [{ expr: 'count()' }], range: testRange })
)
);
// same
const state = store.getState().explore[ExploreId.left];
const state = getState().explore[ExploreId.left];
expect(state.datasourceInstance?.name).toBe('someDs');
expect(state.queries.length).toBe(1);
expect(state.queries).toMatchObject([{ expr: 'count()' }]);
@ -130,17 +131,17 @@ describe('refreshExplore', () => {
});
it('should not do anything if pane is not initialized', async () => {
const { store } = setup({
const { dispatch, getState } = setup({
initialized: false,
});
const state = store.getState();
await store.dispatch(
const state = getState();
await dispatch(
refreshExplore(
ExploreId.left,
serializeStateToUrlParam({ datasource: 'newDs', queries: [{ expr: 'count()' }], range: testRange })
)
);
expect(state).toEqual(store.getState());
expect(state).toEqual(getState());
});
});

View File

@ -1,31 +1,31 @@
import {
addQueryRowAction,
addResultsToCache,
clearCache,
cancelQueries,
cancelQueriesAction,
clearCache,
importQueries,
queryReducer,
removeQueryRowAction,
importQueries,
runQueries,
scanStartAction,
scanStopAction,
} from './query';
import { ExploreId, ExploreItemState } from 'app/types';
import { ExploreId, ExploreItemState, StoreState, ThunkDispatch } from 'app/types';
import { interval, of } from 'rxjs';
import {
ArrayVector,
DataQueryResponse,
DefaultTimeZone,
MutableDataFrame,
RawTimeRange,
toUtc,
PanelData,
DataFrame,
LoadingState,
DataQuery,
DataQueryResponse,
DataSourceApi,
DataSourceJsonData,
DataQuery,
DefaultTimeZone,
LoadingState,
MutableDataFrame,
PanelData,
RawTimeRange,
toUtc,
} from '@grafana/data';
import { thunkTester } from 'test/core/thunk/thunkTester';
import { makeExplorePaneState } from './utils';
@ -76,10 +76,10 @@ describe('runQueries', () => {
setTimeSrv({
init() {},
} as any);
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
});
(store.getState().explore[ExploreId.left].datasourceInstance?.query as Mock).mockReturnValueOnce(
(getState().explore[ExploreId.left].datasourceInstance?.query as Mock).mockReturnValueOnce(
of({
error: { message: 'test error' },
data: [
@ -92,9 +92,9 @@ describe('runQueries', () => {
],
} as DataQueryResponse)
);
await store.dispatch(runQueries(ExploreId.left));
expect(store.getState().explore[ExploreId.left].showMetrics).toBeTruthy();
expect(store.getState().explore[ExploreId.left].graphResult).toBeDefined();
await dispatch(runQueries(ExploreId.left));
expect(getState().explore[ExploreId.left].showMetrics).toBeTruthy();
expect(getState().explore[ExploreId.left].graphResult).toBeDefined();
});
});
@ -131,7 +131,7 @@ describe('running queries', () => {
describe('importing queries', () => {
describe('when importing queries between the same type of data source', () => {
it('remove datasource property from all of the queries', async () => {
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
explore: {
[ExploreId.left]: {
@ -141,7 +141,7 @@ describe('importing queries', () => {
},
});
await store.dispatch(
await dispatch(
importQueries(
ExploreId.left,
[
@ -153,10 +153,10 @@ describe('importing queries', () => {
)
);
expect(store.getState().explore[ExploreId.left].queries[0]).toHaveProperty('refId', 'refId_A');
expect(store.getState().explore[ExploreId.left].queries[1]).toHaveProperty('refId', 'refId_B');
expect(store.getState().explore[ExploreId.left].queries[0]).not.toHaveProperty('datasource');
expect(store.getState().explore[ExploreId.left].queries[1]).not.toHaveProperty('datasource');
expect(getState().explore[ExploreId.left].queries[0]).toHaveProperty('refId', 'refId_A');
expect(getState().explore[ExploreId.left].queries[1]).toHaveProperty('refId', 'refId_B');
expect(getState().explore[ExploreId.left].queries[0]).not.toHaveProperty('datasource');
expect(getState().explore[ExploreId.left].queries[1]).not.toHaveProperty('datasource');
});
});
});
@ -266,7 +266,7 @@ describe('reducer', () => {
describe('caching', () => {
it('should add response to cache', async () => {
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
explore: {
[ExploreId.left]: {
@ -280,15 +280,15 @@ describe('reducer', () => {
},
});
await store.dispatch(addResultsToCache(ExploreId.left));
await dispatch(addResultsToCache(ExploreId.left));
expect(store.getState().explore[ExploreId.left].cache).toEqual([
expect(getState().explore[ExploreId.left].cache).toEqual([
{ key: 'from=1621348027000&to=1621348050000', value: { series: [{ name: 'test name' }], state: 'Done' } },
]);
});
it('should not add response to cache if response is still loading', async () => {
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
explore: {
[ExploreId.left]: {
@ -299,13 +299,13 @@ describe('reducer', () => {
},
});
await store.dispatch(addResultsToCache(ExploreId.left));
await dispatch(addResultsToCache(ExploreId.left));
expect(store.getState().explore[ExploreId.left].cache).toEqual([]);
expect(getState().explore[ExploreId.left].cache).toEqual([]);
});
it('should not add duplicate response to cache', async () => {
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
explore: {
[ExploreId.left]: {
@ -325,16 +325,16 @@ describe('reducer', () => {
},
});
await store.dispatch(addResultsToCache(ExploreId.left));
await dispatch(addResultsToCache(ExploreId.left));
expect(store.getState().explore[ExploreId.left].cache).toHaveLength(1);
expect(store.getState().explore[ExploreId.left].cache).toEqual([
expect(getState().explore[ExploreId.left].cache).toHaveLength(1);
expect(getState().explore[ExploreId.left].cache).toEqual([
{ key: 'from=1621348027000&to=1621348050000', value: { series: [{ name: 'old test name' }], state: 'Done' } },
]);
});
it('should clear cache', async () => {
const store = configureStore({
const { dispatch, getState }: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
...(defaultInitialState as any),
explore: {
[ExploreId.left]: {
@ -349,9 +349,9 @@ describe('reducer', () => {
},
});
await store.dispatch(clearCache(ExploreId.left));
await dispatch(clearCache(ExploreId.left));
expect(store.getState().explore[ExploreId.left].cache).toEqual([]);
expect(getState().explore[ExploreId.left].cache).toEqual([]);
});
});
});

View File

@ -3,7 +3,7 @@ import { initialState } from './reducers';
import { getMockPlugins } from '../__mocks__/pluginMocks';
describe('Selectors', () => {
const mockState = initialState;
const mockState = { ...initialState };
it('should return search query', () => {
mockState.searchQuery = 'test';

View File

@ -64,8 +64,8 @@ export type GrafanaManagedReceiverConfig = {
uid?: string;
disableResolveMessage: boolean;
secureFields?: Record<string, boolean>;
secureSettings?: Record<string, unknown>;
settings: Record<string, unknown>;
secureSettings?: Record<string, any>;
settings: Record<string, any>;
type: string;
name: string;
updated?: string;
@ -76,15 +76,15 @@ export type Receiver = {
name: string;
email_configs?: EmailConfig[];
pagerduty_configs?: unknown[];
pushover_configs?: unknown[];
slack_configs?: unknown[];
opsgenie_configs?: unknown[];
pagerduty_configs?: any[];
pushover_configs?: any[];
slack_configs?: any[];
opsgenie_configs?: any[];
webhook_configs?: WebhookConfig[];
victorops_configs?: unknown[];
wechat_configs?: unknown[];
victorops_configs?: any[];
wechat_configs?: any[];
grafana_managed_receiver_configs?: GrafanaManagedReceiverConfig[];
[key: string]: unknown;
[key: string]: any;
};
export type Route = {

View File

@ -1,9 +1,10 @@
import { configureStore as reduxConfigureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import { ThunkMiddleware } from 'redux-thunk';
import { configureStore as reduxConfigureStore } from '@reduxjs/toolkit';
import { setStore } from './store';
import { StoreState } from 'app/types/store';
import { addReducer, createRootReducer } from '../core/reducers/root';
import { buildInitialState } from '../core/reducers/navModel';
import { ThunkMiddlewareFor } from '@reduxjs/toolkit/src/getDefaultMiddleware';
import { AnyAction } from 'redux';
export function addRootReducer(reducers: any) {
// this is ok now because we add reducers before configureStore is called
@ -13,15 +14,14 @@ export function addRootReducer(reducers: any) {
}
export function configureStore(initialState?: Partial<StoreState>) {
const reduxDefaultMiddleware = getDefaultMiddleware<StoreState>({
thunk: true,
serializableCheck: false,
immutableCheck: false,
} as any);
const store = reduxConfigureStore<StoreState>({
const store = reduxConfigureStore<
StoreState,
AnyAction,
ReadonlyArray<ThunkMiddlewareFor<StoreState, { thunk: true }>>
>({
reducer: createRootReducer(),
middleware: (reduxDefaultMiddleware as unknown) as [ThunkMiddleware<StoreState>],
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ thunk: true, serializableCheck: false, immutableCheck: false }),
devTools: process.env.NODE_ENV !== 'production',
preloadedState: {
navIndex: buildInitialState(),

View File

@ -2,7 +2,6 @@ import { ThunkAction, ThunkDispatch as GenericThunkDispatch } from 'redux-thunk'
import { Action, PayloadAction } from '@reduxjs/toolkit';
import { NavIndex } from '@grafana/data';
import { AlertRulesState, NotificationChannelState } from './alerting';
import { UnifiedAlertingState } from '../features/alerting/unified/state/reducers';
import { TeamsState, TeamState } from './teams';
import { FolderState } from './folders';
import { DashboardState } from './dashboard';
@ -18,6 +17,7 @@ import { ApiKeysState } from './apiKeys';
import { TemplatingState } from '../features/variables/state/reducers';
import { ImportDashboardState } from '../features/manage-dashboards/state/reducers';
import { UserState } from 'app/features/profile/state/reducers';
import { UnifiedAlertingState } from 'app/features/alerting/unified/state/reducers';
export interface StoreState {
navIndex: NavIndex;

View File

@ -3191,13 +3191,13 @@
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
"@reduxjs/toolkit@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.5.0.tgz#1025c1ccb224d1fc06d8d98a61f6717d57e6d477"
integrity sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ==
"@reduxjs/toolkit@1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.6.1.tgz#7bc83b47352a663bf28db01e79d17ba54b98ade9"
integrity sha512-pa3nqclCJaZPAyBhruQtiRwtTjottRrVJqziVZcWzI73i6L3miLTtUyWfauwv08HWtiXLx1xGyGt+yLFfW/d0A==
dependencies:
immer "^8.0.0"
redux "^4.0.0"
immer "^9.0.1"
redux "^4.1.0"
redux-thunk "^2.3.0"
reselect "^4.0.0"
@ -5315,17 +5315,7 @@
"@types/react" "*"
"@types/webpack" "*"
"@types/react-redux@7.1.7":
version "7.1.7"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.7.tgz#12a0c529aba660696947384a059c5c6e08185c7a"
integrity sha512-U+WrzeFfI83+evZE2dkZ/oF/1vjIYgqrb5dGgedkqVV8HEfDFujNgWCwHL89TDuWKb47U0nTBT6PLGq4IIogWg==
dependencies:
"@types/hoist-non-react-statics" "^3.3.0"
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
redux "^4.0.0"
"@types/react-redux@^7.1.16":
"@types/react-redux@7.1.18", "@types/react-redux@^7.1.16":
version "7.1.18"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.18.tgz#2bf8fd56ebaae679a90ebffe48ff73717c438e04"
integrity sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==
@ -13354,11 +13344,16 @@ image-size@~0.5.0:
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
immer@8.0.1, immer@^8.0.0:
immer@8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656"
integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==
immer@9.0.6, immer@^9.0.1:
version "9.0.6"
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73"
integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==
immutable@3.8.2, immutable@^3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
@ -20067,7 +20062,7 @@ react-is@16.8.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.0.tgz#518db476214f3fb0716af9f82dfd420225ae970f"
integrity sha512-LOy+3La39aduxaPfuj+lCXC5RQ8ukjVPAAsFJ3yQ+DIOLf4eR9OMKeWKF0IzjRyE95xMj5QELwiXGgfQsIJguA==
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0:
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@ -20114,16 +20109,17 @@ react-popper@^2.2.4:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-redux@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==
react-redux@7.2.5:
version "7.2.5"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.5.tgz#213c1b05aa1187d9c940ddfc0b29450957f6a3b8"
integrity sha512-Dt29bNyBsbQaysp6s/dN0gUodcq+dVKKER8Qv82UrpeygwYeX1raTtil7O/fftw/rFqzaf6gJhDZRkkZnn6bjg==
dependencies:
"@babel/runtime" "^7.5.5"
hoist-non-react-statics "^3.3.0"
"@babel/runtime" "^7.12.1"
"@types/react-redux" "^7.1.16"
hoist-non-react-statics "^3.3.2"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.9.0"
react-is "^16.13.1"
react-redux@^7.2.0:
version "7.2.4"
@ -20617,7 +20613,14 @@ redux-thunk@2.3.0, redux-thunk@^2.3.0:
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
redux@4.0.5, redux@^4.0.0, redux@^4.0.4, redux@^4.0.5:
redux@4.1.1, redux@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47"
integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==
dependencies:
"@babel/runtime" "^7.9.2"
redux@^4.0.0, redux@^4.0.4, redux@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==