renders angular component

This commit is contained in:
Peter Holmberg
2018-10-31 13:23:05 +01:00
parent a7bd944098
commit 5140325a0d
7 changed files with 133 additions and 102 deletions

View File

@@ -0,0 +1,34 @@
import React, { SFC } from 'react';
import { Label } from '../../../core/components/Forms/Forms';
export interface Props {
dataSourceName: string;
onChange: (name: string) => void;
}
const BasicSettings: SFC<Props> = ({ dataSourceName, onChange }) => {
return (
<div className="gf-form-group">
<div className="gf-form max-width-30">
<Label
tooltip={
'The name is used when you select the data source in panels. The Default data source is' +
'preselected in new panels.'
}
>
Name
</Label>
<input
className="gf-form-input max-width-23"
type="text"
value={dataSourceName}
placeholder="Name"
onChange={event => onChange(event.target.value)}
required
/>
</div>
</div>
);
};
export default BasicSettings;

View File

@@ -0,0 +1,25 @@
import React, { SFC } from 'react';
export interface Props {
isReadOnly: boolean;
onDelete: (event) => void;
onSubmit: (event) => void;
}
const ButtonRow: SFC<Props> = ({ isReadOnly, onDelete, onSubmit }) => {
return (
<div className="gf-form-button-row">
<button type="submit" className="btn btn-success" disabled={isReadOnly} onClick={event => onSubmit(event)}>
Save &amp; Test
</button>
<button type="submit" className="btn btn-danger" disabled={isReadOnly} onClick={event => onDelete(event)}>
Delete
</button>
<a className="btn btn-inverse" href="/datasources">
Back
</a>
</div>
);
};
export default ButtonRow;

View File

