resolves #38: implement pagination for the job page

pull/70/head
Oliver Giles 6 years ago
parent d1ca6392a4
commit a0f586581d

@ -60,6 +60,7 @@ struct MonitorScope {
Type type;
std::string job;
uint num = 0;
uint page = 0;
};
// Represents a (websocket) client that wants to be notified about events

@ -195,9 +195,10 @@ void Laminar::sendStatus(LaminarClient* client) {
populateArtifacts(j, client->scope.job, client->scope.num);
j.EndArray();
} else if(client->scope.type == MonitorScope::JOB) {
const uint runsPerPage = 10;
j.startArray("recent");
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 25")
.bind(client->scope.job)
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT ?,?")
.bind(client->scope.job, client->scope.page * runsPerPage, runsPerPage)
.fetch<uint,time_t,time_t,int,str>([&](uint build,time_t started,time_t completed,int result,str reason){
j.StartObject();
j.set("number", build)
@ -208,6 +209,11 @@ void Laminar::sendStatus(LaminarClient* client) {
.EndObject();
});
j.EndArray();
db->stmt("SELECT COUNT(*) FROM builds WHERE name = ?")
.bind(client->scope.job)
.fetch<uint>([&](uint nRuns){
j.set("pages", (nRuns-1) / runsPerPage + 1);
});
j.startArray("running");
auto p = activeJobs.byJobName().equal_range(client->scope.job);
for(auto it = p.first; it != p.second; ++it) {

@ -189,6 +189,11 @@
<td class="text-center hidden-xs">{{job.reason}}</td>
</tr>
</table>
<ul class="pagination pull-right">
<li><button class="btn btn-default" v-on:click="page_prev" :disabled="page==0">&laquo;</button></li>
<li>Page {{page+1}} of {{pages}}</li>
<li><button class="btn btn-default" v-on:click="page_next" :disabled="page==pages-1">&raquo;</button></li>
</ul>
</div></div>
</div>
</div></template>

@ -21,8 +21,10 @@ const WebsocketHandler = function() {
// "status" is the first message the websocket always delivers.
// Use this to confirm the navigation. The component is not
// created until next() is called, so creating a reference
// for other message types must be deferred
if (msg.type === 'status') {
// for other message types must be deferred. Also check that
// the reference is not already created, this allows a subsequent
// status message to be handled as an update.
if (msg.type === 'status' && !this.comp) {
next(comp => {
// Set up bidirectional reference
// 1. needed to reference the component for other msg types
@ -394,6 +396,8 @@ var Job = function() {
lastSuccess: null,
lastFailed: null,
nQueued: 0,
pages: 0,
page: 0
};
return Vue.extend({
template: '#job',
@ -408,6 +412,7 @@ var Job = function() {
state.lastSuccess = msg.lastSuccess;
state.lastFailed = msg.lastFailed;
state.nQueued = msg.nQueued;
state.pages = msg.pages;
var chtBt = new Chart(document.getElementById("chartBt").getContext("2d")).Bar({
labels: msg.recent.map(function(e) {
@ -454,6 +459,12 @@ var Job = function() {
break;
}
}
},
page_next: function() {
this.ws.send(JSON.stringify({page:++state.page}));
},
page_prev: function() {
this.ws.send(JSON.stringify({page:--state.page}));
}
}
});

@ -36,6 +36,8 @@
#include <sys/signal.h>
#include <sys/signalfd.h>
#include <rapidjson/document.h>
// Size of buffer used to read from file descriptors. Should be
// a multiple of sizeof(struct signalfd_siginfo) == 128
#define PROC_IO_BUFSIZE 4096
@ -213,11 +215,18 @@ public:
// wss.set_access_channels(websocketpp::log::alevel::all);
// wss.set_error_channels(websocketpp::log::elevel::all);
// TODO: This could be used in the future to trigger actions on the
// server in response to a web client request. Currently not supported.
// wss.set_message_handler([](std::weak_ptr<void> s, websocket::message_ptr msg){
// msg->get_payload();
// });
// Handle incoming websocket message
wss.set_message_handler([this](websocketpp::connection_hdl hdl, websocket::message_ptr msg){
websocket::connection_ptr c = wss.get_con_from_hdl(hdl);
std::string payload = msg->get_payload();
rapidjson::Document d;
d.ParseInsitu(const_cast<char*>(payload.data()));
if(d.HasMember("page") && d["page"].IsInt()) {
int page = d["page"].GetInt();
c->lc->scope.page = page;
laminar.sendStatus(c->lc);
}
});
// Handle plain HTTP requests by delivering the binary resource
wss.set_http_handler([this](websocketpp::connection_hdl hdl){

Loading…
Cancel
Save