// Libraries import React, { PureComponent } from 'react'; import { hot } from 'react-hot-loader'; import isString from 'lodash/isString'; import { Icon } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; // Components import Page from 'app/core/components/Page/Page'; import { GenericDataSourcePlugin, PluginSettings } from './PluginSettings'; import BasicSettings from './BasicSettings'; import ButtonRow from './ButtonRow'; // Services & Utils import appEvents from 'app/core/app_events'; // Actions & selectors import { getDataSource, getDataSourceMeta } from '../state/selectors'; import { deleteDataSource, initDataSourceSettings, loadDataSource, testDataSource, updateDataSource, } from '../state/actions'; import { getNavModel } from 'app/core/selectors/navModel'; import { getRouteParamsId } from 'app/core/selectors/location'; // Types import { CoreEvents, StoreState } from 'app/types/'; import { DataSourcePluginMeta, DataSourceSettings, NavModel, UrlQueryMap } from '@grafana/data'; import { getDataSourceLoadingNav } from '../state/navModel'; import PluginStateinfo from 'app/features/plugins/PluginStateInfo'; import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers'; import { connectWithCleanUp } from 'app/core/components/connectWithCleanUp'; export interface Props { navModel: NavModel; dataSource: DataSourceSettings; dataSourceMeta: DataSourcePluginMeta; pageId: number; deleteDataSource: typeof deleteDataSource; loadDataSource: typeof loadDataSource; setDataSourceName: typeof setDataSourceName; updateDataSource: typeof updateDataSource; setIsDefault: typeof setIsDefault; dataSourceLoaded: typeof dataSourceLoaded; initDataSourceSettings: typeof initDataSourceSettings; testDataSource: typeof testDataSource; plugin?: GenericDataSourcePlugin; query: UrlQueryMap; page?: string; testingStatus?: { message?: string; status?: string; }; loadError?: Error | string; } export class DataSourceSettingsPage extends PureComponent { componentDidMount() { const { initDataSourceSettings, pageId } = this.props; initDataSourceSettings(pageId); } onSubmit = async (evt: React.FormEvent) => { evt.preventDefault(); await this.props.updateDataSource({ ...this.props.dataSource }); this.testDataSource(); }; onTest = async (evt: React.FormEvent) => { evt.preventDefault(); this.testDataSource(); }; onDelete = () => { appEvents.emit(CoreEvents.showConfirmModal, { title: 'Delete', text: 'Are you sure you want to delete this data source?', yesText: 'Delete', icon: 'trash-alt', onConfirm: () => { this.confirmDelete(); }, }); }; confirmDelete = () => { this.props.deleteDataSource(); }; onModelChange = (dataSource: DataSourceSettings) => { this.props.dataSourceLoaded(dataSource); }; isReadOnly() { return this.props.dataSource.readOnly === true; } renderIsReadOnlyMessage() { return (
This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
); } testDataSource() { const { dataSource, testDataSource } = this.props; testDataSource(dataSource.name); } get hasDataSource() { return this.props.dataSource.id > 0; } renderLoadError(loadError: any) { let showDelete = false; let msg = loadError.toString(); if (loadError.data) { if (loadError.data.message) { msg = loadError.data.message; } } else if (isString(loadError)) { showDelete = true; } const node = { text: msg, subTitle: 'Data Source Error', icon: 'exclamation-triangle', }; const nav = { node: node, main: node, }; return (
{showDelete && ( )} Back
); } renderConfigPageBody(page: string) { const { plugin } = this.props; if (!plugin || !plugin.configPages) { return null; // still loading } for (const p of plugin.configPages) { if (p.id === page) { return ; } } return
Page Not Found: {page}
; } renderSettings() { const { dataSourceMeta, setDataSourceName, setIsDefault, dataSource, testingStatus, plugin } = this.props; return (
{this.isReadOnly() && this.renderIsReadOnlyMessage()} {dataSourceMeta.state && (
)} setIsDefault(state)} onNameChange={name => setDataSourceName(name)} /> {plugin && ( )}
{testingStatus && testingStatus.message && (
{testingStatus.status === 'error' ? : }
{testingStatus.message}
)}
this.onSubmit(event)} isReadOnly={this.isReadOnly()} onDelete={this.onDelete} onTest={event => this.onTest(event)} /> ); } render() { const { navModel, page, loadError } = this.props; if (loadError) { return this.renderLoadError(loadError); } return ( {this.hasDataSource ?
{page ? this.renderConfigPageBody(page) : this.renderSettings()}
: null}
); } } function mapStateToProps(state: StoreState) { const pageId = getRouteParamsId(state.location); const dataSource = getDataSource(state.dataSources, pageId); const page = state.location.query.page as string; const { plugin, loadError, testingStatus } = state.dataSourceSettings; return { navModel: getNavModel( state.navIndex, page ? `datasource-page-${page}` : `datasource-settings-${pageId}`, getDataSourceLoadingNav('settings') ), dataSource: getDataSource(state.dataSources, pageId), dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type), pageId: pageId, query: state.location.query, page, plugin, loadError, testingStatus, }; } const mapDispatchToProps = { deleteDataSource, loadDataSource, setDataSourceName, updateDataSource, setIsDefault, dataSourceLoaded, initDataSourceSettings, testDataSource, }; export default hot(module)( connectWithCleanUp(mapStateToProps, mapDispatchToProps, state => state.dataSourceSettings)(DataSourceSettingsPage) );