Konova Codelist enhancements

* adds proper boolean mapping to update_codelist
* differs between id and atom_id for KonovaCode since atomIds are not unique (could change in the future)
* adds is_selectable and is_archived to KonovaCode
* scales width of DAL form fields to 100% width
* adds table-responsive wrapping container for table forms to prevent unwanted rendering artifacts in case of table resizing due to long content
* adds autocomplete routes for law, registration offices and conservation offices
This commit is contained in:
mipel 2021-08-26 12:45:48 +02:00
parent d33cf5ad4e
commit 97571d4363
8 changed files with 107 additions and 73 deletions

View File

@ -16,17 +16,21 @@ class KonovaCodeListAdmin(admin.ModelAdmin):
class KonovaCodeAdmin(admin.ModelAdmin):
list_display = [
"id",
"atom_id",
"parent",
"short_name",
"long_name",
"is_leaf",
"is_active",
"is_selectable",
"is_archived",
]
readonly_fields = [
"id",
"short_name",
"long_name",
"is_archived",
"is_selectable",
"is_leaf",
"parent",
]

View File

@ -15,6 +15,10 @@ from codelist.settings import CODELIST_INTERVENTION_HANDLER_ID, CODELIST_CONSERV
CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_CLASS_ID, CODELIST_COMPENSATION_ADDITIONAL_TYPE_ID, \
CODELIST_COMPENSATION_COMBINATION_ID, CODELIST_BASE_URL
bool_map = {
"true": True,
"false": False,
}
class Command(BaseCommand):
help = "Performs test on collisions using the identifier generation"
@ -56,41 +60,6 @@ class Command(BaseCommand):
code_list=code_list,
parent=None,
)
"""
for element in items:
atom_id = element.find("atomid").text
parent = element.find("vaterid").text
short_name = element.find("shortname").text
long_name = element.find("longname").text
is_archived = bool(element.find("archive").text)
# If a parent has been set, we need to fetch/create this entry. Otherwise ("0") we ignore it.
if parent == "0":
parent = None
else:
parent = KonovaCode.objects.get_or_create(
id=parent,
)[0]
code = KonovaCode.objects.get_or_create(
id=atom_id,
)
created = code[1]
if created:
num_created += 1
else:
num_updated += 1
code = code[0]
code.short_name = short_name
code.long_name = long_name
code.parent = parent
code.is_active = is_archived
code.save()
if code not in code_list.codes.all():
code_list.codes.add(code)
"""
except KeyboardInterrupt:
self._break_line()
@ -102,19 +71,24 @@ class Command(BaseCommand):
else:
for element in items:
children = element.find("items")
_id = element.find("id").text
atom_id = element.find("atomid").text
selectable = element.find("selectable").text.lower()
selectable = bool_map.get(selectable, False)
short_name = element.find("shortname").text
long_name = element.find("longname").text
is_archived = bool(element.find("archive").text)
is_archived = bool_map.get((element.find("archive").text.lower()), False)
code = KonovaCode.objects.get_or_create(
id=atom_id,
id=_id,
)
code = code[0]
code.atom_id = atom_id
code.short_name = short_name
code.long_name = long_name
code.parent = parent
code.is_active = is_archived
code.is_selectable = selectable
code.is_archived = is_archived
code.is_leaf = children is None
code.save()

View File

