[enh] make one new page per app

This commit is contained in:
Laurent Peuch 2018-11-05 01:59:48 +01:00
parent 719cb13c08
commit 84cc6f86a3
2 changed files with 113 additions and 7 deletions

43
run.py
View file

@ -322,7 +322,7 @@ async def run_job(worker, job):
await broadcast({
"action": "update_job",
"data": model_to_dict(job),
}, ["jobs", f"job-{job.id}"])
}, ["jobs", f"job-{job.id}", f"app-jobs-{job.url_or_path}"])
# fake stupid command, whould run CI instead
task_logger.info(f"Starting job '{job.name}' #{job.id}...")
@ -351,7 +351,7 @@ async def run_job(worker, job):
"action": "update_job",
"id": job.id,
"data": model_to_dict(job),
}, ["jobs", f"job-{job.id}"])
}, ["jobs", f"job-{job.id}", f"app-jobs-{job.url_or_path}"])
except Exception as e:
traceback.print_exc()
@ -385,7 +385,7 @@ async def run_job(worker, job):
"action": "update_job",
"id": job.id,
"data": model_to_dict(job),
}, ["jobs", f"job-{job.id}"])
}, ["jobs", f"job-{job.id}", f"app-jobs-{job.url_or_path}"])
async def broadcast(message, channels):
@ -539,6 +539,24 @@ async def ws_apps(request, websocket):
await websocket.recv()
@app.websocket('/app-<app_name>-ws')
async def ws_app(request, websocket, app_name):
# XXX I don't check if the app exists because this websocket is supposed to
# be only loaded from the app page which does this job already
app = Repo.select().where(Repo.name == app_name)[0]
subscribe(websocket, f"app-jobs-{app.url}")
await websocket.send(ujson.dumps({
"action": "init_jobs",
"data": Job.select().where(Job.url_or_path == app.url).order_by(-Job.id),
}))
while True:
# do nothing with input but wait
await websocket.recv()
def require_token():
def decorator(f):
@wraps(f)
@ -584,7 +602,7 @@ async def api_new_job(request):
await broadcast({
"action": "new_job",
"data": model_to_dict(job),
}, "jobs")
}, ["jobs", f"app-jobs-{job.url_or_path}"])
return response.text("ok")
@ -618,7 +636,7 @@ async def api_delete_job(request, job_id):
await broadcast({
"action": "delete_job",
"data": data,
}, ["jobs", f"job-{job_id}"])
}, ["jobs", f"job-{job_id}", f"app-jobs-{job.url_or_path}"])
return response.text("ok")
@ -643,7 +661,7 @@ async def api_stop_job(request, job_id):
await broadcast({
"action": "update_job",
"data": model_to_dict(job),
}, ["jobs", f"job-{job.id}"])
}, ["jobs", f"job-{job.id}", f"app-jobs-{job.url_or_path}"])
return response.text("ok")
@ -662,7 +680,7 @@ async def api_stop_job(request, job_id):
await broadcast({
"action": "update_job",
"data": model_to_dict(job),
}, ["jobs", f"job-{job.id}"])
}, ["jobs", f"job-{job.id}", f"app-jobs-{job.url_or_path}"])
return response.text("ok")
@ -710,6 +728,17 @@ async def html_apps(request):
return {'relative_path_to_root': '../', 'path': request.path}
@app.route('/apps/<app_name>/')
@jinja.template('app.html')
async def html_app(request, app_name):
app = Repo.select().where(Repo.name == app_name)
if app.count == 0:
raise NotFound()
return {"app": app[0], 'relative_path_to_root': '../../', 'path': request.path}
@app.route('/')
@jinja.template('index.html')
async def html_index(request):

77
templates/app.html Normal file
View file

@ -0,0 +1,77 @@
<% extends "base.html" %>
<% block content %>
<section class="section">
<div class="container">
<h1 class="title">Jobs for app <{ app.name }> <a target="_blank" href="<{ app.url }>"></a></h1>
<div id="jobs">
<table class="table is-bordered is-hoverable is-striped is-fullwidth">
<thead>
<th>App</th>
<th>State</th>
<th>Created time</th>
<th>Started time</th>
<th>End time</th>
</thead>
<tr v-for="(job, index) in jobs" :id="job.id" v-bind:class="[{deleted: job.deleted}, job.state + 'Job']">
<td><a v-if="!job.deleted" v-bind:href="'<{ relative_path_to_root }>job/' + job.id">{{job.name}}</a><span v-if="job.deleted">{{job.name}} (deleted)</span> <small title="job's id">#{{job.id}} </small></td>
<td>{{job.state}}</td>
<td>{{timestampToDate(job.created_time)}}</td>
<td>{{timestampToDate(job.started_time)}}</td>
<td>{{timestampToDate(job.end_time)}}</td>
</tr>
</table>
</div>
</div>
</section>
<% endblock %>
<% block javascript %>
<script>
(function() {
var app = new Vue({
el: '#jobs',
data: {
jobs: []
},
methods: {
timestampToDate: function (timestamp) {
console.log(timestamp)
if (timestamp === null) return "";
return new Date(timestamp * 1000).toLocaleString()
}
}
})
ws = new ReconnectingWebSocket(websocketPrefix() + '://' + document.domain + ':' + location.port + websocketRelativePath('<{ path }>') + '/app-<{ app.name }>-ws');
ws.onmessage = function (event) {
var message = JSON.parse(event.data);
var data = message.data;
var action = message.action;
if (action == "init_jobs") {
app.jobs = data;
} else if (action == "update_job") {
for (var i = 0; i < app.jobs.length; ++i) {
if (app.jobs[i].id == data.id) {
Vue.set(app.jobs, i, data);
break;
}
}
} else if (action == "new_job") {
app.jobs.splice(0, 0, data);
} else if (action == "delete_job") {
for (var i = 0; i < app.jobs.length; ++i) {
if (app.jobs[i].id == data.id) {
Vue.set(app.jobs[i], 'deleted', true);
Vue.set(app.jobs[i], 'state', 'deleted');
break;
}
}
}
};
})()
</script>
<% endblock %>