import React, { PureComponent, FC } from 'react'; import { connect } from 'react-redux'; import { hot } from 'react-hot-loader'; import Page from 'app/core/components/Page/Page'; import { StoreState } from 'app/types'; import { addDataSource, loadDataSourceTypes, setDataSourceTypeSearchQuery } from './state/actions'; import { getDataSourceTypes } from './state/selectors'; import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; import { NavModel, DataSourcePluginMeta, List } from '@grafana/ui'; export interface Props { navModel: NavModel; dataSourceTypes: DataSourcePluginMeta[]; isLoading: boolean; addDataSource: typeof addDataSource; loadDataSourceTypes: typeof loadDataSourceTypes; searchQuery: string; setDataSourceTypeSearchQuery: typeof setDataSourceTypeSearchQuery; } interface DataSourceCategories { [key: string]: DataSourcePluginMeta[]; } interface DataSourceCategoryInfo { id: string; title: string; } class NewDataSourcePage extends PureComponent { searchInput: HTMLElement; categoryInfoList: DataSourceCategoryInfo[] = [ { id: 'tsdb', title: 'Time series databases' }, { id: 'logging', title: 'Logging & document databases' }, { id: 'sql', title: 'SQL' }, { id: 'cloud', title: 'Cloud' }, { id: 'other', title: 'Others' }, ]; sortingRules: { [id: string]: number } = { prometheus: 100, graphite: 95, loki: 90, mysql: 80, postgres: 79, }; componentDidMount() { this.props.loadDataSourceTypes(); this.searchInput.focus(); } onDataSourceTypeClicked = (plugin: DataSourcePluginMeta) => { this.props.addDataSource(plugin); }; onSearchQueryChange = (value: string) => { this.props.setDataSourceTypeSearchQuery(value); }; renderTypes(types: DataSourcePluginMeta[]) { if (!types) { return null; } // apply custom sort ranking types.sort((a, b) => { const aSort = this.sortingRules[a.id] || 0; const bSort = this.sortingRules[b.id] || 0; if (aSort > bSort) { return -1; } if (aSort < bSort) { return 1; } return a.name > b.name ? -1 : 1; }); return ( item.id.toString()} renderItem={item => ( this.onDataSourceTypeClicked(item)} onLearnMoreClick={this.onLearnMoreClick} /> )} /> ); } onLearnMoreClick = (evt: React.SyntheticEvent) => { evt.stopPropagation(); }; renderGroupedList() { const { dataSourceTypes } = this.props; if (dataSourceTypes.length === 0) { return null; } const categories = dataSourceTypes.reduce( (accumulator, item) => { const category = item.category || 'other'; const list = accumulator[category] || []; list.push(item); accumulator[category] = list; return accumulator; }, {} as DataSourceCategories ); return ( <> {this.categoryInfoList.map(category => (
{category.title}
{this.renderTypes(categories[category.id])}
))}
Find more data source plugins on grafana.com
); } render() { const { navModel, isLoading, searchQuery, dataSourceTypes } = this.props; return (
(this.searchInput = elem)} labelClassName="gf-form--has-input-icon" inputClassName="gf-form-input width-30" value={searchQuery} onChange={this.onSearchQueryChange} placeholder="Filter by name or type" />
{searchQuery && this.renderTypes(dataSourceTypes)} {!searchQuery && this.renderGroupedList()}
); } } interface DataSourceTypeCardProps { plugin: DataSourcePluginMeta; onClick: () => void; onLearnMoreClick: (evt: React.SyntheticEvent) => void; } const DataSourceTypeCard: FC = props => { const { plugin, onClick, onLearnMoreClick } = props; // find first plugin info link const learnMoreLink = plugin.info.links && plugin.info.links.length > 0 ? plugin.info.links[0].url : null; return (
{plugin.name} {plugin.info.description && {plugin.info.description}}
{learnMoreLink && ( Learn more )}
); }; export function getNavModel(): NavModel { const main = { icon: 'gicon gicon-add-datasources', id: 'datasource-new', text: 'Add data source', href: 'datasources/new', subTitle: 'Choose a data source type', }; return { main: main, node: main, }; } function mapStateToProps(state: StoreState) { return { navModel: getNavModel(), dataSourceTypes: getDataSourceTypes(state.dataSources), searchQuery: state.dataSources.dataSourceTypeSearchQuery, isLoading: state.dataSources.isLoadingDataSources, }; } const mapDispatchToProps = { addDataSource, loadDataSourceTypes, setDataSourceTypeSearchQuery, }; export default hot(module)( connect( mapStateToProps, mapDispatchToProps )(NewDataSourcePage) );