Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

server side project list paging #431

Merged
merged 1 commit into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/common/db-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ async function scan(model, scanParams) {
});
}

/**
* Get data collection by scan parameters with paging
* @param {Object} model The dynamoose model to scan
* @param {Object} scanParams The scan parameters object
* @param {String} size The size of result
* @param {String} lastKey The lastKey param
* @returns {Promise<void>}
*/
async function scanWithLimit(model, scanParams, size, lastKey) {
return await new Promise((resolve, reject) => {
const scanMethod = model.scan(scanParams).limit(size);
if (lastKey) scanMethod.startAt(lastKey);
scanMethod.exec((err, result) => {
if (err) {
logger.error(`DynamoDB scan error ${err}`);
return reject(err);
}
return resolve(result.count === 0 ? [] : result);
});
});
}

/**
* Get data collection by scan parameters with paging
* @param {Object} model The dynamoose model to scan
Expand All @@ -91,6 +113,25 @@ async function scanAll(model, size, lastKey) {
});
}

/**
* Get data collection by scan parameters
* @param {Object} model The dynamoose model to scan
* @param {Object} scanParams The scan parameters object
* @returns {Promise<void>}
*/
async function scanAllWithParams(model, scanParams) {
return await new Promise((resolve, reject) => {
model.scan(scanParams).all().exec((err, result) => {
if (err) {
logger.error(`DynamoDB scan error ${err}`);
return reject(err);
}

return resolve(result.count === 0 ? [] : result);
});
});
}

/**
* Get data collection by scan with search
* @param {Object} model The dynamoose model to scan
Expand Down Expand Up @@ -544,6 +585,8 @@ module.exports = {
scan,
scanAll,
scanAllWithSearch,
scanWithLimit,
scanAllWithParams,
create,
update,
removeById,
Expand Down
10 changes: 10 additions & 0 deletions src/controllers/ProjectController.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ async function getAll(req) {
return await ProjectService.getAll(req.query, req.currentUser);
}

/**
* search all projects
* @param {Object} req the request
* @returns {Array} the result
*/
async function search(req) {
return await ProjectService.search(req.query, req.currentUser);
}

