Added Paginator for build errors. Issue #85.

This commit is contained in:
Dmitry Khomutov 2017-10-29 14:06:41 +07:00
commit 6b102f214e
No known key found for this signature in database
GPG key ID: EC19426474B37AAC
8 changed files with 190 additions and 117 deletions

View file

@ -22,7 +22,7 @@ var Build = Class.extend({
self.buildData = data.queryData;
// If the build has finished, stop updating every 10 seconds:
// If the build has finished, stop updating every 5 seconds:
if (self.buildData && self.buildData.status > 1) {
self.cancelQuery('build-updated');
$(window).trigger({type: 'build-complete'});
@ -34,6 +34,7 @@ var Build = Class.extend({
$('.build-finished').html(self.buildData.finish_date ? self.buildData.finish_date : '');
$('#log pre').html(self.buildData.log);
$('.errors-table tbody').html(self.buildData.error_html);
$('#paginator').html(self.buildData.paginator);
if (self.buildData.errors == 0) {
$('.errors-label').hide();
@ -77,7 +78,7 @@ var Build = Class.extend({
var fullUri = window.APP_URL + uri;
if (name == 'build-updated') {
fullUri = window.APP_URL + 'build/ajax-data/' + self.buildId;
fullUri = window.APP_URL + 'build/ajax-data/' + self.buildId + '?per_page=' + PER_PAGE + '&page=' + PAGE;
}
$.ajax({

View file

@ -5,11 +5,13 @@ namespace PHPCensor\Controller;
use b8;
use b8\Exception\HttpException\NotFoundException;
use b8\Http\Response\JsonResponse;
use JasonGrimes\Paginator;
use PHPCensor\BuildFactory;
use PHPCensor\Helper\AnsiConverter;
use PHPCensor\Helper\Lang;
use PHPCensor\Model\Build;
use PHPCensor\Model\Project;
use PHPCensor\Model\User;
use PHPCensor\Service\BuildService;
use PHPCensor\Controller;
@ -40,10 +42,16 @@ class BuildController extends Controller
}
/**
* View a specific build.
*/
* View a specific build.
*
* @param integer $buildId
*
* @throws NotFoundException
*/
public function view($buildId)
{
$page = (integer)$this->getParam('page', 1);
try {
$build = BuildFactory::getBuildById($buildId);
} catch (\Exception $ex) {
@ -54,9 +62,24 @@ class BuildController extends Controller
throw new NotFoundException(Lang::get('build_x_not_found', $buildId));
}
$this->view->plugins = $this->getUiPlugins();
$this->view->build = $build;
$this->view->data = $this->getBuildData($build);
/** @var User $user */
$user = $_SESSION['php-censor-user'];
$perPage = $user->getFinalPerPage();
$data = $this->getBuildData($build, (($page - 1) * $perPage), $perPage);
$pages = ($data['errors'] === 0)
? 1
: (integer)ceil($data['errors'] / $perPage);
if ($page > $pages) {
$page = $pages;
}
$this->view->plugins = $this->getUiPlugins();
$this->view->build = $build;
$this->view->data = $data;
$this->view->page = $page;
$this->view->perPage = $perPage;
$this->view->paginator = $this->getPaginatorHtml($buildId, $data['errors'], $perPage, $page);
$this->layout->title = Lang::get('build_n', $buildId);
$this->layout->subtitle = $build->getProjectTitle();
@ -121,9 +144,15 @@ class BuildController extends Controller
}
/**
* Get build data from database and json encode it:
*/
protected function getBuildData(Build $build)
* Get build data from database and json encode it.
*
* @param Build $build
* @param integer $start
* @param integer $perPage
*
* @return array
*/
protected function getBuildData(Build $build, $start = 0, $perPage = 10)
{
$data = [];
$data['status'] = (int)$build->getStatus();
@ -135,19 +164,40 @@ class BuildController extends Controller
/** @var \PHPCensor\Store\BuildErrorStore $errorStore */
$errorStore = b8\Store\Factory::getStore('BuildError');
$errors = $errorStore->getErrorsForBuild($build->getId());
$errors = $errorStore->getByBuildId($build->getId(), $perPage, $start);
$errorView = new b8\View('Build/errors');
$errorView->build = $build;
$errorView->errors = $errors;
$errorView->errors = $errors['items'];
$data['errors'] = $errorStore->getErrorTotalForBuild($build->getId());
$data['errors'] = (integer)$errorStore->getErrorTotalForBuild($build->getId());
$data['error_html'] = $errorView->render();
$data['since'] = (new \DateTime())->format('Y-m-d H:i:s');
return $data;
}
/**
* @param integer $buildId
* @param integer $total
* @param integer $perPage
* @param integer $page
*
* @return string
*/
protected function getPaginatorHtml($buildId, $total, $perPage, $page)
{
$view = new b8\View('pagination');
$urlPattern = APP_URL . 'build/view/' . $buildId;
$urlPattern = $urlPattern . '?' . str_replace('%28%3Anum%29', '(:num)', http_build_query(['page' => '(:num)'])) . '#errors';
$paginator = new Paginator($total, $perPage, $page, $urlPattern);
$view->paginator = $paginator;
return $view->render();
}
/**
* Create a build using an existing build as a template:
*/
@ -230,6 +280,9 @@ class BuildController extends Controller
public function ajaxData($buildId)
{
$page = (integer)$this->getParam('page', 1);
$perPage = (integer)$this->getParam('per_page', 10);
$response = new JsonResponse();
$build = BuildFactory::getBuildById($buildId);
@ -240,7 +293,10 @@ class BuildController extends Controller
return $response;
}
$response->setContent($this->getBuildData($build));
$data = $this->getBuildData($build, (($page - 1) * $perPage), $perPage);
$data['paginator'] = $this->getPaginatorHtml($buildId, $data['errors'], $perPage, $page);
$response->setContent($data);
return $response;
}

View file

@ -94,30 +94,18 @@ class ProjectController extends PHPCensor\Controller
throw new NotFoundException(Lang::get('project_x_not_found', $projectId));
}
$perPage = $_SESSION['php-censor-user']->getFinalPerPage();
/** @var PHPCensor\Model\User $user */
$user = $_SESSION['php-censor-user'];
$perPage = $user->getFinalPerPage();
$builds = $this->getLatestBuildsHtml($projectId, $environment, $branch, (($page - 1) * $perPage), $perPage);
$pages = $builds[1] == 0 ? 1 : (integer)ceil($builds[1] / $perPage);
$pages = ($builds[1] === 0)
? 1
: (integer)ceil($builds[1] / $perPage);
if ($page > $pages) {
$response = new RedirectResponse();
$response->setHeader('Location', APP_URL . 'project/view/' . $projectId);
return $response;
$page = $pages;
}
$urlPattern = APP_URL . 'project/view/' . $project->getId();
$params = [];
if (!empty($branch)) {
$params['branch'] = $branch;
}
if (!empty($environment)) {
$params['environment'] = $environment;
}
$urlPattern = $urlPattern . '?' . str_replace('%28%3Anum%29', '(:num)', http_build_query(array_merge($params, ['page' => '(:num)'])));
$paginator = new Paginator($builds[1], $perPage, $page, $urlPattern);
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
@ -127,7 +115,7 @@ class ProjectController extends PHPCensor\Controller
$this->view->environments = $project->getEnvironmentsNames();
$this->view->page = $page;
$this->view->perPage = $perPage;
$this->view->paginator = $paginator;
$this->view->paginator = $this->getPaginatorHtml($projectId, $branch, $environment, $builds[1], $perPage, $page);
$this->layout->title = $project->getTitle();
$this->layout->subtitle = '';
@ -141,6 +129,38 @@ class ProjectController extends PHPCensor\Controller
return $this->view->render();
}
/**
* @param integer $projectId
* @param string $branch
* @param string $environment
* @param integer $total
* @param integer $perPage
* @param integer $page
*
* @return string
*/
protected function getPaginatorHtml($projectId, $branch, $environment, $total, $perPage, $page)
{
$view = new b8\View('pagination');
$urlPattern = APP_URL . 'project/view/' . $projectId;
$params = [];
if (!empty($branch)) {
$params['branch'] = $branch;
}
if (!empty($environment)) {
$params['environment'] = $environment;
}
$urlPattern = $urlPattern . '?' . str_replace('%28%3Anum%29', '(:num)', http_build_query(array_merge($params, ['page' => '(:num)'])));
$paginator = new Paginator($total, $perPage, $page, $urlPattern);
$view->paginator = $paginator;
return $view->render();
}
/**
* Create a new pending build for a project.
*
@ -259,9 +279,12 @@ class ProjectController extends PHPCensor\Controller
$build = BuildFactory::getBuild($build);
}
$view->builds = $builds['items'];
$view->builds = $builds['items'];
return [$view->render(), $builds['count']];
return [
$view->render(),
(integer)$builds['count']
];
}
/**

View file

@ -60,23 +60,33 @@ class BuildErrorStore extends Store
*
* @param integer $buildId
* @param integer $limit
* @param string $useConnection
* @param integer $offset
*
* @return array
*
* @throws HttpException
*/
public function getByBuildId($buildId, $limit = 1000, $useConnection = 'read')
public function getByBuildId($buildId, $limit = null, $offset = 0)
{
if (is_null($buildId)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{build_error}} WHERE {{build_id}} = :build_id LIMIT :limit';
$stmt = Database::getConnection($useConnection)->prepareCommon($query);
$query = 'SELECT * FROM {{build_error}} WHERE {{build_id}} = :build_id ORDER BY plugin, severity';
if (null !== $limit) {
$query .= ' LIMIT :limit';
}
if ($offset) {
$query .= ' OFFSET :offset';
}
$stmt = Database::getConnection()->prepareCommon($query);
$stmt->bindValue(':build_id', $buildId);
$stmt->bindValue(':limit', (int)$limit, \PDO::PARAM_INT);
if (null !== $limit) {
$stmt->bindValue(':limit', (integer)$limit, \PDO::PARAM_INT);
}
if ($offset) {
$stmt->bindValue(':offset', (integer)$offset, \PDO::PARAM_INT);
}
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
@ -94,46 +104,6 @@ class BuildErrorStore extends Store
}
}
/**
* Get a list of errors for a given build, since a given time.
*
* @param integer $buildId
* @param string $since date string
*
* @return array
*/
public function getErrorsForBuild($buildId, $since = null)
{
$query = 'SELECT * FROM {{build_error}} WHERE {{build_id}} = :build';
if (!is_null($since)) {
$query .= ' AND created_date > :since';
}
$query .= ' LIMIT 15000';
$stmt = Database::getConnection('read')->prepareCommon($query);
$stmt->bindValue(':build', $buildId, \PDO::PARAM_INT);
if (!is_null($since)) {
$stmt->bindValue(':since', $since);
}
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new BuildError($item);
};
$rtn = array_map($map, $res);
return $rtn;
} else {
return [];
}
}
/**
* Gets the total number of errors for a given build.
*

View file

@ -204,6 +204,9 @@ use PHPCensor\Model\Build;
<?php print $data['error_html']; ?>
</tbody>
</table>
<div id="paginator">
<?= $paginator; ?>
</div>
</div>
<div class="tab-pane" id="information">
@ -214,10 +217,21 @@ use PHPCensor\Model\Build;
<script src="<?php print APP_URL; ?>assets/js/build.js"></script>
<script>
var PER_PAGE = <?= $perPage; ?>;
var PAGE = <?= $page; ?>;
var ActiveBuild = new Build(<?php print $build->getId() ?>);
ActiveBuild.setupBuild(<?php print json_encode($data); ?>, <?php print json_encode($build->getFileLinkTemplate()); ?>);
var url = document.location.toString();
if (url.match('#')) {
$('.nav-tabs a[href="#' + url.split('#')[1] + '"]').tab('show');
}
$('.nav-tabs a').on('shown.bs.tab', function (e) {
window.location.hash = e.target.hash;
})
</script>
<?php

View file

@ -124,26 +124,8 @@ use PHPCensor\Helper\Lang;
</tbody>
</table>
</div>
<div>
<ul class="pagination">
<?php if ($paginator->getPrevUrl()): ?>
<li><a href="<?php echo $paginator->getPrevUrl(); ?>"><?= Lang::get('prev_link'); ?></a></li>
<?php endif; ?>
<?php foreach ($paginator->getPages() as $pageArray): ?>
<?php if ($pageArray['url']): ?>
<li <?php echo $pageArray['isCurrent'] ? 'class="active"' : ''; ?>>
<a href="<?php echo $pageArray['url']; ?>"><?php echo $pageArray['num']; ?></a>
</li>
<?php else: ?>
<li class="disabled"><span><?php echo $pageArray['num']; ?></span></li>
<?php endif; ?>
<?php endforeach; ?>
<?php if ($paginator->getNextUrl()): ?>
<li><a href="<?php echo $paginator->getNextUrl(); ?>"><?= Lang::get('prev_link'); ?></a></li>
<?php endif; ?>
</ul>
<div id="paginator">
<?= $paginator; ?>
</div>
</div>

View file

@ -14,6 +14,19 @@
<link href="<?php print APP_URL; ?>assets/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link href="<?php print APP_URL; ?>assets/vendor/ion-icons/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<script src="<?php print APP_URL; ?>assets/js/class.js"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/jQueryUI/jquery-ui.min.js" type="text/javascript"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<link href="<?php print APP_URL; ?>assets/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/chartjs/Chart.min.js" type="text/javascript"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/dist/js/app.min.js" type="text/javascript"></script>
<script src="<?php print APP_URL; ?>assets/vendor/sprintf-js/dist/sprintf.min.js"></script>
<script src="<?php print APP_URL; ?>assets/js/app.js" type="text/javascript"></script>
<script>
var APP_URL = '<?= APP_URL; ?>';
var LANGUAGE = '<?= Lang::getLanguage(); ?>';
@ -25,11 +38,6 @@
<?php endif; ?>
</script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="<?php print APP_URL; ?>assets/js/class.js"></script>
<script src="<?php print APP_URL; ?>assets/vendor/sprintf-js/dist/sprintf.min.js"></script>
<script src="<?php print APP_URL; ?>assets/js/app.js" type="text/javascript"></script>
</head>
<body class="app-layout <?php print !empty($skin) ? 'skin-' . $skin : 'skin-black'; ?>">
<div class="wrapper row-offcanvas row-offcanvas-left">
@ -245,14 +253,5 @@
</section><!-- /.content -->
</aside><!-- /.content-wrapper -->
</div><!-- ./wrapper -->
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/jQueryUI/jquery-ui.min.js" type="text/javascript"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<link href="<?php print APP_URL; ?>assets/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/plugins/chartjs/Chart.min.js" type="text/javascript"></script>
<script src="<?php print APP_URL; ?>assets/vendor/admin-lte/dist/js/app.min.js" type="text/javascript"></script>
</body>
</html>

View file

@ -0,0 +1,28 @@
<?php
use PHPCensor\Helper\Lang;
/**
* @var \JasonGrimes\Paginator $paginator
*/
?>
<ul class="pagination">
<?php if ($paginator->getPrevUrl()): ?>
<li><a href="<?php echo $paginator->getPrevUrl(); ?>"><?= Lang::get('prev_link'); ?></a></li>
<?php endif; ?>
<?php foreach ($paginator->getPages() as $pageArray): ?>
<?php if ($pageArray['url']): ?>
<li <?php echo $pageArray['isCurrent'] ? 'class="active"' : ''; ?>>
<a href="<?php echo $pageArray['url']; ?>"><?php echo $pageArray['num']; ?></a>
</li>
<?php else: ?>
<li class="disabled"><span><?php echo $pageArray['num']; ?></span></li>
<?php endif; ?>
<?php endforeach; ?>
<?php if ($paginator->getNextUrl()): ?>
<li><a href="<?php echo $paginator->getNextUrl(); ?>"><?= Lang::get('prev_link'); ?></a></li>
<?php endif; ?>
</ul>