Dashboard visualizations

This commit is contained in:
Amir Nissim 2014-02-03 16:12:29 +02:00
parent 5c7baf9e05
commit c2cbcd3727
9 changed files with 50 additions and 70 deletions

View File

@ -201,7 +201,7 @@ class Widget(models.Model):
'type': self.type, 'type': self.type,
'width': self.width, 'width': self.width,
'options': json.loads(self.options), 'options': json.loads(self.options),
'visualization_id': self.visualization_id, 'visualization': self.visualization.to_dict(),
'dashboard_id': self.dashboard_id 'dashboard_id': self.dashboard_id
} }

View File

@ -7,7 +7,7 @@
var WidgetCtrl = function ($scope, $http, $location, Query) { var WidgetCtrl = function ($scope, $http, $location, Query) {
$scope.deleteWidget = function() { $scope.deleteWidget = function() {
if (!confirm('Are you sure you want to remove "' + $scope.widget.query.name + '" from the dashboard?')) { if (!confirm('Are you sure you want to remove "' + $scope.widget.visualization.name + '" from the dashboard?')) {
return; return;
} }
@ -24,7 +24,7 @@
$location.path('/queries/' + query.id); $location.path('/queries/' + query.id);
} }
$scope.query = new Query($scope.widget.query); $scope.query = new Query($scope.widget.visualization.query);
$scope.queryResult = $scope.query.getQueryResult(); $scope.queryResult = $scope.query.getQueryResult();
$scope.updateTime = (new Date($scope.queryResult.getUpdatedAt())).toISOString(); $scope.updateTime = (new Date($scope.queryResult.getUpdatedAt())).toISOString();

View File

@ -70,7 +70,7 @@
// create new visualization // create new visualization
// wait for query to load to populate with defaults // wait for query to load to populate with defaults
var unwatch = scope.$watch('query', function(q) { var unwatch = scope.$watch('query', function(q) {
if (q.id) { if (q && q.id) {
unwatch(); unwatch();
scope.vis = { scope.vis = {
'query_id': q.id, 'query_id': q.id,
@ -168,7 +168,7 @@
row: rowIndex+1, row: rowIndex+1,
ySize: 1, ySize: 1,
xSize: widget.width, xSize: widget.width,
name: widget.query.name name: widget.visualization.name
}); });
}); });
}); });
@ -230,14 +230,14 @@
templateUrl: '/views/new_widget_form.html', templateUrl: '/views/new_widget_form.html',
replace: true, replace: true,
link: function($scope, element, attrs) { link: function($scope, element, attrs) {
$scope.visReady = false;
$scope.currentView = 'existing';
$scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}]; $scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}];
var reset = function() { var reset = function() {
$scope.saveInProgress = false; $scope.saveInProgress = false;
$scope.widgetSize = 1; $scope.widgetSize = 1;
$scope.queryId = null; $scope.queryId = null;
$scope.selectedVis = null;
} }
reset(); reset();
@ -247,18 +247,18 @@
}; };
$scope.loadVisualizations = function() { $scope.loadVisualizations = function() {
if (!$scope.queryId) {
return;
}
Query.get({ Query.get({
id: $scope.queryId id: $scope.queryId
}, function(query) { }, function(query) {
if (query) { if (query) {
// TODO $scope.query = query;
$scope.visReady = true; if(query.visualizations.length) {
var visualizations = query.getVisualizations(); $scope.selectedVis = query.visualizations[0];
$scope.existing = visualizations = [ }
{'name': 'vis1', 'type': 'Cohort'},
{'name': 'vis2', 'type': 'Pivot Table'}
];
$scope.currentView = (visualizations.length) ? 'existing' : 'addNew';
} }
}); });
}; };
@ -267,7 +267,7 @@
$scope.saveInProgress = true; $scope.saveInProgress = true;
var widget = { var widget = {
'query_id': $scope.queryId, 'visualization_id': $scope.selectedVis.id,
'dashboard_id': $scope.dashboard.id, 'dashboard_id': $scope.dashboard.id,
'options': {}, 'options': {},
'width': $scope.widgetSize 'width': $scope.widgetSize

View File

@ -1,5 +1,21 @@
var renderers = angular.module('redash.renderers', []); var renderers = angular.module('redash.renderers', []);
renderers.directive('visualizationRenderer', function() {
return {
restrict: 'E',
scope: {
visualization: '=',
queryResult: '='
},
template: '<div ng-switch on="visualization.type">' +
'<chart-renderer ng-switch-when="CHART" options="visualization.options" query-result="queryResult"></chart-renderer>' +
'<grid-renderer ng-switch-when="GRID" options="visualization.options" query-result="queryResult"></grid-renderer>' +
'<cohort-renderer ng-switch-when="COHORT" options="visualization.options" query-result="queryResult"></cohort-renderer>' +
'</div>',
replace: false
}
});
renderers.directive('chartRenderer', function () { renderers.directive('chartRenderer', function () {
return { return {
restrict: 'E', restrict: 'E',

View File

@ -280,12 +280,6 @@
return [this.name, this.description, this.query].join('!#'); return [this.name, this.description, this.query].join('!#');
}; };
Query.prototype.getVisualizations = function() {
// TODO
// not implemented
return [];
};
return Query; return Query;
}; };

View File

@ -29,11 +29,8 @@
</h3> </h3>
</div> </div>
<div ng-switch on="widget.type" class="panel-body"> <visualization-renderer visualization="widget.visualization" query-result="queryResult"></visualization-renderer class="panel-body">
<chart-renderer ng-switch-when="chart" query-result="queryResult"></chart-renderer>
<grid-renderer ng-switch-when="grid" query-result="queryResult"></grid-renderer>
<cohort-renderer ng-switch-when="cohort" query-result="queryResult"></cohort-renderer>
</div>
<div class="panel-footer"> <div class="panel-footer">
<span class="label label-default" <span class="label label-default"
tooltip="next update {{nextUpdateTime}} (query runtime: {{queryResult.getRuntime() | durationHumanize}})" tooltip="next update {{nextUpdateTime}} (query runtime: {{queryResult.getRuntime() | durationHumanize}})"

View File

@ -20,7 +20,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<a class="link" ng-click="toggleAdvancedMode()">Advanced Mode</a> <a class="link" ng-click="toggleAdvancedMode()">Advanced</a>
<textarea json-text class="form-control" rows="5" ng-model="vis.options" ng-show="advancedMode"></textarea> <textarea json-text class="form-control" rows="5" ng-model="vis.options" ng-show="advancedMode"></textarea>
</div> </div>

View File

@ -9,50 +9,25 @@
<p> <p>
<form class="form-inline" role="form" ng-submit="loadVisualizations()"> <form class="form-inline" role="form" ng-submit="loadVisualizations()">
<div class="form-group"> <div class="form-group">
<input type="number" class="form-control" placeholder="Query Id" ng-model="queryId"> <input class="form-control" placeholder="Query Id" ng-model="queryId">
</div> </div>
<button type="submit" class="btn btn-primary" ng-disabled="!queryId"> <button type="submit" class="btn btn-primary" ng-disabled="!queryId">
Load <span class="glyphicon glyphicon-refresh"></span> Load
</button> </button>
</form> </form>
</p> </p>
<div ng-show="visReady"> <div ng-show="query">
<div class="form-group"> <div class="form-group">
<label for="">Choose Visualation</label> <label for="">Choose Visualation</label>
<div class="panel-group"> <select ng-model="selectedVis" ng-options="vis as vis.name group by vis.type for vis in query.visualizations" class="form-control"></select>
<!-- Existing visualizations panel --> </div>
<div class="panel panel-default" ng-show="existing.length">
<div class="panel-heading">
<a ng-click="toggleView('existing')" href="#">
Existing
</a>
</div>
<div class="panel-collapse collapse" ng-class="{in: currentView=='existing'}">
<div class="panel-body">
<ul>
<li ng-repeat="item in existing">
{{item.name}} <span class="label label-info">{{item.type}}</span>
</li>
</ul>
</div>
</div>
</div>
<!-- add new visualizations panel --> <div class="form-group">
<div class="panel panel-default"> <a ng-click="toggleView('addNew')" class="link">&plus; Add New</a>
<div class="panel-heading"> <div class="well" ng-show="currentView=='addNew'">
<a ng-click="toggleView('addNew')" href="#"> <edit-visulatization-form query="query"></edit-visulatization-form>
Add New </div>
</a>
</div>
<div class="panel-collapse collapse" ng-class="{in: currentView=='addNew'}">
<div class="panel-body">
<add-visulatization-form></add-visulatization-form>
</div>
</div>
</div>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">

View File

@ -74,9 +74,8 @@
<div class="col-lg-6"> <div class="col-lg-6">
<edit-visulatization-form vis="vis" query="query"></edit-visulatization-form> <edit-visulatization-form vis="vis" query="query"></edit-visulatization-form>
</div> </div>
<div class="col-lg-6" ng-switch="vis.type"> <div class="col-lg-6">
<chart-renderer options="vis.options" query-result="queryResult" ng-switch-when="CHART"></chart-renderer> <visualization-renderer visualization="vis" query-result="queryResult"></visualization-renderer>
<cohort-renderer options="vis.options" query-result="queryResult" ng-switch-when="COHORT"></cohort-renderer>
</div> </div>
</p> </p>
</div> </div>
@ -88,9 +87,8 @@
<div class="col-lg-6"> <div class="col-lg-6">
<edit-visulatization-form vis="newVisualization" query="query"></edit-visulatization-form> <edit-visulatization-form vis="newVisualization" query="query"></edit-visulatization-form>
</div> </div>
<div class="col-lg-6" ng-switch="newVisualization.type"> <div class="col-lg-6">
<chart-renderer options="newVisualization.options" query-result="queryResult" ng-switch-when="CHART"></chart-renderer> <visualization-renderer visualization="newVisualization" query-result="queryResult"></visualization-renderer>
<cohort-renderer options="newVisualization.options" query-result="queryResult" ng-switch-when="COHORT"></cohort-renderer>
</div> </div>
</p> </p>
</div> </div>