From 4a5804460fe38037c41a00b6ffa8d24e0efb1199 Mon Sep 17 00:00:00 2001 From: Patrick Jentsch <p.jentsch@uni-bielefeld.de> Date: Fri, 16 Aug 2019 09:49:27 +0200 Subject: [PATCH] Add admin functions to api. Add to_jsonifyable method to Job and Corpus and use it in API. --- app/models.py | 21 +++++ app/templates/main/dashboard.html.j2 | 129 ++++++++++++++++++++------- 2 files changed, 120 insertions(+), 30 deletions(-) diff --git a/app/models.py b/app/models.py index c3a09668..d5284554 100644 --- a/app/models.py +++ b/app/models.py @@ -247,6 +247,21 @@ class Job(db.Model): """ return '<Job %r>' % self.title + def to_jsonifyable(self): + return {'id': self.id, + 'creation_date': self.creation_date.timestamp(), + 'description': self.description, + 'end_date': (self.end_date.timestamp() if self.end_date else + None), + 'mem_mb': self.mem_mb, + 'n_cores': self.n_cores, + 'service': self.service, + 'service_args': self.service_args, + 'service_version': self.service_version, + 'status': self.status, + 'title': self.title, + 'user_id': self.user_id} + class Corpus(db.Model): """ @@ -269,6 +284,12 @@ class Corpus(db.Model): """ return '<Corpus %r>' % self.title + def to_jsonifyable(self): + return {'id': self.id, + 'creation_date': self.creation_date, + 'description': self.description, + 'title': self.title, + 'user_id': self.user_id} ''' ' Flask-Login is told to use the application’s custom anonymous user by setting diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2 index c8a02c07..ac063dae 100644 --- a/app/templates/main/dashboard.html.j2 +++ b/app/templates/main/dashboard.html.j2 @@ -76,45 +76,114 @@ </div> </div> </div> - <div class="collection list"> - {% for job in current_user.jobs.all() %} - {% if job.service == 'nlp' %} - {% set service_color = 'blue' %} - {% set service_icon = 'format_textdirection_l_to_r' %} - {% elif job.service =='ocr' %} - {% set service_color = 'green' %} - {% set service_icon = 'find_in_page' %} - {% else %} - {% set service_color = 'red' %} - {% set service_icon = 'help' %} - {% endif %} - {% if job.status == 'pending' %} - {% set badge_color = 'amber' %} - {% elif job.status =='running' %} - {% set badge_color = 'indigo' %} - {% elif job.status =='complete' %} - {% set badge_color = 'teal' %} - {% else %} - {% set badge_color = 'red' %} - {% endif %} - <a href="{{ url_for('main.job', job_id=job.id) }}" class="collection-item avatar"> - <i class="material-icons circle {{ service_color }}">{{ service_icon }}</i> - <span class="new badge {{ badge_color }}" data-badge-caption="">{{ job.status }}</span> - <span class="title">{{ job.title }}</span> - <p>{{ job.description }}</p> - </a> - {% endfor %} - </div> + <div class="collection list"></div> </div> </div> <script> var jobList = new List("job-list", {valueNames: ["title"], page: 4, - pagination: true}); + pagination: false}); jobList.on("filterComplete", updatePagination); jobList.on("searchComplete", updatePagination); </script> +<script> + const SERVICE_COLORS = {"nlp": "blue", + "ocr": "green"} + const SERVICE_ICONS = {"nlp": "format_textdirection_l_to_r", + "ocr": "find_in_page"} + const STATUS_COLORS = {"pending": "amber", + "running": "indigo", + "complete": "teal"} + + var getJobsCallbackFunctions = []; + + function getJobs() { + fetch("/api/v1.0/jobs") + .then(function(response) { + if (response.status >= 200 && response.status < 300) { + return Promise.resolve(response) + } else { + return Promise.reject(new Error(response.statusText)) + } + }) + .then(function(response) { + return response.json() + }) + .then(function(jobs) { + for (callbackFunction of getJobsCallbackFunctions) { + callbackFunction(jobs); + } + }) + .catch(function(error) { + console.log('Request failed', error); + }); + } + + setInterval(getJobs, 1000); + + function createJobElement(job) { + jobElement = document.createElement("a"); + jobElement.classList.add("avatar", "collection-item"); + jobElement.dataset.key = "id"; + jobElement.dataset.value = job.id; + jobElement.href = `/jobs/${job.id}`; + jobDescriptionElement = document.createElement("p"); + jobDescriptionElement.dataset.key = "description"; + jobDescriptionElement.innerText = job.description; + jobServiceElement = document.createElement("i"); + jobServiceElement.classList.add("circle", "material-icons", SERVICE_COLORS[job.service]); + jobServiceElement.dataset.key = "service"; + jobServiceElement.innerText = SERVICE_ICONS[job.service]; + jobStatusElement = document.createElement("span"); + jobStatusElement.classList.add("badge", "new", "status", STATUS_COLORS[job.status]); + jobStatusElement.dataset.badgeCaption = ""; + jobStatusElement.dataset.key = "status"; + jobStatusElement.innerText = job.status; + jobTitleElement = document.createElement("span"); + jobTitleElement.classList.add("title"); + jobTitleElement.dataset.key = "title"; + jobTitleElement.innerText = job.title; + + jobElement.appendChild(jobServiceElement); + jobElement.appendChild(jobStatusElement); + jobElement.appendChild(jobTitleElement); + jobElement.appendChild(jobDescriptionElement); + + return jobElement; + } + + + function updateJobElement(job, jobElement) { + /* + if (jobElement.dataset.value != job.id) { + jobElement.dataset.value = job.id; + jobElement.href = `/jobs/${job.id}`; + } + */ + + + } + + function processJobs(jobs) { + for (job of jobs) { + jobElement = jobList.list.querySelectorAll('[data-key="id"]') + .querySelector(`[data-value="${job.id}"]`); + console.log(jobElement); + if (jobElement) { + statusElement = jobElement.querySelector(".status"); + currentStatus = statusElement.text + continue; + } + jobList.list.appendChild(createJobElement(job)); + } + jobList.reIndex(); + jobList.update(); + } + + getJobsCallbackFunctions.push(processJobs) +</script> + <div id="new-corpus-modal" class="modal"> <div class="modal-content"> <h4>New corpus</h4> -- GitLab