// Libraries import React, { PureComponent } from 'react'; import { hot } from 'react-hot-loader'; import { connect } from 'react-redux'; // Components import Page from 'app/core/components/Page/Page'; import PluginSettings from './PluginSettings'; import BasicSettings from './BasicSettings'; import ButtonRow from './ButtonRow'; // Services & Utils import appEvents from 'app/core/app_events'; import { getBackendSrv } from 'app/core/services/backend_srv'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; // Actions & selectors import { getDataSource, getDataSourceMeta } from '../state/selectors'; import { deleteDataSource, loadDataSource, setDataSourceName, setIsDefault, updateDataSource } from '../state/actions'; import { getNavModel } from 'app/core/selectors/navModel'; import { getRouteParamsId } from 'app/core/selectors/location'; // Types import { NavModel, StoreState } from 'app/types/'; import { DataSourceSettings, DataSourcePlugin, DataSourcePluginMeta } from '@grafana/ui/src/types/'; import { getDataSourceLoadingNav } from '../state/navModel'; import PluginStateinfo from 'app/features/plugins/PluginStateInfo'; import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader'; 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; plugin?: DataSourcePlugin; } interface State { dataSource: DataSourceSettings; plugin: DataSourcePlugin; isTesting?: boolean; testingMessage?: string; testingStatus?: string; } export class DataSourceSettingsPage extends PureComponent { constructor(props: Props) { super(props); this.state = { dataSource: props.dataSource, plugin: props.plugin, }; } async loadPlugin(pluginId?: string) { const { dataSourceMeta } = this.props; let importedPlugin: DataSourcePlugin; try { importedPlugin = await importDataSourcePlugin(dataSourceMeta.module); } catch (e) { console.log('Failed to import plugin module', e); } this.setState({ plugin: importedPlugin }); } async componentDidMount() { const { loadDataSource, pageId } = this.props; await loadDataSource(pageId); if (!this.state.plugin) { await this.loadPlugin(); } } componentDidUpdate(prevProps: Props) { const { dataSource } = this.props; if (prevProps.dataSource !== dataSource) { this.setState({ dataSource }); } } onSubmit = async (evt: React.FormEvent) => { evt.preventDefault(); await this.props.updateDataSource({ ...this.state.dataSource }); this.testDataSource(); }; onTest = async (evt: React.FormEvent) => { evt.preventDefault(); this.testDataSource(); }; onDelete = () => { appEvents.emit('confirm-modal', { title: 'Delete', text: 'Are you sure you want to delete this data source?', yesText: 'Delete', icon: 'fa-trash', onConfirm: () => { this.confirmDelete(); }, }); }; confirmDelete = () => { this.props.deleteDataSource(); }; onModelChange = (dataSource: DataSourceSettings) => { this.setState({ 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.
); } async testDataSource() { const dsApi = await getDatasourceSrv().get(this.state.dataSource.name); if (!dsApi.testDatasource) { return; } this.setState({ isTesting: true, testingMessage: 'Testing...', testingStatus: 'info' }); getBackendSrv().withNoBackendCache(async () => { try { const result = await dsApi.testDatasource(); this.setState({ isTesting: false, testingStatus: result.status, testingMessage: result.message, }); } catch (err) { let message = ''; if (err.statusText) { message = 'HTTP Error ' + err.statusText; } else { message = err.message; } this.setState({ isTesting: false, testingStatus: 'error', testingMessage: message, }); } }); } get hasDataSource() { return Object.keys(this.props.dataSource).length > 0; } render() { const { dataSourceMeta, navModel, setDataSourceName, setIsDefault } = this.props; const { testingMessage, testingStatus, plugin, dataSource } = this.state; return ( {this.hasDataSource && (
{this.isReadOnly() && this.renderIsReadOnlyMessage()} setIsDefault(state)} onNameChange={name => setDataSourceName(name)} /> {dataSourceMeta.module && plugin && ( )}
{testingMessage && (
{testingStatus === 'error' ? ( ) : ( )}
{testingMessage}
)}
this.onSubmit(event)} isReadOnly={this.isReadOnly()} onDelete={this.onDelete} onTest={event => this.onTest(event)} />
)}
); } } function mapStateToProps(state: StoreState) { const pageId = getRouteParamsId(state.location); const dataSource = getDataSource(state.dataSources, pageId); return { navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`, getDataSourceLoadingNav('settings')), dataSource: getDataSource(state.dataSources, pageId), dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type), pageId: pageId, }; } const mapDispatchToProps = { deleteDataSource, loadDataSource, setDataSourceName, updateDataSource, setIsDefault, }; export default hot(module)( connect( mapStateToProps, mapDispatchToProps )(DataSourceSettingsPage) );