diff --git a/apollo/factory.py b/apollo/factory.py index 72a27d716..c5af551a3 100644 --- a/apollo/factory.py +++ b/apollo/factory.py @@ -189,6 +189,7 @@ def on_failure(self, exc, task_id, args, kwargs, einfo): 'progress': self.task_info, 'description': TASK_DESCRIPTIONS.get(self.request.task, _('Task')), 'quit': True, + 'name': self.request.task.split('.')[-1], } if channel is not None: @@ -207,6 +208,7 @@ def on_success(self, retval, task_id, args, kwargs): 'progress': self.task_info, 'description': TASK_DESCRIPTIONS.get(self.request.task, _('Task')), 'quit': True, + 'name': self.request.task.split('.')[-1], } if channel is not None: @@ -227,7 +229,9 @@ def update_task_info(self, **kwargs): 'id': request.id, 'status': _('RUNNING'), 'progress': task_metadata.get('result'), - 'description': TASK_DESCRIPTIONS.get(self.request.task, _('Task')) + 'description': TASK_DESCRIPTIONS.get(self.request.task, _('Task')), + 'name': self.request.task.split('.')[-1], + 'quit': False, } if channel is not None: diff --git a/apollo/formsframework/tasks.py b/apollo/formsframework/tasks.py deleted file mode 100644 index fbc6c0760..000000000 --- a/apollo/formsframework/tasks.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from .. import services -from ..factory import create_celery_app - -celery = create_celery_app() - - -@celery.task -def update_submissions(form_pk): - ''' - Updates submissions after a form has been updated, so all the fields - in the form are existent in the submissions. - ''' - form = services.forms.get(pk=form_pk) - tags = form.tags - for submission in services.submissions.find(form=form): - for tag in tags: - if not hasattr(submission, tag): - setattr(submission, tag, None) - submission.save() diff --git a/apollo/formsframework/views_forms.py b/apollo/formsframework/views_forms.py index dd5631ca1..94ce50dfb 100644 --- a/apollo/formsframework/views_forms.py +++ b/apollo/formsframework/views_forms.py @@ -234,6 +234,7 @@ def forms_list(view): 'breadcrumbs': breadcrumbs, 'init_form': checklist_init_form, 'form_import_form': form_import_form, + 'channel': session.get('_id'), } return view.render(template_name, **context) diff --git a/apollo/locations/views_locations.py b/apollo/locations/views_locations.py index d1c386971..0c59d0438 100644 --- a/apollo/locations/views_locations.py +++ b/apollo/locations/views_locations.py @@ -95,6 +95,7 @@ def locations_list(view, location_set_id): else: ctx = dict( args=args, + channel=session.get('_id'), extra_fields=extra_fields, filter_form=queryset_filter.form, breadcrumbs=breadcrumbs, diff --git a/apollo/participants/views_participants.py b/apollo/participants/views_participants.py index 98ec88e40..57fcf4d85 100644 --- a/apollo/participants/views_participants.py +++ b/apollo/participants/views_participants.py @@ -358,7 +358,8 @@ def participant_list(participant_set_id=0, view=None): location_types=helpers.displayable_location_types( is_administrative=True, location_set_id=location_set_id), participants=queryset_filterset.qs.paginate( - page=page, per_page=current_app.config.get('PAGE_SIZE')) + page=page, per_page=current_app.config.get('PAGE_SIZE')), + channel=session.get('_id'), ) if view: diff --git a/apollo/static/js/task-toasts.js b/apollo/static/js/task-toasts.js new file mode 100644 index 000000000..336cc2cb2 --- /dev/null +++ b/apollo/static/js/task-toasts.js @@ -0,0 +1,122 @@ +function setupTaskToasts(appSelector, taskNames, taskListUrl, eventStreamUrl) { + var roundTo = function(num) { + return Math.round((num + 0.00001) * 100) / 100; + }; + + Vue.component('task-toast', { + updated: function() { + // clear completed tasks + if (this.taskInfo.quit == true) + this.clear(); + }, + template: '#task-toast', + props: { + taskInfo: { + id: String, + status: String, + quit: Boolean, + progress: Object, + description: String, + name: String + } + }, + methods: { + clear: function() { + var self = this; + setTimeout(function() { + $(self.$el).toast('hide'); + }, 5000); + } + }, + computed: { + processedCount: function() { + return this.taskInfo.progress.processed_records; + }, + warningCount: function() { + return this.taskInfo.progress.warning_records; + }, + errorCount: function() { + return this.taskInfo.progress.error_records; + }, + totalCount: function() { + return this.taskInfo.progress.total_records; + }, + processedStyle: function() { + return {width: roundTo(100 * this.taskInfo.progress.processed_records / this.taskInfo.progress.total_records) + '%'}; + }, + warningStyle: function() { + return {width: roundTo(100 * this.taskInfo.progress.warning_records / this.taskInfo.progress.total_records) + '%'}; + }, + errorStyle: function() { + return {width: roundTo(100 * this.taskInfo.progress.error_records / this.taskInfo.progress.total_records) + '%'}; + } + }, + mounted: function() { + $(this.$el).toast('show'); + var self = this; + if (this.taskInfo.quit == true) { + self.clear(); + } + }, + destroyed: function() { + $(this.el).toast('dispose'); + } + }); + + var vm = new Vue({ + el: appSelector, + data: { + tasks: [] + }, + methods: { + addTask: function(taskInfo) { + // skip unregistered tasks + if (taskNames.indexOf(taskInfo.name) === -1) + return; + + var self = this; + var index = self.tasks.findIndex(function(task) { + return task.id == taskInfo.id; + }); + if (index == -1) + self.tasks.unshift(taskInfo); + else + self.tasks.splice(index, 1, taskInfo); + }, + loadCompletedTasks: function() { + var self = this; + fetch(taskListUrl) + .then(function(response) { + return response.json(); + }).then(function(data) { + if (data.results.length > 0) { + data.results.forEach(function(taskInfo) { + self.addTask(taskInfo); + }); + } + + }).catch(function(err) { + console.error(err); + }); + }, + loadRunningTasks: function() { + var self = this; + if (window.EventSource) { + var es = new EventSource(eventStreamUrl); + es.onmessage = function (ev) { + let data = JSON.parse(ev.data); + if (data.id !== undefined) { + self.addTask(data); + } + }; + } + } + }, + mounted: function() { + this.loadCompletedTasks(); + this.loadRunningTasks(); + } + }); + + return vm; +} \ No newline at end of file diff --git a/apollo/tasks.py b/apollo/tasks.py index 907009675..8c5da75ec 100644 --- a/apollo/tasks.py +++ b/apollo/tasks.py @@ -3,7 +3,6 @@ celery = create_celery_app() -from apollo.formsframework.tasks import update_submissions from apollo.messaging.tasks import send_messages, send_email from apollo.participants.tasks import import_participants from apollo.locations.tasks import import_locations diff --git a/apollo/templates/admin/form_list.html b/apollo/templates/admin/form_list.html index b7ab85034..e3606f335 100644 --- a/apollo/templates/admin/form_list.html +++ b/apollo/templates/admin/form_list.html @@ -1,4 +1,6 @@ {% extends "admin/base.html" %} +{%- from 'admin/task_toast.html' import render_toast_parent, render_toast_template -%} +{%- set toast_app_id = 'toast_app' -%} {%- block body %}
@@ -172,11 +174,25 @@
{% endblock %} - +{% block footer %} +{{ render_toast_parent(toast_app_id) }} +{% endblock footer %} {%- block tail_js %} {{ super() }} +{{ render_toast_template() }} + + + + + + + + + + + + + +