Refactored Datasources as POC
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
import { actionCreatorFactory } from './actionCreatorFactory';
|
||||
import { reducerFactory } from './reducerFactory';
|
||||
|
||||
export { actionCreatorFactory, reducerFactory };
|
||||
@@ -28,7 +28,7 @@ const dummyActionCreator = actionCreatorFactory<DummyReducerState>('dummy').crea
|
||||
const dummyReducer = reducerFactory(dummyReducerIntialState)
|
||||
.addHandler({
|
||||
filter: dummyActionCreator,
|
||||
handler: (state, action) => ({ ...state, ...action.payload }),
|
||||
mapper: (state, action) => ({ ...state, ...action.payload }),
|
||||
})
|
||||
.create();
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('reducerFactory', () => {
|
||||
it('then is should throw', () => {
|
||||
const faultyReducer = reducerFactory(dummyReducerIntialState).addHandler({
|
||||
filter: dummyActionCreator,
|
||||
handler: (state, action) => {
|
||||
mapper: (state, action) => {
|
||||
return { ...state, ...action.payload };
|
||||
},
|
||||
});
|
||||
@@ -86,7 +86,7 @@ describe('reducerFactory', () => {
|
||||
expect(() => {
|
||||
faultyReducer.addHandler({
|
||||
filter: dummyActionCreator,
|
||||
handler: state => {
|
||||
mapper: state => {
|
||||
return state;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { ActionOf, ActionCreator } from './actionCreatorFactory';
|
||||
import { Reducer } from 'redux';
|
||||
|
||||
export type Mapper<State, Payload> = (state: State, action: ActionOf<Payload>) => State;
|
||||
|
||||
export interface HandlerConfig<State, Payload> {
|
||||
filter: ActionCreator<Payload>;
|
||||
handler: (state: State, action: ActionOf<Payload>) => State;
|
||||
mapper: Mapper<State, Payload>;
|
||||
}
|
||||
|
||||
export interface AddHandler<State> {
|
||||
@@ -11,7 +12,7 @@ export interface AddHandler<State> {
|
||||
}
|
||||
|
||||
export interface CreateReducer<State> extends AddHandler<State> {
|
||||
create: () => Reducer<State, ActionOf<any>>;
|
||||
create: () => Mapper<State, any>;
|
||||
}
|
||||
|
||||
export const reducerFactory = <State>(initialState: State): AddHandler<State> => {
|
||||
@@ -27,18 +28,14 @@ export const reducerFactory = <State>(initialState: State): AddHandler<State> =>
|
||||
return instance;
|
||||
};
|
||||
|
||||
const create = (): Reducer<State, ActionOf<any>> => {
|
||||
const reducer: Reducer<State, ActionOf<any>> = (state: State = initialState, action: ActionOf<any>) => {
|
||||
const validHandlers = allHandlerConfigs
|
||||
.filter(config => config.filter.type === action.type)
|
||||
.map(config => config.handler);
|
||||
const create = () => (state: State = initialState, action: ActionOf<any>): State => {
|
||||
const handlerConfig = allHandlerConfigs.filter(config => config.filter.type === action.type)[0];
|
||||
|
||||
return validHandlers.reduce((currentState, handler) => {
|
||||
return handler(currentState, action);
|
||||
}, state || initialState);
|
||||
};
|
||||
if (handlerConfig) {
|
||||
return handlerConfig.mapper(state, action);
|
||||
}
|
||||
|
||||
return reducer;
|
||||
return state;
|
||||
};
|
||||
|
||||
const instance: CreateReducer<State> = {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NavModel } from 'app/types';
|
||||
import { DataSourceSettings } from '@grafana/ui/src/types';
|
||||
import { LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector';
|
||||
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
|
||||
import { setDataSourcesSearchQuery, setDataSourcesLayoutMode } from './state/actions';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
@@ -13,16 +14,16 @@ const setup = (propOverrides?: object) => {
|
||||
loadDataSources: jest.fn(),
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
text: 'Configuration',
|
||||
},
|
||||
node: {
|
||||
text: 'Data Sources'
|
||||
}
|
||||
text: 'Data Sources',
|
||||
},
|
||||
} as NavModel,
|
||||
dataSourcesCount: 0,
|
||||
searchQuery: '',
|
||||
setDataSourcesSearchQuery: jest.fn(),
|
||||
setDataSourcesLayoutMode: jest.fn(),
|
||||
setDataSourcesSearchQuery,
|
||||
setDataSourcesLayoutMode,
|
||||
hasFetched: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NavModel } from 'app/types';
|
||||
import { DataSourceSettings } from '@grafana/ui';
|
||||
import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
|
||||
import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
|
||||
import { setDataSourceName, setIsDefault } from '../state/actions';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
@@ -14,9 +15,9 @@ const setup = (propOverrides?: object) => {
|
||||
pageId: 1,
|
||||
deleteDataSource: jest.fn(),
|
||||
loadDataSource: jest.fn(),
|
||||
setDataSourceName: jest.fn(),
|
||||
setDataSourceName,
|
||||
updateDataSource: jest.fn(),
|
||||
setIsDefault: jest.fn(),
|
||||
setIsDefault,
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
@@ -8,6 +8,8 @@ import { UpdateLocationAction } from 'app/core/actions/location';
|
||||
import { buildNavModel } from './navModel';
|
||||
import { DataSourceSettings } from '@grafana/ui/src/types';
|
||||
import { Plugin, StoreState } from 'app/types';
|
||||
import { actionCreatorFactory } from 'app/core/redux';
|
||||
import { ActionOf } from 'app/core/redux/actionCreatorFactory';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadDataSources = 'LOAD_DATA_SOURCES',
|
||||
@@ -22,124 +24,36 @@ export enum ActionTypes {
|
||||
SetIsDefault = 'SET_IS_DEFAULT',
|
||||
}
|
||||
|
||||
interface LoadDataSourcesAction {
|
||||
type: ActionTypes.LoadDataSources;
|
||||
payload: DataSourceSettings[];
|
||||
}
|
||||
export const dataSourceLoaded = actionCreatorFactory<DataSourceSettings>(ActionTypes.LoadDataSource).create();
|
||||
|
||||
interface SetDataSourcesSearchQueryAction {
|
||||
type: ActionTypes.SetDataSourcesSearchQuery;
|
||||
payload: string;
|
||||
}
|
||||
export const dataSourcesLoaded = actionCreatorFactory<DataSourceSettings[]>(ActionTypes.LoadDataSources).create();
|
||||
|
||||
interface SetDataSourcesLayoutModeAction {
|
||||
type: ActionTypes.SetDataSourcesLayoutMode;
|
||||
payload: LayoutMode;
|
||||
}
|
||||
export const dataSourceMetaLoaded = actionCreatorFactory<Plugin>(ActionTypes.LoadDataSourceMeta).create();
|
||||
|
||||
interface LoadDataSourceTypesAction {
|
||||
type: ActionTypes.LoadDataSourceTypes;
|
||||
}
|
||||
export const dataSourceTypesLoad = actionCreatorFactory(ActionTypes.LoadDataSourceTypes).create();
|
||||
|
||||
interface LoadedDataSourceTypesAction {
|
||||
type: ActionTypes.LoadedDataSourceTypes;
|
||||
payload: Plugin[];
|
||||
}
|
||||
export const dataSourceTypesLoaded = actionCreatorFactory<Plugin[]>(ActionTypes.LoadedDataSourceTypes).create();
|
||||
|
||||
interface SetDataSourceTypeSearchQueryAction {
|
||||
type: ActionTypes.SetDataSourceTypeSearchQuery;
|
||||
payload: string;
|
||||
}
|
||||
export const setDataSourcesSearchQuery = actionCreatorFactory<string>(ActionTypes.SetDataSourcesSearchQuery).create();
|
||||
|
||||
interface LoadDataSourceAction {
|
||||
type: ActionTypes.LoadDataSource;
|
||||
payload: DataSourceSettings;
|
||||
}
|
||||
export const setDataSourcesLayoutMode = actionCreatorFactory<LayoutMode>(ActionTypes.SetDataSourcesLayoutMode).create();
|
||||
|
||||
interface LoadDataSourceMetaAction {
|
||||
type: ActionTypes.LoadDataSourceMeta;
|
||||
payload: Plugin;
|
||||
}
|
||||
export const setDataSourceTypeSearchQuery = actionCreatorFactory<string>(
|
||||
ActionTypes.SetDataSourceTypeSearchQuery
|
||||
).create();
|
||||
|
||||
interface SetDataSourceNameAction {
|
||||
type: ActionTypes.SetDataSourceName;
|
||||
payload: string;
|
||||
}
|
||||
export const setDataSourceName = actionCreatorFactory<string>(ActionTypes.SetDataSourceName).create();
|
||||
|
||||
interface SetIsDefaultAction {
|
||||
type: ActionTypes.SetIsDefault;
|
||||
payload: boolean;
|
||||
}
|
||||
export const setIsDefault = actionCreatorFactory<boolean>(ActionTypes.SetIsDefault).create();
|
||||
|
||||
const dataSourcesLoaded = (dataSources: DataSourceSettings[]): LoadDataSourcesAction => ({
|
||||
type: ActionTypes.LoadDataSources,
|
||||
payload: dataSources,
|
||||
});
|
||||
|
||||
const dataSourceLoaded = (dataSource: DataSourceSettings): LoadDataSourceAction => ({
|
||||
type: ActionTypes.LoadDataSource,
|
||||
payload: dataSource,
|
||||
});
|
||||
|
||||
const dataSourceMetaLoaded = (dataSourceMeta: Plugin): LoadDataSourceMetaAction => ({
|
||||
type: ActionTypes.LoadDataSourceMeta,
|
||||
payload: dataSourceMeta,
|
||||
});
|
||||
|
||||
const dataSourceTypesLoad = (): LoadDataSourceTypesAction => ({
|
||||
type: ActionTypes.LoadDataSourceTypes,
|
||||
});
|
||||
|
||||
const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadedDataSourceTypesAction => ({
|
||||
type: ActionTypes.LoadedDataSourceTypes,
|
||||
payload: dataSourceTypes,
|
||||
});
|
||||
|
||||
export const setDataSourcesSearchQuery = (searchQuery: string): SetDataSourcesSearchQueryAction => ({
|
||||
type: ActionTypes.SetDataSourcesSearchQuery,
|
||||
payload: searchQuery,
|
||||
});
|
||||
|
||||
export const setDataSourcesLayoutMode = (layoutMode: LayoutMode): SetDataSourcesLayoutModeAction => ({
|
||||
type: ActionTypes.SetDataSourcesLayoutMode,
|
||||
payload: layoutMode,
|
||||
});
|
||||
|
||||
export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSearchQueryAction => ({
|
||||
type: ActionTypes.SetDataSourceTypeSearchQuery,
|
||||
payload: query,
|
||||
});
|
||||
|
||||
export const setDataSourceName = (name: string) => ({
|
||||
type: ActionTypes.SetDataSourceName,
|
||||
payload: name,
|
||||
});
|
||||
|
||||
export const setIsDefault = (state: boolean) => ({
|
||||
type: ActionTypes.SetIsDefault,
|
||||
payload: state,
|
||||
});
|
||||
|
||||
export type Action =
|
||||
| LoadDataSourcesAction
|
||||
| SetDataSourcesSearchQueryAction
|
||||
| SetDataSourcesLayoutModeAction
|
||||
| UpdateLocationAction
|
||||
| LoadDataSourceTypesAction
|
||||
| LoadedDataSourceTypesAction
|
||||
| SetDataSourceTypeSearchQueryAction
|
||||
| LoadDataSourceAction
|
||||
| UpdateNavIndexAction
|
||||
| LoadDataSourceMetaAction
|
||||
| SetDataSourceNameAction
|
||||
| SetIsDefaultAction;
|
||||
export type Action = UpdateLocationAction | UpdateNavIndexAction | ActionOf<any>;
|
||||
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
||||
|
||||
export function loadDataSources(): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const response = await getBackendSrv().get('/api/datasources');
|
||||
dispatch(dataSourcesLoaded(response));
|
||||
dataSourcesLoaded(response);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -177,7 +91,7 @@ export function addDataSource(plugin: Plugin): ThunkResult<void> {
|
||||
|
||||
export function loadDataSourceTypes(): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
dispatch(dataSourceTypesLoad());
|
||||
dispatch(dataSourceTypesLoad({}));
|
||||
const result = await getBackendSrv().get('/api/plugins', { enabled: 1, type: 'datasource' });
|
||||
dispatch(dataSourceTypesLoaded(result));
|
||||
};
|
||||
|
||||
@@ -1,56 +1,87 @@
|
||||
import { DataSourcesState, Plugin } from 'app/types';
|
||||
import { DataSourceSettings } from '@grafana/ui/src/types';
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import {
|
||||
dataSourceLoaded,
|
||||
dataSourcesLoaded,
|
||||
setDataSourcesSearchQuery,
|
||||
setDataSourcesLayoutMode,
|
||||
dataSourceTypesLoad,
|
||||
dataSourceTypesLoaded,
|
||||
setDataSourceTypeSearchQuery,
|
||||
dataSourceMetaLoaded,
|
||||
setDataSourceName,
|
||||
setIsDefault,
|
||||
} from './actions';
|
||||
import { LayoutModes } from 'app/core/components/LayoutSelector/LayoutSelector';
|
||||
import { reducerFactory } from 'app/core/redux';
|
||||
|
||||
const initialState: DataSourcesState = {
|
||||
dataSources: [] as DataSourceSettings[],
|
||||
dataSources: [],
|
||||
dataSource: {} as DataSourceSettings,
|
||||
layoutMode: LayoutModes.List,
|
||||
searchQuery: '',
|
||||
dataSourcesCount: 0,
|
||||
dataSourceTypes: [] as Plugin[],
|
||||
dataSourceTypes: [],
|
||||
dataSourceTypeSearchQuery: '',
|
||||
hasFetched: false,
|
||||
isLoadingDataSources: false,
|
||||
dataSourceMeta: {} as Plugin,
|
||||
};
|
||||
|
||||
export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.LoadDataSources:
|
||||
return { ...state, hasFetched: true, dataSources: action.payload, dataSourcesCount: action.payload.length };
|
||||
|
||||
case ActionTypes.LoadDataSource:
|
||||
return { ...state, dataSource: action.payload };
|
||||
|
||||
case ActionTypes.SetDataSourcesSearchQuery:
|
||||
return { ...state, searchQuery: action.payload };
|
||||
|
||||
case ActionTypes.SetDataSourcesLayoutMode:
|
||||
return { ...state, layoutMode: action.payload };
|
||||
|
||||
case ActionTypes.LoadDataSourceTypes:
|
||||
return { ...state, dataSourceTypes: [], isLoadingDataSources: true };
|
||||
|
||||
case ActionTypes.LoadedDataSourceTypes:
|
||||
return { ...state, dataSourceTypes: action.payload, isLoadingDataSources: false };
|
||||
|
||||
case ActionTypes.SetDataSourceTypeSearchQuery:
|
||||
return { ...state, dataSourceTypeSearchQuery: action.payload };
|
||||
|
||||
case ActionTypes.LoadDataSourceMeta:
|
||||
return { ...state, dataSourceMeta: action.payload };
|
||||
|
||||
case ActionTypes.SetDataSourceName:
|
||||
return { ...state, dataSource: { ...state.dataSource, name: action.payload } };
|
||||
|
||||
case ActionTypes.SetIsDefault:
|
||||
return { ...state, dataSource: { ...state.dataSource, isDefault: action.payload } };
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
export const dataSourcesReducer = reducerFactory(initialState)
|
||||
.addHandler({
|
||||
filter: dataSourcesLoaded,
|
||||
mapper: (state, action) => ({
|
||||
...state,
|
||||
hasFetched: true,
|
||||
dataSources: action.payload,
|
||||
dataSourcesCount: action.payload.length,
|
||||
}),
|
||||
})
|
||||
.addHandler({
|
||||
filter: dataSourceLoaded,
|
||||
mapper: (state, action) => ({ ...state, dataSource: action.payload }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: setDataSourcesSearchQuery,
|
||||
mapper: (state, action) => ({ ...state, searchQuery: action.payload }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: setDataSourcesLayoutMode,
|
||||
mapper: (state, action) => ({ ...state, layoutMode: action.payload }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: dataSourceTypesLoad,
|
||||
mapper: state => ({ ...state, dataSourceTypes: [], isLoadingDataSources: true }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: dataSourceTypesLoaded,
|
||||
mapper: (state, action) => ({
|
||||
...state,
|
||||
dataSourceTypes: action.payload,
|
||||
isLoadingDataSources: false,
|
||||
}),
|
||||
})
|
||||
.addHandler({
|
||||
filter: setDataSourceTypeSearchQuery,
|
||||
mapper: (state, action) => ({ ...state, dataSourceTypeSearchQuery: action.payload }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: dataSourceMetaLoaded,
|
||||
mapper: (state, action) => ({ ...state, dataSourceMeta: action.payload }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: setDataSourceName,
|
||||
mapper: (state, action) => ({ ...state, dataSource: { ...state.dataSource, name: action.payload } }),
|
||||
})
|
||||
.addHandler({
|
||||
filter: setIsDefault,
|
||||
mapper: (state, action) => ({
|
||||
...state,
|
||||
dataSource: { ...state.dataSource, isDefault: action.payload },
|
||||
}),
|
||||
})
|
||||
.create();
|
||||
|
||||
export default {
|
||||
dataSources: dataSourcesReducer,
|
||||
|
||||
Reference in New Issue
Block a user