diff --git a/app/apps/authenticatie/managers.py b/app/apps/authenticatie/managers.py index a2e412cc..7e68a08e 100644 --- a/app/apps/authenticatie/managers.py +++ b/app/apps/authenticatie/managers.py @@ -1,6 +1,6 @@ from django.contrib.auth.base_user import BaseUserManager from django.contrib.auth.hashers import make_password -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class GebruikerManager(BaseUserManager): diff --git a/app/apps/authenticatie/signal_receivers.py b/app/apps/authenticatie/signal_receivers.py index 4b2fdc93..9d9ed4e4 100644 --- a/app/apps/authenticatie/signal_receivers.py +++ b/app/apps/authenticatie/signal_receivers.py @@ -12,6 +12,8 @@ @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): + if kwargs.get("raw"): + return if not hasattr(instance, "profiel"): Profiel.objects.create(gebruiker=instance) try: diff --git a/app/apps/authorisatie/apps.py b/app/apps/authorisatie/apps.py new file mode 100644 index 00000000..eb0fadb8 --- /dev/null +++ b/app/apps/authorisatie/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AuthorisatieConfig(AppConfig): + name = "apps.authorisatie" + verbose_name = "Authorisatie" diff --git a/app/apps/context/forms.py b/app/apps/context/forms.py index d6ea0aea..8c5cca6b 100644 --- a/app/apps/context/forms.py +++ b/app/apps/context/forms.py @@ -3,7 +3,6 @@ from apps.context.constanten import FILTERS, KOLOMMEN from apps.context.models import Context from django import forms -from utils.forms import RadioSelect class CheckboxSelectMultiplePaths(forms.CheckboxSelectMultiple): @@ -50,7 +49,7 @@ def optgroups(self, name, value, attrs=None): class ContextAanpassenForm(forms.ModelForm): template = forms.ChoiceField( - widget=RadioSelect( + widget=forms.RadioSelect( attrs={ "class": "list--form-radio-input", } diff --git a/app/apps/context/templates/context/context_form.html b/app/apps/context/templates/context/context_form.html index eaa7d397..7bf67857 100644 --- a/app/apps/context/templates/context/context_form.html +++ b/app/apps/context/templates/context/context_form.html @@ -56,9 +56,12 @@

Rol aanmaken

{{ form.kolommen|render_rotterdam_formulier }}

Onderwerpen

- {{ form.standaard_filters }} +
{{ form.standaard_filters }}
+
+
+

{{ form.taaktypes.label_tag }}

+ {{ form.taaktypes }}
- {{ form.taaktypes|render_rotterdam_formulier }} {{ form.template|render_rotterdam_formulier }}
diff --git a/app/apps/context/templatetags/main_tags.py b/app/apps/context/templatetags/main_tags.py index a439cb47..56bc8127 100644 --- a/app/apps/context/templatetags/main_tags.py +++ b/app/apps/context/templatetags/main_tags.py @@ -1,4 +1,5 @@ import json +import os from datetime import datetime from django import template @@ -87,3 +88,10 @@ def python_any(values): if values: return any(values) return values + + +@register.filter +def file_exists(file_path): + return os.path.isfile( + os.path.join(settings.BASE_DIR, "apps/main/templates/", file_path) + ) diff --git a/app/apps/main/apps.py b/app/apps/main/apps.py new file mode 100644 index 00000000..3244b3a0 --- /dev/null +++ b/app/apps/main/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MainConfig(AppConfig): + name = "apps.main" + verbose_name = "Main" diff --git a/app/apps/main/forms.py b/app/apps/main/forms.py index d79879c4..13736e44 100644 --- a/app/apps/main/forms.py +++ b/app/apps/main/forms.py @@ -18,6 +18,24 @@ logger = logging.getLogger(__name__) +class MultipleFileInput(forms.ClearableFileInput): + allow_multiple_selected = True + + +class MultipleFileField(forms.FileField): + def __init__(self, *args, **kwargs): + kwargs.setdefault("widget", MultipleFileInput()) + super().__init__(*args, **kwargs) + + def clean(self, data, initial=None): + single_file_clean = super().clean + if isinstance(data, (list, tuple)): + result = [single_file_clean(d, initial) for d in data] + else: + result = [single_file_clean(data, initial)] + return result + + class CheckboxSelectMultiple(forms.CheckboxSelectMultiple): template_name = "widgets/checkbox_options_grouped.html" @@ -273,13 +291,14 @@ class InformatieToevoegenForm(forms.Form): max_length=5000, ) - bijlagen_extra = forms.FileField( - widget=forms.widgets.FileInput( + bijlagen_extra = MultipleFileField( + widget=MultipleFileInput( attrs={ "accept": ".jpg, .jpeg, .png, .heic", "data-action": "change->bijlagen#updateImageDisplay", "data-bijlagen-target": "bijlagenExtra", - "multiple": "multiple", + "class": "file-upload-input", + # "multiple": "multiple", } ), label="Voeg één of meerdere foto's toe", @@ -291,7 +310,7 @@ class TaakStartenForm(forms.Form): afdeling = forms.ChoiceField( label="Afdeling", required=True, - widget=RadioSelect( + widget=forms.RadioSelect( attrs={ "class": "form-check-input", } @@ -299,7 +318,7 @@ class TaakStartenForm(forms.Form): ) onderwerp_gerelateerd_taaktype = forms.ChoiceField( - widget=RadioSelect( + widget=forms.RadioSelect( attrs={ "data-taakstartenformulier-target": "onderwerpGerelateerdTaaktypeField", "class": "form-check-input", @@ -310,7 +329,7 @@ class TaakStartenForm(forms.Form): ) taaktype = forms.ChoiceField( - widget=RadioSelect( + widget=forms.RadioSelect( attrs={ "data-taakstartenformulier-target": "taaktypeField", "class": "form-check-input", @@ -364,7 +383,7 @@ def __init__(self, *args, **kwargs): class TaakAfrondenForm(forms.Form): resolutie = forms.ChoiceField( - widget=RadioSelect( + widget=forms.RadioSelect( attrs={ "class": "list--form-radio-input", "data-action": "change->bijlagen#updateImageDisplay", @@ -374,13 +393,14 @@ class TaakAfrondenForm(forms.Form): choices=[[x[4], x[1]] for x in TAAK_BEHANDEL_OPTIES], required=True, ) - bijlagen = forms.FileField( - widget=forms.widgets.FileInput( + bijlagen = MultipleFileField( + widget=MultipleFileInput( attrs={ "accept": ".jpg, .jpeg, .png, .heic", "data-action": "change->bijlagen#updateImageDisplay", "data-bijlagen-target": "bijlagenAfronden", - "multiple": "multiple", + "class": "file-upload-input", + # "multiple": "multiple", } ), label="Foto's", @@ -818,13 +838,14 @@ class MeldingAanmakenForm(forms.Form): required=True, ) - bijlagen = forms.FileField( - widget=forms.widgets.FileInput( + bijlagen = MultipleFileField( + widget=MultipleFileInput( attrs={ "accept": ".jpg, .jpeg, .png, .heic", "data-action": "change->bijlagen#updateImageDisplay", "data-bijlagen-target": "bijlagenNieuw", - "multiple": "multiple", + "class": "file-upload-input", + # "multiple": "multiple", } ), label="Foto's", diff --git a/app/apps/main/templates/django/forms/widgets/checkbox_select.html b/app/apps/main/templates/django/forms/widgets/checkbox_select.html new file mode 100644 index 00000000..737a6187 --- /dev/null +++ b/app/apps/main/templates/django/forms/widgets/checkbox_select.html @@ -0,0 +1,68 @@ +{% load file_exists from main_tags %} +{% load l10n %} +{% with id=widget.attrs.id %} +
+ {% if id and not widget.attrs.hideLabel %} +

+ {{ widget.label }}{{ widget.attrs.hideLabel }} +

+ {% endif %} + {% if widget.attrs.hasMoreInfo and widget.help_text %} +
+

{% include "icons/info-filled.svg" %}

+

{{ widget.help_text|safe }}

+
+ {% endif %} + {% if widget.attrs.showSelectAll %} +
+ + | + +
+ {% endif %} +
+
    + {% for group, options, index in widget.optgroups %} + {% if group %} +
  • + {{ group }} +
      + {% endif %} + {% for option in options %} +
    • +
      + {% include "django/forms/widgets/input.html" with widget=option %} + +
      +
    • + {% endfor %} + {% if group %} +
    +
  • + {% endif %} + {% endfor %} +
+
+
+{% endwith %} diff --git a/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html b/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html new file mode 100644 index 00000000..70d25a5f --- /dev/null +++ b/app/apps/main/templates/django/forms/widgets/checkbox_select_old.html @@ -0,0 +1,26 @@ +{% with id=widget.attrs.id %} +
+ +
+{% endwith %} diff --git a/app/apps/main/templates/django/forms/widgets/clearable_file_input.html b/app/apps/main/templates/django/forms/widgets/clearable_file_input.html new file mode 100644 index 00000000..7603115c --- /dev/null +++ b/app/apps/main/templates/django/forms/widgets/clearable_file_input.html @@ -0,0 +1,30 @@ +
+ + {% if field.help_text %}

{{ field.help_text|safe }}

{% endif %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + +
diff --git a/app/apps/main/templates/django/forms/widgets/file.html b/app/apps/main/templates/django/forms/widgets/file.html new file mode 100644 index 00000000..380c0663 --- /dev/null +++ b/app/apps/main/templates/django/forms/widgets/file.html @@ -0,0 +1,30 @@ +
+ + {% if field.help_text %}

{{ field.help_text|safe }}

{% endif %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + +
diff --git a/app/apps/main/templates/django/forms/widgets/multiple_input.html b/app/apps/main/templates/django/forms/widgets/multiple_input.html new file mode 100644 index 00000000..0d2acf25 --- /dev/null +++ b/app/apps/main/templates/django/forms/widgets/multiple_input.html @@ -0,0 +1,19 @@ +{% with id=widget.attrs.id %} + +{% endwith %} diff --git a/app/apps/main/templates/widgets/checkbox_select.html b/app/apps/main/templates/widgets/checkbox_select.html new file mode 100644 index 00000000..a80a5ac9 --- /dev/null +++ b/app/apps/main/templates/widgets/checkbox_select.html @@ -0,0 +1,31 @@ +{% with id=widget.attrs.id %} +
+ {% if not widget.attrs.hideLabel %} +

+ {{ field.label }}{{ widget.attrs.hideLabel }} +

+ {% endif %} + +
+{% endwith %} diff --git a/app/apps/main/templates/widgets/radio_option.html b/app/apps/main/templates/widgets/radio_option.html index d67c0b3c..08b1e61c 100644 --- a/app/apps/main/templates/widgets/radio_option.html +++ b/app/apps/main/templates/widgets/radio_option.html @@ -1,3 +1 @@ {% include "django/forms/widgets/input.html" %} - diff --git a/app/apps/main/templates/widgets/radio_option_simple.html b/app/apps/main/templates/widgets/radio_option_simple.html index d67c0b3c..08b1e61c 100644 --- a/app/apps/main/templates/widgets/radio_option_simple.html +++ b/app/apps/main/templates/widgets/radio_option_simple.html @@ -1,3 +1 @@ {% include "django/forms/widgets/input.html" %} - diff --git a/app/apps/main/views.py b/app/apps/main/views.py index 9f2310d6..ba4498e9 100644 --- a/app/apps/main/views.py +++ b/app/apps/main/views.py @@ -62,7 +62,13 @@ from django.core.cache import cache from django.core.files.storage import default_storage from django.db.models import Q -from django.http import HttpResponse, JsonResponse, QueryDict, StreamingHttpResponse +from django.http import ( + HttpResponse, + HttpResponseRedirect, + JsonResponse, + QueryDict, + StreamingHttpResponse, +) from django.shortcuts import redirect, render from django.template.loader import render_to_string from django.urls import reverse, reverse_lazy @@ -1299,6 +1305,9 @@ class StandaardExterneOmschrijvingVerwijderenView( def get(self, request, *args, **kwargs): return self.post(request, *args, **kwargs) + def render_to_response(self, context, **response_kwargs): + return HttpResponseRedirect(self.get_success_url()) + # Locatie views diff --git a/app/apps/release_notes/forms.py b/app/apps/release_notes/forms.py index 43d5a309..538f35e2 100644 --- a/app/apps/release_notes/forms.py +++ b/app/apps/release_notes/forms.py @@ -48,7 +48,7 @@ class ReleaseNoteAanpassenForm(forms.ModelForm): "accept": ".jpg, .jpeg, .png, .heic, .gif", "data-action": "change->bijlagen#updateImageDisplay", "data-bijlagen-target": "bijlagenExtra", - "multiple": "multiple", + # "multiple": "multiple", "hideLabel": True, } ), diff --git a/app/config/settings.py b/app/config/settings.py index 9c2569b9..a4b968ec 100644 --- a/app/config/settings.py +++ b/app/config/settings.py @@ -16,9 +16,12 @@ SECRET_KEY = os.getenv( "DJANGO_SECRET_KEY", os.getenv("SECRET_KEY", os.getenv("APP_SECRET")) ) + +# APP_ENV's PRODUCTIE = "productie" ACCEPTATIE = "acceptatie" TEST = "test" + APP_ENV = os.getenv("APP_ENV", PRODUCTIE) # acceptatie/test/productie GIT_SHA = os.getenv("GIT_SHA") DEPLOY_DATE = os.getenv("DEPLOY_DATE", "") @@ -45,6 +48,7 @@ INSTALLED_APPS = ( # templates override + "apps.main", "apps.health", "django.contrib.humanize", "django.contrib.contenttypes", @@ -56,6 +60,7 @@ "django.contrib.admin", "django.contrib.gis", "django.contrib.postgres", + "django.forms", "rest_framework", "rest_framework.authtoken", "drf_spectacular", @@ -76,7 +81,6 @@ "django_select2", # Apps "apps.rotterdam_formulier_html", - "apps.main", "apps.authorisatie", "apps.authenticatie", "apps.context", @@ -305,6 +309,7 @@ ) ) +FORM_RENDERER = "django.forms.renderers.TemplatesSetting" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", diff --git a/app/frontend/assets/controllers/taakstartenformulier_controller.js b/app/frontend/assets/controllers/taakstartenformulier_controller.js index d4d924f1..34cf945e 100644 --- a/app/frontend/assets/controllers/taakstartenformulier_controller.js +++ b/app/frontend/assets/controllers/taakstartenformulier_controller.js @@ -60,8 +60,14 @@ export default class extends Controller { handleTaaktypeChoices() { const self = this - this.afdelingFieldTarget.addEventListener('change', (event) => { - const selectedAfdeling = event.target.value + this.afdelingFieldTarget.addEventListener('change', (e) => { + const selectedAfdeling = e.target + const list = e.target.closest('ul').getElementsByTagName('label') + + for (let item of list) { + item.classList.remove('checked') + } + e.target.parentNode.classList.add('checked') self.clearSearch() self.filterTaaktypes(selectedAfdeling) @@ -163,7 +169,7 @@ export default class extends Controller { input.name = 'taaktype' input.value = value input.id = `id_taaktype_${index}` - input.className = 'form-check-input' + input.className = 'form-check-input hooooi' input.required = true input.setAttribute('data-taakstartenformulier-target', 'taaktypeField') diff --git a/app/frontend/assets/styles/_theme.scss b/app/frontend/assets/styles/_theme.scss index b37b6466..637aea77 100644 --- a/app/frontend/assets/styles/_theme.scss +++ b/app/frontend/assets/styles/_theme.scss @@ -85,6 +85,7 @@ $container-max-widths: ( lg: 832px, xl: 992px, xxl: 1152px, + xxxl: 1280px, ); // rotterdam-ui extension: we have extra margins *outside* the normal diff --git a/app/frontend/assets/styles/components/_forms.scss b/app/frontend/assets/styles/components/_forms.scss index 1f1d6fa5..c995d33a 100644 --- a/app/frontend/assets/styles/components/_forms.scss +++ b/app/frontend/assets/styles/components/_forms.scss @@ -285,11 +285,14 @@ textarea { ~ .form-radio-label { line-height: 1.5rem; font-weight: 400; + font-size: 1rem; } } .list--form-check-input, -.list--form-radio-input { +.list--form-radio-input, +.list--form-check-input ul, +.list--form-radio-input ul { @include list-clean(); li { margin-bottom: 0.25rem; @@ -517,6 +520,15 @@ input.form-radio-input { margin: 0; } } + + .list--grouped { + font-weight: 700; + font-size: 1rem; + ul ul { + font-weight: 400; + margin: $input-padding-y 0; + } + } } .wrapper-horizontal { @@ -673,6 +685,7 @@ input.form-radio-input { border: 0; border-radius: 0; color: $white; + white-space: initial; .select2-selection__choice__remove { height: 100%; @@ -821,8 +834,9 @@ form.taak--start { padding: $input-padding-y 0; border-top: 1px solid $gray-tint04; border-bottom: 1px solid $gray-tint04; - max-height: 295px; + max-height: 300px; overflow: auto; + box-sizing: border-box; ul { margin: 0 0 0 2px; @@ -845,6 +859,22 @@ form.taak--start { margin-bottom: 0; } } + label { + display: block; + padding: 0.25em 0.5em; + border-left: 3px solid $gray-tint01; + line-height: 1.5em; + font-weight: 400; + cursor: pointer; + + &.checked, + &:hover, + &:focus { + border-color: $green-tint01; + color: $green-tint01; + font-weight: 700; + } + } input.form-check-input { -webkit-appearance: none; position: relative; @@ -853,24 +883,6 @@ form.taak--start { position: absolute; border: 0; box-shadow: none; - - + label { - display: block; - padding: 0.25em 0.5em; - border-left: 3px solid $gray-tint01; - cursor: pointer; - } - &:checked, - &:hover, - &:focus { - border: 0; - - + label { - border-color: $green-tint01; - color: $green-tint01; - font-weight: 700; - } - } } .inactive { diff --git a/app/frontend/assets/styles/components/_modal.scss b/app/frontend/assets/styles/components/_modal.scss index a1b5b180..73e95261 100644 --- a/app/frontend/assets/styles/components/_modal.scss +++ b/app/frontend/assets/styles/components/_modal.scss @@ -66,7 +66,7 @@ body.show-modal--first-filter { max-width: map-get($container-max-widths, md); } &--wide { - max-width: 100%; + max-width: map-get($container-max-widths, xxxl); } } diff --git a/app/requirements.txt b/app/requirements.txt index a4317564..586547de 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,8 +1,8 @@ -Django==3.2.16 +Django==4.2.15 django-filter==22.1 -djangorestframework==3.13.1 +djangorestframework==3.15.1 drf-spectacular==0.26.0 -uWSGI==2.0.22 +uWSGI==2.0.25.1 django-webpack-loader==1.7.0 requests==2.29.0 debugpy @@ -18,9 +18,9 @@ mozilla-django-oidc==3.0.0 PyJWT<2.4.0 django-session-timeout-joinup==1.0.0 deepdiff==6.7.1 -celery==5.2.6 -django-celery-beat==2.2.1 -django-celery-results==2.4.0 +celery==5.4.0 +django-celery-beat==2.5.0 +django-celery-results==2.5.1 django-select2==8.1.2 Pillow==9.4.0 pillow-heif==0.13.0 diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml index 4952e405..dc3afd44 100644 --- a/docker-compose.test.yaml +++ b/docker-compose.test.yaml @@ -23,7 +23,7 @@ services: - "6379" database: - image: postgis/postgis:11-3.3 + image: postgis/postgis:16-3.4 shm_size: "1024m" ports: - "5432" diff --git a/docker-compose.yaml b/docker-compose.yaml index 559a6088..87aa1263 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -46,14 +46,14 @@ services: - "6379" database: - image: postgis/postgis:11-3.3 + image: postgis/postgis:16-3.4 shm_size: "1024m" ports: - "7997:5432" env_file: - .env.local volumes: - - postgres-data:/var/lib/postgresql/data + - postgres-data-16:/var/lib/postgresql/data healthcheck: test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ] interval: 5s @@ -115,7 +115,7 @@ services: - mercure_config:/config volumes: - postgres-data: + postgres-data-16: mercure_data: mercure_config: