added pagination to the repository GetUser method.

added pagesixe to userlist object.
added total user count to enable PageCount to work correctly.
added GET_TOTAL_USER_COUNT and GET_ALL_USERS_PAGINATE sqlite procedures to support pagination.
updated methods in SQLiteRepository to support pagination procedures and pagination properties of UserList.
updated UsersController to support pagination parameters.
tidied html script tags.
added pagination buttons at the bottom of user page. including drop down to select PageSize
added setPageSize, goToUserPage and setPagination methods to the viewmodel.
updated other methods for sammy etc to work with pagesize and PageNumber params.
#11
This commit is contained in:
chris.watts90@outlook.com 2017-02-12 22:26:00 +00:00
parent 159c0a7625
commit cdac61b18d
7 changed files with 161 additions and 41 deletions

View File

@ -11,7 +11,17 @@ namespace Interfaces
/// Returns <see cref="UserList"/> with full list of users, /// Returns <see cref="UserList"/> with full list of users,
/// plus a total user count. Pagination options are supported. /// plus a total user count. Pagination options are supported.
/// </returns> /// </returns>
UserList GetUsers(); UserList GetUsers(int pageNumber=-1, int pageSize=-1);
///// <summary>
///// Get a paginated list of users
///// </summary>
///// <param name="pageNumber">The number of the page to retrieve</param>
///// <param name="pageSize">The size of the pages</param>
///// <returns>
///// Returns <see cref="UserList"/> with full list of users,
///// plus a total user count. Pagination options are supported.
///// </returns>
//UserList GetUsers(int pageNumber, int pageSize);
/// <summary> /// <summary>
/// Search the user list for the following string /// Search the user list for the following string
/// </summary> /// </summary>

View File

@ -7,10 +7,23 @@ namespace Interfaces
public UserList() public UserList()
{ {
Users = new List<User>(); Users = new List<User>();
PageSize = 10;
} }
public string Query { get; set; } public string Query { get; set; }
public int UserCount { get { return Users.Count; } } public int UserCount { get { return Users.Count; } }
public int TotalUserCount { get; set; }
public List<User> Users { get; set; } public List<User> Users { get; set; }
public int PageCount
{
get
{
if (TotalUserCount < PageSize)
return 1;
return (TotalUserCount / PageSize);
}
}
public int PageSize { get; set; } public int PageSize { get; set; }
public int PageNumber { get; set; } public int PageNumber { get; set; }
} }

View File

@ -18,5 +18,9 @@ namespace SQLiteRepository
public const string SEARCH_USER_LIST = "SELECT * FROM " + nameof(UserIdentity) + " where(" + nameof(UserIdentity.FirstName) + " Like ? OR " + nameof(UserIdentity.LastName) + " Like ?)"; public const string SEARCH_USER_LIST = "SELECT * FROM " + nameof(UserIdentity) + " where(" + nameof(UserIdentity.FirstName) + " Like ? OR " + nameof(UserIdentity.LastName) + " Like ?)";
public const string GET_LAST_TIMELOG_DIRECTION = "SELECT * FROM " + nameof(TimeLogDb) + " where " + nameof(TimeLogDb.UserId_FK) + " = ? order by " + nameof(TimeLogDb.SwipeEventDateTime) + " LIMIT 1"; public const string GET_LAST_TIMELOG_DIRECTION = "SELECT * FROM " + nameof(TimeLogDb) + " where " + nameof(TimeLogDb.UserId_FK) + " = ? order by " + nameof(TimeLogDb.SwipeEventDateTime) + " LIMIT 1";
public const string GET_ALL_USERS_PAGINATE = "select * from "+ nameof(UserIdentity)+" limit ? offset ?";
public const string GET_TOTAL_USER_COUNT = "select Max("+nameof(UserIdentity.Id)+") from " + nameof(UserIdentity);
} }
} }

View File

@ -23,16 +23,35 @@ namespace SQLiteRepository
_connection.CreateTable<TimeLogDb>(); _connection.CreateTable<TimeLogDb>();
} }
public UserList GetUsers() public UserList GetUsers(int pageNumber=-1, int pageSize=-1)
{ {
var ret = new UserList(); var ret = new UserList();
List<UserIdentity> users;
var users = _connection.Query<UserIdentity>(SQLiteProcedures.GET_ALL_USERS); int userCount = -1;
if (pageNumber == -1 && pageSize == -1)
{
users = _connection.Query<UserIdentity>(SQLiteProcedures.GET_ALL_USERS);
userCount = users.Count;
}
else
{
users = _connection.Query<UserIdentity>(SQLiteProcedures.GET_ALL_USERS_PAGINATE,
pageSize, (pageNumber-1)*pageSize);
userCount = _connection.ExecuteScalar<int>(SQLiteProcedures.GET_TOTAL_USER_COUNT);
}
if (!users.Any()) if (!users.Any())
{ {
ret.PageNumber = 1; if (pageNumber == -1 && pageSize == -1)
ret.PageSize = 20; {
ret.PageNumber = 1;
ret.PageSize = 20;
}
else
{
ret.PageNumber = pageNumber;
ret.PageSize = pageSize;
}
return ret; return ret;
} }
@ -54,9 +73,17 @@ namespace SQLiteRepository
} }
ret.Users.Add(userObj); ret.Users.Add(userObj);
} }
ret.PageSize = 20; if (pageNumber == -1 && pageSize == -1)
ret.PageNumber = 1; {
ret.PageSize = 1; //TODO: switch to ret.UserCount
ret.PageNumber = 1;
}
else
{
ret.PageSize = pageSize;
ret.PageNumber = pageNumber;
}
ret.TotalUserCount = userCount;
return ret; return ret;
} }

