Skip to content

Commit

Permalink
Merge pull request #1306 from getredash/pagination
Browse files Browse the repository at this point in the history
Change: paginate queries page & add explicit urls.
  • Loading branch information
arikfr authored Oct 5, 2016
2 parents e8582ec + 5096e4e commit 0b79fb8
Show file tree
Hide file tree
Showing 17 changed files with 315 additions and 110 deletions.
12 changes: 12 additions & 0 deletions migrations/0026_add_queries_org_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from redash.models import db
from playhouse.migrate import PostgresqlMigrator, migrate

if __name__ == '__main__':
migrator = PostgresqlMigrator(db.database)

with db.database.transaction():
migrate(
migrator.add_index('queries', ('org_id',)),
)

db.close_db(None)
10 changes: 10 additions & 0 deletions rd_ui/app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ angular.module('redash', [
}]
}
});
$routeProvider.when('/queries/my', {
templateUrl: '/views/queries.html',
controller: 'QueriesCtrl',
reloadOnSearch: false
});
$routeProvider.when('/queries/drafts', {
templateUrl: '/views/queries.html',
controller: 'QueriesCtrl',
reloadOnSearch: false
});
$routeProvider.when('/queries/search', {
templateUrl: '/views/queries_search_results.html',
controller: 'QuerySearchCtrl',
Expand Down
123 changes: 49 additions & 74 deletions rd_ui/app/scripts/controllers/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,91 +63,66 @@
};

var QueriesCtrl = function ($scope, $http, $location, $filter, Query) {
$scope.$parent.pageTitle = "All Queries";
$scope.gridConfig = {
isPaginationEnabled: true,
itemsByPage: 50,
maxSize: 8,
isGlobalSearchActivated: true};
var loader;

$scope.allQueries = [];
$scope.queries = [];
$scope.page = parseInt($location.search().page || 1);
$scope.total = undefined;
$scope.pageSize = 25;

function loadQueries(resource, defaultOptions) {
return function(options) {
options = _.extend({}, defaultOptions, options);
resource(options, function (queries) {
$scope.totalQueriesCount = queries.count;
$scope.queries = _.map(queries.results, function (query) {
query.created_at = moment(query.created_at);
query.retrieved_at = moment(query.retrieved_at);
return query;
});
});
}
}

var filterQueries = function () {
$scope.queries = _.filter($scope.allQueries, function (query) {
if (!$scope.selectedTab) {
return false;
}

if ($scope.selectedTab.key == 'my') {
return query.user.id == currentUser.id && query.name != 'New Query';
} else if ($scope.selectedTab.key == 'drafts') {
return query.user.id == currentUser.id && query.name == 'New Query';
}

return query.name != 'New Query';
});
switch($location.path()) {
case '/queries':
$scope.$parent.pageTitle = "Queries";
// page title
loader = loadQueries(Query.query);
break;
case '/queries/drafts':
$scope.$parent.pageTitle = "Drafts";
loader = loadQueries(Query.myQueries, {drafts: true});
break;
case '/queries/my':
$scope.$parent.pageTitle = "My Queries";
loader = loadQueries(Query.myQueries);
break;
}

Query.query(function (queries) {
$scope.allQueries = _.map(queries, function (query) {
query.created_at = moment(query.created_at);
query.retrieved_at = moment(query.retrieved_at);
return query;
});
var loadAllQueries = loadQueries(Query.query);
var loadMyQueries = loadQueries(Query.myQueries);

filterQueries();
});
function load() {
var options = {page: $scope.page, page_size: $scope.pageSize};
loader(options);
}

$scope.gridColumns = [
{
"label": "Name",
"map": "name",
"cellTemplateUrl": "/views/queries_query_name_cell.html"
},
{
'label': 'Created By',
'map': 'user.name'
},
{
'label': 'Created At',
'map': 'created_at',
'formatFunction': dateFormatter
},
{
'label': 'Runtime',
'map': 'runtime',
'formatFunction': function (value) {
return $filter('durationHumanize')(value);
}
},
{
'label': 'Last Executed At',
'map': 'retrieved_at',
'formatFunction': dateFormatter
},
{
'label': 'Update Schedule',
'map': 'schedule',
'formatFunction': function (value) {
return $filter('scheduleHumanize')(value);
}
}
]
$scope.selectPage = function(page) {
$location.search('page', page);
$scope.page = page;
load();
}

$scope.tabs = [
{"name": "My Queries", "key": "my"},
{"key": "all", "name": "All Queries"},
{"key": "drafts", "name": "Drafts"}
{"name": "My Queries", "path": "queries/my", loader: loadMyQueries},
{"path": "queries", "name": "All Queries", isActive: function(path) {
return path === '/queries';
}, "loader": loadAllQueries},
{"path": "queries/drafts", "name": "Drafts", loader: loadMyQueries},
];

$scope.$watch('selectedTab', function (tab) {
if (tab) {
$scope.$parent.pageTitle = tab.name;
}

filterQueries();
});
load();
}

var MainCtrl = function ($scope, $location, Dashboard) {
Expand Down
122 changes: 111 additions & 11 deletions rd_ui/app/scripts/directives/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,21 +483,121 @@
restrict: 'E',
transclude: true,
templateUrl: '/views/directives/settings_screen.html',
link: function(scope, elem, attrs) {
scope.usersPage = _.string.startsWith($location.path(), '/users');
scope.groupsPage = _.string.startsWith($location.path(), '/groups');
scope.dsPage = _.string.startsWith($location.path(), '/data_sources');
scope.destinationsPage = _.string.startsWith($location.path(), '/destinations');
scope.snippetsPage = _.string.startsWith($location.path(), '/query_snippets');

scope.showGroupsLink = currentUser.hasPermission('list_users');
scope.showUsersLink = currentUser.hasPermission('list_users');
scope.showDsLink = currentUser.hasPermission('admin');
scope.showDestinationsLink = currentUser.hasPermission('admin');
controller: ['$scope', function(scope) {
scope.tabs = [];

if (currentUser.hasPermission('admin')) {
scope.tabs.push({name: 'Data Sources', path: 'data_sources'});
}

if (currentUser.hasPermission('list_users')) {
scope.tabs.push({name: 'Users', path: 'users'});
scope.tabs.push({name: 'Groups', path: 'groups'});
}

if (currentUser.hasPermission('admin')) {
scope.tabs.push({name: 'Alert Destinations', path: 'destinations'});
}

scope.tabs.push({name: "Query Snippets", path: "query_snippets"});
}]
}
}]);

