Skip to content

Commit

Permalink
UI and cache
Browse files Browse the repository at this point in the history
  • Loading branch information
saxix committed Dec 1, 2024
1 parent 286d8df commit a63092c
Show file tree
Hide file tree
Showing 19 changed files with 237 additions and 50 deletions.
16 changes: 13 additions & 3 deletions src/country_workspace/admin/household.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.contrib import admin
from django.contrib import admin, messages
from django.http import HttpRequest, HttpResponse
from django.urls import reverse
from django.utils.translation import gettext as _

from admin_extra_buttons.buttons import LinkButton
from admin_extra_buttons.decorators import link
from admin_extra_buttons.decorators import button, link
from adminfilters.autocomplete import LinkedAutoCompleteFilter

from ..models import Household
Expand All @@ -19,7 +21,7 @@ class HouseholdAdmin(BaseModelAdmin):
("batch", LinkedAutoCompleteFilter.factory(parent="batch__program")),
IsValidFilter,
)
# readonly_fields = ("country_office", "program")
readonly_fields = ("errors",)
search_fields = ("name",)
autocomplete_fields = ("batch",)

Expand All @@ -35,3 +37,11 @@ def view_in_workspace(self, btn: "LinkButton") -> None:
req = btn.context["request"]
base = reverse("workspace:workspaces_countryhousehold_changelist")
btn.href = f"{base}?%s" % req.META["QUERY_STRING"]

@button(label=_("Validate"), enabled=lambda btn: btn.context["original"].checker)
def validate_single(self, request: "HttpRequest", pk: str) -> "HttpResponse":
obj: "Household" = self.get_object(request, pk)
if obj.validate_with_checker():
self.message_user(request, _("Validation successful!"), messages.SUCCESS)
else:
self.message_user(request, _("Validation failed!"), messages.ERROR)
6 changes: 6 additions & 0 deletions src/country_workspace/admin/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from admin_extra_buttons.api import button, link
from adminfilters.autocomplete import AutoCompleteFilter

from ..cache.manager import cache_manager
from ..compat.admin_extra_buttons import confirm_action
from ..models import Program
from .base import BaseModelAdmin
Expand All @@ -22,6 +23,11 @@ class ProgramAdmin(BaseModelAdmin):
list_filter = (("country_office", AutoCompleteFilter), "status", "active", "sector")
ordering = ("name",)

@button()
def invalidate_cache(self, request: HttpRequest, pk: str) -> None:
obj: [Program] = Program.objects.select_related("country_office").get(pk=pk)
cache_manager.incr_cache_version(program=obj)

@link(change_list=False)
def view_in_workspace(self, btn: "LinkButton") -> None:
obj = btn.context["original"]
Expand Down
9 changes: 9 additions & 0 deletions src/country_workspace/cache/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.apps import AppConfig


class Config(AppConfig):
name = __name__.rpartition(".")[0]
verbose_name = "Cache"

def ready(self) -> None:
from . import handlers # noqa
2 changes: 2 additions & 0 deletions src/country_workspace/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"flags",
"reversion",
"tailwind",
"django_select2",
"social_django",
"admin_extra_buttons",
"adminactions",
Expand All @@ -49,6 +50,7 @@
"country_workspace.apps.Config",
"country_workspace.workspaces.apps.Config",
"country_workspace.versioning",
"country_workspace.cache",
# these should be optional in the future
"country_workspace.contrib.hope.apps.Config",
"country_workspace.contrib.aurora.apps.Config",
Expand Down
1 change: 1 addition & 0 deletions src/country_workspace/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
path(r"accounts/", include("django.contrib.auth.urls")),
path(r"adminactions/", include("adminactions.urls")),
path(r"sentry_debug/", lambda _: 1 / 0),
path("select2/", include("django_select2.urls")),
path(r"__debug__/", include(debug_toolbar.urls)),
]

Expand Down
11 changes: 10 additions & 1 deletion src/country_workspace/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.1.3 on 2024-11-30 09:06
# Generated by Django 5.1.3 on 2024-12-01 19:19

