Browse Source

updated view to use angular loader

Peter Holmberg 7 years ago
parent
commit
a7bd944098

+ 0 - 331
public/app/features/datasources/DataSourceHttpSettings.tsx

@@ -1,331 +0,0 @@
-import React, { PureComponent } from 'react';
-import { connect } from 'react-redux';
-import { DataSource } from 'app/types';
-import FormSwitch from '../../core/components/FormSwitch/FormSwitch';
-
-interface Props {
-  dataSource: DataSource;
-  showAccessOption: any;
-  tlsAuth: any;
-  tlsAuthWithCACert: any;
-  tlsCACert: any;
-  tlsClientCert: any;
-  tlsClientKey: any;
-}
-
-interface State {
-  basicAuthUser: string;
-  basicAuthPassword: string;
-  showAccessHelp: boolean;
-  url: string;
-  access: string;
-}
-
-export class DataSourceHttpSettings extends PureComponent<Props, State> {
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      url: '',
-      basicAuthUser: props.dataSource.basicAuthUser,
-      basicAuthPassword: props.dataSource.basicAuthPassword,
-      showAccessHelp: false,
-      access: '',
-    };
-  }
-
-  onToggleAccessHelp = () => {
-    this.setState(prevState => ({
-      showAccessHelp: !prevState.showAccessHelp,
-    }));
-  };
-
-  onUrlChange = event => {
-    this.setState({
-      url: event.target.value,
-    });
-  };
-
-  onAccessChange = event => {
-    this.setState({
-      access: event.target.value,
-    });
-  };
-
-  onBasicAuthChange = event => {
-    console.log(event);
-  };
-
-  onWithCredentialsChange = event => {
-    console.log(event);
-  };
-
-  onTlsAuthChange = event => {
-    console.log(event);
-  };
-
-  onTlsAuthWithCACertChange = event => {
-    console.log(event);
-  };
-
-  onTlsSkipVerifyChange = event => {
-    console.log(event);
-  };
-
-  render() {
-    const {
-      dataSource,
-      showAccessOption,
-      tlsAuth,
-      tlsAuthWithCACert,
-      tlsCACert,
-      tlsClientCert,
-      tlsClientKey,
-    } = this.props;
-
-    const { access, showAccessHelp, basicAuthUser, basicAuthPassword, url } = 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}
-                onChange={this.onUrlChange}
-                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>
-                <select className="width-20" value={access} onChange={this.onAccessChange}>
-                  {accessOptions.map(option => {
-                    return (
-                      <option key={option.key} value={option.key}>
-                        {option.value}
-                      </option>
-                    );
-                  })}
-                </select>
-              </div>
-              <div className="gf-form">
-                <label className="gf-form-label query-keyword pointer" onClick={this.onToggleAccessHelp}>
-                  Help&nbsp;
-                  {showAccessHelp ? <i className="fa fa-caret-down" /> : <i className="fa fa-caret-right">&nbsp;</i>}
-                </label>
-              </div>
-            </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">
-            <FormSwitch
-              onChange={this.onBasicAuthChange}
-              label="Basic auth"
-              checked={dataSource.basicAuth}
-              labelClass="width-10"
-              switchClass="max-width-6"
-            />
-            <FormSwitch
-              label="With credentials"
-              checked={dataSource.withCredentials}
-              onChange={this.onWithCredentialsChange}
-              labelClass="width-10"
-              switchClass="max-width-6"
-            />
-          </div>
-          <div className="gf-form-inline">
-            {dataSource.jsonData && [
-              <FormSwitch
-                key="TLS CLient Auth"
-                label="TLS CLient Auth"
-                checked={dataSource.jsonData.authType === 'tlsAuth'}
-                onChange={this.onTlsAuthChange}
-                labelClass="width-10"
-                switchClass="max-width-6"
-              />,
-              <FormSwitch
-                key="With CA Cert"
-                label="With CA Cert"
-                checked={dataSource.jsonData.authType === 'tlsAuthWithCACert'}
-                onChange={this.onTlsAuthWithCACertChange}
-                labelClass="width-10"
-                switchClass="max-width-6"
-              />,
-            ]}
-          </div>
-        </div>
-        <div className="gf-form-inline">
-          {dataSource.jsonData && (
-            <FormSwitch
-              label="Skip TLS Verify"
-              checked={dataSource.jsonData.authType === 'tlsSkipVerify'}
-              onChange={this.onTlsSkipVerifyChange}
-              labelClass="width-10"
-              switchClass="max-width-6"
-            />
-          )}
-        </div>
-
-        {dataSource.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>
-    );
-  }
-}
-
-function mapStateToProps(state) {
-  return {
-    dataSource: state.dataSources.dataSource,
-  };
-}
-
-export default connect(mapStateToProps)(DataSourceHttpSettings);

