The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/features/datasources/settings/DataSourceSettings.tsx

221 lines
6.5 KiB

import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { DataSource, DataSourceTest, NavModel, Plugin } from 'app/types/';
import PageHeader from '../../../core/components/PageHeader/PageHeader';
import PageLoader from '../../../core/components/PageLoader/PageLoader';
import PluginSettings from './PluginSettings';
import BasicSettings from './BasicSettings';
import ButtonRow from './ButtonRow';
import appEvents from '../../../core/app_events';
import { clearTesting, deleteDataSource, loadDataSource, setDataSourceName, updateDataSource } from '../state/actions';
import { getNavModel } from '../../../core/selectors/navModel';
import { getRouteParamsId } from '../../../core/selectors/location';
import { getDataSource, getDataSourceMeta } from '../state/selectors';
export interface Props {
navModel: NavModel;
dataSource: DataSource;
dataSourceMeta: Plugin;
pageId: number;
testing: DataSourceTest;
7 years ago
deleteDataSource: typeof deleteDataSource;
loadDataSource: typeof loadDataSource;
setDataSourceName: typeof setDataSourceName;
7 years ago
updateDataSource: typeof updateDataSource;
clearTesting: typeof clearTesting;
}
interface State {
dataSource: DataSource;
hasClosedTest: boolean;
}
enum DataSourceStates {
Alpha = 'alpha',
Beta = 'beta',
}
export class DataSourceSettings extends PureComponent<Props, State> {
state = {
dataSource: {} as DataSource,
hasClosedTest: false,
};
async componentDidMount() {
const { loadDataSource, pageId } = this.props;
await loadDataSource(pageId);
7 years ago
}
componentDidUpdate(prevProps) {
const { clearTesting } = this.props;
if (!this.state.hasClosedTest && prevProps.testing.status === 'success') {
this.setState({ hasClosedTest: true });
setTimeout(() => {
clearTesting();
this.setState({ hasClosedTest: false });
}, 3000);
}
}
componentWillUnmount() {
this.props.clearTesting();
}
onSubmit = event => {
event.preventDefault();
7 years ago
this.props.updateDataSource({ ...this.state.dataSource, name: this.props.dataSource.name });
7 years ago
};
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();
},
});
};
7 years ago
confirmDelete = () => {
this.props.deleteDataSource();
};
onModelChange = dataSource => {
this.setState({
dataSource: dataSource,
});
};
isReadOnly() {
return this.props.dataSource.readOnly === true;
}
shouldRenderInfoBox() {
const { state } = this.props.dataSourceMeta;
return state === DataSourceStates.Alpha || state === DataSourceStates.Beta;
}
getInfoText() {
const { dataSourceMeta } = this.props;
switch (dataSourceMeta.state) {
case DataSourceStates.Alpha:
return (
'This plugin is marked as being in alpha state, which means it is in early development phase and updates' +
' will include breaking changes.'
);
case DataSourceStates.Beta:
return (
'This plugin is marked as being in a beta development state. This means it is in currently in active' +
' development and could be missing important features.'
);
}
return null;
}
renderIsReadOnlyMessage() {
return (
<div className="grafana-info-box span8">
This datasource was added by config and cannot be modified using the UI. Please contact your server admin to
update this datasource.
</div>
);
}
render() {
const { dataSource, dataSourceMeta, navModel, testing } = this.props;
return (
<div>
<PageHeader model={navModel} />
{Object.keys(dataSource).length === 0 ? (
<PageLoader pageName="Data source settings" />
) : (
<div className="page-container page-body">
<div>
<form onSubmit={this.onSubmit}>
<BasicSettings
dataSourceName={this.props.dataSource.name}
onChange={name => this.props.setDataSourceName(name)}
/>
{this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>}
{this.isReadOnly() && this.renderIsReadOnlyMessage()}
{dataSourceMeta.module && (
<PluginSettings
dataSource={dataSource}
dataSourceMeta={dataSourceMeta}
onModelChange={this.onModelChange}
/>
)}
<div className="gf-form-group section">
{testing.inProgress && (
<h5>
Testing.... <i className="fa fa-spiner fa-spin" />
</h5>
)}
{!testing.inProgress &&
testing.status && (
<div className={`alert-${testing.status} alert`}>
<div className="alert-icon">
{testing.status === 'error' ? (
<i className="fa fa-exclamation-triangle" />
) : (
<i className="fa fa-check" />
)}
</div>
<div className="alert-body">
<div className="alert-title">{testing.message}</div>
</div>
</div>
)}
</div>
<ButtonRow
onSubmit={event => this.onSubmit(event)}
isReadOnly={this.isReadOnly()}
7 years ago
onDelete={this.onDelete}
/>
</form>
</div>
</div>
)}
</div>
);
}
}
function mapStateToProps(state) {
const pageId = getRouteParamsId(state.location);
const dataSource = getDataSource(state.dataSources, pageId);
return {
navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`),
dataSource: getDataSource(state.dataSources, pageId),
dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type),
pageId: pageId,
testing: state.dataSources.testing,
};
}
const mapDispatchToProps = {
7 years ago
deleteDataSource,
loadDataSource,
setDataSourceName,
7 years ago
updateDataSource,
clearTesting,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourceSettings));