diff --git a/bower.json b/bower.json index e3362e29..aff48516 100644 --- a/bower.json +++ b/bower.json @@ -2,10 +2,7 @@ "name": "redash", "version": "0.11.0", "dependencies": { - "pivottable": "2.0.2", "pace": "~0.5.1", "canvg": "gabelerner/canvg", - "leaflet": "~0.7.3", - "leaflet.markercluster": "^0.5.0" }, } diff --git a/frontend/app/visualizations/index.js b/frontend/app/visualizations/index.js index 554a3efb..3301760c 100644 --- a/frontend/app/visualizations/index.js +++ b/frontend/app/visualizations/index.js @@ -13,6 +13,7 @@ import wordCloudVisualization from './word-cloud'; import boxPlotVisualization from './box-plot'; import cohortVisualization from './cohort'; import mapVisualization from './map'; +import pivotVisualization from './pivot'; function VisualizationProvider() { this.visualizations = {}; @@ -168,5 +169,6 @@ export default function (ngModule) { boxPlotVisualization(ngModule); cohortVisualization(ngModule); mapVisualization(ngModule); + pivotVisualization(ngModule); tableVisualization(ngModule); } diff --git a/frontend/app/visualizations/pivot/index.js b/frontend/app/visualizations/pivot/index.js new file mode 100644 index 00000000..e723e4d0 --- /dev/null +++ b/frontend/app/visualizations/pivot/index.js @@ -0,0 +1,68 @@ +import $ from 'jquery'; +import 'pivottable'; +import 'pivottable/dist/pivot.css'; + +function pivotTableRenderer() { + return { + restrict: 'E', + scope: { + queryResult: '=', + visualization: '=', + }, + template: '', + replace: false, + link($scope, element) { + $scope.$watch('queryResult && queryResult.getData()', (data) => { + if (!data) { + return; + } + + if ($scope.queryResult.getData() !== null) { + // We need to give the pivot table its own copy of the data, because it changes + // it which interferes with other visualizations. + data = $.extend(true, [], $scope.queryResult.getRawData()); + const options = { + renderers: $.pivotUtilities.renderers, + onRefresh(config) { + const configCopy = Object.assign({}, config); + // delete some values which are functions + delete configCopy.aggregators; + delete configCopy.renderers; + delete configCopy.onRefresh; + // delete some bulky default values + delete configCopy.rendererOptions; + delete configCopy.localeStrings; + + if ($scope.visualization) { + $scope.visualization.options = configCopy; + } + }, + }; + + if ($scope.visualization) { + Object.assign(options, $scope.visualization.options); + } + $(element).pivotUI(data, options, true); + } + }); + }, + }; +} + +export default function (ngModule) { + ngModule.directive('pivotTableRenderer', pivotTableRenderer); + + ngModule.config((VisualizationProvider) => { + const editTemplate = '
'; + const defaultOptions = { + }; + + VisualizationProvider.registerVisualization({ + type: 'PIVOT', + name: 'Pivot Table', + renderTemplate: '