+ 40 - 0
public/app/features/datasources/DataSourcePluginSettings.tsx

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

+ 65 - 81
public/app/features/datasources/DataSourceSettings.tsx

@@ -1,11 +1,15 @@
-import React, { createRef, PureComponent } from 'react';
+import React, { PureComponent } from 'react';
+import { hot } from 'react-hot-loader';
 import { connect } from 'react-redux';
 import { DataSource, NavModel, Plugin } from 'app/types';
 import PageHeader from '../../core/components/PageHeader/PageHeader';
-import { importPluginModule } from '../plugins/plugin_loader';
-import { loadDataSource } from './state/actions';
+import DataSourcePluginSettings from './DataSourcePluginSettings';
+import { loadDataSource, setDataSourceName } from './state/actions';
 import { getNavModel } from '../../core/selectors/navModel';
 import { getRouteParamsId } from '../../core/selectors/location';
+import { Label } from '../../core/components/Forms/Forms';
+import PageLoader from '../../core/components/PageLoader/PageLoader';
+import { getDataSource } from './state/selectors';
 
 export interface Props {
   navModel: NavModel;
@@ -13,6 +17,7 @@ export interface Props {
   dataSourceMeta: Plugin;
   pageId: number;
   loadDataSource: typeof loadDataSource;
+  setDataSourceName: typeof setDataSourceName;
 }
 interface State {
   name: string;
@@ -25,28 +30,12 @@ enum DataSourceStates {
 }
 
 export class DataSourceSettings extends PureComponent<Props, State> {
-  settingsElement = createRef<HTMLDivElement>();
-
-  state = {
-    name: this.props.dataSource.name,
-    showNamePopover: false,
-  };
-
   async componentDidMount() {
     const { loadDataSource, pageId } = this.props;
 
     await loadDataSource(pageId);
-    importPluginModule(this.props.dataSourceMeta.module).then(pluginExports => {
-      console.log(pluginExports);
-    });
   }
 
-  onNameChange = event => {
-    this.setState({
-      name: event.target.value,
-    });
-  };
-
   onSubmit = event => {
     event.preventDefault();
     console.log(event);
@@ -56,12 +45,6 @@ export class DataSourceSettings extends PureComponent<Props, State> {
     console.log(event);
   };
 
-  onTogglePopover = () => {
-    this.setState(prevState => ({
-      showNamePopover: !prevState.showNamePopover,
-    }));
-  };
-
   isReadyOnly() {
     return this.props.dataSource.readOnly === true;
   }
@@ -93,74 +76,74 @@ export class DataSourceSettings extends PureComponent<Props, State> {
   }
 
   render() {
-    const { name, showNamePopover } = this.state;
-
-    console.log(this.props);
+    const { dataSource, dataSourceMeta, navModel } = this.props;
 
     return (
       <div>
-        <PageHeader model={this.props.navModel} />
-        <div className="page-container page-body">
-          <div>
-            <form onSubmit={this.onSubmit}>
-              <div className="gf-form-group">
-                <div className="gf-form-inline">
+        <PageHeader model={navModel} />
+        {Object.keys(dataSource).length === 0 && Object.keys(dataSourceMeta).length === 0 ? (
+          <PageLoader pageName="Data source settings" />
+        ) : (
+          <div className="page-container page-body">
+            <div>
+              <form onSubmit={this.onSubmit}>
+                <div className="gf-form-group">
                   <div className="gf-form max-width-30">
-                    <span className="gf-form-label width-10">Name</span>
+                    <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={name}
+                      value={this.props.dataSource.name}
                       placeholder="Name"
-                      onChange={this.onNameChange}
+                      onChange={event => this.props.setDataSourceName(event.target.value)}
                       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>
-              {this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>}
-              {this.isReadyOnly() && (
-                <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.
+
+                {this.shouldRenderInfoBox() && <div className="grafana-info-box">{this.getInfoText()}</div>}
+
+                {this.isReadyOnly() ? (
+                  <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>
+                ) : (
+                  <DataSourcePluginSettings dataSource={dataSource} dataSourceMeta={dataSourceMeta} />
+                )}
+
+                <div className="gf-form-button-row">
+                  <button
+                    type="submit"
+                    className="btn btn-success"
+                    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>
-              )}
-              <div ref={this.settingsElement} />
-              <div className="gf-form-button-row">
-                <button type="submit" className="btn btn-success" 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>
     );
   }
@@ -171,7 +154,7 @@ function mapStateToProps(state) {
 
   return {
     navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`),
-    dataSource: state.dataSources.dataSource,
+    dataSource: getDataSource(state.dataSources, pageId),
     dataSourceMeta: state.dataSources.dataSourceMeta,
     pageId: pageId,
   };
@@ -179,6 +162,7 @@ function mapStateToProps(state) {
 
 const mapDispatchToProps = {
   loadDataSource,
+  setDataSourceName,
 };
 
-export default connect(mapStateToProps, mapDispatchToProps)(DataSourceSettings);
+export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourceSettings));

+ 0 - 177
public/app/features/datasources/__snapshots__/AddDataSourcePermissions.test.tsx.snap

@@ -1,177 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Render should render component 1`] = `
-<div
-  className="gf-form-inline cta-form"
->
-  <button
-    className="cta-form__close btn btn-transparent"
-    onClick={[MockFunction]}
-  >
-    <i
-      className="fa fa-close"
-    />
-  </button>
-  <form
-    name="addPermission"
-    onSubmit={[Function]}
-  >
-    <h5>
-      Add Permission For
-    </h5>
-    <div
-      className="gf-form-inline"
-    >
-      <div
-        className="gf-form"
-      >
-        <select
-          className="gf-form-input gf-size-auto"
-          onChange={[Function]}
-          value="Team"
-        >
-          <option
-            key="0"
-            value="Team"
-          >
-            Team
-          </option>
-          <option
-            key="1"
-            value="User"
-          >
-            User
-          </option>
-        </select>
-      </div>
-      <div
-        className="gf-form"
-      >
-        <TeamPicker
-          className="width-20"
-          onSelected={[Function]}
-        />
-      </div>
-      <div
-        className="gf-form"
-      >
-        <DescriptionPicker
-          className="gf-form-input--form-dropdown-right"
-          disabled={false}
-          onSelected={[Function]}
-          optionsWithDesc={
-            Array [
-              Object {
-                "description": "Can query data source.",
-                "label": "Query",
-                "value": 1,
-              },
-            ]
-          }
-          value={1}
-        />
-      </div>
-      <div
-        className="gf-form"
-      >
-        <button
-          className="btn btn-success"
-          data-save-permission={true}
-          disabled={true}
-          type="submit"
-        >
-          Save
-        </button>
-      </div>
-    </div>
-  </form>
-</div>
-`;
-
-exports[`Render should render user picker 1`] = `
-<div
-  className="gf-form-inline cta-form"
->
-  <button
-    className="cta-form__close btn btn-transparent"
-    onClick={[MockFunction]}
-  >
-    <i
-      className="fa fa-close"
-    />
-  </button>
-  <form
-    name="addPermission"
-    onSubmit={[Function]}
-  >
-    <h5>
-      Add Permission For
-    </h5>
-    <div
-      className="gf-form-inline"
-    >
-      <div
-        className="gf-form"
-      >
-        <select
-          className="gf-form-input gf-size-auto"
-          onChange={[Function]}
-          value="User"
-        >
-          <option
-            key="0"
-            value="Team"
-          >
-            Team
-          </option>
-          <option
-            key="1"
-            value="User"
-          >
-            User
-          </option>
-        </select>
-      </div>
-      <div
-        className="gf-form"
-      >
-        <UserPicker
-          className="width-20"
-          onSelected={[Function]}
-        />
-      </div>
-      <div
-        className="gf-form"
-      >
-        <DescriptionPicker
-          className="gf-form-input--form-dropdown-right"
-          disabled={false}
-          onSelected={[Function]}
-          optionsWithDesc={
-            Array [
-              Object {
-                "description": "Can query data source.",
-                "label": "Query",
-                "value": 1,
-              },
-            ]
-          }
-          value={1}
-        />
-      </div>
-      <div
-        className="gf-form"
-      >
-        <button
-          className="btn btn-success"
-          data-save-permission={true}
-          disabled={true}
-          type="submit"
-        >
-          Save
-        </button>
-      </div>
-    </div>
-  </form>
-</div>
-`;

+ 0 - 327
public/app/features/datasources/__snapshots__/DataSourcePermissionsList.test.tsx.snap

@@ -1,327 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Render should render component 1`] = `
-<table
-  className="filter-table gf-form-group"
->
-  <tbody>
-    <tr
-      className="gf-form-disabled"
-    >
-      <td
-        style={
-          Object {
-            "width": "1%",
-          }
-        }
-      >
-        <i
-          className="gicon gicon-shield"
-          style={
-            Object {
-              "height": "25px",
-              "width": "25px",
-            }
-          }
-        />
-      </td>
-      <td
-        style={
-          Object {
-            "width": "90%",
-          }
-        }
-      >
-        Admin
-        <span
-          className="filter-table__weak-italic"
-        >
-           (Role)
-        </span>
-      </td>
-      <td />
-      <td
-        className="query-keyword"
-      >
-        Can
-      </td>
-      <td>
-        <div
-          className="gf-form"
-        >
-          <DescriptionPicker
-            className="gf-form-input--form-dropdown-right"
-            disabled={true}
-            onSelected={[Function]}
-            optionsWithDesc={
-              Array [
-                Object {
-                  "description": "Can query data source.",
-                  "label": "Query",
-                  "value": 1,
-                },
-                Object {
-                  "description": "",
-                  "label": "Admin",
-                  "value": 2,
-                },
-              ]
-            }
-            value={2}
-          />
-        </div>
-      </td>
-      <td>
-        <button
-          className="btn btn-inverse btn-small"
-        >
-          <i
-            className="fa fa-lock"
-          />
-        </button>
-      </td>
-    </tr>
-  </tbody>
-</table>
-`;
-
-exports[`Render should render items 1`] = `
-<table
-  className="filter-table gf-form-group"
->
-  <tbody>
-    <tr
-      className="gf-form-disabled"
-    >
-      <td
-        style={
-          Object {
-            "width": "1%",
-          }
-        }
-      >
-        <i
-          className="gicon gicon-shield"
-          style={
-            Object {
-              "height": "25px",
-              "width": "25px",
-            }
-          }
-        />
-      </td>
-      <td
-        style={
-          Object {
-            "width": "90%",
-          }
-        }
-      >
-        Admin
-        <span
-          className="filter-table__weak-italic"
-        >
-           (Role)
-        </span>
-      </td>
-      <td />
-      <td
-        className="query-keyword"
-      >
-        Can
-      </td>
-      <td>
-        <div
-          className="gf-form"
-        >
-          <DescriptionPicker
-            className="gf-form-input--form-dropdown-right"
-            disabled={true}
-            onSelected={[Function]}
-            optionsWithDesc={
-              Array [
-                Object {
-                  "description": "Can query data source.",
-                  "label": "Query",
-                  "value": 1,
-                },
-                Object {
-                  "description": "",
-                  "label": "Admin",
-                  "value": 2,
-                },
-              ]
-            }
-            value={2}
-          />
-        </div>
-      </td>
-      <td>
-        <button
-          className="btn btn-inverse btn-small"
-        >
-          <i
-            className="fa fa-lock"
-          />
-        </button>
-      </td>
-    </tr>
-    <tr
-      key="2-0"
-    >
-      <td
-        style={
-          Object {
-            "width": "1%",
-          }
-        }
-      >
-        <img
-          className="filter-table__avatar"
-          src="/avatar/926aa85c6bcefa0b4deca3223f337ae1"
-        />
-      </td>
-      <td
-        style={
-          Object {
-            "width": "90%",
-          }
-        }
-      >
-        <span
-          key="name"
-        >
-          testUser
-           
-        </span>
-        <span
-          className="filter-table__weak-italic"
-          key="description"
-        >
-          (User)
-        </span>
-      </td>
-      <td />
-      <td
-        className="query-keyword"
-      >
-        Can
-      </td>
-      <td>
-        <div
-          className="gf-form"
-        >
-          <DescriptionPicker
-            className="gf-form-input--form-dropdown-right"
-            disabled={true}
-            onSelected={[Function]}
-            optionsWithDesc={
-              Array [
-                Object {
-                  "description": "Can query data source.",
-                  "label": "Query",
-                  "value": 1,
-                },
-                Object {
-                  "description": "",
-                  "label": "Admin",
-                  "value": 2,
-                },
-              ]
-            }
-            value={1}
-          />
-        </div>
-      </td>
-      <td>
-        <button
-          className="btn btn-danger btn-small"
-          onClick={[Function]}
-        >
-          <i
-            className="fa fa-remove"
-          />
-        </button>
-      </td>
-    </tr>
-    <tr
-      key="6-1"
-    >
-      <td
-        style={
-          Object {
-            "width": "1%",
-          }
-        }
-      >
-        <img
-          className="filter-table__avatar"
-          src="/avatar/93c0801b955cbd443a8cfa91a401d7bc"
-        />
-      </td>
-      <td
-        style={
-          Object {
-            "width": "90%",
-          }
-        }
-      >
-        <span
-          key="name"
-        >
-          A-team
-           
-        </span>
-        <span
-          className="filter-table__weak-italic"
-          key="description"
-        >
-          (Team)
-        </span>
-      </td>
-      <td />
-      <td
-        className="query-keyword"
-      >
-        Can
-      </td>
-      <td>
-        <div
-          className="gf-form"
-        >
-          <DescriptionPicker
-            className="gf-form-input--form-dropdown-right"
-            disabled={true}
-            onSelected={[Function]}
-            optionsWithDesc={
-              Array [
-                Object {
-                  "description": "Can query data source.",
-                  "label": "Query",
-                  "value": 1,
-                },
-                Object {
-                  "description": "",
-                  "label": "Admin",
-                  "value": 2,
-                },
-              ]
-            }
-            value={1}
-          />
-        </div>
-      </td>
-      <td>
-        <button
-          className="btn btn-danger btn-small"
-          onClick={[Function]}
-        >
-          <i
-            className="fa fa-remove"
-          />
-        </button>
-      </td>
-    </tr>
-  </tbody>
-</table>
-`;

+ 0 - 27
public/app/features/datasources/__snapshots__/EditDataSourcePage.test.tsx.snap

@@ -1,27 +0,0 @@
-// 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>
-`;

+ 20 - 8
public/app/features/datasources/state/actions.ts

@@ -14,43 +14,49 @@ export enum ActionTypes {
   SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
   SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
   SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
+  SetDataSourceName = 'SET_DATA_SOURCE_NAME',
 }
 
-export interface LoadDataSourcesAction {
+interface LoadDataSourcesAction {
   type: ActionTypes.LoadDataSources;
   payload: DataSource[];
 }
 
-export interface SetDataSourcesSearchQueryAction {
+interface SetDataSourcesSearchQueryAction {
   type: ActionTypes.SetDataSourcesSearchQuery;
   payload: string;
 }
 
-export interface SetDataSourcesLayoutModeAction {
+interface SetDataSourcesLayoutModeAction {
   type: ActionTypes.SetDataSourcesLayoutMode;
   payload: LayoutMode;
 }
 
-export interface LoadDataSourceTypesAction {
+interface LoadDataSourceTypesAction {
   type: ActionTypes.LoadDataSourceTypes;
   payload: Plugin[];
 }
 
-export interface SetDataSourceTypeSearchQueryAction {
+interface SetDataSourceTypeSearchQueryAction {
   type: ActionTypes.SetDataSourceTypeSearchQuery;
   payload: string;
 }
 
-export interface LoadDataSourceAction {
+interface LoadDataSourceAction {
   type: ActionTypes.LoadDataSource;
   payload: DataSource;
 }
 
-export interface LoadDataSourceMetaAction {
+interface LoadDataSourceMetaAction {
   type: ActionTypes.LoadDataSourceMeta;
   payload: Plugin;
 }
 
+interface SetDataSourceNameAction {
+  type: ActionTypes.SetDataSourceName;
+  payload: string;
+}
+
 const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
   type: ActionTypes.LoadDataSources,
   payload: dataSources,
@@ -86,6 +92,11 @@ export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSe
   payload: query,
 });
 
+export const setDataSourceName = (name: string) => ({
+  type: ActionTypes.SetDataSourceName,
+  payload: name,
+});
+
 export type Action =
   | LoadDataSourcesAction
   | SetDataSourcesSearchQueryAction
@@ -95,7 +106,8 @@ export type Action =
   | SetDataSourceTypeSearchQueryAction
   | LoadDataSourceAction
   | UpdateNavIndexAction
-  | LoadDataSourceMetaAction;
+  | LoadDataSourceMetaAction
+  | SetDataSourceNameAction;
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 

+ 1 - 1
public/app/features/datasources/state/selectors.ts

@@ -20,7 +20,7 @@ export const getDataSource = (state, dataSourceId): DataSource | null => {
   if (state.dataSource.id === parseInt(dataSourceId, 10)) {
     return state.dataSource;
   }
-  return null;
+  return {} as DataSource;
 };
 
 export const getDataSourcesSearchQuery = state => state.searchQuery;

+ 1 - 1
scripts/webpack/webpack.hot.js

@@ -47,7 +47,7 @@ module.exports = merge(common, {
   module: {
     rules: [
       {
-        test: /\.tsx?$/,
+        test: /(?!.*\.test)\.tsx$/,
         exclude: /node_modules/,
         use: [{
           loader: 'babel-loader',