mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Migrates reducers and actions to Redux Toolkit (#21287)
* Refactor: Adds Redux Toolkit package * Refactor: Uses configureStore from Redux Toolkit * Refactor: Migrates applicationReducer * Refactor: Migrates appNotificationsReducer * Refactor: Migrates locationReducer * Refactor: Migrates navModelReducer * Refactor: Migrates teamsReducer and teamReducer * Refactor: Migrates cleanUpAction * Refactor: Migrates alertRulesReducer * Refactor: Cleans up recursiveCleanState * Refactor: Switched to Angular compatible reducers * Refactor: Migrates folderReducer * Refactor: Migrates dashboardReducer * Migrates panelEditorReducer * Refactor: Migrates dataSourcesReducer * Refactor: Migrates usersReducer * Refactor: Migrates organizationReducer * Refactor: Migrates pluginsReducer * Refactor: Migrates ldapReducer and ldapUserReducer * Refactor: Migrates apiKeysReducer * Refactor: Migrates exploreReducer and itemReducer * Refactor: Removes actionCreatorFactory and reducerFactory * Refactor: Moves mocks to test section * Docs: Removes sections about home grown framework * Update contribute/style-guides/redux.md Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Refactor: Cleans up some code * Refactor: Adds state typings * Refactor: Cleans up typings * Refactor: Adds comment about ImmerJs autoFreeze Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Props, ApiKeysPage } from './ApiKeysPage';
|
||||
import { ApiKeysPage, Props } from './ApiKeysPage';
|
||||
import { ApiKey } from 'app/types';
|
||||
import { getMultipleMockKeys, getMockKey } from './__mocks__/apiKeysMock';
|
||||
import { getMockKey, getMultipleMockKeys } from './__mocks__/apiKeysMock';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { setSearchQuery } from './state/reducers';
|
||||
import { mockToolkitActionCreator } from '../../../test/core/redux/mocks';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
@@ -20,7 +22,7 @@ const setup = (propOverrides?: object) => {
|
||||
hasFetched: false,
|
||||
loadApiKeys: jest.fn(),
|
||||
deleteApiKey: jest.fn(),
|
||||
setSearchQuery: jest.fn(),
|
||||
setSearchQuery: mockToolkitActionCreator(setSearchQuery),
|
||||
addApiKey: jest.fn(),
|
||||
apiKeysCount: 0,
|
||||
includeExpired: false,
|
||||
|
||||
@@ -2,25 +2,24 @@ import React, { PureComponent } from 'react';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { ApiKey, NewApiKey, OrgRole } from 'app/types';
|
||||
// Utils
|
||||
import { ApiKey, CoreEvents, NewApiKey, OrgRole } from 'app/types';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getApiKeys, getApiKeysCount } from './state/selectors';
|
||||
import { loadApiKeys, deleteApiKey, setSearchQuery, addApiKey } from './state/actions';
|
||||
import { addApiKey, deleteApiKey, loadApiKeys } from './state/actions';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { SlideDown } from 'app/core/components/Animations/SlideDown';
|
||||
import ApiKeysAddedModal from './ApiKeysAddedModal';
|
||||
import config from 'app/core/config';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { EventsWithValidation, FormLabel, Input, Switch, ValidationEvents, DeleteButton } from '@grafana/ui';
|
||||
import { NavModel, dateTime, isDateTime } from '@grafana/data';
|
||||
import { DeleteButton, EventsWithValidation, FormLabel, Input, Switch, ValidationEvents } from '@grafana/ui';
|
||||
import { dateTime, isDateTime, NavModel } from '@grafana/data';
|
||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
||||
import { store } from 'app/store/store';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
|
||||
// Utils
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { setSearchQuery } from './state/reducers';
|
||||
|
||||
const timeRangeValidationEvents: ValidationEvents = {
|
||||
[EventsWithValidation.onBlur]: [
|
||||
|
||||
@@ -1,30 +1,6 @@
|
||||
import { ThunkAction } from 'redux-thunk';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { StoreState, ApiKey } from 'app/types';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadApiKeys = 'LOAD_API_KEYS',
|
||||
SetApiKeysSearchQuery = 'SET_API_KEYS_SEARCH_QUERY',
|
||||
}
|
||||
|
||||
export interface LoadApiKeysAction {
|
||||
type: ActionTypes.LoadApiKeys;
|
||||
payload: ApiKey[];
|
||||
}
|
||||
|
||||
export interface SetSearchQueryAction {
|
||||
type: ActionTypes.SetApiKeysSearchQuery;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export type Action = LoadApiKeysAction | SetSearchQueryAction;
|
||||
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
||||
|
||||
const apiKeysLoaded = (apiKeys: ApiKey[]): LoadApiKeysAction => ({
|
||||
type: ActionTypes.LoadApiKeys,
|
||||
payload: apiKeys,
|
||||
});
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { ApiKey, ThunkResult } from 'app/types';
|
||||
import { apiKeysLoaded, setSearchQuery } from './reducers';
|
||||
|
||||
export function addApiKey(
|
||||
apiKey: ApiKey,
|
||||
@@ -53,8 +29,3 @@ export function deleteApiKey(id: number, includeExpired: boolean): ThunkResult<v
|
||||
.then(dispatch(loadApiKeys(includeExpired)));
|
||||
};
|
||||
}
|
||||
|
||||
export const setSearchQuery = (searchQuery: string): SetSearchQueryAction => ({
|
||||
type: ActionTypes.SetApiKeysSearchQuery,
|
||||
payload: searchQuery,
|
||||
});
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { initialApiKeysState, apiKeysReducer } from './reducers';
|
||||
import { apiKeysLoaded, apiKeysReducer, initialApiKeysState, setSearchQuery } from './reducers';
|
||||
import { getMultipleMockKeys } from '../__mocks__/apiKeysMock';
|
||||
import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
||||
import { ApiKeysState } from '../../../types';
|
||||
|
||||
describe('API Keys reducer', () => {
|
||||
it('should set keys', () => {
|
||||
const payload = getMultipleMockKeys(4);
|
||||
|
||||
const action: Action = {
|
||||
type: ActionTypes.LoadApiKeys,
|
||||
payload,
|
||||
};
|
||||
|
||||
const result = apiKeysReducer(initialApiKeysState, action);
|
||||
|
||||
expect(result.keys).toEqual(payload);
|
||||
reducerTester<ApiKeysState>()
|
||||
.givenReducer(apiKeysReducer, { ...initialApiKeysState })
|
||||
.whenActionIsDispatched(apiKeysLoaded(getMultipleMockKeys(4)))
|
||||
.thenStateShouldEqual({
|
||||
...initialApiKeysState,
|
||||
keys: getMultipleMockKeys(4),
|
||||
hasFetched: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set search query', () => {
|
||||
const payload = 'test query';
|
||||
|
||||
const action: Action = {
|
||||
type: ActionTypes.SetApiKeysSearchQuery,
|
||||
payload,
|
||||
};
|
||||
|
||||
const result = apiKeysReducer(initialApiKeysState, action);
|
||||
|
||||
expect(result.searchQuery).toEqual('test query');
|
||||
reducerTester<ApiKeysState>()
|
||||
.givenReducer(apiKeysReducer, { ...initialApiKeysState })
|
||||
.whenActionIsDispatched(setSearchQuery('test query'))
|
||||
.thenStateShouldEqual({
|
||||
...initialApiKeysState,
|
||||
searchQuery: 'test query',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ApiKeysState } from 'app/types';
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import { ApiKeysState } from 'app/types';
|
||||
|
||||
export const initialApiKeysState: ApiKeysState = {
|
||||
keys: [],
|
||||
@@ -8,15 +9,22 @@ export const initialApiKeysState: ApiKeysState = {
|
||||
includeExpired: false,
|
||||
};
|
||||
|
||||
export const apiKeysReducer = (state = initialApiKeysState, action: Action): ApiKeysState => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.LoadApiKeys:
|
||||
const apiKeysSlice = createSlice({
|
||||
name: 'apiKeys',
|
||||
initialState: initialApiKeysState,
|
||||
reducers: {
|
||||
apiKeysLoaded: (state, action): ApiKeysState => {
|
||||
return { ...state, hasFetched: true, keys: action.payload };
|
||||
case ActionTypes.SetApiKeysSearchQuery:
|
||||
},
|
||||
setSearchQuery: (state, action): ApiKeysState => {
|
||||
return { ...state, searchQuery: action.payload };
|
||||
}
|
||||
return state;
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setSearchQuery, apiKeysLoaded } = apiKeysSlice.actions;
|
||||
|
||||
export const apiKeysReducer = apiKeysSlice.reducer;
|
||||
|
||||
export default {
|
||||
apiKeys: apiKeysReducer,
|
||||
|
||||
Reference in New Issue
Block a user