@ -10,7 +10,12 @@ class KonovaCode(models.Model):
"""
id = models.IntegerField(
primary_key=True,
help_text="AtomId; Identifies this code uniquely over all NatIT projects"
help_text="Regular Id"
)
atom_id = models.IntegerField(
help_text="AtomId; Identifies this code uniquely over all NatIT projects; Duplicates possible",
null=True,
blank=True,
)
parent = models.ForeignKey(
"KonovaCode",
@ -30,20 +35,27 @@ class KonovaCode(models.Model):
blank=True,
help_text="",
)
is_selectable = models.BooleanField(
default=False,
help_text="Whether this code shall be used for any select actions or not"
)
is_leaf = models.BooleanField(
default=False,
help_text="Whether this code has children or not"
)
is_active = models.BooleanField(
is_archived = models.BooleanField(
default=False,
help_text="Whether this code is archived or not"
)
def __str__(self):
ret_val = ""
if self.parent:
ret_val += self.parent.long_name + " > "
ret_val += self.long_name
if self.short_name:
return "{} ({})".format(self.long_name, self.short_name)
else:
return self.long_name
ret_val += " ({})".format(self.short_name)
return ret_val
class KonovaCodeList(models.Model):

View File

@ -16,7 +16,7 @@ from django.utils.translation import gettext_lazy as _
from django.utils.translation import pgettext_lazy as _con
from codelist.models import KonovaCode
from codelist.settings import CODELIST_BIOTOPES_ID
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID
from compensation.models import Payment, CompensationState, CompensationAction, UnitChoices
from konova.contexts import BaseContext
from konova.forms import BaseForm, BaseModalForm
@ -106,7 +106,7 @@ class NewStateModalForm(BaseModalForm):
required=True,
help_text=_("Select the biotope type"),
queryset=KonovaCode.objects.filter(
is_active=True,
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_BIOTOPES_ID],
),
@ -278,13 +278,14 @@ class NewActionModalForm(BaseModalForm):
required=True,
help_text=_("Select the action type"),
queryset=KonovaCode.objects.filter(
is_active=True,
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_COMPENSATION_ACTION_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-compensation-action-autocomplete",
attrs={
"data-placeholder": _("Action"),
"data-class": "w-100",
}
),
)

View File

@ -9,7 +9,8 @@ from dal_select2.views import Select2QuerySetView
from django.db.models import Q
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, CODELIST_LAW_ID, \
CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID
from compensation.models import EcoAccount
from intervention.models import Intervention
from organisation.models import Organisation
@ -92,7 +93,8 @@ class KonovaCodeAutocomplete(Select2QuerySetView):
if self.request.user.is_anonymous:
return KonovaCode.objects.none()
qs = KonovaCode.objects.filter(
is_active=True,
is_archived=False,
is_selectable=True,
is_leaf=True,
).order_by(
"long_name"
@ -125,3 +127,30 @@ class BiotopeCodeAutocomplete(KonovaCodeAutocomplete):
def __init__(self, *args, **kwargs):
self.c = CODELIST_BIOTOPES_ID
super().__init__(*args, **kwargs)
class LawCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
def __init__(self, *args, **kwargs):
self.c = CODELIST_LAW_ID
super().__init__(*args, **kwargs)
class RegistrationOfficeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
def __init__(self, *args, **kwargs):
self.c = CODELIST_REGISTRATION_OFFICE_ID
super().__init__(*args, **kwargs)
class ConservationOfficeCodeAutocomplete(KonovaCodeAutocomplete):
"""
Due to limitations of the django dal package, we need to subclass for each code list
"""
def __init__(self, *args, **kwargs):
self.c = CODELIST_CONSERVATION_OFFICE_ID
super().__init__(*args, **kwargs)

View File

@ -203,4 +203,12 @@ input:focus, textarea:focus, select:focus{
.scroll-300{
max-height: 300px;
overflow: auto;
}
/*
Extends css for django autocomplete light (dal)
No other approach worked to get the autocomplete fields to full width of parent containers
*/
.select2-container{
width: 100% !important;
}

View File

@ -18,7 +18,8 @@ from django.contrib import admin
from django.urls import path, include
from konova.autocompletes import OrganisationAutocomplete, NonOfficialOrganisationAutocomplete, EcoAccountAutocomplete, \
InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete
InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete, LawCodeAutocomplete, \
RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete
from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
from konova.sso.sso import KonovaSSOClient
from konova.views import logout_view, home_view, get_document_view, remove_document_view, remove_deadline_view
@ -51,6 +52,9 @@ urlpatterns = [
path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="interventions-autocomplete"),
path("atcmplt/codes/compensation-action", CompensationActionCodeAutocomplete.as_view(), name="codes-compensation-action-autocomplete"),
path("atcmplt/codes/biotope", BiotopeCodeAutocomplete.as_view(), name="codes-biotope-autocomplete"),
path("atcmplt/codes/law", LawCodeAutocomplete.as_view(), name="codes-law-autocomplete"),
path("atcmplt/codes/reg-off", RegistrationOfficeCodeAutocomplete.as_view(), name="codes-registration-office-autocomplete"),
path("atcmplt/codes/cons-off", ConservationOfficeCodeAutocomplete.as_view(), name="codes-conservation-office-autocomplete"),
]
if DEBUG:

View File

@ -1,23 +1,25 @@
{% load i18n %}
<table class="table">
<tbody>
{% for field in form %}
<tr title="{{ field.help_text }}" class="{% if field.errors %}alert-danger{% endif %}">
<th scope="row" class="col-sm-3">
<label for="id_{{ field.name }}">{{ field.label }}<span class="label-required">{% if field.field.required %}*{% endif %}</span></label>
<small>{{ field.help_text }}</small>
</th>
<td class="col-sm-9">
{{ field }}
{% for error in field.errors %}
<br>
<strong class="invalid">{{ error }}</strong>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if form.has_required_fields %}
<small>{% trans 'Fields with * are required.' %}</small>
{% endif %}
<div class="table-responsive">
<table class="table">
<tbody>
{% for field in form %}
<tr title="{{ field.help_text }}" class="{% if field.errors %}alert-danger{% endif %}">
<th scope="row" class="col-sm-3">
<label for="id_{{ field.name }}">{{ field.label }}<span class="label-required">{% if field.field.required %}*{% endif %}</span></label>
<small>{{ field.help_text }}</small>
</th>
<td class="col-sm-9">
{{ field }}
{% for error in field.errors %}
<br>
<strong class="invalid">{{ error }}</strong>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if form.has_required_fields %}
<small>{% trans 'Fields with * are required.' %}</small>
{% endif %}
</div>