Compare commits

..
Author SHA1 Message Date
imperosol 0fe1a2529f style: standardize UE search style 2026-08-30 19:38:52 +02:00
17 changed files with 27 additions and 128 deletions
@@ -7,7 +7,7 @@
<form <form
hx-post="{{ url('club:club_new_members', club_id=club.id) }}" hx-post="{{ url('club:club_new_members', club_id=club.id) }}"
hx-disable="find input[type='submit']" hx-disabled-elt="find input[type='submit']"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="#member-fragment-container" hx-target="#member-fragment-container"
id="add_club_members_form" id="add_club_members_form"
+5 -10
View File
@@ -6,15 +6,10 @@
* for more efficient tree-shaking and gzip compression. * for more efficient tree-shaking and gzip compression.
*/ */
// Must be loaded before Apline
import htmx from "htmx.org";
import "htmx.org/dist/ext/hx-alpine-compat.js";
import "htmx.org/dist/ext/hx-prompt.js";
import "htmx.org/dist/ext/hx-download.js";
import sort from "@alpinejs/sort"; import sort from "@alpinejs/sort";
import Alpine from "alpinejs"; import Alpine from "alpinejs";
import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill"; import { polyfillCountryFlagEmojis } from "country-flag-emoji-polyfill";
import htmx from "htmx.org";
import { limitedChoices } from "#core:alpine/limited-choices"; import { limitedChoices } from "#core:alpine/limited-choices";
import { expireOldStorage } from "#core:core/localstorage"; import { expireOldStorage } from "#core:core/localstorage";
import { default as navbar } from "#core:core/navbar"; import { default as navbar } from "#core:core/navbar";
@@ -49,16 +44,16 @@ polyfillCountryFlagEmojis();
* HTMX * HTMX
*/ */
document.body.addEventListener( document.body.addEventListener(
"htmx:before:request" as keyof HTMLElementEventMap, "htmx:beforeRequest" as keyof HTMLElementEventMap,
(event) => { (event) => {
(event as CustomEvent).detail.ctx.target.ariaBusy = true; (event as CustomEvent).detail.target.ariaBusy = true;
}, },
); );
document.body.addEventListener( document.body.addEventListener(
"htmx:before:swap" as keyof HTMLElementEventMap, "htmx:beforeSwap" as keyof HTMLElementEventMap,
(event) => { (event) => {
(event as CustomEvent).detail.ctx.target.ariaBusy = null; (event as CustomEvent).detail.target.ariaBusy = null;
}, },
); );
@@ -1,6 +1,6 @@
<form <form
hx-post="{{ url("core:user_visibility_fragment", user_id=form.instance.id) }}" hx-post="{{ url("core:user_visibility_fragment", user_id=form.instance.id) }}"
hx-disable="find input[type='submit']" hx-disabled-elt="find input[type='submit']"
hx-swap="outerHTML" x-data="{ isViewable: {{ form.is_viewable.value()|tojson }} }" hx-swap="outerHTML" x-data="{ isViewable: {{ form.is_viewable.value()|tojson }} }"
> >
{% for message in messages %} {% for message in messages %}
-16
View File
@@ -141,22 +141,6 @@ class TestSearchUsersView(TestSearchUsers):
response = self.client.get(reverse("core:search")) response = self.client.get(reverse("core:search"))
assert response.status_code == 200 assert response.status_code == 200
def test_search_with_whitelist_unique(self):
"""Test that when a user has a whitelist and appears in the results,
it appears only once.
This is a regression test (cf #1463)
"""
user = subscriber_user.make(is_viewable=False)
user.whitelisted_users.add(
*subscriber_user.make(_quantity=4, _bulk_create=True)
)
self.client.force_login(user)
response = self.client.get(
reverse("core:search", query={"query": user.last_name})
)
assert response.context_data["users"] == [user]
@pytest.mark.django_db @pytest.mark.django_db
def test_user_account_not_found(client: Client): def test_user_account_not_found(client: Client):
-1
View File
@@ -65,7 +65,6 @@ class SearchView(LoginRequiredMixin, TemplateView):
UserFilterSchema(search=query) UserFilterSchema(search=query)
.filter(User.objects.viewable_by(self.request.user)) .filter(User.objects.viewable_by(self.request.user))
.order_by(F("last_login").desc(nulls_last=True)) .order_by(F("last_login").desc(nulls_last=True))
.distinct()
) )
clubs = list(Club.objects.filter(name__icontains=query)[:5]) clubs = list(Club.objects.filter(name__icontains=query)[:5])
return super().get_context_data(**kwargs) | {"users": users, "clubs": clubs} return super().get_context_data(**kwargs) | {"users": users, "clubs": clubs}
@@ -28,23 +28,18 @@ export class ProductAjaxSelect extends AjaxSelect {
return []; return [];
} }
// In the context in which this method is called, `this` might be shadowed private getName(item: SimpleProductSchema, sanitize: typeof escape_html): string {
// We need to call it explicitly from the class itself
private static getName(
item: SimpleProductSchema,
sanitize: typeof escape_html,
): string {
return item.code ? `${sanitize(item.code)} - ${sanitize(item.name)}` : item.name; return item.code ? `${sanitize(item.code)} - ${sanitize(item.name)}` : item.name;
} }
protected renderOption(item: SimpleProductSchema, sanitize: typeof escape_html) { protected renderOption(item: SimpleProductSchema, sanitize: typeof escape_html) {
return `<div class="select-item"> return `<div class="select-item">
<span class="select-item-text">${ProductAjaxSelect.getName(item, sanitize)}</span> <span class="select-item-text">${this.getName(item, sanitize)}</span>
</div>`; </div>`;
} }
protected renderItem(item: SimpleProductSchema, sanitize: typeof escape_html) { protected renderItem(item: SimpleProductSchema, sanitize: typeof escape_html) {
return `<span>${ProductAjaxSelect.getName(item, sanitize)}</span>`; return `<span>${this.getName(item, sanitize)}</span>`;
} }
} }
@@ -1,10 +1,5 @@
<div id="student_card_form"> <div id="student_card_form">
<form <form hx-post="{{ action }}" hx-swap="outerHTML" hx-target="#student_card_form">
hx-post="{{ action }}"
hx-swap="outerHTML"
hx-target="#student_card_form"
hx-disable="input[type='submit']"
>
{% csrf_token %} {% csrf_token %}
<p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p> <p>{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}</p>
<input type="submit" value="{% trans %}Confirm{% endtrans %}" /> <input type="submit" value="{% trans %}Confirm{% endtrans %}" />
+1 -1
View File
@@ -217,7 +217,7 @@ C'est une technologie simple et puissante qui se veut comme le jQuery du web mod
### Htmx ### Htmx
[Site officiel](https://four.htmx.org/) [Site officiel](https://htmx.org/)
En plus de AlpineJS, linteractivité sur le site est augmentée via Htmx. En plus de AlpineJS, linteractivité sur le site est augmentée via Htmx.
C'est une librairie js qui s'utilise également au moyen d'attributs HTML à C'est une librairie js qui s'utilise également au moyen d'attributs HTML à
@@ -41,7 +41,7 @@
hx-post="{{ url("election:apply_result", election_id=form.election.id) }}" hx-post="{{ url("election:apply_result", election_id=form.election.id) }}"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="#apply-election-result-fragment" hx-target="#apply-election-result-fragment"
hx-disable="find input[type='submit']" hx-disabled-elt="find input[type='submit']"
> >
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}
+1 -17
View File
@@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-01 18:32+0200\n" "POT-Creation-Date: 2026-08-21 14:10+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n" "Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@@ -5089,10 +5089,6 @@ msgstr "signalant"
msgid "A guide of courses available at UTBM." msgid "A guide of courses available at UTBM."
msgstr "Un guide de tous les cours disponibles à l'UTBM." msgstr "Un guide de tous les cours disponibles à l'UTBM."
#: pedagogy/templates/pedagogy/guide.jinja
msgid "Search UE"
msgstr "Recherche d'UE"
#: pedagogy/templates/pedagogy/guide.jinja #: pedagogy/templates/pedagogy/guide.jinja
#, python-format #, python-format
msgid "%(display_name)s" msgid "%(display_name)s"
@@ -5762,18 +5758,6 @@ msgstr "fin de la cotisation"
msgid "location" msgid "location"
msgstr "lieu" msgstr "lieu"
#: subscription/models.py
msgid "created_at"
msgstr "créé le"
#: subscription/models.py
msgid ""
"When this subscription was created. This date may differ from the start of "
"the subscription."
msgstr ""
"Quand la cotisation a été créée. Cette date peut différer du début effectif de "
"la cotisation."
#: subscription/models.py #: subscription/models.py
msgid "You can not subscribe many time for the same period" msgid "You can not subscribe many time for the same period"
msgstr "Vous ne pouvez pas cotiser plusieurs fois pour la même période" msgstr "Vous ne pouvez pas cotiser plusieurs fois pour la même période"
+5 -11
View File
@@ -30,7 +30,7 @@
"easymde": "^2.21.0", "easymde": "^2.21.0",
"glob": "^13.0.6", "glob": "^13.0.6",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"htmx.org": "^4.0.0", "htmx.org": "^2.0.10",
"js-cookie": "^3.0.8", "js-cookie": "^3.0.8",
"lit-html": "^3.3.3", "lit-html": "^3.3.3",
"native-file-system-adapter": "^3.0.1", "native-file-system-adapter": "^3.0.1",
@@ -3801,16 +3801,10 @@
} }
}, },
"node_modules/htmx.org": { "node_modules/htmx.org": {
"version": "4.0.0", "version": "2.0.10",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-4.0.0.tgz", "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.10.tgz",
"integrity": "sha512-T/171FUY93Kdfp8t+DnHdk45QvKRiBhVhhrwSzrXgUi4pHKvhp77dUA/qg8FAjsFWPIHNbmUuIdCrcVHuiZWng==", "integrity": "sha512-kdeJe7ZVwaS6QMz/ebBIVtZdpwen6L0OQ5GOhPV9MKBb196TCZeZu4yA7ZIQsaLKv7EpXz+So7KSXNuHXhj7Cw==",
"license": "BSD-0-Clause", "license": "0BSD"
"workspaces": [
"ext/*"
],
"bin": {
"upgrade-check": "dist/scripts/upgrade-check.js"
}
}, },
"node_modules/ical.js": { "node_modules/ical.js": {
"version": "1.5.0", "version": "1.5.0",
+2 -2
View File
@@ -34,8 +34,8 @@
"@types/cytoscape-klay": "^3.1.5", "@types/cytoscape-klay": "^3.1.5",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"@types/node": "^26.2.0", "@types/node": "^26.2.0",
"@typescript/native": "npm:typescript@^7.0.2",
"rollup-plugin-visualizer": "^7.1.1", "rollup-plugin-visualizer": "^7.1.1",
"@typescript/native": "npm:typescript@^7.0.2",
"typescript": "npm:@typescript/typescript6@^6.0.2", "typescript": "npm:@typescript/typescript6@^6.0.2",
"vite": "^8.2.2" "vite": "^8.2.2"
}, },
@@ -61,7 +61,7 @@
"easymde": "^2.21.0", "easymde": "^2.21.0",
"glob": "^13.0.6", "glob": "^13.0.6",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"htmx.org": "^4.0.0", "htmx.org": "^2.0.10",
"js-cookie": "^3.0.8", "js-cookie": "^3.0.8",
"lit-html": "^3.3.3", "lit-html": "^3.3.3",
"native-file-system-adapter": "^3.0.1", "native-file-system-adapter": "^3.0.1",
+4
View File
@@ -44,6 +44,10 @@
x-model.debounce.500ms="search" x-model.debounce.500ms="search"
/> />
</fieldset> </fieldset>
<fieldset>
<input type="checkbox" class="switch" name="hide_closed_ues" id="hide-closed-ues">
<label for="hide-closed-ues">{% trans %}Show closed UEs{% endtrans %}</label>
</fieldset>
<div class="row gap-3x margin-bottom radio-guide"> <div class="row gap-3x margin-bottom radio-guide">
<fieldset> <fieldset>
{% set departments = [ {% set departments = [
@@ -1,43 +0,0 @@
# Generated by Django 5.2.17 on 2026-09-01 08:44
import django.utils.timezone
from django.db import migrations, models
from django.db.migrations.state import StateApps
from django.db.models import F, Value
from django.db.models.functions import Least
from django.utils.timezone import now
def make_default_creation_date(apps: StateApps, schema_editor):
Subscription = apps.get_model("subscription", "Subscription")
Subscription.objects.update(
created_at=Least(
F("subscription_start"), Value(now()), output_field=models.DateTimeField()
)
)
class Migration(migrations.Migration):
dependencies = [("subscription", "0016_alter_subscription_subscription_type")]
operations = [
migrations.AddField(
model_name="subscription",
name="created_at",
field=models.DateTimeField(
auto_now_add=True,
default=django.utils.timezone.now,
help_text=(
"When this subscription was created. "
"This date may differ from the start of the subscription."
),
verbose_name="created_at",
),
preserve_default=False,
),
migrations.RunPython(
make_default_creation_date,
reverse_code=migrations.RunPython.noop,
elidable=True,
),
]
-8
View File
@@ -64,14 +64,6 @@ class Subscription(models.Model):
max_length=20, max_length=20,
verbose_name=_("location"), verbose_name=_("location"),
) )
created_at = models.DateTimeField(
_("created_at"),
help_text=_(
"When this subscription was created. "
"This date may differ from the start of the subscription."
),
auto_now_add=True,
)
class Meta: class Meta:
ordering = ["subscription_start"] ordering = ["subscription_start"]
@@ -1,7 +1,7 @@
<form <form
hx-post="{{ url("subscription:fragment-existing-user") }}" hx-post="{{ url("subscription:fragment-existing-user") }}"
hx-target="this" hx-target="this"
hx-disable="find input[type='submit']" hx-disabled-elt="find input[type='submit']"
hx-swap="outerHTML" hx-swap="outerHTML"
> >
{% csrf_token %} {% csrf_token %}
@@ -1,7 +1,7 @@
<form <form
hx-post="{{ url("subscription:fragment-new-user") }}" hx-post="{{ url("subscription:fragment-new-user") }}"
hx-target="this" hx-target="this"
hx-disable="find input[type='submit']" hx-disabled-elt="find input[type='submit']"
hx-swap="outerHTML" hx-swap="outerHTML"
> >
{% csrf_token %} {% csrf_token %}