View File

@ -24,8 +24,21 @@ namespace WindowsDataCenter
[CacheControl(MaxAge = 0)] [CacheControl(MaxAge = 0)]
public IHttpActionResult GetUsers([FromUri] string query = "",[FromUri] int pageSize = -1, [FromUri] int pageNumber =-1) public IHttpActionResult GetUsers([FromUri] string query = "",[FromUri] int pageSize = -1, [FromUri] int pageNumber =-1)
{ {
var userList = query == string.Empty ? _repo.GetUsers() : _repo.Search(query); UserList userList = new UserList();
userList.Query = query == string.Empty ? null : query; pageNumber = pageNumber == -1 ? 1 : pageNumber;
pageSize = pageSize == -1 ? 1 : pageSize;
userList = query == string.Empty ? _repo.GetUsers(pageNumber, pageSize) : _repo.Search(query);
if (query != string.Empty)
{
userList.Query = query;
userList.PageNumber = 1;
userList.PageSize = userList.UserCount;
}
else
userList.Query = null;
userList.PageNumber = pageNumber;
userList.PageSize = pageSize;
var msg = Request.CreateResponse(HttpStatusCode.OK, userList); var msg = Request.CreateResponse(HttpStatusCode.OK, userList);
return ResponseMessage(msg); return ResponseMessage(msg);

View File

@ -1,9 +1,7 @@
<html> <html>
<head> <head>
<title>Flexi Time Data Viewer</title> <title>Flexi Time Data Viewer</title>
<link rel="shortcut icon" href="/favicon.ico" /> <link rel="shortcut icon" href="favicon.ico" />
<!--<script src="https://code.jquery.com/jquery-3.1.0.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>-->
<link rel="stylesheet preload" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <link rel="stylesheet preload" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet preload" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/css/bootstrap-datepicker3.min.css"> <link rel="stylesheet preload" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/css/bootstrap-datepicker3.min.css">
@ -61,28 +59,46 @@
<div> <div>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>UserId</th> <th>UserId</th>
<th class="col-md-1">firstName</th> <th class="col-md-1">firstName</th>
<th class="col-md-1">lastName</th> <th class="col-md-1">lastName</th>
<th /> <th />
<th /> <th />
</tr> </tr>
</thead> </thead>
<tbody data-bind="foreach: Users"> <tbody data-bind="foreach: Users">
<tr> <tr>
<td class="valign" data-bind="text: UserId"></td> <td class="valign" data-bind="text: UserId"></td>
<td class="valign" data-bind="text: UserId"></td> <td class="valign" data-bind="text: UserId"></td>
<td class="valign" data-bind="text: LastName"></td> <td class="valign" data-bind="text: LastName"></td>
<td class="valign" data-bind="text: FirstName"></td> <td class="valign" data-bind="text: FirstName"></td>
<td class="fit"><button data-bind="click: $root.goToUserDetails" class="btn btn-default">Details</button></td> <td class="fit"><button data-bind="click: $root.goToUserDetails" class="btn btn-default">Details</button></td>
<td class="fit hidden-md-down"><button data-bind="click: $root.goToTimeLogs" class="btn btn-default">View Logs</button></td> <td class="fit hidden-md-down"><button data-bind="click: $root.goToTimeLogs" class="btn btn-default">View Logs</button></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<label>Total User Count: <span data-bind="text: UserCount"></span></label> <label>Total User Count: <span data-bind="text: UserCount"></span></label>
</div> </div>
<div class="row">
<ul class="pagination" data-bind="foreach: new Array(PageCount)">
<li data-bind="css:{ active: $parent.PageNumber==($index()+1)}"><a data-bind="text: $index()+1, click: function(){$root.goToUserPage($index()+1);}"></a></li>
</ul>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Page Size
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li data-bind="css:{disabled:$root.userList().PageSize===-1}"><a data-bind="click: function(){$root.setPageSize(-1);}">All</a></li>
<li data-bind="css:{disabled:$root.userList().PageSize===1}"><a data-bind="click: function(){$root.setPageSize(1);}">1</a></li>
<li data-bind="css:{disabled:$root.userList().PageSize===10}"><a data-bind="click: function(){$root.setPageSize(10);}">10</a></li>
<li data-bind="css:{disabled:$root.userList().PageSize===20}"><a data-bind="click: function(){$root.setPageSize(20);}">20</a></li>
<li data-bind="css:{disabled:$root.userList().PageSize===50}"><a data-bind="click: function(){$root.setPageSize(50);}">50</a></li>
</ul>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -35,11 +35,7 @@
} }
var url = "timelogs" + "/" + userId; var url = "timelogs" + "/" + userId;
if (args) { if (args) {
var appender = "?"; url = self.createRequestUrl(url, args, false, true);
args.forEach(function(arg) {
url += appender + arg.key + "=" + arg.value;
appender = "&";
});
} }
location.hash = url; location.hash = url;
}; };
@ -80,16 +76,16 @@
* @param {string} routePath * @param {string} routePath
* @param {Array<Object<string>} params - Key, Value object detailing the param name (key) and value (value). * @param {Array<Object<string>} params - Key, Value object detailing the param name (key) and value (value).
* @param {boolean} requiresCallback - True - add callback function for JSONP/CORS. * @param {boolean} requiresCallback - True - add callback function for JSONP/CORS.
* @param {boolean} isRelativePath - True, create a relative URL (without root). * @param {boolean} isAbsolutePath - True, create a relative URL (without root).
* @returns {string} the url generated * @returns {string} the url generated
* @example * @example
* createRequestUrl("/api/endpoint", [{key:"param", value:"value"}], true, false); * createRequestUrl("/api/endpoint", [{key:"param", value:"value"}], true, false);
* returns: "http://192.168.2.2/api/endpoint?param=value&callback=?" * returns: "http://192.168.2.2/api/endpoint?param=value&callback=?"
*/ */
self.createRequestUrl = function (routePath, params, requiresCallback, isRelativePath) { self.createRequestUrl = function (routePath, params, requiresCallback, isAbsoluteUrl) {
var appender = "?"; var appender = "?";
var url = ""; var url = "";
if (isRelativePath) { if (isAbsoluteUrl) {
url = self.apiEndpoints.root; url = self.apiEndpoints.root;
} }
url = url + routePath; url = url + routePath;
@ -136,6 +132,32 @@
self.dismissAlert = function(data, event) { self.dismissAlert = function(data, event) {
self.errorData(null); self.errorData(null);
}; };
self.setPageSize = function(data) {
if (self.userList().PageSize !== data && self.userList().PageSize !== -1) {
self.setPagination(data, 1);
}
};
self.goToUserPage = function (data) {
if (self.userList().PageNumber !== data && self.userList().PageNumber !== -1) {
self.setPagination(self.userList().PageSize, data);
}
};
self.setPagination = function(pageSize, pageNumber) {
var args = [
{
key: "pageSize",
value: pageSize
},
{
key: "pageNumber",
value: pageNumber
}
];
var url = self.createRequestUrl("users", args, false, false);
location.hash = url;
console.log(url);
};
self.initDatePicker = function (selectedDate) { self.initDatePicker = function (selectedDate) {
$("#weeklyDatePicker").datepicker({ $("#weeklyDatePicker").datepicker({
weekStart: 1, weekStart: 1,
@ -170,8 +192,21 @@
}); });
} }
} }
self.getUserList = function () { self.getUserList = function (pageSize, pageNumber) {
var url = self.createRequestUrl(self.apiEndpoints.getUserList, null, false); var args = null;
if (pageSize && pageNumber) {
args = [
{
key: "pageSize",
value: pageSize
},
{
key: "pageNumber",
value: pageNumber
}
];
}
var url = self.createRequestUrl(self.apiEndpoints.getUserList, args, false);
$.getJSON(url, function (res) { $.getJSON(url, function (res) {
self.userList(res); self.userList(res);
}).fail(function (response, status, error) { }).fail(function (response, status, error) {
@ -251,6 +286,8 @@
Sammy(function () { Sammy(function () {
this.get("#users", function () { this.get("#users", function () {
var query = this.params.query; var query = this.params.query;
var pageSize = this.params.pageSize;
var pageNumber = this.params.pageNumber;
self.chosenMenuItemId("Users"); self.chosenMenuItemId("Users");
self.chosenUserDetails(null); self.chosenUserDetails(null);
self.userList(null); self.userList(null);
@ -258,7 +295,7 @@
if (query) if (query)
self.searchUsers(query); self.searchUsers(query);
else else
self.getUserList(); self.getUserList(pageSize, pageNumber);
self.assignErrorObject(101, "An Error has occurred.. run away!!!", "test"); self.assignErrorObject(101, "An Error has occurred.. run away!!!", "test");
//$.get("http://localhost:3000", { menu: this.params.menu }, self.chosenMenuData); //$.get("http://localhost:3000", { menu: this.params.menu }, self.chosenMenuData);
}); });