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