mirror of
https://github.com/getredash/redash.git
synced 2025-12-21 18:35:48 -05:00
rd_ui: sync filters with location.search [closes #146]
This commit is contained in:
@@ -55,7 +55,7 @@
|
|||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
|
||||||
var VisualizationRenderer = function (Visualization) {
|
var VisualizationRenderer = function ($location, Visualization) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
scope: {
|
scope: {
|
||||||
@@ -68,12 +68,47 @@
|
|||||||
template: '<filters></filters>\n' + Visualization.renderVisualizationsTemplate,
|
template: '<filters></filters>\n' + Visualization.renderVisualizationsTemplate,
|
||||||
replace: false,
|
replace: false,
|
||||||
link: function (scope) {
|
link: function (scope) {
|
||||||
|
|
||||||
scope.select2Options = {
|
scope.select2Options = {
|
||||||
width: '50%'
|
width: '50%'
|
||||||
|
};
|
||||||
|
|
||||||
|
function readURL() {
|
||||||
|
var searchFilters = angular.fromJson($location.search().filters);
|
||||||
|
if (searchFilters) {
|
||||||
|
_.forEach(scope.filters, function(filter) {
|
||||||
|
var value = searchFilters[filter.friendlyName];
|
||||||
|
if (value) {
|
||||||
|
filter.current = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateURL(filters) {
|
||||||
|
var current = {};
|
||||||
|
_.each(filters, function(filter) {
|
||||||
|
if (filter.current) {
|
||||||
|
current[filter.friendlyName] = filter.current;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var newSearch = angular.extend($location.search(), {
|
||||||
|
filters: angular.toJson(current)
|
||||||
|
});
|
||||||
|
$location.search(newSearch);
|
||||||
|
}
|
||||||
|
|
||||||
scope.$watch('queryResult && queryResult.getFilters()', function (filters) {
|
scope.$watch('queryResult && queryResult.getFilters()', function (filters) {
|
||||||
if (filters) {
|
if (filters) {
|
||||||
scope.filters = filters;
|
scope.filters = filters;
|
||||||
|
|
||||||
|
if (filters.length) {
|
||||||
|
readURL();
|
||||||
|
|
||||||
|
// start watching for changes and update URL
|
||||||
|
scope.$watch('filters', updateURL, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -172,7 +207,7 @@
|
|||||||
|
|
||||||
angular.module('redash.visualization', [])
|
angular.module('redash.visualization', [])
|
||||||
.provider('Visualization', VisualizationProvider)
|
.provider('Visualization', VisualizationProvider)
|
||||||
.directive('visualizationRenderer', ['Visualization', VisualizationRenderer])
|
.directive('visualizationRenderer', ['$location', 'Visualization', VisualizationRenderer])
|
||||||
.directive('visualizationOptionsEditor', ['Visualization', VisualizationOptionsEditor])
|
.directive('visualizationOptionsEditor', ['Visualization', VisualizationOptionsEditor])
|
||||||
.directive('filters', Filters)
|
.directive('filters', Filters)
|
||||||
.directive('editVisulatizationForm', ['Events', 'Visualization', 'growl', EditVisualizationForm])
|
.directive('editVisulatizationForm', ['Events', 'Visualization', 'growl', EditVisualizationForm])
|
||||||
|
|||||||
@@ -171,7 +171,7 @@
|
|||||||
<edit-visulatization-form visualization="vis" query="query" query-result="queryResult" ng-show="canEdit"></edit-visulatization-form>
|
<edit-visulatization-form visualization="vis" query="query" query-result="queryResult" ng-show="canEdit"></edit-visulatization-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-show="selectedTab == 'add'">
|
<div ng-if="canEdit" ng-show="selectedTab == 'add'">
|
||||||
<visualization-renderer visualization="newVisualization" query-result="queryResult"></visualization-renderer>
|
<visualization-renderer visualization="newVisualization" query-result="queryResult"></visualization-renderer>
|
||||||
<edit-visulatization-form visualization="newVisualization" query="query" query-result="queryResult" ng-show="canEdit" open-editor="true" on-new-success="setVisualizationTab"></edit-visulatization-form>
|
<edit-visulatization-form visualization="newVisualization" query="query" query-result="queryResult" ng-show="canEdit" open-editor="true" on-new-success="setVisualizationTab"></edit-visulatization-form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
"karma-jasmine": "~0.1.5",
|
"karma-jasmine": "~0.1.5",
|
||||||
"grunt-karma": "~0.8.3",
|
"grunt-karma": "~0.8.3",
|
||||||
"karma-phantomjs-launcher": "~0.1.4",
|
"karma-phantomjs-launcher": "~0.1.4",
|
||||||
"karma": "~0.12.19"
|
"karma": "~0.12.19",
|
||||||
|
"karma-ng-html2js-preprocessor": "~0.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|||||||
@@ -75,10 +75,17 @@ module.exports = function(config) {
|
|||||||
'app/scripts/directives/dashboard_directives.js',
|
'app/scripts/directives/dashboard_directives.js',
|
||||||
'app/scripts/filters.js',
|
'app/scripts/filters.js',
|
||||||
|
|
||||||
|
'app/views/**/*.html',
|
||||||
|
|
||||||
'test/mocks/*.js',
|
'test/mocks/*.js',
|
||||||
'test/unit/*.js'
|
'test/unit/*.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// generate js files from html templates
|
||||||
|
preprocessors: {
|
||||||
|
'app/views/**/*.html': 'ng-html2js'
|
||||||
|
},
|
||||||
|
|
||||||
// list of files / patterns to exclude
|
// list of files / patterns to exclude
|
||||||
exclude: [],
|
exclude: [],
|
||||||
|
|
||||||
@@ -100,7 +107,8 @@ module.exports = function(config) {
|
|||||||
// Which plugins to enable
|
// Which plugins to enable
|
||||||
plugins: [
|
plugins: [
|
||||||
'karma-phantomjs-launcher',
|
'karma-phantomjs-launcher',
|
||||||
'karma-jasmine'
|
'karma-jasmine',
|
||||||
|
'karma-ng-html2js-preprocessor'
|
||||||
],
|
],
|
||||||
|
|
||||||
// Continuous Integration mode
|
// Continuous Integration mode
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ currentUser = {
|
|||||||
|
|
||||||
|
|
||||||
angular.module('redashMocks', [])
|
angular.module('redashMocks', [])
|
||||||
.value('mockData', {
|
.value('MockData', {
|
||||||
query: {
|
query: {
|
||||||
|
|
||||||
"ttl": -1,
|
"ttl": -1,
|
||||||
"query": "select name from users;",
|
"query": "select name from users;",
|
||||||
"id": 1803,
|
"id": 1803,
|
||||||
@@ -72,5 +71,38 @@ angular.module('redashMocks', [])
|
|||||||
"data_source_id": 1
|
"data_source_id": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
queryResult: {
|
||||||
|
"job": {},
|
||||||
|
"query_result": {
|
||||||
|
"retrieved_at": "2014-08-04T13:33:45.563486+03:00",
|
||||||
|
"query_hash": "9951c38c9cf00e6ee8aecce026b51c19",
|
||||||
|
"query": "select name as \"name::filter\" from users",
|
||||||
|
"runtime": 0.00896096229553223,
|
||||||
|
"data": {
|
||||||
|
"rows": [],
|
||||||
|
"columns": [{
|
||||||
|
"friendly_name": "name::filter",
|
||||||
|
"type": null,
|
||||||
|
"name": "name::filter"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"id": 106673,
|
||||||
|
"data_source_id": 1
|
||||||
|
},
|
||||||
|
"status": "done",
|
||||||
|
"filters": [],
|
||||||
|
"filterFreeze": "test@example.com",
|
||||||
|
"updatedAt": "2014-08-05T13:13:40.833Z",
|
||||||
|
"columnNames": ["name::filter"],
|
||||||
|
"filteredData": [{
|
||||||
|
"name::filter": "test@example.com"
|
||||||
|
}],
|
||||||
|
"columns": [{
|
||||||
|
"friendly_name": "name::filter",
|
||||||
|
"type": null,
|
||||||
|
"name": "name::filter"
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
|
|
||||||
describe('QueryViewCtrl', function() {
|
describe('QueryViewCtrl', function() {
|
||||||
var scope;
|
var scope;
|
||||||
var mockData;
|
var MockData;
|
||||||
|
|
||||||
beforeEach(module('redash', 'redashMocks'));
|
beforeEach(module('redash', 'redashMocks'));
|
||||||
|
|
||||||
beforeEach(inject(function($injector, $controller, $rootScope, Query, _mockData_) {
|
beforeEach(inject(function($injector, $controller, $rootScope, Query, _MockData_) {
|
||||||
mockData = _mockData_;
|
MockData = _MockData_;
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
|
|
||||||
var route = {
|
var route = {
|
||||||
current: {
|
current: {
|
||||||
locals: {
|
locals: {
|
||||||
query: new Query(mockData.query)
|
query: new Query(MockData.query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
89
rd_ui/test/unit/test_visualization_renderer.js
Normal file
89
rd_ui/test/unit/test_visualization_renderer.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('VisualizationRenderer', function() {
|
||||||
|
var element;
|
||||||
|
var scope;
|
||||||
|
|
||||||
|
var filters = [{
|
||||||
|
"name": "name::filter",
|
||||||
|
"friendlyName": "Name",
|
||||||
|
"values": ["test@example.com", "amirn@example.com"],
|
||||||
|
"multiple": false
|
||||||
|
}];
|
||||||
|
|
||||||
|
beforeEach(module('redash', 'redashMocks'));
|
||||||
|
|
||||||
|
// loading templates
|
||||||
|
beforeEach(module('app/views/grid_renderer.html',
|
||||||
|
'app/views/visualizations/filters.html'));
|
||||||
|
|
||||||
|
// serving templates
|
||||||
|
beforeEach(inject(function($httpBackend, $templateCache) {
|
||||||
|
$httpBackend.whenGET('/views/grid_renderer.html')
|
||||||
|
.respond($templateCache.get('app/views/grid_renderer.html'));
|
||||||
|
|
||||||
|
$httpBackend.whenGET('/views/visualizations/filters.html')
|
||||||
|
.respond($templateCache.get('app/views/visualizations/filters.html'));
|
||||||
|
}));
|
||||||
|
|
||||||
|
// directive setup
|
||||||
|
beforeEach(inject(function($rootScope, $compile, MockData, QueryResult) {
|
||||||
|
var qr = new QueryResult(MockData.queryResult)
|
||||||
|
qr.filters = filters;
|
||||||
|
|
||||||
|
$rootScope.queryResult = qr;
|
||||||
|
|
||||||
|
element = angular.element(
|
||||||
|
'<visualization-renderer query-result="queryResult">' +
|
||||||
|
'</visualization-renderer>');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
describe('scope', function() {
|
||||||
|
beforeEach(inject(function($rootScope, $compile) {
|
||||||
|
$compile(element)($rootScope);
|
||||||
|
|
||||||
|
// we will test the isolated scope of the directive
|
||||||
|
scope = element.isolateScope();
|
||||||
|
scope.$digest();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have filters', function() {
|
||||||
|
expect(scope.filters).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('URL binding', function() {
|
||||||
|
|
||||||
|
beforeEach(inject(function($rootScope, $compile, $location) {
|
||||||
|
spyOn($location, 'search').andCallThrough();
|
||||||
|
|
||||||
|
// set initial search
|
||||||
|
var initialSearch = {};
|
||||||
|
initialSearch[filters[0].friendlyName] = filters[0].values[0];
|
||||||
|
$location.search('filters', initialSearch);
|
||||||
|
|
||||||
|
$compile(element)($rootScope);
|
||||||
|
|
||||||
|
// we will test the isolated scope of the directive
|
||||||
|
scope = element.isolateScope();
|
||||||
|
scope.$digest();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should update scope from URL',
|
||||||
|
inject(function($location) {
|
||||||
|
expect($location.search).toHaveBeenCalled();
|
||||||
|
expect(scope.filters[0].current).toEqual(filters[0].values[0]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should update URL from scope',
|
||||||
|
inject(function($location) {
|
||||||
|
scope.filters[0].current = 'newValue';
|
||||||
|
scope.$digest();
|
||||||
|
|
||||||
|
var searchFilters = angular.fromJson($location.search().filters);
|
||||||
|
expect(searchFilters[filters[0].friendlyName]).toEqual('newValue');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user