@@ -1,15 +1,16 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { DataSource, NavModel, Plugin } from 'app/types'; import { DataSource, NavModel, Plugin } from 'app/types/';
import PageHeader from '../../core/components/PageHeader/PageHeader'; import PageHeader from '../../../core/components/PageHeader/PageHeader';
import DataSourcePluginSettings from './DataSourcePluginSettings'; import PageLoader from '../../../core/components/PageLoader/PageLoader';
import { loadDataSource, setDataSourceName } from './state/actions'; import PluginSettings from './PluginSettings';
import { getNavModel } from '../../core/selectors/navModel'; import BasicSettings from './BasicSettings';
import { getRouteParamsId } from '../../core/selectors/location'; import ButtonRow from './ButtonRow';
import { Label } from '../../core/components/Forms/Forms'; import { loadDataSource, setDataSourceName } from '../state/actions';
import PageLoader from '../../core/components/PageLoader/PageLoader'; import { getNavModel } from '../../../core/selectors/navModel';
import { getDataSource } from './state/selectors'; import { getRouteParamsId } from '../../../core/selectors/location';
import { getDataSource, getDataSourceMeta } from '../state/selectors';
export interface Props { export interface Props {
navModel: NavModel; navModel: NavModel;
@@ -45,7 +46,7 @@ export class DataSourceSettings extends PureComponent<Props, State> {
console.log(event); console.log(event);
}; };
isReadyOnly() { isReadOnly() {
return this.props.dataSource.readOnly === true; return this.props.dataSource.readOnly === true;
} }
@@ -87,59 +88,27 @@ export class DataSourceSettings extends PureComponent<Props, State> {
<div className="page-container page-body"> <div className="page-container page-body">
<div> <div>
<form onSubmit={this.onSubmit}> <form onSubmit={this.onSubmit}>
<div className="gf-form-group"> <BasicSettings
<div className="gf-form max-width-30"> dataSourceName={this.props.dataSource.name}
<Label onChange={name => this.props.setDataSourceName(name)}
tooltip={ />
'The name is used when you select the data source in panels. The Default data source is' +
'preselected in new panels.'
}
>
Name
</Label>
<input
className="gf-form-input max-width-23"
type="text"
value={this.props.dataSource.name}
placeholder="Name"
onChange={event => this.props.setDataSourceName(event.target.value)}
required
/>
</div>
</div>
{this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>} {this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>}
{this.isReadyOnly() ? ( {this.isReadOnly() ? (
<div className="grafana-info-box span8"> <div className="grafana-info-box span8">
This datasource was added by config and cannot be modified using the UI. Please contact your server This datasource was added by config and cannot be modified using the UI. Please contact your server
admin to update this datasource. admin to update this datasource.
</div> </div>
) : ( ) : (
<DataSourcePluginSettings dataSource={dataSource} dataSourceMeta={dataSourceMeta} /> dataSourceMeta.module && <PluginSettings dataSource={dataSource} dataSourceMeta={dataSourceMeta} />
)} )}
<div className="gf-form-button-row"> <ButtonRow
<button onSubmit={event => this.onSubmit(event)}
type="submit" isReadOnly={this.isReadOnly()}
className="btn btn-success" onDelete={event => this.onDelete(event)}
disabled={this.isReadyOnly()} />
onClick={this.onSubmit}
>
Save &amp; Test
</button>
<button
type="submit"
className="btn btn-danger"
disabled={this.isReadyOnly()}
onClick={this.onDelete}
>
Delete
</button>
<a className="btn btn-inverse" href="/datasources">
Back
</a>
</div>
</form> </form>
</div> </div>
</div> </div>
@@ -151,11 +120,12 @@ export class DataSourceSettings extends PureComponent<Props, State> {
function mapStateToProps(state) { function mapStateToProps(state) {
const pageId = getRouteParamsId(state.location); const pageId = getRouteParamsId(state.location);
const dataSource = getDataSource(state.dataSources, pageId);
return { return {
navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`), navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`),
dataSource: getDataSource(state.dataSources, pageId), dataSource: getDataSource(state.dataSources, pageId),
dataSourceMeta: state.dataSources.dataSourceMeta, dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type),
pageId: pageId, pageId: pageId,
}; };
} }

View File

@@ -1,31 +1,29 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { DataSource, Plugin } from 'app/types'; import { DataSource, Plugin } from 'app/types/';
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { importPluginModule } from '../plugins/plugin_loader';
interface Props { interface Props {
dataSource: DataSource; dataSource: DataSource;
dataSourceMeta: Plugin; dataSourceMeta: Plugin;
} }
export class DataSourcePluginSettings extends PureComponent<Props> { export class PluginSettings extends PureComponent<Props> {
element: any; element: any;
component: AngularComponent; component: AngularComponent;
componentDidMount() { componentDidMount() {
const { dataSource, dataSourceMeta } = this.props;
if (!this.element) { if (!this.element) {
return; return;
} }
importPluginModule(this.props.dataSourceMeta.module).then(pluginExports => {
console.log(pluginExports);
});
const loader = getAngularLoader(); const loader = getAngularLoader();
const template = '<plugin-component type="datasource-config-ctrl" />'; const template = '<plugin-component type="datasource-config-ctrl" />';
const scopeProps = { const scopeProps = {
ctrl: { ctrl: {
dataSourceMeta: this.props.dataSourceMeta, datasourceMeta: dataSourceMeta,
current: this.props.dataSource, current: dataSource,
}, },
}; };
@@ -37,4 +35,4 @@ export class DataSourcePluginSettings extends PureComponent<Props> {
} }
} }
export default DataSourcePluginSettings; export default PluginSettings;

View File

@@ -23,6 +23,14 @@ export const getDataSource = (state, dataSourceId): DataSource | null => {
return {} as DataSource; return {} as DataSource;
}; };
export const getDataSourceMeta = (state, type): Plugin => {
if (state.dataSourceMeta.id === type) {
return state.dataSourceMeta;
}
return {} as Plugin;
};
export const getDataSourcesSearchQuery = state => state.searchQuery; export const getDataSourcesSearchQuery = state => state.searchQuery;
export const getDataSourcesLayoutMode = state => state.layoutMode; export const getDataSourcesLayoutMode = state => state.layoutMode;
export const getDataSourcesCount = state => state.dataSourcesCount; export const getDataSourcesCount = state => state.dataSourcesCount;

View File

@@ -14,7 +14,7 @@ import DataSourcesListPage from 'app/features/datasources/DataSourcesListPage';
import NewDataSourcePage from '../features/datasources/NewDataSourcePage'; import NewDataSourcePage from '../features/datasources/NewDataSourcePage';
import UsersListPage from 'app/features/users/UsersListPage'; import UsersListPage from 'app/features/users/UsersListPage';
import DataSourceDashboards from 'app/features/datasources/DataSourceDashboards'; import DataSourceDashboards from 'app/features/datasources/DataSourceDashboards';
import DataSourceSettings from '../features/datasources/DataSourceSettings'; import DataSourceSettings from '../features/datasources/settings/DataSourceSettings';
/** @ngInject */ /** @ngInject */
export function setupAngularRoutes($routeProvider, $locationProvider) { export function setupAngularRoutes($routeProvider, $locationProvider) {

View File

@@ -4,22 +4,19 @@ const merge = require('webpack-merge');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const HtmlWebpackPlugin = require("html-webpack-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin'); const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin'); const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = merge(common, { module.exports = merge(common, {
entry: { entry: {
app: [ app: ['webpack-dev-server/client?http://localhost:3333', './public/app/dev.ts'],
'webpack-dev-server/client?http://localhost:3333',
'./public/app/dev.ts',
],
}, },
output: { output: {
path: path.resolve(__dirname, '../../public/build'), path: path.resolve(__dirname, '../../public/build'),
filename: '[name].[hash].js', filename: '[name].[hash].js',
publicPath: "/public/build/", publicPath: '/public/build/',
pathinfo: false, pathinfo: false,
}, },
@@ -34,8 +31,8 @@ module.exports = merge(common, {
hot: true, hot: true,
port: 3333, port: 3333,
proxy: { proxy: {
'!/public/build': 'http://localhost:3000' '!/public/build': 'http://localhost:3000',
} },
}, },
optimization: { optimization: {
@@ -47,40 +44,39 @@ module.exports = merge(common, {
module: { module: {
rules: [ rules: [
{ {
test: /(?!.*\.test)\.tsx$/, test: /(?!.*\.test)\.(ts|tsx)$/,
exclude: /node_modules/, exclude: /node_modules/,
use: [{ use: [
loader: 'babel-loader', {
options: { loader: 'babel-loader',
cacheDirectory: true, options: {
babelrc: false, cacheDirectory: true,
plugins: [ babelrc: false,
'syntax-dynamic-import', plugins: ['syntax-dynamic-import', 'react-hot-loader/babel'],
'react-hot-loader/babel' },
]
}
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
experimentalWatchApi: true
}, },
}], {
loader: 'ts-loader',
options: {
transpileOnly: true,
experimentalWatchApi: true,
},
},
],
}, },
{ {
test: /\.scss$/, test: /\.scss$/,
use: [ use: [
"style-loader", // creates style nodes from JS strings 'style-loader', // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS 'css-loader', // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS 'sass-loader', // compiles Sass to CSS
] ],
}, },
{ {
test: /\.(png|jpg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, test: /\.(png|jpg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader' loader: 'file-loader',
}, },
] ],
}, },
plugins: [ plugins: [
@@ -89,16 +85,16 @@ module.exports = merge(common, {
filename: path.resolve(__dirname, '../../public/views/index.html'), filename: path.resolve(__dirname, '../../public/views/index.html'),
template: path.resolve(__dirname, '../../public/views/index.template.html'), template: path.resolve(__dirname, '../../public/views/index.template.html'),
inject: 'body', inject: 'body',
alwaysWriteToDisk: true alwaysWriteToDisk: true,
}), }),
new HtmlWebpackHarddiskPlugin(), new HtmlWebpackHarddiskPlugin(),
new webpack.NamedModulesPlugin(), new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'GRAFANA_THEME': JSON.stringify(process.env.GRAFANA_THEME || 'dark'), GRAFANA_THEME: JSON.stringify(process.env.GRAFANA_THEME || 'dark'),
'process.env': { 'process.env': {
'NODE_ENV': JSON.stringify('development') NODE_ENV: JSON.stringify('development'),
} },
}), }),
] ],
}); });