diff --git a/rd_ui/app/scripts/controllers/query_view.js b/rd_ui/app/scripts/controllers/query_view.js index 93e8c2ea08..63a7379772 100644 --- a/rd_ui/app/scripts/controllers/query_view.js +++ b/rd_ui/app/scripts/controllers/query_view.js @@ -168,6 +168,8 @@ return; } + $scope.filters = $scope.queryResult.getFilters(); + if ($scope.queryResult.getId() == null) { $scope.dataUri = ""; } else { diff --git a/rd_ui/app/scripts/ng_highchart.js b/rd_ui/app/scripts/ng_highchart.js index 9bbc2b1ee0..8aed056e73 100644 --- a/rd_ui/app/scripts/ng_highchart.js +++ b/rd_ui/app/scripts/ng_highchart.js @@ -181,17 +181,13 @@ }, true); //Update when charts data changes - scope.$watch(function () { - // TODO: this might be an issue in case the series change, but they stay - // with the same length - return (scope.series && scope.series.length) || 0; - }, function (length) { - if (!length || length == 0) { + scope.$watchCollection('series', function (series) { + if (!series || series.length == 0) { scope.chart.showLoading(); } else { drawChart(); }; - }, true); + }); }); function initChart(options) { diff --git a/rd_ui/app/scripts/services/services.js b/rd_ui/app/scripts/services/services.js index 9a4f5d870d..8d95659a48 100644 --- a/rd_ui/app/scripts/services/services.js +++ b/rd_ui/app/scripts/services/services.js @@ -7,6 +7,8 @@ angular.extend(this, props); if ('query_result' in props) { this.status = "done"; + this.filters = undefined; + this.filterFreeze = undefined; _.each(this.query_result.data.rows, function (row) { _.each(row, function (v, k) { @@ -26,6 +28,8 @@ this.job = {}; this.query_result = {}; this.status = "waiting"; + this.filters = undefined; + this.filterFreeze = undefined; this.updatedAt = moment(); @@ -76,15 +80,51 @@ return this.query_result.runtime; } - QueryResult.prototype.getData = function() { + QueryResult.prototype.getRawData = function() { if (!this.query_result.data) { return null; } var data = this.query_result.data.rows; + return data; } + QueryResult.prototype.getData = function() { + if (!this.query_result.data) { + return null; + } + + var filterValues = function(filters) { + if (!filters) { + return null; + } + + return _.reduce(filters, function(str, filter) { + return str + filter.current; + }, "") + } + + var filters = this.getFilters(); + var filterFreeze = filterValues(filters); + + if (this.filterFreeze != filterFreeze) { + this.filterFreeze = filterFreeze; + + if (filters) { + this.filteredData = _.filter(this.query_result.data.rows, function (row) { + return _.reduce(filters, function (memo, filter) { + return (memo && row[filter.name] == filter.current); + }, true); + }); + } else { + this.filteredData = this.query_result.data.rows; + } + } + + return this.filteredData; + } + QueryResult.prototype.getChartData = function () { var series = {}; @@ -181,6 +221,14 @@ } QueryResult.prototype.getFilters = function () { + if (!this.filters) { + this.prepareFilters(); + } + + return this.filters; + }; + + QueryResult.prototype.prepareFilters = function() { var filterNames = []; _.each(this.getColumns(), function (col) { if (col.split('::')[1] == 'filter') { @@ -189,7 +237,7 @@ }); var filterValues = []; - _.each(this.getData(), function (row) { + _.each(this.getRawData(), function (row) { _.each(filterNames, function (filter, i) { if (filterValues[i] == undefined) { filterValues[i] = []; @@ -198,7 +246,7 @@ }) }); - var filters = _.map(filterNames, function (filter, i) { + this.filters = _.map(filterNames, function (filter, i) { var f = { name: filter, friendlyName: this.getColumnFriendlyName(filter), @@ -208,9 +256,7 @@ f.current = f.values[0]; return f; }, this); - - return filters; - }; + } var refreshStatus = function(queryResult, query, ttl) { Job.get({'id': queryResult.job.id}, function(response) { diff --git a/rd_ui/app/scripts/visualizations/base.js b/rd_ui/app/scripts/visualizations/base.js index d940edbe04..5a0a34daf4 100644 --- a/rd_ui/app/scripts/visualizations/base.js +++ b/rd_ui/app/scripts/visualizations/base.js @@ -64,8 +64,11 @@ // TODO: using switch here (and in the options editor) might introduce errors and bad // performance wise. It's better to eventually show the correct template based on the // visualization type and not make the browser render all of them. - template: Visualization.renderVisualizationsTemplate, - replace: false + template: '\n' + Visualization.renderVisualizationsTemplate, + replace: false, + link: function(scope) { + scope.filters = scope.queryResult.getFilters(); + } } }; @@ -77,6 +80,13 @@ } }; + var Filters = function() { + return { + restrict: 'E', + templateUrl: '/views/visualizations/filters.html' + } + } + var EditVisualizationForm = function(Visualization, growl) { return { restrict: 'E', @@ -141,9 +151,12 @@ } }; + + angular.module('redash.visualization', []) .provider('Visualization', VisualizationProvider) .directive('visualizationRenderer', ['Visualization', VisualizationRenderer]) .directive('visualizationOptionsEditor', ['Visualization', VisualizationOptionsEditor]) + .directive('filters', Filters) .directive('editVisulatizationForm', ['Visualization', 'growl', EditVisualizationForm]) })(); diff --git a/rd_ui/app/scripts/visualizations/table.js b/rd_ui/app/scripts/visualizations/table.js index 5b5835e3cb..70dfd00055 100644 --- a/rd_ui/app/scripts/visualizations/table.js +++ b/rd_ui/app/scripts/visualizations/table.js @@ -38,17 +38,21 @@ $scope.gridData = []; $scope.filters = []; } else { + $scope.filters = $scope.queryResult.getFilters(); + var prepareGridData = function(data) { + var gridData = _.map(data, function (row) { + var newRow = {}; + _.each(row, function (val, key) { + newRow[$scope.queryResult.getColumnCleanName(key)] = val; + }) + return newRow; + }); - $scope.filters = $scope.queryResult.getFilters(); + return gridData; + }; - var gridData = _.map($scope.queryResult.getData(), function (row) { - var newRow = {}; - _.each(row, function (val, key) { - newRow[$scope.queryResult.getColumnCleanName(key)] = val; - }) - return newRow; - }); + $scope.gridData = prepareGridData($scope.queryResult.getData()); $scope.gridColumns = _.map($scope.queryResult.getColumnCleanNames(), function (col, i) { var columnDefinition = { @@ -56,8 +60,10 @@ 'map': col }; - if (gridData.length > 0) { - var exampleData = gridData[0][col]; + var rawData = $scope.queryResult.getRawData(); + + if (rawData.length > 0) { + var exampleData = rawData[0][col]; if (angular.isNumber(exampleData)) { columnDefinition['formatFunction'] = 'number'; columnDefinition['formatParameter'] = 2; @@ -76,20 +82,6 @@ return columnDefinition; }); - - $scope.gridData = _.clone(gridData); - - $scope.$watch('filters', function (filters) { - $scope.gridData = _.filter(gridData, function (row) { - return _.reduce(filters, function (memo, filter) { - if (filter.current == 'All') { - return memo && true; - } - - return (memo && row[$scope.queryResult.getColumnCleanName(filter.name)] == filter.current); - }, true); - }); - }, true); } }); }] diff --git a/rd_ui/app/views/grid_renderer.html b/rd_ui/app/views/grid_renderer.html index 3524c8338e..148e9c8f5b 100644 --- a/rd_ui/app/views/grid_renderer.html +++ b/rd_ui/app/views/grid_renderer.html @@ -1,17 +1,4 @@
-
- - -
- diff --git a/rd_ui/app/views/queryview.html b/rd_ui/app/views/queryview.html index db0b90abca..0e584b24be 100644 --- a/rd_ui/app/views/queryview.html +++ b/rd_ui/app/views/queryview.html @@ -150,7 +150,11 @@

- +
+ + +
+
diff --git a/rd_ui/app/views/visualizations/filters.html b/rd_ui/app/views/visualizations/filters.html new file mode 100644 index 0000000000..3d718a944d --- /dev/null +++ b/rd_ui/app/views/visualizations/filters.html @@ -0,0 +1,12 @@ +
+
+ + +
+
\ No newline at end of file