mirror of
https://github.com/ohwgiles/laminar.git
synced 2024-10-27 20:34:20 +00:00
resolves #38: implement pagination for the job page
This commit is contained in:
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">«</button></li>
|
||||
<li>Page {{page+1}} of {{pages}}</li>
|
||||
<li><button class="btn btn-default" v-on:click="page_next" :disabled="page==pages-1">»</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…
Reference in New Issue
Block a user