rd_ui: sync filters with location.search [closes #146]

This commit is contained in:
Amir Nissim
2014-08-06 16:18:05 +03:00
parent 9592610f8b
commit 948e2247e4
8 changed files with 177 additions and 12 deletions

View File

@@ -55,7 +55,7 @@
}];
};
var VisualizationRenderer = function (Visualization) {
var VisualizationRenderer = function ($location, Visualization) {
return {
restrict: 'E',
scope: {
@@ -68,12 +68,47 @@
template: '<filters></filters>\n' + Visualization.renderVisualizationsTemplate,
replace: false,
link: function (scope) {
scope.select2Options = {
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) {
if (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', [])
.provider('Visualization', VisualizationProvider)
.directive('visualizationRenderer', ['Visualization', VisualizationRenderer])
.directive('visualizationRenderer', ['$location', 'Visualization', VisualizationRenderer])
.directive('visualizationOptionsEditor', ['Visualization', VisualizationOptionsEditor])
.directive('filters', Filters)
.directive('editVisulatizationForm', ['Events', 'Visualization', 'growl', EditVisualizationForm])

View File

@@ -171,7 +171,7 @@
<edit-visulatization-form visualization="vis" query="query" query-result="queryResult" ng-show="canEdit"></edit-visulatization-form>
</div>
<div ng-show="selectedTab == 'add'">
<div ng-if="canEdit" ng-show="selectedTab == 'add'">
<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>
</div>

View File

@@ -29,7 +29,8 @@
"karma-jasmine": "~0.1.5",
"grunt-karma": "~0.8.3",
"karma-phantomjs-launcher": "~0.1.4",
"karma": "~0.12.19"
"karma": "~0.12.19",
"karma-ng-html2js-preprocessor": "~0.1.0"
},
"engines": {
"node": ">=0.10.0"

View File

@@ -75,10 +75,17 @@ module.exports = function(config) {
'app/scripts/directives/dashboard_directives.js',
'app/scripts/filters.js',
'app/views/**/*.html',
'test/mocks/*.js',
'test/unit/*.js'
],
// generate js files from html templates
preprocessors: {
'app/views/**/*.html': 'ng-html2js'
},
// list of files / patterns to exclude
exclude: [],
@@ -100,7 +107,8 @@ module.exports = function(config) {
// Which plugins to enable
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine'
'karma-jasmine',
'karma-ng-html2js-preprocessor'
],
// Continuous Integration mode

View File

@@ -16,9 +16,8 @@ currentUser = {
angular.module('redashMocks', [])
.value('mockData', {
.value('MockData', {
query: {
"ttl": -1,
"query": "select name from users;",
"id": 1803,
@@ -72,5 +71,38 @@ angular.module('redashMocks', [])
"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"
}]
}
});

View File

@@ -2,18 +2,18 @@
describe('QueryViewCtrl', function() {
var scope;
var mockData;
var MockData;
beforeEach(module('redash', 'redashMocks'));
beforeEach(inject(function($injector, $controller, $rootScope, Query, _mockData_) {
mockData = _mockData_;
beforeEach(inject(function($injector, $controller, $rootScope, Query, _MockData_) {
MockData = _MockData_;
scope = $rootScope.$new();
var route = {
current: {
locals: {
query: new Query(mockData.query)
query: new Query(MockData.query)
}
}
};

View 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');
}));
});
});