diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-09-05 10:41:24 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2018-10-24 12:06:08 +0200 |
commit | c5e794a0f21d5ebd8db764ae34d8026cf5caf365 (patch) | |
tree | 63a7d4c8f7cb34c6f4c0c9089bfafce00a46dfd8 /ishtar_common | |
parent | 8d6714d0c71137b5b6f05723e9b336f67e10ee09 (diff) | |
download | Ishtar-c5e794a0f21d5ebd8db764ae34d8026cf5caf365.tar.bz2 Ishtar-c5e794a0f21d5ebd8db764ae34d8026cf5caf365.zip |
Quick actions: generic urls, views and forms
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms.py | 15 | ||||
-rw-r--r-- | ishtar_common/models.py | 48 | ||||
-rw-r--r-- | ishtar_common/static/js/ishtar.js | 19 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/DataTables.html | 37 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/qa_form.html | 25 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 5 |
6 files changed, 124 insertions, 25 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 3dfcad09e..4300e9c36 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -640,6 +640,21 @@ class ManageOldType(IshtarForm): self.fields[field.key].help_text = field.get_help() +class QAForm(CustomForm, ManageOldType): + MULTI = False + + def __init__(self, *args, **kwargs): + self.items = kwargs.pop('items') + super(QAForm, self).__init__(*args, **kwargs) + for k in self.fields: + if self.MULTI and k not in self.REPLACE_FIELDS: + self.fields[k].label = unicode(self.fields[k].label) + \ + unicode(u" - append to existing") + else: + self.fields[k].label = unicode(self.fields[k].label) + \ + unicode(u" - replace") + + class DocumentGenerationForm(forms.Form): """ Form to generate document by choosing the template diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 5141ed66d..45ce9f504 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1661,52 +1661,68 @@ class QuickAction(object): """ Quick action available from tables """ - def __init__(self, url, icon='', text='', target=None, rights=None): + def __init__(self, url, icon_class='', text='', target=None, rights=None, + module=None): self.url = url - self.icon = icon + self.icon_class = icon_class self.text = text self.rights = rights self.target = target + self.module = module assert self.target in ('one', 'many', None) def is_available(self, user, session=None, obj=None): + if self.module and not getattr(get_current_profile(), self.module): + return False if not self.rights: # no restriction return True + if not user or not hasattr(user, 'ishtaruser') or not user.ishtaruser: + return False + user = user.ishtaruser + for right in self.rights: if user.has_perm(right, session=session, obj=obj): return True return False - def render(self): - lbl = self.text - if self.icon: - lbl = self.icon + @property + def rendered_icon(self): + if not self.icon_class: + return "" + return u"<i class='{}' aria-hidden='true'></i>".format(self.icon_class) + + @property + def base_url(self): if self.target is None: url = reverse(self.url) else: # put arbitrary pk for the target url = reverse(self.url, args=[0]) - url = url[:-1] # all quick action url have to finish with the - # pk of the selected item - return u'<a href="#" data-url="{}" title="{}">{}</a>'.format( - url, self.text, lbl - ) + url = url[:-2] # all quick action url have to finish with the + # pk of the selected item and a "/" + return url class MainItem(ShortMenuItem): """ - Item with quick actions availables from tables + Item with quick actions available from tables """ QUICK_ACTIONS = [] @classmethod - def render_quick_actions(cls, user, session=None, obj=None): - rendered = [] + def get_quick_actions(cls, user, session=None, obj=None): + """ + Get a list of (url, title, icon, target) actions for an user + """ + qas = [] for action in cls.QUICK_ACTIONS: if not action.is_available(user, session=session, obj=obj): continue - rendered.append(action.render()) - return mark_safe(u" ".join(rendered)) + qas.append([action.base_url, + mark_safe(action.text), + mark_safe(action.rendered_icon), + action.target or ""]) + return qas class LightHistorizedItem(BaseHistorizedItem): diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js index f05eb5a1b..119229e8d 100644 --- a/ishtar_common/static/js/ishtar.js +++ b/ishtar_common/static/js/ishtar.js @@ -761,3 +761,22 @@ function manage_pinned_search(name, data){ } } +var dt_generate_qa_url = function (table, url){ + var data = table.rows( { selected: true } ).data(); + var value = ""; + for (k in data){ + if (!data[k]['id']) continue; + if (k > 0) value += "-"; + value += data[k]['id']; + } + url += value + "/"; + return url; +} + +var dt_qa_open = function (url){ + long_wait(); + $('#modal-dynamic-form').load(url, function(){ + $('#modal-dynamic-form').modal("show"); + close_wait(); + }); +} diff --git a/ishtar_common/templates/blocks/DataTables.html b/ishtar_common/templates/blocks/DataTables.html index 70d47cb8d..7fad1f121 100644 --- a/ishtar_common/templates/blocks/DataTables.html +++ b/ishtar_common/templates/blocks/DataTables.html @@ -162,16 +162,35 @@ jQuery(document).ready(function(){ "select": { "style": {% if multiple_select %}'multi'{% else %}'single'{% endif %} }, - {% if multiple_select %}"buttons": [ - 'selectAll', - 'selectNone' - ], - "language": { - buttons: { - selectAll: "{% trans 'Select all items' %}", - selectNone: "{% trans 'Select none' %}" + {% if multiple_select or quick_actions %}"buttons": [ + {% for url, title, icon, target in quick_actions %} + { + {% if target == 'one' %}extend: 'selectedSingle', + {% elif target == 'many' %}extend: 'selected', + {% endif %} + className: "btn btn-success", + text: "{{icon}}", + titleAttr: "{{title}}", + action: function (e, dt, node, config) { + var url = dt_generate_qa_url(dt, "{{url}}"); + dt_qa_open(url); + return false; + } + }, + {% if not forloop.last %},{% endif %} + {% endfor %}{% if multiple_select %}{% if quick_actions%},{% endif %} + { + extend: 'selectAll', + text: '<i class="fa fa-check-circle-o"></i>', + titleAttr: "{% trans 'Select all items' %}" + }, + { + extend: 'selectNone', + text: '<i class="fa fa-times"></i>', + titleAttr: "{% trans 'Deselect' %}" } - }, + {% endif %} + ], "dom": 'lBtip', {% else %} "dom": 'ltip', diff --git a/ishtar_common/templates/ishtar/qa_form.html b/ishtar_common/templates/ishtar/qa_form.html new file mode 100644 index 000000000..95f8887a8 --- /dev/null +++ b/ishtar_common/templates/ishtar/qa_form.html @@ -0,0 +1,25 @@ +{% load i18n inline_formset table_form %} + +<div class="modal-dialog modal-lg modal-dialog-centered"> + <div class="modal-content" id='progress-content'> + <div class="modal-header"> + <h2>{{page_name}}</h2> + </div> + <form enctype="multipart/form-data" action="." method="post">{% csrf_token %} + <div class="modal-body"> + <div class='form'> + {% for error in form.non_field_errors %} + <p>{{ error }}</p> + {% endfor %} + {% bs_form form %} + </div> + <button type="submit" id="submit_form" name='validate' + value="validate" class="btn btn-success"> + {% trans "Modify" %} + </button> + </div> + </form> + </div> +</div> + + diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index fc8926364..b5e1f5891 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -1033,6 +1033,7 @@ class DataTable(Select2Media, forms.RadioSelect): # dct['source_full'] = unicode(self.source_full) dct['extra_sources'] = [] + dct['quick_actions'] = [] if self.associated_model: model_name = "{}.{}".format( self.associated_model.__module__, @@ -1043,6 +1044,10 @@ class DataTable(Select2Media, forms.RadioSelect): dct['extra_sources'].append(( imp.slug, imp.name, reverse('get-by-importer', args=[imp.slug]))) + if hasattr(self.associated_model, "QUICK_ACTIONS"): + dct['quick_actions'] = \ + self.associated_model.get_quick_actions(user=self.user) + self.multiple_select = True source = unicode(self.source) dct.update({'name': name, 'col_names': col_names, |