diff --git a/public/assets/js/app.js b/public/assets/js/app.js index 143a3ba5..a3cb3f48 100644 --- a/public/assets/js/app.js +++ b/public/assets/js/app.js @@ -23,6 +23,9 @@ var PHPCensor = { PHPCensor.intervals.getProjectBuilds = setInterval(PHPCensor.getProjectBuilds, 10000); } + PHPCensor.intervals.getDashboard = setInterval(PHPCensor.getDashboard, 10000); + PHPCensor.intervals.getTimeline = setInterval(PHPCensor.getTimeline, 10000); + PHPCensor.uiUpdated(); }); @@ -33,7 +36,7 @@ var PHPCensor = { getBuilds: function () { $.ajax({ - url: APP_URL + 'build/latest', + url: APP_URL + 'build/ajax-queue', success: function (data) { $(window).trigger('builds-updated', [data]); @@ -45,7 +48,7 @@ var PHPCensor = { getProjectBuilds: function () { $.ajax({ - url: APP_URL + 'project/builds/' + PROJECT_ID + '?branch=' + PROJECT_BRANCH + '&per_page=' + PER_PAGE, + url: APP_URL + 'project/ajax-builds/' + PROJECT_ID + '?branch=' + PROJECT_BRANCH + '&per_page=' + PER_PAGE, success: function (data) { $('#latest-builds').html(data); @@ -55,6 +58,34 @@ var PHPCensor = { }); }, + getDashboard: function () { + $('.project-box').each(function(index) { + var projectId = this.id.substring(12); + + $.ajax({ + url: APP_URL + 'project/ajax-dashboard-project/' + projectId, + + success: function (data) { + $(('#project-box-' + projectId)).html(data); + }, + + error: PHPCensor.handleFailedAjax + }); + }); + }, + + getTimeline: function () { + $.ajax({ + url: APP_URL + 'build/ajax-timeline', + + success: function (data) { + $('#timeline-box').html(data); + }, + + error: PHPCensor.handleFailedAjax + }); + }, + updateHeaderBuilds: function (data) { $('.app-pending-list').empty(); $('.app-running-list').empty(); @@ -411,7 +442,7 @@ function setupProjectForm() $.ajax({ dataType: "json", - url: window.APP_URL + 'project/github-repositories', + url: window.APP_URL + 'project/ajax-github-repositories', success: function (data) { $('#loading').hide(); diff --git a/public/assets/js/build.js b/public/assets/js/build.js index fad4fd4a..bb8a96ac 100644 --- a/public/assets/js/build.js +++ b/public/assets/js/build.js @@ -72,14 +72,14 @@ var Build = Class.extend({ registerQuery: function(name, seconds, query) { var self = this; - var uri = 'build/meta/' + self.buildId; + var uri = 'build/ajax-meta/' + self.buildId; var query = query || {}; var cb = function() { var fullUri = window.APP_URL + uri; if (name == 'build-updated') { - fullUri = window.APP_URL + 'build/data/' + self.buildId; + fullUri = window.APP_URL + 'build/ajax-data/' + self.buildId; } $.ajax({ diff --git a/src/B8Framework/Http/Router.php b/src/B8Framework/Http/Router.php index 256db752..aa651c55 100644 --- a/src/B8Framework/Http/Router.php +++ b/src/B8Framework/Http/Router.php @@ -29,8 +29,8 @@ class Router public function __construct(Application $application, Request $request, Config $config) { $this->application = $application; - $this->request = $request; - $this->config = $config; + $this->request = $request; + $this->config = $config; } public function clearRoutes() diff --git a/src/PHPCensor/Controller/BuildController.php b/src/PHPCensor/Controller/BuildController.php index a84276d1..714e60c7 100644 --- a/src/PHPCensor/Controller/BuildController.php +++ b/src/PHPCensor/Controller/BuildController.php @@ -124,43 +124,6 @@ class BuildController extends Controller return $rtn; } - /** - * AJAX call to get build data: - */ - public function data($buildId) - { - $response = new JsonResponse(); - $build = BuildFactory::getBuildById($buildId); - - if (!$build) { - $response->setResponseCode(404); - $response->setContent([]); - return $response; - } - - $response->setContent($this->getBuildData($build)); - return $response; - } - - /** - * AJAX call to get build meta: - */ - public function meta($buildId) - { - $build = BuildFactory::getBuildById($buildId); - $key = $this->getParam('key', null); - $numBuilds = $this->getParam('num_builds', 1); - $data = null; - - if ($key && $build) { - $data = $this->buildStore->getMeta($key, $build->getProjectId(), $buildId, $build->getBranch(), $numBuilds); - } - - $response = new JsonResponse(); - $response->setContent($data); - return $response; - } - /** * Get build data from database and json encode it: */ @@ -208,6 +171,7 @@ class BuildController extends Controller $response = new b8\Http\Response\RedirectResponse(); $response->setHeader('Location', APP_URL.'build/view/' . $build->getId()); + return $response; } @@ -228,6 +192,7 @@ class BuildController extends Controller $response = new b8\Http\Response\RedirectResponse(); $response->setHeader('Location', APP_URL.'project/view/' . $build->getProjectId()); + return $response; } @@ -239,21 +204,6 @@ class BuildController extends Controller return AnsiConverter::convert($log); } - /** - * Allows the UI to poll for the latest running and pending builds. - */ - public function latest() - { - $rtn = [ - 'pending' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_NEW)), - 'running' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_RUNNING)), - ]; - - $response = new JsonResponse(); - $response->setContent($rtn); - return $response; - } - /** * Formats a list of builds into rows suitable for the dropdowns in the PHPCI header bar. * @param $builds @@ -278,4 +228,64 @@ class BuildController extends Controller ksort($rtn['items']); return $rtn; } + + public function ajaxData($buildId) + { + $response = new JsonResponse(); + $build = BuildFactory::getBuildById($buildId); + + if (!$build) { + $response->setResponseCode(404); + $response->setContent([]); + return $response; + } + + $response->setContent($this->getBuildData($build)); + return $response; + } + + public function ajaxMeta($buildId) + { + $build = BuildFactory::getBuildById($buildId); + $key = $this->getParam('key', null); + $numBuilds = $this->getParam('num_builds', 1); + $data = null; + + if ($key && $build) { + $data = $this->buildStore->getMeta($key, $build->getProjectId(), $buildId, $build->getBranch(), $numBuilds); + } + + $response = new JsonResponse(); + $response->setContent($data); + return $response; + } + + public function ajaxQueue() + { + $rtn = [ + 'pending' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_NEW)), + 'running' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_RUNNING)), + ]; + + $response = new JsonResponse(); + $response->setContent($rtn); + + return $response; + } + + public function ajaxTimeline() + { + $builds = $this->buildStore->getLatestBuilds(null, 10); + foreach ($builds as &$build) { + $build = BuildFactory::getBuild($build); + } + + $view = new b8\View('Home/ajax-timeline'); + $view->builds = $builds; + + $this->response->disableLayout(); + $this->response->setContent($view->render()); + + return $this->response; + } } diff --git a/src/PHPCensor/Controller/HomeController.php b/src/PHPCensor/Controller/HomeController.php index 9aa3c427..19f6cfc8 100644 --- a/src/PHPCensor/Controller/HomeController.php +++ b/src/PHPCensor/Controller/HomeController.php @@ -44,8 +44,8 @@ class HomeController extends Controller */ public function init() { - $this->buildStore = b8\Store\Factory::getStore('Build'); - $this->projectStore = b8\Store\Factory::getStore('Project'); + $this->buildStore = b8\Store\Factory::getStore('Build'); + $this->projectStore = b8\Store\Factory::getStore('Project'); $this->groupStore = b8\Store\Factory::getStore('ProjectGroup'); } @@ -61,33 +61,12 @@ class HomeController extends Controller $build = BuildFactory::getBuild($build); } - $this->view->builds = $builds; + $this->view->builds = $builds; $this->view->groups = $this->getGroupInfo(); return $this->view->render(); } - /** - * AJAX get latest builds table (HTML) - */ - public function latest() - { - $this->response->disableLayout(); - $this->response->setContent($this->getLatestBuildsHtml()); - return $this->response; - } - - /** - * Ajax request for the project overview section of the dashboard. - */ - public function summary() - { - $this->response->disableLayout(); - $projects = $this->projectStore->getWhere([], 50, 0, [], ['title' => 'ASC']); - $this->response->setContent($this->getSummaryHtml($projects)); - return $this->response; - } - /** * Generate the HTML for the project overview section of the dashboard. * @param $projects @@ -119,29 +98,12 @@ class HomeController extends Controller $failures[$project->getId()] = $failure; } - $summaryView = new b8\View('SummaryTable'); - $summaryView->projects = $projects; - $summaryView->builds = $summaryBuilds; - $summaryView->successful = $successes; - $summaryView->failed = $failures; - $summaryView->counts = $counts; - - return $summaryView->render(); - } - - /** - * Get latest builds and render as a table. - */ - protected function getLatestBuildsHtml() - { - $builds = $this->buildStore->getWhere([], 5, 0, [], ['id' => 'DESC']); - $view = new b8\View('BuildsTable'); - - foreach ($builds['items'] as &$build) { - $build = BuildFactory::getBuild($build); - } - - $view->builds = $builds['items']; + $view = new b8\View('Home/dashboard-projects'); + $view->projects = $projects; + $view->builds = $summaryBuilds; + $view->successful = $successes; + $view->failed = $failures; + $view->counts = $counts; return $view->render(); } @@ -152,15 +114,15 @@ class HomeController extends Controller */ protected function getGroupInfo() { - $rtn = []; + $rtn = []; $groups = $this->groupStore->getWhere([], 100, 0, [], ['title' => 'ASC']); foreach ($groups['items'] as $group) { - $thisGroup = ['title' => $group->getTitle()]; - $projects = $this->projectStore->getByGroupId($group->getId()); + $thisGroup = ['title' => $group->getTitle()]; + $projects = $this->projectStore->getByGroupId($group->getId()); $thisGroup['projects'] = $projects['items']; - $thisGroup['summary'] = $this->getSummaryHtml($thisGroup['projects']); - $rtn[] = $thisGroup; + $thisGroup['summary'] = $this->getSummaryHtml($thisGroup['projects']); + $rtn[] = $thisGroup; } return $rtn; diff --git a/src/PHPCensor/Controller/ProjectController.php b/src/PHPCensor/Controller/ProjectController.php index 52959f07..c9abbf0c 100644 --- a/src/PHPCensor/Controller/ProjectController.php +++ b/src/PHPCensor/Controller/ProjectController.php @@ -142,24 +142,6 @@ class ProjectController extends PHPCensor\Controller return $response; } - /** - * AJAX get latest builds. - * - * @param int $projectId - * - * @return b8\Http\Response - */ - public function builds($projectId) - { - $branch = $this->getParam('branch', ''); - $perPage = (integer)$this->getParam('per_page', 10); - $builds = $this->getLatestBuildsHtml($projectId, urldecode($branch), 0, $perPage); - - $this->response->disableLayout(); - $this->response->setContent($builds[0]); - return $this->response; - } - /** * Render latest builds for project as HTML table. * @@ -179,7 +161,7 @@ class ProjectController extends PHPCensor\Controller $order = ['id' => 'DESC']; $builds = $this->buildStore->getWhere($criteria, $perPage, $start, [], $order); - $view = new b8\View('BuildsTable'); + $view = new b8\View('Project/ajax-builds'); foreach ($builds['items'] as &$build) { $build = BuildFactory::getBuild($build); @@ -190,6 +172,35 @@ class ProjectController extends PHPCensor\Controller return [$view->render(), $builds['count']]; } + /** + * Render latest builds for project as HTML table. + * + * @param int $projectId + * + * @return array + */ + protected function getDashboardProjectHtml($projectId) + { + $count = $this->buildStore->getWhere( + ['project_id' => $projectId], + 1, + 0, + [], + ['id' => 'DESC'] + ); + $counts = $count['count']; + + $view = new b8\View('Home/ajax-dashboard-project'); + + $view->project = $this->projectStore->getById($projectId); + $view->builds = $this->buildStore->getLatestBuilds($projectId); + $view->successful = $this->buildStore->getLastBuildByStatus($projectId, PHPCensor\Model\Build::STATUS_SUCCESS); + $view->failed = $this->buildStore->getLastBuildByStatus($projectId, PHPCensor\Model\Build::STATUS_FAILED); + $view->counts = $counts; + + return $view->render(); + } + /** * Add a new project. Handles both the form, and processing. */ @@ -215,7 +226,7 @@ class ProjectController extends PHPCensor\Controller $form = $this->projectForm($values); if ($method != 'POST' || ($method == 'POST' && !$form->validate())) { - $view = new b8\View('ProjectForm'); + $view = new b8\View('Project/edit'); $view->type = 'add'; $view->project = null; $view->form = $form; @@ -278,7 +289,7 @@ class ProjectController extends PHPCensor\Controller $form = $this->projectForm($values, 'edit/' . $projectId); if ($method != 'POST' || ($method == 'POST' && !$form->validate())) { - $view = new b8\View('ProjectForm'); + $view = new b8\View('Project/edit'); $view->type = 'edit'; $view->project = $project; $view->form = $form; @@ -403,18 +414,6 @@ class ProjectController extends PHPCensor\Controller return $form; } - /** - * Get an array of repositories from Github's API. - */ - protected function githubRepositories() - { - $github = new Github(); - - $response = new b8\Http\Response\JsonResponse(); - $response->setContent($github->getRepositories()); - return $response; - } - /** * Get the validator to use to check project references. * @param $values @@ -457,4 +456,48 @@ class ProjectController extends PHPCensor\Controller return true; }; } + + /** + * @param int $projectId + * + * @return b8\Http\Response + */ + public function ajaxBuilds($projectId) + { + $branch = $this->getParam('branch', ''); + $perPage = (integer)$this->getParam('per_page', 10); + $builds = $this->getLatestBuildsHtml($projectId, urldecode($branch), 0, $perPage); + + $this->response->disableLayout(); + $this->response->setContent($builds[0]); + return $this->response; + } + + /** + * @param int $projectId + * + * @return b8\Http\Response + */ + public function ajaxDashboardProject($projectId) + { + $builds = $this->getDashboardProjectHtml($projectId); + + $this->response->disableLayout(); + $this->response->setContent($builds); + + return $this->response; + } + + /** + * Get an array of repositories from Github's API. + */ + public function ajaxGithubRepositories() + { + $github = new Github(); + + $response = new b8\Http\Response\JsonResponse(); + $response->setContent($github->getRepositories()); + + return $response; + } } diff --git a/src/PHPCensor/Controller/UserController.php b/src/PHPCensor/Controller/UserController.php index b151ac83..67b619dd 100644 --- a/src/PHPCensor/Controller/UserController.php +++ b/src/PHPCensor/Controller/UserController.php @@ -166,7 +166,7 @@ class UserController extends Controller $form = $this->userForm($values); if ($method != 'POST' || ($method == 'POST' && !$form->validate())) { - $view = new b8\View('UserForm'); + $view = new b8\View('User/edit'); $view->type = 'add'; $view->user = null; $view->form = $form; @@ -208,7 +208,7 @@ class UserController extends Controller $form = $this->userForm($values, 'edit/' . $userId); if ($method != 'POST' || ($method == 'POST' && !$form->validate())) { - $view = new b8\View('UserForm'); + $view = new b8\View('User/edit'); $view->type = 'edit'; $view->user = $user; $view->form = $form; diff --git a/src/PHPCensor/View/Home/ajax-dashboard-project.phtml b/src/PHPCensor/View/Home/ajax-dashboard-project.phtml new file mode 100644 index 00000000..61bf3416 --- /dev/null +++ b/src/PHPCensor/View/Home/ajax-dashboard-project.phtml @@ -0,0 +1,132 @@ +getStatus(); + switch($status) { + case 0: + $subcls = 'blue'; + break; + case 1: + $subcls = 'yellow'; + break; + case 2: + $subcls = 'green'; + break; + case 3: + $subcls = 'red'; + break; + } + // Use the last 5 builds to determine project health: + $failures = 0; + + foreach ($builds as $build) { + switch ($build->getStatus()) { + case 0: + $statuses[] = 'pending'; + break; + case 1: + $statuses[] = 'running'; + break; + case 2: + $statuses[] = 'ok'; + $success = is_null($success) && !is_null($build->getFinished()) ? Lang::formatDateTime($build->getFinished()) : $success; + break; + case 3: + $failures++; + $statuses[] = 'failed'; + $failure = is_null($failure) && !is_null($build->getFinished()) ? Lang::formatDateTime($build->getFinished()) : $failure; + break; + } + } +} + +$buildCount = count($builds); +$lastSuccess = $successful; +$lastFailure = $failed; +$message = Lang::get('no_builds_yet'); +$shortMessage = Lang::get('no_builds_yet'); + +if ($buildCount > 0) { + if ($failures > 0) { + $shortMessage = Lang::get('x_of_x_failed_short', $failures, $buildCount); + $message = Lang::get('x_of_x_failed', $failures, $buildCount); + + if (!is_null($lastSuccess) && !is_null($lastSuccess->getFinished())) { + $message .= Lang::get('last_successful_build', Lang::formatDateTime($lastSuccess->getFinished())); + } else { + $message .= Lang::get('never_built_successfully'); + } + } else { + $message = Lang::get('all_builds_passed', $buildCount); + $shortMessage = Lang::get('all_builds_passed_short', $buildCount, $buildCount); + + if (!is_null($lastFailure) && !is_null($lastFailure->getFinished())) { + $message .= Lang::get('last_failed_build', Lang::formatDateTime($lastFailure->getFinished())); + } else { + $message .= Lang::get('never_failed_build'); + } + } +} + +?> + +
+ +
+

+ + getTitle(); ?> + +

+ +

+ +

+ +
+
+ +
+ + () + + + '; + } else { + $build = $builds[$idx]; + $link = APP_URL . 'build/view/' . $build->id; + switch ($build->getStatus()) { + case 0: + $class = 'bg-blue'; + $icon = 'fa-minus'; + break; + case 1: + $class = 'bg-yellow'; + $icon = 'fa-clock-o'; + break; + case 2: + $class = 'bg-green'; + $icon = 'fa-check'; + break; + case 3: + $class = 'bg-red'; + $icon = 'fa-times'; + break; + } + echo ''; + } + } ?> +
+
diff --git a/src/PHPCensor/View/Home/ajax-timeline.phtml b/src/PHPCensor/View/Home/ajax-timeline.phtml new file mode 100644 index 00000000..94dce271 --- /dev/null +++ b/src/PHPCensor/View/Home/ajax-timeline.phtml @@ -0,0 +1,88 @@ + + diff --git a/src/PHPCensor/View/SummaryTable.phtml b/src/PHPCensor/View/Home/dashboard-projects.phtml similarity index 98% rename from src/PHPCensor/View/SummaryTable.phtml rename to src/PHPCensor/View/Home/dashboard-projects.phtml index c1fb9c41..ac4c792c 100644 --- a/src/PHPCensor/View/SummaryTable.phtml +++ b/src/PHPCensor/View/Home/dashboard-projects.phtml @@ -80,7 +80,7 @@ foreach($projects as $project): } ?> - +
@@ -131,5 +131,6 @@ foreach($projects as $project): } ?>
+
diff --git a/src/PHPCensor/View/Home/index.phtml b/src/PHPCensor/View/Home/index.phtml index b504e319..523dd6a7 100644 --- a/src/PHPCensor/View/Home/index.phtml +++ b/src/PHPCensor/View/Home/index.phtml @@ -21,7 +21,7 @@

-
+