import concurrency.fields
import country_workspace.models.base
Expand Down Expand Up @@ -29,6 +29,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("name", models.CharField(db_index=True, max_length=255)),
("iso_code2", models.CharField(max_length=2, unique=True)),
],
Expand All @@ -42,6 +43,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("hope_id", models.CharField(blank=True, max_length=100, null=True, unique=True)),
("long_name", models.CharField(blank=True, db_index=True, max_length=100, null=True)),
("name", models.CharField(blank=True, db_index=True, max_length=100, null=True)),
Expand Down Expand Up @@ -171,6 +173,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("name", models.CharField(blank=True, max_length=255, null=True)),
("import_date", models.DateTimeField(auto_now=True)),
(
Expand Down Expand Up @@ -211,6 +214,7 @@ class Migration(migrations.Migration):
models.CharField(blank=True, db_index=True, max_length=300, null=True, verbose_name="checksum"),
),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("system_fields", models.JSONField(blank=True, default=dict)),
("batch", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="country_workspace.batch")),
],
Expand All @@ -234,6 +238,7 @@ class Migration(migrations.Migration):
models.CharField(blank=True, db_index=True, max_length=300, null=True, verbose_name="checksum"),
),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("system_fields", models.JSONField(blank=True, default=dict)),
("batch", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="country_workspace.batch")),
(
Expand Down Expand Up @@ -263,6 +268,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("hope_id", models.CharField(editable=False, max_length=200, unique=True)),
("name", models.CharField(max_length=255)),
("code", models.CharField(blank=True, max_length=255, null=True)),
Expand Down Expand Up @@ -443,6 +449,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("name", models.CharField(blank=True, max_length=255, null=True)),
(
"hhs",
Expand Down Expand Up @@ -473,6 +480,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("object_id", models.PositiveIntegerField(blank=True, null=True)),
("last_update_date", models.DateTimeField(blank=True, null=True)),
("last_id", models.CharField(max_length=255, null=True)),
Expand Down Expand Up @@ -536,6 +544,7 @@ class Migration(migrations.Migration):
fields=[
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("last_modified", models.DateTimeField(auto_now=True)),
("version", concurrency.fields.IntegerVersionField(default=0, help_text="record revision number")),
("expires", models.DateField(blank=True, null=True)),
(
"country_office",
Expand Down
2 changes: 2 additions & 0 deletions src/country_workspace/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import dictdiffer
import reversion
from concurrency.fields import IntegerVersionField

from country_workspace.cache.manager import cache_manager
from country_workspace.state import state
Expand Down Expand Up @@ -134,6 +135,7 @@ def diff(self, first: Optional[int] = None, second: Optional[int] = None) -> "An

class BaseModel(models.Model):
last_modified = models.DateTimeField(auto_now=True, editable=False)
version = IntegerVersionField(_("Version"), db_index=True)

objects = BaseManager()

Expand Down
3 changes: 1 addition & 2 deletions src/country_workspace/workspaces/admin/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ class CountryBatchAdmin(SelectedProgramMixin, WorkspaceModelAdmin):
change_form_template = "workspace/change_form.html"
ordering = ("name",)
list_filter = (("source", ChoiceFilter), ("imported_by", UserAutoCompleteFilter))
exclude = ("program", "country_office", "imported_by")
readonly_fields = fields = ("name", "source")

def get_search_results(self, request, queryset, search_term):

queryset = self.model.objects.filter(program=state.program)
return queryset, False

Expand Down
6 changes: 1 addition & 5 deletions src/country_workspace/workspaces/admin/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,7 @@ class WFailedFilter(FailedFilter):

class UserAutoCompleteFilter(AutoCompleteFilter):
template = "workspace/adminfilters/autocomplete.html"

def get_url(self) -> str:
base_url = reverse("admin:country_workspace_user_autocomplete")
url = f"{base_url}?program={state.program.pk}"
return url
ajax_url = "admin:country_workspace_user_autocomplete"

def html_attrs(self):
classes = f"adminfilters {self.__class__.__name__.lower()}"
Expand Down
8 changes: 7 additions & 1 deletion src/country_workspace/workspaces/admin/hh_ind.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,21 @@ def _changeform_view(
if request.method == "POST":
if obj:
form: "FlexForm" = form_class(request.POST, prefix="flex_field", initial=initials)
if form.is_valid():
form_valid = form.is_valid()
if form_valid or "_save_invalid" in request.POST:
obj.flex_fields = form.cleaned_data
self.save_model(request, obj, form, True)
if form_valid:
self.message_user(request, _("Record saved!"), messages.SUCCESS)
else:
self.message_user(request, _("Record saved but not validated"), messages.WARNING)
return HttpResponseRedirect(request.META["HTTP_REFERER"])
else:
self.message_user(request, "Please fixes the errors below", messages.ERROR)
else:
form = form_class(prefix="flex_field", initial=initials)

context["show_save_invalid"] = True
context["title"] = self.title
context["checker_form"] = form
context["has_change_permission"] = self.has_change_permission(request)
Expand Down
37 changes: 30 additions & 7 deletions src/country_workspace/workspaces/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

from django_select2 import forms as s2forms

from ..models import Program
from ..state import state
from . import models
from .config import conf

if TYPE_CHECKING:
Expand Down Expand Up @@ -37,13 +39,40 @@ def __init__(self, *args: "Any", **kwargs: "Any") -> None:
self.fields["tenant"].queryset = conf.auth.get_allowed_tenants(self.request)


class ProgramWidget(s2forms.ModelSelect2Widget):
model = Program
search_fields = ["name__icontains"]

def filter_queryset(self, request, term, queryset=None, **dependent_fields):
qs = super().filter_queryset(request, term, queryset, **dependent_fields)
return qs.filter(country_office=state.tenant)

@property
def media(self):
original = super().media
return original + forms.Media(
css={
"screen": [
"adminfilters/adminfilters.css",
]
},
)


class SelectProgramForm(forms.Form):
program = forms.ModelChoiceField(
label=_("Program"),
queryset=None,
required=True,
blank=False,
limit_choices_to={"active": True},
widget=ProgramWidget(
attrs={
"data-minimum-input-length": 0,
"data-placeholder": "Select a Program",
"data-close-on-select": "true",
}
),
)
next = forms.CharField(required=False, widget=forms.HiddenInput)

Expand All @@ -52,9 +81,3 @@ def __init__(self, *args: "Any", **kwargs: "Any") -> None:
super().__init__(*args, **kwargs)
if state.tenant:
self.fields["program"].queryset = state.tenant.programs.filter().order_by("name").all()


class ProgramForm(forms.ModelForm):
class Meta:
model = models.CountryProgram
fields = ("country_office", "name")
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.1.3 on 2024-11-30 09:06
# Generated by Django 5.1.3 on 2024-12-01 19:19

import django.db.models.deletion
from django.db import migrations, models
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% extends "workspace/layout.html" %}{% load feature_flags i18n workspace_urls %}
{% block header %}
{{ program_form.media.css }}
<div class="pr-10 flex-grow align-middle pt-3">
<form id="select-tenant" method="post" action="{% url "workspace:select_tenant" %}">
{% csrf_token %}
Expand All @@ -12,6 +13,7 @@
{% csrf_token %}
<span class="flex align-middle">{{ program_form.program }}{% admin_url active_program %}</span>
</form>
{{ program_form.media.js }}
</div>
{% endif %}
{% endblock header %}
Expand Down
18 changes: 9 additions & 9 deletions src/country_workspace/workspaces/templates/workspace/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
{% block stylesheet %}
{# <link rel="stylesheet" href="{% static "power_query.css" %}" type="text/css"> #}
<link rel="stylesheet" href="{% static "icons.css" %}" type="text/css">
{# <link rel="stylesheet" href="{% static "css/styles.css" %}" type="text/css"> #}
{% tailwind_css %}
{# <link rel="stylesheet" href="{% static "css/styles.css" %}" type="text/css"> #}
{% endblock stylesheet %}
{% block scripts %}
<script src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
<script src="{% static "hcr.js" %}"></script>
{% endblock scripts %}
{{ media }}
{% tailwind_css %}
{% block extrahead %}{% endblock %}
</head>
<body class="web">
Expand All @@ -38,14 +38,14 @@
<main class="flex flex-col h-screen">
<header class="flex drop-shadow-md">
{% block logo %}
<div class="w-52 bg-unicef-blue p-0 flex h-16 items-center display-open">
<div class="flex-grow">
<div class="w-52 bg-unicef-blue p-0 flex-none h-16 items-center display-open">
<div class="inline-flex">
<img src="{% static "hope_logo.png" %}" class="pl-8 h-16">
</div>
<div class="flex-shrink align-middle pr-2 cursor-pointer" id="close-sidebar">
<svg focusable="false" class="sidebar-button text-white" viewBox="0 0 24 24" aria-hidden="true">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path>
</svg>
<div class="cursor-pointer" id="close-sidebar">
<svg focusable="false" class="sidebar-button text-white align-middle mt-5" viewBox="0 0 24 24" aria-hidden="true">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path>
</svg>
</div>
</div>
</div>
{% endblock logo %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{% if show_save_as_new %}<input type="submit" value="{% translate 'Save as new' %}" name="_saveasnew">{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="{% translate 'Save and add another' %}" name="_addanother">{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% if can_change %}{% translate 'Save and continue editing' %}{% else %}{% translate 'Save and view' %}{% endif %}" name="_continue">{% endif %}
{% if show_save_invalid %}<input type="submit" value="{% translate 'Save & ignore errors' %}" class="default" name="_save_invalid">{% endif %}
{% if show_close %}
{% url opts|workspace_urlname:'changelist' as changelist_url %}
<a href="{% add_preserved_filters changelist_url %}" class="closelink">{% translate 'Close' %}</a>
Expand Down
Loading

0 comments on commit a63092c

Please sign in to comment.