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;
|
Type type;
|
||||||
std::string job;
|
std::string job;
|
||||||
uint num = 0;
|
uint num = 0;
|
||||||
|
uint page = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents a (websocket) client that wants to be notified about events
|
// 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);
|
populateArtifacts(j, client->scope.job, client->scope.num);
|
||||||
j.EndArray();
|
j.EndArray();
|
||||||
} else if(client->scope.type == MonitorScope::JOB) {
|
} else if(client->scope.type == MonitorScope::JOB) {
|
||||||
|
const uint runsPerPage = 10;
|
||||||
j.startArray("recent");
|
j.startArray("recent");
|
||||||
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 25")
|
db->stmt("SELECT number,startedAt,completedAt,result,reason FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT ?,?")
|
||||||
.bind(client->scope.job)
|
.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){
|
.fetch<uint,time_t,time_t,int,str>([&](uint build,time_t started,time_t completed,int result,str reason){
|
||||||
j.StartObject();
|
j.StartObject();
|
||||||
j.set("number", build)
|
j.set("number", build)
|
||||||
@ -208,6 +209,11 @@ void Laminar::sendStatus(LaminarClient* client) {
|
|||||||
.EndObject();
|
.EndObject();
|
||||||
});
|
});
|
||||||
j.EndArray();
|
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");
|
j.startArray("running");
|
||||||
auto p = activeJobs.byJobName().equal_range(client->scope.job);
|
auto p = activeJobs.byJobName().equal_range(client->scope.job);
|
||||||
for(auto it = p.first; it != p.second; ++it) {
|
for(auto it = p.first; it != p.second; ++it) {
|
||||||
|
@ -189,6 +189,11 @@
|
|||||||
<td class="text-center hidden-xs">{{job.reason}}</td>
|
<td class="text-center hidden-xs">{{job.reason}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</div></template>
|
</div></template>
|
||||||
|
@ -21,8 +21,10 @@ const WebsocketHandler = function() {
|
|||||||
// "status" is the first message the websocket always delivers.
|
// "status" is the first message the websocket always delivers.
|
||||||
// Use this to confirm the navigation. The component is not
|
// Use this to confirm the navigation. The component is not
|
||||||
// created until next() is called, so creating a reference
|
// created until next() is called, so creating a reference
|
||||||
// for other message types must be deferred
|
// for other message types must be deferred. Also check that
|
||||||
if (msg.type === 'status') {
|
// 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 => {
|
next(comp => {
|
||||||
// Set up bidirectional reference
|
// Set up bidirectional reference
|
||||||
// 1. needed to reference the component for other msg types
|
// 1. needed to reference the component for other msg types
|
||||||
@ -394,6 +396,8 @@ var Job = function() {
|
|||||||
lastSuccess: null,
|
lastSuccess: null,
|
||||||
lastFailed: null,
|
lastFailed: null,
|
||||||
nQueued: 0,
|
nQueued: 0,
|
||||||
|
pages: 0,
|
||||||
|
page: 0
|
||||||
};
|
};
|
||||||
return Vue.extend({
|
return Vue.extend({
|
||||||
template: '#job',
|
template: '#job',
|
||||||
@ -408,6 +412,7 @@ var Job = function() {
|
|||||||
state.lastSuccess = msg.lastSuccess;
|
state.lastSuccess = msg.lastSuccess;
|
||||||
state.lastFailed = msg.lastFailed;
|
state.lastFailed = msg.lastFailed;
|
||||||
state.nQueued = msg.nQueued;
|
state.nQueued = msg.nQueued;
|
||||||
|
state.pages = msg.pages;
|
||||||
|
|
||||||
var chtBt = new Chart(document.getElementById("chartBt").getContext("2d")).Bar({
|
var chtBt = new Chart(document.getElementById("chartBt").getContext("2d")).Bar({
|
||||||
labels: msg.recent.map(function(e) {
|
labels: msg.recent.map(function(e) {
|
||||||
@ -454,6 +459,12 @@ var Job = function() {
|
|||||||
break;
|
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/signal.h>
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
|
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
|
||||||
// Size of buffer used to read from file descriptors. Should be
|
// Size of buffer used to read from file descriptors. Should be
|
||||||
// a multiple of sizeof(struct signalfd_siginfo) == 128
|
// a multiple of sizeof(struct signalfd_siginfo) == 128
|
||||||
#define PROC_IO_BUFSIZE 4096
|
#define PROC_IO_BUFSIZE 4096
|
||||||
@ -213,11 +215,18 @@ public:
|
|||||||
// wss.set_access_channels(websocketpp::log::alevel::all);
|
// wss.set_access_channels(websocketpp::log::alevel::all);
|
||||||
// wss.set_error_channels(websocketpp::log::elevel::all);
|
// wss.set_error_channels(websocketpp::log::elevel::all);
|
||||||
|
|
||||||
// TODO: This could be used in the future to trigger actions on the
|
// Handle incoming websocket message
|
||||||
// server in response to a web client request. Currently not supported.
|
wss.set_message_handler([this](websocketpp::connection_hdl hdl, websocket::message_ptr msg){
|
||||||
// wss.set_message_handler([](std::weak_ptr<void> s, websocket::message_ptr msg){
|
websocket::connection_ptr c = wss.get_con_from_hdl(hdl);
|
||||||
// msg->get_payload();
|
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
|
// Handle plain HTTP requests by delivering the binary resource
|
||||||
wss.set_http_handler([this](websocketpp::connection_hdl hdl){
|
wss.set_http_handler([this](websocketpp::connection_hdl hdl){
|
||||||
|
Loading…
Reference in New Issue
Block a user