mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
created component for http settings
This commit is contained in:
parent
c5946ebd27
commit
e642fce4a5
7
public/app/core/components/InfoPopover/InfoPopover.tsx
Normal file
7
public/app/core/components/InfoPopover/InfoPopover.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React, { SFC } from 'react';
|
||||
interface Props {}
|
||||
const InfoPopover: SFC<Props> = props => {
|
||||
return <div />;
|
||||
};
|
||||
|
||||
export default InfoPopover;
|
223
public/app/features/datasources/DataSourceHttpSettings.tsx
Normal file
223
public/app/features/datasources/DataSourceHttpSettings.tsx
Normal file
@ -0,0 +1,223 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
interface Props {
|
||||
access: any;
|
||||
basicAuth: any;
|
||||
showAccessOption: any;
|
||||
tlsAuth: any;
|
||||
tlsAuthWithCACert: any;
|
||||
tlsCACert: any;
|
||||
tlsClientCert: any;
|
||||
tlsClientKey: any;
|
||||
url: any;
|
||||
}
|
||||
|
||||
interface State {
|
||||
basicAuthUser: string;
|
||||
basicAuthPassword: string;
|
||||
showAccessHelp: boolean;
|
||||
}
|
||||
|
||||
export default class DataSourceHttpSettings extends PureComponent<Props, State> {
|
||||
state = {
|
||||
basicAuthUser: '',
|
||||
basicAuthPassword: '',
|
||||
showAccessHelp: false,
|
||||
};
|
||||
|
||||
onToggleAccessHelp = () => {};
|
||||
|
||||
render() {
|
||||
const {
|
||||
access,
|
||||
basicAuth,
|
||||
showAccessOption,
|
||||
tlsAuth,
|
||||
tlsAuthWithCACert,
|
||||
tlsCACert,
|
||||
tlsClientCert,
|
||||
tlsClientKey,
|
||||
url,
|
||||
} = this.props;
|
||||
|
||||
const { showAccessHelp, basicAuthUser, basicAuthPassword } = this.state;
|
||||
|
||||
// const accessOptions = [{key: 'proxy', value: 'Server (Default)'}, { key: 'direct', value: 'Browser'}];
|
||||
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<h3 className="page-heading">HTTP</h3>
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form max-width-30">
|
||||
<span className="gf-form-label width-10">URL</span>
|
||||
<input className="gf-form-input" type="text" value={url} placeholder="https://localhost:9090" />
|
||||
</div>
|
||||
</div>
|
||||
{showAccessOption && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form max-width-30">
|
||||
<span className="gf-form-label width-10">Access</span>
|
||||
<div className="gf-form-select-wrapper max-width-24" />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label query-keyword pointer" onClick={this.onToggleAccessHelp}>
|
||||
Help
|
||||
{showAccessHelp && <i className="fa fa-caret-down" />}
|
||||
{!showAccessHelp && <i className="fa fa-caret-right"> </i>}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showAccessHelp && (
|
||||
<div className="grafana-info-box m-t-2">
|
||||
<p>
|
||||
Access mode controls how requests to the data source will be handled.
|
||||
<strong>
|
||||
<i>Server</i>
|
||||
</strong>{' '}
|
||||
should be the preferred way if nothing else stated.
|
||||
</p>
|
||||
<div className="alert-title">Server access mode (Default):</div>
|
||||
<p>
|
||||
All requests will be made from the browser to Grafana backend/server which in turn will forward the
|
||||
requests to the data source and by that circumvent possible Cross-Origin Resource Sharing (CORS)
|
||||
requirements. The URL needs to be accessible from the grafana backend/server if you select this access
|
||||
mode.
|
||||
</p>
|
||||
<div className="alert-title">Browser access mode:</div>
|
||||
<p>
|
||||
All requests will be made from the browser directly to the data source and may be subject to
|
||||
Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser if
|
||||
you select this access mode.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{access === 'proxy' && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-10">Whitelisted Cookies</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h3 className="page-heading">Auth</h3>
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline" />
|
||||
<div className="gf-form-inline" />
|
||||
<div className="gf-form-inline" />
|
||||
</div>
|
||||
|
||||
{basicAuth && (
|
||||
<div className="gf-form-group">
|
||||
<h6>Basic Auth Details</h6>
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-10">User</span>
|
||||
<input className="gf-form-input max-width-21" type="text" value={basicAuthUser} placeholder="User" />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-10">Password</span>
|
||||
<input
|
||||
className="gf-form-input max-width-21"
|
||||
type="password"
|
||||
value={basicAuthPassword}
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(tlsAuth || tlsAuthWithCACert) &&
|
||||
access === 'proxy' && (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<h6>TLS Auth Details</h6>
|
||||
</div>
|
||||
{tlsAuthWithCACert && (
|
||||
<div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form gf-form--v-stretch">
|
||||
<label className="gf-form-label width-7">CA Cert</label>
|
||||
</div>
|
||||
{!tlsCACert && (
|
||||
<div className="gf-form gf-form--grow">
|
||||
<textarea
|
||||
rows={7}
|
||||
className="gf-form-input gf-form-textarea"
|
||||
value={tlsCACert}
|
||||
placeholder="Begins with -----BEGIN CERTIFICATE-----"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{tlsCACert && (
|
||||
<div className="gf-form">
|
||||
<input type="text" className="gf-form-input max-width-12" value="configured" />
|
||||
<a className="btn btn-secondary gf-form-btn" href="#" onClick={() => {}}>
|
||||
reset
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tlsAuth && (
|
||||
<div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form gf-form--v-stretch">
|
||||
<label className="gf-form-label width-7">Client Cert</label>
|
||||
</div>
|
||||
{!tlsClientCert && (
|
||||
<div className="gf-form gf-form--grow">
|
||||
<textarea
|
||||
rows={7}
|
||||
className="gf-form-input gf-form-textarea"
|
||||
value={tlsClientCert}
|
||||
placeholder="Begins with -----BEGIN CERTIFICATE-----"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{tlsClientCert && (
|
||||
<div className="gf-form">
|
||||
<input type="text" className="gf-form-input max-width-12" value="configured" />
|
||||
<a className="btn btn-secondary gf-form-btn" href="#" onClick={() => {}}>
|
||||
reset
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form gf-form--v-stretch">
|
||||
<label className="gf-form-label width-7">Client Key</label>
|
||||
</div>
|
||||
{tlsClientKey && (
|
||||
<div className="gf-form gf-form--grow">
|
||||
<textarea
|
||||
rows={7}
|
||||
className="gf-form-input gf-form-textarea"
|
||||
value={tlsClientKey}
|
||||
placeholder="Begins with -----BEGIN RSA PRIVATE KEY-----"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{tlsClientKey && (
|
||||
<div className="gf-form">
|
||||
<input type="text" className="gf-form-input max-width-12" value="configured" />
|
||||
<a className="btn btn-secondary gf-form-btn" href="#" onClick={() => {}}>
|
||||
reset
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { DataSource, Plugin } from 'app/types';
|
||||
import DataSourceHttpSettings from './DataSourceHttpSettings';
|
||||
|
||||
export interface Props {
|
||||
dataSource: DataSource;
|
||||
@ -8,6 +9,7 @@ export interface Props {
|
||||
}
|
||||
interface State {
|
||||
name: string;
|
||||
showNamePopover: boolean;
|
||||
}
|
||||
|
||||
enum DataSourceStates {
|
||||
@ -16,13 +18,10 @@ enum DataSourceStates {
|
||||
}
|
||||
|
||||
export class DataSourceSettings extends PureComponent<Props, State> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: props.dataSource.name,
|
||||
};
|
||||
}
|
||||
state = {
|
||||
name: this.props.dataSource.name,
|
||||
showNamePopover: false,
|
||||
};
|
||||
|
||||
onNameChange = event => {
|
||||
this.setState({
|
||||
@ -39,6 +38,12 @@ export class DataSourceSettings extends PureComponent<Props, State> {
|
||||
console.log(event);
|
||||
};
|
||||
|
||||
onTogglePopover = () => {
|
||||
this.setState(prevState => ({
|
||||
showNamePopover: !prevState.showNamePopover,
|
||||
}));
|
||||
};
|
||||
|
||||
isReadyOnly() {
|
||||
return this.props.dataSource.readOnly === true;
|
||||
}
|
||||
@ -70,11 +75,22 @@ export class DataSourceSettings extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { name } = this.state;
|
||||
const { name, showNamePopover } = this.state;
|
||||
|
||||
const props = {
|
||||
access: {},
|
||||
basicAuth: {},
|
||||
showAccessOption: {},
|
||||
tlsAuth: {},
|
||||
tlsAuthWithCACert: {},
|
||||
tlsCACert: {},
|
||||
tlsClientCert: {},
|
||||
tlsClientKey: {},
|
||||
url: {},
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="page-sub-heading">Settings</h3>
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline">
|
||||
@ -84,10 +100,31 @@ export class DataSourceSettings extends PureComponent<Props, State> {
|
||||
className="gf-form-input max-width-23"
|
||||
type="text"
|
||||
value={name}
|
||||
placeholder="name"
|
||||
placeholder="Name"
|
||||
onChange={this.onNameChange}
|
||||
required
|
||||
/>
|
||||
<div onClick={this.onTogglePopover}>
|
||||
<i className="fa fa-info-circle" />
|
||||
</div>
|
||||
{showNamePopover && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '450px',
|
||||
top: '-20px',
|
||||
padding: '10px',
|
||||
backgroundColor: 'black',
|
||||
zIndex: 2,
|
||||
width: '300px',
|
||||
border: '1px solid gray',
|
||||
borderRadius: '3px',
|
||||
}}
|
||||
>
|
||||
The name is used when you select the data source in panels. The <em>Default</em> data source is
|
||||
preselected in new panels.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -110,6 +147,7 @@ export class DataSourceSettings extends PureComponent<Props, State> {
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
<DataSourceHttpSettings {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
74
public/app/features/datasources/EditDataSourcePage.test.tsx
Normal file
74
public/app/features/datasources/EditDataSourcePage.test.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EditDataSourcePage, Props } from './EditDataSourcePage';
|
||||
import { DataSource, NavModel } from '../../types';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
navModel: {} as NavModel,
|
||||
dataSource: {} as DataSource,
|
||||
dataSourceId: 1,
|
||||
pageName: '',
|
||||
loadDataSource: jest.fn(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const wrapper = shallow(<EditDataSourcePage {...props} />);
|
||||
const instance = wrapper.instance() as EditDataSourcePage;
|
||||
|
||||
return {
|
||||
wrapper,
|
||||
instance,
|
||||
};
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const { wrapper } = setup();
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render permissions page', () => {
|
||||
const { wrapper } = setup({
|
||||
pageName: 'permissions',
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Functions', () => {
|
||||
describe('is page valid', () => {
|
||||
it('should be a valid page', () => {
|
||||
const { instance } = setup();
|
||||
|
||||
expect(instance.isValidPage('permissions')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not be a valid page', () => {
|
||||
const { instance } = setup();
|
||||
|
||||
expect(instance.isValidPage('asdf')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('get current page', () => {
|
||||
it('should return permissions', () => {
|
||||
const { instance } = setup({
|
||||
pageName: 'permissions',
|
||||
});
|
||||
|
||||
expect(instance.getCurrentPage()).toEqual('permissions');
|
||||
});
|
||||
|
||||
it('should return settings if bogus route', () => {
|
||||
const { instance } = setup({
|
||||
pageName: 'asdf',
|
||||
});
|
||||
|
||||
expect(instance.getCurrentPage()).toEqual('settings');
|
||||
});
|
||||
});
|
||||
});
|
@ -3,6 +3,7 @@ import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import PageHeader from '../../core/components/PageHeader/PageHeader';
|
||||
import DataSourcePermissions from './DataSourcePermissions';
|
||||
import DataSourceSettings from './DataSourceSettings';
|
||||
import { DataSource, NavModel } from 'app/types';
|
||||
import { loadDataSource } from './state/actions';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
@ -24,6 +25,8 @@ enum PageTypes {
|
||||
Dashboards = 'dashboards',
|
||||
}
|
||||
|
||||
const fallBackPage = PageTypes.Settings;
|
||||
|
||||
export class EditDataSourcePage extends PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
this.fetchDataSource();
|
||||
@ -39,12 +42,13 @@ export class EditDataSourcePage extends PureComponent<Props> {
|
||||
|
||||
getCurrentPage() {
|
||||
const currentPage = this.props.pageName;
|
||||
|
||||
return this.isValidPage(currentPage) ? currentPage : PageTypes.Permissions;
|
||||
return this.isValidPage(currentPage) ? currentPage : fallBackPage;
|
||||
}
|
||||
|
||||
renderPage() {
|
||||
switch (this.getCurrentPage()) {
|
||||
case PageTypes.Settings:
|
||||
return <DataSourceSettings />;
|
||||
case PageTypes.Permissions:
|
||||
return <DataSourcePermissions />;
|
||||
}
|
||||
@ -65,7 +69,7 @@ export class EditDataSourcePage extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const pageName = getRouteParamsPage(state.location) || PageTypes.Permissions;
|
||||
const pageName = getRouteParamsPage(state.location) || fallBackPage;
|
||||
const dataSourceId = getRouteParamsId(state.location);
|
||||
const dataSourceLoadingNav = getDataSourceLoadingNav(pageName);
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
<Connect(DataSourceSettings) />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Render should render permissions page 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
<Connect(DataSourcePermissions) />
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -73,11 +73,6 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
|
||||
component: () => DataSourcesListPage,
|
||||
},
|
||||
})
|
||||
.when('/datasources/edit/:id', {
|
||||
templateUrl: 'public/app/features/plugins/partials/ds_edit.html',
|
||||
controller: 'DataSourceEditCtrl',
|
||||
controllerAs: 'ctrl',
|
||||
})
|
||||
.when('/datasources/edit/:id/dashboards', {
|
||||
templateUrl: 'public/app/features/plugins/partials/ds_dashboards.html',
|
||||
controller: 'DataSourceDashboardsCtrl',
|
||||
|
Loading…
Reference in New Issue
Block a user