diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/context_processors.py | 3 | ||||
-rw-r--r-- | ishtar_common/models_imports.py | 33 | ||||
-rw-r--r-- | ishtar_common/static/js/ishtar.js | 48 | ||||
-rw-r--r-- | ishtar_common/static/media/styles.css | 2 | ||||
-rw-r--r-- | ishtar_common/templates/base.html | 7 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/import_list.html | 71 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/import_table.html | 81 | ||||
-rw-r--r-- | ishtar_common/urls.py | 4 | ||||
-rw-r--r-- | ishtar_common/utils.py | 13 | ||||
-rw-r--r-- | ishtar_common/views.py | 24 |
10 files changed, 210 insertions, 76 deletions
diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py index 90817776f..7619363dc 100644 --- a/ishtar_common/context_processors.py +++ b/ishtar_common/context_processors.py @@ -52,7 +52,8 @@ def get_base_context(request): # messages dct['MESSAGES'] = [] - if 'messages' in request.session and request.session['messages']: + if not request.is_ajax() and 'messages' in request.session and \ + request.session['messages']: for message, message_type in request.session['messages']: dct['MESSAGES'].append((message, message_type)) request.session['messages'] = [] diff --git a/ishtar_common/models_imports.py b/ishtar_common/models_imports.py index e0a144adc..b6b68d5a6 100644 --- a/ishtar_common/models_imports.py +++ b/ishtar_common/models_imports.py @@ -39,7 +39,8 @@ from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _, pgettext_lazy from ishtar_common.utils import create_slug, \ - get_all_related_m2m_objects_with_model, put_session_message + get_all_related_m2m_objects_with_model, put_session_message, \ + put_session_var, get_session_var from ishtar_common.data_importer import Importer, ImportFormater, \ IntegerFormater, FloatFormater, UnicodeFormater, DateFormater, \ TypeFormater, YearFormater, StrToBoolean, FileFormater, InseeFormater @@ -822,8 +823,8 @@ class Import(models.Model): help_text=_(u'If set to true, do not overload existing values.')) creation_date = models.DateTimeField( _(u"Creation date"), auto_now_add=True, blank=True, null=True) - end_date = models.DateTimeField(_(u"End date"), blank=True, - null=True, editable=False) + end_date = models.DateTimeField(_(u"End date"), auto_now_add=True, + blank=True, null=True, editable=False) seconds_remaining = models.IntegerField( _(u"Remaining seconds"), blank=True, null=True, editable=False) @@ -922,24 +923,29 @@ class Import(models.Model): def initialize(self, user=None): self.state = 'AP' + self.end_date = datetime.datetime.now() self.save() self.get_importer_instance().initialize(self.data_table, user=user, output='db') self.state = 'A' + self.end_date = datetime.datetime.now() self.save() def delayed_importation(self, session_key): if not settings.USE_BACKGROUND_TASK: return self.importation(session_key=session_key) - put_session_message(session_key, - unicode(_(u"Import added to the queue")), - "warning") + put_session_message( + session_key, + unicode(_(u"Import {} added to the queue")).format(self.name), + "info") self.state = 'IQ' + self.end_date = datetime.datetime.now() self.save() return delayed_import(self.pk, session_key) def importation(self, session_key=None): self.state = 'IP' + self.end_date = datetime.datetime.now() self.save() importer = self.get_importer_instance() try: @@ -952,6 +958,11 @@ class Import(models.Model): self.imported_file), "warning" ) + ids = get_session_var(session_key, 'current_import_id') + if not ids: + ids = [] + ids.append(self.pk) + put_session_var(session_key, 'current_import_id', ids) self.state = 'FE' self.save() return @@ -970,26 +981,32 @@ class Import(models.Model): ContentFile(importer.get_csv_errors().encode('utf-8')) ) msg = unicode(_(u"Import {} finished with errors")).format( - self.imported_file) + self.name) msg_cls = "warning" else: self.state = 'F' self.error_file = None msg = unicode(_(u"Import {} finished with no errors")).format( - self.imported_file) + self.name) msg_cls = "primary" if session_key: put_session_message(session_key, msg, msg_cls) + ids = self.request.session['current_import_id'] \ + if 'current_import_id' in self.request.session else [] + ids.append(self.pk) + put_session_var(session_key, 'current_import_id', ids) if importer.match_table: match_file = filename + "_match_%s.csv" % now self.match_file.save( match_file, ContentFile(importer.get_csv_matches().encode('utf-8')) ) + self.end_date = datetime.datetime.now() self.save() def archive(self): self.state = 'AC' + self.end_date = datetime.datetime.now() self.save() def get_all_imported(self): diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index fbf1ddc17..126373b94 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -188,6 +188,21 @@ function display_info(msg){ }, 5000); } +function add_message(message, message_type){ + if (!message_type) message_type = 'info'; + + var html = $("#message_list").html(); + html += '<div class="alert alert-' + message_type + ' alert-dismissible fade show"'; + html += ' role="alert">'; + html += message; + html += ' <button type="button" class="close" data-dismiss="alert"'; + html += ' aria-label="Close">'; + html += ' <span aria-hidden="true">×</span>'; + html += ' </button>'; + html += ' </div>'; + $("#message_list").html(html); +} + function load_opened_shortcut_menu(){ load_shortcut_menu(true); } @@ -257,6 +272,39 @@ $(document).on("click", '#to_top_arrow', function(){ $("html, body").animate({ scrollTop: 0}, 1000); }); +var autorefresh = false; +var autorefresh_message_start = ""; +var autorefresh_message_end = ""; + +function startRefresh() { + if (!autorefresh) return; + autorefresh_link = $('#autorefreshpage').attr("data-link"); + autorefresh_div_id = $('#autorefreshpage').attr("data-div"); + $.get(autorefresh_link, function(data) { + $('#' + autorefresh_div_id).html(data); + }); + setTimeout(startRefresh, 10000); +} + +$(document).on("click", '#autorefreshpage', function(){ + autorefresh_div_id = $('#autorefreshpage').attr("data-div"); + if (!$(this).hasClass('disabled')) { + $(this).addClass('disabled'); + autorefresh = false; + display_info(autorefresh_message_end); + $("#" + autorefresh_div_id).find('select').prop('disabled', false); + $("#" + autorefresh_div_id).find('input').prop('disabled', false); + } else { + $(this).removeClass('disabled'); + autorefresh = true; + setTimeout(startRefresh, 10000); + display_info(autorefresh_message_start); + $("#" + autorefresh_div_id).find('select').prop('disabled', true); + $("#" + autorefresh_div_id).find('input').prop('disabled', true); + + } +}); + $(document).on("click", '.check-all', function(){ $(this).closest('table' ).find('input:checkbox' diff --git a/ishtar_common/static/media/styles.css b/ishtar_common/static/media/styles.css index 37170a801..4ab36afe2 100644 --- a/ishtar_common/static/media/styles.css +++ b/ishtar_common/static/media/styles.css @@ -69,7 +69,7 @@ div.nav-button:hover{ opacity: 0.2; } -#to_bottom_arrow{ +#to_top_arrow{ bottom:84px; } diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html index c11ae524e..bbf030409 100644 --- a/ishtar_common/templates/base.html +++ b/ishtar_common/templates/base.html @@ -40,6 +40,8 @@ var activate_own_search_msg = "{% trans 'Searches in the shortcut menu deal with only your items.' %}"; var YES = "{% trans 'yes' %}"; var NO = "{% trans 'no' %}"; + var autorefresh_message_start = "{% trans 'Autorefresh start. The form is disabled.' %}"; + var autorefresh_message_end = "{% trans 'Autorefresh end. The form is re-enabled.' %}"; </script> {% endcompress %} {% compress css %} @@ -67,9 +69,6 @@ <p><strong class='lbl'>{{lbl}}{% trans ":"%}</strong> <span class='value'>{{value}}</span></p> {% endfor %} </div> {%endif%} - <button class="nav-button btn btn-sm btn-secondary" id="to_bottom_arrow"> - <i class="fa fa-arrow-down" aria-hidden="true"></i> - </button> <button class="nav-button btn btn-sm btn-secondary" id="to_top_arrow"> <i class="fa fa-arrow-up" aria-hidden="true"></i> </button> @@ -97,6 +96,7 @@ <div id="window_wrapper"> <div id="window" role="tablist"></div> </div> + <div id="message_list"> {% if MESSAGES %}{% for message, message_type in MESSAGES %} <div class="alert alert-{{message_type}} alert-dismissible fade show" role="alert"> @@ -107,6 +107,7 @@ </button> </div> {% endfor %}{% endif %} + </div> {% if warnings %}{% for warning in warnings %} <div class="alert alert-warning alert-dismissible fade show" role="alert"> {{warning}}<button type="button" class="close" data-dismiss="alert" aria-label="Close"> diff --git a/ishtar_common/templates/ishtar/import_list.html b/ishtar_common/templates/ishtar/import_list.html index 4ac8a79be..a5fa34660 100644 --- a/ishtar_common/templates/ishtar/import_list.html +++ b/ishtar_common/templates/ishtar/import_list.html @@ -2,71 +2,20 @@ {% load i18n inline_formset %} {% block pre_container %} +<button id="autorefreshpage" + class="nav-button btn btn-sm btn-secondary disabled" + data-link="{% url 'current_imports_table' %}" + data-div="import-container" + title="{% trans 'Autorefresh the table (useful when waiting for an import result)' %}"> + <i class="fa fa-refresh" aria-hidden="true"></i> +</button> + <form action="." method="post">{% csrf_token %} {% endblock %} {% block content %} -<h2>{{page_name}}</h2> -<div class='form'> -{% if not object_list %} -<p>{% trans "No pending imports." %}</p> -{% else %} -<table class="table table-striped"> -<tr> - <th>{% trans "Name" %}</th> - <th>{% trans "Type" %}</th> - <th>{% trans "File" context "file" %}</th> - <th>{% trans "Creation" %}</th> - <th>{% trans "Status" %}</th> - <th>{% trans "Action" %}</th> - <th>{% trans "Unmatched items" %}</th> - <th>{% trans "Error" %}</th> - <th>{% trans "Control" %}</th> - <th>{% trans "Match" %}</th> -</tr> -{% for import in object_list %} -<tr> - <td> - {{import.name|default:"-"}} - </td> - <td> - {{import.importer_type}} - </td> - <td> - <a href='{{import.imported_file.url}}'>{% trans "Source file" %}</a> - </td> - <td> - {{import.creation_date}} ({{import.user}}) - </td> - <td> - {{import.status}} - </td> - <td> - <select name='import-action-{{import.pk}}'> - <option value=''>--------</option> - {% for action, lbl in import.get_actions %} - <option value='{{action}}'>{{lbl}}</option> - {% endfor%} - </select> - </td> - <td> - {% if import.need_matching %} - <a href='{% url "import_link_unmatched" import.pk %}'>{% trans "Match"%}</a> - {% endif %} - </td> - <td style="white-space: nowrap;">{% if import.error_file %} - <i class="text-danger fa fa-exclamation-triangle" aria-hidden="true"></i> <a href='{{import.error_file.url}}'>{% trans "File" context "not a directory" %}</a> - {% endif %}</td> - <td>{% if import.result_file %} - <a href='{{import.result_file.url}}'>{% trans "File" context "not a directory" %}</a> - {% endif %}</td> - <td>{% if import.match_file %} - <a href='{{import.match_file.url}}'>{% trans "File" context "not a directory" %}</a> - {% endif %}</td> -</tr> -{% endfor %} -</table> -{% endif %} +<div id="import-container"> + {% include "ishtar/import_table.html" %} </div> {% endblock %} diff --git a/ishtar_common/templates/ishtar/import_table.html b/ishtar_common/templates/ishtar/import_table.html new file mode 100644 index 000000000..95940a4ab --- /dev/null +++ b/ishtar_common/templates/ishtar/import_table.html @@ -0,0 +1,81 @@ +{% load i18n inline_formset %} +<script type="text/javascript"> +var html = $("#message_list").html(); +{% if MESSAGES and AJAX %}{% for message, message_type in MESSAGES %} +html += '<div class="alert alert-{{message_type}} alert-dismissible fade show"'; +html += ' role="alert">'; +html += ' {{message}}'; +html += ' <button type="button" class="close" data-dismiss="alert"'; +html += ' aria-label="Close">'; +html += ' <span aria-hidden="true">×</span>'; +html += ' </button>'; +html += ' </div>'; +{% endfor %}{% endif %} +$("#message_list").html(html); + +$("#import-list").find('select').prop('disabled', true); +$("#import-list").find('input').prop('disabled', true); + +</script> +<h2>{{page_name}}</h2> +<div class='form' id="import-list"> + {% if not object_list %} + <p>{% trans "No pending imports." %}</p> + {% else %} + <table class="table table-striped"> + <tr> + <th>{% trans "Name" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "File" context "file" %}</th> + <th>{% trans "Creation" %}</th> + <th>{% trans "Status" %}</th> + <th>{% trans "Action" %}</th> + <th>{% trans "Unmatched items" %}</th> + <th>{% trans "Error" %}</th> + <th>{% trans "Control" %}</th> + <th>{% trans "Match" %}</th> + </tr> + {% for import in object_list %} + <tr{% if import.pk in refreshed_pks %} class='bg-info'{% endif %}> + <td> + {{import.name|default:"-"}} + </td> + <td> + {{import.importer_type}} + </td> + <td> + <a href='{{import.imported_file.url}}'>{% trans "Source file" %}</a> + </td> + <td> + {{import.creation_date}} ({{import.user}}) + </td> + <td> + {{import.status}} + </td> + <td> + <select name='import-action-{{import.pk}}'> + <option value=''>--------</option> + {% for action, lbl in import.get_actions %} + <option value='{{action}}'>{{lbl}}</option> + {% endfor%} + </select> + </td> + <td> + {% if import.need_matching %} + <a href='{% url "import_link_unmatched" import.pk %}'>{% trans "Match"%}</a> + {% endif %} + </td> + <td style="white-space: nowrap;">{% if import.error_file %} + <i class="text-danger fa fa-exclamation-triangle" aria-hidden="true"></i> <a href='{{import.error_file.url}}'>{% trans "File" context "not a directory" %}</a> + {% endif %}</td> + <td>{% if import.result_file %} + <a href='{{import.result_file.url}}'>{% trans "File" context "not a directory" %}</a> + {% endif %}</td> + <td>{% if import.match_file %} + <a href='{{import.match_file.url}}'>{% trans "File" context "not a directory" %}</a> + {% endif %}</td> + </tr> + {% endfor %} + </table> + {% endif %} +</div> diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index ce3386363..5aa3bb409 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -105,6 +105,10 @@ urlpatterns = [ check_rights(['change_import'])( views.ImportListView.as_view()), name='current_imports'), + url(r'^import-list-table/$', + check_rights(['change_import'])( + views.ImportListTableView.as_view()), + name='current_imports_table'), url(r'^import-list-old/$', check_rights(['change_import'])( views.ImportOldListView.as_view()), diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 675b840ca..948604c16 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -383,3 +383,16 @@ def put_session_message(session_key, message, message_type): messages.append((message, message_type)) session['messages'] = messages session.save() + + +def put_session_var(session_key, key, value): + session = SessionStore(session_key=session_key) + session[key] = value + session.save() + + +def get_session_var(session_key, key): + session = SessionStore(session_key=session_key) + if key not in session: + return + return session[key] diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 66642090f..c2b292ed4 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -1789,9 +1789,9 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView): def get_queryset(self): q = self.model.objects.exclude(state='AC') if self.request.user.is_superuser: - return q.order_by('-creation_date') + return q.order_by('-creation_date').order_by('-end_date') user = models.IshtarUser.objects.get(pk=self.request.user.pk) - return q.filter(user=user).order_by('-creation_date') + return q.filter(user=user).order_by('-end_date') def post(self, request, *args, **kwargs): for field in request.POST: @@ -1824,6 +1824,26 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView): return HttpResponseRedirect(reverse(self.current_url)) +class ImportListTableView(ImportListView): + template_name = 'ishtar/import_table.html' + current_url = 'current_imports_table' + + def get_context_data(self, **kwargs): + dct = super(ImportListTableView, self).get_context_data(**kwargs) + dct['AJAX'] = True + dct['MESSAGES'] = [] + request = self.request + if 'messages' in request.session and \ + request.session['messages']: + for message, message_type in request.session['messages']: + dct['MESSAGES'].append((message, message_type)) + request.session['messages'] = [] + if 'current_import_id' in request.session and \ + request.session['current_import_id']: + dct['refreshed_pks'] = request.session.pop('current_import_id') + return dct + + class ImportOldListView(ImportListView): page_name = _(u"Old imports") current_url = 'old_imports' |