diff --git a/rd_ui/app/scripts/app.js b/rd_ui/app/scripts/app.js index 1b7006523..7ff54b51a 100644 --- a/rd_ui/app/scripts/app.js +++ b/rd_ui/app/scripts/app.js @@ -17,6 +17,15 @@ angular.module('redash', [ ]).config(['$routeProvider', '$locationProvider', '$compileProvider', 'growlProvider', function($routeProvider, $locationProvider, $compileProvider, growlProvider) { + function newQuery(Query) { + return new Query({ + query: "", + name: "New Query", + ttl: -1, + user: currentUser + }); + } + function getQuery(Query, $q, $route) { var defer = $q.defer(); @@ -42,6 +51,14 @@ angular.module('redash', [ controller: 'QueriesCtrl', reloadOnSearch: false }); + $routeProvider.when('/queries/new', { + templateUrl: '/views/query.html', + controller: 'QueryEditCtrl', + reloadOnSearch: false, + resolve: { + 'query': ['Query', newQuery] + } + }); $routeProvider.when('/queries/:queryId', { templateUrl: '/views/query.html', controller: 'QueryViewCtrl', @@ -50,11 +67,6 @@ angular.module('redash', [ 'query': ['Query', '$q', '$route', getQuery] } }); - $routeProvider.when('/queries/new', { - templateUrl: '/views/query.html', - controller: 'QueryEditCtrl', - reloadOnSearch: false - }); $routeProvider.when('/queries/:queryId/source', { templateUrl: '/views/query.html', controller: 'QueryEditCtrl', diff --git a/rd_ui/app/scripts/controllers/query_edit.js b/rd_ui/app/scripts/controllers/query_edit.js index 981d49efe..7e257b90b 100644 --- a/rd_ui/app/scripts/controllers/query_edit.js +++ b/rd_ui/app/scripts/controllers/query_edit.js @@ -1,125 +1,106 @@ -(function () { - 'use strict'; +(function() { + 'use strict'; - function QueryEditCtrl($controller, $scope, $window, $route, $http, $location, growl, notifications, Query, Visualization) { - var pristineHash = ""; - var leavingPageText = "You will lose your changes if you leave"; + function QueryEditCtrl($controller, $scope, $window, $route, $location, growl, Query, Visualization) { + var pristineHash = ""; + var leavingPageText = "You will lose your changes if you leave"; + var isNewQuery = !$route.current.locals.query.id; - // controller inheritance - $controller('QueryViewCtrl', {$scope: $scope}); + // controller inheritance + $controller('QueryViewCtrl', {$scope: $scope}); - $scope.sourceMode = true; + $scope.sourceMode = true; + $scope.isDirty = undefined; - $scope.dirty = undefined; - $scope.isNewQuery = false; + $scope.canEdit = currentUser.canEdit($scope.query); - $scope.canEdit = currentUser.canEdit($scope.query); + $scope.newVisualization = undefined; - $scope.newVisualization = undefined; + $window.onbeforeunload = function() { + if ($scope.canEdit && $scope.isDirty) { + return leavingPageText; + } + } - $window.onbeforeunload = function () { - if ($scope.canEdit && $scope.dirty) { - return leavingPageText; - } + $scope.$on('$locationChangeStart', function(event, next, current) { + if (next.split("#")[0] == current.split("#")[0]) { + return; + } + + if (!$scope.canEdit) { + return; + } + + if ($scope.isDirty && !confirm(leavingPageText + "\n\nAre you sure you want to leave this page?")) { + event.preventDefault(); + } else { + Mousetrap.unbind("meta+s"); + } + }); + + $scope.saveQuery = function(duplicate, oldId) { + if (!oldId) { + oldId = $scope.query.id; + } + + delete $scope.query.latest_query_data; + $scope.query.$save(function(q) { + pristineHash = q.getHash(); + $scope.isDirty = false; + + if (duplicate) { + growl.addSuccessMessage("Query forked"); + } else { + growl.addSuccessMessage("Query saved"); } - function getQuerySourceUrl(queryId) { - return '/queries/' + queryId + '/source#' + $location.hash(); - }; - - Mousetrap.bindGlobal("meta+s", function (e) { - e.preventDefault(); - - if ($scope.canEdit) { - $scope.saveQuery(); - } - }); - - $scope.$on('$locationChangeStart', function (event, next, current) { - if (next.split("#")[0] == current.split("#")[0]) { - return; - } - - if (!$scope.canEdit) { - return; - } - - if ($scope.dirty && !confirm(leavingPageText + "\n\nAre you sure you want to leave this page?")) { - event.preventDefault(); - } else { - Mousetrap.unbind("meta+s"); - } - }); - - $scope.saveQuery = function (duplicate, oldId) { - if (!oldId) { - oldId = $scope.query.id; - } - - delete $scope.query.latest_query_data; - $scope.query.$save(function (q) { - pristineHash = q.getHash(); - $scope.dirty = false; - - if (duplicate) { - growl.addSuccessMessage("Query forked"); - } else { - growl.addSuccessMessage("Query saved"); - } - - if (oldId != q.id) { - $location.url(getQuerySourceUrl(q.id)).replace(); - } - }, function (httpResponse) { - growl.addErrorMessage("Query could not be saved"); - }); - }; - - - // new query - if (!$route.current.locals.query) { - $scope.query = new Query({ - query: "", - name: "New Query", - ttl: -1, - user: currentUser - }); - $scope.lockButton(false); - $scope.isOwner = $scope.canEdit = true; - $scope.isNewQuery = true; - - var unbind = $scope.$watch('selectedTab == "add"', function (newPanel) { - if (newPanel && route.params.queryId == undefined) { - unbind(); - $scope.saveQuery(); - } - }); + if (oldId != q.id) { + $location.url($location.url().replace(oldId, q.id)).replace(); } - - $scope.$watch(function () { - return $scope.query.getHash(); - }, function (newHash) { - $scope.dirty = (newHash !== pristineHash); - }); - - - $scope.deleteVisualization = function ($e, vis) { - $e.preventDefault(); - if (confirm('Are you sure you want to delete ' + vis.name + ' ?')) { - Visualization.delete(vis); - if ($scope.selectedTab == vis.id) { - $scope.selectedTab = DEFAULT_TAB; - $location.hash($scope.selectedTab); - } - $scope.query.visualizations = - $scope.query.visualizations.filter(function (v) { - return vis.id !== v.id; - }); - } - }; + }, function(httpResponse) { + growl.addErrorMessage("Query could not be saved"); + }); }; - angular.module('redash.controllers') - .controller('QueryEditCtrl', ['$controller', '$scope', '$window', '$route', '$http', '$location', 'growl', 'notifications', 'Query', 'Visualization', QueryEditCtrl]); + $scope.deleteVisualization = function($e, vis) { + $e.preventDefault(); + if (confirm('Are you sure you want to delete ' + vis.name + ' ?')) { + Visualization.delete(vis); + if ($scope.selectedTab == vis.id) { + $scope.selectedTab = DEFAULT_TAB; + $location.hash($scope.selectedTab); + } + $scope.query.visualizations = + $scope.query.visualizations.filter(function(v) { + return vis.id !== v.id; + }); + } + }; + + + $scope.$watch(function() { + return $scope.query.getHash(); + }, function(newHash) { + $scope.isDirty = (newHash !== pristineHash); + }); + + if (isNewQuery) { + // $scope.lockButton(false); + + // save new query when creating a visualization + var unbind = $scope.$watch('selectedTab == "add"', function(newPanel) { + if (newPanel && $route.current.params.queryId == undefined) { + unbind(); + $scope.saveQuery(); + } + }); + } + + }; + + angular.module('redash.controllers').controller('QueryEditCtrl', [ + '$controller', '$scope', '$window', '$route', '$location', 'growl', 'Query', + 'Visualization', QueryEditCtrl + ]); })(); \ No newline at end of file diff --git a/rd_ui/app/scripts/controllers/query_view.js b/rd_ui/app/scripts/controllers/query_view.js index 784461e96..5c481192a 100644 --- a/rd_ui/app/scripts/controllers/query_view.js +++ b/rd_ui/app/scripts/controllers/query_view.js @@ -9,6 +9,7 @@ $scope.queryExecuting = false; $scope.isQueryOwner = currentUser.id === $scope.query.user.id; + $scope.canViewSource = currentUser.hasPermission('view_source'); $scope.lockButton = function(lock) { $scope.queryExecuting = lock; diff --git a/rd_ui/app/scripts/directives/directives.js b/rd_ui/app/scripts/directives/directives.js index da2b1f1de..5791adc3e 100644 --- a/rd_ui/app/scripts/directives/directives.js +++ b/rd_ui/app/scripts/directives/directives.js @@ -3,6 +3,24 @@ var directives = angular.module('redash.directives', []); + directives.directive('keyboardShortcut', function() { + return { + restrict: 'E', + replace: true, + template: 'foo', + scope: { + key: '@', + action: '=' + }, + link: function($scope) { + Mousetrap.bindGlobal($scope.key, function(e) { + e.preventDefault(); + $scope.action(); + }); + } + } + }); + directives.directive('rdTab', function() { return { restrict: 'E', diff --git a/rd_ui/app/scripts/directives/query_directives.js b/rd_ui/app/scripts/directives/query_directives.js index 631b54bad..abd3569fe 100644 --- a/rd_ui/app/scripts/directives/query_directives.js +++ b/rd_ui/app/scripts/directives/query_directives.js @@ -1,5 +1,20 @@ (function() { 'use strict' + + function querySourceLink() { + return { + restrict: 'E', + template: '\ + Show Source\ + \ + Hide Source\ + \ + ' + } + } + function queryEditor() { return { restrict: 'E', @@ -58,7 +73,7 @@ return { restrict: 'E', template: '\ @@ -96,7 +111,8 @@ } angular.module('redash.directives') - .directive('queryRefreshSelect', queryRefreshSelect) + .directive('querySourceLink', querySourceLink) .directive('queryEditor', queryEditor) + .directive('queryRefreshSelect', queryRefreshSelect) .directive('queryFormatter', ['$http', queryFormatter]); })(); \ No newline at end of file diff --git a/rd_ui/app/views/query.html b/rd_ui/app/views/query.html index 259f9e407..1b3cd07dd 100644 --- a/rd_ui/app/views/query.html +++ b/rd_ui/app/views/query.html @@ -1,5 +1,7 @@
+ +
@@ -14,9 +16,10 @@

-
- Show Source - Hide Source +
+
+ +
@@ -39,10 +42,7 @@ {{queryResult.getData().length}}

- - Hide Source - View Source - +

@@ -64,17 +64,19 @@

-

- -

-
+
+

+ +

+
+