directives.directive('tabNav', ['$location', function($location) {
return {
restrict: 'E',
transclude: true,
scope: {
tabs: '='
},
template: '<ul class="tab-nav bg-white">' +
'<li ng-repeat="tab in tabs" ng-class="{\'active\': tab.active }"><a ng-href="{{tab.path}}">{{tab.name}}</a></li>' +
'</ul>',
link: function($scope) {
_.each($scope.tabs, function(tab) {
if (tab.isActive) {
tab.active = tab.isActive($location.path());
} else {
tab.active = _.string.startsWith($location.path(), "/" + tab.path);
}
});
}
}
}]);

directives.directive('queriesList', [function () {
return {
restrict: 'E',
replace: true,
scope: {
queries: '=',
total: '=',
selectPage: '=',
page: '=',
pageSize: '='
},
templateUrl: '/views/directives/queries_list.html',
link: function ($scope) {
function hasNext() {
return !($scope.page * $scope.pageSize >= $scope.total);
}

function hasPrevious() {
return $scope.page !== 1;
}

function updatePages() {
if ($scope.total === undefined) {
return;
}

var maxSize = 5;
var pageCount = Math.ceil($scope.total/$scope.pageSize);
var pages = [];

function makePage(title, page, disabled) {
return {title: title, page: page, active: page == $scope.page, disabled: disabled};
}

// Default page limits
var startPage = 1, endPage = pageCount;

// recompute if maxSize
if (maxSize && maxSize < pageCount) {
startPage = Math.max($scope.page - Math.floor(maxSize / 2), 1);
endPage = startPage + maxSize - 1;

// Adjust if limit is exceeded
if (endPage > pageCount) {
endPage = pageCount;
startPage = endPage - maxSize + 1;
}
}

// Add page number links
for (var number = startPage; number <= endPage; number++) {
var page = makePage(number, number, false);
pages.push(page);
}

// Add previous & next links
var previousPage = makePage('<', $scope.page - 1, !hasPrevious());
pages.unshift(previousPage);

var nextPage = makePage('>', $scope.page + 1, !hasNext());
pages.push(nextPage);

$scope.pages = pages;
}

$scope.$watch('total', updatePages);
$scope.$watch('page', updatePages);
}
}
}]);


