Projet

Général

Profil

0001-applications-sort-elements-by-category-in-add-popup-.patch

Lauréline Guérin, 14 novembre 2022 14:33

Télécharger (8,95 ko)

Voir les différences:

Subject: [PATCH] applications: sort elements by category in add popup (#63883)

 .../hobo/applications/add-element.html        | 15 ++++++-
 hobo/applications/views.py                    | 45 ++++++++++++++++++-
 tests/test_application.py                     | 44 ++++++++++++++++--
 tox.ini                                       |  1 +
 4 files changed, 98 insertions(+), 7 deletions(-)
hobo/applications/templates/hobo/applications/add-element.html
9 9
  <form method="post">
10 10
    {% csrf_token %}
11 11
    <div class="application-elements">
12
      {% for element in elements %}
13
        <label data-slugged-text="{{ element.text|slugify }}"><input type="checkbox" name="elements" value="{{ element.id }}">{{ element.text }}</label>
12
      {% for category in categories %}
13
        <div>
14
          <h4>{{ category.name }}</h4>
15
          {% for element in category.elements %}
16
            <label data-slugged-text="{{ element.text|slugify }}"><input type="checkbox" name="elements" value="{{ element.id }}">{{ element.text }}</label>
17
          {% endfor %}
18
        </div>
14 19
      {% endfor %}
15 20
    </div>
16 21
    <div style="text-align: right">
......
27 32
        $('.application-elements').css('height', $('.application-elements').height());
28 33
        $('.application-elements').css('width', $('.application-elements').width());
29 34
        if (!val) {
35
          $('.application-elements div').show();
30 36
          $('.application-elements label').show();
31 37
        } else {
32 38
          $('.application-elements label').each(function(idx, elem) {
39
            var container = $(elem).parent();
33 40
            var slugged_text = $(elem).attr('data-slugged-text');
34 41
            if (slugged_text.indexOf(val) > -1) {
35 42
              $(elem).show();
43
              container.show();
36 44
            } else {
37 45
              $(elem).hide();
46
              if (!$('label:visible', container).lenght) {
47
                container.hide();
48
              }
38 49
            }
39 50
          });
40 51
        }
hobo/applications/views.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import dataclasses
17 18
import io
18 19
import json
20
import re
19 21
import tarfile
22
import unicodedata
20 23
import urllib.parse
21 24

  
22 25
from django.conf import settings
......
25 28
from django.http import HttpResponse, HttpResponseRedirect
26 29
from django.shortcuts import get_object_or_404
27 30
from django.urls import reverse, reverse_lazy
31
from django.utils.encoding import force_text
28 32
from django.utils.translation import ugettext_lazy as _
29 33
from django.views.generic import DetailView, FormView, ListView, TemplateView
30 34
from django.views.generic.edit import CreateView, DeleteView, UpdateView
......
146 150
metadata = MetadataView.as_view()
147 151

  
148 152

  
153
@dataclasses.dataclass
154
class Category:
155
    name: str
156
    elements: list
157

  
158

  
159
def simplify(s, space='-'):
160
    if s is None:
161
        return ''
162
    s = force_text(unicodedata.normalize('NFKD', s).encode('ascii', 'ignore'))
163
    s = re.sub(r'[^\w\s\'%s]' % space, '', s).strip().lower()
164
    s = re.sub(r'[\s\'%s]+' % space, space, s)
165
    return s
166

  
167

  
149 168
class AppAddElementView(TemplateView):
150 169
    template_name = 'hobo/applications/add-element.html'
151 170

  
......
157 176
                context['type'] = object_type
158 177
                url = object_type['urls']['list']
159 178
                response = requests.get(url)
160
                context['elements'] = response.json()['data']
179
                elements = response.json()['data']
180
                category_names = {el.get('category') or '' for el in elements}
181
                categories = [
182
                    Category(
183
                        name=c,
184
                        elements=sorted(
185
                            [el for el in elements if el.get('category') == c],
186
                            key=lambda a: simplify(a['text']),
187
                        ),
188
                    )
189
                    for c in sorted(list(category_names))
190
                    if c
191
                ]
192
                categories.append(
193
                    Category(
194
                        name=_('Uncategorized'),
195
                        elements=sorted(
196
                            [el for el in elements if not el.get('category')],
197
                            key=lambda a: simplify(a['text']),
198
                        ),
199
                    )
200
                )
201
                context['categories'] = categories
161 202
                break
162 203
        return context
163 204

  
164 205
    def post(self, request, app_slug, type):
165 206
        context = self.get_context_data()
166 207
        app = context['app']
167
        element_infos = {x['id']: x for x in context['elements']}
208
        element_infos = {x['id']: x for c in context['categories'] for x in c.elements}
168 209
        for element_slug in request.POST.getlist('elements'):
169 210
            element, created = Element.objects.get_or_create(
170 211
                type=type, slug=element_slug, defaults={'name': element_infos[element_slug]['text']}
tests/test_application.py
7 7
import httmock
8 8
import pytest
9 9
from httmock import HTTMock
10
from pyquery import PyQuery
10 11
from test_manager import login
11 12
from webtest import Upload
12 13

  
......
102 103
                "dependencies": "https://wcs.example.invalid/api/export-import/forms/test2-form/dependencies/",
103 104
            },
104 105
        },
