diff options
| -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'  | 