/**
* create label
* @param {Object} req the request
Expand Down Expand Up @@ -126,6 +135,7 @@ module.exports = {
createHook,
addWikiRules,
transferOwnerShip,
search,
};

helper.buildController(module.exports);
2 changes: 1 addition & 1 deletion src/front/src/app/main/main.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ angular.module('topcoderX')

//private function to get projects.
$scope.getProjects = function (status) {
ProjectService.getProjects(status, false).then(function (response) {
ProjectService.getProjects(status, false, 1).then(function (response) {
$scope.projects = response.data;
if (!$scope.projects || $scope.projects.length === 0) {
$scope.showTutorial();
Expand Down
11 changes: 8 additions & 3 deletions src/front/src/app/projects/project.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@ angular.module('topcoderX')
};

/**
* Get all projects
* Get projects
*/
ProjectService.getProjects = function (status, showAll) {
var url = Helper.baseUrl + '/api/v1/projects?status=' + status + '&showAll=' + showAll;
ProjectService.getProjects = function (status, showAll, perPage, lastKey, query) {
var url = Helper.baseUrl + '/api/v1/projects?status=' + status + '&showAll=' + showAll + '&perPage=' + perPage +
(lastKey ? '&lastKey=' + lastKey : '' );
if (query) {
url = Helper.baseUrl + '/api/v1/projects/search?status=' + status + '&showAll=' + showAll + '&perPage=' + perPage +
'&query=' + query;
}
if (projectsGetLock[url]) {
return projectsDataPromise[url];
}
Expand Down
120 changes: 88 additions & 32 deletions src/front/src/app/projects/projects.controller.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';

angular.module('topcoderX')
.controller('ProjectsController', ['currentUser', '$scope', '$state', 'ProjectService', '$filter', '$rootScope', 'Alert', 'Helper', '$timeout',
function (currentUser, $scope, $state, ProjectService, $filter, $rootScope, Alert, Helper, $timeout) {
.controller('ProjectsController', ['currentUser', '$scope', '$state', 'ProjectService', '$filter', '$rootScope', 'Alert', 'Helper',
function (currentUser, $scope, $state, ProjectService, $filter, $rootScope, Alert, Helper) {
//Current title
$scope.title = 'Project Management';

Expand All @@ -15,6 +15,15 @@ angular.module('topcoderX')
$scope.state = {
status: 'active',
};
$scope.tableConfig = {
pageNumber: 1,
pageSize: 10,
isLoading: false,
initialized: false,
query: '',
lastKey: [],
pages: 1
};

//go to a project detail
$scope.goProject = function (project) {
Expand Down Expand Up @@ -44,13 +53,27 @@ angular.module('topcoderX')
$scope.state.status = status;
$scope.isLoaded = false;
$scope.projects = [];
ProjectService.getProjects(status, $scope.filter.showAll).then(function (response) {
ProjectService.getProjects(
status, $scope.filter.showAll,
$scope.tableConfig.pageSize, $scope.tableConfig.lastKey[$scope.tableConfig.pageNumber],
$scope.tableConfig.query).then(function (response) {
var config = $scope.tableConfig;

if (config.query) {
config.allItems = response.data.docs;
$scope.projects = config.allItems.slice(0, config.pageSize);
config.pages = Math.ceil(config.allItems.length / config.pageSize);
}
else {
$scope.projects = response.data.docs;
}
if (response.data.lastKey) {
config.lastKey[config.pageNumber + 1] = response.data.lastKey;
if (!config.pages || config.pages <= config.pageNumber) {
config.pages = config.pageNumber + 1;
}
}
$scope.isLoaded = true;
$scope.projects = response.data;
$scope.allProjects = angular.copy($scope.projects);
$timeout(function () {
$scope.init();
}, 1000);
}).catch(function (error) {
$scope.isLoaded = true;
if (error.data) {
Expand All @@ -61,6 +84,51 @@ angular.module('topcoderX')
});
};

/**
* get the number array that shows the pagination bar
*/
$scope.getPageArray = function () {
var res = [];

var pageNo = $scope.tableConfig.pageNumber;
var i = pageNo - 5;
for (i; i <= pageNo; i++) {
if (i > 0) {
res.push(i);
}
}
var j = pageNo + 1;
for (j; j <= $scope.tableConfig.pages && j <= pageNo + 5; j++) {
res.push(j);
}
return res;
};

/**
* handles the change page click
* @param {Number} pageNumber the page number
*/
$scope.changePage = function (pageNumber) {
if (pageNumber === 0 || pageNumber > $scope.tableConfig.pages ||
(pageNumber === $scope.tableConfig.pages &&
$scope.tableConfig.pageNumber === pageNumber)) {
return false;
}
$scope.tableConfig.pageNumber = pageNumber;
if ($scope.tableConfig.query && $scope.tableConfig.allItems) {
var start = ($scope.tableConfig.pageNumber - 1) * $scope.tableConfig.pageSize - 1;
if (pageNumber === 1) {
start = 0;
}
$scope.projects = $scope.tableConfig.allItems.slice(
start, $scope.tableConfig.pageSize);
$scope.isLoaded = true;
}
else {
$scope.getProjects($scope.state.status);
}
};

$scope.repoType = function (repo) {
if (repo.toLocaleLowerCase().indexOf("github") >= 0) {
return "Github";
Expand All @@ -82,31 +150,19 @@ angular.module('topcoderX')
$scope.getProjects($scope.state.status);
};


$scope.onSearchChange = function (obj) {
$scope.searchText = obj.searchText;
if (!obj.searchText || obj.searchText.length === 0) {
$scope.getProjects($scope.state.status);
}

if ($scope.allProjects.length > 0) {
_searchLocal(obj.searchText);
}
};

$scope.onSearchIconClicked = function () {
if ($scope.allProjects.length > 0 && $scope.searchText) {
_searchLocal($scope.searchText);
}
$scope.tableConfig.pageNumber = 1;
$scope.tableConfig.pages = 1;
$scope.tableConfig.allItems = [];
$scope.getProjects($scope.state.status);
};

function _searchLocal(query) {
$scope.projects = $scope.allProjects.filter(function(value) {
return value['title'].toLowerCase().includes(query.toLowerCase());
})
$timeout(function () {
$('.footable').filter('[data-page="0"]').trigger('click');
}, 1000);
}

$scope.onSearchReset = function () {
var config = $scope.tableConfig;
config.query = '';
config.pageNumber = 1;
config.pages = 1;
config.allItems = [];
$scope.getProjects($scope.state.status);
};
}]);
62 changes: 48 additions & 14 deletions src/front/src/app/projects/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ <h2>{{title}}</h2>
<uib-tab index="0" heading="Current Projects" select="getProjects('active')">
<br />
<div ng-if="isLoaded">
<div ng-show="allProjects.length===0">
<div ng-show="projects.length===0 && !tableConfig.query">
<div class="text-center m-t-lg">
<h4>You don't have active projects right now. Please
<button class="btn btn-sm btn-info" ng-click="goProject()">
Expand All @@ -41,15 +41,18 @@ <h4>You don't have active projects right now. Please
</h4>
</div>
</div>
<div ng-hide="allProjects.length===0">
<div ng-hide="projects.length===0 && !tableConfig.query">
<div class="col-lg-4" style="padding-left: 0px">
<div class="input-group custom-search-form">
<input ng-model="searchText" type="text" class="form-control" placeholder="Find projects" ng-change="onSearchChange(this)">
<input ng-model="tableConfig.query" type="text" class="form-control" placeholder="Find projects" ng-keyup="$event.keyCode == 13 && onSearchIconClicked()">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-click="onSearchIconClicked('github')">
<button class="btn btn-default" type="button" ng-click="onSearchIconClicked()">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
<button class="btn btn-danger" type="button" ng-click="onSearchReset()">
<span class="glyphicon glyphicon-remove"></span>
</button>
</span>
</div>
</div>
<table class="footable table table-stripped toggle-arrow-tiny"
Expand Down Expand Up @@ -94,10 +97,24 @@ <h4>You don't have active projects right now. Please
</td>
</tr>
</tbody>
<tfoot ng-hide="searchText">
<tfoot>
<tr>
<td colspan="{{isAdminUser? 5: 4}}">
<ul class="pagination pull-right"></ul>
<td colspan="5">
<ul class="pagination pull-right">
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === 1}">
<a ng-click="changePage(1)">«</a>
</li>
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === 1}">
<a ng-click="changePage(tableConfig.pageNumber - 1)">‹</a>
</li>
<li class="footable-page" ng-class="{'active' : item === tableConfig.pageNumber}"
ng-repeat="item in getPageArray()">
<a ng-click="changePage(item)">{{item}}</a>
</li>
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === tableConfig.pages}">
<a ng-click="changePage(tableConfig.pageNumber + 1)">›</a>
</li>
</ul>
</td>
</tr>
</tfoot>
Expand All @@ -108,17 +125,20 @@ <h4>You don't have active projects right now. Please
<uib-tab index="1" heading="Archived Projects" select="getProjects('archived')">
<br />
<div ng-if="isLoaded">
<div ng-show="allProjects.length===0" class="text-center m-t-lg">
<div ng-show="projects.length===0 && !tableConfig.query" class="text-center m-t-lg">
<p>No projects have been archived.</p>
</div>
<div ng-hide="allProjects.length===0">
<div ng-hide="projects.length===0 && !tableConfig.query">
<div class="col-lg-4" style="padding-left: 0px">
<div class="input-group custom-search-form">
<input ng-model="searchText" type="text" class="form-control" placeholder="Find projects" ng-change="onSearchChange(this)">
<input ng-model="tableConfig.query" type="text" class="form-control" placeholder="Find projects" ng-keyup="$event.keyCode == 13 && onSearchIconClicked()">
<span class="input-group-btn">
<button class="btn btn-default" type="button" ng-click="onSearchIconClicked()">
<span class="glyphicon glyphicon-search"></span>
</button>
<button class="btn btn-danger" type="button" ng-click="onSearchReset()">
<span class="glyphicon glyphicon-remove"></span>
</button>
</span>
</div>
</div>
Expand Down Expand Up @@ -148,10 +168,24 @@ <h4>You don't have active projects right now. Please
</td>
</tr>
</tbody>
<tfoot ng-hide="searchText">
<tfoot>
<tr>
<td colspan="{{isAdminUser? 5: 4}}">
<ul class="pagination pull-right"></ul>
<td colspan="5">
<ul class="pagination pull-right">
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === 1}">
<a ng-click="changePage(1)">«</a>
</li>
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === 1}">
<a ng-click="changePage(tableConfig.pageNumber - 1)">‹</a>
</li>
<li class="footable-page" ng-class="{'active' : item === tableConfig.pageNumber}"
ng-repeat="item in getPageArray()">
<a ng-click="changePage(item)">{{item}}</a>
</li>
<li class="footable-page-arrow" ng-class="{'disabled': tableConfig.pageNumber === tableConfig.pages}">
<a ng-click="changePage(tableConfig.pageNumber + 1)">›</a>
</li>
</ul>
</td>
</tr>
</tfoot>
Expand Down
6 changes: 6 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ module.exports = {
method: 'update',
},
},
'/projects/search': {
get: {
controller: 'ProjectController',
method: 'search',
},
},
'/projects/label': {
post: {
controller: 'ProjectController',
Expand Down
Loading