Sfoglia il codice sorgente

Merge branch 'master' of github.com:grafana/grafana

Torkel Ödegaard 7 anni fa
parent
commit
5c95a01229

+ 3 - 1
CHANGELOG.md

@@ -2,9 +2,10 @@
 
 ### New Features
 
+* **Alerting**: Option to disable OK alert notifications [#12330](https://github.com/grafana/grafana/issues/12330) & [#6696](https://github.com/grafana/grafana/issues/6696), thx [@davewat](https://github.com/davewat)
 * **Postgres/MySQL/MSSQL**: Adds support for configuration of max open/idle connections and connection max lifetime. Also, panels with multiple SQL queries will now be executed concurrently [#11711](https://github.com/grafana/grafana/issues/11711), thx [@connection-reset](https://github.com/connection-reset)
 * **MSSQL**: Add encrypt setting to allow configuration of how data sent between client and server are encrypted [#13629](https://github.com/grafana/grafana/issues/13629), thx [@ramiro](https://github.com/ramiro)
-* **Alerting**: Option to disable OK alert notifications [#12330](https://github.com/grafana/grafana/issues/12330) & [#6696](https://github.com/grafana/grafana/issues/6696), thx [@davewat](https://github.com/davewat)
+* **MySQL**: Support connecting thru Unix socket for MySQL datasource [#12342](https://github.com/grafana/grafana/issues/12342), thx [@Yukinoshita-Yukino](https://github.com/Yukinoshita-Yukino)
 
 ### Minor
 
@@ -19,6 +20,7 @@
 # 5.3.2 (unreleased)
 
 * **Postgres**: Fix template variables error [#13692](https://github.com/grafana/grafana/issues/13692), thx [@svenklemm](https://github.com/svenklemm)
+* **Cloudwatch**: Fix service panic because of race conditions [#13674](https://github.com/grafana/grafana/issues/13674), thx [@mtanda](https://github.com/mtanda)
 
 # 5.3.1 (2018-10-16)
 

+ 14 - 14
README.md

@@ -69,15 +69,27 @@ bra run
 
 Open grafana in your browser (default: `http://localhost:3000`) and login with admin user (default: `user/pass = admin/admin`).
 
-### Building a docker image (on linux/amd64)
+### Building a Docker image
 
-This builds a docker image from your local sources:
+There are two different ways to build a Grafana docker image. If you're machine is setup for Grafana development and you run linux/amd64 you can build just the image. Otherwise, there is the option to build Grafana completely within Docker.
+
+Run the image you have built using: `docker run --rm -p 3000:3000 grafana/grafana:dev`
+
+#### Building on linux/amd64 (fast)
 
 1. Build the frontend `go run build.go build-frontend`
 2. Build the docker image `make build-docker-dev`
 
 The resulting image will be tagged as `grafana/grafana:dev`
 
+#### Building anywhere (slower)
+
+Choose this option to build on platforms other than linux/amd64 and/or not have to setup the Grafana development environment.
+
+1. `make build-docker-full` or `docker build -t grafana/grafana:dev .`
+
+The resulting image will be tagged as `grafana/grafana:dev`
+
 ### Dev config
 
 Create a custom.ini in the conf directory to override default configuration options.
@@ -113,18 +125,6 @@ GRAFANA_TEST_DB=mysql go test ./pkg/...
 GRAFANA_TEST_DB=postgres go test ./pkg/...
 ```
 
-## Building custom docker image
-
-You can build a custom image using Docker, which doesn't require installing any dependencies besides docker itself.
-```bash
-git clone https://github.com/grafana/grafana
-cd grafana
-docker build -t grafana:dev .
-docker run -d --name=grafana -p 3000:3000 grafana:dev
-```
-
-Open grafana in your browser (default: `http://localhost:3000`) and login with admin user (default: `user/pass = admin/admin`).
-
 ## Contribute
 
 If you have any idea for an improvement or found a bug, do not hesitate to open an issue.

+ 1 - 0
package.json

@@ -160,6 +160,7 @@
     "react-redux": "^5.0.7",
     "react-select": "2.1.0",
     "react-sizeme": "^2.3.6",
+    "react-table": "^6.8.6",
     "react-transition-group": "^2.2.1",
     "redux": "^4.0.0",
     "redux-logger": "^3.0.6",

+ 3 - 1
pkg/login/ldap.go

@@ -185,7 +185,9 @@ func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo
 
 		if ldapUser.isMemberOf(group.GroupDN) {
 			extUser.OrgRoles[group.OrgId] = group.OrgRole
-			extUser.IsGrafanaAdmin = group.IsGrafanaAdmin
+			if extUser.IsGrafanaAdmin == nil || *extUser.IsGrafanaAdmin == false {
+				extUser.IsGrafanaAdmin = group.IsGrafanaAdmin
+			}
 		}
 	}
 

+ 16 - 10
pkg/tsdb/cloudwatch/cloudwatch.go

@@ -86,9 +86,10 @@ func (e *CloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSourc
 }
 
 func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
-	result := &tsdb.Response{
+	results := &tsdb.Response{
 		Results: make(map[string]*tsdb.QueryResult),
 	}
+	resultChan := make(chan *tsdb.QueryResult, len(queryContext.Queries))
 
 	eg, ectx := errgroup.WithContext(ctx)
 
@@ -102,10 +103,10 @@ func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
 		RefId := queryContext.Queries[i].RefId
 		query, err := parseQuery(queryContext.Queries[i].Model)
 		if err != nil {
-			result.Results[RefId] = &tsdb.QueryResult{
+			results.Results[RefId] = &tsdb.QueryResult{
 				Error: err,
 			}
-			return result, nil
+			return results, nil
 		}
 		query.RefId = RefId
 
@@ -118,10 +119,10 @@ func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
 		}
 
 		if query.Id == "" && query.Expression != "" {
-			result.Results[query.RefId] = &tsdb.QueryResult{
+			results.Results[query.RefId] = &tsdb.QueryResult{
 				Error: fmt.Errorf("Invalid query: id should be set if using expression"),
 			}
-			return result, nil
+			return results, nil
 		}
 
 		eg.Go(func() error {
@@ -130,12 +131,13 @@ func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
 				return err
 			}
 			if err != nil {
-				result.Results[query.RefId] = &tsdb.QueryResult{
+				resultChan <- &tsdb.QueryResult{
+					RefId: query.RefId,
 					Error: err,
 				}
 				return nil
 			}
-			result.Results[queryRes.RefId] = queryRes
+			resultChan <- queryRes
 			return nil
 		})
 	}
@@ -149,10 +151,10 @@ func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
 					return err
 				}
 				for _, queryRes := range queryResponses {
-					result.Results[queryRes.RefId] = queryRes
 					if err != nil {
-						result.Results[queryRes.RefId].Error = err
+						queryRes.Error = err
 					}
+					resultChan <- queryRes
 				}
 				return nil
 			})
@@ -162,8 +164,12 @@ func (e *CloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
 	if err := eg.Wait(); err != nil {
 		return nil, err
 	}
+	close(resultChan)
+	for result := range resultChan {
+		results.Results[result.RefId] = result
+	}
 
-	return result, nil
+	return results, nil
 }
 
 func (e *CloudWatchExecutor) executeQuery(ctx context.Context, query *CloudWatchQuery, queryContext *tsdb.TsdbQuery) (*tsdb.QueryResult, error) {

+ 6 - 1
pkg/tsdb/mysql/mysql.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"reflect"
 	"strconv"
+	"strings"
 
 	"github.com/go-sql-driver/mysql"
 	"github.com/go-xorm/core"
@@ -20,10 +21,14 @@ func init() {
 func newMysqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
 	logger := log.New("tsdb.mysql")
 
+	protocol := "tcp"
+	if strings.HasPrefix(datasource.Url, "/") {
+		protocol = "unix"
+	}
 	cnnstr := fmt.Sprintf("%s:%s@%s(%s)/%s?collation=utf8mb4_unicode_ci&parseTime=true&loc=UTC&allowNativePasswords=true",
 		datasource.User,
 		datasource.Password,
-		"tcp",
+		protocol,
 		datasource.Url,
 		datasource.Database,
 	)

+ 3 - 1
public/app/features/explore/Explore.tsx

@@ -644,7 +644,9 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
                   />
                 )}
               {supportsTable && showingTable ? (
-                <Table className="m-t-3" data={tableResult} loading={loading} onClickCell={this.onClickTableCell} />
+                <div className="panel-container">
+                  <Table data={tableResult} loading={loading} onClickCell={this.onClickTableCell} />
+                </div>
               ) : null}
               {supportsLogs && showingLogs ? <Logs data={logsResult} loading={loading} /> : null}
             </main>

+ 34 - 63
public/app/features/explore/Table.tsx

@@ -1,84 +1,55 @@
+import _ from 'lodash';
 import React, { PureComponent } from 'react';
+import ReactTable from 'react-table';
+
 import TableModel from 'app/core/table_model';
 
 const EMPTY_TABLE = new TableModel();
 
 interface TableProps {
-  className?: string;
   data: TableModel;
   loading: boolean;
   onClickCell?: (columnKey: string, rowValue: string) => void;
 }
 
-interface SFCCellProps {
-  columnIndex: number;
-  onClickCell?: (columnKey: string, rowValue: string, columnIndex: number, rowIndex: number, table: TableModel) => void;
-  rowIndex: number;
-  table: TableModel;
-  value: string;
+function prepareRows(rows, columnNames) {
+  return rows.map(cells => _.zipObject(columnNames, cells));
 }
 
-function Cell(props: SFCCellProps) {
-  const { columnIndex, rowIndex, table, value, onClickCell } = props;
-  const column = table.columns[columnIndex];
-  if (column && column.filterable && onClickCell) {
-    const onClick = event => {
-      event.preventDefault();
-      onClickCell(column.text, value, columnIndex, rowIndex, table);
+export default class Table extends PureComponent<TableProps> {
+  getCellProps = (state, rowInfo, column) => {
+    return {
+      onClick: () => {
+        const columnKey = column.Header;
+        const rowValue = rowInfo.row[columnKey];
+        this.props.onClickCell(columnKey, rowValue);
+      },
     };
-    return (
-      <td>
-        <a className="link" onClick={onClick}>
-          {value}
-        </a>
-      </td>
-    );
-  }
-  return <td>{value}</td>;
-}
+  };
 
-export default class Table extends PureComponent<TableProps, {}> {
   render() {
-    const { className = '', data, loading, onClickCell } = this.props;
+    const { data, loading } = this.props;
     const tableModel = data || EMPTY_TABLE;
-    if (!loading && data && data.rows.length === 0) {
-      return (
-        <table className={`${className} filter-table`}>
-          <thead>
-            <tr>
-              <th>Table</th>
-            </tr>
-          </thead>
-          <tbody>
-            <tr>
-              <td className="muted">The queries returned no data for a table.</td>
-            </tr>
-          </tbody>
-        </table>
-      );
-    }
+    const columnNames = tableModel.columns.map(({ text }) => text);
+    const columns = tableModel.columns.map(({ filterable, text }) => ({
+      Header: text,
+      accessor: text,
+      show: text !== 'Time',
+      Cell: row => <span className={filterable ? 'link' : ''}>{row.value}</span>,
+    }));
+    const noDataText = data ? 'The queries returned no data for a table.' : '';
+
     return (
-      <table className={`${className} filter-table`}>
-        <thead>
-          <tr>{tableModel.columns.map(col => <th key={col.text}>{col.text}</th>)}</tr>
-        </thead>
-        <tbody>
-          {tableModel.rows.map((row, i) => (
-            <tr key={i}>
-              {row.map((value, j) => (
-                <Cell
-                  key={j}
-                  columnIndex={j}
-                  rowIndex={i}
-                  value={String(value)}
-                  table={data}
-                  onClickCell={onClickCell}
-                />
-              ))}
-            </tr>
-          ))}
-        </tbody>
-      </table>
+      <ReactTable
+        columns={columns}
+        data={tableModel.rows}
+        getTdProps={this.getCellProps}
+        loading={loading}
+        minRows={0}
+        noDataText={noDataText}
+        resolveData={data => prepareRows(data, columnNames)}
+        showPagination={data}
+      />
     );
   }
 }

+ 4 - 1
public/sass/_grafana.scss

@@ -1,4 +1,7 @@
-// vendor
+// DEPENDENCIES
+@import '../../node_modules/react-table/react-table.css';
+
+// VENDOR
 @import '../vendor/css/timepicker.css';
 @import '../vendor/css/spectrum.css';
 @import '../vendor/css/rc-cascader.scss';

+ 1 - 0
public/sass/components/_slate_editor.scss

@@ -2,6 +2,7 @@
   font-size: $font-size-root;
   font-family: $font-family-monospace;
   height: auto;
+  word-break: break-word;
 }
 
 .slate-query-field-wrapper {

+ 58 - 1
public/sass/pages/_explore.scss

@@ -126,7 +126,7 @@
 }
 
 .query-row-tools {
-  width: 6rem;
+  white-space: nowrap;
 }
 
 .query-row-field {
@@ -186,3 +186,60 @@
     margin: 0.25em 0.5em 0.5em;
   }
 }
+
+// ReactTable basic overrides (does not include pivot/groups/filters)
+// When integrating ReactTable as new panel plugin, move to _panel_table.scss
+
+.ReactTable {
+  border: none;
+  // Allow some space for the no-data text
+  min-height: 120px;
+}
+
+.ReactTable .rt-thead.-header {
+  box-shadow: none;
+  background: $list-item-bg;
+  border-top: 2px solid $body-bg;
+  border-bottom: 2px solid $body-bg;
+  height: 2em;
+}
+.ReactTable .rt-thead.-header .rt-th {
+  text-align: left;
+  color: $blue;
+  font-weight: 500;
+}
+.ReactTable .rt-thead .rt-td,
+.ReactTable .rt-thead .rt-th {
+  padding: 0.45em 0 0.45em 1.1em;
+  border-right: none;
+  box-shadow: none;
+}
+.ReactTable .rt-tbody .rt-td {
+  padding: 0.45em 0 0.45em 1.1em;
+  border-bottom: 2px solid $body-bg;
+  border-right: 2px solid $body-bg;
+}
+.ReactTable .rt-tbody .rt-td:last-child {
+  border-right: none;
+}
+.ReactTable .-pagination .-btn {
+  color: $blue;
+  background: $list-item-bg;
+}
+.ReactTable .-pagination input,
+.ReactTable .-pagination select {
+  color: $input-color;
+  background-color: $input-bg;
+}
+.ReactTable .-loading {
+  background: $input-bg;
+}
+.ReactTable .-loading.-active {
+  opacity: 0.8;
+}
+.ReactTable .-loading > div {
+  color: $input-color;
+}
+.ReactTable .rt-tr .rt-td:last-child {
+  text-align: right;
+}

File diff suppressed because it is too large
+ 0 - 176
yarn.lock


Some files were not shown because too many files changed in this diff