summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
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
commitc5e794a0f21d5ebd8db764ae34d8026cf5caf365 (patch)
tree63a7d4c8f7cb34c6f4c0c9089bfafce00a46dfd8 /ishtar_common
parent8d6714d0c71137b5b6f05723e9b336f67e10ee09 (diff)
downloadIshtar-c5e794a0f21d5ebd8db764ae34d8026cf5caf365.tar.bz2
Ishtar-c5e794a0f21d5ebd8db764ae34d8026cf5caf365.zip
Quick actions: generic urls, views and forms
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms.py15
-rw-r--r--ishtar_common/models.py48
-rw-r--r--ishtar_common/static/js/ishtar.js19
-rw-r--r--ishtar_common/templates/blocks/DataTables.html37
-rw-r--r--ishtar_common/templates/ishtar/qa_form.html25
-rw-r--r--ishtar_common/widgets.py5
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,