mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-14 16:55:42 +00:00
Reviewed Job Package
This commit is contained in:
parent
3789f61ca4
commit
57a598ed20
@ -1,10 +1,10 @@
|
||||
from flask import (abort, current_app, jsonify)
|
||||
from flask import abort, current_app, jsonify
|
||||
from flask_login import current_user, login_required
|
||||
from threading import Thread
|
||||
import os
|
||||
from app import db
|
||||
from app.decorators import admin_required, content_negotiation
|
||||
from app.models import Job, JobInput, JobResult, JobStatus
|
||||
from app.models import Job, JobStatus
|
||||
from . import bp
|
||||
|
||||
@bp.route('/<hashid:job_id>', methods=['DELETE'])
|
||||
@ -36,6 +36,7 @@ def delete_job(job_id):
|
||||
@bp.route('/<hashid:job_id>/log')
|
||||
@login_required
|
||||
@admin_required
|
||||
@content_negotiation(produces='application/json')
|
||||
def job_log(job_id):
|
||||
job = Job.query.get_or_404(job_id)
|
||||
if job.status not in [JobStatus.COMPLETED, JobStatus.FAILED]:
|
||||
@ -43,11 +44,18 @@ def job_log(job_id):
|
||||
return response, 409
|
||||
with open(os.path.join(job.path, 'pipeline_data', 'logs', 'pyflow_log.txt')) as log_file:
|
||||
log = log_file.read()
|
||||
return log, 200, {'Content-Type': 'text/plain; charset=utf-8'}
|
||||
response_data = {
|
||||
'message': '',
|
||||
'jobLog': log
|
||||
}
|
||||
response = jsonify(response_data)
|
||||
response.status_code = 200
|
||||
return response
|
||||
|
||||
|
||||
@bp.route('/<hashid:job_id>/restart', methods=['POST'])
|
||||
@login_required
|
||||
@content_negotiation(produces='application/json')
|
||||
def restart_job(job_id):
|
||||
def _restart_job(app, job_id):
|
||||
with app.app_context():
|
||||
@ -66,4 +74,10 @@ def restart_job(job_id):
|
||||
args=(current_app._get_current_object(), job_id)
|
||||
)
|
||||
thread.start()
|
||||
return {}, 202
|
||||
response_data = {
|
||||
'message': \
|
||||
f'Job "{job.title}" marked for restarting'
|
||||
}
|
||||
response = jsonify(response_data)
|
||||
response.status_code = 202
|
||||
return response
|
||||
|
@ -21,3 +21,11 @@ Requests.jobs.entity.log = (jobId) => {
|
||||
};
|
||||
return Requests.JSONfetch(input, init);
|
||||
}
|
||||
|
||||
Requests.jobs.entity.restart = (jobId) => {
|
||||
let input = `/jobs/${jobId}/restart`;
|
||||
let init = {
|
||||
method: 'POST'
|
||||
};
|
||||
return Requests.JSONfetch(input, init);
|
||||
}
|
||||
|
@ -2,16 +2,6 @@ class JobDisplay extends ResourceDisplay {
|
||||
constructor(displayElement) {
|
||||
super(displayElement);
|
||||
this.jobId = this.displayElement.dataset.jobId;
|
||||
this.displayElement
|
||||
.querySelector('.action-button[data-action="get-log-request"]')
|
||||
.addEventListener('click', (event) => {
|
||||
Utils.getJobLogRequest(this.userId, this.jobId);
|
||||
});
|
||||
this.displayElement
|
||||
.querySelector('.action-button[data-action="restart-request"]')
|
||||
.addEventListener('click', (event) => {
|
||||
Utils.restartJobRequest(this.userId, this.jobId);
|
||||
});
|
||||
}
|
||||
|
||||
init(user) {
|
||||
|
@ -229,138 +229,138 @@ class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
static deleteJobRequest(userId, jobId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let job;
|
||||
try {
|
||||
job = app.data.users[userId].jobs[jobId];
|
||||
} catch (error) {
|
||||
job = {};
|
||||
}
|
||||
// static deleteJobRequest(userId, jobId) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// let job;
|
||||
// try {
|
||||
// job = app.data.users[userId].jobs[jobId];
|
||||
// } catch (error) {
|
||||
// job = {};
|
||||
// }
|
||||
|
||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||
confirmElement.addEventListener('click', (event) => {
|
||||
let jobTitle = job?.title;
|
||||
fetch(`/jobs/${jobId}`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
app.flash(`Job "${jobTitle}" marked for deletion`, 'job');
|
||||
resolve(response);
|
||||
},
|
||||
(response) => {
|
||||
app.flash('Something went wrong', 'error');
|
||||
reject(response);
|
||||
}
|
||||
);
|
||||
});
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
// let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||
// confirmElement.addEventListener('click', (event) => {
|
||||
// let jobTitle = job?.title;
|
||||
// fetch(`/jobs/${jobId}`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
||||
// .then(
|
||||
// (response) => {
|
||||
// if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
// if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
// app.flash(`Job "${jobTitle}" marked for deletion`, 'job');
|
||||
// resolve(response);
|
||||
// },
|
||||
// (response) => {
|
||||
// app.flash('Something went wrong', 'error');
|
||||
// reject(response);
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// modal.open();
|
||||
// });
|
||||
// }
|
||||
|
||||
static getJobLogRequest(userId, jobId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(`/jobs/${jobId}/log`, {method: 'GET', headers: {Accept: 'application/json, text/plain'}})
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
return response.text();
|
||||
},
|
||||
(response) => {
|
||||
app.flash('Something went wrong', 'error');
|
||||
reject(response);
|
||||
}
|
||||
)
|
||||
.then(
|
||||
(text) => {
|
||||
let modalElement = Utils.HTMLToElement(
|
||||
`
|
||||
<div class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Job logs</h4>
|
||||
<pre><code>${text}</code></pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn modal-close waves-effect waves-light">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
document.querySelector('#modals').appendChild(modalElement);
|
||||
let modal = M.Modal.init(
|
||||
modalElement,
|
||||
{
|
||||
onCloseEnd: () => {
|
||||
modal.destroy();
|
||||
modalElement.remove();
|
||||
}
|
||||
}
|
||||
);
|
||||
modal.open();
|
||||
resolve(text);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
// static getJobLogRequest(userId, jobId) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// fetch(`/jobs/${jobId}/log`, {method: 'GET', headers: {Accept: 'application/json, text/plain'}})
|
||||
// .then(
|
||||
// (response) => {
|
||||
// if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
// if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
// return response.text();
|
||||
// },
|
||||
// (response) => {
|
||||
// app.flash('Something went wrong', 'error');
|
||||
// reject(response);
|
||||
// }
|
||||
// )
|
||||
// .then(
|
||||
// (text) => {
|
||||
// let modalElement = Utils.HTMLToElement(
|
||||
// `
|
||||
// <div class="modal">
|
||||
// <div class="modal-content">
|
||||
// <h4>Job logs</h4>
|
||||
// <pre><code>${text}</code></pre>
|
||||
// </div>
|
||||
// <div class="modal-footer">
|
||||
// <a class="btn modal-close waves-effect waves-light">Close</a>
|
||||
// </div>
|
||||
// </div>
|
||||
// `
|
||||
// );
|
||||
// document.querySelector('#modals').appendChild(modalElement);
|
||||
// let modal = M.Modal.init(
|
||||
// modalElement,
|
||||
// {
|
||||
// onCloseEnd: () => {
|
||||
// modal.destroy();
|
||||
// modalElement.remove();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// modal.open();
|
||||
// resolve(text);
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// }
|
||||
|
||||
static restartJobRequest(userId, jobId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let job;
|
||||
try {
|
||||
job = app.data.users[userId].jobs[jobId];
|
||||
} catch (error) {
|
||||
job = {};
|
||||
}
|
||||
// static restartJobRequest(userId, jobId) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// let job;
|
||||
// try {
|
||||
// job = app.data.users[userId].jobs[jobId];
|
||||
// } catch (error) {
|
||||
// job = {};
|
||||
// }
|
||||
|
||||
let modalElement = Utils.HTMLToElement(
|
||||
`
|
||||
<div class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm Job restart</h4>
|
||||
<p>Do you really want to restart the Job <b>${job?.title}</b>? All Job Results will be permanently deleted.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
||||
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Restart</a>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
document.querySelector('#modals').appendChild(modalElement);
|
||||
let modal = M.Modal.init(
|
||||
modalElement,
|
||||
{
|
||||
dismissible: false,
|
||||
onCloseEnd: () => {
|
||||
modal.destroy();
|
||||
modalElement.remove();
|
||||
}
|
||||
}
|
||||
);
|
||||
// let modalElement = Utils.HTMLToElement(
|
||||
// `
|
||||
// <div class="modal">
|
||||
// <div class="modal-content">
|
||||
// <h4>Confirm Job restart</h4>
|
||||
// <p>Do you really want to restart the Job <b>${job?.title}</b>? All Job Results will be permanently deleted.</p>
|
||||
// </div>
|
||||
// <div class="modal-footer">
|
||||
// <a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
||||
// <a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Restart</a>
|
||||
// </div>
|
||||
// </div>
|
||||
// `
|
||||
// );
|
||||
// document.querySelector('#modals').appendChild(modalElement);
|
||||
// let modal = M.Modal.init(
|
||||
// modalElement,
|
||||
// {
|
||||
// dismissible: false,
|
||||
// onCloseEnd: () => {
|
||||
// modal.destroy();
|
||||
// modalElement.remove();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||
confirmElement.addEventListener('click', (event) => {
|
||||
let jobTitle = job?.title;
|
||||
fetch(`/jobs/${jobId}/restart`, {method: 'POST', headers: {Accept: 'application/json'}})
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
if (response.status === 409) {app.flash('Conflict', 'error'); reject(response);}
|
||||
app.flash(`Job "${jobTitle}" restarted.`, 'job');
|
||||
resolve(response);
|
||||
},
|
||||
(response) => {
|
||||
app.flash('Something went wrong', 'error');
|
||||
reject(response);
|
||||
}
|
||||
);
|
||||
});
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
// let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||
// confirmElement.addEventListener('click', (event) => {
|
||||
// let jobTitle = job?.title;
|
||||
// fetch(`/jobs/${jobId}/restart`, {method: 'POST', headers: {Accept: 'application/json'}})
|
||||
// .then(
|
||||
// (response) => {
|
||||
// if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
||||
// if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
||||
// if (response.status === 409) {app.flash('Conflict', 'error'); reject(response);}
|
||||
// app.flash(`Job "${jobTitle}" restarted.`, 'job');
|
||||
// resolve(response);
|
||||
// },
|
||||
// (response) => {
|
||||
// app.flash('Something went wrong', 'error');
|
||||
// reject(response);
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// modal.open();
|
||||
// });
|
||||
// }
|
||||
|
||||
static deleteUserRequest(userId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -79,9 +79,9 @@
|
||||
</div>
|
||||
<div class="card-action right-align">
|
||||
{% if current_user.is_administrator() %}
|
||||
<a class="btn disabled waves-effect waves-light modal-trigger" id="log-job-modal"><i class="material-icons left">text_snippet</i>Log</a>
|
||||
<a class="action-button btn disabled waves-effect waves-light modal-trigger" data-action="get-log-request" id="job-log-button" href="#job-log-modal"><i class="material-icons left">text_snippet</i>Log</a>
|
||||
{% endif %}
|
||||
<a class="action-button btn disabled waves-effect waves-light" data-action="restart-request"><i class="material-icons left">repeat</i>Restart</a>
|
||||
<a class="btn disabled waves-effect waves-light modal-trigger" href="#restart-job-modal"><i class="material-icons left">repeat</i>Restart</a>
|
||||
<a class="btn red waves-effect waves-light modal-trigger" href="#delete-job-modal"><i class="material-icons left">delete</i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -120,20 +120,31 @@
|
||||
<p>Do you really want to delete the Job <b>{{job.title}}</b>? All files will be permanently deleted!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
||||
<a class="btn modal-close waves-effect waves-light">Cancel</a>
|
||||
<a class="btn modal-close red waves-effect waves-light" id="delete-job-request">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="log-job-modal">
|
||||
<div class="modal" id="job-log-modal">
|
||||
<div class="modal-content">
|
||||
<h4>Job logs</h4>
|
||||
<pre><code>${text}</code></pre>
|
||||
<pre><code></code></pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn modal-close waves-effect waves-light">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="restart-job-modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm Job restart</h4>
|
||||
<p>Do you really want to restart the Job <b>{{ job.title }}</b>? All Job Results will be permanently deleted.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn modal-close waves-effect waves-light">Cancel</a>
|
||||
<a class="btn modal-close red waves-effect waves-light" id="restart-job-request">Restart</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock modals %}
|
||||
|
||||
|
||||
@ -142,12 +153,24 @@
|
||||
<script>
|
||||
let jobDisplay = new JobDisplay(document.querySelector('#job-display'));
|
||||
let deleteJobRequestElement = document.querySelector('#delete-job-request');
|
||||
let logJobModalElement = document.querySelector('#log-job-modal');
|
||||
let jobLogButtonElement = document.querySelector('#job-log-button');
|
||||
let restartJobRequestElement = document.querySelector('#restart-job-request');
|
||||
deleteJobRequestElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.delete({{ job.hashid|tojson }});
|
||||
});
|
||||
logJobModalElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.log({{ job.hashid|tojson }});
|
||||
});
|
||||
jobLogButtonElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.log({{ job.hashid|tojson }})
|
||||
.then(
|
||||
(response) => {
|
||||
response.json()
|
||||
.then((json) => {
|
||||
let jobLogModalElement = document.querySelector('#job-log-modal');
|
||||
jobLogModalElement.querySelector('pre code').textContent = json.jobLog;
|
||||
});
|
||||
});
|
||||
});
|
||||
restartJobRequestElement.addEventListener('click', (event) => {
|
||||
Requests.jobs.entity.restart({{ job.hashid|tojson }});
|
||||
});
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
Loading…
Reference in New Issue
Block a user