diff --git a/public/app/core/directives/dropdown_typeahead.js b/public/app/core/directives/dropdown_typeahead.js
index c306b9ff8e5..ad484bb18d7 100644
--- a/public/app/core/directives/dropdown_typeahead.js
+++ b/public/app/core/directives/dropdown_typeahead.js
@@ -45,16 +45,25 @@ function (_, $, coreModule) {
}
var typeaheadValues = _.reduce($scope.menuItems, function(memo, value, index) {
- _.each(value.submenu, function(item, subIndex) {
- item.click = 'menuItemSelected(' + index + ',' + subIndex + ')';
- memo.push(value.text + ' ' + item.text);
- });
+ if (!value.submenu) {
+ value.click = 'menuItemSelected(' + index + ')';
+ memo.push(value.text);
+ } else {
+ _.each(value.submenu, function(item, subIndex) {
+ item.click = 'menuItemSelected(' + index + ',' + subIndex + ')';
+ memo.push(value.text + ' ' + item.text);
+ });
+ }
return memo;
}, []);
$scope.menuItemSelected = function(index, subIndex) {
- var item = $scope.menuItems[index];
- $scope.dropdownTypeaheadOnSelect({$item: item, $subItem: item.submenu[subIndex]});
+ var menuItem = $scope.menuItems[index];
+ var payload = {$item: menuItem};
+ if (menuItem.submenu && subIndex !== void 0) {
+ payload.$subItem = menuItem.submenu[subIndex];
+ }
+ $scope.dropdownTypeaheadOnSelect(payload);
};
$input.attr('data-provide', 'typeahead');
@@ -65,9 +74,10 @@ function (_, $, coreModule) {
updater: function (value) {
var result = {};
_.each($scope.menuItems, function(menuItem) {
+ result.$item = menuItem;
+
_.each(menuItem.submenu, function(submenuItem) {
if (value === (menuItem.text + ' ' + submenuItem.text)) {
- result.$item = menuItem;
result.$subItem = submenuItem;
}
});
diff --git a/public/app/features/panel/panel_helper.js b/public/app/features/panel/panel_helper.js
index c3ccbfe7e09..52a6727eb2c 100644
--- a/public/app/features/panel/panel_helper.js
+++ b/public/app/features/panel/panel_helper.js
@@ -32,9 +32,9 @@ function (angular, _, $, kbn, dateMath, rangeUtil) {
scope.timing.renderEnd = new Date().getTime();
};
- this.broadcastRender = function(scope, data) {
+ this.broadcastRender = function(scope, arg1, arg2) {
this.setTimeRenderStart(scope);
- scope.$broadcast('render', data);
+ scope.$broadcast('render', arg1, arg2);
this.setTimeRenderEnd(scope);
if ($rootScope.profilingEnabled) {
diff --git a/public/app/panels/table/controller.ts b/public/app/panels/table/controller.ts
index 4ae5a1807fa..7c22ba2823f 100644
--- a/public/app/panels/table/controller.ts
+++ b/public/app/panels/table/controller.ts
@@ -3,24 +3,15 @@
import angular = require('angular');
import _ = require('lodash');
import moment = require('moment');
-import kbn = require('app/core/utils/kbn');
import PanelMeta = require('app/features/panel/panel_meta');
import {TableModel} from './table_model';
-import {transformers} from './transformers';
export class TablePanelCtrl {
constructor($scope, $rootScope, $q, panelSrv, panelHelper) {
$scope.ctrl = this;
- $scope.transformers = transformers;
$scope.pageIndex = 0;
- $scope.unitFormats = kbn.getUnitFormats();
- $scope.colorModes = {
- 'cell': {text: 'Cell'},
- 'value': {text: 'Value'},
- 'row': {text: 'Row'},
- };
$scope.panelMeta = new PanelMeta({
panelName: 'Table',
@@ -38,23 +29,18 @@ export class TablePanelCtrl {
pageSize: 50,
showHeader: true,
columns: [],
+ fields: []
};
$scope.init = function() {
_.defaults($scope.panel, panelDefaults);
if ($scope.panel.columns.length === 0) {
- $scope.addColumnStyle();
}
panelSrv.init($scope);
};
- $scope.setUnitFormat = function(column, subItem) {
- column.unit = subItem.value;
- $scope.render();
- };
-
$scope.refreshData = function(datasource) {
panelHelper.updateTimeRange($scope);
@@ -73,32 +59,7 @@ export class TablePanelCtrl {
$scope.render = function() {
$scope.table = TableModel.transform($scope.dataRaw, $scope.panel);
- panelHelper.broadcastRender($scope, $scope.table);
- };
-
- $scope.getColumnNames = function() {
- if (!$scope.table) {
- return [];
- }
- return _.map($scope.table.columns, function(col: any) {
- return col.text;
- });
- };
-
- $scope.addColumnStyle = function() {
- var columnStyleDefaults = {
- unit: 'short',
- decimals: 2,
- colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
- pattern: '/.*/',
- colorMode: 'value',
- };
-
- $scope.panel.columns.push(angular.copy(columnStyleDefaults));
- };
-
- $scope.removeColumnStyle = function(col) {
- $scope.panel.columns = _.without($scope.panel.columns, col);
+ panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw);
};
$scope.init();
diff --git a/public/app/panels/table/editor.html b/public/app/panels/table/editor.html
new file mode 100644
index 00000000000..e7c76402974
--- /dev/null
+++ b/public/app/panels/table/editor.html
@@ -0,0 +1,167 @@
+
+
+
+
Column Styles
+
+
+
+
+
+
diff --git a/public/app/panels/table/editor.ts b/public/app/panels/table/editor.ts
new file mode 100644
index 00000000000..4cd4070dd1b
--- /dev/null
+++ b/public/app/panels/table/editor.ts
@@ -0,0 +1,106 @@
+
+///
+
+import angular = require('angular');
+import $ = require('jquery');
+import _ = require('lodash');
+import kbn = require('app/core/utils/kbn');
+import moment = require('moment');
+
+import {transformers} from './transformers';
+
+export function tablePanelEditor() {
+ 'use strict';
+ return {
+ restrict: 'E',
+ scope: true,
+ templateUrl: 'app/panels/table/editor.html',
+ link: function(scope, elem) {
+ scope.transformers = transformers;
+ scope.unitFormats = kbn.getUnitFormats();
+ scope.colorModes = {
+ 'cell': {text: 'Cell'},
+ 'value': {text: 'Value'},
+ 'row': {text: 'Row'},
+ };
+ scope.columnTypes = {
+ 'number': {text: 'Number'},
+ 'string': {text: 'String'},
+ 'date': {text: 'Date'},
+ };
+
+ scope.updateJsonFieldsMenu = function(data) {
+ scope.jsonFieldsMenu = [];
+ if (!data || data.length === 0) {
+ return;
+ }
+
+ var names = {};
+ for (var i = 0; i < data.length; i++) {
+ var series = data[i];
+ if (series.type !== 'docs') {
+ continue;
+ }
+
+ for (var y = 0; y < series.datapoints.length; y++) {
+ var doc = series.datapoints[y];
+ for (var propName in doc) {
+ names[propName] = true;
+ }
+ }
+ }
+
+ _.each(names, function(value, key) {
+ scope.jsonFieldsMenu.push({text: key});
+ });
+ };
+
+ scope.updateJsonFieldsMenu(scope.dataRaw);
+
+ scope.$on('render', function(event, table, rawData) {
+ scope.updateJsonFieldsMenu(rawData);
+ });
+
+ scope.addJsonField = function(menuItem) {
+ scope.panel.fields.push({name: menuItem.text});
+ };
+
+ scope.removeJsonField = function(field) {
+ scope.panel.fields = _.without(scope.panel.fields, field);
+ };
+
+ scope.setUnitFormat = function(column, subItem) {
+ column.unit = subItem.value;
+ scope.render();
+ };
+
+ scope.addColumnStyle = function() {
+ var columnStyleDefaults = {
+ unit: 'short',
+ type: 'number',
+ decimals: 2,
+ colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
+ colorMode: 'value',
+ pattern: '/.*/',
+ };
+
+ scope.panel.columns.push(angular.copy(columnStyleDefaults));
+ };
+
+ scope.removeColumnStyle = function(col) {
+ scope.panel.columns = _.without(scope.panel.columns, col);
+ };
+
+ scope.getColumnNames = function() {
+ if (!scope.table) {
+ return [];
+ }
+ return _.map(scope.table.columns, function(col: any) {
+ return col.text;
+ });
+ };
+
+ }
+ };
+}
+
diff --git a/public/app/panels/table/module.ts b/public/app/panels/table/module.ts
index 39cd1056290..84955070be4 100644
--- a/public/app/panels/table/module.ts
+++ b/public/app/panels/table/module.ts
@@ -4,10 +4,12 @@ import angular = require('angular');
import $ = require('jquery');
import _ = require('lodash');
import kbn = require('app/core/utils/kbn');
+import moment = require('moment');
import {TablePanelCtrl} from './controller';
+import {tablePanelEditor} from './editor';
-export function tablePanelDirective() {
+export function tablePanel() {
'use strict';
return {
restrict: 'E',
@@ -45,9 +47,13 @@ export function tablePanelDirective() {
if (v === null || v === void 0) {
return '-';
}
- if (_.isString(v) || style) {
+ if (_.isString(v) || !style) {
return v;
}
+ if (style.type === 'date') {
+ var date = moment(v);
+ return date.format(style.dateFormat);
+ }
let valueFormater = kbn.valueFormats[style.unit];
return valueFormater(v, style.decimals);
};
@@ -136,4 +142,5 @@ export function tablePanelDirective() {
};
}
-angular.module('grafana.directives').directive('grafanaPanelTable', tablePanelDirective);
+angular.module('grafana.directives').directive('grafanaPanelTable', tablePanel);
+angular.module('grafana.directives').directive('grafanaPanelTableEditor', tablePanelEditor);
diff --git a/public/app/panels/table/options.html b/public/app/panels/table/options.html
index c1d4ca658ac..d43ff958c5d 100644
--- a/public/app/panels/table/options.html
+++ b/public/app/panels/table/options.html
@@ -1,117 +1,2 @@
-
-
-
-
Column Styles
-
-
-
-
-
-
+
+
diff --git a/public/app/panels/table/specs/transformers_specs.ts b/public/app/panels/table/specs/transformers_specs.ts
index ea3eb609976..af9dd880cf1 100644
--- a/public/app/panels/table/specs/transformers_specs.ts
+++ b/public/app/panels/table/specs/transformers_specs.ts
@@ -67,6 +67,41 @@ describe('when transforming time series table', () => {
expect(table.rows[1][2]).to.be(undefined);
});
});
+
+ describe('JSON Data', () => {
+ var panel = {
+ transform: 'json',
+ fields: [{name: 'timestamp'}, {name: 'message'}]
+ };
+ var rawData = [
+ {
+ type: 'docs',
+ datapoints: [
+ {
+ timestamp: 'time',
+ message: 'message'
+ }
+ ]
+ }
+ ];
+
+ beforeEach(() => {
+ table = TableModel.transform(rawData, panel);
+ });
+
+ it ('should return 2 columns', () => {
+ expect(table.columns.length).to.be(2);
+ expect(table.columns[0].text).to.be('timestamp');
+ expect(table.columns[1].text).to.be('message');
+ });
+
+ it ('should return 2 rows', () => {
+ expect(table.rows.length).to.be(2);
+ expect(table.rows[0][0]).to.be('time');
+ expect(table.rows[0][1]).to.be('message');
+ });
+
+ });
});
});
diff --git a/public/app/panels/table/transformers.ts b/public/app/panels/table/transformers.ts
index 42ccae1982e..096ebb73051 100644
--- a/public/app/panels/table/transformers.ts
+++ b/public/app/panels/table/transformers.ts
@@ -9,7 +9,7 @@ transformers['timeseries_to_rows'] = {
description: 'Time series to rows',
transform: function(data, panel, model) {
model.columns = [
- {text: 'Time'},
+ {text: 'Time', type: 'date'},
{text: 'Series'},
{text: 'Value'},
];
@@ -18,9 +18,7 @@ transformers['timeseries_to_rows'] = {
var series = data[i];
for (var y = 0; y < series.datapoints.length; y++) {
var dp = series.datapoints[y];
- var time = moment(dp[1]).format('LLL');
- var value = dp[0];
- model.rows.push([time, series.target, value]);
+ model.rows.push([dp[1], series.target, dp[0]]);
}
}
},
@@ -29,7 +27,7 @@ transformers['timeseries_to_rows'] = {
transformers['timeseries_to_columns'] = {
description: 'Time series to columns',
transform: function(data, panel, model) {
- model.columns.push({text: 'Time'});
+ model.columns.push({text: 'Time', type: 'date'});
// group by time
var points = {};
@@ -54,7 +52,7 @@ transformers['timeseries_to_columns'] = {
for (var time in points) {
var point = points[time];
- var values = [moment(point.time).format('LLL')];
+ var values = [point.time];
for (var i = 0; i < data.length; i++) {
var value = point[i];
@@ -71,17 +69,31 @@ transformers['annotations'] = {
};
transformers['json'] = {
- description: 'JSON',
+ description: 'JSON Data',
transform: function(data, panel, model) {
- model.columns.push({text: 'JSON'});
- debugger;
+ var i, y, z;
+ for (i = 0; i < panel.fields.length; i++) {
+ model.columns.push({text: panel.fields[i].name});
+ }
- for (var i = 0; i < data.length; i++) {
+ if (model.columns.length === 0) {
+ model.columns.push({text: 'JSON'});
+ }
+
+ for (i = 0; i < data.length; i++) {
var series = data[i];
- for (var y = 0; y < series.datapoints.length; y++) {
+ for (y = 0; y < series.datapoints.length; y++) {
var dp = series.datapoints[y];
- model.rows.push([JSON.stringify(dp)]);
+ var values = [];
+ for (z = 0; z < panel.fields.length; z++) {
+ values.push(dp[panel.fields[z].name]);
+ }
+
+ if (values.length === 0) {
+ values.push([JSON.stringify(dp)]);
+ }
+ model.rows.push(values);
}
}
}