directives.directive('parameters', ['$location', '$modal', function($location, $modal) {
return {
restrict: 'E',
Expand Down
3 changes: 3 additions & 0 deletions rd_ui/app/scripts/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ angular.module('redash.filters', []).

.filter('dateTime', function() {
return function(value) {
if (!value) {
return '-';
}
return moment(value).format(clientConfig.dateTimeFormat);
}
})
Expand Down
10 changes: 9 additions & 1 deletion rd_ui/app/scripts/services/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,14 @@
method: 'get',
isArray: true,
url: "api/queries/recent"
},
query: {
isArray: false
},
myQueries: {
method: 'get',
isArray: false,
url: "api/queries/my"
}
});

Expand Down Expand Up @@ -769,7 +777,7 @@
"tabTrigger": this.trigger
};
}

return resource;
};

Expand Down
30 changes: 30 additions & 0 deletions rd_ui/app/views/directives/queries_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<div class="bg-white">
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>Name</th>
<th>Created By</th>
<th>Created At</th>
<th>Runtime</th>
<th>Last Executed At</th>
<th>Update Schedule</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="query in queries">
<td><a href="queries/{{query.id}}">{{query.name}}</a></td>
<td>{{query.user.name}}</td>
<td>{{query.created_at | dateTime}}</td>
<td>{{query.runtime | durationHumanize}}</td>
<td>{{query.retrieved_at | dateTime}}</td>
<td>{{query.schedule | scheduleHumanize}}</td>
</tr>
</tbody>
</table>

<div class="text-center">
<ul class="pagination">
<li ng-repeat="p in pages" ng-class="{active: p.active, disabled: p.disabled}"><a ng-click="selectPage(p.page)">{{p.title}}</a></li>
</ul>
</div>
</div>
8 changes: 1 addition & 7 deletions rd_ui/app/views/directives/settings_screen.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@

<div class="container">
<div class="container bg-white p-5">
<ul class="tab-nav">
<li ng-class="{'active': dsPage }" ng-if="showDsLink"><a href="data_sources">Data Sources</a></li>
<li ng-class="{'active': usersPage }" ng-if="showUsersLink"><a href="users">Users</a></li>
<li ng-class="{'active': groupsPage }" ng-if="showGroupsLink"><a href="groups">Groups</a></li>
<li ng-class="{'active': destinationsPage }" ng-if="showDestinationsLink"><a href="destinations">Alert Destinations</a></li>
<li ng-class="{'active': snippetsPage }"><a href="query_snippets">Query Snippets</a></li>
</ul>
<tab-nav tabs="tabs"></tab-nav>

<div ng-transclude>

Expand Down
6 changes: 2 additions & 4 deletions rd_ui/app/views/queries.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<div class="container">
<page-header title="Queries"></page-header>

<rd-tabs tabs-collection='tabs' selected-tab='selectedTab'></rd-tabs>
<smart-table rows="queries" columns="gridColumns"
config="gridConfig"
class="table table-condensed table-hover"></smart-table>
<tab-nav tabs="tabs"></tab-nav>
<queries-list queries="queries" total="totalQueriesCount" page="page" select-page="selectPage" page-size="pageSize"></queries-list>
</div>
Loading

0 comments on commit 0b79fb8

Please sign in to comment.