diff --git a/public/app/features/datasources/NewDataSourcePage.tsx b/public/app/features/datasources/NewDataSourcePage.tsx index f03304327a6..08ab4fdee4f 100644 --- a/public/app/features/datasources/NewDataSourcePage.tsx +++ b/public/app/features/datasources/NewDataSourcePage.tsx @@ -3,9 +3,10 @@ import { connect } from 'react-redux'; import { hot } from 'react-hot-loader'; import PageHeader from 'app/core/components/PageHeader/PageHeader'; import { NavModel, Plugin } from 'app/types'; -import { addDataSource, loadDataSourceTypes } from './state/actions'; +import { addDataSource, loadDataSourceTypes, setDataSourceTypeSearchQuery } from './state/actions'; import { updateLocation } from '../../core/actions'; import { getNavModel } from 'app/core/selectors/navModel'; +import { getDataSourceTypes } from './state/selectors'; export interface Props { navModel: NavModel; @@ -13,6 +14,8 @@ export interface Props { addDataSource: typeof addDataSource; loadDataSourceTypes: typeof loadDataSourceTypes; updateLocation: typeof updateLocation; + dataSourceTypeSearchQuery: string; + setDataSourceTypeSearchQuery: typeof setDataSourceTypeSearchQuery; } class NewDataSourcePage extends PureComponent { @@ -24,14 +27,30 @@ class NewDataSourcePage extends PureComponent { this.props.addDataSource(type.name, type.value); }; + onSearchQueryChange = event => { + this.props.setDataSourceTypeSearchQuery(event.target.value); + }; + render() { - const { navModel, dataSourceTypes } = this.props; + const { navModel, dataSourceTypes, dataSourceTypeSearchQuery } = this.props; return (

Choose data source type

+
+ +
{dataSourceTypes.map((type, index) => { return ( @@ -55,7 +74,7 @@ class NewDataSourcePage extends PureComponent { function mapStateToProps(state) { return { navModel: getNavModel(state.navIndex, 'datasources'), - dataSourceTypes: state.dataSources.dataSourceTypes, + dataSourceTypes: getDataSourceTypes(state.dataSources), }; } @@ -63,6 +82,7 @@ const mapDispatchToProps = { addDataSource, loadDataSourceTypes, updateLocation, + setDataSourceTypeSearchQuery, }; export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(NewDataSourcePage)); diff --git a/public/app/features/datasources/state/actions.ts b/public/app/features/datasources/state/actions.ts index b8cdafa9fe3..f423ae65d53 100644 --- a/public/app/features/datasources/state/actions.ts +++ b/public/app/features/datasources/state/actions.ts @@ -10,6 +10,7 @@ export enum ActionTypes { LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES', SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY', SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE', + SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY', } export interface LoadDataSourcesAction { @@ -32,6 +33,11 @@ export interface LoadDataSourceTypesAction { payload: Plugin[]; } +export interface SetDataSourceTypeSearchQueryAction { + type: ActionTypes.SetDataSourceTypeSearchQuery; + payload: string; +} + const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({ type: ActionTypes.LoadDataSources, payload: dataSources, @@ -52,12 +58,18 @@ export const setDataSourcesLayoutMode = (layoutMode: LayoutMode): SetDataSources payload: layoutMode, }); +export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSearchQueryAction => ({ + type: ActionTypes.SetDataSourceTypeSearchQuery, + payload: query, +}); + export type Action = | LoadDataSourcesAction | SetDataSourcesSearchQueryAction | SetDataSourcesLayoutModeAction | UpdateLocationAction - | LoadDataSourceTypesAction; + | LoadDataSourceTypesAction + | SetDataSourceTypeSearchQueryAction; type ThunkResult = ThunkAction; diff --git a/public/app/features/datasources/state/reducers.ts b/public/app/features/datasources/state/reducers.ts index ec5e0f811a9..acb228d3ed6 100644 --- a/public/app/features/datasources/state/reducers.ts +++ b/public/app/features/datasources/state/reducers.ts @@ -8,6 +8,7 @@ const initialState: DataSourcesState = { searchQuery: '', dataSourcesCount: 0, dataSourceTypes: [] as Plugin[], + dataSourceTypeSearchQuery: '', }; export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => { @@ -23,6 +24,9 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo case ActionTypes.LoadDataSourceTypes: return { ...state, dataSourceTypes: action.payload }; + + case ActionTypes.SetDataSourceTypeSearchQuery: + return { ...state, dataSourceTypeSearchQuery: action.payload }; } return state; diff --git a/public/app/features/datasources/state/selectors.ts b/public/app/features/datasources/state/selectors.ts index 6df08f68037..80e1400114f 100644 --- a/public/app/features/datasources/state/selectors.ts +++ b/public/app/features/datasources/state/selectors.ts @@ -6,6 +6,14 @@ export const getDataSources = state => { }); }; +export const getDataSourceTypes = state => { + const regex = new RegExp(state.dataSourceTypeSearchQuery, 'i'); + + return state.dataSourceTypes.filter(type => { + return regex.test(type.name); + }); +}; + export const getDataSourcesSearchQuery = state => state.searchQuery; export const getDataSourcesLayoutMode = state => state.layoutMode; export const getDataSourcesCount = state => state.dataSourcesCount; diff --git a/public/app/types/datasources.ts b/public/app/types/datasources.ts index 237d51c53b0..4d8d755f106 100644 --- a/public/app/types/datasources.ts +++ b/public/app/types/datasources.ts @@ -21,6 +21,7 @@ export interface DataSource { export interface DataSourcesState { dataSources: DataSource[]; searchQuery: string; + dataSourceTypeSearchQuery: string; layoutMode: LayoutMode; dataSourcesCount: number; dataSourceTypes: Plugin[]; diff --git a/public/sass/components/_add_data_source.scss b/public/sass/components/_add_data_source.scss index 9da3b14ad51..9a6c71d8061 100644 --- a/public/sass/components/_add_data_source.scss +++ b/public/sass/components/_add_data_source.scss @@ -1,13 +1,27 @@ .add-data-source-header { - margin-bottom: 20px; + margin-bottom: $panel-margin * 2; text-align: center; } +.add-data-source-search { + display: flex; + justify-content: center; + margin-bottom: $panel-margin * 6; +} + .add-data-source-grid { display: grid; - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(2, 1fr); grid-row-gap: 10px; grid-column-gap: 10px; + + @include media-breakpoint-up(md) { + grid-template-columns: repeat(3, 1fr); + } + + @include media-breakpoint-up(lg) { + grid-template-columns: repeat(4, 1fr); + } } .add-data-source-grid-item {