1// Libraries 2import React, { PureComponent } from 'react'; 3import { connect, ConnectedProps } from 'react-redux'; 4// Services & Utils 5import { contextSrv } from 'app/core/core'; 6// Components 7import Page from 'app/core/components/Page/Page'; 8import PageActionBar from 'app/core/components/PageActionBar/PageActionBar'; 9import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; 10import DataSourcesList from './DataSourcesList'; 11// Types 12import { IconName } from '@grafana/ui'; 13import { StoreState, AccessControlAction } from 'app/types'; 14// Actions 15import { loadDataSources } from './state/actions'; 16import { getNavModel } from 'app/core/selectors/navModel'; 17 18import { 19 getDataSources, 20 getDataSourcesCount, 21 getDataSourcesLayoutMode, 22 getDataSourcesSearchQuery, 23} from './state/selectors'; 24import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/reducers'; 25 26function mapStateToProps(state: StoreState) { 27 return { 28 navModel: getNavModel(state.navIndex, 'datasources'), 29 dataSources: getDataSources(state.dataSources), 30 layoutMode: getDataSourcesLayoutMode(state.dataSources), 31 dataSourcesCount: getDataSourcesCount(state.dataSources), 32 searchQuery: getDataSourcesSearchQuery(state.dataSources), 33 hasFetched: state.dataSources.hasFetched, 34 }; 35} 36 37const mapDispatchToProps = { 38 loadDataSources, 39 setDataSourcesSearchQuery, 40 setDataSourcesLayoutMode, 41}; 42 43const connector = connect(mapStateToProps, mapDispatchToProps); 44 45export type Props = ConnectedProps<typeof connector>; 46 47const emptyListModel = { 48 title: 'No data sources defined', 49 buttonIcon: 'database' as IconName, 50 buttonLink: 'datasources/new', 51 buttonTitle: 'Add data source', 52 proTip: 'You can also define data sources through configuration files.', 53 proTipLink: 'http://docs.grafana.org/administration/provisioning/#datasources?utm_source=grafana_ds_list', 54 proTipLinkTitle: 'Learn more', 55 proTipTarget: '_blank', 56}; 57 58export class DataSourcesListPage extends PureComponent<Props> { 59 componentDidMount() { 60 this.props.loadDataSources(); 61 } 62 63 render() { 64 const { 65 dataSources, 66 dataSourcesCount, 67 navModel, 68 layoutMode, 69 searchQuery, 70 setDataSourcesSearchQuery, 71 hasFetched, 72 } = this.props; 73 74 const canCreateDataSource = 75 contextSrv.hasPermission(AccessControlAction.DataSourcesCreate) && 76 contextSrv.hasPermission(AccessControlAction.DataSourcesWrite); 77 78 const linkButton = { 79 href: 'datasources/new', 80 title: 'Add data source', 81 disabled: !canCreateDataSource, 82 }; 83 84 const emptyList = { 85 ...emptyListModel, 86 buttonDisabled: !canCreateDataSource, 87 }; 88 89 return ( 90 <Page navModel={navModel}> 91 <Page.Contents isLoading={!hasFetched}> 92 <> 93 {hasFetched && dataSourcesCount === 0 && <EmptyListCTA {...emptyList} />} 94 {hasFetched && 95 dataSourcesCount > 0 && [ 96 <PageActionBar 97 searchQuery={searchQuery} 98 setSearchQuery={(query) => setDataSourcesSearchQuery(query)} 99 linkButton={linkButton} 100 key="action-bar" 101 />, 102 <DataSourcesList dataSources={dataSources} layoutMode={layoutMode} key="list" />, 103 ]} 104 </> 105 </Page.Contents> 106 </Page> 107 ); 108 } 109} 110 111export default connector(DataSourcesListPage); 112