106
        {
107
            "id": "foo2-form",
108
            "text": "Foo2 Test Form",
109
            "type": "forms",
110
            "category": "Foo",
111
            "urls": {
112
                "export": "https://wcs.example.invalid/api/export-import/forms/foo2-form/",
113
                "dependencies": "https://wcs.example.invalid/api/export-import/forms/foo2-form/dependencies/",
114
            },
115
        },
116
        {
117
            "id": "foo-form",
118
            "text": "Foo Test Form",
119
            "type": "forms",
120
            "category": "Foo",
121
            "urls": {
122
                "export": "https://wcs.example.invalid/api/export-import/forms/foo-form/",
123
                "dependencies": "https://wcs.example.invalid/api/export-import/forms/foo-form/dependencies/",
124
            },
125
        },
126
        {
127
            "id": "bar-form",
128
            "text": "Bar Test Form",
129
            "type": "forms",
130
            "category": "Bar",
131
            "urls": {
132
                "export": "https://wcs.example.invalid/api/export-import/forms/bar-form/",
133
                "dependencies": "https://wcs.example.invalid/api/export-import/forms/bar-form/dependencies/",
134
            },
135
        },
105 136
    ]
106 137
}
107 138

  
......
203 234
        # add forms
204 235
        assert '/add/forms/' in resp
205 236
        resp = resp.click('Forms')
206
        assert resp.form.fields['elements'][0]._value == 'test-form'
207
        assert resp.form.fields['elements'][1]._value == 'test2-form'
208
        resp.form.fields['elements'][0].checked = True
237
        assert len(resp.pyquery('.application-elements div')) == 3
238
        assert resp.pyquery('.application-elements div:nth-child(1) h4').text() == 'Bar'
239
        assert PyQuery(resp.pyquery('.application-elements div:nth-child(1) input')[0]).val() == 'bar-form'
240
        assert resp.pyquery('.application-elements div:nth-child(2) h4').text() == 'Foo'
241
        assert PyQuery(resp.pyquery('.application-elements div:nth-child(2) input')[0]).val() == 'foo-form'
242
        assert PyQuery(resp.pyquery('.application-elements div:nth-child(2) input')[1]).val() == 'foo2-form'
243
        assert resp.pyquery('.application-elements div:nth-child(3) h4').text() == 'Uncategorized'
244
        assert PyQuery(resp.pyquery('.application-elements div:nth-child(3) input')[0]).val() == 'test2-form'
245
        assert PyQuery(resp.pyquery('.application-elements div:nth-child(3) input')[1]).val() == 'test-form'
246
        resp.form.fields['elements'][4].checked = True
209 247
        resp = resp.form.submit().follow()
210 248
        assert application.elements.count() == 1
211 249
        element = application.elements.all()[0]
tox.ini
42 42
	pytest-cov
43 43
	pytest-django
44 44
	pytest-mock
45
	pyquery
45 46
	coverage
46 47
	cssselect
47 48
	WebTest
48
-